magix-combine
Version:
合并Magix View的html,js,css成一个js文件,并检测html,js,css中可能存在的问题
123 lines • 4.59 kB
JavaScript
/*
检测js代码中的循环嵌套,在以往的代码review中,通常3层以上的循环都可以通过合理的数据结构避免
*/
let slog = require('./util-log');
let configs = require('./util-config');
let chalk = require('chalk');
let loopNames = {
forEach: 1,
map: 1,
filter: 1,
some: 1,
every: 1,
reduce: 1,
reduceRight: 1,
find: 1,
each: 1
};
module.exports = (node, comments, tmpl, e) => {
let outerExprs = [];
let addedOuterExprs = Object.create(null);
let enterFns = Object.create(null);
let uncheck = p => {
while (--p > 0) {
if (comments[p]) {
if (comments[p].text == 'mc-uncheck') {
return true;
}
}
let c = tmpl.charAt(p);
if (c != ' ' &&
c != ';' &&
c != '\r' &&
c != '\n' &&
c != '\t' &&
c != '\f' &&
c != '\v' &&
c != '\u00A0' &&
c != '\uFEFF' &&
c != '\u2028' &&
c != '\u2029') {
return false;
}
}
};
let take = (lc, expr) => {
if (lc >= configs.jsLoopDepth) {
let key = expr.start + '@' + expr.end;
if (!addedOuterExprs[key]) {
addedOuterExprs[key] = 1;
outerExprs.push(expr);
}
return false;
}
return true;
};
let walk = (expr, lc, outerLoop) => {
if (Array.isArray(expr) || expr instanceof Object) {
let walkSub = true;
switch (expr.type) {
case 'ForStatement':
case 'WhileStatement':
case 'DoWhileStatement':
case 'ForOfStatement':
case 'ForInStatement':
if (!uncheck(expr.start)) {
if (!outerLoop) {
outerLoop = expr;
}
lc++;
walkSub = take(lc, outerLoop);
}
break;
case 'CallExpression': //检测是否是[].forEach _.each $.each调用
let args = expr.arguments;
if (args && args.length > 1) {
let a0 = args[0];
let a1 = args[1];
if (a0.type == 'FunctionExpression' ||
a0.type == 'ArrowFunctionExpression' ||
(a1 && (a1.type == 'FunctionExpression' ||
a1.type == 'ArrowFunctionExpression'))) {
let callee = expr.callee;
if (callee.type == 'MemberExpression') {
let p = callee.property;
if (loopNames.hasOwnProperty(p.name)) {
let key = a0.start + '@' + a0.end;
enterFns[key] = 1;
if (!uncheck(expr.start)) {
if (!outerLoop) {
outerLoop = expr;
}
lc++;
walkSub = take(lc, outerLoop);
}
}
}
}
}
break;
}
let key = expr.start + '@' + expr.end;
if (walkSub && (enterFns[key] || (
expr.type != 'FunctionDeclaration' &&
expr.type != 'FunctionExpression' &&
expr.type != 'ArrowFunctionExpression'))) {
if (Array.isArray(expr)) {
for (let i = 0; i < expr.length; i++) {
walk(expr[i], lc, outerLoop);
}
} else if (expr instanceof Object) {
for (let p in expr) {
walk(expr[p], lc, outerLoop);
}
}
}
}
};
walk(node.body.body, 0);
outerExprs.forEach(expr => {
let part = tmpl.substring(expr.start, expr.end);
slog.ever(chalk.magenta('[MXC Tip(checker-js-loop)]'), chalk.red('avoid nested loops'), 'at', chalk.gray(e.shortFrom), 'near\r\n', chalk.magenta(part));
});
};