Skip to content

Commit e030dd7

Browse files
devsnektargos
authored andcommitted
tools: add no-duplicate-requires rule
PR-URL: #21712 Reviewed-By: Richard Lau <[email protected]> Reviewed-By: Tiancheng "Timothy" Gu <[email protected]> Reviewed-By: Weijia Wang <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Jon Moss <[email protected]>
1 parent 3096ee5 commit e030dd7

File tree

8 files changed

+116
-11
lines changed

8 files changed

+116
-11
lines changed

‎.eslintrc.js‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ module.exports ={
9898
'no-dupe-class-members': 'error',
9999
'no-dupe-keys': 'error',
100100
'no-duplicate-case': 'error',
101+
'no-duplicate-imports': 'error',
101102
'no-empty-character-class': 'error',
102103
'no-ex-assign': 'error',
103104
'no-extra-boolean-cast': 'error',
@@ -246,6 +247,7 @@ module.exports ={
246247

247248
// Custom rules from eslint-plugin-node-core
248249
'node-core/no-unescaped-regexp-dot': 'error',
250+
'node-core/no-duplicate-requires': 'error',
249251
},
250252
globals: {
251253
Atomics: false,

‎benchmark/streams/creation.js‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
'use strict';
22
constcommon=require('../common.js');
3-
constDuplex=require('stream').Duplex;
4-
constReadable=require('stream').Readable;
5-
constTransform=require('stream').Transform;
6-
constWritable=require('stream').Writable;
3+
const{
4+
Duplex,
5+
Readable,
6+
Transform,
7+
Writable,
8+
}=require('stream');
79

810
constbench=common.createBenchmark(main,{
911
n: [50e6],

‎doc/api/worker_threads.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ For example:
286286
```js
287287
constassert=require('assert');
288288
const{
289-
Worker, MessageChannel, MessagePort, isMainThread
289+
Worker, MessageChannel, MessagePort, isMainThread, parentPort
290290
} =require('worker_threads');
291291
if (isMainThread){
292292
constworker=newWorker(__filename);
@@ -296,7 +296,7 @@ if (isMainThread){
296296
console.log('received:', value);
297297
});
298298
} else{
299-
require('worker_threads').once('message', (value) =>{
299+
parentPort.once('message', (value) =>{
300300
assert(value.hereIsYourPortinstanceofMessagePort);
301301
value.hereIsYourPort.postMessage('the worker is sending this');
302302
value.hereIsYourPort.close();

‎lib/internal/http2/core.js‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,12 @@ const{kIncomingMessage } = require('_http_common');
2424
const{ kServerResponse }=require('_http_server');
2525
const{ StreamWrap }=require('_stream_wrap');
2626

27-
const{ defaultTriggerAsyncIdScope }=require('internal/async_hooks');
28-
const{ async_id_symbol }=require('internal/async_hooks').symbols;
27+
const{
28+
defaultTriggerAsyncIdScope,
29+
symbols: {
30+
async_id_symbol,
31+
},
32+
}=require('internal/async_hooks');
2933
const{ internalBinding }=require('internal/bootstrap/loaders');
3034
const{
3135
codes: {

‎lib/internal/modules/esm/translators.js‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,14 @@ const fs = require('fs');
1414
const{ _makeLong }=require('path');
1515
const{ SafeMap }=require('internal/safe_globals');
1616
const{URL}=require('url');
17-
constutil=require('util');
18-
constdebug=util.debuglog('esm');
19-
constreadFileAsync=util.promisify(fs.readFile);
17+
const{ debuglog, promisify }=require('util');
18+
constreadFileAsync=promisify(fs.readFile);
2019
constreadFileSync=fs.readFileSync;
2120
constStringReplace=Function.call.bind(String.prototype.replace);
2221
constJsonParse=JSON.parse;
2322

23+
constdebug=debuglog('esm');
24+
2425
consttranslators=newSafeMap();
2526
module.exports=translators;
2627

‎test/.eslintrc.yaml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ rules:
1818
node-core/number-isnan: error
1919
## common module is mandatory in tests
2020
node-core/required-modules: [error, common]
21+
node-core/no-duplicate-requires: off
2122

2223
no-restricted-syntax:
2324
# Config copied from .eslintrc.js
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
'use strict';
2+
3+
constcommon=require('../common');
4+
5+
common.skipIfEslintMissing();
6+
7+
const{ RuleTester }=require('../../tools/node_modules/eslint');
8+
construle=require('../../tools/eslint-rules/no-duplicate-requires');
9+
10+
newRuleTester().run('no-duplicate-requires',rule,{
11+
valid: [
12+
{
13+
code: 'require("a"); require("b"); (function(){require("a")});',
14+
},
15+
{
16+
code: 'require(a); require(a);',
17+
},
18+
],
19+
invalid: [
20+
{
21+
code: 'require("a"); require("a");',
22+
errors: [{message: '\'a\' require is duplicated.'}],
23+
},
24+
],
25+
});
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/**
2+
* @fileoverview Ensure modules are not required twice at top level of a module
3+
* @author devsnek
4+
*/
5+
'use strict';
6+
7+
//------------------------------------------------------------------------------
8+
// Rule Definition
9+
//------------------------------------------------------------------------------
10+
11+
12+
functionisString(node){
13+
returnnode&&node.type==='Literal'&&typeofnode.value==='string';
14+
}
15+
16+
functionisRequireCall(node){
17+
returnnode.callee.type==='Identifier'&&node.callee.name==='require';
18+
}
19+
20+
functionisTopLevel(node){
21+
do{
22+
if(node.type==='FunctionDeclaration'||
23+
node.type==='FunctionExpression'||
24+
node.type==='ArrowFunctionExpression'||
25+
node.type==='ClassBody'||
26+
node.type==='MethodDefinition'){
27+
returnfalse;
28+
}
29+
}while(node=node.parent);
30+
returntrue;
31+
}
32+
33+
module.exports=(context)=>{
34+
if(context.parserOptions.sourceType==='module'){
35+
return{};
36+
}
37+
38+
functiongetRequiredModuleNameFromCall(node){
39+
// node has arguments and first argument is string
40+
if(node.arguments.length&&isString(node.arguments[0])){
41+
returnnode.arguments[0].value.trim();
42+
}
43+
44+
returnundefined;
45+
}
46+
47+
constrequired=newSet();
48+
49+
construles={
50+
CallExpression: (node)=>{
51+
if(isRequireCall(node)&&isTopLevel(node)){
52+
constmoduleName=getRequiredModuleNameFromCall(node);
53+
if(moduleName===undefined){
54+
return;
55+
}
56+
if(required.has(moduleName)){
57+
context.report(
58+
node,
59+
'\'{{moduleName}}\' require is duplicated.',
60+
{ moduleName }
61+
);
62+
}else{
63+
required.add(moduleName);
64+
}
65+
}
66+
},
67+
};
68+
69+
returnrules;
70+
};

0 commit comments

Comments
(0)