@yugu/gogocode
Version:
The simplest tool to parse/transform/generate code on ast
141 lines (134 loc) • 5.34 kB
JavaScript
// 把简单的api转换成ast
// todo await
const recast = require('recast-yx');
const parse = require('./parse');
const visit = recast.types.visit;
const filterProps = require('./filter-prop.js');
function getSelector(selectorCode, parseOptions, expando) {
const selector = { nodeType: '', structure: {} };
if (typeof selectorCode != 'string') {
// 如果是通过builders造出来的ast结构,比如return语句
selector.nodeType = selectorCode.type;
filterProps(selectorCode, selector.structure, '', expando);
selector.type = selectorCode.type; // 兼容只用type匹配的选择器
return selector;
} else {
selectorCode = selectorCode
.replace(/\$_\$/g, expando)
.replace(/\$\$\$/g, expando.slice(0, -1) + '$3')
.replace(/\/\$_\/\$/g, '$_$')
.replace(/\/\$\/\$\/\$/g, '$$$$$$')
}
if (selectorCode.match(/^{((.|\s)+(:|\(\))(.|\s)+)+}$/)) {
// 如果是对象字面量
let ast = parse(`var o = ${selectorCode}`);
ast = ast.program.body[0].declarations[0].init;
selector.nodeType = 'ObjectExpression';
filterProps(ast, selector.structure);
return selector;
}
let seletorAst;
try {
seletorAst = parse(selectorCode, parseOptions);
if (seletorAst.program.body.length == 0) {
// 开头的字符串会被解析成directive
if (seletorAst.program.directives.length) {
return {
nodeType: 'StringLiteral',
structure: {
value: selectorCode ? selectorCode.slice(1, -1) : ''
}
}
} else if (seletorAst.program.comments.length) {
let ast = seletorAst.program.comments[0]
selector.nodeType = ast.type;
filterProps(ast, selector.structure);
return selector;
}
} else if (seletorAst.program.body[0] && seletorAst.program.body[0].type == 'LabeledStatement') {
throw new Error('Missing semicolon')
}
} catch(e) {
// 可能是对象属性
try {
seletorAst = parse(`({${selectorCode}})`, parseOptions);
seletorAst = seletorAst.program.body[0].expression.properties[0]
} catch(e) {
seletorAst = null;
}
// 可能是类属性
let clsSelectorAst = null;
try {
clsSelectorAst = parse(`class a$_$ { ${selectorCode} }`, parseOptions)
clsSelectorAst = clsSelectorAst.program.body[0].body.body[0]
} catch(e) {
//
}
const result = [seletorAst, clsSelectorAst]
.filter(s => !!s)
.map(sel => {
const selector = {
nodeType: sel.type,
structure: {}
}
filterProps(sel, selector.structure)
return selector;
})
if (result.length) {
return result;
} else {
throw new Error('parse error!' + e.message);
}
}
visit(seletorAst, {
visitExpressionStatement(path) {
const expression = path.value.expression;
if (!expression) return;
selector.nodeType = expression.type;
filterProps(expression, selector.structure);
this.abort();
},
visitStatement(path) {
const expression = path.value;
if (!expression) return;
selector.nodeType = expression.type;
filterProps(expression, selector.structure);
this.abort();
},
visitDeclaration(path) {
const declaration = path.value;
if (!declaration) return;
selector.nodeType = declaration.type;
filterProps(declaration, selector.structure);
this.abort();
}
});
if (selector.nodeType == 'AssignmentExpression') {
// class中的属性
try {
const selectorAstList = [selector]
const classPropSelector = { nodeType: '', structure: {} };
const classPropSelectorAst = parse(`class A { ${selectorCode } }`, parseOptions).program.body[0].body.body[0]
classPropSelector.nodeType = classPropSelectorAst.type;
filterProps(classPropSelectorAst, classPropSelector.structure);
selectorAstList.push(classPropSelector);
return selectorAstList;
} catch(e) {
//
}
} else if (selector.nodeType == 'MemberExpression') {
try {
const selectorAstList = [selector]
const classPropSelector = { nodeType: '', structure: {} };
const classPropSelectorAst = parse(`type a = ${selectorCode}`, parseOptions).program.body[0].typeAnnotation.typeName
classPropSelector.nodeType = classPropSelectorAst.type;
filterProps(classPropSelectorAst, classPropSelector.structure);
selectorAstList.push(classPropSelector);
return selectorAstList;
} catch(e) {
// maybe selectorCode = this.xxx
}
}
return selector;
}
module.exports = getSelector;