magix-combine
Version:
合并Magix View的html,js,css成一个js文件,并检测html,js,css中可能存在的问题
180 lines (177 loc) • 5.94 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 consts = require('./util-const');
//let selfCloseTags = require('./html-selfclose-tags');
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(consts.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, attrs, unary, { attrsMap, start, end }) {
let a = tmpl.slice(start, end);
if (!unary) {
tags.push({
line: attrsMap['mc:line'],
match: a,
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 isClosed = (currentLine, offset) => {
let i = currentLine.indexOf('>', offset),
closed = false, results = [];
if (i == -1) {
let start = lineCount;
while (start < lines.length) {//从当前行向后查找'>'结束
let current = lines[start++];
i = current.indexOf('>');
if (i > -1) {
results.push(current.substring(0, i));
break;
} else {
results.push(current);
}
}
} else {
results.push(currentLine.substring(offset, i));
}
let near = results.join('');//当前标签的片断
let found = null;
i = near.length;
while (i) {//从后向前查'/'自闭合
found = near.charAt(--i);
if (found == '/') {
closed = true;
break;
}
if (found.trim()) {
break;
}
}
return closed;
};
console.log(lines);
for (let line of lines) {
line.replace(tagReg, (m, close, name, offset) => {
if (selfCloseTags.hasOwnProperty(name)) {
// close = isClosed(line, offset);
// if (!close) {
// slog.ever(chalk.red('tag ' + name + ' recommand closed at line: ' + lineCount), 'at file', chalk.magenta(e.shortHTMLFile));
// }
return;
}
let check = true;
if (!close) {
close = isClosed(line, offset);
if (close) {
check = false;
}
}
if (check) {
tags.push({
line: lineCount,
close: !!close,
match: m,
name: name
});
}
});
lineCount++;
}*/
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 = `open tag "${recover(last.match)}"`;
if (last.name.startsWith('art\x11')) {
before = `art "${last.close ? '/' : ''}${last.name.substring(4)}"`;
}
let current = recover(tag.match);
if (tag.name.startsWith('art\x11')) {
current = `art "${tag.close ? '/' : ''}${tag.name.substring(4)}"`;
}
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}`);
}
};