1import { assert, describe } from "@effect/vitest";
2
3import { createOxlintRuleHarness } from "../test/utils.ts";
4
5const rule = createOxlintRuleHarness("t3code/require-suppression-reason", {
6 filename: "fixture.tsx",
7});
8
9describe("t3code/require-suppression-reason", () => {
10 rule.valid(
11 "allows a directive with a -- reason",
12 `
13 // oxlint-disable-next-line no-control-regex -- ANSI sequences start with ESC.
14 const ansi = /\\x1b\\[/;
15 /* eslint-disable no-console -- this script reports to the terminal */
16 `,
17 );
18
19 rule.valid(
20 "allows a directive explained by the comment above",
21 `
22 // Positions are stable for a given string.
23 // oxlint-disable-next-line react/no-array-index-key
24 const items = ["a"].map((item, index) => <li key={index}>{item}</li>);
25 `,
26 );
27
28 rule.valid(
29 "allows stacked directives under one explanation",
30 `
31 // The fixture is invalid on purpose.
32 // @ts-expect-error
33 // oxlint-disable-next-line no-unused-vars
34 const value: number = "text";
35 `,
36 );
37
38 rule.valid(
39 "allows a TypeScript directive followed by its reason",
40 `
41 // @ts-expect-error the fixture passes a string on purpose
42 const count: number = "text";
43 `,
44 );
45
46 rule.valid(
47 "allows a directive in a JSX comment with a reason",
48 `const el = <div>{/* oxlint-disable-next-line react/no-danger -- sanitized above */}</div>;`,
49 );
50
51 rule.valid("ignores enable directives", `/* oxlint-enable no-console */`);
52
53 rule.invalid(
54 "reports a lint directive without a reason",
55 `
56 // oxlint-disable-next-line no-control-regex
57 const ansi = /\\x1b\\[/;
58 `,
59 (output) => {
60 assert.match(output, /end the directive with `-- reason`/);
61 },
62 );
63
64 rule.invalid(
65 "reports a file-level directive without a reason",
66 `/* oxlint-disable eslint/no-useless-escape */`,
67 );
68
69 rule.invalid(
70 "reports a TypeScript directive without a reason",
71 `
72 // @ts-expect-error
73 const count: number = "text";
74 `,
75 (output) => {
76 assert.match(output, /write the reason after the directive/);
77 },
78 );
79
80 rule.invalid(
81 "does not count a comment separated by a blank line",
82 `
83 // Positions are stable for a given string.
84
85 // oxlint-disable-next-line react/no-array-index-key
86 const items = ["a"].map((item, index) => <li key={index}>{item}</li>);
87 `,
88 );
89
90 rule.valid(
91 "allows an empty comment line between the reason and the directive",
92 `
93 // Positions are stable for a given string.
94 //
95 // oxlint-disable-next-line react/no-array-index-key
96 const items = ["a"].map((item, index) => <li key={index}>{item}</li>);
97 `,
98 );
99
100 rule.invalid(
101 "does not count an empty comment above",
102 `
103 //
104 /* */
105 // oxlint-disable-next-line react/no-array-index-key
106 const items = ["a"].map((item, index) => <li key={index}>{item}</li>);
107 `,
108 );
109
110 rule.invalid(
111 "does not count a trailing comment on the code line above",
112 `
113 const first = 1; // the first value
114 const second = 2; // oxlint-disable-line no-unused-vars
115 `,
116 );
117});