Skip to content

Commit 09d57ce

Browse files
fix(eslint-plugin): [ban-ts-comment] counts graphemes instead of String.prototype.length (typescript-eslint#5704)
* fix: counts graphemes instead of String length * Update packages/eslint-plugin/src/rules/ban-ts-comment.ts Co-authored-by: Josh Goldberg <git@joshuakgoldberg.com> * chore: add valid tests * Add grapheme-splitter to peerDependencies * Move to standard dependency * No more peerDependency Co-authored-by: Josh Goldberg <git@joshuakgoldberg.com> Co-authored-by: Josh Goldberg <me@joshuakgoldberg.com>
1 parent 47074b0 commit 09d57ce

File tree

4 files changed

+121
-1
lines changed

4 files changed

+121
-1
lines changed

packages/eslint-plugin/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
"@typescript-eslint/type-utils": "5.49.0",
4949
"@typescript-eslint/utils": "5.49.0",
5050
"debug": "^4.3.4",
51+
"grapheme-splitter": "^1.0.4",
5152
"ignore": "^5.2.0",
5253
"natural-compare-lite": "^1.4.0",
5354
"regexpp": "^3.2.0",
@@ -61,6 +62,7 @@
6162
"@types/natural-compare-lite": "^1.4.0",
6263
"@types/prettier": "*",
6364
"chalk": "^5.0.1",
65+
"grapheme-splitter": "^1.0.4",
6466
"cross-fetch": "^3.1.5",
6567
"json-schema": "*",
6668
"markdown-table": "^3.0.2",

packages/eslint-plugin/src/rules/ban-ts-comment.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,22 @@
11
import { AST_TOKEN_TYPES } from '@typescript-eslint/utils';
2+
import GraphemeSplitter from 'grapheme-splitter';
23

34
import * as util from '../util';
45

6+
let splitter: GraphemeSplitter;
7+
function isASCII(value: string): boolean {
8+
return /^[\u0020-\u007f]*$/u.test(value);
9+
}
10+
function getStringLength(value: string): number {
11+
if (isASCII(value)) {
12+
return value.length;
13+
}
14+
15+
splitter ??= new GraphemeSplitter();
16+
17+
return splitter.countGraphemes(value);
18+
}
19+
520
type DirectiveConfig =
621
| boolean
722
| 'allow-with-description'
@@ -147,7 +162,9 @@ export default util.createRule<[Options], MessageIds>({
147162
minimumDescriptionLength = defaultMinimumDescriptionLength,
148163
} = options;
149164
const format = descriptionFormats.get(fullDirective);
150-
if (description.trim().length < minimumDescriptionLength) {
165+
if (
166+
getStringLength(description.trim()) < minimumDescriptionLength
167+
) {
151168
context.report({
152169
data: { directive, minimumDescriptionLength },
153170
node: comment,

packages/eslint-plugin/tests/rules/ban-ts-comment.test.ts

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@ ruleTester.run('ts-expect-error', rule, {
4545
},
4646
],
4747
},
48+
{
49+
code: noFormat`// @ts-expect-error 👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦`,
50+
options: [
51+
{
52+
'ts-expect-error': 'allow-with-description',
53+
},
54+
],
55+
},
4856
],
4957
invalid: [
5058
{
@@ -228,6 +236,22 @@ if (false) {
228236
},
229237
],
230238
},
239+
{
240+
code: noFormat`// @ts-expect-error 👨‍👩‍👧‍👦`,
241+
options: [
242+
{
243+
'ts-expect-error': 'allow-with-description',
244+
},
245+
],
246+
errors: [
247+
{
248+
data: { directive: 'expect-error', minimumDescriptionLength: 3 },
249+
messageId: 'tsDirectiveCommentRequiresDescription',
250+
line: 1,
251+
column: 1,
252+
},
253+
],
254+
},
231255
],
232256
});
233257

@@ -266,6 +290,14 @@ ruleTester.run('ts-ignore', rule, {
266290
},
267291
],
268292
},
293+
{
294+
code: noFormat`// @ts-ignore 👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦`,
295+
options: [
296+
{
297+
'ts-ignore': 'allow-with-description',
298+
},
299+
],
300+
},
269301
],
270302
invalid: [
271303
{
@@ -460,6 +492,22 @@ if (false) {
460492
},
461493
],
462494
},
495+
{
496+
code: noFormat`// @ts-ignore 👨‍👩‍👧‍👦`,
497+
options: [
498+
{
499+
'ts-ignore': 'allow-with-description',
500+
},
501+
],
502+
errors: [
503+
{
504+
data: { directive: 'ignore', minimumDescriptionLength: 3 },
505+
messageId: 'tsDirectiveCommentRequiresDescription',
506+
line: 1,
507+
column: 1,
508+
},
509+
],
510+
},
463511
],
464512
});
465513

@@ -498,6 +546,14 @@ ruleTester.run('ts-nocheck', rule, {
498546
},
499547
],
500548
},
549+
{
550+
code: noFormat`// @ts-nocheck 👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦`,
551+
options: [
552+
{
553+
'ts-nocheck': 'allow-with-description',
554+
},
555+
],
556+
},
501557
],
502558
invalid: [
503559
{
@@ -668,6 +724,22 @@ if (false) {
668724
},
669725
],
670726
},
727+
{
728+
code: noFormat`// @ts-nocheck 👨‍👩‍👧‍👦`,
729+
options: [
730+
{
731+
'ts-nocheck': 'allow-with-description',
732+
},
733+
],
734+
errors: [
735+
{
736+
data: { directive: 'nocheck', minimumDescriptionLength: 3 },
737+
messageId: 'tsDirectiveCommentRequiresDescription',
738+
line: 1,
739+
column: 1,
740+
},
741+
],
742+
},
671743
],
672744
});
673745

@@ -700,6 +772,14 @@ ruleTester.run('ts-check', rule, {
700772
},
701773
],
702774
},
775+
{
776+
code: noFormat`// @ts-check 👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦`,
777+
options: [
778+
{
779+
'ts-check': 'allow-with-description',
780+
},
781+
],
782+
},
703783
],
704784
invalid: [
705785
{
@@ -863,5 +943,21 @@ if (false) {
863943
},
864944
],
865945
},
946+
{
947+
code: noFormat`// @ts-check 👨‍👩‍👧‍👦`,
948+
options: [
949+
{
950+
'ts-check': 'allow-with-description',
951+
},
952+
],
953+
errors: [
954+
{
955+
data: { directive: 'check', minimumDescriptionLength: 3 },
956+
messageId: 'tsDirectiveCommentRequiresDescription',
957+
line: 1,
958+
column: 1,
959+
},
960+
],
961+
},
866962
],
867963
});

yarn.lock

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8086,6 +8086,11 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6
80868086
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96"
80878087
integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==
80888088

8089+
grapheme-splitter@^1.0.4:
8090+
version "1.0.4"
8091+
resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e"
8092+
integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==
8093+
80898094
gray-matter@^4.0.3:
80908095
version "4.0.3"
80918096
resolved "https://registry.yarnpkg.com/gray-matter/-/gray-matter-4.0.3.tgz#e893c064825de73ea1f5f7d88c7a9f7274288798"

0 commit comments

Comments
 (0)