UNPKG

gogoast

Version:

The simplest tool to parse/transform/generate code by ast

117 lines (111 loc) 4.42 kB
// 通过简单ast结构查找ast节点 const recast = require('recast'); const visit = recast.types.visit; const filterProps = require('./filter-prop.js'); const hasOwn = Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty); function checkIsMatch(full, partial, extraData, strictSequence) { return Object.keys(partial).every(prop => { if (!full || !partial) { // 这个分支存疑,不知道会不会有bug return false; } else if (isObject(partial[prop])) { let res = false; if (Array.isArray(partial[prop]) && !strictSequence) { if (hasOwn(full, prop)) { res = partial[prop].every(p => { let a = false; full[prop] && full[prop].forEach(f => { if (f && f.type == 'ObjectProperty') { // 兼容 { a: 1 } 匹配 { 'a': 1 } 这种情况 f.key.name && (f.key.value = f.key.name); f.key.value && (f.key.name = f.key.value); } if (checkIsMatch(f, p, extraData, strictSequence)) { a = true; } }); return a; }); } else { res = false; } } else { // todo try { res = hasOwn(full, prop) && checkIsMatch(full[prop], partial[prop], extraData, strictSequence); } catch (e) { console.log(e) } } return res; } else { if (partial[prop] == '$_$') { let extra = { structure: full }; if (!full) return; switch (full.type) { case 'ThisExpression': extra.value = 'this'; break; case 'StringLiteral': extra.value = full.value; break; default: if (full[prop]) { extra.value = full[prop]; } else { extra.value = {}; filterProps(full, extra.value); } } extraData.push(extra); return true; } else if (partial[prop]) { const reg = /^(?:\$\[).*(?=\]\$)/; } if (full && full.type == 'ObjectProperty') { // 兼容 { a: 1 } 匹配 { 'a': 1 } 这种情况 full.key.name && (full.key.value = full.key.name); full.key.value && (full.key.name = full.key.value); } return full ? full[prop] == partial[prop] : false; } }); } function isObject(value) { return typeof value === 'object' && value; } function find(nodeType, structure, strictSequence = false, deep = 'nn') { const nodePathList = []; const matchWildCardList = []; let isMatch = false; const ast = this; visit(ast, { [`visit${nodeType}`](path) { const extraData = []; if (deep != 'n' || path.parent.name == 'program') { isMatch = checkIsMatch(path.value, structure, extraData, strictSequence); } else { isMatch = false } if (isMatch) { nodePathList.push(path); matchWildCardList.push(extraData); } switch (deep) { case '1': this.abort(); case 'n': return false; case 'nn': this.traverse(path); default: return false; } } }); return { nodePathList, matchWildCardList }; } module.exports = { find, visit };