UNPKG

magix-composer

Version:

compile html, style and javascript files into javascript

406 lines (401 loc) 15.4 kB
let configs = require('./util-config'); let slog = require('./util-log'); let chalk = require('chalk'); let consts = require('./util-const'); let ItemUsed = 1; let ItemDeclared = 2; let ItemSecondhand = 4; //文件之间关系,主要通过js关联的html和css let FileRelationships = Object.create(null); //记录js文件中,如@scoped.style:--css-var使用的选择器,变量等 let FileHostUsed = Object.create(null); //记录样式文件声明了哪些选择器,变量及@规则 let FileStylesDeclared = Object.create(null); //记录模板文件中使用了哪些选择器,css变量 let FileTemplatesUsed = Object.create(null); //追踪不存在的文件 let FileUnexists = Object.create(null); //记录样式文件中[ref="@path.css:selector"]使用的选择器或变量 let FileStylesUsed = Object.create(null); //记录复杂的样式 let FileStylesComplex = Object.create(null); //记录使用过的全局变量 let FileStylesGlobalVarUsed = Object.create(null); module.exports = { reset() { //文件之间关系,主要通过js关联的html和css FileRelationships = Object.create(null); //记录js文件中,如@scoped.style:--css-var使用的选择器,变量等 FileHostUsed = Object.create(null); //记录样式文件声明了哪些选择器,变量及@规则 FileStylesDeclared = Object.create(null); //记录模板文件中使用了哪些选择器,css变量 FileTemplatesUsed = Object.create(null); //追踪不存在的文件 FileUnexists = Object.create(null); //记录样式文件中[ref="@path.css:selector"]使用的选择器或变量 FileStylesUsed = Object.create(null); //记录复杂的样式 FileStylesComplex = Object.create(null); //记录使用过的全局变量 FileStylesGlobalVarUsed = Object.create(null); }, resetByHost(from) { delete FileRelationships[from]; delete FileHostUsed[from]; delete FileUnexists[from]; }, resetByTemplate(from) { delete FileTemplatesUsed[from]; }, resetByStyle(from) { delete FileStylesDeclared[from]; delete FileStylesUsed[from]; delete FileStylesComplex[from]; delete FileStylesGlobalVarUsed[from]; }, resetUnexist(host) { delete FileUnexists[host]; }, storeStyleGlobalVars(host, vars) { let info = FileStylesGlobalVarUsed[host]; if (!info) { info = FileStylesGlobalVarUsed[host] = Object.create(null); } info[vars] = ItemUsed; }, storeUnexist(host, name) { FileUnexists[host] = name; }, storeStyleDeclared(file, declares) { /* declares:{ vars:{}, selectors:{}, tagsOrAttrs:{} } */ let info = FileStylesDeclared[file]; if (!info) { info = FileStylesDeclared[file] = { vars: Object.create(null), selectors: Object.create(null), tagsOrAttrs: Object.create(null), atRules: Object.create(null) }; } if (declares.selectors) { Object.assign(info.selectors, declares.selectors); } if (declares.vars) { Object.assign(info.vars, declares.vars); } if (declares.tagsOrAttrs) { Object.assign(info.tagsOrAttrs, declares.tagsOrAttrs); } if (declares.atRules) { Object.assign(info.atRules, declares.atRules); } }, storeTemplateUsed(file, used) { /* used:{ vars:{}, selectors:{} } */ let info = FileTemplatesUsed[file]; if (!info) { info = FileTemplatesUsed[file] = { vars: Object.create(null), selectors: Object.create(null), tagsOrAttrs: Object.create(null) }; } if (used.selectors) { Object.assign(info.selectors, used.selectors); } if (used.vars) { Object.assign(info.vars, used.vars); } if (used.tagsOrAttrs) { Object.assign(info.tagsOrAttrs, used.tagsOrAttrs); } }, storeStyleUsed(host, file, used) { let info = FileStylesUsed[host]; if (!info) { info = FileStylesUsed[host] = Object.create(null); } info = info[file]; if (!info) { info = FileStylesUsed[host][file] = { selectors: Object.create(null), vars: Object.create(null), atRules: Object.create(null) }; } if (used.selectors) { Object.assign(info.selectors, used.selectors); } if (used.vars) { Object.assign(info.vars, used.vars); } if (used.atRules) { Object.assign(info.atRules, used.atRules); } }, storeStyleComplex(file, rules) { FileStylesComplex[file] = rules; }, storeHostUsed(host, file, used) { /* used:{ vars:{}, selectors:{} } */ let info = FileHostUsed[host]; if (!info) { info = FileHostUsed[host] = Object.create(null); } info = info[file]; if (!info) { info = FileHostUsed[host][file] = { vars: Object.create(null), selectors: Object.create(null) }; } if (used.selectors) { Object.assign(info.selectors, used.selectors); } if (used.vars) { Object.assign(info.vars, used.vars); } }, hostAddTemplate(host, template) { if (!FileRelationships[host]) { FileRelationships[host] = { templates: Object.create(null), styles: Object.create(null) }; } FileRelationships[host].templates[template] = 1; }, hostAddStyle(host, style) { if (!FileRelationships[host]) { FileRelationships[host] = { templates: Object.create(null), styles: Object.create(null) }; } let dest = FileRelationships[host].styles; let keys = Object.keys(dest); dest[style] = keys.length; }, output() { if (!configs.checker.css || !configs.debug) return; let declared = Object.create(null); for (let p in FileStylesDeclared) { let init = {}; let t = FileStylesDeclared[p]; for (let i in t) { init[i] = Object.create(null); for (let z in t[i]) { init[i][z] = ItemDeclared; } } declared[p] = init; } let updateStyleUsed = (style, used, un, locker) => { let dest = declared[style]; for (let p in used) { if (locker && !locker[p]) locker[p] = Object.create(null); for (let z in used[p]) { if (dest && dest[p][z]) { if (!locker || locker[p][z] != ItemSecondhand) { if (configs.selectorDSEndReg.test(z)) { for (let f in dest[p]) { if (f.startsWith(z)) { dest[p][f] |= ItemUsed; } } } else { dest[p][z] |= ItemUsed; } if (locker) { locker[p][z] = ItemSecondhand; } } } else if (un) { if (!un[p]) { un[p] = Object.create(null); } un[p][z] = ItemUsed; } } } }; let sortStyles = styles => { let result = []; for (let p in styles) { result.push({ num: styles[p], file: p }); } result = result.sort((a, b) => b.num - a.num); return result; }; let usedGlobalVars = Object.create(null); let updateGlobalVars = vars => { let result = false; if (vars.startsWith(`--${consts.cssIdGlobalPrefix}`)) { for (let host in FileStylesGlobalVarUsed) { let dest = FileStylesGlobalVarUsed[host]; if (!usedGlobalVars[host]) { usedGlobalVars[host] = Object.create(null); } if (dest[vars]) { usedGlobalVars[host][vars] = ItemDeclared; result = true; } } } return result; }; let templateUsed = Object.create(null); for (let fr in FileRelationships) { let { styles, templates } = FileRelationships[fr]; styles = sortStyles(styles); for (let template in templates) { let used = FileTemplatesUsed[template]; templateUsed[template] = Object.create(null); if (used) { for (let style of styles) { updateStyleUsed(style.file, used, null, templateUsed[template]); } } } } let unexist = Object.create(null); for (let fhu in FileHostUsed) { unexist[fhu] = Object.create(null); let s = FileHostUsed[fhu]; for (let style in s) { unexist[fhu][style] = Object.create(null); updateStyleUsed(style, s[style], unexist[fhu][style]); } } for (let fsu in FileStylesUsed) { unexist[fsu] = Object.create(null); let fileWrap = FileStylesUsed[fsu]; for (let style in fileWrap) { let styleWrap = fileWrap[style]; unexist[fsu][style] = Object.create(null); updateStyleUsed(style, styleWrap, unexist[fsu][style]); } } for (let host in unexist) { let dest = unexist[host]; let hostShort = host.replace(configs.moduleIdRemovedPath, '').substring(1); for (let aim in dest) { let selectors = dest[aim]; let aimShort = aim.replace(configs.moduleIdRemovedPath, '').substring(1); for (let selector in selectors) { for (let key in selectors[selector]) { slog.ever('[MXC(checker)]', chalk.grey(hostShort), 'use unexist', chalk.red(key), 'from', chalk.grey(aimShort)); } } } } for (let p in FileStylesComplex) { let short = p.replace(configs.moduleIdRemovedPath, '').substring(1); let rules = FileStylesComplex[p]; slog.ever('[MXC(checker)]', chalk.grey(short) + ' avoid use ' + chalk.red(`"${rules.join('","')}"`)); } for (let fn in declared) { let selectors = declared[fn]; let short = fn.replace(configs.moduleIdRemovedPath, '').substring(1); let neverUsedSelectors = [], neverUsedTagsOrAttrs = [], neverUsedVars = [], neverUsedAtRules = []; for (let selector in selectors) { let dest = selectors[selector]; for (let key in dest) { if ((dest[key] & ItemUsed) != ItemUsed) { if (selector == 'selectors') { if (!configs.selectorDSEndReg.test(key)) { neverUsedSelectors.push('.' + key); } } else if (selector == 'vars') { if (!updateGlobalVars(key)) { neverUsedVars.push(key); } } else if (selector == 'tagsOrAttrs') { neverUsedTagsOrAttrs.push(key); } else if (selector == 'atRules') { neverUsedAtRules.push(key); } } } } if (neverUsedSelectors.length) { slog.ever('[MXC(checker)]', chalk.grey(short) + ' never used selectors ' + chalk.red(`"${neverUsedSelectors.join('","')}"`)); } if (neverUsedTagsOrAttrs.length) { slog.ever('[MXC(checker)]', chalk.grey(short) + ' never used tags or attrs ' + chalk.red(`"${neverUsedTagsOrAttrs.join('","')}"`)); } if (neverUsedVars.length) { slog.ever('[MXC(checker)]', chalk.grey(short) + ' never used vars ' + chalk.red(`"${neverUsedVars.join('","')}"`)); } if (neverUsedAtRules.length) { slog.ever('[MXC(checker)]', chalk.grey(short) + ' never used at rules ' + chalk.red(`"${neverUsedAtRules.join('","')}"`)); } } for (let host in FileTemplatesUsed) { let short = host.replace(configs.moduleIdRemovedPath, '').substring(1); let dest = FileTemplatesUsed[host]; let undeclared = []; let tUsed = templateUsed[host]; if (dest.selectors) { for (let p in dest.selectors) { if (!tUsed || !tUsed.selectors || tUsed.selectors[p] !== ItemSecondhand) { undeclared.push('.' + p); } } } if (dest.vars) { for (let p in dest.vars) { if (!tUsed || !tUsed.vars || tUsed.vars[p] !== ItemSecondhand) { undeclared.push('var(' + p + ')'); } } } if (undeclared.length) { slog.ever('[MXC(checker)]', chalk.grey(short), 'used undeclared', chalk.red(`"${undeclared.join('","')}"`)); } } for (let fu in FileUnexists) { let short = fu.replace(configs.moduleIdRemovedPath, '').substring(1); slog.ever('[MXC(checker)]', chalk.grey(short), 'can not find', chalk.red(FileUnexists[fu])); } for (let host in FileStylesGlobalVarUsed) { let short = host.replace(configs.moduleIdRemovedPath, '').substring(1); let dest = FileStylesGlobalVarUsed[host]; let used = usedGlobalVars[host]; for (let key in dest) { if (!used || used[key] != ItemDeclared) { slog.ever('[MXC(checker)]', chalk.grey(short), 'used undeclared', chalk.red(key)); } } } } }