Skip to content

Commit

Permalink
docs: fix malformed eslint config comments in rule examples (#18078)
Browse files Browse the repository at this point in the history
* fix: fix malformed `eslint` config comments in rule examples

* extend rule example validation

* fix test for runtime-specific error message
  • Loading branch information
fasttime committed Feb 4, 2024
1 parent 07a1ada commit 9458735
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 21 deletions.
8 changes: 4 additions & 4 deletions docs/src/rules/lines-around-comment.md
Expand Up @@ -233,7 +233,7 @@ class C {
switch (foo) {
/* what a great and wonderful day */

case 1:
case 1:
bar();
break;
}
Expand Down Expand Up @@ -317,7 +317,7 @@ class C {
}

switch (foo) {
case 1:
case 1:
bar();
break;

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

foo();
/* eslint mentioned in this comment */
/* jshint mentioned in this comment */
bar();

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

foo();
/* eslint mentioned in comment */
/* jshint mentioned in comment */

```

Expand Down
12 changes: 11 additions & 1 deletion tests/fixtures/bad-examples.md
Expand Up @@ -2,7 +2,7 @@
title: no-restricted-syntax
---

This file contains rule example code with syntax errors.
This file contains rule example code with syntax errors and other problems.

<!-- markdownlint-capture -->
<!-- markdownlint-disable MD040 -->
Expand Down Expand Up @@ -32,3 +32,13 @@ const foo = "baz";
```

:::

:::correct

```js
/* eslint no-restricted-syntax: "error" */

/* eslint doesn't allow this comment */
```

:::
17 changes: 13 additions & 4 deletions tests/tools/check-rule-examples.js
Expand Up @@ -55,10 +55,18 @@ describe("check-rule-examples", () => {
assert.strictEqual(code, 1);
assert.strictEqual(stdout, "");

// Remove OS-dependent path except base name.
/* eslint-disable no-control-regex -- escaping control characters */

const normalizedStderr =
// eslint-disable-next-line no-control-regex -- escaping control character
stderr.replace(/(?<=\x1B\[4m).*(?=bad-examples\.md)/u, "");
stderr

// Remove OS-dependent path except base name.
.replace(/(?<=\x1B\[4m).*(?=bad-examples\.md)/u, "")

// Remove runtime-specific error message part (different in Node.js 18, 20 and 21).
.replace(/(?<=' doesn't allow this comment'):.*(?=\x1B\[0m)/u, "");

/* eslint-enable no-control-regex -- re-enable rule */

const expectedStderr =
"\x1B[0m\x1B[0m\n" +
Expand All @@ -68,8 +76,9 @@ describe("check-rule-examples", () => {
"\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" +
"\x1B[0m \x1B[2m23:7\x1B[22m \x1B[31merror\x1B[39m Syntax error: Identifier 'foo' has already been declared\x1B[0m\n" +
"\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" +
"\x1B[0m \x1B[2m41:1\x1B[22m \x1B[31merror\x1B[39m Failed to parse JSON from ' doesn't allow this comment'\x1B[0m\n" +
"\x1B[0m\x1B[0m\n" +
"\x1B[0m\x1B[31m\x1B[1m✖ 5 problems (5 errors, 0 warnings)\x1B[22m\x1B[39m\x1B[0m\n" +
"\x1B[0m\x1B[31m\x1B[1m✖ 6 problems (6 errors, 0 warnings)\x1B[22m\x1B[39m\x1B[0m\n" +
"\x1B[0m\x1B[31m\x1B[1m\x1B[22m\x1B[39m\x1B[0m\n";

assert.strictEqual(normalizedStderr, expectedStderr);
Expand Down
30 changes: 18 additions & 12 deletions tools/check-rule-examples.js
Expand Up @@ -38,7 +38,7 @@ const commentParser = new ConfigCommentParser();
*/
function tryParseForPlayground(code, parserOptions) {
try {
const ast = parse(code, { ecmaVersion: "latest", ...parserOptions, comment: true });
const ast = parse(code, { ecmaVersion: "latest", ...parserOptions, comment: true, loc: true });

return { ast };
} catch (error) {
Expand Down Expand Up @@ -81,20 +81,26 @@ async function findProblems(filename) {

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

if (ast && !isRuleRemoved) {
const hasRuleConfigComment = ast.comments.some(
comment => {
if (comment.type !== "Block" || !/^\s*eslint(?!\S)/u.test(comment.value)) {
return false;
}
const { directiveValue } = commentParser.parseDirective(comment);
const parseResult = commentParser.parseJsonConfig(directiveValue, comment.loc);
if (ast) {
let hasRuleConfigComment = false;

return parseResult.success && Object.hasOwn(parseResult.config, title);
for (const comment of ast.comments) {
if (comment.type !== "Block" || !/^\s*eslint(?!\S)/u.test(comment.value)) {
continue;
}
);
const { directiveValue } = commentParser.parseDirective(comment);
const parseResult = commentParser.parseJsonConfig(directiveValue, comment.loc);
const parseError = parseResult.error;

if (parseError) {
parseError.line += codeBlockToken.map[0] + 1;
problems.push(parseError);
} else if (Object.hasOwn(parseResult.config, title)) {
hasRuleConfigComment = true;
}
}

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

problems.push({
Expand Down

0 comments on commit 9458735

Please sign in to comment.