diff --git a/eslint.config.js b/eslint.config.js index 76a2410b3..d16eb4192 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -24,35 +24,29 @@ import tseslint from "typescript-eslint"; export default tseslint.config( { ignores: [ + "**/*.snap", "coverage*", "lib", "node_modules", "pnpm-lock.yaml", - "**/*.snap", ], }, - { - linterOptions: { - reportUnusedDisableDirectives: "error", - }, - }, + { linterOptions: { reportUnusedDisableDirectives: "error" } }, eslint.configs.recommended, - ...jsonc.configs["flat/recommended-with-json"], - ...markdown.configs.recommended, - ...yml.configs["flat/recommended"], - ...yml.configs["flat/prettier"], comments.recommended, jsdoc.configs["flat/contents-typescript-error"], jsdoc.configs["flat/logical-typescript-error"], jsdoc.configs["flat/stylistic-typescript-error"], + jsonc.configs["flat/recommended-with-json"], + markdown.configs.recommended, n.configs["flat/recommended"], packageJson, perfectionist.configs["recommended-natural"], regexp.configs["flat/recommended"], { extends: [ - ...tseslint.configs.strictTypeChecked, - ...tseslint.configs.stylisticTypeChecked, + tseslint.configs.strictTypeChecked, + tseslint.configs.stylisticTypeChecked, ], files: ["**/*.js", "**/*.ts"], languageOptions: { @@ -94,39 +88,31 @@ export default tseslint.config( "object-shorthand": "error", "operator-assignment": "error", }, - settings: { - perfectionist: { - partitionByComment: true, - type: "natural", - }, - }, + settings: { perfectionist: { partitionByComment: true, type: "natural" } }, + }, + { + extends: [tseslint.configs.disableTypeChecked], + files: ["**/*.md/*.ts"], }, { extends: [vitest.configs.recommended], files: ["**/*.test.*"], rules: { - // These on-by-default rules aren't useful in test files. "@typescript-eslint/no-unsafe-assignment": "off", - "@typescript-eslint/no-unsafe-call": "off", }, }, { + extends: [yml.configs["flat/recommended"], yml.configs["flat/prettier"]], files: ["**/*.{yml,yaml}"], rules: { "yml/file-extension": ["error", { extension: "yml" }], "yml/sort-keys": [ "error", - { - order: { type: "asc" }, - pathPattern: "^.*$", - }, + { order: { type: "asc" }, pathPattern: "^.*$" }, ], "yml/sort-sequence-values": [ "error", - { - order: { type: "asc" }, - pathPattern: "^.*$", - }, + { order: { type: "asc" }, pathPattern: "^.*$" }, ], }, }, diff --git a/script/__snapshots__/migrate-test-e2e.ts.snap b/script/__snapshots__/migrate-test-e2e.ts.snap index 59ab47a41..e394b0f2b 100644 --- a/script/__snapshots__/migrate-test-e2e.ts.snap +++ b/script/__snapshots__/migrate-test-e2e.ts.snap @@ -124,13 +124,29 @@ exports[`expected file changes > eslint.config.js 1`] = ` import comments from "@eslint-community/eslint-plugin-eslint-comments/configs"; import eslint from "@eslint/js"; import vitest from "@vitest/eslint-plugin"; +@@ ... @@ import tseslint from "typescript-eslint"; + + export default tseslint.config( + { +- ignores: [ +- "**/*.snap", +- "coverage*", +- "lib", +- "node_modules", +- "pnpm-lock.yaml", +- ], ++ ignores: ["**/*.snap", "coverage", "lib", "node_modules", "pnpm-lock.yaml"], + }, + { linterOptions: { reportUnusedDisableDirectives: "error" } }, + eslint.configs.recommended, @@ ... @@ export default tseslint.config( + files: ["**/*.js", "**/*.ts"], languageOptions: { parserOptions: { - projectService: { +- projectService: { - allowDefaultProject: ["*.config.*s", "bin/*.js", "script/*.ts"], -+ allowDefaultProject: ["*.config.*s"], - }, +- }, ++ projectService: { allowDefaultProject: ["*.config.*s"] }, tsconfigRootDir: import.meta.dirname, }, }, @@ -159,22 +175,18 @@ exports[`expected file changes > eslint.config.js 1`] = ` "logical-assignment-operators": [ "error", @@ ... @@ export default tseslint.config( - }, - }, - }, -+ { -+ extends: [tseslint.configs.disableTypeChecked], -+ files: ["**/*.md/*.ts"], + { + extends: [tseslint.configs.disableTypeChecked], + files: ["**/*.md/*.ts"], + rules: { + "n/no-missing-import": [ + "error", + { allowModules: ["create-typescript-app"] }, + ], + }, -+ }, + }, { - extends: [vitest.configs.recommended], - files: ["**/*.test.*"]," + extends: [vitest.configs.recommended]," `; exports[`expected file changes > knip.json 1`] = ` diff --git a/src/steps/writing/creation/createESLintConfig.test.ts b/src/steps/writing/creation/createESLintConfig.test.ts index c1bd85614..b01e074be 100644 --- a/src/steps/writing/creation/createESLintConfig.test.ts +++ b/src/steps/writing/creation/createESLintConfig.test.ts @@ -55,14 +55,8 @@ describe("createESLintConfig", () => { import tseslint from "typescript-eslint"; export default tseslint.config( - { - ignores: ["lib", "node_modules", "pnpm-lock.yaml"], - }, - { - linterOptions: { - reportUnusedDisableDirectives: "error", - }, - }, + { ignores: ["lib", "node_modules", "pnpm-lock.yaml"] }, + { linterOptions: { reportUnusedDisableDirectives: "error" } }, eslint.configs.recommended, n.configs["flat/recommended"], { @@ -70,9 +64,7 @@ describe("createESLintConfig", () => { files: ["**/*.js", "**/*.ts"], languageOptions: { parserOptions: { - projectService: { - allowDefaultProject: ["*.config.*s"], - }, + projectService: { allowDefaultProject: ["*.config.*s"] }, tsconfigRootDir: import.meta.dirname, }, }, @@ -107,43 +99,29 @@ describe("createESLintConfig", () => { export default tseslint.config( { - ignores: [ - "coverage*", - "lib", - "node_modules", - "pnpm-lock.yaml", - "**/*.snap", - ], - }, - { - linterOptions: { - reportUnusedDisableDirectives: "error", - }, + ignores: ["**/*.snap", "coverage", "lib", "node_modules", "pnpm-lock.yaml"], }, + { linterOptions: { reportUnusedDisableDirectives: "error" } }, eslint.configs.recommended, - ...jsonc.configs["flat/recommended-with-json"], - ...markdown.configs.recommended, - ...yml.configs["flat/recommended"], - ...yml.configs["flat/prettier"], comments.recommended, jsdoc.configs["flat/contents-typescript-error"], jsdoc.configs["flat/logical-typescript-error"], jsdoc.configs["flat/stylistic-typescript-error"], + jsonc.configs["flat/recommended-with-json"], + markdown.configs.recommended, n.configs["flat/recommended"], packageJson, perfectionist.configs["recommended-natural"], regexp.configs["flat/recommended"], { extends: [ - ...tseslint.configs.strictTypeChecked, - ...tseslint.configs.stylisticTypeChecked, + tseslint.configs.strictTypeChecked, + tseslint.configs.stylisticTypeChecked, ], files: ["**/*.js", "**/*.ts"], languageOptions: { parserOptions: { - projectService: { - allowDefaultProject: ["*.config.*s"], - }, + projectService: { allowDefaultProject: ["*.config.*s"] }, tsconfigRootDir: import.meta.dirname, }, }, @@ -158,12 +136,7 @@ describe("createESLintConfig", () => { "object-shorthand": "error", "operator-assignment": "error", }, - settings: { - perfectionist: { - partitionByComment: true, - type: "natural", - }, - }, + settings: { perfectionist: { partitionByComment: true, type: "natural" } }, }, { extends: [tseslint.configs.disableTypeChecked], @@ -173,31 +146,24 @@ describe("createESLintConfig", () => { }, }, { - files: ["**/*.test.*"], extends: [vitest.configs.recommended], + files: ["**/*.test.*"], rules: { - // These on-by-default rules aren't useful in test files. "@typescript-eslint/no-unsafe-assignment": "off", - "@typescript-eslint/no-unsafe-call": "off", }, }, { + extends: [yml.configs["flat/recommended"], yml.configs["flat/prettier"]], files: ["**/*.{yml,yaml}"], rules: { "yml/file-extension": ["error", { extension: "yml" }], "yml/sort-keys": [ "error", - { - order: { type: "asc" }, - pathPattern: "^.*$", - }, + { order: { type: "asc" }, pathPattern: "^.*$" }, ], "yml/sort-sequence-values": [ "error", - { - order: { type: "asc" }, - pathPattern: "^.*$", - }, + { order: { type: "asc" }, pathPattern: "^.*$" }, ], }, }, diff --git a/src/steps/writing/creation/createESLintConfig.ts b/src/steps/writing/creation/createESLintConfig.ts index e3b109fc7..9f9ba7314 100644 --- a/src/steps/writing/creation/createESLintConfig.ts +++ b/src/steps/writing/creation/createESLintConfig.ts @@ -25,16 +25,13 @@ export async function createESLintConfig(options: Options) { const elements = [ `eslint.configs.recommended,`, - !options.excludeLintJson && - ` ...jsonc.configs["flat/recommended-with-json"],`, - !options.excludeLintMd && ` ...markdown.configs.recommended,`, - !options.excludeLintYml && ` ...yml.configs["flat/recommended"],`, - !options.excludeLintYml && ` ...yml.configs["flat/prettier"],`, !options.excludeLintESLint && ` comments.recommended,`, !options.excludeLintJSDoc && ` jsdoc.configs["flat/contents-typescript-error"], - jsdoc.configs["flat/logical-typescript-error"], - jsdoc.configs["flat/stylistic-typescript-error"],`, + jsdoc.configs["flat/logical-typescript-error"], + jsdoc.configs["flat/stylistic-typescript-error"],`, + !options.excludeLintJson && ` jsonc.configs["flat/recommended-with-json"],`, + !options.excludeLintMd && ` markdown.configs.recommended,`, ` n.configs["flat/recommended"],`, !options.excludeLintPackageJson && ` packageJson,`, !options.excludeLintPerfectionist && @@ -42,6 +39,15 @@ export async function createESLintConfig(options: Options) { !options.excludeLintRegex && ` regexp.configs["flat/recommended"],`, ].filter(Boolean); + const ignores = [ + ...(options.excludeTests ? [] : ["**/*.snap", "coverage"]), + "lib", + "node_modules", + "pnpm-lock.yaml", + ] + .map((ignore) => JSON.stringify(ignore)) + .sort(); + const rules = !options.excludeLintStylistic && `{ @@ -59,44 +65,22 @@ export async function createESLintConfig(options: Options) { return await formatTypeScript(`${imports.join("\n")} export default tseslint.config( - { - ignores: [${ - options.excludeTests - ? "" - : ` - "coverage*",` - } - "lib", - "node_modules", - "pnpm-lock.yaml",${ - options.excludeTests - ? "" - : ` - "**/*.snap",` - } - ], - }, - { - linterOptions: { - reportUnusedDisableDirectives: "error", - }, - }, + { ignores: [${ignores.join(", ")}], }, + { linterOptions: { reportUnusedDisableDirectives: "error" } }, ${elements.join("\n")} { extends: ${ options.excludeLintStylistic ? `tseslint.configs.${tseslintBase}TypeChecked` : `[ - ...tseslint.configs.${tseslintBase}TypeChecked, - ...tseslint.configs.stylisticTypeChecked, + tseslint.configs.${tseslintBase}TypeChecked, + tseslint.configs.stylisticTypeChecked, ]` }, files: ["**/*.js", "**/*.ts"], languageOptions: { parserOptions: { - projectService: { - allowDefaultProject: ["*.config.*s"], - }, + projectService: { allowDefaultProject: ["*.config.*s"] }, tsconfigRootDir: import.meta.dirname }, },${ @@ -108,12 +92,7 @@ export default tseslint.config( options.excludeLintPerfectionist ? "" : ` - settings: { - perfectionist: { - partitionByComment: true, - type: "natural", - }, - },` + settings: { perfectionist: { partitionByComment: true, type: "natural" } },` } }, { @@ -130,12 +109,10 @@ export default tseslint.config( ? "" : ` { - files: ["**/*.test.*"], extends: [vitest.configs.recommended], + files: ["**/*.test.*"], rules: { - // These on-by-default rules aren't useful in test files. "@typescript-eslint/no-unsafe-assignment": "off", - "@typescript-eslint/no-unsafe-call": "off", }, },` }${ @@ -143,22 +120,17 @@ export default tseslint.config( ? "" : ` { + extends: [yml.configs["flat/recommended"], yml.configs["flat/prettier"]], files: ["**/*.{yml,yaml}"], rules: { "yml/file-extension": ["error", { extension: "yml" }], "yml/sort-keys": [ "error", - { - order: { type: "asc" }, - pathPattern: "^.*$", - }, + { order: { type: "asc" }, pathPattern: "^.*$" }, ], "yml/sort-sequence-values": [ "error", - { - order: { type: "asc" }, - pathPattern: "^.*$", - }, + { order: { type: "asc" }, pathPattern: "^.*$" }, ], }, },`