chameleon-linter
Version:
cml规范校验工具
136 lines (126 loc) • 4.02 kB
JavaScript
const parser = require('@babel/parser');
const traverse = require('@babel/traverse')['default'];
const objectBlockStatement = /^\s*{(.*)}\s*$/;
const fakePrefix = 'cml=';
/**
* @param {Object} loc
* @param {Boolean} isFakeBlock
*/
function getStartPos(loc, isFakeBlock = false) {
let pos = [0, 0];
// loc.start.column begins with 0
if (loc && loc.start) {
if (isFakeBlock) {
pos = [loc.start.line, loc.start.column - fakePrefix.length];
} else {
pos = [loc.start.line, loc.start.column];
}
}
return pos;
}
function getVarFromIdentifier(node, isFakeBlock, method = false) {
return {
name: node.name,
method: method,
variable: !method,
pos: getStartPos(node.loc, isFakeBlock)
};
}
module.exports.parseSingleExpression = function(expressinoStr = '') {
let nodes = [];
let ast = null;
let isFakeBlock = false;
/**
* !!We are using babel parser to get an ast of current expression, which takes experssion as
* an entire program. So when we pass something like {a:1,b:3} this will be considered as
* a blockstatement and obviously it contains a syntax error.
* So we wrap the expression we assingment expression in those particular cases.
*/
if (objectBlockStatement.test(expressinoStr)) {
expressinoStr = fakePrefix + expressinoStr;
isFakeBlock = true;
}
try {
ast = parser.parse(expressinoStr);
} catch (err) {
console.trace(err);
}
ast && traverse(ast, {
Identifier(path) {
if (path.parent.type === 'ExpressionStatement') {
nodes.push(getVarFromIdentifier(path.node, isFakeBlock));
}
},
MemberExpression(path) {
if (path.get('object').isIdentifier()) {
nodes.push(getVarFromIdentifier(path.node.object, isFakeBlock));
}
if (path.get('property').isIdentifier() && path.node.computed) {
nodes.push(getVarFromIdentifier(path.node.property, isFakeBlock));
}
},
LogicalExpression(path) {
if (path.get('left').isIdentifier()) {
nodes.push(getVarFromIdentifier(path.node.left, isFakeBlock));
}
if (path.get('right').isIdentifier()) {
nodes.push(getVarFromIdentifier(path.node.right, isFakeBlock));
}
},
BinaryExpression(path) {
if (path.get('left').isIdentifier()) {
nodes.push(getVarFromIdentifier(path.node.left, isFakeBlock));
}
if (path.get('right').isIdentifier()) {
nodes.push(getVarFromIdentifier(path.node.right, isFakeBlock));
}
},
LogicalExpression(path) {
if (path.get('left').isIdentifier()) {
nodes.push(getVarFromIdentifier(path.node.left, isFakeBlock));
}
if (path.get('right').isIdentifier()) {
nodes.push(getVarFromIdentifier(path.node.right, isFakeBlock));
}
},
SequenceExpression(path) {
path.get('expressions').forEach((ele) => {
if (ele.isIdentifier()) {
nodes.push(getVarFromIdentifier(ele.node, isFakeBlock));
}
});
},
ConditionalExpression(path) {
['test', 'alternate', 'consequent'].forEach((key) => {
if (path.get(key).isIdentifier()) {
nodes.push(getVarFromIdentifier(path.node[key], isFakeBlock));
}
});
},
CallExpression(path) {
if (path.get('callee').isIdentifier()) {
nodes.push(getVarFromIdentifier(path.node.callee, isFakeBlock, true));
}
path.get('arguments').forEach((arg) => {
if (arg.isIdentifier()) {
nodes.push(getVarFromIdentifier(arg.node, isFakeBlock));
}
});
},
ArrayExpression(path) {
path.get('elements').forEach((ele) => {
if (ele.isIdentifier()) {
nodes.push(getVarFromIdentifier(ele.node, isFakeBlock));
}
});
},
ObjectExpression(path) {
path.get('properties').forEach((ele) => {
if (ele.isIdentifier()) {
nodes.push(getVarFromIdentifier(ele.node, isFakeBlock));
}
});
}
});
return nodes;
}