tools: add no-duplicate-requires rule
PR-URL: https://github.com/nodejs/node/pull/21712 Reviewed-By: Richard Lau <riclau@uk.ibm.com> Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com> Reviewed-By: Weijia Wang <starkwang@126.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Jon Moss <me@jonathanmoss.me>
This commit is contained in:
parent
1849a2b2e9
commit
8cae9b2ff8
@ -98,6 +98,7 @@ module.exports = {
|
|||||||
'no-dupe-class-members': 'error',
|
'no-dupe-class-members': 'error',
|
||||||
'no-dupe-keys': 'error',
|
'no-dupe-keys': 'error',
|
||||||
'no-duplicate-case': 'error',
|
'no-duplicate-case': 'error',
|
||||||
|
'no-duplicate-imports': 'error',
|
||||||
'no-empty-character-class': 'error',
|
'no-empty-character-class': 'error',
|
||||||
'no-ex-assign': 'error',
|
'no-ex-assign': 'error',
|
||||||
'no-extra-boolean-cast': 'error',
|
'no-extra-boolean-cast': 'error',
|
||||||
@ -246,6 +247,7 @@ module.exports = {
|
|||||||
|
|
||||||
// Custom rules from eslint-plugin-node-core
|
// Custom rules from eslint-plugin-node-core
|
||||||
'node-core/no-unescaped-regexp-dot': 'error',
|
'node-core/no-unescaped-regexp-dot': 'error',
|
||||||
|
'node-core/no-duplicate-requires': 'error',
|
||||||
},
|
},
|
||||||
globals: {
|
globals: {
|
||||||
Atomics: false,
|
Atomics: false,
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
const common = require('../common.js');
|
const common = require('../common.js');
|
||||||
const Duplex = require('stream').Duplex;
|
const {
|
||||||
const Readable = require('stream').Readable;
|
Duplex,
|
||||||
const Transform = require('stream').Transform;
|
Readable,
|
||||||
const Writable = require('stream').Writable;
|
Transform,
|
||||||
|
Writable,
|
||||||
|
} = require('stream');
|
||||||
|
|
||||||
const bench = common.createBenchmark(main, {
|
const bench = common.createBenchmark(main, {
|
||||||
n: [50e6],
|
n: [50e6],
|
||||||
|
@ -286,7 +286,7 @@ For example:
|
|||||||
```js
|
```js
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
const {
|
const {
|
||||||
Worker, MessageChannel, MessagePort, isMainThread
|
Worker, MessageChannel, MessagePort, isMainThread, parentPort
|
||||||
} = require('worker_threads');
|
} = require('worker_threads');
|
||||||
if (isMainThread) {
|
if (isMainThread) {
|
||||||
const worker = new Worker(__filename);
|
const worker = new Worker(__filename);
|
||||||
@ -296,7 +296,7 @@ if (isMainThread) {
|
|||||||
console.log('received:', value);
|
console.log('received:', value);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
require('worker_threads').once('message', (value) => {
|
parentPort.once('message', (value) => {
|
||||||
assert(value.hereIsYourPort instanceof MessagePort);
|
assert(value.hereIsYourPort instanceof MessagePort);
|
||||||
value.hereIsYourPort.postMessage('the worker is sending this');
|
value.hereIsYourPort.postMessage('the worker is sending this');
|
||||||
value.hereIsYourPort.close();
|
value.hereIsYourPort.close();
|
||||||
|
@ -24,8 +24,12 @@ const { kIncomingMessage } = require('_http_common');
|
|||||||
const { kServerResponse } = require('_http_server');
|
const { kServerResponse } = require('_http_server');
|
||||||
const { StreamWrap } = require('_stream_wrap');
|
const { StreamWrap } = require('_stream_wrap');
|
||||||
|
|
||||||
const { defaultTriggerAsyncIdScope } = require('internal/async_hooks');
|
const {
|
||||||
const { async_id_symbol } = require('internal/async_hooks').symbols;
|
defaultTriggerAsyncIdScope,
|
||||||
|
symbols: {
|
||||||
|
async_id_symbol,
|
||||||
|
},
|
||||||
|
} = require('internal/async_hooks');
|
||||||
const { internalBinding } = require('internal/bootstrap/loaders');
|
const { internalBinding } = require('internal/bootstrap/loaders');
|
||||||
const {
|
const {
|
||||||
codes: {
|
codes: {
|
||||||
|
@ -14,13 +14,14 @@ const fs = require('fs');
|
|||||||
const { _makeLong } = require('path');
|
const { _makeLong } = require('path');
|
||||||
const { SafeMap } = require('internal/safe_globals');
|
const { SafeMap } = require('internal/safe_globals');
|
||||||
const { URL } = require('url');
|
const { URL } = require('url');
|
||||||
const util = require('util');
|
const { debuglog, promisify } = require('util');
|
||||||
const debug = util.debuglog('esm');
|
const readFileAsync = promisify(fs.readFile);
|
||||||
const readFileAsync = util.promisify(fs.readFile);
|
|
||||||
const readFileSync = fs.readFileSync;
|
const readFileSync = fs.readFileSync;
|
||||||
const StringReplace = Function.call.bind(String.prototype.replace);
|
const StringReplace = Function.call.bind(String.prototype.replace);
|
||||||
const JsonParse = JSON.parse;
|
const JsonParse = JSON.parse;
|
||||||
|
|
||||||
|
const debug = debuglog('esm');
|
||||||
|
|
||||||
const translators = new SafeMap();
|
const translators = new SafeMap();
|
||||||
module.exports = translators;
|
module.exports = translators;
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ rules:
|
|||||||
node-core/number-isnan: error
|
node-core/number-isnan: error
|
||||||
## common module is mandatory in tests
|
## common module is mandatory in tests
|
||||||
node-core/required-modules: [error, common]
|
node-core/required-modules: [error, common]
|
||||||
|
node-core/no-duplicate-requires: off
|
||||||
|
|
||||||
no-restricted-syntax:
|
no-restricted-syntax:
|
||||||
# Config copied from .eslintrc.js
|
# Config copied from .eslintrc.js
|
||||||
|
25
test/parallel/test-eslint-duplicate-requires.js
Normal file
25
test/parallel/test-eslint-duplicate-requires.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const common = require('../common');
|
||||||
|
|
||||||
|
common.skipIfEslintMissing();
|
||||||
|
|
||||||
|
const { RuleTester } = require('../../tools/node_modules/eslint');
|
||||||
|
const rule = require('../../tools/eslint-rules/no-duplicate-requires');
|
||||||
|
|
||||||
|
new RuleTester().run('no-duplicate-requires', rule, {
|
||||||
|
valid: [
|
||||||
|
{
|
||||||
|
code: 'require("a"); require("b"); (function() { require("a"); });',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: 'require(a); require(a);',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
invalid: [
|
||||||
|
{
|
||||||
|
code: 'require("a"); require("a");',
|
||||||
|
errors: [{ message: '\'a\' require is duplicated.' }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
70
tools/eslint-rules/no-duplicate-requires.js
Normal file
70
tools/eslint-rules/no-duplicate-requires.js
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
/**
|
||||||
|
* @fileoverview Ensure modules are not required twice at top level of a module
|
||||||
|
* @author devsnek
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Rule Definition
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
function isString(node) {
|
||||||
|
return node && node.type === 'Literal' && typeof node.value === 'string';
|
||||||
|
}
|
||||||
|
|
||||||
|
function isRequireCall(node) {
|
||||||
|
return node.callee.type === 'Identifier' && node.callee.name === 'require';
|
||||||
|
}
|
||||||
|
|
||||||
|
function isTopLevel(node) {
|
||||||
|
do {
|
||||||
|
if (node.type === 'FunctionDeclaration' ||
|
||||||
|
node.type === 'FunctionExpression' ||
|
||||||
|
node.type === 'ArrowFunctionExpression' ||
|
||||||
|
node.type === 'ClassBody' ||
|
||||||
|
node.type === 'MethodDefinition') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} while (node = node.parent);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = (context) => {
|
||||||
|
if (context.parserOptions.sourceType === 'module') {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRequiredModuleNameFromCall(node) {
|
||||||
|
// node has arguments and first argument is string
|
||||||
|
if (node.arguments.length && isString(node.arguments[0])) {
|
||||||
|
return node.arguments[0].value.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const required = new Set();
|
||||||
|
|
||||||
|
const rules = {
|
||||||
|
CallExpression: (node) => {
|
||||||
|
if (isRequireCall(node) && isTopLevel(node)) {
|
||||||
|
const moduleName = getRequiredModuleNameFromCall(node);
|
||||||
|
if (moduleName === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (required.has(moduleName)) {
|
||||||
|
context.report(
|
||||||
|
node,
|
||||||
|
'\'{{moduleName}}\' require is duplicated.',
|
||||||
|
{ moduleName }
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
required.add(moduleName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return rules;
|
||||||
|
};
|
Loading…
x
Reference in New Issue
Block a user