@forthtilliath/eslint-config 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +49 -4
- package/dist/angular.d.ts.map +1 -1
- package/dist/angular.js +2 -1
- package/dist/base.d.ts +6 -4
- package/dist/base.d.ts.map +1 -1
- package/dist/base.js +10 -5
- package/dist/internal/lazy-config.d.ts +16 -0
- package/dist/internal/lazy-config.d.ts.map +1 -0
- package/dist/internal/lazy-config.js +27 -0
- package/dist/internal/optional-plugin.d.ts +36 -0
- package/dist/internal/optional-plugin.d.ts.map +1 -0
- package/dist/internal/optional-plugin.js +63 -0
- package/dist/nextjs.d.ts.map +1 -1
- package/dist/nextjs.js +2 -1
- package/dist/react-native.d.ts.map +1 -1
- package/dist/react-native.js +2 -1
- package/dist/react.d.ts +14 -10
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +27 -14
- package/dist/storybook.d.ts.map +1 -1
- package/dist/storybook.js +2 -1
- package/package.json +64 -9
package/README.md
CHANGED
|
@@ -24,10 +24,51 @@ Or, from within this monorepo, as a workspace dependency:
|
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
`eslint` and `typescript` are peer dependencies — install them yourself (any
|
|
27
|
-
recent flat-config-era ESLint 9+/10+, and TypeScript 5+).
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
recent flat-config-era ESLint 9+/10+, and TypeScript 5+). Only what the base
|
|
28
|
+
config needs (`typescript-eslint`, `@eslint/js`, `globals`, import sorting,
|
|
29
|
+
Prettier conflict-resolution) ships as a regular dependency: every other
|
|
30
|
+
plugin is an **optional peer dependency**, installed by the project only for
|
|
31
|
+
the variant and options it actually uses. A React Native app doesn't get
|
|
32
|
+
`angular-eslint` (and the Angular CLI it pulls in), nor a TypeScript library
|
|
33
|
+
every React plugin.
|
|
34
|
+
|
|
35
|
+
| Variant / option | Also install |
|
|
36
|
+
| ----------------------- | --------------------------------------------------------------------------------------------------------- |
|
|
37
|
+
| `.` (base) | — |
|
|
38
|
+
| `/react` | `@eslint-react/eslint-plugin eslint-plugin-react eslint-plugin-react-hooks eslint-plugin-react-refresh` |
|
|
39
|
+
| `/react-native` | the `/react` list + `eslint-plugin-react-native` |
|
|
40
|
+
| `/nextjs` | the `/react` list + `@next/eslint-plugin-next` |
|
|
41
|
+
| `/storybook` | the `/react` list + `eslint-plugin-storybook` |
|
|
42
|
+
| `/angular` | `angular-eslint` |
|
|
43
|
+
| `turbo: true` (default) | `eslint-plugin-turbo` — or pass `turbo: false` outside a Turborepo |
|
|
44
|
+
| `a11y: true`\* | `eslint-plugin-jsx-a11y` — \*default for `/react`, `/nextjs`, `/storybook`; pass `a11y: false` to skip it |
|
|
45
|
+
| `i18n: true` | `eslint-plugin-i18next` |
|
|
46
|
+
| `testingLibrary: true` | `eslint-plugin-testing-library eslint-plugin-jest-dom` |
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# e.g. a standalone React Native / Expo app, with createReactNativeConfig({ turbo: false })
|
|
50
|
+
npm install --save-dev @forthtilliath/eslint-config eslint typescript \
|
|
51
|
+
@eslint-react/eslint-plugin eslint-plugin-react eslint-plugin-react-hooks \
|
|
52
|
+
eslint-plugin-react-refresh eslint-plugin-react-native
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
A missing plugin fails with an explicit error naming the package to install
|
|
56
|
+
(or the option to turn off) as soon as ESLint loads the config.
|
|
57
|
+
|
|
58
|
+
**ESLint 10:** `eslint-plugin-react` and `eslint-plugin-react-native` still
|
|
59
|
+
declare `eslint` up to 9 only, so npm refuses to install them next to ESLint
|
|
60
|
+
10 (`ERESOLVE`). They work under ESLint 10 (see the `react-native` rules
|
|
61
|
+
below for the exceptions), so tell npm to accept it in the app's
|
|
62
|
+
`package.json`:
|
|
63
|
+
|
|
64
|
+
```json
|
|
65
|
+
{
|
|
66
|
+
"overrides": {
|
|
67
|
+
"eslint-plugin-react": { "eslint": "$eslint" },
|
|
68
|
+
"eslint-plugin-react-native": { "eslint": "$eslint" }
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
```
|
|
31
72
|
|
|
32
73
|
## Usage
|
|
33
74
|
|
|
@@ -173,6 +214,10 @@ consumer here yet, so `src/angular.test.js` lints small fixture files under
|
|
|
173
214
|
for that. Extend it (or add a sibling `<variant>.test.js`) whenever a variant
|
|
174
215
|
changes without a real consumer to catch a regression.
|
|
175
216
|
|
|
217
|
+
`src/package.test.js` guards the dependency layout: any plugin imported
|
|
218
|
+
outside the base config must stay an optional peer dependency, never a
|
|
219
|
+
regular one.
|
|
220
|
+
|
|
176
221
|
## Scripts
|
|
177
222
|
|
|
178
223
|
```bash
|
package/dist/angular.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"angular.d.ts","sourceRoot":"","sources":["../src/angular.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"angular.d.ts","sourceRoot":"","sources":["../src/angular.js"],"names":[],"mappings":"AAOA;;;;;;;;;;GAUG;AACH,8CAHW,OAAO,WAAW,EAAE,iBAAiB,GACnC,OAAO,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,CA+D5C;AAED;;;;8CAI8C;AAC9C,4BADU,OAAO,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,CAC2B"}
|
package/dist/angular.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import angular from "angular-eslint";
|
|
2
2
|
import { defineConfig } from "eslint/config";
|
|
3
3
|
import tseslint from "typescript-eslint";
|
|
4
|
+
import { lazyConfig } from "./internal/lazy-config.js";
|
|
4
5
|
import { createBaseConfig, NODE_BUILTIN_IMPORT_GROUP } from "./base.js";
|
|
5
6
|
/**
|
|
6
7
|
* A custom ESLint configuration for Angular applications/libraries.
|
|
@@ -80,4 +81,4 @@ export function createAngularConfig(options) {
|
|
|
80
81
|
* default options. Use `createAngularConfig(options)` instead to customize it.
|
|
81
82
|
*
|
|
82
83
|
* @type {import("eslint").Linter.Config[]} */
|
|
83
|
-
export const angularConfig = createAngularConfig();
|
|
84
|
+
export const angularConfig = lazyConfig(() => createAngularConfig());
|
package/dist/base.d.ts
CHANGED
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
* fall back to the plain `recommended` preset instead (useful while
|
|
10
10
|
* migrating an existing codebase that isn't ready for the strict rules).
|
|
11
11
|
* @property {boolean} [turbo=true] - Enable eslint-plugin-turbo's
|
|
12
|
-
* `no-undeclared-env-vars` rule
|
|
13
|
-
* `false` for a standalone
|
|
12
|
+
* `no-undeclared-env-vars` rule (needs `eslint-plugin-turbo` installed).
|
|
13
|
+
* Only relevant inside a Turborepo; set to `false` for a standalone
|
|
14
|
+
* project.
|
|
14
15
|
* @property {boolean} [snakeCase=false] - Also accept `snake_case` variable
|
|
15
16
|
* names in `@typescript-eslint/naming-convention` — for code that
|
|
16
17
|
* destructures rows straight from a SQL database (e.g. Supabase), whose
|
|
@@ -70,8 +71,9 @@ export type BaseConfigOptions = {
|
|
|
70
71
|
strict?: boolean | undefined;
|
|
71
72
|
/**
|
|
72
73
|
* - Enable eslint-plugin-turbo's
|
|
73
|
-
* `no-undeclared-env-vars` rule
|
|
74
|
-
* `false` for a standalone
|
|
74
|
+
* `no-undeclared-env-vars` rule (needs `eslint-plugin-turbo` installed).
|
|
75
|
+
* Only relevant inside a Turborepo; set to `false` for a standalone
|
|
76
|
+
* project.
|
|
75
77
|
*/
|
|
76
78
|
turbo?: boolean | undefined;
|
|
77
79
|
/**
|
package/dist/base.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../src/base.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../src/base.js"],"names":[],"mappings":"AAgCA;;;;;;;;;;;;;;;;;;GAkBG;AAEH;;;;;;;;;;GAUG;AACH,mEALG;IAA0B,SAAS;IACT,KAAK;CAE/B,GAAU,OAAO,QAAQ,EAAE,MAAM,CAAC,SAAS,CA+B7C;AAED;;;;;GAKG;AACH,2EAHW,iBAAiB,GACf,OAAO,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,CAiH5C;AAlMD;;;;;;GAMG;AACH,wCAFU,MAAM,EAAE,CAQhB;AAuLF;;;;;KAKK;AACL,yBAFU,OAAO,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,CAEqB"}
|
package/dist/base.js
CHANGED
|
@@ -2,9 +2,13 @@ import eslint from "@eslint/js";
|
|
|
2
2
|
import { defineConfig } from "eslint/config";
|
|
3
3
|
import eslintConfigPrettier from "eslint-config-prettier";
|
|
4
4
|
import simpleImportSortPlugin from "eslint-plugin-simple-import-sort";
|
|
5
|
-
import turboPlugin from "eslint-plugin-turbo";
|
|
6
5
|
import globals from "globals";
|
|
7
6
|
import tseslint from "typescript-eslint";
|
|
7
|
+
import { lazyConfig } from "./internal/lazy-config.js";
|
|
8
|
+
import { importOptional, requirePlugin } from "./internal/optional-plugin.js";
|
|
9
|
+
// Optional peer dependency: only a Turborepo needs it (and its own `turbo`
|
|
10
|
+
// peer dependency, the whole Turborepo binary).
|
|
11
|
+
const turboPlugin = await importOptional("eslint-plugin-turbo", () => import("eslint-plugin-turbo"));
|
|
8
12
|
/**
|
|
9
13
|
* Node.js builtins without the `node:` prefix, as the first
|
|
10
14
|
* `simple-import-sort/imports` group. Exported so other variants (e.g.
|
|
@@ -30,8 +34,9 @@ export const NODE_BUILTIN_IMPORT_GROUP = [
|
|
|
30
34
|
* fall back to the plain `recommended` preset instead (useful while
|
|
31
35
|
* migrating an existing codebase that isn't ready for the strict rules).
|
|
32
36
|
* @property {boolean} [turbo=true] - Enable eslint-plugin-turbo's
|
|
33
|
-
* `no-undeclared-env-vars` rule
|
|
34
|
-
* `false` for a standalone
|
|
37
|
+
* `no-undeclared-env-vars` rule (needs `eslint-plugin-turbo` installed).
|
|
38
|
+
* Only relevant inside a Turborepo; set to `false` for a standalone
|
|
39
|
+
* project.
|
|
35
40
|
* @property {boolean} [snakeCase=false] - Also accept `snake_case` variable
|
|
36
41
|
* names in `@typescript-eslint/naming-convention` — for code that
|
|
37
42
|
* destructures rows straight from a SQL database (e.g. Supabase), whose
|
|
@@ -152,7 +157,7 @@ export function createBaseConfig({ prettier = true, strict = true, turbo = true,
|
|
|
152
157
|
turbo
|
|
153
158
|
? {
|
|
154
159
|
plugins: {
|
|
155
|
-
turbo: turboPlugin,
|
|
160
|
+
turbo: requirePlugin(turboPlugin, "eslint-plugin-turbo", "turbo"),
|
|
156
161
|
},
|
|
157
162
|
rules: {
|
|
158
163
|
"turbo/no-undeclared-env-vars": "error",
|
|
@@ -194,4 +199,4 @@ export function createBaseConfig({ prettier = true, strict = true, turbo = true,
|
|
|
194
199
|
*
|
|
195
200
|
* @type {import("eslint").Linter.Config[]}
|
|
196
201
|
* */
|
|
197
|
-
export const baseConfig = createBaseConfig();
|
|
202
|
+
export const baseConfig = lazyConfig(() => createBaseConfig());
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wraps a config factory call so it only runs the first time the resulting
|
|
3
|
+
* array is actually read (spread, iterated, indexed...).
|
|
4
|
+
*
|
|
5
|
+
* Every variant module exports a ready-made default (`reactConfig`,
|
|
6
|
+
* `nextJsConfig`...) next to its factory. Built eagerly, that default would
|
|
7
|
+
* load every optional plugin its default options enable (`a11y`, `turbo`) as
|
|
8
|
+
* soon as the module is imported — so a project calling
|
|
9
|
+
* `createReactNativeConfig({ turbo: false })` would still crash on a missing
|
|
10
|
+
* eslint-plugin-turbo, just because `reactConfig` was evaluated on the way.
|
|
11
|
+
*
|
|
12
|
+
* @param {() => import("eslint").Linter.Config[]} create
|
|
13
|
+
* @returns {import("eslint").Linter.Config[]}
|
|
14
|
+
*/
|
|
15
|
+
export function lazyConfig(create: () => import("eslint").Linter.Config[]): import("eslint").Linter.Config[];
|
|
16
|
+
//# sourceMappingURL=lazy-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lazy-config.d.ts","sourceRoot":"","sources":["../../src/internal/lazy-config.js"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,mCAHW,MAAM,OAAO,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GACpC,OAAO,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,CAe5C"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wraps a config factory call so it only runs the first time the resulting
|
|
3
|
+
* array is actually read (spread, iterated, indexed...).
|
|
4
|
+
*
|
|
5
|
+
* Every variant module exports a ready-made default (`reactConfig`,
|
|
6
|
+
* `nextJsConfig`...) next to its factory. Built eagerly, that default would
|
|
7
|
+
* load every optional plugin its default options enable (`a11y`, `turbo`) as
|
|
8
|
+
* soon as the module is imported — so a project calling
|
|
9
|
+
* `createReactNativeConfig({ turbo: false })` would still crash on a missing
|
|
10
|
+
* eslint-plugin-turbo, just because `reactConfig` was evaluated on the way.
|
|
11
|
+
*
|
|
12
|
+
* @param {() => import("eslint").Linter.Config[]} create
|
|
13
|
+
* @returns {import("eslint").Linter.Config[]}
|
|
14
|
+
*/
|
|
15
|
+
export function lazyConfig(create) {
|
|
16
|
+
/** @type {import("eslint").Linter.Config[] | undefined} */
|
|
17
|
+
let config;
|
|
18
|
+
const resolve = () => (config ??= create());
|
|
19
|
+
// The target is a real (empty) array so `Array.isArray()` stays true —
|
|
20
|
+
// ESLint's `defineConfig()` relies on it to flatten nested configs.
|
|
21
|
+
return new Proxy(/** @type {import("eslint").Linter.Config[]} */ ([]), {
|
|
22
|
+
get: (_target, key) => Reflect.get(resolve(), key),
|
|
23
|
+
has: (_target, key) => Reflect.has(resolve(), key),
|
|
24
|
+
ownKeys: () => Reflect.ownKeys(resolve()),
|
|
25
|
+
getOwnPropertyDescriptor: (_target, key) => Reflect.getOwnPropertyDescriptor(resolve(), key),
|
|
26
|
+
});
|
|
27
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugins that only some variants or options use are optional peer
|
|
3
|
+
* dependencies (see package.json's `peerDependenciesMeta`): a React Native app
|
|
4
|
+
* must not end up installing angular-eslint (and the whole Angular CLI it
|
|
5
|
+
* pulls in), nor a plain TypeScript library every React plugin. Plugins a
|
|
6
|
+
* variant always needs are imported statically by that variant's module;
|
|
7
|
+
* plugins behind an option (`a11y`, `i18n`, `testingLibrary`, `turbo`) go
|
|
8
|
+
* through these helpers instead, so a project that leaves the option off
|
|
9
|
+
* doesn't have to install them.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Imports an optional plugin, resolving to `undefined` when the package isn't
|
|
13
|
+
* installed. Any other failure (a broken install, a missing transitive
|
|
14
|
+
* dependency of the plugin itself) is rethrown rather than hidden.
|
|
15
|
+
*
|
|
16
|
+
* @template T
|
|
17
|
+
* @param {string} name - The package name, as passed to `import()`.
|
|
18
|
+
* @param {() => Promise<{ default: T }>} load - `() => import(name)`, written
|
|
19
|
+
* out by the caller so the plugin keeps its type.
|
|
20
|
+
* @returns {Promise<T | undefined>}
|
|
21
|
+
*/
|
|
22
|
+
export function importOptional<T>(name: string, load: () => Promise<{
|
|
23
|
+
default: T;
|
|
24
|
+
}>): Promise<T | undefined>;
|
|
25
|
+
/**
|
|
26
|
+
* Returns `plugin`, or throws an error explaining which package to install
|
|
27
|
+
* (or which option to turn off) when it's missing.
|
|
28
|
+
*
|
|
29
|
+
* @template T
|
|
30
|
+
* @param {T | undefined} plugin
|
|
31
|
+
* @param {string} name - The package name.
|
|
32
|
+
* @param {string} option - The option that needs it, e.g. `a11y`.
|
|
33
|
+
* @returns {T}
|
|
34
|
+
*/
|
|
35
|
+
export function requirePlugin<T>(plugin: T | undefined, name: string, option: string): T;
|
|
36
|
+
//# sourceMappingURL=optional-plugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"optional-plugin.d.ts","sourceRoot":"","sources":["../../src/internal/optional-plugin.js"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;;;;;;;;;GAUG;AACH,+BANa,CAAC,QACH,MAAM,QACN,MAAM,OAAO,CAAC;IAAE,OAAO,EAAE,CAAC,CAAA;CAAE,CAAC,GAE3B,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CASlC;AAmBD;;;;;;;;;GASG;AACH,8BANa,CAAC,UACH,CAAC,GAAG,SAAS,QACb,MAAM,UACN,MAAM,GACJ,CAAC,CAWb"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugins that only some variants or options use are optional peer
|
|
3
|
+
* dependencies (see package.json's `peerDependenciesMeta`): a React Native app
|
|
4
|
+
* must not end up installing angular-eslint (and the whole Angular CLI it
|
|
5
|
+
* pulls in), nor a plain TypeScript library every React plugin. Plugins a
|
|
6
|
+
* variant always needs are imported statically by that variant's module;
|
|
7
|
+
* plugins behind an option (`a11y`, `i18n`, `testingLibrary`, `turbo`) go
|
|
8
|
+
* through these helpers instead, so a project that leaves the option off
|
|
9
|
+
* doesn't have to install them.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Imports an optional plugin, resolving to `undefined` when the package isn't
|
|
13
|
+
* installed. Any other failure (a broken install, a missing transitive
|
|
14
|
+
* dependency of the plugin itself) is rethrown rather than hidden.
|
|
15
|
+
*
|
|
16
|
+
* @template T
|
|
17
|
+
* @param {string} name - The package name, as passed to `import()`.
|
|
18
|
+
* @param {() => Promise<{ default: T }>} load - `() => import(name)`, written
|
|
19
|
+
* out by the caller so the plugin keeps its type.
|
|
20
|
+
* @returns {Promise<T | undefined>}
|
|
21
|
+
*/
|
|
22
|
+
export async function importOptional(name, load) {
|
|
23
|
+
try {
|
|
24
|
+
return (await load()).default;
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
if (isPackageNotFound(error, name))
|
|
28
|
+
return undefined;
|
|
29
|
+
throw error;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* @param {unknown} error
|
|
34
|
+
* @param {string} name
|
|
35
|
+
* @returns {boolean}
|
|
36
|
+
*/
|
|
37
|
+
function isPackageNotFound(error, name) {
|
|
38
|
+
return (error instanceof Error &&
|
|
39
|
+
"code" in error &&
|
|
40
|
+
error.code === "ERR_MODULE_NOT_FOUND" &&
|
|
41
|
+
// Node names the package it couldn't find: checking it tells "the
|
|
42
|
+
// plugin isn't installed" apart from "the plugin is installed but one of
|
|
43
|
+
// its own dependencies is missing", which must not be swallowed.
|
|
44
|
+
error.message.includes(`'${name}'`));
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Returns `plugin`, or throws an error explaining which package to install
|
|
48
|
+
* (or which option to turn off) when it's missing.
|
|
49
|
+
*
|
|
50
|
+
* @template T
|
|
51
|
+
* @param {T | undefined} plugin
|
|
52
|
+
* @param {string} name - The package name.
|
|
53
|
+
* @param {string} option - The option that needs it, e.g. `a11y`.
|
|
54
|
+
* @returns {T}
|
|
55
|
+
*/
|
|
56
|
+
export function requirePlugin(plugin, name, option) {
|
|
57
|
+
if (plugin === undefined) {
|
|
58
|
+
throw new Error(`@forthtilliath/eslint-config: the \`${option}\` option needs ${name}, ` +
|
|
59
|
+
`which isn't installed. Install it as a devDependency ` +
|
|
60
|
+
`(npm install --save-dev ${name}), or pass \`${option}: false\`.`);
|
|
61
|
+
}
|
|
62
|
+
return plugin;
|
|
63
|
+
}
|
package/dist/nextjs.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nextjs.d.ts","sourceRoot":"","sources":["../src/nextjs.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"nextjs.d.ts","sourceRoot":"","sources":["../src/nextjs.js"],"names":[],"mappings":"AAMA;;;;;;;KAOK;AACL,6CAHW,OAAO,WAAW,EAAE,iBAAiB,GAAG,OAAO,YAAY,EAAE,kBAAkB,GAC7E,OAAO,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,CAsD5C;AAED;;;;;KAKK;AACL,2BAFU,OAAO,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,CAEyB"}
|
package/dist/nextjs.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import pluginNext from "@next/eslint-plugin-next";
|
|
2
2
|
import { defineConfig } from "eslint/config";
|
|
3
|
+
import { lazyConfig } from "./internal/lazy-config.js";
|
|
3
4
|
import { createReactConfig } from "./react.js";
|
|
4
5
|
/**
|
|
5
6
|
* A custom ESLint configuration for Next.js applications, built on top of
|
|
@@ -68,4 +69,4 @@ export function createNextJsConfig(options) {
|
|
|
68
69
|
*
|
|
69
70
|
* @type {import("eslint").Linter.Config[]}
|
|
70
71
|
* */
|
|
71
|
-
export const nextJsConfig = createNextJsConfig();
|
|
72
|
+
export const nextJsConfig = lazyConfig(() => createNextJsConfig());
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react-native.d.ts","sourceRoot":"","sources":["../src/react-native.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"react-native.d.ts","sourceRoot":"","sources":["../src/react-native.js"],"names":[],"mappings":"AAMA;;;;;GAKG;AAEH;;;;iDAIiD;AACjD,+DAFW,OAAO,WAAW,EAAE,iBAAiB,GAAG,OAAO,YAAY,EAAE,kBAAkB,GAC7E,OAAO,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,CAwC5C;AAED;;;;;8CAK8C;AAC9C,gCADU,OAAO,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,CACmC"}
|
package/dist/react-native.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { defineConfig } from "eslint/config";
|
|
2
2
|
import pluginReactNative from "eslint-plugin-react-native";
|
|
3
|
+
import { lazyConfig } from "./internal/lazy-config.js";
|
|
3
4
|
import { createReactConfig } from "./react.js";
|
|
4
5
|
/**
|
|
5
6
|
* eslint-plugin-react-native only ships a legacy (eslintrc) `configs.all`
|
|
@@ -58,4 +59,4 @@ export function createReactNativeConfig({ a11y = false, ...options } = {}) {
|
|
|
58
59
|
* customize it.
|
|
59
60
|
*
|
|
60
61
|
* @type {import("eslint").Linter.Config[]} */
|
|
61
|
-
export const reactNativeConfig = createReactNativeConfig();
|
|
62
|
+
export const reactNativeConfig = lazyConfig(() => createReactNativeConfig());
|
package/dist/react.d.ts
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @typedef {object} ReactConfigOptions
|
|
3
3
|
* @property {boolean} [a11y=true] - Enable eslint-plugin-jsx-a11y's
|
|
4
|
-
* recommended rules.
|
|
4
|
+
* recommended rules (needs `eslint-plugin-jsx-a11y` installed).
|
|
5
5
|
* @property {boolean} [i18n=false] - Enable eslint-plugin-i18next's
|
|
6
|
-
* `no-literal-string` rule, forbidding any hardcoded string in JSX
|
|
7
|
-
* makes sense for a project fully
|
|
8
|
-
* next-intl) — off by default since it
|
|
6
|
+
* `no-literal-string` rule, forbidding any hardcoded string in JSX (needs
|
|
7
|
+
* `eslint-plugin-i18next` installed). Only makes sense for a project fully
|
|
8
|
+
* committed to i18n (e.g. driven by next-intl) — off by default since it
|
|
9
|
+
* flags every literal otherwise.
|
|
9
10
|
* @property {boolean} [testingLibrary=false] - Enable
|
|
10
11
|
* eslint-plugin-testing-library's React rules and eslint-plugin-jest-dom's
|
|
11
|
-
* recommended rules, scoped to test files only. Off
|
|
12
|
+
* recommended rules, scoped to test files only (needs both installed). Off
|
|
13
|
+
* by default:
|
|
12
14
|
* `testing-library/no-manual-cleanup` in particular assumes
|
|
13
15
|
* `@testing-library/*`'s automatic `afterEach(cleanup)` is active, which
|
|
14
16
|
* only happens when `afterEach` is a real global (vitest's `test.globals:
|
|
@@ -31,20 +33,22 @@ export const reactConfig: import("eslint").Linter.Config[];
|
|
|
31
33
|
export type ReactConfigOptions = {
|
|
32
34
|
/**
|
|
33
35
|
* - Enable eslint-plugin-jsx-a11y's
|
|
34
|
-
* recommended rules.
|
|
36
|
+
* recommended rules (needs `eslint-plugin-jsx-a11y` installed).
|
|
35
37
|
*/
|
|
36
38
|
a11y?: boolean | undefined;
|
|
37
39
|
/**
|
|
38
40
|
* - Enable eslint-plugin-i18next's
|
|
39
|
-
* `no-literal-string` rule, forbidding any hardcoded string in JSX
|
|
40
|
-
* makes sense for a project fully
|
|
41
|
-
* next-intl) — off by default since it
|
|
41
|
+
* `no-literal-string` rule, forbidding any hardcoded string in JSX (needs
|
|
42
|
+
* `eslint-plugin-i18next` installed). Only makes sense for a project fully
|
|
43
|
+
* committed to i18n (e.g. driven by next-intl) — off by default since it
|
|
44
|
+
* flags every literal otherwise.
|
|
42
45
|
*/
|
|
43
46
|
i18n?: boolean | undefined;
|
|
44
47
|
/**
|
|
45
48
|
* - Enable
|
|
46
49
|
* eslint-plugin-testing-library's React rules and eslint-plugin-jest-dom's
|
|
47
|
-
* recommended rules, scoped to test files only. Off
|
|
50
|
+
* recommended rules, scoped to test files only (needs both installed). Off
|
|
51
|
+
* by default:
|
|
48
52
|
* `testing-library/no-manual-cleanup` in particular assumes
|
|
49
53
|
* `@testing-library/*`'s automatic `afterEach(cleanup)` is active, which
|
|
50
54
|
* only happens when `afterEach` is a real global (vitest's `test.globals:
|
package/dist/react.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.js"],"names":[],"mappings":"AA2DA;;;;;;;;;;;;;;;;;;GAkBG;AAEH;;;;;GAKG;AACH,0FAHW,OAAO,WAAW,EAAE,iBAAiB,GAAG,kBAAkB,GACxD,OAAO,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,CAyG5C;AAED;;;;8CAI8C;AAC9C,0BADU,OAAO,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,CACuB"}
|
package/dist/react.js
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
import pluginEslintReact from "@eslint-react/eslint-plugin";
|
|
2
2
|
import { defineConfig } from "eslint/config";
|
|
3
|
-
import pluginI18next from "eslint-plugin-i18next";
|
|
4
|
-
import pluginJestDom from "eslint-plugin-jest-dom";
|
|
5
|
-
import pluginJsxA11y from "eslint-plugin-jsx-a11y";
|
|
6
3
|
import pluginReact from "eslint-plugin-react";
|
|
7
4
|
import pluginReactHooks from "eslint-plugin-react-hooks";
|
|
8
5
|
import pluginReactRefresh from "eslint-plugin-react-refresh";
|
|
9
|
-
import pluginTestingLibrary from "eslint-plugin-testing-library";
|
|
10
6
|
import globals from "globals";
|
|
7
|
+
import { lazyConfig } from "./internal/lazy-config.js";
|
|
8
|
+
import { importOptional, requirePlugin } from "./internal/optional-plugin.js";
|
|
11
9
|
import { createBaseConfig, createNamingConventionRule } from "./base.js";
|
|
10
|
+
// Optional peer dependencies, each behind an option (see
|
|
11
|
+
// ReactConfigOptions): a project leaving the option off doesn't install them.
|
|
12
|
+
const [pluginJsxA11y, pluginI18next, pluginTestingLibrary, pluginJestDom] = await Promise.all([
|
|
13
|
+
importOptional("eslint-plugin-jsx-a11y", () => import("eslint-plugin-jsx-a11y")),
|
|
14
|
+
importOptional("eslint-plugin-i18next", () => import("eslint-plugin-i18next")),
|
|
15
|
+
importOptional("eslint-plugin-testing-library", () => import("eslint-plugin-testing-library")),
|
|
16
|
+
importOptional("eslint-plugin-jest-dom", () => import("eslint-plugin-jest-dom")),
|
|
17
|
+
]);
|
|
12
18
|
/**
|
|
13
19
|
* Any file matching this is a test file, whatever runner or naming
|
|
14
20
|
* convention is used to suffix it (`.test.`, `.spec.`, `.dom.test.`...) —
|
|
@@ -36,14 +42,16 @@ const RULES_COVERED_BY_ESLINT_REACT = [
|
|
|
36
42
|
/**
|
|
37
43
|
* @typedef {object} ReactConfigOptions
|
|
38
44
|
* @property {boolean} [a11y=true] - Enable eslint-plugin-jsx-a11y's
|
|
39
|
-
* recommended rules.
|
|
45
|
+
* recommended rules (needs `eslint-plugin-jsx-a11y` installed).
|
|
40
46
|
* @property {boolean} [i18n=false] - Enable eslint-plugin-i18next's
|
|
41
|
-
* `no-literal-string` rule, forbidding any hardcoded string in JSX
|
|
42
|
-
* makes sense for a project fully
|
|
43
|
-
* next-intl) — off by default since it
|
|
47
|
+
* `no-literal-string` rule, forbidding any hardcoded string in JSX (needs
|
|
48
|
+
* `eslint-plugin-i18next` installed). Only makes sense for a project fully
|
|
49
|
+
* committed to i18n (e.g. driven by next-intl) — off by default since it
|
|
50
|
+
* flags every literal otherwise.
|
|
44
51
|
* @property {boolean} [testingLibrary=false] - Enable
|
|
45
52
|
* eslint-plugin-testing-library's React rules and eslint-plugin-jest-dom's
|
|
46
|
-
* recommended rules, scoped to test files only. Off
|
|
53
|
+
* recommended rules, scoped to test files only (needs both installed). Off
|
|
54
|
+
* by default:
|
|
47
55
|
* `testing-library/no-manual-cleanup` in particular assumes
|
|
48
56
|
* `@testing-library/*`'s automatic `afterEach(cleanup)` is active, which
|
|
49
57
|
* only happens when `afterEach` is a real global (vitest's `test.globals:
|
|
@@ -59,21 +67,26 @@ const RULES_COVERED_BY_ESLINT_REACT = [
|
|
|
59
67
|
export function createReactConfig({ a11y = true, i18n = false, testingLibrary = false, snakeCase = false, ...options } = {}) {
|
|
60
68
|
return defineConfig([
|
|
61
69
|
...createBaseConfig({ snakeCase, ...options }),
|
|
62
|
-
a11y
|
|
70
|
+
a11y
|
|
71
|
+
? requirePlugin(pluginJsxA11y, "eslint-plugin-jsx-a11y", "a11y")
|
|
72
|
+
.flatConfigs.recommended
|
|
73
|
+
: [],
|
|
63
74
|
i18n
|
|
64
75
|
? {
|
|
65
|
-
plugins: {
|
|
76
|
+
plugins: {
|
|
77
|
+
i18next: requirePlugin(pluginI18next, "eslint-plugin-i18next", "i18n"),
|
|
78
|
+
},
|
|
66
79
|
rules: { "i18next/no-literal-string": "error" },
|
|
67
80
|
}
|
|
68
81
|
: [],
|
|
69
82
|
testingLibrary
|
|
70
83
|
? [
|
|
71
84
|
{
|
|
72
|
-
...pluginTestingLibrary.configs["flat/react"],
|
|
85
|
+
...requirePlugin(pluginTestingLibrary, "eslint-plugin-testing-library", "testingLibrary").configs["flat/react"],
|
|
73
86
|
files: TEST_FILE_GLOBS,
|
|
74
87
|
},
|
|
75
88
|
{
|
|
76
|
-
...pluginJestDom.configs["flat/recommended"],
|
|
89
|
+
...requirePlugin(pluginJestDom, "eslint-plugin-jest-dom", "testingLibrary").configs["flat/recommended"],
|
|
77
90
|
files: TEST_FILE_GLOBS,
|
|
78
91
|
},
|
|
79
92
|
]
|
|
@@ -140,4 +153,4 @@ export function createReactConfig({ a11y = true, i18n = false, testingLibrary =
|
|
|
140
153
|
* default options. Use `createReactConfig(options)` instead to customize it.
|
|
141
154
|
*
|
|
142
155
|
* @type {import("eslint").Linter.Config[]} */
|
|
143
|
-
export const reactConfig = createReactConfig();
|
|
156
|
+
export const reactConfig = lazyConfig(() => createReactConfig());
|
package/dist/storybook.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storybook.d.ts","sourceRoot":"","sources":["../src/storybook.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"storybook.d.ts","sourceRoot":"","sources":["../src/storybook.js"],"names":[],"mappings":"AAMA;;;;iDAIiD;AACjD,gDAFW,OAAO,WAAW,EAAE,iBAAiB,GAAG,OAAO,YAAY,EAAE,kBAAkB,GAC7E,OAAO,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,CAiB5C;AAED;;;;;8CAK8C;AAC9C,8BADU,OAAO,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,CAC+B"}
|
package/dist/storybook.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { defineConfig } from "eslint/config";
|
|
2
2
|
import storybook from "eslint-plugin-storybook";
|
|
3
|
+
import { lazyConfig } from "./internal/lazy-config.js";
|
|
3
4
|
import { createReactConfig } from "./react.js";
|
|
4
5
|
/**
|
|
5
6
|
* A custom ESLint configuration for libraries that use React and Storybook.
|
|
@@ -29,4 +30,4 @@ export function createStorybookConfig(options) {
|
|
|
29
30
|
* customize it.
|
|
30
31
|
*
|
|
31
32
|
* @type {import("eslint").Linter.Config[]} */
|
|
32
|
-
export const storybookConfig = createStorybookConfig();
|
|
33
|
+
export const storybookConfig = lazyConfig(() => createStorybookConfig());
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forthtilliath/eslint-config",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
@@ -18,14 +18,21 @@
|
|
|
18
18
|
],
|
|
19
19
|
"exports": {
|
|
20
20
|
".": "./dist/base.js",
|
|
21
|
+
"./internal/*": null,
|
|
21
22
|
"./*": "./dist/*.js"
|
|
22
23
|
},
|
|
23
24
|
"dependencies": {
|
|
24
|
-
"@eslint-react/eslint-plugin": "^5.18.3",
|
|
25
25
|
"@eslint/js": "^9.39.5",
|
|
26
|
+
"eslint-config-prettier": "^10.1.8",
|
|
27
|
+
"eslint-plugin-simple-import-sort": "^13.0.0",
|
|
28
|
+
"globals": "^17.9.0",
|
|
29
|
+
"typescript-eslint": "^8.67.0"
|
|
30
|
+
},
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"@eslint-react/eslint-plugin": "^5.18.3",
|
|
26
33
|
"@next/eslint-plugin-next": "^16.3.0",
|
|
27
34
|
"angular-eslint": "^21.4.0",
|
|
28
|
-
"eslint
|
|
35
|
+
"eslint": "^9.0.0 || ^10.0.0",
|
|
29
36
|
"eslint-plugin-i18next": "^6.1.5",
|
|
30
37
|
"eslint-plugin-jest-dom": "^5.10.1",
|
|
31
38
|
"eslint-plugin-jsx-a11y": "^6.10.2",
|
|
@@ -33,20 +40,68 @@
|
|
|
33
40
|
"eslint-plugin-react-hooks": "^7.1.1",
|
|
34
41
|
"eslint-plugin-react-native": "^5.0.0",
|
|
35
42
|
"eslint-plugin-react-refresh": "^0.5.4",
|
|
36
|
-
"eslint-plugin-simple-import-sort": "^13.0.0",
|
|
37
43
|
"eslint-plugin-storybook": "^10.6.1",
|
|
38
44
|
"eslint-plugin-testing-library": "^7.16.2",
|
|
39
45
|
"eslint-plugin-turbo": "^2.10.9",
|
|
40
|
-
"globals": "^17.9.0",
|
|
41
|
-
"typescript-eslint": "^8.67.0"
|
|
42
|
-
},
|
|
43
|
-
"peerDependencies": {
|
|
44
|
-
"eslint": "^9.0.0 || ^10.0.0",
|
|
45
46
|
"typescript": ">=5.0.0"
|
|
46
47
|
},
|
|
48
|
+
"peerDependenciesMeta": {
|
|
49
|
+
"@eslint-react/eslint-plugin": {
|
|
50
|
+
"optional": true
|
|
51
|
+
},
|
|
52
|
+
"@next/eslint-plugin-next": {
|
|
53
|
+
"optional": true
|
|
54
|
+
},
|
|
55
|
+
"angular-eslint": {
|
|
56
|
+
"optional": true
|
|
57
|
+
},
|
|
58
|
+
"eslint-plugin-i18next": {
|
|
59
|
+
"optional": true
|
|
60
|
+
},
|
|
61
|
+
"eslint-plugin-jest-dom": {
|
|
62
|
+
"optional": true
|
|
63
|
+
},
|
|
64
|
+
"eslint-plugin-jsx-a11y": {
|
|
65
|
+
"optional": true
|
|
66
|
+
},
|
|
67
|
+
"eslint-plugin-react": {
|
|
68
|
+
"optional": true
|
|
69
|
+
},
|
|
70
|
+
"eslint-plugin-react-hooks": {
|
|
71
|
+
"optional": true
|
|
72
|
+
},
|
|
73
|
+
"eslint-plugin-react-native": {
|
|
74
|
+
"optional": true
|
|
75
|
+
},
|
|
76
|
+
"eslint-plugin-react-refresh": {
|
|
77
|
+
"optional": true
|
|
78
|
+
},
|
|
79
|
+
"eslint-plugin-storybook": {
|
|
80
|
+
"optional": true
|
|
81
|
+
},
|
|
82
|
+
"eslint-plugin-testing-library": {
|
|
83
|
+
"optional": true
|
|
84
|
+
},
|
|
85
|
+
"eslint-plugin-turbo": {
|
|
86
|
+
"optional": true
|
|
87
|
+
}
|
|
88
|
+
},
|
|
47
89
|
"devDependencies": {
|
|
48
90
|
"@angular/core": "^21.0.0",
|
|
91
|
+
"@eslint-react/eslint-plugin": "^5.18.3",
|
|
92
|
+
"@next/eslint-plugin-next": "^16.3.0",
|
|
93
|
+
"angular-eslint": "^21.4.0",
|
|
49
94
|
"eslint": "10.7.0",
|
|
95
|
+
"eslint-plugin-i18next": "^6.1.5",
|
|
96
|
+
"eslint-plugin-jest-dom": "^5.10.1",
|
|
97
|
+
"eslint-plugin-jsx-a11y": "^6.10.2",
|
|
98
|
+
"eslint-plugin-react": "^7.37.5",
|
|
99
|
+
"eslint-plugin-react-hooks": "^7.1.1",
|
|
100
|
+
"eslint-plugin-react-native": "^5.0.0",
|
|
101
|
+
"eslint-plugin-react-refresh": "^0.5.4",
|
|
102
|
+
"eslint-plugin-storybook": "^10.6.1",
|
|
103
|
+
"eslint-plugin-testing-library": "^7.16.2",
|
|
104
|
+
"eslint-plugin-turbo": "^2.10.9",
|
|
50
105
|
"rxjs": "^7.8.0",
|
|
51
106
|
"typescript": "^5.9.3",
|
|
52
107
|
"vitest": "^5.0.2",
|