@forthtilliath/eslint-config 0.8.0 → 0.10.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 +67 -8
- package/dist/angular.d.ts.map +1 -1
- package/dist/angular.js +2 -1
- package/dist/base.d.ts +9 -5
- package/dist/base.d.ts.map +1 -1
- package/dist/base.js +11 -7
- 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 +16 -0
- package/dist/internal/optional-plugin.d.ts.map +1 -0
- package/dist/internal/optional-plugin.js +76 -0
- package/dist/internal/turborepo.d.ts +12 -0
- package/dist/internal/turborepo.d.ts.map +1 -0
- package/dist/internal/turborepo.js +20 -0
- package/dist/nextjs.d.ts.map +1 -1
- package/dist/nextjs.js +2 -1
- package/dist/react-native.d.ts +20 -2
- package/dist/react-native.d.ts.map +1 -1
- package/dist/react-native.js +28 -3
- package/dist/react.d.ts +14 -10
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +19 -14
- package/dist/storybook.d.ts.map +1 -1
- package/dist/storybook.js +2 -1
- package/package.json +71 -11
package/README.md
CHANGED
|
@@ -24,10 +24,52 @@ 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`\*\* | `eslint-plugin-turbo` — \*\*default inside a Turborepo (a `turbo.json` in the working directory or above) |
|
|
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
|
+
| `expo: true` | `eslint-plugin-expo` — `/react-native` only |
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# e.g. a standalone React Native / Expo app, with createReactNativeConfig({ expo: true })
|
|
51
|
+
npm install --save-dev @forthtilliath/eslint-config eslint typescript \
|
|
52
|
+
@eslint-react/eslint-plugin eslint-plugin-react eslint-plugin-react-hooks \
|
|
53
|
+
eslint-plugin-react-refresh eslint-plugin-react-native eslint-plugin-expo
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
A missing plugin fails with an explicit error naming the package to install
|
|
57
|
+
(or the option to turn off) as soon as ESLint loads the config.
|
|
58
|
+
|
|
59
|
+
**ESLint 10:** `eslint-plugin-react` and `eslint-plugin-react-native` still
|
|
60
|
+
declare `eslint` up to 9 only, so npm refuses to install them next to ESLint
|
|
61
|
+
10 (`ERESOLVE`). They work under ESLint 10 (see the `react-native` rules
|
|
62
|
+
below for the exceptions), so tell npm to accept it in the app's
|
|
63
|
+
`package.json`:
|
|
64
|
+
|
|
65
|
+
```json
|
|
66
|
+
{
|
|
67
|
+
"overrides": {
|
|
68
|
+
"eslint-plugin-react": { "eslint": "$eslint" },
|
|
69
|
+
"eslint-plugin-react-native": { "eslint": "$eslint" }
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
31
73
|
|
|
32
74
|
## Usage
|
|
33
75
|
|
|
@@ -82,9 +124,21 @@ export default reactNativeConfig;
|
|
|
82
124
|
|
|
83
125
|
All six are **named** exports — a default import (`import config from "..."`)
|
|
84
126
|
resolves to the whole module namespace object instead of the config array and
|
|
85
|
-
crashes ESLint's flat-config loader outright. Two of the
|
|
127
|
+
crashes ESLint's flat-config loader outright. Two of the variants had
|
|
86
128
|
exactly this bug at one point; use the named-import form above.
|
|
87
129
|
|
|
130
|
+
The config loads from a CommonJS `eslint.config.js` too (the one Expo's
|
|
131
|
+
templates generate), through `require()` — no top-level `await` anywhere in
|
|
132
|
+
the package. That needs Node 20.19+ or 22.12+ (`require()` of an ES module):
|
|
133
|
+
|
|
134
|
+
```js
|
|
135
|
+
// eslint.config.js (CommonJS)
|
|
136
|
+
const {
|
|
137
|
+
createReactNativeConfig,
|
|
138
|
+
} = require("@forthtilliath/eslint-config/react-native");
|
|
139
|
+
module.exports = createReactNativeConfig({ expo: true });
|
|
140
|
+
```
|
|
141
|
+
|
|
88
142
|
Each variant is additive: `reactConfig`/`angularConfig` extend `baseConfig`,
|
|
89
143
|
`nextJsConfig`/`storybookConfig`/`reactNativeConfig` extend `reactConfig`.
|
|
90
144
|
|
|
@@ -105,20 +159,21 @@ export default createReactConfig({ prettier: false });
|
|
|
105
159
|
```ts
|
|
106
160
|
// Fall back to typescript-eslint's `recommended` preset instead of
|
|
107
161
|
// `strictTypeChecked`/`stylisticTypeChecked` (e.g. while migrating an
|
|
108
|
-
// existing codebase)
|
|
162
|
+
// existing codebase).
|
|
109
163
|
import { createBaseConfig } from "@forthtilliath/eslint-config";
|
|
110
|
-
export default createBaseConfig({ strict: false
|
|
164
|
+
export default createBaseConfig({ strict: false });
|
|
111
165
|
```
|
|
112
166
|
|
|
113
167
|
| Option | Default | Effect |
|
|
114
168
|
| ---------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
115
169
|
| `prettier` | `true` | Append `eslint-config-prettier` at the end. |
|
|
116
170
|
| `strict` | `true` | Use `strictTypeChecked`/`stylisticTypeChecked` instead of plain `recommended`. |
|
|
117
|
-
| `turbo` |
|
|
171
|
+
| `turbo` | auto | Enable `eslint-plugin-turbo`'s `no-undeclared-env-vars` rule. Defaults to `true` when a `turbo.json` sits in ESLint's working directory or one of its parents, `false` otherwise. |
|
|
118
172
|
| `snakeCase` | `false` | Also accept `snake_case` variable names in `@typescript-eslint/naming-convention` (e.g. rows destructured straight from a Supabase/SQL database). |
|
|
119
173
|
| `a11y` | `true`\* | _(react/nextjs/storybook/react-native)_ Enable `eslint-plugin-jsx-a11y`'s recommended rules. \*Defaults to `false` in `createReactNativeConfig` (jsx-a11y targets DOM semantics, which RN doesn't have). |
|
|
120
174
|
| `i18n` | `false` | _(react/nextjs/storybook/react-native)_ Enable `eslint-plugin-i18next`'s `no-literal-string` rule. |
|
|
121
175
|
| `testingLibrary` | `false` | _(react/nextjs/storybook/react-native)_ Enable `eslint-plugin-testing-library` + `eslint-plugin-jest-dom` on test files. |
|
|
176
|
+
| `expo` | `false` | _(react-native)_ Enable the `eslint-plugin-expo` rules `eslint-config-expo` turns on: `use-dom-exports`, `no-env-var-destructuring`, `no-dynamic-env-var`. |
|
|
122
177
|
|
|
123
178
|
Options are forwarded down the chain, so `createNextJsConfig({ prettier: false })`
|
|
124
179
|
also disables Prettier in the `reactConfig`/`baseConfig` layers it builds on.
|
|
@@ -173,6 +228,10 @@ consumer here yet, so `src/angular.test.js` lints small fixture files under
|
|
|
173
228
|
for that. Extend it (or add a sibling `<variant>.test.js`) whenever a variant
|
|
174
229
|
changes without a real consumer to catch a regression.
|
|
175
230
|
|
|
231
|
+
`src/package.test.js` guards the dependency layout: any plugin imported
|
|
232
|
+
outside the base config must stay an optional peer dependency, never a
|
|
233
|
+
regular one.
|
|
234
|
+
|
|
176
235
|
## Scripts
|
|
177
236
|
|
|
178
237
|
```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
|
@@ -8,9 +8,11 @@
|
|
|
8
8
|
* `strictTypeChecked` + `stylisticTypeChecked` presets. Set to `false` to
|
|
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
|
-
* @property {boolean} [turbo
|
|
12
|
-
* `no-undeclared-env-vars` rule
|
|
13
|
-
* `
|
|
11
|
+
* @property {boolean} [turbo] - Enable eslint-plugin-turbo's
|
|
12
|
+
* `no-undeclared-env-vars` rule (needs `eslint-plugin-turbo` installed).
|
|
13
|
+
* Only relevant inside a Turborepo: defaults to `true` when a `turbo.json`
|
|
14
|
+
* sits in ESLint's working directory or one of its parents, `false`
|
|
15
|
+
* otherwise.
|
|
14
16
|
* @property {boolean} [snakeCase=false] - Also accept `snake_case` variable
|
|
15
17
|
* names in `@typescript-eslint/naming-convention` — for code that
|
|
16
18
|
* destructures rows straight from a SQL database (e.g. Supabase), whose
|
|
@@ -70,8 +72,10 @@ export type BaseConfigOptions = {
|
|
|
70
72
|
strict?: boolean | undefined;
|
|
71
73
|
/**
|
|
72
74
|
* - Enable eslint-plugin-turbo's
|
|
73
|
-
* `no-undeclared-env-vars` rule
|
|
74
|
-
* `
|
|
75
|
+
* `no-undeclared-env-vars` rule (needs `eslint-plugin-turbo` installed).
|
|
76
|
+
* Only relevant inside a Turborepo: defaults to `true` when a `turbo.json`
|
|
77
|
+
* sits in ESLint's working directory or one of its parents, `false`
|
|
78
|
+
* otherwise.
|
|
75
79
|
*/
|
|
76
80
|
turbo?: boolean | undefined;
|
|
77
81
|
/**
|
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":"AA0BA;;;;;;;;;;;;;;;;;;;GAmBG;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,CAmH5C;AArMD;;;;;;GAMG;AACH,wCAFU,MAAM,EAAE,CAQhB;AA0LF;;;;;KAKK;AACL,yBAFU,OAAO,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,CAEqB"}
|
package/dist/base.js
CHANGED
|
@@ -2,9 +2,11 @@ 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 { requireOptional } from "./internal/optional-plugin.js";
|
|
9
|
+
import { isInsideTurborepo } from "./internal/turborepo.js";
|
|
8
10
|
/**
|
|
9
11
|
* Node.js builtins without the `node:` prefix, as the first
|
|
10
12
|
* `simple-import-sort/imports` group. Exported so other variants (e.g.
|
|
@@ -29,9 +31,11 @@ export const NODE_BUILTIN_IMPORT_GROUP = [
|
|
|
29
31
|
* `strictTypeChecked` + `stylisticTypeChecked` presets. Set to `false` to
|
|
30
32
|
* fall back to the plain `recommended` preset instead (useful while
|
|
31
33
|
* migrating an existing codebase that isn't ready for the strict rules).
|
|
32
|
-
* @property {boolean} [turbo
|
|
33
|
-
* `no-undeclared-env-vars` rule
|
|
34
|
-
* `
|
|
34
|
+
* @property {boolean} [turbo] - Enable eslint-plugin-turbo's
|
|
35
|
+
* `no-undeclared-env-vars` rule (needs `eslint-plugin-turbo` installed).
|
|
36
|
+
* Only relevant inside a Turborepo: defaults to `true` when a `turbo.json`
|
|
37
|
+
* sits in ESLint's working directory or one of its parents, `false`
|
|
38
|
+
* otherwise.
|
|
35
39
|
* @property {boolean} [snakeCase=false] - Also accept `snake_case` variable
|
|
36
40
|
* names in `@typescript-eslint/naming-convention` — for code that
|
|
37
41
|
* destructures rows straight from a SQL database (e.g. Supabase), whose
|
|
@@ -81,7 +85,7 @@ export function createNamingConventionRule({ snakeCase = false, react = false, }
|
|
|
81
85
|
* @param {BaseConfigOptions} [options]
|
|
82
86
|
* @returns {import("eslint").Linter.Config[]}
|
|
83
87
|
*/
|
|
84
|
-
export function createBaseConfig({ prettier = true, strict = true, turbo =
|
|
88
|
+
export function createBaseConfig({ prettier = true, strict = true, turbo = isInsideTurborepo(), snakeCase = false, } = {}) {
|
|
85
89
|
return defineConfig([
|
|
86
90
|
eslint.configs.recommended,
|
|
87
91
|
strict ? tseslint.configs.strictTypeChecked : tseslint.configs.recommended,
|
|
@@ -152,7 +156,7 @@ export function createBaseConfig({ prettier = true, strict = true, turbo = true,
|
|
|
152
156
|
turbo
|
|
153
157
|
? {
|
|
154
158
|
plugins: {
|
|
155
|
-
turbo:
|
|
159
|
+
turbo: /** @type {typeof import("eslint-plugin-turbo").default} */ (requireOptional("eslint-plugin-turbo", "turbo")),
|
|
156
160
|
},
|
|
157
161
|
rules: {
|
|
158
162
|
"turbo/no-undeclared-env-vars": "error",
|
|
@@ -194,4 +198,4 @@ export function createBaseConfig({ prettier = true, strict = true, turbo = true,
|
|
|
194
198
|
*
|
|
195
199
|
* @type {import("eslint").Linter.Config[]}
|
|
196
200
|
* */
|
|
197
|
-
export const baseConfig = createBaseConfig();
|
|
201
|
+
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,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loads an optional plugin, or throws an error explaining which package to
|
|
3
|
+
* install (or which option to turn off) when it isn't installed. Any other
|
|
4
|
+
* failure (a broken install, a missing transitive dependency of the plugin
|
|
5
|
+
* itself) is rethrown rather than hidden.
|
|
6
|
+
*
|
|
7
|
+
* Callers cast the result to the package's own type (its `import()`
|
|
8
|
+
* default export) to keep the plugin's type, which `require()` loses.
|
|
9
|
+
*
|
|
10
|
+
* @param {string} name - The package name.
|
|
11
|
+
* @param {string} option - The option that needs it, e.g. `a11y`.
|
|
12
|
+
* @param {(name: string) => unknown} [load] - Stands in for `require` in tests.
|
|
13
|
+
* @returns {unknown}
|
|
14
|
+
*/
|
|
15
|
+
export function requireOptional(name: string, option: string, load?: (name: string) => unknown): unknown;
|
|
16
|
+
//# 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":"AAmBA;;;;;;;;;;;;;GAaG;AACH,sCALW,MAAM,UACN,MAAM,SACN,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,GACvB,OAAO,CAmBnB"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
/**
|
|
3
|
+
* Plugins that only some variants or options use are optional peer
|
|
4
|
+
* dependencies (see package.json's `peerDependenciesMeta`): a React Native app
|
|
5
|
+
* must not end up installing angular-eslint (and the whole Angular CLI it
|
|
6
|
+
* pulls in), nor a plain TypeScript library every React plugin. Plugins a
|
|
7
|
+
* variant always needs are imported statically by that variant's module;
|
|
8
|
+
* plugins behind an option (`a11y`, `expo`, `i18n`, `testingLibrary`,
|
|
9
|
+
* `turbo`) go through {@link requireOptional} instead, only when the option is
|
|
10
|
+
* on, so a project that leaves it off doesn't have to install them.
|
|
11
|
+
*
|
|
12
|
+
* Loaded with `require()` rather than `import()`: an `await import()` at the
|
|
13
|
+
* top of a variant module would make the whole package an async module, which
|
|
14
|
+
* Node refuses to `require()` (`ERR_REQUIRE_ASYNC_MODULE`) — and the CommonJS
|
|
15
|
+
* `eslint.config.js` generated by Expo's templates does exactly that.
|
|
16
|
+
*/
|
|
17
|
+
const require = createRequire(import.meta.url);
|
|
18
|
+
/**
|
|
19
|
+
* Loads an optional plugin, or throws an error explaining which package to
|
|
20
|
+
* install (or which option to turn off) when it isn't installed. Any other
|
|
21
|
+
* failure (a broken install, a missing transitive dependency of the plugin
|
|
22
|
+
* itself) is rethrown rather than hidden.
|
|
23
|
+
*
|
|
24
|
+
* Callers cast the result to the package's own type (its `import()`
|
|
25
|
+
* default export) to keep the plugin's type, which `require()` loses.
|
|
26
|
+
*
|
|
27
|
+
* @param {string} name - The package name.
|
|
28
|
+
* @param {string} option - The option that needs it, e.g. `a11y`.
|
|
29
|
+
* @param {(name: string) => unknown} [load] - Stands in for `require` in tests.
|
|
30
|
+
* @returns {unknown}
|
|
31
|
+
*/
|
|
32
|
+
export function requireOptional(name, option, load = require) {
|
|
33
|
+
/** @type {unknown} */
|
|
34
|
+
let loaded;
|
|
35
|
+
try {
|
|
36
|
+
loaded = load(name);
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
if (isPackageNotFound(error, name)) {
|
|
40
|
+
throw new Error(`@forthtilliath/eslint-config: the \`${option}\` option needs ${name}, ` +
|
|
41
|
+
`which isn't installed. Install it as a devDependency ` +
|
|
42
|
+
`(npm install --save-dev ${name}), or pass \`${option}: false\`.`, { cause: error });
|
|
43
|
+
}
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
46
|
+
return isModuleNamespace(loaded) ? loaded.default : loaded;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* `require()` of an ES module returns its namespace object, where `import()`'s
|
|
50
|
+
* `.default` is the plugin; a CommonJS module is returned as `module.exports`,
|
|
51
|
+
* which is already what `import()` puts in `.default`.
|
|
52
|
+
*
|
|
53
|
+
* @param {unknown} value
|
|
54
|
+
* @returns {value is { default: unknown }}
|
|
55
|
+
*/
|
|
56
|
+
function isModuleNamespace(value) {
|
|
57
|
+
return (typeof value === "object" &&
|
|
58
|
+
value !== null &&
|
|
59
|
+
Object.prototype.toString.call(value) === "[object Module]");
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* @param {unknown} error
|
|
63
|
+
* @param {string} name
|
|
64
|
+
* @returns {boolean}
|
|
65
|
+
*/
|
|
66
|
+
function isPackageNotFound(error, name) {
|
|
67
|
+
return (error instanceof Error &&
|
|
68
|
+
"code" in error &&
|
|
69
|
+
(error.code === "MODULE_NOT_FOUND" ||
|
|
70
|
+
error.code === "ERR_MODULE_NOT_FOUND") &&
|
|
71
|
+
// Node names the package it couldn't find on the first line (the
|
|
72
|
+
// require stack follows): checking it tells "the plugin isn't installed"
|
|
73
|
+
// apart from "the plugin is installed but one of its own dependencies is
|
|
74
|
+
// missing", which must not be swallowed.
|
|
75
|
+
(error.message.split("\n")[0] ?? "").includes(`'${name}'`));
|
|
76
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether `dir` or one of its parents holds a `turbo.json` — i.e. ESLint runs
|
|
3
|
+
* inside a Turborepo, where eslint-plugin-turbo's rule makes sense. Used as
|
|
4
|
+
* the default of the `turbo` option, so a standalone app doesn't have to pass
|
|
5
|
+
* `turbo: false` (nor install the plugin) to load the config.
|
|
6
|
+
*
|
|
7
|
+
* @param {string} [dir] - Where to start looking; ESLint's working directory
|
|
8
|
+
* by default.
|
|
9
|
+
* @returns {boolean}
|
|
10
|
+
*/
|
|
11
|
+
export function isInsideTurborepo(dir?: string): boolean;
|
|
12
|
+
//# sourceMappingURL=turborepo.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"turborepo.d.ts","sourceRoot":"","sources":["../../src/internal/turborepo.js"],"names":[],"mappings":"AAGA;;;;;;;;;GASG;AACH,wCAJW,MAAM,GAEJ,OAAO,CAOnB"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
/**
|
|
4
|
+
* Whether `dir` or one of its parents holds a `turbo.json` — i.e. ESLint runs
|
|
5
|
+
* inside a Turborepo, where eslint-plugin-turbo's rule makes sense. Used as
|
|
6
|
+
* the default of the `turbo` option, so a standalone app doesn't have to pass
|
|
7
|
+
* `turbo: false` (nor install the plugin) to load the config.
|
|
8
|
+
*
|
|
9
|
+
* @param {string} [dir] - Where to start looking; ESLint's working directory
|
|
10
|
+
* by default.
|
|
11
|
+
* @returns {boolean}
|
|
12
|
+
*/
|
|
13
|
+
export function isInsideTurborepo(dir = process.cwd()) {
|
|
14
|
+
for (let current = dir;; current = dirname(current)) {
|
|
15
|
+
if (existsSync(join(current, "turbo.json")))
|
|
16
|
+
return true;
|
|
17
|
+
if (dirname(current) === current)
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
}
|
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());
|
package/dist/react-native.d.ts
CHANGED
|
@@ -4,12 +4,20 @@
|
|
|
4
4
|
* hand here instead of spreading a ready-made flat config like storybook.js
|
|
5
5
|
* does.
|
|
6
6
|
*/
|
|
7
|
+
/**
|
|
8
|
+
* @typedef {object} ReactNativeConfigOptions
|
|
9
|
+
* @property {boolean} [expo=false] - Enable the eslint-plugin-expo rules that
|
|
10
|
+
* eslint-config-expo turns on (`use-dom-exports`,
|
|
11
|
+
* `no-env-var-destructuring`, `no-dynamic-env-var`), so an Expo app
|
|
12
|
+
* migrating from eslint-config-expo keeps them (needs `eslint-plugin-expo`
|
|
13
|
+
* installed).
|
|
14
|
+
*/
|
|
7
15
|
/**
|
|
8
16
|
* A custom ESLint configuration for React Native / Expo apps.
|
|
9
17
|
*
|
|
10
|
-
* @param {import("./base.js").BaseConfigOptions & import("./react.js").ReactConfigOptions} [options]
|
|
18
|
+
* @param {import("./base.js").BaseConfigOptions & import("./react.js").ReactConfigOptions & ReactNativeConfigOptions} [options]
|
|
11
19
|
* @returns {import("eslint").Linter.Config[]} */
|
|
12
|
-
export function createReactNativeConfig({ a11y, ...options }?: import("./base.js").BaseConfigOptions & import("./react.js").ReactConfigOptions): import("eslint").Linter.Config[];
|
|
20
|
+
export function createReactNativeConfig({ a11y, expo, ...options }?: import("./base.js").BaseConfigOptions & import("./react.js").ReactConfigOptions & ReactNativeConfigOptions): import("eslint").Linter.Config[];
|
|
13
21
|
/**
|
|
14
22
|
* A custom ESLint configuration for React Native / Expo apps, with the
|
|
15
23
|
* default options. Use `createReactNativeConfig(options)` instead to
|
|
@@ -17,4 +25,14 @@ export function createReactNativeConfig({ a11y, ...options }?: import("./base.js
|
|
|
17
25
|
*
|
|
18
26
|
* @type {import("eslint").Linter.Config[]} */
|
|
19
27
|
export const reactNativeConfig: import("eslint").Linter.Config[];
|
|
28
|
+
export type ReactNativeConfigOptions = {
|
|
29
|
+
/**
|
|
30
|
+
* - Enable the eslint-plugin-expo rules that
|
|
31
|
+
* eslint-config-expo turns on (`use-dom-exports`,
|
|
32
|
+
* `no-env-var-destructuring`, `no-dynamic-env-var`), so an Expo app
|
|
33
|
+
* migrating from eslint-config-expo keeps them (needs `eslint-plugin-expo`
|
|
34
|
+
* installed).
|
|
35
|
+
*/
|
|
36
|
+
expo?: boolean | undefined;
|
|
37
|
+
};
|
|
20
38
|
//# sourceMappingURL=react-native.d.ts.map
|
|
@@ -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":"AAOA;;;;;GAKG;AAEH;;;;;;;GAOG;AAEH;;;;iDAIiD;AACjD,qEAFW,OAAO,WAAW,EAAE,iBAAiB,GAAG,OAAO,YAAY,EAAE,kBAAkB,GAAG,wBAAwB,GACxG,OAAO,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,CA6D5C;AAED;;;;;8CAK8C;AAC9C,gCADU,OAAO,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,CACmC"}
|
package/dist/react-native.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { defineConfig } from "eslint/config";
|
|
2
2
|
import pluginReactNative from "eslint-plugin-react-native";
|
|
3
|
+
import { lazyConfig } from "./internal/lazy-config.js";
|
|
4
|
+
import { requireOptional } from "./internal/optional-plugin.js";
|
|
3
5
|
import { createReactConfig } from "./react.js";
|
|
4
6
|
/**
|
|
5
7
|
* eslint-plugin-react-native only ships a legacy (eslintrc) `configs.all`
|
|
@@ -7,14 +9,37 @@ import { createReactConfig } from "./react.js";
|
|
|
7
9
|
* hand here instead of spreading a ready-made flat config like storybook.js
|
|
8
10
|
* does.
|
|
9
11
|
*/
|
|
12
|
+
/**
|
|
13
|
+
* @typedef {object} ReactNativeConfigOptions
|
|
14
|
+
* @property {boolean} [expo=false] - Enable the eslint-plugin-expo rules that
|
|
15
|
+
* eslint-config-expo turns on (`use-dom-exports`,
|
|
16
|
+
* `no-env-var-destructuring`, `no-dynamic-env-var`), so an Expo app
|
|
17
|
+
* migrating from eslint-config-expo keeps them (needs `eslint-plugin-expo`
|
|
18
|
+
* installed).
|
|
19
|
+
*/
|
|
10
20
|
/**
|
|
11
21
|
* A custom ESLint configuration for React Native / Expo apps.
|
|
12
22
|
*
|
|
13
|
-
* @param {import("./base.js").BaseConfigOptions & import("./react.js").ReactConfigOptions} [options]
|
|
23
|
+
* @param {import("./base.js").BaseConfigOptions & import("./react.js").ReactConfigOptions & ReactNativeConfigOptions} [options]
|
|
14
24
|
* @returns {import("eslint").Linter.Config[]} */
|
|
15
|
-
export function createReactNativeConfig({ a11y = false, ...options } = {}) {
|
|
25
|
+
export function createReactNativeConfig({ a11y = false, expo = false, ...options } = {}) {
|
|
16
26
|
return defineConfig([
|
|
17
27
|
...createReactConfig({ a11y, ...options }),
|
|
28
|
+
expo
|
|
29
|
+
? {
|
|
30
|
+
plugins: {
|
|
31
|
+
expo: /** @type {typeof import("eslint-plugin-expo")} */ (requireOptional("eslint-plugin-expo", "expo")),
|
|
32
|
+
},
|
|
33
|
+
rules: {
|
|
34
|
+
// Every `EXPO_PUBLIC_*` variable is inlined at build time by
|
|
35
|
+
// reading `process.env.EXPO_PUBLIC_X` literally: a destructured or
|
|
36
|
+
// computed access stays `undefined` in the bundle.
|
|
37
|
+
"expo/no-env-var-destructuring": "error",
|
|
38
|
+
"expo/no-dynamic-env-var": "error",
|
|
39
|
+
"expo/use-dom-exports": "error",
|
|
40
|
+
},
|
|
41
|
+
}
|
|
42
|
+
: [],
|
|
18
43
|
{
|
|
19
44
|
languageOptions: {
|
|
20
45
|
globals: {
|
|
@@ -58,4 +83,4 @@ export function createReactNativeConfig({ a11y = false, ...options } = {}) {
|
|
|
58
83
|
* customize it.
|
|
59
84
|
*
|
|
60
85
|
* @type {import("eslint").Linter.Config[]} */
|
|
61
|
-
export const reactNativeConfig = createReactNativeConfig();
|
|
86
|
+
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":"AAqCA;;;;;;;;;;;;;;;;;;GAkBG;AAEH;;;;;GAKG;AACH,0FAHW,OAAO,WAAW,EAAE,iBAAiB,GAAG,kBAAkB,GACxD,OAAO,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,CAqG5C;AAED;;;;8CAI8C;AAC9C,0BADU,OAAO,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,CACuB"}
|
package/dist/react.js
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
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 { requireOptional } from "./internal/optional-plugin.js";
|
|
11
9
|
import { createBaseConfig, createNamingConventionRule } from "./base.js";
|
|
12
10
|
/**
|
|
13
11
|
* Any file matching this is a test file, whatever runner or naming
|
|
@@ -36,14 +34,16 @@ const RULES_COVERED_BY_ESLINT_REACT = [
|
|
|
36
34
|
/**
|
|
37
35
|
* @typedef {object} ReactConfigOptions
|
|
38
36
|
* @property {boolean} [a11y=true] - Enable eslint-plugin-jsx-a11y's
|
|
39
|
-
* recommended rules.
|
|
37
|
+
* recommended rules (needs `eslint-plugin-jsx-a11y` installed).
|
|
40
38
|
* @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
|
|
39
|
+
* `no-literal-string` rule, forbidding any hardcoded string in JSX (needs
|
|
40
|
+
* `eslint-plugin-i18next` installed). Only makes sense for a project fully
|
|
41
|
+
* committed to i18n (e.g. driven by next-intl) — off by default since it
|
|
42
|
+
* flags every literal otherwise.
|
|
44
43
|
* @property {boolean} [testingLibrary=false] - Enable
|
|
45
44
|
* eslint-plugin-testing-library's React rules and eslint-plugin-jest-dom's
|
|
46
|
-
* recommended rules, scoped to test files only. Off
|
|
45
|
+
* recommended rules, scoped to test files only (needs both installed). Off
|
|
46
|
+
* by default:
|
|
47
47
|
* `testing-library/no-manual-cleanup` in particular assumes
|
|
48
48
|
* `@testing-library/*`'s automatic `afterEach(cleanup)` is active, which
|
|
49
49
|
* only happens when `afterEach` is a real global (vitest's `test.globals:
|
|
@@ -59,21 +59,26 @@ const RULES_COVERED_BY_ESLINT_REACT = [
|
|
|
59
59
|
export function createReactConfig({ a11y = true, i18n = false, testingLibrary = false, snakeCase = false, ...options } = {}) {
|
|
60
60
|
return defineConfig([
|
|
61
61
|
...createBaseConfig({ snakeCase, ...options }),
|
|
62
|
-
a11y
|
|
62
|
+
a11y
|
|
63
|
+
? /** @type {typeof import("eslint-plugin-jsx-a11y").default} */ (requireOptional("eslint-plugin-jsx-a11y", "a11y")).flatConfigs.recommended
|
|
64
|
+
: [],
|
|
63
65
|
i18n
|
|
64
66
|
? {
|
|
65
|
-
plugins: {
|
|
67
|
+
plugins: {
|
|
68
|
+
i18next:
|
|
69
|
+
/** @type {typeof import("eslint-plugin-i18next").default} */ (requireOptional("eslint-plugin-i18next", "i18n")),
|
|
70
|
+
},
|
|
66
71
|
rules: { "i18next/no-literal-string": "error" },
|
|
67
72
|
}
|
|
68
73
|
: [],
|
|
69
74
|
testingLibrary
|
|
70
75
|
? [
|
|
71
76
|
{
|
|
72
|
-
...
|
|
77
|
+
... /** @type {typeof import("eslint-plugin-testing-library").default} */(requireOptional("eslint-plugin-testing-library", "testingLibrary")).configs["flat/react"],
|
|
73
78
|
files: TEST_FILE_GLOBS,
|
|
74
79
|
},
|
|
75
80
|
{
|
|
76
|
-
...
|
|
81
|
+
... /** @type {typeof import("eslint-plugin-jest-dom").default} */(requireOptional("eslint-plugin-jest-dom", "testingLibrary")).configs["flat/recommended"],
|
|
77
82
|
files: TEST_FILE_GLOBS,
|
|
78
83
|
},
|
|
79
84
|
]
|
|
@@ -140,4 +145,4 @@ export function createReactConfig({ a11y = true, i18n = false, testingLibrary =
|
|
|
140
145
|
* default options. Use `createReactConfig(options)` instead to customize it.
|
|
141
146
|
*
|
|
142
147
|
* @type {import("eslint").Linter.Config[]} */
|
|
143
|
-
export const reactConfig = createReactConfig();
|
|
148
|
+
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.10.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
@@ -18,14 +18,22 @@
|
|
|
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",
|
|
36
|
+
"eslint-plugin-expo": "^1.2.1",
|
|
29
37
|
"eslint-plugin-i18next": "^6.1.5",
|
|
30
38
|
"eslint-plugin-jest-dom": "^5.10.1",
|
|
31
39
|
"eslint-plugin-jsx-a11y": "^6.10.2",
|
|
@@ -33,23 +41,75 @@
|
|
|
33
41
|
"eslint-plugin-react-hooks": "^7.1.1",
|
|
34
42
|
"eslint-plugin-react-native": "^5.0.0",
|
|
35
43
|
"eslint-plugin-react-refresh": "^0.5.4",
|
|
36
|
-
"eslint-plugin-simple-import-sort": "^13.0.0",
|
|
37
44
|
"eslint-plugin-storybook": "^10.6.1",
|
|
38
45
|
"eslint-plugin-testing-library": "^7.16.2",
|
|
39
46
|
"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
47
|
"typescript": ">=5.0.0"
|
|
46
48
|
},
|
|
49
|
+
"peerDependenciesMeta": {
|
|
50
|
+
"@eslint-react/eslint-plugin": {
|
|
51
|
+
"optional": true
|
|
52
|
+
},
|
|
53
|
+
"@next/eslint-plugin-next": {
|
|
54
|
+
"optional": true
|
|
55
|
+
},
|
|
56
|
+
"angular-eslint": {
|
|
57
|
+
"optional": true
|
|
58
|
+
},
|
|
59
|
+
"eslint-plugin-expo": {
|
|
60
|
+
"optional": true
|
|
61
|
+
},
|
|
62
|
+
"eslint-plugin-i18next": {
|
|
63
|
+
"optional": true
|
|
64
|
+
},
|
|
65
|
+
"eslint-plugin-jest-dom": {
|
|
66
|
+
"optional": true
|
|
67
|
+
},
|
|
68
|
+
"eslint-plugin-jsx-a11y": {
|
|
69
|
+
"optional": true
|
|
70
|
+
},
|
|
71
|
+
"eslint-plugin-react": {
|
|
72
|
+
"optional": true
|
|
73
|
+
},
|
|
74
|
+
"eslint-plugin-react-hooks": {
|
|
75
|
+
"optional": true
|
|
76
|
+
},
|
|
77
|
+
"eslint-plugin-react-native": {
|
|
78
|
+
"optional": true
|
|
79
|
+
},
|
|
80
|
+
"eslint-plugin-react-refresh": {
|
|
81
|
+
"optional": true
|
|
82
|
+
},
|
|
83
|
+
"eslint-plugin-storybook": {
|
|
84
|
+
"optional": true
|
|
85
|
+
},
|
|
86
|
+
"eslint-plugin-testing-library": {
|
|
87
|
+
"optional": true
|
|
88
|
+
},
|
|
89
|
+
"eslint-plugin-turbo": {
|
|
90
|
+
"optional": true
|
|
91
|
+
}
|
|
92
|
+
},
|
|
47
93
|
"devDependencies": {
|
|
48
|
-
"@angular/core": "^21.
|
|
94
|
+
"@angular/core": "^21.2.25",
|
|
95
|
+
"@eslint-react/eslint-plugin": "^5.18.3",
|
|
96
|
+
"@next/eslint-plugin-next": "^16.3.0",
|
|
97
|
+
"angular-eslint": "^21.4.0",
|
|
49
98
|
"eslint": "10.7.0",
|
|
99
|
+
"eslint-plugin-expo": "^1.2.1",
|
|
100
|
+
"eslint-plugin-i18next": "^6.1.5",
|
|
101
|
+
"eslint-plugin-jest-dom": "^5.10.1",
|
|
102
|
+
"eslint-plugin-jsx-a11y": "^6.10.2",
|
|
103
|
+
"eslint-plugin-react": "^7.37.5",
|
|
104
|
+
"eslint-plugin-react-hooks": "^7.1.1",
|
|
105
|
+
"eslint-plugin-react-native": "^5.0.0",
|
|
106
|
+
"eslint-plugin-react-refresh": "^0.5.4",
|
|
107
|
+
"eslint-plugin-storybook": "^10.6.1",
|
|
108
|
+
"eslint-plugin-testing-library": "^7.16.2",
|
|
109
|
+
"eslint-plugin-turbo": "^2.10.9",
|
|
50
110
|
"rxjs": "^7.8.0",
|
|
51
111
|
"typescript": "^5.9.3",
|
|
52
|
-
"vitest": "^5.0.
|
|
112
|
+
"vitest": "^5.0.5",
|
|
53
113
|
"@forthtilliath/typescript-config": "0.1.1"
|
|
54
114
|
},
|
|
55
115
|
"scripts": {
|