Skip to content

Commit e511ffd

Browse files
axetroyfisker
andauthoredJul 25, 2024··
prefer-query-selector: Add support for getElementsByName (#2398)
Co-authored-by: fisker Cheung <lionkay@gmail.com>
1 parent 4db75c4 commit e511ffd

6 files changed

+196
-4
lines changed
 

‎docs/rules/prefer-query-selector.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Prefer `.querySelector()` over `.getElementById()`, `.querySelectorAll()` over `.getElementsByClassName()` and `.getElementsByTagName()`
1+
# Prefer `.querySelector()` over `.getElementById()`, `.querySelectorAll()` over `.getElementsByClassName()` and `.getElementsByTagName()` and `.getElementsByName()`
22

33
💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#preset-configs-eslintconfigjs).
44

‎readme.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ If you don't use the preset, ensure you use the same `env` and `parserOptions` c
204204
| [prefer-object-from-entries](docs/rules/prefer-object-from-entries.md) | Prefer using `Object.fromEntries(…)` to transform a list of key-value pairs into an object. || 🔧 | |
205205
| [prefer-optional-catch-binding](docs/rules/prefer-optional-catch-binding.md) | Prefer omitting the `catch` binding parameter. || 🔧 | |
206206
| [prefer-prototype-methods](docs/rules/prefer-prototype-methods.md) | Prefer borrowing methods from the prototype instead of the instance. || 🔧 | |
207-
| [prefer-query-selector](docs/rules/prefer-query-selector.md) | Prefer `.querySelector()` over `.getElementById()`, `.querySelectorAll()` over `.getElementsByClassName()` and `.getElementsByTagName()`. || 🔧 | |
207+
| [prefer-query-selector](docs/rules/prefer-query-selector.md) | Prefer `.querySelector()` over `.getElementById()`, `.querySelectorAll()` over `.getElementsByClassName()` and `.getElementsByTagName()` and `.getElementsByName()`. || 🔧 | |
208208
| [prefer-reflect-apply](docs/rules/prefer-reflect-apply.md) | Prefer `Reflect.apply()` over `Function#apply()`. || 🔧 | |
209209
| [prefer-regexp-test](docs/rules/prefer-regexp-test.md) | Prefer `RegExp#test()` over `String#match()` and `RegExp#exec()`. || 🔧 | 💡 |
210210
| [prefer-set-has](docs/rules/prefer-set-has.md) | Prefer `Set#has()` over `Array#includes()` when checking for existence or non-existence. || 🔧 | 💡 |

‎rules/prefer-query-selector.js

+35-2
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,37 @@ const disallowedIdentifierNames = new Map([
1111
['getElementById', 'querySelector'],
1212
['getElementsByClassName', 'querySelectorAll'],
1313
['getElementsByTagName', 'querySelectorAll'],
14+
['getElementsByName', 'querySelectorAll'],
1415
]);
1516

1617
const getReplacementForId = value => `#${value}`;
1718
const getReplacementForClass = value => value.match(/\S+/g).map(className => `.${className}`).join('');
19+
const getReplacementForName = (value, originQuote) => `[name=${wrapQuoted(value, originQuote)}]`;
1820

1921
const getQuotedReplacement = (node, value) => {
2022
const leftQuote = node.raw.charAt(0);
2123
const rightQuote = node.raw.at(-1);
2224
return `${leftQuote}${value}${rightQuote}`;
2325
};
2426

27+
const wrapQuoted = (value, originalQuote) => {
28+
switch (originalQuote) {
29+
case '\'': {
30+
return `"${value}"`;
31+
}
32+
33+
case '"': {
34+
return `'${value}'`;
35+
}
36+
37+
case '`': {
38+
return `'${value}'`;
39+
}
40+
41+
// No default
42+
}
43+
};
44+
2545
function * getLiteralFix(fixer, node, identifierName) {
2646
let replacement = node.raw;
2747
if (identifierName === 'getElementById') {
@@ -32,6 +52,11 @@ function * getLiteralFix(fixer, node, identifierName) {
3252
replacement = getQuotedReplacement(node, getReplacementForClass(node.value));
3353
}
3454

55+
if (identifierName === 'getElementsByName') {
56+
const quoted = node.raw.charAt(0);
57+
replacement = getQuotedReplacement(node, getReplacementForName(node.value, quoted));
58+
}
59+
3560
yield fixer.replaceText(node, replacement);
3661
}
3762

@@ -53,6 +78,14 @@ function * getTemplateLiteralFix(fixer, node, identifierName) {
5378
getReplacementForClass(templateElement.value.cooked),
5479
);
5580
}
81+
82+
if (identifierName === 'getElementsByName') {
83+
const quoted = node.raw ? node.raw.charAt(0) : '"';
84+
yield fixer.replaceText(
85+
templateElement,
86+
getReplacementForName(templateElement.value.cooked, quoted),
87+
);
88+
}
5689
}
5790
}
5891

