scoped-component-traverse.js 4.8 KB
Newer Older
fxy060608's avatar
fxy060608 已提交
1 2 3 4 5 6 7 8
const t = require('@babel/types')
const babelTraverse = require('@babel/traverse').default

const {
  parseComponents
} = require('./util')

function handleObjectExpression (declaration, path, state) {
9
  if (state.options) { // name,inheritAttrs,props
fxy060608's avatar
fxy060608 已提交
10 11 12 13 14 15 16
    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) {
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
        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)) {
fxy060608's avatar
fxy060608 已提交
32 33 34 35 36 37 38 39
          state.options[name] = JSON.stringify(optionProperty.value.value)
        } else {
          state.options[name] = optionProperty.value.value
        }
      }
    })
  }

fxy060608's avatar
fxy060608 已提交
40 41
  const componentsProperty = declaration.properties.filter(prop => {
    return t.isObjectProperty(prop) &&
fxy060608's avatar
fxy060608 已提交
42 43
      t.isIdentifier(prop.key) &&
      prop.key.name === 'components'
fxy060608's avatar
fxy060608 已提交
44 45 46
  })[0]

  if (componentsProperty && t.isObjectExpression(componentsProperty.value)) {
fxy060608's avatar
fxy060608 已提交
47
    handleComponentsObjectExpression(componentsProperty.value, path, state)
fxy060608's avatar
fxy060608 已提交
48 49 50
  }
}

51
function handleComponentsObjectExpression (componentsObjExpr, path, state, prepend) {
fxy060608's avatar
fxy060608 已提交
52 53
  const properties = componentsObjExpr.properties
    .filter(prop => t.isObjectProperty(prop) && t.isIdentifier(prop.value))
54
  const components = parseComponents(properties.map(prop => {
fxy060608's avatar
fxy060608 已提交
55 56 57 58 59
    return {
      name: prop.key.name || prop.key.value,
      value: prop.value.name
    }
  }), path.scope.bindings, path)
60
  state.components = prepend ? components.concat(state.components) : components
fxy060608's avatar
fxy060608 已提交
61 62
}

fxy060608's avatar
fxy060608 已提交
63 64
module.exports = function (ast, state = {
  type: 'Component',
fxy060608's avatar
fxy060608 已提交
65 66
  components: [],
  options: {}
fxy060608's avatar
fxy060608 已提交
67 68
}) {
  babelTraverse(ast, {
fxy060608's avatar
fxy060608 已提交
69
    AssignmentExpression (path) {
fxy060608's avatar
fxy060608 已提交
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
      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])
fxy060608's avatar
fxy060608 已提交
91
      ) {
92
        handleComponentsObjectExpression(rightExpression.arguments[0], path, state, true)
fxy060608's avatar
fxy060608 已提交
93 94
      }
    },
fxy060608's avatar
fxy060608 已提交
95 96 97 98 99
    ExportDefaultDeclaration (path) {
      const declaration = path.node.declaration
      if (t.isObjectExpression(declaration)) { // export default {components:{}}
        handleObjectExpression(declaration, path, state)
      } else if (t.isCallExpression(declaration) &&
fxy060608's avatar
fxy060608 已提交
100 101
        t.isMemberExpression(declaration.callee) &&
        declaration.arguments.length === 1) { // export default Vue.extend({components:{}})
fxy060608's avatar
fxy060608 已提交
102
        if (declaration.callee.object.name === 'Vue' && declaration.callee.property.name ===
fxy060608's avatar
fxy060608 已提交
103
          'extend') {
fxy060608's avatar
fxy060608 已提交
104 105 106
          handleObjectExpression(declaration.arguments[0], path, state)
        }
      } else if (t.isClassDeclaration(declaration) &&
fxy060608's avatar
fxy060608 已提交
107 108
        declaration.decorators &&
        declaration.decorators.length) { // export default @Component({components:{}}) class MyComponent extend Vue
fxy060608's avatar
fxy060608 已提交
109 110 111 112 113 114 115 116 117 118 119 120 121 122
        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
  }
123
}