const t = require('@babel/types') const babelTraverse = require('@babel/traverse').default const { parseComponents } = require('./util') function handleObjectExpression (declaration, path, state) { if (state.options) { // name,inheritAttrs,props Object.keys(state.options).forEach(name => { const optionProperty = declaration.properties.filter(prop => { return t.isObjectProperty(prop) && t.isIdentifier(prop.key) && prop.key.name === name })[0] if (optionProperty) { if (name === 'props') { if (t.isArrayExpression(optionProperty.value)) { state.options[name] = JSON.stringify(optionProperty.value.elements.filter(element => t.isStringLiteral(element)).map(({ value }) => value)) } else if (t.isObjectExpression(optionProperty.value)) { const props = [] optionProperty.value.properties.forEach(({ key }) => { if (t.isIdentifier(key)) { props.push(key.name) } else if (t.isStringLiteral(key)) { props.push(key.value) } }) state.options[name] = JSON.stringify(props) } } else if (t.isStringLiteral(optionProperty.value)) { state.options[name] = JSON.stringify(optionProperty.value.value) } else { state.options[name] = optionProperty.value.value } } }) } const componentsProperty = declaration.properties.filter(prop => { return t.isObjectProperty(prop) && t.isIdentifier(prop.key) && prop.key.name === 'components' })[0] if (componentsProperty && t.isObjectExpression(componentsProperty.value)) { handleComponentsObjectExpression(componentsProperty.value, path, state) } } function handleComponentsObjectExpression (componentsObjExpr, path, state, prepend) { const properties = componentsObjExpr.properties .filter(prop => t.isObjectProperty(prop) && t.isIdentifier(prop.value)) const components = parseComponents(properties.map(prop => { return { name: prop.key.name || prop.key.value, value: prop.value.name } }), path.scope.bindings, path) state.components = prepend ? components.concat(state.components) : components } module.exports = function (ast, state = { type: 'Component', components: [], options: {} }) { babelTraverse(ast, { AssignmentExpression (path) { const leftExpression = path.node.left const rightExpression = path.node.right if ( // global['__wxVueOptions'] = {'van-button':VanButton} t.isMemberExpression(leftExpression) && t.isObjectExpression(rightExpression) && leftExpression.object.name === 'global' && leftExpression.property.value === '__wxVueOptions' ) { handleObjectExpression(rightExpression, path, state) } if ( // exports.default.components = Object.assign({'van-button': VanButton}, exports.default.components || {}) t.isMemberExpression(leftExpression) && t.isCallExpression(rightExpression) && leftExpression.property.name === 'components' && t.isMemberExpression(leftExpression.object) && leftExpression.object.object.name === 'exports' && leftExpression.object.property.name === 'default' && rightExpression.arguments.length === 2 && t.isObjectExpression(rightExpression.arguments[0]) ) { handleComponentsObjectExpression(rightExpression.arguments[0], path, state, true) } }, ExportDefaultDeclaration (path) { const declaration = path.node.declaration if (t.isObjectExpression(declaration)) { // export default {components:{}} handleObjectExpression(declaration, path, state) } else if (t.isCallExpression(declaration) && t.isMemberExpression(declaration.callee) && declaration.arguments.length === 1) { // export default Vue.extend({components:{}}) if (declaration.callee.object.name === 'Vue' && declaration.callee.property.name === 'extend') { handleObjectExpression(declaration.arguments[0], path, state) } } else if (t.isClassDeclaration(declaration) && declaration.decorators && declaration.decorators.length) { // export default @Component({components:{}}) class MyComponent extend Vue const componentDecorator = declaration.decorators[0] if (t.isCallExpression(componentDecorator.expression)) { const args = componentDecorator.expression.arguments if (args && args.length && t.isObjectExpression(args[0])) { handleObjectExpression(args[0], path, state) } } } } }) return { ast, state } }