Blame view

node_modules/eslint-module-utils/moduleVisitor.js 3.25 KB
ce4c83ff   wxy   初始提交
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
  'use strict'
  exports.__esModule = true
  
  /**
   * Returns an object of node visitors that will call
   * 'visitor' with every discovered module path.
   *
   * todo: correct function prototype for visitor
   * @param  {Function(String)} visitor [description]
   * @param  {[type]} options [description]
   * @return {object}
   */
  exports.default = function visitModules(visitor, options) {
    // if esmodule is not explicitly disabled, it is assumed to be enabled
    options = Object.assign({ esmodule: true }, options)
  
    let ignoreRegExps = []
    if (options.ignore != null) {
      ignoreRegExps = options.ignore.map(p => new RegExp(p))
    }
  
    function checkSourceValue(source, importer) {
      if (source == null) return //?
  
      // handle ignore
      if (ignoreRegExps.some(re => re.test(source.value))) return
  
      // fire visitor
      visitor(source, importer)
    }
  
    // for import-y declarations
    function checkSource(node) {
      checkSourceValue(node.source, node)
    }
  
    // for CommonJS `require` calls
    // adapted from @mctep: http://git.io/v4rAu
    function checkCommon(call) {
      if (call.callee.type !== 'Identifier') return
      if (call.callee.name !== 'require') return
      if (call.arguments.length !== 1) return
  
      const modulePath = call.arguments[0]
      if (modulePath.type !== 'Literal') return
      if (typeof modulePath.value !== 'string') return
  
      checkSourceValue(modulePath, call)
    }
  
    function checkAMD(call) {
      if (call.callee.type !== 'Identifier') return
      if (call.callee.name !== 'require' &&
          call.callee.name !== 'define') return
      if (call.arguments.length !== 2) return
  
      const modules = call.arguments[0]
      if (modules.type !== 'ArrayExpression') return
  
      for (let element of modules.elements) {
        if (element.type !== 'Literal') continue
        if (typeof element.value !== 'string') continue
  
        if (element.value === 'require' ||
            element.value === 'exports') continue // magic modules: http://git.io/vByan
  
        checkSourceValue(element, element)
      }
    }
  
    const visitors = {}
    if (options.esmodule) {
      Object.assign(visitors, {
        'ImportDeclaration': checkSource,
        'ExportNamedDeclaration': checkSource,
        'ExportAllDeclaration': checkSource,
      })
    }
  
    if (options.commonjs || options.amd) {
      visitors['CallExpression'] = function (call) {
        if (options.commonjs) checkCommon(call)
        if (options.amd) checkAMD(call)
      }
    }
  
    return visitors
  }
  
  /**
   * make an options schema for the module visitor, optionally
   * adding extra fields.
   */
  function makeOptionsSchema(additionalProperties) {
    const base =  {
      'type': 'object',
      'properties': {
        'commonjs': { 'type': 'boolean' },
        'amd': { 'type': 'boolean' },
        'esmodule': { 'type': 'boolean' },
        'ignore': {
          'type': 'array',
          'minItems': 1,
          'items': { 'type': 'string' },
          'uniqueItems': true,
        },
      },
      'additionalProperties': false,
    }
  
    if (additionalProperties){
      for (let key in additionalProperties) {
        base.properties[key] = additionalProperties[key]
      }
    }
  
    return base
  }
  exports.makeOptionsSchema = makeOptionsSchema
  
  /**
   * json schema object for options parameter. can be used to build
   * rule options schema object.
   * @type {Object}
   */
  exports.optionsSchema = makeOptionsSchema()