From 1d3533fca47673ca1dc9e50dbe5a00ad8adb5362 Mon Sep 17 00:00:00 2001 From: Rebecca Stevens Date: Thu, 14 Mar 2024 18:29:46 +1300 Subject: [PATCH] feat: move flat configs to new "flat" subpackage --- .eslintrc.json | 1 + GETTING_STARTED.md | 11 ++++++ README.md | 3 -- knip.jsonc | 7 +++- package.json | 24 ++++++++---- rollup.config.ts | 40 ++++++++++++++++--- src/classic.ts | 47 ++++++++++++++++++++++ src/flat.ts | 60 ++++++++++++++++++++++++++++ src/index.ts | 96 --------------------------------------------- tests/index.test.ts | 44 +++++++++++++++++---- tsconfig.base.json | 3 +- 11 files changed, 216 insertions(+), 120 deletions(-) create mode 100644 src/classic.ts create mode 100644 src/flat.ts delete mode 100644 src/index.ts diff --git a/.eslintrc.json b/.eslintrc.json index 606af606c..b51e8ac66 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -119,6 +119,7 @@ "@typescript-eslint/no-unused-vars": "off", "@typescript-eslint/prefer-function-type": "off", "@typescript-eslint/consistent-generic-constructors": "off", + "import/extensions": "off", "import/no-unresolved": "off", "init-declarations": "off", "jsdoc/require-jsdoc": "off", diff --git a/GETTING_STARTED.md b/GETTING_STARTED.md index afe80fdba..44f7198a6 100644 --- a/GETTING_STARTED.md +++ b/GETTING_STARTED.md @@ -30,6 +30,17 @@ pnpm add -D eslint @typescript-eslint/parser eslint-plugin-functional ## Usage +### Flat Config + +If using the new [flat config](https://eslint.org/docs/latest/use/configure/configuration-files-new), +import from `eslint-plugin-functional/flat`. + +```ts +import functional from "eslint-plugin-functional/flat"; +``` + +### Classic Config + Add `functional` to the plugins section of your `.eslintrc` configuration file. Then configure the rules you want to use under the rules section. ```jsonc diff --git a/README.md b/README.md index 5b39e7325..6cd12ff70 100644 --- a/README.md +++ b/README.md @@ -35,9 +35,6 @@ Tidelift is working with the maintainers of `eslint-plugin-functional` and a gro The following rulesets are made available by this plugin. -Note: if using a [flat config](https://eslint.org/docs/latest/use/configure/configuration-files-new) add a `flat/` prefix to the preset name -(e.g. `functional.configs["flat/recommended"]`). - Presets: - **Strict** (`plugin:functional/strict`)\ diff --git a/knip.jsonc b/knip.jsonc index 1df103e8f..f56a9a26a 100644 --- a/knip.jsonc +++ b/knip.jsonc @@ -1,6 +1,11 @@ { "$schema": "node_modules/knip/schema-jsonc.json", - "entry": ["src/index.ts!", "tests/**/*.test.ts", "cz-adapter/index.js"], + "entry": [ + "src/flat.ts!", + "src/classic.ts!", + "tests/**/*.test.ts", + "cz-adapter/index.js", + ], "project": ["src/**/*.ts!", "tests/**/*.ts", "cz-adapter/**/*.{js,ts}"], "ignore": ["tests/fixture/file.ts"], "ignoreDependencies": ["@types/eslint", "@vitest/coverage-istanbul"], diff --git a/package.json b/package.json index 31d4ed5dc..fc090acda 100644 --- a/package.json +++ b/package.json @@ -34,15 +34,25 @@ "Jonas Kello" ], "exports": { - "types": { - "import": "./lib/index.d.mts", - "require": "./lib/index.d.cts" + ".": { + "types": { + "import": "./lib/classic.d.mts", + "require": "./lib/classic.d.cts" + }, + "import": "./lib/classic.mjs", + "require": "./lib/classic.cjs" }, - "import": "./lib/index.mjs", - "require": "./lib/index.cjs" + "./flat": { + "types": { + "import": "./lib/flat.d.mts", + "require": "./lib/flat.d.cts" + }, + "import": "./lib/flat.mjs", + "require": "./lib/flat.cjs" + } }, - "main": "lib/index.cjs", - "types": "lib/index.d.cts", + "main": "lib/classic.cjs", + "types": "lib/classic.d.cts", "files": [ "lib/", "package.json", diff --git a/rollup.config.ts b/rollup.config.ts index 2bfb8f232..5c85096c7 100644 --- a/rollup.config.ts +++ b/rollup.config.ts @@ -12,17 +12,17 @@ const treeshake = { unknownGlobalSideEffects: false, } satisfies RollupOptions["treeshake"]; -const library = { - input: "src/index.ts", +const classic = { + input: "src/classic.ts", output: [ { - file: pkg.exports.import, + file: pkg.exports["."].import, format: "esm", sourcemap: false, }, { - file: pkg.exports.require, + file: pkg.exports["."].require, format: "cjs", sourcemap: false, }, @@ -42,4 +42,34 @@ const library = { treeshake, } satisfies RollupOptions; -export default [library]; +const flat = { + input: "src/flat.ts", + + output: [ + { + file: pkg.exports["./flat"].import, + format: "esm", + sourcemap: false, + }, + { + file: pkg.exports["./flat"].require, + format: "cjs", + sourcemap: false, + }, + ], + + plugins: [ + rollupPluginAutoExternal(), + rollupPluginTs({ + transpileOnly: true, + tsconfig: "tsconfig.build.json", + }), + rollupPluginDeassert({ + include: ["**/*.{js,ts}"], + }), + ], + + treeshake, +} satisfies RollupOptions; + +export default [classic, flat]; diff --git a/src/classic.ts b/src/classic.ts new file mode 100644 index 000000000..21ca483ab --- /dev/null +++ b/src/classic.ts @@ -0,0 +1,47 @@ +import { type Linter } from "@typescript-eslint/utils/ts-eslint"; + +import all from "#eslint-plugin-functional/configs/all"; +import currying from "#eslint-plugin-functional/configs/currying"; +import disableTypeChecked from "#eslint-plugin-functional/configs/disable-type-checked"; +import externalTypeScriptRecommended from "#eslint-plugin-functional/configs/external-typescript-recommended"; +import externalVanillaRecommended from "#eslint-plugin-functional/configs/external-vanilla-recommended"; +import lite from "#eslint-plugin-functional/configs/lite"; +import noExceptions from "#eslint-plugin-functional/configs/no-exceptions"; +import noMutations from "#eslint-plugin-functional/configs/no-mutations"; +import noOtherParadigms from "#eslint-plugin-functional/configs/no-other-paradigms"; +import noStatements from "#eslint-plugin-functional/configs/no-statements"; +import off from "#eslint-plugin-functional/configs/off"; +import recommended from "#eslint-plugin-functional/configs/recommended"; +import strict from "#eslint-plugin-functional/configs/strict"; +import stylistic from "#eslint-plugin-functional/configs/stylistic"; +import { rules } from "#eslint-plugin-functional/rules"; +import { ruleNameScope } from "#eslint-plugin-functional/utils/misc"; + +export default { + rules, + configs: { + all: { plugins: [ruleNameScope], rules: all }, + lite: { plugins: [ruleNameScope], rules: lite }, + recommended: { plugins: [ruleNameScope], rules: recommended }, + strict: { plugins: [ruleNameScope], rules: strict }, + off: { plugins: [ruleNameScope], rules: off }, + "disable-type-checked": { + plugins: [ruleNameScope], + rules: disableTypeChecked, + }, + "external-vanilla-recommended": { + plugins: [ruleNameScope], + rules: externalVanillaRecommended, + }, + "external-typescript-recommended": { + plugins: [ruleNameScope], + rules: externalTypeScriptRecommended, + }, + currying: { plugins: [ruleNameScope], rules: currying }, + "no-exceptions": { plugins: [ruleNameScope], rules: noExceptions }, + "no-mutations": { plugins: [ruleNameScope], rules: noMutations }, + "no-other-paradigms": { plugins: [ruleNameScope], rules: noOtherParadigms }, + "no-statements": { plugins: [ruleNameScope], rules: noStatements }, + stylistic: { plugins: [ruleNameScope], rules: stylistic }, + }, +} as Linter.Plugin; diff --git a/src/flat.ts b/src/flat.ts new file mode 100644 index 000000000..3ec7ba694 --- /dev/null +++ b/src/flat.ts @@ -0,0 +1,60 @@ +import { type FlatConfig } from "@typescript-eslint/utils/ts-eslint"; + +import all from "#eslint-plugin-functional/configs/all"; +import currying from "#eslint-plugin-functional/configs/currying"; +import disableTypeChecked from "#eslint-plugin-functional/configs/disable-type-checked"; +import externalTypeScriptRecommended from "#eslint-plugin-functional/configs/external-typescript-recommended"; +import externalVanillaRecommended from "#eslint-plugin-functional/configs/external-vanilla-recommended"; +import lite from "#eslint-plugin-functional/configs/lite"; +import noExceptions from "#eslint-plugin-functional/configs/no-exceptions"; +import noMutations from "#eslint-plugin-functional/configs/no-mutations"; +import noOtherParadigms from "#eslint-plugin-functional/configs/no-other-paradigms"; +import noStatements from "#eslint-plugin-functional/configs/no-statements"; +import off from "#eslint-plugin-functional/configs/off"; +import recommended from "#eslint-plugin-functional/configs/recommended"; +import strict from "#eslint-plugin-functional/configs/strict"; +import stylistic from "#eslint-plugin-functional/configs/stylistic"; +import { rules } from "#eslint-plugin-functional/rules"; +import { __VERSION__ } from "#eslint-plugin-functional/utils/constants"; + +const functional = { + meta: { + name: "eslint-plugin-functional", + version: __VERSION__, + } as const, + rules, +} satisfies Omit; + +const configs = { + all: { plugins: { functional }, rules: all }, + lite: { plugins: { functional }, rules: lite }, + recommended: { plugins: { functional }, rules: recommended }, + strict: { plugins: { functional }, rules: strict }, + off: { plugins: { functional }, rules: off }, + disableTypeChecked: { + plugins: { functional }, + rules: disableTypeChecked, + }, + externalVanillaRecommended: { + plugins: { functional }, + rules: externalVanillaRecommended, + }, + externalTypescriptRecommended: { + plugins: { functional }, + rules: externalTypeScriptRecommended, + }, + currying: { plugins: { functional }, rules: currying }, + noExceptions: { plugins: { functional }, rules: noExceptions }, + noMutations: { plugins: { functional }, rules: noMutations }, + noOtherParadigms: { + plugins: { functional }, + rules: noOtherParadigms, + }, + noStatements: { plugins: { functional }, rules: noStatements }, + stylistic: { plugins: { functional }, rules: stylistic }, +} satisfies Record; + +export default { + ...functional, + configs, +} as const; diff --git a/src/index.ts b/src/index.ts deleted file mode 100644 index 6e3aa8958..000000000 --- a/src/index.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { - type ClassicConfig, - type FlatConfig, -} from "@typescript-eslint/utils/ts-eslint"; - -import all from "#eslint-plugin-functional/configs/all"; -import currying from "#eslint-plugin-functional/configs/currying"; -import disableTypeChecked from "#eslint-plugin-functional/configs/disable-type-checked"; -import externalTypeScriptRecommended from "#eslint-plugin-functional/configs/external-typescript-recommended"; -import externalVanillaRecommended from "#eslint-plugin-functional/configs/external-vanilla-recommended"; -import lite from "#eslint-plugin-functional/configs/lite"; -import noExceptions from "#eslint-plugin-functional/configs/no-exceptions"; -import noMutations from "#eslint-plugin-functional/configs/no-mutations"; -import noOtherParadigms from "#eslint-plugin-functional/configs/no-other-paradigms"; -import noStatements from "#eslint-plugin-functional/configs/no-statements"; -import off from "#eslint-plugin-functional/configs/off"; -import recommended from "#eslint-plugin-functional/configs/recommended"; -import strict from "#eslint-plugin-functional/configs/strict"; -import stylistic from "#eslint-plugin-functional/configs/stylistic"; -import { rules } from "#eslint-plugin-functional/rules"; -import { __VERSION__ } from "#eslint-plugin-functional/utils/constants"; -import { ruleNameScope } from "#eslint-plugin-functional/utils/misc"; - -const functional = { - meta: { - name: "eslint-plugin-functional", - version: __VERSION__, - } as const, - rules, -} satisfies Omit; - -const classicConfigs = { - all: { plugins: [ruleNameScope], rules: all }, - lite: { plugins: [ruleNameScope], rules: lite }, - recommended: { plugins: [ruleNameScope], rules: recommended }, - strict: { plugins: [ruleNameScope], rules: strict }, - off: { plugins: [ruleNameScope], rules: off }, - "disable-type-checked": { - plugins: [ruleNameScope], - rules: disableTypeChecked, - }, - "external-vanilla-recommended": { - plugins: [ruleNameScope], - rules: externalVanillaRecommended, - }, - "external-typescript-recommended": { - plugins: [ruleNameScope], - rules: externalTypeScriptRecommended, - }, - currying: { plugins: [ruleNameScope], rules: currying }, - "no-exceptions": { plugins: [ruleNameScope], rules: noExceptions }, - "no-mutations": { plugins: [ruleNameScope], rules: noMutations }, - "no-other-paradigms": { plugins: [ruleNameScope], rules: noOtherParadigms }, - "no-statements": { plugins: [ruleNameScope], rules: noStatements }, - stylistic: { plugins: [ruleNameScope], rules: stylistic }, -} satisfies Record; - -const flatConfigs = { - "flat/all": { plugins: { functional }, rules: all }, - "flat/lite": { plugins: { functional }, rules: lite }, - "flat/recommended": { plugins: { functional }, rules: recommended }, - "flat/strict": { plugins: { functional }, rules: strict }, - "flat/off": { plugins: { functional }, rules: off }, - "flat/disable-type-checked": { - plugins: { functional }, - rules: disableTypeChecked, - }, - "flat/external-vanilla-recommended": { - plugins: { functional }, - rules: externalVanillaRecommended, - }, - "flat/external-typescript-recommended": { - plugins: { functional }, - rules: externalTypeScriptRecommended, - }, - "flat/currying": { plugins: { functional }, rules: currying }, - "flat/no-exceptions": { plugins: { functional }, rules: noExceptions }, - "flat/no-mutations": { plugins: { functional }, rules: noMutations }, - "flat/no-other-paradigms": { - plugins: { functional }, - rules: noOtherParadigms, - }, - "flat/no-statements": { plugins: { functional }, rules: noStatements }, - "flat/stylistic": { plugins: { functional }, rules: stylistic }, -} satisfies Record; - -export default { - ...functional, - configs: { - ...(flatConfigs as Record), - ...(classicConfigs as Record< - keyof typeof classicConfigs, - ClassicConfig.Config - >), - } as const, -} as const; diff --git a/tests/index.test.ts b/tests/index.test.ts index 62d9c2e55..103552985 100644 --- a/tests/index.test.ts +++ b/tests/index.test.ts @@ -6,19 +6,20 @@ import { readdirSync } from "node:fs"; import { describe, expect, it } from "vitest"; -import plugin from "#eslint-plugin-functional"; +import classic from "#eslint-plugin-functional/classic"; +import flat from "#eslint-plugin-functional/flat"; -describe("index.ts", () => { +describe("Flat", () => { it("should have all the rules", () => { const ruleFiles: string[] = readdirSync("./src/rules").filter( (file) => file !== "index.ts" && file.endsWith(".ts"), ); expect( - Object.hasOwn(plugin, "rules"), + Object.hasOwn(flat, "rules"), 'The plugin\'s config object should have a "rules" property.', ); - expect(ruleFiles.length).to.equal(Object.keys(plugin.rules ?? {}).length); + expect(ruleFiles.length).to.equal(Object.keys(flat.rules ?? {}).length); }); it("should have all the configs", () => { @@ -27,11 +28,40 @@ describe("index.ts", () => { ); expect( - Object.hasOwn(plugin, "configs"), + Object.hasOwn(flat, "configs"), 'The plugin\'s config object should have a "configs" property.', ); - expect(2 * configFiles.length).to.equal( - Object.keys(plugin.configs ?? {}).length, + expect(configFiles.length).to.equal( + Object.keys(flat.configs ?? {}).length, + "should have all the configs except deprecated", + ); + }); +}); + +describe("Classic", () => { + it("should have all the rules", () => { + const ruleFiles: string[] = readdirSync("./src/rules").filter( + (file) => file !== "index.ts" && file.endsWith(".ts"), + ); + + expect( + Object.hasOwn(classic, "rules"), + 'The plugin\'s config object should have a "rules" property.', + ); + expect(ruleFiles.length).to.equal(Object.keys(classic.rules ?? {}).length); + }); + + it("should have all the configs", () => { + const configFiles: string[] = readdirSync("./src/configs").filter( + (file) => file !== "index.ts" && file.endsWith(".ts"), + ); + + expect( + Object.hasOwn(classic, "configs"), + 'The plugin\'s config object should have a "configs" property.', + ); + expect(configFiles.length).to.equal( + Object.keys(classic.configs ?? {}).length, "should have all the configs except deprecated", ); }); diff --git a/tsconfig.base.json b/tsconfig.base.json index 40ccfd783..9a14633b9 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -31,7 +31,8 @@ "types": ["vitest/importMeta"], "baseUrl": ".", "paths": { - "#eslint-plugin-functional": ["src"], + "#eslint-plugin-functional/flat": ["src/flat.ts"], + "#eslint-plugin-functional/classic": ["src/classic.ts"], "#eslint-plugin-functional/configs/*": ["src/configs/*"], "#eslint-plugin-functional/options": ["src/options"], "#eslint-plugin-functional/rules": ["src/rules"],