magix-composer
Version:
compile html, style and javascript files into javascript
120 lines (117 loc) • 3.83 kB
JavaScript
//https://github.com/marcosbasualdo/UnclosedHtmlTags/blob/master/index.js
//let chalk = require('chalk');
//let slog = require('./util-log');
let configs = require('./util-config');
let htmlParser = require('./html-parser');
//let tmplCmd = require('./tmpl-cmd');
let commentReg = /<!--[\s\S]*?-->/g;
let tagRemovedReg = /<(style|script)[^>]*>[\s\S]*?<\/\1>/g;
let tagReg = /<(\/)?([a-z0-9\-.:_\x11]+)/ig;
let brReg = /(?:\r\n|\r|\n)/;
let { microTmplCommand,
quickGroupTagName,
quickSourceArt } = require('./util-const');
let hdreg = /\x1f\d+\s*\x1f/g;
let brPlaceholder = (m, store) => {
let count = m.split(brReg).length;
let key = `\x1f${++store.__idx}${new Array(count).join('\n')}\x1f`;
store[key] = m;
return key;
};
let cleanHTML = (tmpl, store) => {
tmpl = tmpl.replace(commentReg, m => {
return brPlaceholder(m, store);
}).replace(tagRemovedReg, m => {
return brPlaceholder(m, store);
});
tmpl = tmpl.replace(microTmplCommand, m => {
return brPlaceholder(m, store);
});
if (configs.tmplCommand) {
tmpl = tmpl.replace(configs.tmplCommand, m => {
return brPlaceholder(m, store);
});
}
return tmpl;
};
let markLine = tmpl => {
tmpl = tmpl.replace(tagReg, (m, close, name) => {
return `<${close || ''}${name} mc:line`;
});
return tmpl;
};
let lineReg = /mc:line/g;
let setLineNo = (tmpl, no) => {
return tmpl.replace(lineReg, 'mc:line=' + no);
};
let lineNoReg = /\smc:line=(\d+)/;
let lineNoGReg = /\smc:line=\d+/g;
let readLineNo = tmpl => {
let m = tmpl.match(lineNoReg);
if (m) {
return m[1];
}
return 'unknown';
};
module.exports = (tmpl, e) => {
let store = Object.create(null);
store.__idx = 0;
tmpl = cleanHTML(tmpl, store);
tmpl = markLine(tmpl);
let tags = [];
let lines = tmpl.split(brReg);
let lineCount = 1;
let newLines = [];
for (let line of lines) {
newLines.push(setLineNo(line, lineCount++));
}
tmpl = newLines.join('');
htmlParser(tmpl, {
start(tag, { unary, attrsMap, start, end }) {
let a = tmpl.slice(start, end);
let prefix = 'open tag';
if (tag == quickGroupTagName) {
a = `"{{${attrsMap[quickSourceArt]}}}"`;
prefix = 'art ctrl';
}
if (!unary) {
tags.push({
line: attrsMap['mc:line'],
match: a,
prefix,
name: tag
});
}
},
end(tag, { start, end }) {
let m = tmpl.slice(start, end);
let no = readLineNo(m);
tags.push({
line: no,
close: true,
match: m,
name: tag
});
}
});
let tagsStack = [];
let recover = str => str.replace(lineNoGReg, '').replace(hdreg, m => store[m]);
for (let tag of tags) {
if (tag.close) {
if (!tagsStack.length) {
throw new Error(`[MXC Error(checker-tmpl-unmatch)] "${recover(tag.match)}" doesn't have corresponding open tag at line ${tag.line}`);
}
let last = tagsStack.pop();
if (tag.name != last.name) {
let before = `${last.prefix} ${recover(last.match)}`;
let current = recover(tag.match);
throw new Error(`[MXC Error(checker-tmpl-unmatch)] "${current}" at line ${tag.line} doesn't match ${before} at line ${last.line}`);
}
} else {
tagsStack.push(tag);
}
}
for (let tag of tagsStack) {
throw new Error(`[MXC Error(checker-tmpl-unmatch)] unclosed tag "${recover(tag.match)}" at line ${tag.line}`);
}
};