Skip to content

Commit 7c8abf5

Browse files
authored
new-for-builtins: Simplify with GlobalReferenceTracker (#1909)
1 parent b002e75 commit 7c8abf5

File tree

2 files changed

+59
-51
lines changed

2 files changed

+59
-51
lines changed

rules/new-for-builtins.js

+49-48
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
'use strict';
2-
const {ReferenceTracker} = require('eslint-utils');
2+
const {GlobalReferenceTracker} = require('./utils/global-reference-tracker.js');
33
const builtins = require('./utils/builtins.js');
44
const {
55
switchCallExpressionToNewExpression,
@@ -11,64 +11,65 @@ const messages = {
1111
disallow: 'Use `{{name}}()` instead of `new {{name}}()`.',
1212
};
1313

14-
function * enforceNewExpression({sourceCode, tracker}) {
15-
const traceMap = Object.fromEntries(
16-
builtins.enforceNew.map(name => [name, {[ReferenceTracker.CALL]: true}]),
17-
);
18-
19-
for (const {node, path: [name]} of tracker.iterateGlobalReferences(traceMap)) {
20-
if (name === 'Object') {
21-
const {parent} = node;
22-
if (
23-
parent.type === 'BinaryExpression'
24-
&& (parent.operator === '===' || parent.operator === '!==')
25-
&& (parent.left === node || parent.right === node)
26-
) {
27-
continue;
28-
}
14+
function enforceNewExpression({node, path: [name]}, sourceCode) {
15+
if (name === 'Object') {
16+
const {parent} = node;
17+
if (
18+
parent.type === 'BinaryExpression'
19+
&& (parent.operator === '===' || parent.operator === '!==')
20+
&& (parent.left === node || parent.right === node)
21+
) {
22+
return;
2923
}
30-
31-
yield {
32-
node,
33-
messageId: 'enforce',
34-
data: {name},
35-
fix: fixer => switchCallExpressionToNewExpression(node, sourceCode, fixer),
36-
};
3724
}
25+
26+
return {
27+
node,
28+
messageId: 'enforce',
29+
data: {name},
30+
fix: fixer => switchCallExpressionToNewExpression(node, sourceCode, fixer),
31+
};
3832
}
3933

40-
function * enforceCallExpression({sourceCode, tracker}) {
41-
const traceMap = Object.fromEntries(
42-
builtins.disallowNew.map(name => [name, {[ReferenceTracker.CONSTRUCT]: true}]),
43-
);
34+
function enforceCallExpression({node, path: [name]}, sourceCode) {
35+
const problem = {
36+
node,
37+
messageId: 'disallow',
38+
data: {name},
39+
};
4440

45-
for (const {node, path: [name]} of tracker.iterateGlobalReferences(traceMap)) {
46-
const problem = {
47-
node,
48-
messageId: 'disallow',
49-
data: {name},
41+
if (name !== 'String' && name !== 'Boolean' && name !== 'Number') {
42+
problem.fix = function * (fixer) {
43+
yield * switchNewExpressionToCallExpression(node, sourceCode, fixer);
5044
};
51-
52-
if (name !== 'String' && name !== 'Boolean' && name !== 'Number') {
53-
problem.fix = function * (fixer) {
54-
yield * switchNewExpressionToCallExpression(node, sourceCode, fixer);
55-
};
56-
}
57-
58-
yield problem;
5945
}
46+
47+
return problem;
6048
}
6149

6250
/** @param {import('eslint').Rule.RuleContext} context */
63-
const create = context => ({
64-
* 'Program:exit'() {
65-
const sourceCode = context.getSourceCode();
66-
const tracker = new ReferenceTracker(context.getScope());
51+
const create = context => {
52+
const sourceCode = context.getSourceCode();
53+
const newExpressionTracker = new GlobalReferenceTracker({
54+
objects: builtins.disallowNew,
55+
type: GlobalReferenceTracker.CONSTRUCT,
56+
handle: reference => enforceCallExpression(reference, sourceCode),
57+
});
58+
const callExpressionTracker = new GlobalReferenceTracker({
59+
objects: builtins.enforceNew,
60+
type: GlobalReferenceTracker.CALL,
61+
handle: reference => enforceNewExpression(reference, sourceCode),
62+
});
6763

68-
yield * enforceNewExpression({sourceCode, tracker});
69-
yield * enforceCallExpression({sourceCode, tracker});
70-
},
71-
});
64+
return {
65+
* 'Program:exit'() {
66+
const scope = context.getScope();
67+
68+
yield * newExpressionTracker.track(scope);
69+
yield * callExpressionTracker.track(scope);
70+
},
71+
};
72+
};
7273

7374
/** @type {import('eslint').Rule.RuleModule} */
7475
module.exports = {

rules/utils/global-reference-tracker.js

+10-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
'use strict';
22
const {ReferenceTracker} = require('eslint-utils');
33

4-
const createTraceMap = object => {
5-
let map = {[ReferenceTracker.READ]: true};
4+
const createTraceMap = (object, type) => {
5+
let map = {[type]: true};
66

77
const path = object.split('.').reverse();
88
for (const name of path) {
@@ -22,9 +22,10 @@ class GlobalReferenceTracker {
2222
objects = [object],
2323
filter,
2424
handle,
25+
type = ReferenceTracker.READ,
2526
}) {
2627
for (const object of objects) {
27-
Object.assign(this.#traceMap, createTraceMap(object));
28+
Object.assign(this.#traceMap, createTraceMap(object, type));
2829
}
2930

3031
this.#filter = filter;
@@ -60,6 +61,12 @@ class GlobalReferenceTracker {
6061
}
6162
}
6263

64+
Object.assign(GlobalReferenceTracker, {
65+
READ: ReferenceTracker.READ,
66+
CALL: ReferenceTracker.CALL,
67+
CONSTRUCT: ReferenceTracker.CONSTRUCT,
68+
});
69+
6370
module.exports = {
6471
GlobalReferenceTracker,
6572
};

0 commit comments

Comments
 (0)