Skip to content

Commit 9458735

Browse files
authored
docs: fix malformed eslint config comments in rule examples (#18078)
* fix: fix malformed `eslint` config comments in rule examples * extend rule example validation * fix test for runtime-specific error message
1 parent 07a1ada commit 9458735

4 files changed

Lines changed: 46 additions & 21 deletions

File tree

docs/src/rules/lines-around-comment.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ class C {
233233
switch (foo) {
234234
/* what a great and wonderful day */
235235

236-
case 1:
236+
case 1:
237237
bar();
238238
break;
239239
}
@@ -317,7 +317,7 @@ class C {
317317
}
318318

319319
switch (foo) {
320-
case 1:
320+
case 1:
321321
bar();
322322
break;
323323

@@ -663,7 +663,7 @@ Examples of **correct** code for the `ignorePattern` option:
663663
/*eslint lines-around-comment: ["error"]*/
664664

665665
foo();
666-
/* eslint mentioned in this comment */
666+
/* jshint mentioned in this comment */
667667
bar();
668668

669669
/*eslint lines-around-comment: ["error", { "ignorePattern": "pragma" }] */
@@ -712,7 +712,7 @@ Examples of **incorrect** code for the `{ "applyDefaultIgnorePatterns": false }`
712712
/*eslint lines-around-comment: ["error", { "applyDefaultIgnorePatterns": false }] */
713713

714714
foo();
715-
/* eslint mentioned in comment */
715+
/* jshint mentioned in comment */
716716

717717
```
718718

tests/fixtures/bad-examples.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
title: no-restricted-syntax
33
---
44

5-
This file contains rule example code with syntax errors.
5+
This file contains rule example code with syntax errors and other problems.
66

77
<!-- markdownlint-capture -->
88
<!-- markdownlint-disable MD040 -->
@@ -32,3 +32,13 @@ const foo = "baz";
3232
```
3333

3434
:::
35+
36+
:::correct
37+
38+
```js
39+
/* eslint no-restricted-syntax: "error" */
40+
41+
/* eslint doesn't allow this comment */
42+
```
43+
44+
:::

tests/tools/check-rule-examples.js

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,18 @@ describe("check-rule-examples", () => {
5555
assert.strictEqual(code, 1);
5656
assert.strictEqual(stdout, "");
5757

58-
// Remove OS-dependent path except base name.
58+
/* eslint-disable no-control-regex -- escaping control characters */
59+
5960
const normalizedStderr =
60-
// eslint-disable-next-line no-control-regex -- escaping control character
61-
stderr.replace(/(?<=\x1B\[4m).*(?=bad-examples\.md)/u, "");
61+
stderr
62+
63+
// Remove OS-dependent path except base name.
64+
.replace(/(?<=\x1B\[4m).*(?=bad-examples\.md)/u, "")
65+
66+
// Remove runtime-specific error message part (different in Node.js 18, 20 and 21).
67+
.replace(/(?<=' doesn't allow this comment'):.*(?=\x1B\[0m)/u, "");
68+
69+
/* eslint-enable no-control-regex -- re-enable rule */
6270

6371
const expectedStderr =
6472
"\x1B[0m\x1B[0m\n" +
@@ -68,8 +76,9 @@ describe("check-rule-examples", () => {
6876
"\x1B[0m \x1B[2m20:5\x1B[22m \x1B[31merror\x1B[39m Nonstandard language tag 'ts': use one of 'javascript', 'js' or 'jsx'\x1B[0m\n" +
6977
"\x1B[0m \x1B[2m23:7\x1B[22m \x1B[31merror\x1B[39m Syntax error: Identifier 'foo' has already been declared\x1B[0m\n" +
7078
"\x1B[0m \x1B[2m31:1\x1B[22m \x1B[31merror\x1B[39m Example code should contain a configuration comment like /* eslint no-restricted-syntax: \"error\" */\x1B[0m\n" +
79+
"\x1B[0m \x1B[2m41:1\x1B[22m \x1B[31merror\x1B[39m Failed to parse JSON from ' doesn't allow this comment'\x1B[0m\n" +
7180
"\x1B[0m\x1B[0m\n" +
72-
"\x1B[0m\x1B[31m\x1B[1m✖ 5 problems (5 errors, 0 warnings)\x1B[22m\x1B[39m\x1B[0m\n" +
81+
"\x1B[0m\x1B[31m\x1B[1m✖ 6 problems (6 errors, 0 warnings)\x1B[22m\x1B[39m\x1B[0m\n" +
7382
"\x1B[0m\x1B[31m\x1B[1m\x1B[22m\x1B[39m\x1B[0m\n";
7483

7584
assert.strictEqual(normalizedStderr, expectedStderr);

tools/check-rule-examples.js

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ const commentParser = new ConfigCommentParser();
3838
*/
3939
function tryParseForPlayground(code, parserOptions) {
4040
try {
41-
const ast = parse(code, { ecmaVersion: "latest", ...parserOptions, comment: true });
41+
const ast = parse(code, { ecmaVersion: "latest", ...parserOptions, comment: true, loc: true });
4242

4343
return { ast };
4444
} catch (error) {
@@ -81,20 +81,26 @@ async function findProblems(filename) {
8181

8282
const { ast, error } = tryParseForPlayground(code, parserOptions);
8383

84-
if (ast && !isRuleRemoved) {
85-
const hasRuleConfigComment = ast.comments.some(
86-
comment => {
87-
if (comment.type !== "Block" || !/^\s*eslint(?!\S)/u.test(comment.value)) {
88-
return false;
89-
}
90-
const { directiveValue } = commentParser.parseDirective(comment);
91-
const parseResult = commentParser.parseJsonConfig(directiveValue, comment.loc);
84+
if (ast) {
85+
let hasRuleConfigComment = false;
9286

93-
return parseResult.success && Object.hasOwn(parseResult.config, title);
87+
for (const comment of ast.comments) {
88+
if (comment.type !== "Block" || !/^\s*eslint(?!\S)/u.test(comment.value)) {
89+
continue;
9490
}
95-
);
91+
const { directiveValue } = commentParser.parseDirective(comment);
92+
const parseResult = commentParser.parseJsonConfig(directiveValue, comment.loc);
93+
const parseError = parseResult.error;
94+
95+
if (parseError) {
96+
parseError.line += codeBlockToken.map[0] + 1;
97+
problems.push(parseError);
98+
} else if (Object.hasOwn(parseResult.config, title)) {
99+
hasRuleConfigComment = true;
100+
}
101+
}
96102

97-
if (!hasRuleConfigComment) {
103+
if (!isRuleRemoved && !hasRuleConfigComment) {
98104
const message = `Example code should contain a configuration comment like /* eslint ${title}: "error" */`;
99105

100106
problems.push({

0 commit comments

Comments
 (0)