From ea428f603ed9383bc663643b41ed8f630c7ae83b Mon Sep 17 00:00:00 2001 From: Jeroen Claassens Date: Sun, 7 Apr 2024 14:50:46 +0200 Subject: [PATCH] feat(eslint-plugin-result)!: update to eslint v9 flat config BREAKING CHANGE: This plugin now requires eslint v9 or higher. For more information see the [eslint migration guide](https://eslint.org/blog/2024/04/eslint-v9.0.0-released) and [flat config guide](https://eslint.org/blog/2022/08/new-config-system-part-2/). The README of this package has instructions for how to use this package with the new flat config system. --- packages/eslint-plugin-result/README.md | 48 ++++++++++++----- packages/eslint-plugin-result/package.json | 31 ++++++++--- .../src/configs/recommended.ts | 11 +++- packages/eslint-plugin-result/src/index.ts | 51 +++++++++++++------ .../src/rules/no-discard-result.ts | 6 ++- .../eslint-plugin-result/src/tsconfig.json | 2 - .../tests/rules/no-discard-result.test.ts | 24 ++++++--- packages/eslint-plugin-result/tests/shared.ts | 10 ---- .../tests/vitest.setup.ts | 4 ++ packages/eslint-plugin-result/tsup.config.ts | 11 ++-- .../eslint-plugin-result/vitest.config.ts | 6 ++- 11 files changed, 141 insertions(+), 63 deletions(-) delete mode 100644 packages/eslint-plugin-result/tests/shared.ts create mode 100644 packages/eslint-plugin-result/tests/vitest.setup.ts diff --git a/packages/eslint-plugin-result/README.md b/packages/eslint-plugin-result/README.md index 1e76e66198..b5894d4b68 100644 --- a/packages/eslint-plugin-result/README.md +++ b/packages/eslint-plugin-result/README.md @@ -30,25 +30,46 @@ You can use the following command to install this package, or replace `npm insta npm install @sapphire/eslint-plugin-result ``` +It is important to note that this package only exports [ESLint Flat Config][]! This means that you _have_ to use `eslint.config.mjs` to use this package. See the ESLint documentation on flat config for more information. + ## Usage -Somewhere in your ESLint configuration: +1. Create a file `eslint.config.mjs` in the root of your project. +2. Add the following content to the file: -```json -{ - "extends": ["plugin:@sapphire/result/recommended"] -} -``` +```js +import sapphireEslintPluginResult from '@sapphire/eslint-plugin-result/recommended'; -Or +/** + * @type {import('@typescript-eslint/utils').TSESLint.FlatConfig.ConfigArray} + */ +const config = [ + // Additional config here + sapphireEslintPluginResult + // or here +]; -```json -{ - "plugins": ["@sapphire/result"], - "rules": { - "@sapphire/result/no-discard-result": "error" +export default config; +``` + +```js +import sapphireEslintPluginResult from '@sapphire/eslint-plugin-result'; + +/** + * @type {import('@typescript-eslint/utils').TSESLint.FlatConfig.ConfigArray} + */ +const config = [ + // Additional config here + { + plugins: { result: sapphireEslintPluginResult }, + rules: { + '@sapphire/result/no-discard-result': 'error' + } } -} + // or here +]; + +export default config; ``` ## Buy us some doughnuts @@ -75,3 +96,4 @@ Thank you to all the people who already contributed to Sapphire! [contributing]: https://github.com/sapphiredev/.github/blob/main/.github/CONTRIBUTING.md +[ESLint Flat Config]: https://eslint.org/blog/2022/08/new-config-system-part-2/ diff --git a/packages/eslint-plugin-result/package.json b/packages/eslint-plugin-result/package.json index 2694ea973b..92fce8eeef 100644 --- a/packages/eslint-plugin-result/package.json +++ b/packages/eslint-plugin-result/package.json @@ -6,12 +6,27 @@ "license": "MIT", "main": "dist/cjs/index.cjs", "module": "dist/esm/index.mjs", + "types": "dist/cjs/index.d.cts", "exports": { - "import": { - "default": "./dist/esm/index.mjs" + ".": { + "import": { + "types": "./dist/esm/index.d.mts", + "default": "./dist/esm/index.mjs" + }, + "require": { + "types": "./dist/cjs/index.d.cts", + "default": "./dist/cjs/index.cjs" + } }, - "require": { - "default": "./dist/cjs/index.cjs" + "./recommended": { + "import": { + "types": "./dist/esm/configs/recommended.d.mts", + "default": "./dist/esm/configs/recommended.mjs" + }, + "require": { + "types": "./dist/cjs/configs/recommended.d.cts", + "default": "./dist/configs/recommended.cjs" + } } }, "sideEffects": false, @@ -19,7 +34,8 @@ "scripts": { "test": "vitest run", "lint": "eslint src tests --fix -c ../../eslint.config.mjs", - "build": "tsup", + "build": "tsup && yarn build:rename-cjs-index", + "build:rename-cjs-index": "tsx --tsconfig ../../scripts/tsconfig.json ../../scripts/rename-cjs-index.cts", "prepack": "yarn build", "bump": "cliff-jumper", "check-update": "cliff-jumper --dry-run" @@ -33,8 +49,8 @@ "dist/" ], "engines": { - "node": ">=v14.0.0", - "npm": ">=7.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0", + "npm": ">=10.0.0" }, "keywords": [ "@sapphire/eslint-plugin-result", @@ -57,6 +73,7 @@ "@typescript-eslint/typescript-estree": "^7.10.0", "@vitest/coverage-v8": "^1.6.0", "tsup": "^8.0.2", + "tsx": "^4.7.2", "typedoc-json-parser": "^10.0.0", "vitest": "^1.6.0" }, diff --git a/packages/eslint-plugin-result/src/configs/recommended.ts b/packages/eslint-plugin-result/src/configs/recommended.ts index 809d076076..579837b5ee 100644 --- a/packages/eslint-plugin-result/src/configs/recommended.ts +++ b/packages/eslint-plugin-result/src/configs/recommended.ts @@ -1,6 +1,13 @@ -export const recommendedConfig = { - plugins: ['@sapphire/eslint-plugin-result'], +import type { TSESLint } from '@typescript-eslint/utils'; +import sapphireEslintPluginResult from '../index'; + +const recommendedConfig: TSESLint.FlatConfig.Config = { + plugins: { + result: sapphireEslintPluginResult + }, rules: { '@sapphire/result/no-discard-result': 'error' } }; + +export default recommendedConfig; diff --git a/packages/eslint-plugin-result/src/index.ts b/packages/eslint-plugin-result/src/index.ts index 5804d0c9ef..d06090b633 100644 --- a/packages/eslint-plugin-result/src/index.ts +++ b/packages/eslint-plugin-result/src/index.ts @@ -1,25 +1,46 @@ -import { recommendedConfig } from './configs/recommended'; +import recommendedConfig from './configs/recommended'; import { noDiscardResult } from './rules/no-discard-result'; +import type { TSESLint } from '@typescript-eslint/utils'; /** * ESLint plugin result for @sapphire/result package * @example - * ```json - * { - * "extends": "plugin:@sapphire/result/recommended" - * } + * file: `eslint.config.mjs` + * ```typescript + * import sapphireEslintPluginResult from '@sapphire/eslint-plugin-result/recommended'; + * + * const config = [ + * sapphireEslintPluginResult, + * ]; + * + * export default config; * ``` + * * @example - * ```json - * { - * "plugins": ["@sapphire/result"], - * "rules": { - * "@sapphire/result/no-discard-result": "error" - * } - *} - *``` + * file: `eslint.config.mjs` + * ```typescript + * import sapphireEslintPluginResult from '@sapphire/eslint-plugin-result'; + * + * const config = [ + * { + * plugins: { result: sapphireEslintPluginResult }, + * rules: { '@sapphire/result/no-discard-result': 'error' } + * }, + * ]; + * + * export default config; + * ``` + * + * Optionally, you can type the config object as + * ``` + * import('@typescript-eslint/utils').TSESLint.FlatConfig.ConfigArray + * ``` */ -const eslintPluginResult = { +const eslintPluginResult: TSESLint.FlatConfig.Plugin = { + meta: { + name: '@sapphire/eslint-plugin-result', + version: '[VI]{{inject}}[/VI]' + }, rules: { 'no-discard-result': noDiscardResult }, @@ -28,4 +49,4 @@ const eslintPluginResult = { } }; -module.exports = eslintPluginResult; +export default eslintPluginResult; diff --git a/packages/eslint-plugin-result/src/rules/no-discard-result.ts b/packages/eslint-plugin-result/src/rules/no-discard-result.ts index daff729a27..6264a51c55 100644 --- a/packages/eslint-plugin-result/src/rules/no-discard-result.ts +++ b/packages/eslint-plugin-result/src/rules/no-discard-result.ts @@ -112,7 +112,11 @@ export const noDiscardResult: RuleModule<'discardedResult', [], RuleListener> = meta: { messages, type: 'problem', - schema: [] + schema: [], + docs: { + description: 'Disallow discarding the result of a function returning a Result.', + url: 'https://github.com/sapphiredev/utilities/blob/main/packages/eslint-plugin-result/README.md' + } }, defaultOptions: [], create: (context) => { diff --git a/packages/eslint-plugin-result/src/tsconfig.json b/packages/eslint-plugin-result/src/tsconfig.json index 8bf47c0152..ad55754826 100644 --- a/packages/eslint-plugin-result/src/tsconfig.json +++ b/packages/eslint-plugin-result/src/tsconfig.json @@ -3,8 +3,6 @@ "compilerOptions": { "rootDir": "./", "outDir": "../dist", - "moduleResolution": "Node16", - "verbatimModuleSyntax": false, "incremental": false }, "include": ["."] diff --git a/packages/eslint-plugin-result/tests/rules/no-discard-result.test.ts b/packages/eslint-plugin-result/tests/rules/no-discard-result.test.ts index 2db74b2174..b55f34404e 100644 --- a/packages/eslint-plugin-result/tests/rules/no-discard-result.test.ts +++ b/packages/eslint-plugin-result/tests/rules/no-discard-result.test.ts @@ -1,7 +1,17 @@ +import { fileURLToPath } from 'url'; import { noDiscardResult } from '../../src/rules/no-discard-result'; -import { ruleTester } from '../shared'; +import { RuleTester } from '@typescript-eslint/rule-tester'; -describe.skip('ESLint plugin result', () => { +export const ruleTester = new RuleTester({ + parserOptions: { + ecmaVersion: 2020, + tsconfigRootDir: fileURLToPath(new URL('..', import.meta.url)), + project: '../tsconfig.json' + }, + parser: '@typescript-eslint/parser' +}); + +describe('ESLint plugin result', () => { ruleTester.run('no-discard-result', noDiscardResult, { valid: [ { @@ -35,7 +45,7 @@ describe.skip('ESLint plugin result', () => { { code: `import { Result } from '@sapphire/result'; function foo(): Result {} - + foo();`, name: 'simple discard', errors: [ @@ -48,7 +58,7 @@ describe.skip('ESLint plugin result', () => { { code: `import { Result } from '@sapphire/result'; async function foo(): Promise> {} - + foo();`, name: 'unawaited async function discarded', errors: [ @@ -61,7 +71,7 @@ describe.skip('ESLint plugin result', () => { { code: `import { Result } from '@sapphire/result'; async function foo(): Promise> {} - + await foo();`, name: 'awaited async function discarded', errors: [ @@ -74,7 +84,7 @@ describe.skip('ESLint plugin result', () => { { code: `import { Result } from '@sapphire/result'; function foo(): Promise> {} - + ( foo(), await foo() @@ -94,7 +104,7 @@ describe.skip('ESLint plugin result', () => { { code: `import { Result } from '@sapphire/result'; function foo(): Promise> {} - + null ?? foo(); `, name: 'potential discard (??)', diff --git a/packages/eslint-plugin-result/tests/shared.ts b/packages/eslint-plugin-result/tests/shared.ts deleted file mode 100644 index ec0ac60e7b..0000000000 --- a/packages/eslint-plugin-result/tests/shared.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { RuleTester } from '@typescript-eslint/rule-tester'; - -export const ruleTester = new RuleTester({ - parserOptions: { - ecmaVersion: 2020, - tsconfigRootDir: __dirname, - project: './tsconfig.json' - }, - parser: '@typescript-eslint/parser' -}); diff --git a/packages/eslint-plugin-result/tests/vitest.setup.ts b/packages/eslint-plugin-result/tests/vitest.setup.ts new file mode 100644 index 0000000000..9bba06e945 --- /dev/null +++ b/packages/eslint-plugin-result/tests/vitest.setup.ts @@ -0,0 +1,4 @@ +import * as vitest from 'vitest'; +import { RuleTester } from '@typescript-eslint/rule-tester'; + +RuleTester.afterAll = vitest.afterAll; diff --git a/packages/eslint-plugin-result/tsup.config.ts b/packages/eslint-plugin-result/tsup.config.ts index c0f53eb9c4..c210cc241c 100644 --- a/packages/eslint-plugin-result/tsup.config.ts +++ b/packages/eslint-plugin-result/tsup.config.ts @@ -1,13 +1,14 @@ +import { esbuildPluginVersionInjector } from 'esbuild-plugin-version-injector'; import { Options } from 'tsup'; import { createTsupConfig } from '../../scripts/tsup.config'; -const options: Options = { - sourcemap: false, - dts: false +const defaultOptions: Options = { + entry: ['src/index.ts', 'src/configs/recommended.ts'], + esbuildPlugins: [esbuildPluginVersionInjector()] }; export default createTsupConfig({ - cjsOptions: options, - esmOptions: options, + cjsOptions: defaultOptions, + esmOptions: defaultOptions, iifeOptions: { disabled: true } }); diff --git a/packages/eslint-plugin-result/vitest.config.ts b/packages/eslint-plugin-result/vitest.config.ts index 5223a8a212..3ebf142df2 100644 --- a/packages/eslint-plugin-result/vitest.config.ts +++ b/packages/eslint-plugin-result/vitest.config.ts @@ -1,3 +1,7 @@ import { createVitestConfig } from '../../scripts/vitest.config'; -export default createVitestConfig(); +export default createVitestConfig({ + test: { + setupFiles: ['./tests/vitest.setup.ts'] + } +});