130 lines
3.3 KiB
JavaScript
130 lines
3.3 KiB
JavaScript
|
"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) {
|
||
|
if (source == null) return //?
|
||
|
|
||
|
// handle ignore
|
||
|
if (ignoreRegExps.some(re => re.test(source.value))) return
|
||
|
|
||
|
// fire visitor
|
||
|
visitor(source)
|
||
|
}
|
||
|
|
||
|
// for import-y declarations
|
||
|
function checkSource(node) {
|
||
|
checkSourceValue(node.source)
|
||
|
}
|
||
|
|
||
|
// 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)
|
||
|
}
|
||
|
|
||
|
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)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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.
|
||
|
|
||
|
* @param {[type]} additionalProperties [description]
|
||
|
* @return {[type]} [description]
|
||
|
*/
|
||
|
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()
|