@@ -91,7 +124,7 @@ const create = () => ({
91124
CallExpression(node) {
92125
if (
93126
!isMethodCall(node, {
94-
methods: ['getElementById', 'getElementsByClassName', 'getElementsByTagName'],
127+
methods: ['getElementById', 'getElementsByClassName', 'getElementsByTagName', 'getElementsByName'],
95128
argumentsLength: 1,
96129
optionalCall: false,
97130
optionalMember: false,
@@ -127,7 +160,7 @@ module.exports = {
127160
meta: {
128161
type: 'suggestion',
129162
docs: {
130-
description: 'Prefer `.querySelector()` over `.getElementById()`, `.querySelectorAll()` over `.getElementsByClassName()` and `.getElementsByTagName()`.',
163+
description: 'Prefer `.querySelector()` over `.getElementById()`, `.querySelectorAll()` over `.getElementsByClassName()` and `.getElementsByTagName()` and `.getElementsByName()`.',
131164
recommended: true,
132165
},
133166
fixable: 'code',

‎test/prefer-query-selector.mjs

+9
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ test.snapshot({
3030
'document.querySelectorAll(".foo .bar");',
3131
'document.querySelectorAll("li a");',
3232
'document.querySelector("li").querySelectorAll("a");',
33+
'document.getElementsByName();',
3334
],
3435
invalid: [
3536
'document.getElementById("foo");',
@@ -61,5 +62,13 @@ test.snapshot({
6162
`,
6263
// #1030
6364
'e.getElementById(3)',
65+
'document.getElementsByName("foo");',
66+
'document.getElementsByName(\'foo\');',
67+
'document.getElementsByName(`foo`);',
68+
'document.getElementsByName(`${\'foo\'}`);', // eslint-disable-line no-template-curly-in-string
69+
'document.getElementsByName(null);',
70+
'document.getElementsByName("");',
71+
'document.getElementsByName(foo + "bar");',
72+
'document.getElementsByName("multiple name should be fixable");',
6473
],
6574
});

‎test/snapshots/prefer-query-selector.mjs.md

+150
Original file line numberDiff line numberDiff line change
@@ -477,3 +477,153 @@ Generated by [AVA](https://avajs.dev).
477477
> 1 | e.getElementById(3)␊
478478
| ^^^^^^^^^^^^^^ Prefer \`.querySelector()\` over \`.getElementById()\`.␊
479479
`
480+
481+
## invalid(25): document.getElementsByName("foo");
482+
483+
> Input
484+
485+
`␊
486+
1 | document.getElementsByName("foo");␊
487+
`
488+
489+
> Output
490+
491+
`␊
492+
1 | document.querySelectorAll("[name='foo']");␊
493+
`
494+
495+
> Error 1/1
496+
497+
`␊
498+
> 1 | document.getElementsByName("foo");␊
499+
| ^^^^^^^^^^^^^^^^^ Prefer \`.querySelectorAll()\` over \`.getElementsByName()\`.␊
500+
`
501+
502+
## invalid(26): document.getElementsByName('foo');
503+
504+
> Input
505+
506+
`␊
507+
1 | document.getElementsByName('foo');␊
508+
`
509+
510+
> Output
511+
512+
`␊
513+
1 | document.querySelectorAll('[name="foo"]');␊
514+
`
515+
516+
> Error 1/1
517+
518+
`␊
519+
> 1 | document.getElementsByName('foo');␊
520+
| ^^^^^^^^^^^^^^^^^ Prefer \`.querySelectorAll()\` over \`.getElementsByName()\`.␊
521+
`
522+
523+
## invalid(27): document.getElementsByName(`foo`);
524+
525+
> Input
526+
527+
`␊
528+
1 | document.getElementsByName(\`foo\`);␊
529+
`
530+
531+
> Output
532+
533+
`␊
534+
1 | document.querySelectorAll(\`[name='foo']\`);␊
535+
`
536+
537+
> Error 1/1
538+
539+
`␊
540+
> 1 | document.getElementsByName(\`foo\`);␊
541+
| ^^^^^^^^^^^^^^^^^ Prefer \`.querySelectorAll()\` over \`.getElementsByName()\`.␊
542+
`
543+
544+
## invalid(28): document.getElementsByName(`${'foo'}`);
545+
546+
> Input
547+
548+
`␊
549+
1 | document.getElementsByName(\`${'foo'}\`);␊
550+
`
551+
552+
> Error 1/1
553+
554+
`␊
555+
> 1 | document.getElementsByName(\`${'foo'}\`);␊
556+
| ^^^^^^^^^^^^^^^^^ Prefer \`.querySelectorAll()\` over \`.getElementsByName()\`.␊
557+
`
558+
559+
## invalid(29): document.getElementsByName(null);
560+
561+
> Input
562+
563+
`␊
564+
1 | document.getElementsByName(null);␊
565+
`
566+
567+
> Output
568+
569+
`␊
570+
1 | document.querySelectorAll(null);␊
571+
`
572+
573+
> Error 1/1
574+
575+
`␊
576+
> 1 | document.getElementsByName(null);␊
577+
| ^^^^^^^^^^^^^^^^^ Prefer \`.querySelectorAll()\` over \`.getElementsByName()\`.␊
578+
`
579+
580+
## invalid(30): document.getElementsByName("");
581+
582+
> Input
583+
584+
`␊
585+
1 | document.getElementsByName("");␊
586+
`
587+
588+
> Error 1/1
589+
590+
`␊
591+
> 1 | document.getElementsByName("");␊
592+
| ^^^^^^^^^^^^^^^^^ Prefer \`.querySelectorAll()\` over \`.getElementsByName()\`.␊
593+
`
594+
595+
## invalid(31): document.getElementsByName(foo + "bar");
596+
597+
> Input
598+
599+
`␊
600+
1 | document.getElementsByName(foo + "bar");␊
601+
`
602+
603+
> Error 1/1
604+
605+
`␊
606+
> 1 | document.getElementsByName(foo + "bar");␊
607+
| ^^^^^^^^^^^^^^^^^ Prefer \`.querySelectorAll()\` over \`.getElementsByName()\`.␊
608+
`
609+
610+
## invalid(32): document.getElementsByName("multiple name should be fixable");
611+
612+
> Input
613+
614+
`␊
615+
1 | document.getElementsByName("multiple name should be fixable");␊
616+
`
617+
618+
> Output
619+
620+
`␊
621+
1 | document.querySelectorAll("[name='multiple name should be fixable']");␊
622+
`
623+
624+
> Error 1/1
625+
626+
`␊
627+
> 1 | document.getElementsByName("multiple name should be fixable");␊
628+
| ^^^^^^^^^^^^^^^^^ Prefer \`.querySelectorAll()\` over \`.getElementsByName()\`.␊
629+
`
296 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)
Please sign in to comment.