codtracker-js/node_modules/eslint/lib/rules/no-mixed-requires.js
2025-04-19 23:12:19 -04:00

268 lines
7.0 KiB
JavaScript

/**
* @fileoverview Rule to enforce grouped require statements for Node.JS
* @author Raphael Pigulla
* @deprecated in ESLint v7.0.0
*/
'use strict';
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
/** @type {import('../types').Rule.RuleModule} */
module.exports = {
meta: {
deprecated: {
message: 'Node.js rules were moved out of ESLint core.',
url: 'https://eslint.org/docs/latest/use/migrating-to-7.0.0#deprecate-node-rules',
deprecatedSince: '7.0.0',
availableUntil: null,
replacedBy: [
{
message:
'eslint-plugin-n now maintains deprecated Node.js-related rules.',
plugin: {
name: 'eslint-plugin-n',
url: 'https://github.com/eslint-community/eslint-plugin-n',
},
rule: {
name: 'no-mixed-requires',
url: 'https://github.com/eslint-community/eslint-plugin-n/tree/master/docs/rules/no-mixed-requires.md',
},
},
],
},
type: 'suggestion',
docs: {
description:
'Disallow `require` calls to be mixed with regular variable declarations',
recommended: false,
url: 'https://eslint.org/docs/latest/rules/no-mixed-requires',
},
schema: [
{
oneOf: [
{
type: 'boolean',
},
{
type: 'object',
properties: {
grouping: {
type: 'boolean',
},
allowCall: {
type: 'boolean',
},
},
additionalProperties: false,
},
],
},
],
messages: {
noMixRequire: "Do not mix 'require' and other declarations.",
noMixCoreModuleFileComputed:
'Do not mix core, module, file and computed requires.',
},
},
create(context) {
const options = context.options[0];
let grouping = false,
allowCall = false;
if (typeof options === 'object') {
grouping = options.grouping;
allowCall = options.allowCall;
} else {
grouping = !!options;
}
/**
* Returns the list of built-in modules.
* @returns {string[]} An array of built-in Node.js modules.
*/
function getBuiltinModules() {
/*
* This list is generated using:
* `require("repl")._builtinLibs.concat('repl').sort()`
* This particular list is as per nodejs v0.12.2 and iojs v0.7.1
*/
return [
'assert',
'buffer',
'child_process',
'cluster',
'crypto',
'dgram',
'dns',
'domain',
'events',
'fs',
'http',
'https',
'net',
'os',
'path',
'punycode',
'querystring',
'readline',
'repl',
'smalloc',
'stream',
'string_decoder',
'tls',
'tty',
'url',
'util',
'v8',
'vm',
'zlib',
];
}
const BUILTIN_MODULES = getBuiltinModules();
const DECL_REQUIRE = 'require',
DECL_UNINITIALIZED = 'uninitialized',
DECL_OTHER = 'other';
const REQ_CORE = 'core',
REQ_FILE = 'file',
REQ_MODULE = 'module',
REQ_COMPUTED = 'computed';
/**
* Determines the type of a declaration statement.
* @param {ASTNode} initExpression The init node of the VariableDeclarator.
* @returns {string} The type of declaration represented by the expression.
*/
function getDeclarationType(initExpression) {
if (!initExpression) {
// "var x;"
return DECL_UNINITIALIZED;
}
if (
initExpression.type === 'CallExpression' &&
initExpression.callee.type === 'Identifier' &&
initExpression.callee.name === 'require'
) {
// "var x = require('util');"
return DECL_REQUIRE;
}
if (
allowCall &&
initExpression.type === 'CallExpression' &&
initExpression.callee.type === 'CallExpression'
) {
// "var x = require('diagnose')('sub-module');"
return getDeclarationType(initExpression.callee);
}
if (initExpression.type === 'MemberExpression') {
// "var x = require('glob').Glob;"
return getDeclarationType(initExpression.object);
}
// "var x = 42;"
return DECL_OTHER;
}
/**
* Determines the type of module that is loaded via require.
* @param {ASTNode} initExpression The init node of the VariableDeclarator.
* @returns {string} The module type.
*/
function inferModuleType(initExpression) {
if (initExpression.type === 'MemberExpression') {
// "var x = require('glob').Glob;"
return inferModuleType(initExpression.object);
}
if (initExpression.arguments.length === 0) {
// "var x = require();"
return REQ_COMPUTED;
}
const arg = initExpression.arguments[0];
if (arg.type !== 'Literal' || typeof arg.value !== 'string') {
// "var x = require(42);"
return REQ_COMPUTED;
}
if (BUILTIN_MODULES.includes(arg.value)) {
// "var fs = require('fs');"
return REQ_CORE;
}
if (/^\.{0,2}\//u.test(arg.value)) {
// "var utils = require('./utils');"
return REQ_FILE;
}
// "var async = require('async');"
return REQ_MODULE;
}
/**
* Check if the list of variable declarations is mixed, i.e. whether it
* contains both require and other declarations.
* @param {ASTNode} declarations The list of VariableDeclarators.
* @returns {boolean} True if the declarations are mixed, false if not.
*/
function isMixed(declarations) {
const contains = {};
declarations.forEach((declaration) => {
const type = getDeclarationType(declaration.init);
contains[type] = true;
});
return !!(
contains[DECL_REQUIRE] &&
(contains[DECL_UNINITIALIZED] || contains[DECL_OTHER])
);
}
/**
* Check if all require declarations in the given list are of the same
* type.
* @param {ASTNode} declarations The list of VariableDeclarators.
* @returns {boolean} True if the declarations are grouped, false if not.
*/
function isGrouped(declarations) {
const found = {};
declarations.forEach((declaration) => {
if (getDeclarationType(declaration.init) === DECL_REQUIRE) {
found[inferModuleType(declaration.init)] = true;
}
});
return Object.keys(found).length <= 1;
}
return {
VariableDeclaration(node) {
if (isMixed(node.declarations)) {
context.report({
node,
messageId: 'noMixRequire',
});
} else if (grouping && !isGrouped(node.declarations)) {
context.report({
node,
messageId: 'noMixCoreModuleFileComputed',
});
}
},
};
},
};