Files
codeql-action/node_modules/eslint-module-utils/moduleVisitor.js
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

165 lines
5.3 KiB
JavaScript
Raw Normal View History

2021-07-27 16:54:26 +00:00
'use strict';
2023-08-01 03:35:02 -07:00
2021-07-27 16:54:26 +00:00
exports.__esModule = true;
2020-09-14 10:42:37 +01:00
2024-08-26 17:13:37 +00:00
/** @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 */
2020-09-14 10:42:37 +01:00
/**
* Returns an object of node visitors that will call
* 'visitor' with every discovered module path.
*
2024-08-26 17:13:37 +00:00
* @type {(import('./moduleVisitor').default)}
2020-09-14 10:42:37 +01:00
*/
exports.default = function visitModules(visitor, options) {
2024-08-26 17:13:37 +00:00
const ignore = options && options.ignore;
const amd = !!(options && options.amd);
const commonjs = !!(options && options.commonjs);
2020-09-14 10:42:37 +01:00
// if esmodule is not explicitly disabled, it is assumed to be enabled
2024-08-26 17:13:37 +00:00
const esmodule = !!Object.assign({ esmodule: true }, options).esmodule;
2020-09-14 10:42:37 +01:00
2024-08-26 17:13:37 +00:00
const ignoreRegExps = ignore == null ? [] : ignore.map((p) => new RegExp(p));
2020-09-14 10:42:37 +01:00
2024-08-26 17:13:37 +00:00
/** @type {(source: undefined | null | import('estree').Literal, importer: Parameters<typeof visitor>[1]) => void} */
2020-09-14 10:42:37 +01:00
function checkSourceValue(source, importer) {
2023-08-01 03:35:02 -07:00
if (source == null) { return; } //?
2020-09-14 10:42:37 +01:00
// handle ignore
2024-08-26 17:13:37 +00:00
if (ignoreRegExps.some((re) => re.test(String(source.value)))) { return; }
2020-09-14 10:42:37 +01:00
// fire visitor
2021-07-27 16:54:26 +00:00
visitor(source, importer);
2020-09-14 10:42:37 +01:00
}
// for import-y declarations
2024-08-26 17:13:37 +00:00
/** @type {(node: Declaration) => void} */
2020-09-14 10:42:37 +01:00
function checkSource(node) {
2021-07-27 16:54:26 +00:00
checkSourceValue(node.source, node);
2020-09-14 10:42:37 +01:00
}
// for esmodule dynamic `import()` calls
2024-08-26 17:13:37 +00:00
/** @type {(node: import('estree').ImportExpression | import('estree').CallExpression) => void} */
2020-09-14 10:42:37 +01:00
function checkImportCall(node) {
2024-08-26 17:13:37 +00:00
/** @type {import('estree').Expression | import('estree').Literal | import('estree').CallExpression['arguments'][0]} */
2021-07-27 16:54:26 +00:00
let modulePath;
// refs https://github.com/estree/estree/blob/HEAD/es2020.md#importexpression
2021-07-27 16:54:26 +00:00
if (node.type === 'ImportExpression') {
modulePath = node.source;
} else if (node.type === 'CallExpression') {
2024-08-26 17:13:37 +00:00
// @ts-expect-error this structure is from an older version of eslint
2023-08-01 03:35:02 -07:00
if (node.callee.type !== 'Import') { return; }
if (node.arguments.length !== 1) { return; }
2021-07-27 16:54:26 +00:00
modulePath = node.arguments[0];
2024-08-26 17:13:37 +00:00
} else {
throw new TypeError('this should be unreachable');
2021-07-27 16:54:26 +00:00
}
2020-09-14 10:42:37 +01:00
2023-08-01 03:35:02 -07:00
if (modulePath.type !== 'Literal') { return; }
if (typeof modulePath.value !== 'string') { return; }
2020-09-14 10:42:37 +01:00
2021-07-27 16:54:26 +00:00
checkSourceValue(modulePath, node);
2020-09-14 10:42:37 +01:00
}
// for CommonJS `require` calls
// adapted from @mctep: https://git.io/v4rAu
2024-08-26 17:13:37 +00:00
/** @type {(call: Call) => void} */
2020-09-14 10:42:37 +01:00
function checkCommon(call) {
2023-08-01 03:35:02 -07:00
if (call.callee.type !== 'Identifier') { return; }
if (call.callee.name !== 'require') { return; }
if (call.arguments.length !== 1) { return; }
2020-09-14 10:42:37 +01:00
2021-07-27 16:54:26 +00:00
const modulePath = call.arguments[0];
2023-08-01 03:35:02 -07:00
if (modulePath.type !== 'Literal') { return; }
if (typeof modulePath.value !== 'string') { return; }
2020-09-14 10:42:37 +01:00
2021-07-27 16:54:26 +00:00
checkSourceValue(modulePath, call);
2020-09-14 10:42:37 +01:00
}
2024-08-26 17:13:37 +00:00
/** @type {(call: Call) => void} */
2020-09-14 10:42:37 +01:00
function checkAMD(call) {
2023-08-01 03:35:02 -07:00
if (call.callee.type !== 'Identifier') { return; }
if (call.callee.name !== 'require' && call.callee.name !== 'define') { return; }
if (call.arguments.length !== 2) { return; }
2020-09-14 10:42:37 +01:00
2021-07-27 16:54:26 +00:00
const modules = call.arguments[0];
2023-08-01 03:35:02 -07:00
if (modules.type !== 'ArrayExpression') { return; }
2020-09-14 10:42:37 +01:00
2021-07-27 16:54:26 +00:00
for (const element of modules.elements) {
2024-08-26 17:13:37 +00:00
if (!element) { continue; }
2023-08-01 03:35:02 -07:00
if (element.type !== 'Literal') { continue; }
if (typeof element.value !== 'string') { continue; }
2020-09-14 10:42:37 +01:00
2023-08-01 03:35:02 -07:00
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
}
2020-09-14 10:42:37 +01:00
2021-07-27 16:54:26 +00:00
checkSourceValue(element, element);
2020-09-14 10:42:37 +01:00
}
}
2021-07-27 16:54:26 +00:00
const visitors = {};
2024-08-26 17:13:37 +00:00
if (esmodule) {
2020-09-14 10:42:37 +01:00
Object.assign(visitors, {
2023-08-01 03:35:02 -07:00
ImportDeclaration: checkSource,
ExportNamedDeclaration: checkSource,
ExportAllDeclaration: checkSource,
CallExpression: checkImportCall,
ImportExpression: checkImportCall,
2021-07-27 16:54:26 +00:00
});
2020-09-14 10:42:37 +01:00
}
2024-08-26 17:13:37 +00:00
if (commonjs || amd) {
2023-08-01 03:35:02 -07:00
const currentCallExpression = visitors.CallExpression;
2024-08-26 17:13:37 +00:00
visitors.CallExpression = /** @type {(call: Call) => void} */ function (call) {
2023-08-01 03:35:02 -07:00
if (currentCallExpression) { currentCallExpression(call); }
2024-08-26 17:13:37 +00:00
if (commonjs) { checkCommon(call); }
if (amd) { checkAMD(call); }
2021-07-27 16:54:26 +00:00
};
2020-09-14 10:42:37 +01:00
}
2021-07-27 16:54:26 +00:00
return visitors;
};
2020-09-14 10:42:37 +01:00
/**
2024-08-26 17:13:37 +00:00
* make an options schema for the module visitor, optionally adding extra fields.
* @type {import('./moduleVisitor').makeOptionsSchema}
2020-09-14 10:42:37 +01:00
*/
function makeOptionsSchema(additionalProperties) {
2024-08-26 17:13:37 +00:00
/** @type {import('./moduleVisitor').Schema} */
2020-09-14 10:42:37 +01:00
const base = {
2023-08-01 03:35:02 -07:00
type: 'object',
properties: {
commonjs: { type: 'boolean' },
amd: { type: 'boolean' },
esmodule: { type: 'boolean' },
ignore: {
type: 'array',
minItems: 1,
items: { type: 'string' },
uniqueItems: true,
2020-09-14 10:42:37 +01:00
},
},
2023-08-01 03:35:02 -07:00
additionalProperties: false,
2021-07-27 16:54:26 +00:00
};
2020-09-14 10:42:37 +01:00
if (additionalProperties) {
2021-07-27 16:54:26 +00:00
for (const key in additionalProperties) {
2024-08-26 17:13:37 +00:00
// @ts-expect-error TS always has trouble with arbitrary object assignment/mutation
2021-07-27 16:54:26 +00:00
base.properties[key] = additionalProperties[key];
2020-09-14 10:42:37 +01:00
}
}
2021-07-27 16:54:26 +00:00
return base;
2020-09-14 10:42:37 +01:00
}
2021-07-27 16:54:26 +00:00
exports.makeOptionsSchema = makeOptionsSchema;
2020-09-14 10:42:37 +01:00
/**
2024-08-26 17:13:37 +00:00
* json schema object for options parameter. can be used to build rule options schema object.
2020-09-14 10:42:37 +01:00
*/
2021-07-27 16:54:26 +00:00
exports.optionsSchema = makeOptionsSchema();