@noctcore/eslint-plugin-contracts 0.6.1 โ 0.7.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/README.md +74 -32
- package/dist/index.cjs +330 -34
- package/dist/index.d.cts +36 -26
- package/dist/index.d.ts +36 -26
- package/dist/index.js +331 -35
- package/docs/rules/env-var-schema-parity.md +10 -2
- package/docs/rules/fetch-must-check-ok.md +18 -6
- package/docs/rules/money-must-be-decimal.md +14 -5
- package/docs/rules/no-direct-process-env.md +10 -2
- package/docs/rules/no-error-stringify.md +10 -0
- package/docs/rules/require-error-cause.md +17 -13
- package/docs/rules/require-registered-keys.md +13 -4
- package/docs/rules/require-schema-parse-at-boundary.md +101 -7
- package/docs/rules/restrict-throw-to-taxonomy.md +10 -4
- package/docs/rules/schema-enum-field-consistency.md +14 -0
- package/docs/rules/translation-key-exists.md +14 -10
- package/docs/rules/wire-message-naming.md +9 -1
- package/docs/rules/zod-schema-naming.md +10 -0
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -1,36 +1,73 @@
|
|
|
1
1
|
# @noctcore/eslint-plugin-contracts
|
|
2
2
|
|
|
3
|
-
Rules for shared **contract** conventions
|
|
4
|
-
stringification, direct `process.env` access
|
|
3
|
+
Rules for shared **contract** conventions: zod schema naming, wire-message discriminants, error
|
|
4
|
+
stringification, direct `process.env` access and money precision, where drift between producer and
|
|
5
|
+
consumer breaks at runtime.
|
|
6
|
+
|
|
7
|
+
**Docs:** [noctcore.github.io/eslint-plugins/packages/contracts](https://noctcore.github.io/eslint-plugins/packages/contracts/)
|
|
8
|
+
|
|
9
|
+
Not a good fit for a codebase that does not use zod, or whose error handling is intentionally
|
|
10
|
+
untyped.
|
|
11
|
+
|
|
12
|
+
## Requirements
|
|
13
|
+
|
|
14
|
+
- ESLint 9 or newer, flat config (`eslint.config.js`) only.
|
|
15
|
+
- `configs.recommended` registers the plugin and sets rule severities, nothing else. It sets no
|
|
16
|
+
`files` and no parser, so it applies to whatever files the rest of your config lints. To lint
|
|
17
|
+
TypeScript, add a `files` pattern and `@typescript-eslint/parser`, as in the quick start.
|
|
5
18
|
|
|
6
19
|
## Install
|
|
7
20
|
|
|
8
21
|
```sh
|
|
9
|
-
bun add -D @noctcore/eslint-plugin-contracts # or npm i -D / pnpm add -D
|
|
22
|
+
bun add -D @noctcore/eslint-plugin-contracts @typescript-eslint/parser # or npm i -D / pnpm add -D
|
|
10
23
|
```
|
|
11
24
|
|
|
12
|
-
##
|
|
25
|
+
## Quick start
|
|
13
26
|
|
|
14
27
|
```js
|
|
15
28
|
// eslint.config.js
|
|
29
|
+
import tsParser from '@typescript-eslint/parser';
|
|
16
30
|
import contracts from '@noctcore/eslint-plugin-contracts';
|
|
17
31
|
|
|
18
32
|
export default [
|
|
19
|
-
|
|
33
|
+
{
|
|
34
|
+
...contracts.configs.recommended,
|
|
35
|
+
files: ['**/*.{ts,tsx}'],
|
|
36
|
+
languageOptions: { parser: tsParser },
|
|
37
|
+
},
|
|
38
|
+
// Optional: tune a preset rule's options.
|
|
39
|
+
{
|
|
40
|
+
files: ['**/*.{ts,tsx}'],
|
|
41
|
+
rules: {
|
|
42
|
+
'noctcore-contracts/zod-schema-naming': ['error', { roleSuffixes: ['Event', 'Command', 'Query'] }],
|
|
43
|
+
'noctcore-contracts/no-direct-process-env': ['error', { configModule: '@acme/config' }],
|
|
44
|
+
},
|
|
45
|
+
},
|
|
20
46
|
];
|
|
21
47
|
```
|
|
22
48
|
|
|
23
|
-
|
|
49
|
+
## Opt-in rules
|
|
24
50
|
|
|
25
|
-
|
|
26
|
-
|
|
51
|
+
Four rules ship `off`: `require-registered-keys`, `env-var-schema-parity` and
|
|
52
|
+
`translation-key-exists` do nothing until their `sinks` / `schema` / `catalogs` options are set, and
|
|
53
|
+
`require-schema-parse-at-boundary` is a conservative syntactic slice of a type-aware concern.
|
|
27
54
|
|
|
55
|
+
```js
|
|
56
|
+
// eslint.config.js
|
|
28
57
|
export default [
|
|
58
|
+
// ...the quick start's entries, then:
|
|
29
59
|
{
|
|
30
|
-
|
|
60
|
+
files: ['**/*.{ts,tsx}'],
|
|
61
|
+
languageOptions: { parser: tsParser },
|
|
31
62
|
rules: {
|
|
32
|
-
'noctcore-contracts/
|
|
33
|
-
|
|
63
|
+
'noctcore-contracts/require-registered-keys': ['error', {
|
|
64
|
+
sinks: [{ callee: 'localStorage.getItem', argIndex: 0 }],
|
|
65
|
+
}],
|
|
66
|
+
'noctcore-contracts/env-var-schema-parity': ['error', { schema: '.env.example' }],
|
|
67
|
+
'noctcore-contracts/translation-key-exists': ['error', {
|
|
68
|
+
catalogs: [{ file: 'locales/en/common.json', namespace: 'common' }],
|
|
69
|
+
}],
|
|
70
|
+
'noctcore-contracts/require-schema-parse-at-boundary': 'error',
|
|
34
71
|
},
|
|
35
72
|
},
|
|
36
73
|
];
|
|
@@ -38,24 +75,29 @@ export default [
|
|
|
38
75
|
|
|
39
76
|
## Rules
|
|
40
77
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
|
47
|
-
|
|
|
48
|
-
| [`
|
|
49
|
-
| [`
|
|
50
|
-
| [`
|
|
51
|
-
| [`
|
|
52
|
-
| [`
|
|
53
|
-
| [`
|
|
54
|
-
| [`require-
|
|
55
|
-
| [`schema-
|
|
56
|
-
| [`
|
|
57
|
-
| [`
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
`
|
|
61
|
-
|
|
78
|
+
<!-- begin generated rules -->
|
|
79
|
+
<!-- Generated by `bun run docs:readmes` from each rule's meta. Do not edit by hand. -->
|
|
80
|
+
|
|
81
|
+
โ
in `recommended` (error) ยท โ๏ธ needs options ยท ๐ง `--fix` ยท ๐ก suggestions ยท ๐ญ needs type info ยท โ deprecated
|
|
82
|
+
|
|
83
|
+
| Rule | Description | โ
| โ๏ธ | ๐ง | ๐ก | ๐ญ |
|
|
84
|
+
| --- | --- | :-: | :-: | :-: | :-: | :-: |
|
|
85
|
+
| [`env-var-schema-parity`](https://noctcore.github.io/eslint-plugins/rules/contracts/env-var-schema-parity/) | Require every `process.env.FOO` / `import.meta.env.FOO` key to be declared in a schema file (`.env.example` or a zod-env module), so config access and config declaration cannot drift apart. | | โ๏ธ | | | |
|
|
86
|
+
| [`fetch-must-check-ok`](https://noctcore.github.io/eslint-plugins/rules/contracts/fetch-must-check-ok/) | Require a fetch response to be checked with `.ok` or a status comparison before `.json()` parses its body. | โ
| | | | |
|
|
87
|
+
| [`money-must-be-decimal`](https://noctcore.github.io/eslint-plugins/rules/contracts/money-must-be-decimal/) | Disallow monetary values typed as the JS primitive `number`. Money-named fields explicitly typed `: number` lose precision to float rounding; use a Decimal money type instead. | โ
| | | | |
|
|
88
|
+
| [`no-direct-process-env`](https://noctcore.github.io/eslint-plugins/rules/contracts/no-direct-process-env/) | Disallow direct `process.env` access. Force every consumer through a typed, validated config accessor so a missing variable fails at boot, not at use. | โ
| | | | |
|
|
89
|
+
| [`no-error-stringify`](https://noctcore.github.io/eslint-plugins/rules/contracts/no-error-stringify/) | Disallow stringifying an error with bare `${error}` interpolation, `error.toString()`, or `error + ""`. These drop the cause chain. Use `error instanceof Error ? error.message : String(error)` instead. | โ
| | | | |
|
|
90
|
+
| [`require-error-cause`](https://noctcore.github.io/eslint-plugins/rules/contracts/require-error-cause/) | Require re-thrown errors inside a `catch` to forward the caught error as `{ cause }`. A `throw new SomeError(...)` that omits the cause severs the chain to the original failure. | โ
| | ๐ง | | |
|
|
91
|
+
| [`require-registered-keys`](https://noctcore.github.io/eslint-plugins/rules/contracts/require-registered-keys/) | Require the key/name argument of configured sink APIs (storage, event channels, cache keys) to be an imported constant from a registry module, not a raw string literal. | | โ๏ธ | | | |
|
|
92
|
+
| [`require-schema-parse-at-boundary`](https://noctcore.github.io/eslint-plugins/rules/contracts/require-schema-parse-at-boundary/) | Disallow asserting external boundary data with `as T` instead of parsing it at runtime. Flags casts of `JSON.parse`, `res.json()`, web storage, URL search params, message-event data and LLM tool input, directly or through a `const`; use a zod/valibot parse. | | | | | |
|
|
93
|
+
| [`restrict-throw-to-taxonomy`](https://noctcore.github.io/eslint-plugins/rules/contracts/restrict-throw-to-taxonomy/) | Restrict `throw` to an approved error taxonomy. Flags throwing a non-allowlisted error class and throwing a non-Error value (string, object, number, ...). | โ
| | | | |
|
|
94
|
+
| [`schema-enum-field-consistency`](https://noctcore.github.io/eslint-plugins/rules/contracts/schema-enum-field-consistency/) | Disallow a zod field that is an enum in one object schema of a module from being `z.string()` in another, which widens the wire type every consumer then narrows by hand. | โ
| | | | |
|
|
95
|
+
| [`translation-key-exists`](https://noctcore.github.io/eslint-plugins/rules/contracts/translation-key-exists/) | Require every static i18next / react-i18next translation key (`t(...)`, `i18n.t(...)`, `<Trans i18nKey>`) to exist in the catalog of the namespace in scope. | | โ๏ธ | | | |
|
|
96
|
+
| [`wire-message-naming`](https://noctcore.github.io/eslint-plugins/rules/contracts/wire-message-naming/) | A message-schema const ending in a role suffix (default Event/Command/Query) whose zod object declares `type: z.literal(...)` must set that literal to kebab-case(const name minus its role suffix). | โ
| | ๐ง | | |
|
|
97
|
+
| [`zod-schema-naming`](https://noctcore.github.io/eslint-plugins/rules/contracts/zod-schema-naming/) | Every exported zod schema is a PascalCase const suffixed `Schema`, paired with a same-named inferred type (`export type Foo = z.infer<typeof FooSchema>`). | โ
| | | | |
|
|
98
|
+
<!-- end generated rules -->
|
|
99
|
+
|
|
100
|
+
## Severity policy
|
|
101
|
+
|
|
102
|
+
Every rule is `error` or `off`, never `warn`: a warning is a rule nobody obeys. See the
|
|
103
|
+
[severity policy](https://noctcore.github.io/eslint-plugins/getting-started/#severity-policy).
|