UNPKG

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