Skip to content
Snippets Groups Projects
Commit 73ba1e17 authored by Hartung, Michael's avatar Hartung, Michael
Browse files

CSS style prefixer implementation

parent af7a7d11
No related branches found
No related tags found
No related merge requests found
FROM nginx
RUN apt-get update
RUN apt-get install -y curl
RUN curl -sL https://deb.nodesource.com/setup_10.x | bash
RUN apt-get install -y nodejs
COPY package.json /app/
COPY package-lock.json /app/
WORKDIR /app/
RUN npm install
COPY . /app/
RUN npm run -- bundle
RUN cp -r website/* /usr/share/nginx/html/
RUN mkdir /usr/share/nginx/html/lib
RUN cp dist/netex/bundle-es2015.js /usr/share/nginx/html/lib/
RUN cp dist/netex/bundle-es5.js /usr/share/nginx/html/lib/
RUN cp dist/netex/styles.css /usr/share/nginx/html/lib/
COPY nginx/default.conf /etc/nginx/conf.d/
COPY nginx/htpasswd /etc/nginx/htpasswd
EXPOSE 80
FROM nginx
RUN apt-get update
RUN apt-get install -y curl
RUN curl -sL https://deb.nodesource.com/setup_10.x | bash
RUN apt-get install -y nodejs
COPY package.json /app/
COPY package-lock.json /app/
WORKDIR /app/
RUN npm install
COPY . /app/
RUN npm run build -- --prod --base-href=/covex/
RUN cp -r dist/netex/* /usr/share/nginx/html/
COPY nginx/default.conf /etc/nginx/conf.d/
COPY nginx/htpasswd /etc/nginx/htpasswd
EXPOSE 80
This diff is collapsed.
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
"package-es2015": "cd dist/netex && cat runtime-es2015.js polyfills-es2015.js main-es2015.js > bundle-es2015.js", "package-es2015": "cd dist/netex && cat runtime-es2015.js polyfills-es2015.js main-es2015.js > bundle-es2015.js",
"bundle": "npm run build-prod netex && npm run package-es5 && npm run package-es2015", "bundle": "npm run build-prod netex && npm run package-es5 && npm run package-es2015",
"build:netex": "npm run build-prod netex && node build-netex.js", "build:netex": "npm run build-prod netex && node build-netex.js",
"build:netex-dev": "npm run build-dev netex && node build-netex.js", "build:netex-dev": "python prefixCSS.py --parse && npm run build-dev netex && node build-netex.js && python prefixCSS.py --cleanup",
"build:netex-old": "npm run build-old netex && node build-netex.js", "build:netex-old": "npm run build-old netex && node build-netex.js",
"prefix": "bash prefix_styles.sh", "prefix": "bash prefix_styles.sh",
"prefixcss": "postcss -r drugsTone-build/styles.css" "prefixcss": "postcss -r drugsTone-build/styles.css"
...@@ -45,7 +45,7 @@ ...@@ -45,7 +45,7 @@
"@ng-select/ng-select": "^6.1.0", "@ng-select/ng-select": "^6.1.0",
"animate.css": "^4.1.1", "animate.css": "^4.1.1",
"bulma": "^0.9.2", "bulma": "^0.9.2",
"bulma-toast": "^2.3.1", "bulma-toast": "^2.4.1",
"bulma-tooltip": "^3.0.2", "bulma-tooltip": "^3.0.2",
"document-register-element": "^1.7.2", "document-register-element": "^1.7.2",
"dom-to-image": "^2.6.0", "dom-to-image": "^2.6.0",
...@@ -55,6 +55,7 @@ ...@@ -55,6 +55,7 @@
"primeng": "^12.0.1", "primeng": "^12.0.1",
"python": "0.0.4", "python": "0.0.4",
"python-shell": "^3.0.0", "python-shell": "^3.0.0",
"remove": "^0.1.5",
"rxjs": "~7.1.0", "rxjs": "~7.1.0",
"tslib": "^2.0.0", "tslib": "^2.0.0",
"zone.js": "~0.11.4" "zone.js": "~0.11.4"
......
import os
import shutil
import re
import subprocess
import argparse
def find_nth(haystack, needle, n):
start = haystack.find(needle)
while start >= 0 and n > 1:
start = haystack.find(needle, start+len(needle))
n -= 1
return start
class ParserHTML:
PREFIX = 'drugstone-plugin-'
CLASSSEARCHPATTERN = 'class="'
IDSEARCHPATTERN = 'id="'
NGCLASSSEARCHPATTERN = '[ngClass]="'
PARSEDFILENEDING = '.parsed'
NGCLASSINDIVIDUALPATTERN = '[class.'
TOOLTIPCLASSPATTERN = '[tooltipStyleClass]="'
def __init__(self):
pass
def prefixNgIndivClassStrings(self, line, classStart):
line = line[:classStart] + self.PREFIX + line[classStart:]
return line
def prefixNgClassStrings(self, line, classStart):
start = False
classIndices = []
for i, c in enumerate(line[classStart:], classStart):
if c == "'":
if not start:
classIndices.append(i+1)
start = True
else:
start = False
elif c == '}':
break
for i, start in enumerate(classIndices):
start += i * len(self.PREFIX)
line = line[:start] + self.PREFIX + line[start:]
return line
def findClassStrings(self, line, classStart):
classIndices = []
start = classStart
lastWasCurl = False
lastWasClosingCurl = False
inVariable = False
for i, c in enumerate(line[classStart:], classStart):
if (c == ' ' or c == '"') and not inVariable and i > start:
classIndices.append((start, i))
start = i + 1
elif c == '{':
if lastWasCurl:
inVariable = True
lastWasCurl = True
elif c == '}':
if lastWasClosingCurl:
inVariable = False
lastWasClosingCurl = True
else:
lastWasCurl = False
lastWasClosingCurl = False
if c == '"':
return classIndices, i
return classIndices, len(line)
def updateClassStrings(self, line, classIndices, classStart, classEnd, iTagOpen):
renamedClassList = []
for start, end in classIndices:
classString = line[start:end]
if classString.startswith('ng-') or (iTagOpen and classString.startswith('fa') or classString.startswith('{')):
renamedClassList.append(classString)
continue
renamedClass = self.prefixClass(classString)
renamedClassList.append(renamedClass)
return self.updateClasses(line, renamedClassList, classStart, classEnd)
def prefixClass(self, classString):
return self.PREFIX + classString
def prefixtooltipStrings(self, line, tooltipClassStart):
subline = line[tooltipClassStart:]
start = subline.find("'")+1
end = find_nth(subline, "'", 2)
classStringList = subline[start:end].split(' ')
classStringList = [self.prefixClass(x) for x in classStringList]
line = line[:tooltipClassStart+start] + ' '.join(classStringList) + line[tooltipClassStart+end:]
return line
def updateClasses(self, line, renamedClassList, classStart, classEnd):
renamedClassString = ' '.join(renamedClassList)
return line[:classStart] + renamedClassString + line[classEnd:]
def parseHtml(self, path):
newLines = []
with open(path) as f:
content = ''
iTagOpen = False
# remove linebreaks in tags
for line in f:
if not len(line.strip()):
continue
# line.count('"') % 2 --> opened but not closed like [ngClass]="
if line.count('"') % 2 and not line.strip().endswith('>'):
content += line.strip() + ' '
else:
content += line + '\n'
for line in content.split('\n'):
line = line.strip()
if '<i' in line:
iTagOpen = True
classStart = line.find(self.CLASSSEARCHPATTERN)
if classStart > -1:
classStart += len(self.CLASSSEARCHPATTERN)
classIndices, classEnd = self.findClassStrings(line, classStart)
line = self.updateClassStrings(line, classIndices, classStart, classEnd, iTagOpen)
ngClassStart = line.find(self.NGCLASSSEARCHPATTERN)
if ngClassStart > -1:
ngClassStart += len(self.NGCLASSSEARCHPATTERN)
line = self.prefixNgClassStrings(line, ngClassStart)
ngClassIndivStart = line.find(self.NGCLASSINDIVIDUALPATTERN)
if ngClassIndivStart > -1:
ngClassIndivStart += len(self.NGCLASSINDIVIDUALPATTERN)
# exclude .fa classes
if not line[ngClassIndivStart:].startswith('fa-'):
line = self.prefixNgIndivClassStrings(line, ngClassIndivStart)
tooltipClassStart = line.find(self.TOOLTIPCLASSPATTERN)
if tooltipClassStart > -1:
tooltipClassStart += len(self.TOOLTIPCLASSPATTERN)
line = self.prefixtooltipStrings(line, tooltipClassStart)
if self.IDSEARCHPATTERN in line:
line = line.replace(self.IDSEARCHPATTERN, self.IDSEARCHPATTERN + self.PREFIX)
newLines.append(line)
if '</i' in line:
iTagOpen = False
return '\n'.join(newLines)
def write(self, path, html):
writePath = path + self.PARSEDFILENEDING
with open(writePath, "w") as f:
print(html, file=f)
# overwrite file
os.rename(writePath, path)
def parseDirectory(self, directory):
for root, dirs, files in os.walk(directory):
for file in files:
if file.endswith(".component.html"):
path = os.path.join(root, file)
print('parsing', path)
html = self.parseHtml(path)
self.write(path, html)
class ParserJS:
PREFIX = 'drugstone-plugin-'
PARSEDFILENEDING = '.parsed'
DIR = 'src/'
ELEMENTBYIDSTRING = 'document.getElementById('
def findId(self, line):
start = line.find(self.ELEMENTBYIDSTRING) + len(self.ELEMENTBYIDSTRING)+1
return start
def replaceElementById(self, line):
start = self.findId(line)
line = line[:start] + self.PREFIX + line[start:]
return line
def parseJS(self, path):
newLines = []
with open(path) as f:
for line in f:
if self.ELEMENTBYIDSTRING in line:
line = self.replaceElementById(line)
newLines.append(line)
return '\n'.join(newLines)
def write(self, path, html):
writePath = path + self.PARSEDFILENEDING
with open(writePath, "w") as f:
print(html, file=f)
# overwrite file
os.rename(writePath, path)
def parseDirectory(self, directory):
for root, dirs, files in os.walk(directory):
for file in files:
if file.endswith(".component.ts"):
path = os.path.join(root, file)
print('parsing', path)
html = self.parseJS(path)
self.write(path, html)
class ParserCSS:
PREFIXCLASS = '.drugstone-plugin-'
PREFIXID = '#drugstone-plugin-'
PARSEDFILENEDING = '.parsed'
DIR = 'src/'
def __init__(self):
pass
def charIsNumber(self, x):
try:
int(x)
return True
except:
return False
def findClassEnding(self, line, start):
start += 1
for i, c in enumerate(line[start:], start):
if c == '.' or c == ' ' or c == '{' or c ==',':
return i
return len(line)
def findPotentialIdEnding(self, line, start):
# can be id or hexacode color
start += 1
for i, c in enumerate(line[start:], start):
if c == ';' or c == '}' or c == '!' or c == ' ' or c == ',':
return i
return len(line)
def prefixClasses(self, classListString):
classListStringList = classListString.split('.')
classListStringList = [x for x in classListStringList if len(x)]
classListStringList = [self.PREFIXCLASS + x if not (x.startswith('ng-') or x.startswith('p-') or x.startswith('drugstone-plugin-') or x.startswith('fa-')) else '.' + x for x in classListStringList]
return '.'.join(classListStringList)
def prefixId(self, classListString):
return classListString.replace('#', self.PREFIXID)
def parseCSS(self, path):
newLines = []
with open(path) as f:
for line in f:
# leading white spaces are necessary for sass
leadingWhiteSaces = len(line) - len(line.lstrip())
line = line.strip()
if line.startswith('//'):
# skip comments
continue
if not len(line):
# skip empty lines as empty lines in the beginning of .sass files cause errors
continue
if line.startswith('@import') or line.startswith('@forward') or line.startswith('@error') or line.startswith('@mixin') or line.startswith('@content') or line.startswith('src'):
line = leadingWhiteSaces*' ' + line
newLines.append(line)
# leave imports untouched
continue
i = 0
while i < len(line):
c = line[i]
if c == '.':
# i+1 < len(line) is necessary for online comments that end with a dot
if not i+1 < len(line):
i += 1
continue
if self.charIsNumber(line[i+1]):
i += 1
continue
classListEnd = self.findClassEnding(line, i)
classListString = line[i:classListEnd]
renamedClasses = self.prefixClasses(classListString)
line = line[:i] + renamedClasses + line[classListEnd:]
i = classListEnd + renamedClasses.count(self.PREFIXCLASS)*len(self.PREFIXCLASS) - 2
elif c == '#':
if i+1 < len(line) and line[i+1] == '{':
i += 1
continue
# test if string is hexacode color
end = self.findPotentialIdEnding(line, i)
# end > -1 for color in comment
if end > -1 and re.search(r'^#(?:[0-9a-fA-F]{3}){1,2}$', line[i:end]):
i = end
continue
classListEnd = self.findClassEnding(line, i)
classListString = line[i:classListEnd]
renamedClasses = self.prefixId(classListString)
line = line[:i] + renamedClasses + line[classListEnd:]
i += classListEnd + len(self.PREFIXID) - 2
i += 1
# add white spaces
line = leadingWhiteSaces*' ' + line
newLines.append(line)
return '\n'.join(newLines)
def write(self, path, html):
writePath = path + self.PARSEDFILENEDING
with open(writePath, "w") as f:
print(html, file=f)
# overwrite file
os.rename(writePath, path)
def parseDirectory(self, directory):
for root, dirs, files in os.walk(directory):
for file in files:
if file.endswith(".scss") or file.endswith(".css") or file.endswith(".sass"):
path = os.path.join(root, file)
# skip ng select classes
if '@ng-select' in path:
continue
print('parsing', path)
scss = self.parseCSS(path)
self.write(path, scss)
class BuildManager:
def __init__(self, buildPath):
self.buildPath = buildPath
def buildDevDir(self):
shutil.copytree('src', os.path.join(self.buildPath, 'src'))
shutil.copytree('node_modules', os.path.join(self.buildPath, 'node_modules'))
def parseApp(self):
ParserHTML().parseDirectory('src/app/')
ParserCSS().parseDirectory('src/')
ParserCSS().parseDirectory('node_modules/')
ParserJS().parseDirectory('src/app/')
def cleanup(self):
shutil.rmtree('src')
shutil.copytree(os.path.join(self.buildPath, 'src'), 'src')
shutil.rmtree('node_modules')
shutil.rmtree(self.buildPath)
subprocess.run(['npm', 'i'])
ORIGDIR = 'original'
def parse():
buildManager = BuildManager(ORIGDIR)
try:
buildManager.buildDevDir()
buildManager.parseApp()
except:
buildManager.cleanup()
raise Exception('ERROR: CSS prefix script failed.')
def cleanup():
buildManager = BuildManager(ORIGDIR)
buildManager.cleanup()
parser = argparse.ArgumentParser()
parser.add_argument("-s", "--stage", help = "Stage of building. Either 'parse' or 'cleanup'.")
if __name__ == '__main__':
args = parser.parse_args()
if not args.stage:
raise Exception('Value for --stage is missing.')
if args.stage == 'parse':
parse()
elif args.stage == 'cleanup':
cleanup()
else:
raise Exception(f'ERROR: Unknown argument for --stage: {args.stage}. Should be "parse" or "stage"').
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment