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