zelda-ast
Version:
zelda static analysis based on javascript ast.
127 lines (98 loc) • 3.7 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _jscodeshift = require('jscodeshift');
var _jscodeshift2 = _interopRequireDefault(_jscodeshift);
var _Collection = require('jscodeshift/src/Collection');
var _Collection2 = _interopRequireDefault(_Collection);
var _lodash = require('lodash.once');
var _lodash2 = _interopRequireDefault(_lodash);
var _assert = require('assert');
var _assert2 = _interopRequireDefault(_assert);
var _Helper = require('./Helper');
var _Helper2 = _interopRequireDefault(_Helper);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
_Helper2.default.register();
const methods = {
findRouters() {
if (!this.hasModule('dva/router')) return _Collection2.default.fromPaths([], this);
return this.find(_jscodeshift2.default.JSXElement, {
openingElement: {
name: {
type: 'JSXIdentifier',
name: 'Router'
}
}
});
},
// TODO: support config router with JavaScript Object
getRouterInfo() {
const routeByIds = {};
const ROUTER_COMPONENTS = ['Router', 'Route', 'Switch', 'Redirect', 'IndexRedirect', 'IndexRoute'];
function parse(node, parentPath = '', parentId, parentDepth = -1) {
(0, _assert2.default)(node.type === 'JSXElement', `getRouterTree: node should be JSXElement, but got ${node.type}`);
const name = node.openingElement.name.name;
(0, _assert2.default)(ROUTER_COMPONENTS.indexOf(name) > -1, `getRouterTree: component should be one of ${ROUTER_COMPONENTS.join(', ')}`);
const ret = { type: name };
ret.depth = parentDepth + 1;
ret.attributes = (0, _jscodeshift2.default)(node.openingElement).find(_jscodeshift2.default.JSXAttribute).simpleMap(path => {
const node = path.node;
return {
name: node.name.name,
value: getAttributeValue(node.value)
};
}).reduce((memo, { name, value }) => {
memo[name] = value;
return memo;
}, {});
const path = ret.attributes.path;
if (path) {
ret.absolutePath = path.charAt(0) === '/' ? path : `${parentPath}/${path}`;
}
if (ret.absolutePath) {
ret.id = `${ret.type}-${ret.absolutePath}`;
} else if (parentId) {
ret.id = `${ret.type}-parentId_${parentId}`;
} else {
ret.id = `${ret.type}-root`;
}
// 有些特殊情况 id 会重复(同样的父子路由,出现在多处,可能父亲的父亲不一样)
if (routeByIds[ret.id]) {
ret.id = `${ret.id}_${Math.random()}`;
}
if (node.children) {
ret.children = node.children.filter(node => node.type === 'JSXElement').map(node => parse(node, ret.attributes.path, ret.id, ret.depth));
}
routeByIds[ret.id] = ret;
return {
id: ret.id,
children: ret.children
};
}
function getAttributeValue(node) {
if (node) {
if (node.type === 'Literal') {
return node.value;
} else if (node.expression.type === 'Identifier') {
return node.expression.name;
} else if (node.type === 'JSXExpressionContainer') {
return (0, _jscodeshift2.default)(node.expression).toSource();
}
throw new Error(`getRouterTree: unsupported attribute type`);
}
return null;
}
return this.simpleMap(path => ({
tree: parse(path.node),
routeByIds
}));
}
};
function register(jscodeshift = _jscodeshift2.default) {
jscodeshift.registerMethods(methods);
}
exports.default = {
register: (0, _lodash2.default)(register)
};
module.exports = exports['default'];