@leyman/eslint-config 0.0.0-stage → 0.0.1
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/LICENSE +21 -0
- package/README.md +110 -2
- package/dist/eslint-config.d.ts +85 -0
- package/dist/eslint-config.js +1170 -0
- package/dist/lib/internal-regex.d.ts +3 -0
- package/dist/lib/internal-regex.js +30 -0
- package/dist/lib/legacy-rule-context.d.ts +12 -0
- package/dist/lib/legacy-rule-context.js +26 -0
- package/dist/lib/node-floor.d.ts +19 -0
- package/dist/lib/node-floor.js +32 -0
- package/dist/lib/package-json-schema.d.ts +56 -0
- package/dist/lib/package-json-schema.js +42 -0
- package/dist/lib/package-plugins.d.ts +15 -0
- package/dist/lib/package-plugins.js +24 -0
- package/dist/lib/plugins.d.ts +14 -0
- package/dist/lib/plugins.js +26 -0
- package/package.json +81 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Jacob Ley
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,111 @@
|
|
|
1
|
-
|
|
1
|
+
<div style="text-align:center">
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
# @leyman/eslint-config
|
|
4
|
+
|
|
5
|
+
Strict, opinionated ESLint flat config for TypeScript ESM packages, generated from each package's package.json: nearly every rule on, every exception explained.
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/@leyman/eslint-config)
|
|
8
|
+
[](https://github.com/JacobLey/leyman/blob/main/leyman/eslint-config/LICENSE)
|
|
9
|
+
|
|
10
|
+
</div>
|
|
11
|
+
|
|
12
|
+
- **Every rule on** — every non-deprecated rule of ESLint and of ten plugins (typescript-eslint, import-x, jsdoc, n, regexp, sonarjs, unicorn, React, React Hooks, JSX accessibility) is an error, read from the installed plugins, so a new rule is on as soon as the plugin ships it.
|
|
13
|
+
- **Every exception explained** — each rule turned off or configured has a comment saying why.
|
|
14
|
+
- **Generated from package.json** — workspace dependencies become internal imports, `engines.node` turns off rules that suggest APIs the package's oldest supported Node.js lacks, and React rules follow whether the package uses React.
|
|
15
|
+
- **Type-aware** — typescript-eslint's type-checked rules run through the project service, with no `parserOptions.project` to maintain.
|
|
16
|
+
- **Formatting left out** — every formatting rule is off, for Biome or Prettier to own.
|
|
17
|
+
|
|
18
|
+
It is the config of the [leyman](https://github.com/JacobLey/leyman) monorepo, published as-is. Expect it to be strict and to change: see [Versioning](#versioning).
|
|
19
|
+
|
|
20
|
+
## Contents
|
|
21
|
+
|
|
22
|
+
- [Install](#install)
|
|
23
|
+
- [Example](#example)
|
|
24
|
+
- [Usage](#usage)
|
|
25
|
+
- [API](#api)
|
|
26
|
+
- [Versioning](#versioning)
|
|
27
|
+
- [Known issues](#known-issues)
|
|
28
|
+
|
|
29
|
+
## Install
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
npm i -D @leyman/eslint-config eslint typescript
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`eslint` (10) and `typescript` (a version typescript-eslint supports) are peers.
|
|
36
|
+
|
|
37
|
+
## Example
|
|
38
|
+
|
|
39
|
+
`eslint.config.js` next to the package's `package.json` and `tsconfig.json`:
|
|
40
|
+
|
|
41
|
+
```js
|
|
42
|
+
import configGenerator from '@leyman/eslint-config';
|
|
43
|
+
import packageJson from './package.json' with { type: 'json' };
|
|
44
|
+
|
|
45
|
+
export default configGenerator({ configUrl: import.meta.url, packageJson });
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Then run `eslint .` from the package directory.
|
|
49
|
+
|
|
50
|
+
## Usage
|
|
51
|
+
|
|
52
|
+
The package is ESM only. The config returned is a flat config array: append your own entries to change it, as with any flat config.
|
|
53
|
+
|
|
54
|
+
It expects this layout, per package:
|
|
55
|
+
|
|
56
|
+
| Path | What the config does with it |
|
|
57
|
+
| ------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
58
|
+
| `tsconfig.json` | Found by typescript-eslint's project service from each file, for type-aware rules. Plain `.js` files outside it are linted without type information. |
|
|
59
|
+
| `src/` | Published code: importing a `devDependency` is an error here. `src/cli.ts` and `src/commands/**` may use `console`. |
|
|
60
|
+
| `test/` | Tests: Node.js globals, and rules that get in the way of tests (magic numbers, return types, `@ts-expect-error`...) are off. |
|
|
61
|
+
| `**/eslint/**` | ESLint plugin code: visitors named after AST nodes and kebab-case rule names are allowed. |
|
|
62
|
+
| `coverage`, `dist`, `dist-test`, `out`, `node_modules` | Ignored. |
|
|
63
|
+
|
|
64
|
+
`.tsx` files get the React, React Hooks and JSX accessibility rules, and the other files don't. CommonJS files (`.cjs`, `.cts`) may use `require`.
|
|
65
|
+
|
|
66
|
+
A disable comment needs a description (`// eslint-disable-next-line rule -- why`), and one that no longer suppresses anything is reported.
|
|
67
|
+
|
|
68
|
+
## API
|
|
69
|
+
|
|
70
|
+
### `configGenerator(params)`
|
|
71
|
+
|
|
72
|
+
The default export. Returns the flat config (`Linter.Config[]`) for one package.
|
|
73
|
+
|
|
74
|
+
| Parameter | Type | Default | Description |
|
|
75
|
+
| ------------- | -------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
76
|
+
| `configUrl` | `string` | — | Required. `import.meta.url` of the package's `eslint.config.js`. typescript-eslint resolves `tsconfig.json` from its directory. |
|
|
77
|
+
| `packageJson` | `unknown` | — | Required. The package's `package.json`, loaded. Must have a `name`; `engines.node`, if present, must start with `>=`. |
|
|
78
|
+
| `node` | `boolean` | `false` | Whether the package's code only runs on Node.js. By default only the globals Node.js shares with browsers (`fetch`, `URL`, `console`...) are defined, so code meant to run elsewhere can't use `process` or `Buffer` by accident. Tests always have them. |
|
|
79
|
+
| `plugins` | `readonly ESLint.Plugin[]` | `[]` | ESLint plugins shipped by your own packages, each turned on with its flat `configs.recommended` rules outside `test/`. Each needs `meta.namespace`. |
|
|
80
|
+
|
|
81
|
+
**Throws** `Error` when `packageJson` isn't an object with a `name`, or `engines.node` doesn't name a floor; `TypeError` when a plugin has no `meta.namespace` or no flat `configs.recommended`.
|
|
82
|
+
|
|
83
|
+
What it reads from `packageJson`:
|
|
84
|
+
|
|
85
|
+
| Field | Effect |
|
|
86
|
+
| ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
87
|
+
| `name`, and dependencies with a `workspace:` version | Treated as internal imports by `import-x`. |
|
|
88
|
+
| `engines.node` | Its major version is the package's floor. Rules that suggest a newer API (`unicorn/prefer-regexp-escape` before Node.js 24...) are off below the Node.js version that has it. Without `engines`, the running Node.js is the floor. |
|
|
89
|
+
| `react` in any dependency field | React's version is detected from the installed package. |
|
|
90
|
+
|
|
91
|
+
### `nonDeprecatedRules(name, plugin)`
|
|
92
|
+
|
|
93
|
+
Every non-deprecated rule of `plugin` that applies to JavaScript, as `'error'`, prefixed with `name/`. What the config uses for each plugin; useful to turn on another plugin the same way.
|
|
94
|
+
|
|
95
|
+
### `baseNamingConvention`, `reactComponentNamingConvention`
|
|
96
|
+
|
|
97
|
+
The options passed to `@typescript-eslint/naming-convention`, the second only in `.tsx` files. Spread them into your own entry to extend the convention rather than replace it.
|
|
98
|
+
|
|
99
|
+
### `@leyman/eslint-config/package-json-schema`
|
|
100
|
+
|
|
101
|
+
`packageJsonSchema` (the JSON Schema the `packageJson` parameter is checked against), `assertIsPackageJson` and the `PackageJson` type.
|
|
102
|
+
|
|
103
|
+
## Versioning
|
|
104
|
+
|
|
105
|
+
Before 1.0, a release that can make passing code fail (a new rule, a stricter option) is a minor, and other changes are patches.
|
|
106
|
+
|
|
107
|
+
The plugins are dependencies with `^` ranges, and every rule a plugin ships is on. So a plugin's minor release can add errors without a release of this package. Keep a lockfile, and update it deliberately, as you would for this package.
|
|
108
|
+
|
|
109
|
+
## Known issues
|
|
110
|
+
|
|
111
|
+
- **`@typescript-eslint/prefer-string-starts-ends-with` misreads `v`-flag regular expressions** (typescript-eslint 8.72), and its autofix can change behavior: `/^\p{N}/v.test(s)` becomes `s.startsWith('p{N}')`. `regexp/require-unicode-sets-regexp`, which is on, moves every regular expression to the `v` flag, so expect to hit it. The fix ([typescript-eslint#13102](https://github.com/typescript-eslint/typescript-eslint/pull/13102)) is merged but not yet released. Until it is, leyman applies [a patch](https://github.com/JacobLey/leyman/blob/main/patches/@typescript-eslint__eslint-plugin@8.72.0.patch) (pnpm's `patchedDependencies`); run `--fix` with care on `v`-flag expressions, or apply the same patch.
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { RuleModule } from '@typescript-eslint/utils/ts-eslint';
|
|
2
|
+
import type { ESLint, Linter, Rule } from 'eslint';
|
|
3
|
+
interface PluginRules {
|
|
4
|
+
rules?: Record<string, Rule.RuleModule | RuleModule<string, unknown[]>> | undefined;
|
|
5
|
+
}
|
|
6
|
+
export declare const nonDeprecatedRules: (name: string, plugin: PluginRules) => Linter.RulesRecord;
|
|
7
|
+
export declare const baseNamingConvention: ({
|
|
8
|
+
selector: string;
|
|
9
|
+
format: string[];
|
|
10
|
+
leadingUnderscore: string;
|
|
11
|
+
trailingUnderscore: string;
|
|
12
|
+
modifiers?: never;
|
|
13
|
+
} | {
|
|
14
|
+
trailingUnderscore?: never;
|
|
15
|
+
selector: string;
|
|
16
|
+
format: string[];
|
|
17
|
+
modifiers?: never;
|
|
18
|
+
leadingUnderscore?: never;
|
|
19
|
+
} | {
|
|
20
|
+
trailingUnderscore?: never;
|
|
21
|
+
selector: string;
|
|
22
|
+
modifiers: string[];
|
|
23
|
+
format: null;
|
|
24
|
+
leadingUnderscore?: never;
|
|
25
|
+
} | {
|
|
26
|
+
trailingUnderscore?: never;
|
|
27
|
+
selector: string;
|
|
28
|
+
modifiers: string[];
|
|
29
|
+
format: string[];
|
|
30
|
+
leadingUnderscore?: never;
|
|
31
|
+
} | {
|
|
32
|
+
trailingUnderscore?: never;
|
|
33
|
+
selector: string;
|
|
34
|
+
modifiers: string[];
|
|
35
|
+
format: string[];
|
|
36
|
+
leadingUnderscore: string;
|
|
37
|
+
})[];
|
|
38
|
+
export declare const reactComponentNamingConvention: ({
|
|
39
|
+
modifiers?: never;
|
|
40
|
+
selector: string;
|
|
41
|
+
format: string[];
|
|
42
|
+
types?: never;
|
|
43
|
+
} | {
|
|
44
|
+
selector: string;
|
|
45
|
+
modifiers: string[];
|
|
46
|
+
types: string[];
|
|
47
|
+
format: string[];
|
|
48
|
+
})[];
|
|
49
|
+
/**
|
|
50
|
+
* Generate flat ESLint config for the specified project.
|
|
51
|
+
* Patterns are relative to the project, so run ESLint from the project directory,
|
|
52
|
+
* or from a parent directory, where ESLint looks up the config from each file.
|
|
53
|
+
*
|
|
54
|
+
* @param params - parameters
|
|
55
|
+
* @param params.configUrl - `import.meta.url` of project-level `eslint.config.js` file.
|
|
56
|
+
* @param params.packageJson - Loaded `package.json` file
|
|
57
|
+
* @param params.plugins - ESLint plugins shipped by packages (e.g. `generated-signature/eslint`), turned on with their recommended rules
|
|
58
|
+
* @param params.node - Whether the package's code only runs on Node.js, so may use its globals like `process` and `Buffer`
|
|
59
|
+
* @returns Generated flat config for most rules and plugins. Can be extended as necessary via normal Flat Config extension.
|
|
60
|
+
*/
|
|
61
|
+
export default function makeEslintConfigForPackage({ configUrl, node, packageJson, plugins, }: {
|
|
62
|
+
/**
|
|
63
|
+
* `import.meta.url` of project-level `eslint.config.js` file.
|
|
64
|
+
*/
|
|
65
|
+
configUrl: string;
|
|
66
|
+
/**
|
|
67
|
+
* Loaded `package.json` file
|
|
68
|
+
*/
|
|
69
|
+
packageJson: unknown;
|
|
70
|
+
/**
|
|
71
|
+
* ESLint plugins shipped by packages, e.g. `generated-signature/eslint`.
|
|
72
|
+
* Each needs `meta.namespace` and a flat `configs.recommended`, whose rules are turned on
|
|
73
|
+
* outside `test/`.
|
|
74
|
+
* The project must depend on the package providing the plugin.
|
|
75
|
+
*/
|
|
76
|
+
plugins?: readonly ESLint.Plugin[];
|
|
77
|
+
/**
|
|
78
|
+
* Whether the package's code only runs on Node.js, so may use its globals like `process` and `Buffer`.
|
|
79
|
+
* By default only globals shared with browsers are defined, so a package that also runs elsewhere
|
|
80
|
+
* can't use one by accident. Tests always run on Node.js, and always have them.
|
|
81
|
+
*/
|
|
82
|
+
node?: boolean;
|
|
83
|
+
}): Linter.Config[];
|
|
84
|
+
export {};
|
|
85
|
+
//# sourceMappingURL=eslint-config.d.ts.map
|