Skip to content

Commit 1d682a1

Browse files
authored
prefer-code-point: Report cases where String.fromCharCode is not called directly (#2766)
1 parent eb97068 commit 1d682a1

File tree

4 files changed

+65
-37
lines changed

4 files changed

+65
-37
lines changed

rules/prefer-code-point.js

Lines changed: 25 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {isMethodCall} from './ast/index.js';
1+
import {isMemberExpression, isMethodCall} from './ast/index.js';
22

33
const messages = {
44
'error/charCodeAt': 'Prefer `String#codePointAt()` over `String#charCodeAt()`.',
@@ -7,47 +7,35 @@ const messages = {
77
'suggestion/fromCodePoint': 'Use `String.fromCodePoint()`.',
88
};
99

10-
const getReplacement = node => {
11-
if (isMethodCall(node, {
12-
method: 'charCodeAt',
13-
optionalCall: false,
14-
})) {
15-
return 'codePointAt';
16-
}
17-
18-
if (isMethodCall(node, {
19-
object: 'String',
20-
method: 'fromCharCode',
21-
optionalCall: false,
22-
optionalMember: false,
23-
})) {
24-
return 'fromCodePoint';
25-
}
26-
};
10+
const getProblem = (node, replacement) => ({
11+
node,
12+
messageId: `error/${node.name}`,
13+
suggest: [
14+
{
15+
messageId: `suggestion/${replacement}`,
16+
fix: fixer => fixer.replaceText(node, replacement),
17+
},
18+
],
19+
});
2720

2821
/** @param {import('eslint').Rule.RuleContext} context */
2922
const create = () => ({
3023
CallExpression(node) {
31-
const replacement = getReplacement(node);
32-
33-
if (!replacement) {
34-
return;
24+
if (isMethodCall(node, {
25+
method: 'charCodeAt',
26+
optionalCall: false,
27+
})) {
28+
return getProblem(node.callee.property, 'codePointAt');
29+
}
30+
},
31+
MemberExpression(node) {
32+
if (isMemberExpression(node, {
33+
object: 'String',
34+
property: 'fromCharCode',
35+
optional: false,
36+
})) {
37+
return getProblem(node.property, 'fromCodePoint');
3538
}
36-
37-
const method = node.callee.property;
38-
const methodName = method.name;
39-
const fix = fixer => fixer.replaceText(method, replacement);
40-
41-
return {
42-
node: method,
43-
messageId: `error/${methodName}`,
44-
suggest: [
45-
{
46-
messageId: `suggestion/${replacement}`,
47-
fix,
48-
},
49-
],
50-
};
5139
},
5240
});
5341

test/prefer-code-point.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,7 @@ test.snapshot({
3131
'(( (( string )).charCodeAt( ((index)), )))',
3232
'String.fromCharCode( code )',
3333
'(( (( String )).fromCharCode( ((code)), ) ))',
34+
'String.fromCharCode.bind(String)',
35+
'const x = String.fromCharCode',
3436
],
3537
});

test/snapshots/prefer-code-point.js.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,41 @@ Generated by [AVA](https://avajs.dev).
9898
Suggestion 1/1: Use \`String.fromCodePoint()\`.␊
9999
1 | (( (( String )).fromCodePoint( ((code)), ) ))␊
100100
`
101+
102+
## invalid(6): String.fromCharCode.bind(String)
103+
104+
> Input
105+
106+
`␊
107+
1 | String.fromCharCode.bind(String)␊
108+
`
109+
110+
> Error 1/1
111+
112+
`␊
113+
> 1 | String.fromCharCode.bind(String)␊
114+
| ^^^^^^^^^^^^ Prefer \`String.fromCodePoint()\` over \`String.fromCharCode()\`.␊
115+
116+
--------------------------------------------------------------------------------␊
117+
Suggestion 1/1: Use \`String.fromCodePoint()\`.␊
118+
1 | String.fromCodePoint.bind(String)␊
119+
`
120+
121+
## invalid(7): const x = String.fromCharCode
122+
123+
> Input
124+
125+
`␊
126+
1 | const x = String.fromCharCode␊
127+
`
128+
129+
> Error 1/1
130+
131+
`␊
132+
> 1 | const x = String.fromCharCode␊
133+
| ^^^^^^^^^^^^ Prefer \`String.fromCodePoint()\` over \`String.fromCharCode()\`.␊
134+
135+
--------------------------------------------------------------------------------␊
136+
Suggestion 1/1: Use \`String.fromCodePoint()\`.␊
137+
1 | const x = String.fromCodePoint␊
138+
`
88 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)