Migrate internal ESLint rules to ESM (#17123)

This commit is contained in:
fisker Cheung authored and GitHub committed 2025-02-16 15:36:06 +08:00
1 parent 150e92fe45
commit b72a37c51e
23 files changed
+82 -161

No files matched your search

+2 -6
View File
@@ -20,7 +20,7 @@ const ignores = `
test*.* test*.*
# Ignore directories and files in 'tests/format' # Ignore directories and files in 'tests/format'
tests/format/**/* tests/format/**/*
# Unignore directories and 'jsfmt.spec.js', 'format.test.js' file # Unignore directories and 'format.test.js' file
!tests/format/**/ !tests/format/**/
!tests/format/**/format.test.js !tests/format/**/format.test.js
tests/integration/cli/ tests/integration/cli/
@@ -289,11 +289,7 @@ export default [
}, },
// CommonJS modules // CommonJS modules
{ {
files: [ files: ["**/*.cjs", "website/**/*.js"],
"**/*.cjs",
"scripts/tools/eslint-plugin-prettier-internal-rules/**/*.js",
"website/**/*.js",
],
languageOptions: { languageOptions: {
sourceType: "script", sourceType: "script",
}, },
@@ -1,5 +1,3 @@
"use strict";
const selector = [ const selector = [
"CallExpression", "CallExpression",
'[callee.type="Identifier"]', '[callee.type="Identifier"]',
@@ -9,12 +7,9 @@ const selector = [
const MESSAGE_ID_CALL = "await-cli-tests/call"; const MESSAGE_ID_CALL = "await-cli-tests/call";
const MESSAGE_ID_GETTER = "await-cli-tests/getter"; const MESSAGE_ID_GETTER = "await-cli-tests/getter";
module.exports = { export default {
meta: { meta: {
type: "suggestion", type: "suggestion",
docs: {
url: "https://github.com/prettier/prettier/blob/main/scripts/tools/eslint-plugin-prettier-internal-rules/await-cli-tests.js",
},
messages: { messages: {
[MESSAGE_ID_CALL]: "'runCli()' should be awaited or calling `.test()`.", [MESSAGE_ID_CALL]: "'runCli()' should be awaited or calling `.test()`.",
[MESSAGE_ID_GETTER]: "'runCli().{{property}}' should be awaited.", [MESSAGE_ID_GETTER]: "'runCli().{{property}}' should be awaited.",
@@ -1,6 +1,4 @@
"use strict"; import path from "node:path";
const path = require("path");
const parentPropertyCheckSelector = [ const parentPropertyCheckSelector = [
"FunctionDeclaration", "FunctionDeclaration",
@@ -44,12 +42,9 @@ const keyCheckSelector = [
const MESSAGE_ID_PREFER_KEY_CHECK = "prefer-key-check"; const MESSAGE_ID_PREFER_KEY_CHECK = "prefer-key-check";
const MESSAGE_ID_KEY_CHECK_FIRST = "key-check-on-left"; const MESSAGE_ID_KEY_CHECK_FIRST = "key-check-on-left";
module.exports = { export default {
meta: { meta: {
type: "suggestion", type: "suggestion",
docs: {
url: "https://github.com/prettier/prettier/blob/main/scripts/tools/eslint-plugin-prettier-internal-rules/better-parent-property-check-in-needs-parens.js",
},
messages: { messages: {
[MESSAGE_ID_PREFER_KEY_CHECK]: [MESSAGE_ID_PREFER_KEY_CHECK]:
"Prefer `key {{operator}} {{propertyText}}` over `parent.{{property}} {{operator}} node`.", "Prefer `key {{operator}} {{propertyText}}` over `parent.{{property}} {{operator}} node`.",
@@ -1,5 +1,3 @@
"use strict";
const selector = [ const selector = [
"MemberExpression", "MemberExpression",
"[computed=false]", "[computed=false]",
@@ -9,12 +7,9 @@ const selector = [
const MESSAGE_ID = "directly-loc-start-end"; const MESSAGE_ID = "directly-loc-start-end";
module.exports = { export default {
meta: { meta: {
type: "suggestion", type: "suggestion",
docs: {
url: "https://github.com/prettier/prettier/blob/main/scripts/tools/eslint-plugin-prettier-internal-rules/directly-loc-start-end.js",
},
messages: { messages: {
[MESSAGE_ID]: [MESSAGE_ID]:
"Please import `{{function}}` function and use it directly.", "Please import `{{function}}` function and use it directly.",
@@ -1,5 +1,3 @@
"use strict";
// This rule only work for nested `AstPath#call()` for now // This rule only work for nested `AstPath#call()` for now
function astPathCallSelector(path) { function astPathCallSelector(path) {
@@ -29,12 +27,9 @@ const selector = [
const MESSAGE_ID = "flat-ast-path-call"; const MESSAGE_ID = "flat-ast-path-call";
module.exports = { export default {
meta: { meta: {
type: "suggestion", type: "suggestion",
docs: {
url: "https://github.com/prettier/prettier/blob/main/scripts/tools/eslint-plugin-prettier-internal-rules/flat-ast-path-call.js",
},
messages: { messages: {
[MESSAGE_ID]: "Do not use nested `AstPath#{{method}}(…)`.", [MESSAGE_ID]: "Do not use nested `AstPath#{{method}}(…)`.",
}, },
@@ -1,25 +1,40 @@
"use strict"; import fs from "node:fs/promises";
import path from "node:path";
import packageJson from "./package.json" with { type: "json" };
module.exports = { const rules = {};
rules: {
"await-cli-tests": require("./await-cli-tests.js"), for (const dirent of await fs.readdir(import.meta.dirname, {
"better-parent-property-check-in-needs-parens": require("./better-parent-property-check-in-needs-parens.js"), withFileTypes: true,
"directly-loc-start-end": require("./directly-loc-start-end.js"), })) {
"flat-ast-path-call": require("./flat-ast-path-call.js"), const fileName = dirent.name;
"jsx-identifier-case": require("./jsx-identifier-case.js"),
"massage-ast-parameter-names": require("./massage-ast-parameter-names.js"), if (
"no-conflicting-comment-check-flags": require("./no-conflicting-comment-check-flags.js"), dirent.isDirectory() ||
"no-doc-public-import": require("./no-doc-public-import.js"), !fileName.endsWith(".js") ||
"no-empty-flat-contents-for-if-break": require("./no-empty-flat-contents-for-if-break.js"), fileName === "index.js" ||
"no-identifier-n": require("./no-identifier-n.js"), fileName === "test.js"
"no-legacy-format-test": require("./no-legacy-format-test.js"), ) {
"no-node-comments": require("./no-node-comments.js"), continue;
"no-unnecessary-ast-path-call": require("./no-unnecessary-ast-path-call.js"), }
"prefer-ast-path-each": require("./prefer-ast-path-each.js"),
"prefer-create-type-check-function": require("./prefer-create-type-check-function.js"), const name = path.basename(fileName, ".js");
"prefer-indent-if-break": require("./prefer-indent-if-break.js"), const { default: rule } = await import(
"prefer-is-non-empty-array": require("./prefer-is-non-empty-array.js"), new URL(fileName, import.meta.url).href
"prefer-fs-promises-submodule": require("./prefer-fs-promises-submodule.js"), );
"prefer-ast-path-getters": require("./prefer-ast-path-getters.js"),
}, if (rule.meta?.docs?.url) {
throw new Error(`Please remove 'meta.docs.url' from '${fileName}'.`);
}
rule.meta ??= {};
rule.meta.docs ??= {};
rule.meta.docs.url = `https://github.com/prettier/prettier/blob/main/scripts/tools/eslint-plugin-prettier-internal-rules/${fileName}`;
rules[name] = rule;
}
export default {
meta: { name: packageJson.name, version: packageJson.version },
rules,
}; };
@@ -1,16 +1,11 @@
"use strict";
const MESSAGE_ID = "jsx-identifier-case"; const MESSAGE_ID = "jsx-identifier-case";
// To ignore variables, config eslint like this // To ignore variables, config eslint like this
// {'prettier-internal-rules/jsx-identifier-case': ['error', 'name1', ... 'nameN']} // {'prettier-internal-rules/jsx-identifier-case': ['error', 'name1', ... 'nameN']}
module.exports = { export default {
meta: { meta: {
type: "suggestion", type: "suggestion",
docs: {
url: "https://github.com/prettier/prettier/blob/main/scripts/tools/eslint-plugin-prettier-internal-rules/jsx-identifier-case.js",
},
messages: { messages: {
[MESSAGE_ID]: "Please rename '{{name}}' to '{{fixed}}'.", [MESSAGE_ID]: "Please rename '{{name}}' to '{{fixed}}'.",
}, },
@@ -1,5 +1,3 @@
"use strict";
const MESSAGE_ID = "massage-ast-parameter-names"; const MESSAGE_ID = "massage-ast-parameter-names";
const massageAstFunctionSelector = [ const massageAstFunctionSelector = [
@@ -17,12 +15,9 @@ const getVariableIdentifiers = ({ identifiers, references }) => [
]), ]),
]; ];
module.exports = { export default {
meta: { meta: {
type: "suggestion", type: "suggestion",
docs: {
url: "https://github.com/prettier/prettier/blob/main/scripts/tools/eslint-plugin-prettier-internal-rules/massage-ast-parameter-names.js",
},
messages: { messages: {
[MESSAGE_ID]: [MESSAGE_ID]:
"The {{name}} node parameter '{{original}}' should be named '{{name}}'.", "The {{name}} node parameter '{{original}}' should be named '{{name}}'.",
@@ -1,4 +1,3 @@
"use strict";
const MESSAGE_ID_UNIQUE = "unique"; const MESSAGE_ID_UNIQUE = "unique";
const MESSAGE_ID_CONFLICTING = "conflicting"; const MESSAGE_ID_CONFLICTING = "conflicting";
@@ -37,12 +36,9 @@ const flatFlags = (node) => {
return flags.map((node) => node.property.name); return flags.map((node) => node.property.name);
}; };
module.exports = { export default {
meta: { meta: {
type: "suggestion", type: "suggestion",
docs: {
url: "https://github.com/prettier/prettier/blob/main/scripts/tools/eslint-plugin-prettier-internal-rules/no-conflicting-comment-check-flags.js",
},
messages: { messages: {
[MESSAGE_ID_UNIQUE]: "Do not use same flag multiple times.", [MESSAGE_ID_UNIQUE]: "Do not use same flag multiple times.",
[MESSAGE_ID_CONFLICTING]: "Do not use {{flags}} together.", [MESSAGE_ID_CONFLICTING]: "Do not use {{flags}} together.",
@@ -1,5 +1,4 @@
"use strict"; import path from "node:path";
const path = require("path");
const selector = [ const selector = [
":matches(ImportDeclaration, ExportNamedDeclaration, ImportExpression)", ":matches(ImportDeclaration, ExportNamedDeclaration, ImportExpression)",
@@ -8,10 +7,13 @@ const selector = [
].join(""); ].join("");
const messageId = "no-doc-public-import"; const messageId = "no-doc-public-import";
const docIndexFile = path.join(__dirname, "../../../src/document/public.js"); const docIndexFile = path.join(
import.meta.dirname,
"../../../src/document/public.js",
);
const ignored = new Set([ const ignored = new Set([
path.join(__dirname, "../../../src/index.js"), path.join(import.meta.dirname, "../../../src/index.js"),
path.join(__dirname, "../../../src/standalone.js"), path.join(import.meta.dirname, "../../../src/standalone.js"),
]); ]);
const docProperties = new Set(["builders", "debug", "printer", "utils"]); const docProperties = new Set(["builders", "debug", "printer", "utils"]);
@@ -84,12 +86,9 @@ function fix(source, context) {
}; };
} }
module.exports = { export default {
meta: { meta: {
type: "suggestion", type: "suggestion",
docs: {
url: "https://github.com/prettier/prettier/blob/main/scripts/tools/eslint-plugin-prettier-internal-rules/no-doc-public-import.js",
},
messages: { messages: {
[messageId]: "Do not {{type}} document/public.js file", [messageId]: "Do not {{type}} document/public.js file",
}, },
@@ -1,5 +1,3 @@
"use strict";
const selector = [ const selector = [
"CallExpression", "CallExpression",
"[optional=false]", "[optional=false]",
@@ -13,12 +11,9 @@ const selector = [
const messageId = "no-empty-flat-contents-for-if-break"; const messageId = "no-empty-flat-contents-for-if-break";
module.exports = { export default {
meta: { meta: {
type: "suggestion", type: "suggestion",
docs: {
url: "https://github.com/prettier/prettier/blob/main/scripts/tools/eslint-plugin-prettier-internal-rules/no-empty-flat-contents-for-if-break.js",
},
messages: { messages: {
[messageId]: [messageId]:
"Please don't pass an empty string to second parameter of ifBreak.", "Please don't pass an empty string to second parameter of ifBreak.",
@@ -1,6 +1,5 @@
"use strict"; import { findVariable } from "@eslint-community/eslint-utils";
const { findVariable } = require("@eslint-community/eslint-utils");
const ERROR = "error"; const ERROR = "error";
const SUGGESTION = "suggestion"; const SUGGESTION = "suggestion";
const selector = [ const selector = [
@@ -12,12 +11,9 @@ const selector = [
].join(", ")})`, ].join(", ")})`,
].join(""); ].join("");
module.exports = { export default {
meta: { meta: {
type: "suggestion", type: "suggestion",
docs: {
url: "https://github.com/prettier/prettier/blob/main/scripts/tools/eslint-plugin-prettier-internal-rules/no-identifier-n.js",
},
messages: { messages: {
[ERROR]: "Please rename variable 'n'.", [ERROR]: "Please rename variable 'n'.",
[SUGGESTION]: "Rename to `node`.", [SUGGESTION]: "Rename to `node`.",
@@ -1,6 +1,4 @@
"use strict"; import path from "node:path";
const path = require("path");
const legacyRunFormatTestCall = [ const legacyRunFormatTestCall = [
"CallExpression", "CallExpression",
@@ -38,12 +36,9 @@ const MESSAGE_ID_ARGUMENT = "dirname-argument";
const MESSAGE_ID_PROPERTY = "dirname-property"; const MESSAGE_ID_PROPERTY = "dirname-property";
const MESSAGE_ID_LEGACY_FILENAME = "legacy-filename"; const MESSAGE_ID_LEGACY_FILENAME = "legacy-filename";
module.exports = { export default {
meta: { meta: {
type: "suggestion", type: "suggestion",
docs: {
url: "https://github.com/prettier/prettier/blob/main/scripts/tools/eslint-plugin-prettier-internal-rules/no-legacy-format-test.js",
},
messages: { messages: {
[MESSAGE_ID_LEGACY_FUNCTION_NAME]: [MESSAGE_ID_LEGACY_FUNCTION_NAME]:
"Use `runFormatTest(…)` instead of `run_spec(…)`.", "Use `runFormatTest(…)` instead of `run_spec(…)`.",
@@ -1,5 +1,4 @@
"use strict"; import path from "node:path";
const path = require("path");
// `node.comments` // `node.comments`
const memberExpressionSelector = [ const memberExpressionSelector = [
@@ -25,12 +24,9 @@ const selector = `:matches(${memberExpressionSelector}, ${objectPatternSelector}
const messageId = "no-node-comments"; const messageId = "no-node-comments";
module.exports = { export default {
meta: { meta: {
type: "suggestion", type: "suggestion",
docs: {
url: "https://github.com/prettier/prettier/blob/main/scripts/tools/eslint-plugin-prettier-internal-rules/no-node-comments.js",
},
messages: { messages: {
[messageId]: "Do not access node.comments.", [messageId]: "Do not access node.comments.",
}, },
@@ -62,7 +58,7 @@ module.exports = {
} }
const { file, functions } = option; const { file, functions } = option;
return [ return [
path.join(__dirname, "../../..", file), path.join(import.meta.dirname, "../../..", file),
functions ? new Set(functions) : true, functions ? new Set(functions) : true,
]; ];
}), }),
@@ -1,5 +1,3 @@
"use strict";
const selector = [ const selector = [
"CallExpression", "CallExpression",
"[optional=false]", "[optional=false]",
@@ -14,12 +12,9 @@ const selector = [
const messageId = "no-unnecessary-ast-path-call"; const messageId = "no-unnecessary-ast-path-call";
module.exports = { export default {
meta: { meta: {
type: "suggestion", type: "suggestion",
docs: {
url: "https://github.com/prettier/prettier/blob/main/scripts/tools/eslint-plugin-prettier-internal-rules/no-unnecessary-ast-path-call.js",
},
messages: { messages: {
[messageId]: "Do not use `AstPath.call()` with one argument.", [messageId]: "Do not use `AstPath.call()` with one argument.",
}, },
@@ -3,9 +3,9 @@
"version": "1.0.3", "version": "1.0.3",
"description": "Prettier internal eslint rules", "description": "Prettier internal eslint rules",
"private": true, "private": true,
"type": "commonjs", "type": "module",
"author": "fisker", "author": "fisker",
"main": "./index.js", "exports": "./index.js",
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {
"test": "node test.js", "test": "node test.js",
@@ -1,5 +1,3 @@
"use strict";
const selector = [ const selector = [
"ExpressionStatement", "ExpressionStatement",
">", ">",
@@ -16,12 +14,9 @@ const selector = [
const messageId = "prefer-ast-path-each"; const messageId = "prefer-ast-path-each";
module.exports = { export default {
meta: { meta: {
type: "suggestion", type: "suggestion",
docs: {
url: "https://github.com/prettier/prettier/blob/main/scripts/tools/eslint-plugin-prettier-internal-rules/require-json-extensions.js",
},
messages: { messages: {
[messageId]: "Prefer `AstPath#each()` over `AstPath#map()`.", [messageId]: "Prefer `AstPath#each()` over `AstPath#map()`.",
}, },
@@ -1,5 +1,3 @@
"use strict";
const selector = [ const selector = [
"CallExpression", "CallExpression",
"[optional=false]", "[optional=false]",
@@ -53,12 +51,9 @@ function getReplacement(callExpression) {
} }
} }
module.exports = { export default {
meta: { meta: {
type: "suggestion", type: "suggestion",
docs: {
url: "https://github.com/prettier/prettier/blob/main/scripts/tools/eslint-plugin-prettier-internal-rules/prefer-ast-path-getters.js",
},
fixable: "code", fixable: "code",
hasSuggestions: true, hasSuggestions: true,
messages: { messages: {
@@ -1,5 +1,3 @@
"use strict";
const MESSAGE_ID = "prefer-create-type-check-function"; const MESSAGE_ID = "prefer-create-type-check-function";
const isTypeAccess = (node, parameterName) => { const isTypeAccess = (node, parameterName) => {
@@ -135,12 +133,9 @@ const selector = [
"[generator!=true]", "[generator!=true]",
].join(""); ].join("");
module.exports = { export default {
meta: { meta: {
type: "suggestion", type: "suggestion",
docs: {
url: "https://github.com/prettier/prettier/blob/main/scripts/tools/eslint-plugin-prettier-internal-rules/prefer-create-type-check-function.js",
},
messages: { messages: {
[MESSAGE_ID]: [MESSAGE_ID]:
"Prefer use `createTypeCheckFunction` to create this function", "Prefer use `createTypeCheckFunction` to create this function",
@@ -1,5 +1,3 @@
"use strict";
const selector = [ const selector = [
"ImportDeclaration", "ImportDeclaration",
"[specifiers.length=1]", "[specifiers.length=1]",
@@ -11,12 +9,9 @@ const selector = [
const messageId = "prefer-fs-promises-submodule"; const messageId = "prefer-fs-promises-submodule";
module.exports = { export default {
meta: { meta: {
type: "suggestion", type: "suggestion",
docs: {
url: "https://github.com/prettier/prettier/blob/main/scripts/tools/eslint-plugin-prettier-internal-rules/prefer-fs-promises-submodule.js",
},
messages: { messages: {
[messageId]: [messageId]:
'Prefer `import fs from "node:fs/promises"` instead of `import { promises as fs } from "fs";`', 'Prefer `import fs from "node:fs/promises"` instead of `import { promises as fs } from "fs";`',
@@ -1,5 +1,3 @@
"use strict";
const selector = [ const selector = [
"CallExpression", "CallExpression",
"[optional=false]", "[optional=false]",
@@ -18,12 +16,9 @@ const selector = [
const messageId = "prefer-indent-if-break"; const messageId = "prefer-indent-if-break";
module.exports = { export default {
meta: { meta: {
type: "suggestion", type: "suggestion",
docs: {
url: "https://github.com/prettier/prettier/blob/main/scripts/tools/eslint-plugin-prettier-internal-rules/prefer-indent-if-break.js",
},
messages: { messages: {
[messageId]: "Prefer `indentIfBreak(…)` over `ifBreak(indent(…), …)`.", [messageId]: "Prefer `indentIfBreak(…)` over `ifBreak(indent(…), …)`.",
}, },
@@ -1,5 +1,3 @@
"use strict";
const getLengthSelector = (path) => const getLengthSelector = (path) =>
`[${path}.type="MemberExpression"][${path}.property.type="Identifier"][${path}.property.name="length"]`; `[${path}.type="MemberExpression"][${path}.property.type="Identifier"][${path}.property.name="length"]`;
const selector = [ const selector = [
@@ -52,12 +50,9 @@ const isArrayIsArrayCall = (node) =>
const MESSAGE_ID = "prefer-is-non-empty-array"; const MESSAGE_ID = "prefer-is-non-empty-array";
module.exports = { export default {
meta: { meta: {
type: "suggestion", type: "suggestion",
docs: {
url: "https://github.com/prettier/prettier/blob/main/scripts/tools/eslint-plugin-prettier-internal-rules/prefer-is-non-empty-array.js",
},
messages: { messages: {
[MESSAGE_ID]: "Please use `isNonEmptyArray()`.", [MESSAGE_ID]: "Please use `isNonEmptyArray()`.",
}, },
@@ -1,12 +1,10 @@
"use strict"; import path from "node:path";
import { RuleTester } from "eslint";
const path = require("path"); import { outdent } from "outdent";
const { outdent } = require("outdent"); import plugin from "./index.js";
const { RuleTester } = require("eslint");
const { rules } = require("./index.js");
const test = (ruleId, tests) => { const test = (ruleId, tests) => {
new RuleTester().run(ruleId, rules[ruleId], tests); new RuleTester().run(ruleId, plugin.rules[ruleId], tests);
}; };
test("await-cli-tests", { test("await-cli-tests", {
@@ -254,7 +252,7 @@ test("no-identifier-n", {
}, },
], ],
}, },
// ESLint 8 doesn't allow suggest invalid code // ESLint>=8 doesn't allow suggest invalid code
// { // {
// code: "const n = 1;const node = 2;", // code: "const n = 1;const node = 2;",
// output: null, // output: null,
@@ -308,12 +306,12 @@ test("no-node-comments", {
"const comments = node.notComments", "const comments = node.notComments",
{ {
code: "function functionName() {return node.comments;}", code: "function functionName() {return node.comments;}",
filename: path.join(__dirname, "../../..", "a.js"), filename: path.join(import.meta.dirname, "../../..", "a.js"),
options: ["a.js"], options: ["a.js"],
}, },
{ {
code: "function functionName() {return node.comments;}", code: "function functionName() {return node.comments;}",
filename: path.join(__dirname, "../../..", "a.js"), filename: path.join(import.meta.dirname, "../../..", "a.js"),
options: [{ file: "a.js", functions: ["functionName"] }], options: [{ file: "a.js", functions: ["functionName"] }],
}, },
], ],
@@ -330,7 +328,7 @@ test("no-node-comments", {
{ {
code: "function notFunctionName() {return node.comments;}", code: "function notFunctionName() {return node.comments;}",
output: null, output: null,
filename: path.join(__dirname, "../../..", "a.js"), filename: path.join(import.meta.dirname, "../../..", "a.js"),
options: [{ file: "a.js", functions: ["functionName"] }], options: [{ file: "a.js", functions: ["functionName"] }],
errors: [{ message: "Do not access node.comments." }], errors: [{ message: "Do not access node.comments." }],
}, },