magix-composer
Version:
compile html, style and javascript files into javascript
153 lines (151 loc) • 5.47 kB
JavaScript
/*
模板指令处理
*/
let chalk = require('chalk');
let configs = require('./util-config');
let htmlminifier = require('html-minifier');
let jsGeneric = require('./js-generic');
let slog = require('./util-log');
let { htmlminifier: cHTMLMinifier,
tmplStoreIndexKey,
microTmplCommand } = require('./util-const');
//模板文件,模板引擎命令处理,因为我们用的是字符串模板,常见的模板命令如<%=output%> {{output}},这种通常会影响我们的分析,我们先把它们做替换处理
let anchor = '\x07';
let tmplCommandAnchorCompressReg = /(\x07\d+\x07)\s+(?=[<>])/g;
let tmplCommandAnchorCompressReg2 = /([<>])\s+(\x07\d+\x07)/g;
let tmplCommandAnchorReg = /\x07\d+\x07/g;
let emptyCmdReg = /<%\s*%>/g;
let bindReg2 = /(\s*)<%:([\s\S]+?)%>(\s*)/g;
let cmdOutReg = /^<%([@=:])?([\s\S]*)%>$/;
let artCtrlsReg = /^(?:<%'\x17?(\d+)\x11([^\x11]+)\x11\x17?'%>)?(<%[\s\S]+?%>)$/;
let artCtrlsReg1 = /<%'\d+\x11([^\x11]+)\x11'%>(<%[\s\S]+?%>)/g;
module.exports = {
compile(tmpl) {
//特殊处理绑定事件及参数
tmpl = tmpl.replace(bindReg2, (m, left, expr, right) => {
let leftBrace = expr.indexOf('{');
if (leftBrace > 0) {
let fns = expr.substring(leftBrace).trim();
if (fns[fns.length - 1] == ')') {
fns = fns.slice(0, -1);
}
try {
fns = ',' + jsGeneric.parseObject(fns, '\x17', '\x18');
} catch (ex) {
slog.ever(chalk.red('check:' + fns));
}
expr = expr.substring(0, leftBrace).trim();
if (expr[expr.length - 1] == '(') {
expr = expr.slice(0, -1);
}
if (expr.endsWith('&')) {
expr = expr.slice(0, -1);
}
expr += fns;
} else {
let temp = expr.split('&');
if (temp.length > 1) {
// if (temp.length != 2) {
// throw new Error('[MXC Error(tmpl-cmd)] unsupport ' + m);
// }
// let bind = temp[0].trim();
// let rule = temp[1].trim();
let bind = temp.shift().trim();
let rule = temp.join('&');
if (rule.startsWith('(') && rule.endsWith(')')) {
rule = rule.slice(1, -1);
}
expr = `${bind},"\x17\x18",${rule},"\x17"`;
}
}
return (left || '') + '<%:' + expr + '%>' + (right || '');
});
tmpl = tmpl.replace(emptyCmdReg, '');
return tmpl;
},
store(tmpl, dataset, reg) { //保存模板引擎命令
let idx = dataset[tmplStoreIndexKey] || 0;
let regs = [reg, configs.tmplCommand, microTmplCommand];
for (let r of regs) {
if (r) {
tmpl = tmpl.replace(r, (match, key) => {
idx++;
key = anchor + idx + anchor;
dataset[match] = key;
dataset[key] = match;
return key;
});
}
}
dataset[tmplStoreIndexKey] = idx;
return tmpl;
},
tidy(tmpl) { //简单压缩
tmpl = htmlminifier.minify(tmpl, cHTMLMinifier);
if (cHTMLMinifier.collapseWhitespace) {
tmpl = tmpl.replace(tmplCommandAnchorCompressReg, '$1');
tmpl = tmpl.replace(tmplCommandAnchorCompressReg2, '$1$2');
}
return tmpl;
},
recover(tmpl, refTmplCommands, processor) { //恢复替换的命令
return tmpl.replace(tmplCommandAnchorReg, match => {
let value = refTmplCommands[match];
if (processor) {
value = processor(value);
}
return value;
});
},
buildCmd(line, operate, art, content) {
return `<%'${line}\x11${art}\x11'%><%${operate}${content}%>`;
},
toArtCmd(cmd, refTmplCommands) {
return this.recover(cmd, refTmplCommands).replace(artCtrlsReg1, '{{$1}}');
},
extractCmdContent(cmd, refTmplCommands) {
let oc = this.recover(cmd, refTmplCommands);
let am = oc.match(artCtrlsReg);
let old = '', line = -1, art = '';
if (am) {
[, line, art, old] = am;
}
let ocm = old.match(cmdOutReg);
if (ocm) {
if (ocm[2].indexOf('%>') > -1 || ocm[2].indexOf('<%') > -1) {
return {
isArt: !!art,
origin: art || old,
succeed: false
};
}
return {
isArt: !!art,
line,
art,
origin: art || old,
succeed: true,
operate: ocm[1] || '',
content: ocm[2]
};
}
return {
isArt: !!art,
origin: art || old,
succeed: false
};
},
extractRefContent(cmd) {
let idx = cmd.indexOf(`,'\x1e`);
if (idx > -1) {
return {
succeed: true,
vars: cmd.substring(0, idx),
key: cmd.substring(idx + 1)
};
}
return {
succeed: false
}
}
};