123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- 'use strict';
- exports.__esModule = true;
- /** @typedef {import('estree').Node} Node */
- /** @typedef {{ arguments: import('estree').CallExpression['arguments'], callee: Node }} Call */
- /** @typedef {import('estree').ImportDeclaration | import('estree').ExportNamedDeclaration | import('estree').ExportAllDeclaration} Declaration */
- /**
- * Returns an object of node visitors that will call
- * 'visitor' with every discovered module path.
- *
- * @type {(import('./moduleVisitor').default)}
- */
- exports.default = function visitModules(visitor, options) {
- const ignore = options && options.ignore;
- const amd = !!(options && options.amd);
- const commonjs = !!(options && options.commonjs);
- // if esmodule is not explicitly disabled, it is assumed to be enabled
- const esmodule = !!Object.assign({ esmodule: true }, options).esmodule;
- const ignoreRegExps = ignore == null ? [] : ignore.map((p) => new RegExp(p));
- /** @type {(source: undefined | null | import('estree').Literal, importer: Parameters<typeof visitor>[1]) => void} */
- function checkSourceValue(source, importer) {
- if (source == null) { return; } //?
- // handle ignore
- if (ignoreRegExps.some((re) => re.test(String(source.value)))) { return; }
- // fire visitor
- visitor(source, importer);
- }
- // for import-y declarations
- /** @type {(node: Declaration) => void} */
- function checkSource(node) {
- checkSourceValue(node.source, node);
- }
- // for esmodule dynamic `import()` calls
- /** @type {(node: import('estree').ImportExpression | import('estree').CallExpression) => void} */
- function checkImportCall(node) {
- /** @type {import('estree').Expression | import('estree').Literal | import('estree').CallExpression['arguments'][0]} */
- let modulePath;
- // refs https://github.com/estree/estree/blob/HEAD/es2020.md#importexpression
- if (node.type === 'ImportExpression') {
- modulePath = node.source;
- } else if (node.type === 'CallExpression') {
- // @ts-expect-error this structure is from an older version of eslint
- if (node.callee.type !== 'Import') { return; }
- if (node.arguments.length !== 1) { return; }
- modulePath = node.arguments[0];
- } else {
- throw new TypeError('this should be unreachable');
- }
- if (modulePath.type !== 'Literal') { return; }
- if (typeof modulePath.value !== 'string') { return; }
- checkSourceValue(modulePath, node);
- }
- // for CommonJS `require` calls
- // adapted from @mctep: https://git.io/v4rAu
- /** @type {(call: Call) => void} */
- 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);
- }
- /** @type {(call: Call) => void} */
- 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 (const element of modules.elements) {
- if (!element) { continue; }
- if (element.type !== 'Literal') { continue; }
- if (typeof element.value !== 'string') { continue; }
- if (
- element.value === 'require'
- || element.value === 'exports'
- ) {
- continue; // magic modules: https://github.com/requirejs/requirejs/wiki/Differences-between-the-simplified-CommonJS-wrapper-and-standard-AMD-define#magic-modules
- }
- checkSourceValue(element, element);
- }
- }
- const visitors = {};
- if (esmodule) {
- Object.assign(visitors, {
- ImportDeclaration: checkSource,
- ExportNamedDeclaration: checkSource,
- ExportAllDeclaration: checkSource,
- CallExpression: checkImportCall,
- ImportExpression: checkImportCall,
- });
- }
- if (commonjs || amd) {
- const currentCallExpression = visitors.CallExpression;
- visitors.CallExpression = /** @type {(call: Call) => void} */ function (call) {
- if (currentCallExpression) { currentCallExpression(call); }
- if (commonjs) { checkCommon(call); }
- if (amd) { checkAMD(call); }
- };
- }
- return visitors;
- };
- /**
- * make an options schema for the module visitor, optionally adding extra fields.
- * @type {import('./moduleVisitor').makeOptionsSchema}
- */
- function makeOptionsSchema(additionalProperties) {
- /** @type {import('./moduleVisitor').Schema} */
- 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 (const key in additionalProperties) {
- // @ts-expect-error TS always has trouble with arbitrary object assignment/mutation
- 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.
- */
- exports.optionsSchema = makeOptionsSchema();
|