eslint-plugin-zod 3.12.1 → 4.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/README.md +44 -58
- package/dist/index.cjs +4 -24
- package/dist/index.d.cts +0 -1
- package/dist/index.d.mts +0 -1
- package/dist/index.mjs +4 -24
- package/dist/meta.cjs +2 -4
- package/dist/meta.mjs +2 -4
- package/dist/rules/array-style.cjs +4 -6
- package/dist/rules/array-style.mjs +3 -6
- package/dist/rules/consistent-import-source.cjs +5 -7
- package/dist/rules/consistent-import-source.mjs +4 -7
- package/dist/rules/consistent-import.cjs +8 -54
- package/dist/rules/consistent-import.mjs +4 -50
- package/dist/rules/consistent-object-schema-type.cjs +3 -6
- package/dist/rules/consistent-object-schema-type.mjs +3 -6
- package/dist/rules/consistent-schema-output-type-style.cjs +3 -6
- package/dist/rules/consistent-schema-output-type-style.mjs +3 -6
- package/dist/rules/consistent-schema-var-name.cjs +4 -26
- package/dist/rules/consistent-schema-var-name.mjs +4 -26
- package/dist/rules/no-any-schema.cjs +3 -6
- package/dist/rules/no-any-schema.mjs +3 -6
- package/dist/rules/no-empty-custom-schema.cjs +4 -5
- package/dist/rules/no-empty-custom-schema.mjs +3 -6
- package/dist/rules/no-number-schema-with-finite.cjs +5 -8
- package/dist/rules/no-number-schema-with-finite.mjs +3 -7
- package/dist/rules/no-number-schema-with-int.cjs +5 -8
- package/dist/rules/no-number-schema-with-int.mjs +3 -7
- package/dist/rules/no-number-schema-with-is-finite.cjs +3 -6
- package/dist/rules/no-number-schema-with-is-finite.mjs +3 -6
- package/dist/rules/no-number-schema-with-is-int.cjs +3 -6
- package/dist/rules/no-number-schema-with-is-int.mjs +3 -6
- package/dist/rules/no-number-schema-with-safe.cjs +5 -8
- package/dist/rules/no-number-schema-with-safe.mjs +3 -7
- package/dist/rules/no-number-schema-with-step.cjs +3 -6
- package/dist/rules/no-number-schema-with-step.mjs +3 -6
- package/dist/rules/no-optional-and-default-together.cjs +4 -5
- package/dist/rules/no-optional-and-default-together.mjs +3 -6
- package/dist/rules/no-string-schema-with-uuid.cjs +4 -5
- package/dist/rules/no-string-schema-with-uuid.mjs +2 -4
- package/dist/rules/no-throw-in-refine.cjs +3 -6
- package/dist/rules/no-throw-in-refine.mjs +3 -6
- package/dist/rules/no-transform-in-record-key.cjs +3 -6
- package/dist/rules/no-transform-in-record-key.mjs +3 -6
- package/dist/rules/no-unknown-schema.cjs +4 -5
- package/dist/rules/no-unknown-schema.mjs +3 -6
- package/dist/rules/prefer-enum-over-literal-union.cjs +3 -6
- package/dist/rules/prefer-enum-over-literal-union.mjs +3 -6
- package/dist/rules/prefer-meta-last.cjs +4 -5
- package/dist/rules/prefer-meta-last.mjs +3 -6
- package/dist/rules/prefer-meta.cjs +4 -5
- package/dist/rules/prefer-meta.mjs +3 -6
- package/dist/rules/prefer-string-schema-with-trim.cjs +5 -8
- package/dist/rules/prefer-string-schema-with-trim.mjs +3 -7
- package/dist/rules/prefer-trim-before-string-length-checks.cjs +5 -8
- package/dist/rules/prefer-trim-before-string-length-checks.mjs +3 -7
- package/dist/rules/require-brand-type-parameter.cjs +4 -5
- package/dist/rules/require-brand-type-parameter.mjs +3 -6
- package/dist/rules/require-error-message.cjs +3 -6
- package/dist/rules/require-error-message.mjs +3 -6
- package/dist/rules/schema-error-property-style.cjs +3 -6
- package/dist/rules/schema-error-property-style.mjs +3 -6
- package/package.json +8 -29
- package/dist/rules/prefer-namespace-import.cjs +0 -117
- package/dist/rules/prefer-namespace-import.mjs +0 -116
- package/dist/rules/require-schema-suffix.cjs +0 -69
- package/dist/rules/require-schema-suffix.mjs +0 -68
- package/dist/utils/build-zod-chain-remove-method-fix.cjs +0 -15
- package/dist/utils/build-zod-chain-remove-method-fix.mjs +0 -15
- package/dist/utils/build-zod-chain-replacement-fix.cjs +0 -30
- package/dist/utils/build-zod-chain-replacement-fix.mjs +0 -30
- package/dist/utils/detect-zod-schema-root-node.cjs +0 -113
- package/dist/utils/detect-zod-schema-root-node.mjs +0 -111
- package/dist/utils/find-parent-schema-matching-condition.cjs +0 -25
- package/dist/utils/find-parent-schema-matching-condition.mjs +0 -24
- package/dist/utils/is-zod-import-source.cjs +0 -17
- package/dist/utils/is-zod-import-source.mjs +0 -16
- package/dist/utils/track-zod-schema-imports.cjs +0 -80
- package/dist/utils/track-zod-schema-imports.mjs +0 -79
package/README.md
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
# eslint-plugin-zod
|
|
2
2
|
|
|
3
|
-
[![CI][CIBadge]][CIURL]
|
|
3
|
+
[![CI Status][CIBadge]][CIURL]
|
|
4
4
|
[![Code style: prettier][CodeStyleBadge]][CodeStyleURL]
|
|
5
5
|
[![Lint: eslint][lintBadge]][lintURL]
|
|
6
|
-
[![
|
|
7
|
-
[![
|
|
6
|
+
[![Open on npmx][npmVersionBadge]][npmVersionURL]
|
|
7
|
+
[![Open issue tracker][issuesBadge]][issuesURL]
|
|
8
8
|
|
|
9
|
-
[CIBadge]: https://img.shields.io/github/actions/workflow/status/marcalexiei/eslint-
|
|
10
|
-
[CIURL]: https://github.com/marcalexiei/eslint-
|
|
9
|
+
[CIBadge]: https://img.shields.io/github/actions/workflow/status/marcalexiei/eslint-zod/ci.yml?style=for-the-badge&logo=github&event=push&label=CI
|
|
10
|
+
[CIURL]: https://github.com/marcalexiei/eslint-zod/actions/workflows/CI.yml/badge.svg
|
|
11
11
|
[CodeStyleBadge]: https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=for-the-badge&logo=prettier
|
|
12
12
|
[CodeStyleURL]: https://prettier.io
|
|
13
13
|
[npmVersionBadge]: https://img.shields.io/npm/v/eslint-plugin-zod.svg?style=for-the-badge&logo=npm
|
|
14
|
-
[npmVersionURL]: https://
|
|
14
|
+
[npmVersionURL]: https://npmx.dev/package/eslint-plugin-zod
|
|
15
15
|
[lintBadge]: https://img.shields.io/badge/lint-eslint-3A33D1?logo=eslint&style=for-the-badge
|
|
16
16
|
[lintURL]: https://eslint.org
|
|
17
|
-
[issuesBadge]: https://img.shields.io/github/issues/marcalexiei/eslint-
|
|
18
|
-
[issuesURL]: https://github.com/marcalexiei/eslint-
|
|
17
|
+
[issuesBadge]: https://img.shields.io/github/issues/marcalexiei/eslint-zod.svg?style=for-the-badge
|
|
18
|
+
[issuesURL]: https://github.com/marcalexiei/eslint-zod/issues
|
|
19
19
|
|
|
20
20
|
[ESLint](https://eslint.org) plugin that adds custom linting rules to enforce best practices when using [Zod](https://github.com/colinhacks/zod).
|
|
21
21
|
|
|
@@ -24,56 +24,42 @@ Find out more about [Oxlint's `jsPLugins`](https://oxc.rs/docs/guide/usage/linte
|
|
|
24
24
|
|
|
25
25
|
## Rules
|
|
26
26
|
|
|
27
|
-
`zod` and `zod-mini` have distinct API surfaces.
|
|
28
|
-
This plugin is primarily built for `zod`, so some rules are exclusive to `zod` and not available for `zod-mini`.
|
|
29
|
-
|
|
30
27
|
<!-- begin auto-generated rules list -->
|
|
31
28
|
|
|
32
29
|
💼 Configurations enabled in.\
|
|
33
30
|
✅ Set in the `recommended` configuration.\
|
|
34
|
-
✔️ Set in the `recommendedMini` configuration.\
|
|
35
31
|
🔧 Automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/user-guide/command-line-interface#--fix).\
|
|
36
|
-
💡 Manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions)
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
|
42
|
-
|
|
|
43
|
-
| [consistent-
|
|
44
|
-
| [consistent-
|
|
45
|
-
| [consistent-
|
|
46
|
-
| [
|
|
47
|
-
| [
|
|
48
|
-
| [no-
|
|
49
|
-
| [no-
|
|
50
|
-
| [no-
|
|
51
|
-
| [
|
|
52
|
-
| [
|
|
53
|
-
| [
|
|
54
|
-
| [
|
|
55
|
-
| [
|
|
56
|
-
| [
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
|
61
|
-
|
|
|
62
|
-
| [
|
|
63
|
-
| [
|
|
64
|
-
| [
|
|
65
|
-
| [
|
|
66
|
-
| [
|
|
67
|
-
| [no-number-schema-with-safe](docs/rules/no-number-schema-with-safe.md) | Disallow deprecated `z.number().safe()`. Use `z.int()`; `.safe()` is now identical to `.int()`. | ✅ | 🔧 | | |
|
|
68
|
-
| [no-number-schema-with-step](docs/rules/no-number-schema-with-step.md) | Disallow deprecated `z.number().step()`. Use `.multipleOf()` instead. | ✅ | 🔧 | | |
|
|
69
|
-
| [no-optional-and-default-together](docs/rules/no-optional-and-default-together.md) | Disallow using both `.optional()` and `.default()` on the same Zod schema | ✅ | 🔧 | | |
|
|
70
|
-
| [no-string-schema-with-uuid](docs/rules/no-string-schema-with-uuid.md) | Disallow usage of `z.string().uuid()` in favor of the dedicated `z.uuid()` schema | ✅ | 🔧 | | |
|
|
71
|
-
| [no-throw-in-refine](docs/rules/no-throw-in-refine.md) | Disallow throwing errors directly inside Zod refine callbacks | ✅ | | | |
|
|
72
|
-
| [no-transform-in-record-key](docs/rules/no-transform-in-record-key.md) | Disallow transforms in z.record() key schemas, which can cause silent key mutations and data loss through key collisions | | | | |
|
|
73
|
-
| [prefer-enum-over-literal-union](docs/rules/prefer-enum-over-literal-union.md) | Prefer `z.enum()` over `z.union()` when all members are string literals. | ✅ | 🔧 | | |
|
|
74
|
-
| [prefer-meta-last](docs/rules/prefer-meta-last.md) | Enforce `.meta()` as last method | ✅ | 🔧 | | |
|
|
75
|
-
| [prefer-string-schema-with-trim](docs/rules/prefer-string-schema-with-trim.md) | Enforce `z.string().trim()` to prevent accidental leading/trailing whitespace | ✅ | 🔧 | | |
|
|
76
|
-
| [prefer-trim-before-string-length-checks](docs/rules/prefer-trim-before-string-length-checks.md) | Enforce `.trim()` is called before string length checks to ensure accurate validation | ✅ | 🔧 | | |
|
|
32
|
+
💡 Manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions).
|
|
33
|
+
|
|
34
|
+
| Name | Description | 💼 | 🔧 | 💡 |
|
|
35
|
+
| :----------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------- | :-- | :-- | :-- |
|
|
36
|
+
| [array-style](docs/rules/array-style.md) | Enforce consistent Zod array style | ✅ | 🔧 | |
|
|
37
|
+
| [consistent-import](docs/rules/consistent-import.md) | Enforce a consistent import style for Zod | ✅ | 🔧 | |
|
|
38
|
+
| [consistent-import-source](docs/rules/consistent-import-source.md) | Enforce consistent source from Zod imports | | | 💡 |
|
|
39
|
+
| [consistent-object-schema-type](docs/rules/consistent-object-schema-type.md) | Enforce consistent usage of Zod schema methods | | | 💡 |
|
|
40
|
+
| [consistent-schema-output-type-style](docs/rules/consistent-schema-output-type-style.md) | Enforce consistent use of z.infer or z.output for schema type inference | | 🔧 | |
|
|
41
|
+
| [consistent-schema-var-name](docs/rules/consistent-schema-var-name.md) | Enforce a consistent naming convention for Zod schema variables | ✅ | | |
|
|
42
|
+
| [no-any-schema](docs/rules/no-any-schema.md) | Disallow usage of `z.any()` in Zod schemas | ✅ | | 💡 |
|
|
43
|
+
| [no-empty-custom-schema](docs/rules/no-empty-custom-schema.md) | Disallow usage of `z.custom()` without arguments | ✅ | | |
|
|
44
|
+
| [no-number-schema-with-finite](docs/rules/no-number-schema-with-finite.md) | Disallow deprecated `z.number().finite()`. In Zod 4+ number schemas do not allow infinite values by default, so it is a no-op. | ✅ | 🔧 | |
|
|
45
|
+
| [no-number-schema-with-int](docs/rules/no-number-schema-with-int.md) | Disallow usage of `z.number().int()` as it is considered legacy | ✅ | 🔧 | |
|
|
46
|
+
| [no-number-schema-with-is-finite](docs/rules/no-number-schema-with-is-finite.md) | Disallow using deprecated `isFinite` on a Zod number schema; in v4+ it is always `true`. | ✅ | | |
|
|
47
|
+
| [no-number-schema-with-is-int](docs/rules/no-number-schema-with-is-int.md) | Disallow using deprecated `isInt` on a Zod number schema; check the `format` property instead. | ✅ | | |
|
|
48
|
+
| [no-number-schema-with-safe](docs/rules/no-number-schema-with-safe.md) | Disallow deprecated `z.number().safe()`. Use `z.int()`; `.safe()` is now identical to `.int()`. | ✅ | 🔧 | |
|
|
49
|
+
| [no-number-schema-with-step](docs/rules/no-number-schema-with-step.md) | Disallow deprecated `z.number().step()`. Use `.multipleOf()` instead. | ✅ | 🔧 | |
|
|
50
|
+
| [no-optional-and-default-together](docs/rules/no-optional-and-default-together.md) | Disallow using both `.optional()` and `.default()` on the same Zod schema | ✅ | 🔧 | |
|
|
51
|
+
| [no-string-schema-with-uuid](docs/rules/no-string-schema-with-uuid.md) | Disallow usage of `z.string().uuid()` in favor of the dedicated `z.uuid()` schema | ✅ | 🔧 | |
|
|
52
|
+
| [no-throw-in-refine](docs/rules/no-throw-in-refine.md) | Disallow throwing errors directly inside Zod refine callbacks | ✅ | | |
|
|
53
|
+
| [no-transform-in-record-key](docs/rules/no-transform-in-record-key.md) | Disallow transforms in z.record() key schemas, which can cause silent key mutations and data loss through key collisions | | | |
|
|
54
|
+
| [no-unknown-schema](docs/rules/no-unknown-schema.md) | Disallow usage of `z.unknown()` in Zod schemas | | | |
|
|
55
|
+
| [prefer-enum-over-literal-union](docs/rules/prefer-enum-over-literal-union.md) | Prefer `z.enum()` over `z.union()` when all members are string literals. | ✅ | 🔧 | |
|
|
56
|
+
| [prefer-meta](docs/rules/prefer-meta.md) | Enforce usage of `.meta()` over `.describe()` | ✅ | 🔧 | |
|
|
57
|
+
| [prefer-meta-last](docs/rules/prefer-meta-last.md) | Enforce `.meta()` as last method | ✅ | 🔧 | |
|
|
58
|
+
| [prefer-string-schema-with-trim](docs/rules/prefer-string-schema-with-trim.md) | Enforce `z.string().trim()` to prevent accidental leading/trailing whitespace | ✅ | 🔧 | |
|
|
59
|
+
| [prefer-trim-before-string-length-checks](docs/rules/prefer-trim-before-string-length-checks.md) | Enforce `.trim()` is called before string length checks to ensure accurate validation | ✅ | 🔧 | |
|
|
60
|
+
| [require-brand-type-parameter](docs/rules/require-brand-type-parameter.md) | Require type parameter on `.brand()` functions | ✅ | | 💡 |
|
|
61
|
+
| [require-error-message](docs/rules/require-error-message.md) | Enforce that custom refinements include an error message | ✅ | 🔧 | |
|
|
62
|
+
| [schema-error-property-style](docs/rules/schema-error-property-style.md) | Enforce consistent style for error messages in Zod schema validation (using ESQuery patterns) | | | |
|
|
77
63
|
|
|
78
64
|
<!-- end auto-generated rules list -->
|
|
79
65
|
|
|
@@ -109,7 +95,7 @@ pnpm add --save-dev eslint eslint-plugin-zod
|
|
|
109
95
|
eslintPluginZod.configs.recommended,
|
|
110
96
|
```
|
|
111
97
|
|
|
112
|
-
Here
|
|
98
|
+
Here's a minimal example using the flat config format:
|
|
113
99
|
|
|
114
100
|
```ts
|
|
115
101
|
// eslint.config.js
|
|
@@ -159,7 +145,7 @@ pnpm add --save-dev oxlint eslint-plugin-zod
|
|
|
159
145
|
3. Add `eslintPluginZod.configs.recommended.rules` to your Oxlint config.\
|
|
160
146
|
Alternatively you can specify the rules manually
|
|
161
147
|
|
|
162
|
-
Here
|
|
148
|
+
Here's a minimal example using the flat config format:
|
|
163
149
|
|
|
164
150
|
```ts
|
|
165
151
|
// oxlint.config.ts
|
|
@@ -178,9 +164,9 @@ export default defineConfig({
|
|
|
178
164
|
|
|
179
165
|
`eslint-plugin-zod` is designed for projects that use `zod@^4`.
|
|
180
166
|
While the plugin analyzes Zod schemas in your code,
|
|
181
|
-
it doesn
|
|
167
|
+
it doesn't import or depend on Zod at runtime.
|
|
182
168
|
To document this relationship without forcing installation,
|
|
183
|
-
Zod is declared as an optional peer dependency in the plugin
|
|
169
|
+
Zod is declared as an optional peer dependency in the plugin's `package.json`.
|
|
184
170
|
|
|
185
171
|
If your project uses Zod v4, the plugin will automatically lint your schemas.
|
|
186
|
-
If you
|
|
172
|
+
If you're not using Zod (for example, in a separate ESLint workspace), you don't need to install it.
|
package/dist/index.cjs
CHANGED
|
@@ -21,12 +21,10 @@ const require_no_unknown_schema = require("./rules/no-unknown-schema.cjs");
|
|
|
21
21
|
const require_prefer_enum_over_literal_union = require("./rules/prefer-enum-over-literal-union.cjs");
|
|
22
22
|
const require_prefer_meta_last = require("./rules/prefer-meta-last.cjs");
|
|
23
23
|
const require_prefer_meta = require("./rules/prefer-meta.cjs");
|
|
24
|
-
const require_prefer_namespace_import = require("./rules/prefer-namespace-import.cjs");
|
|
25
24
|
const require_prefer_string_schema_with_trim = require("./rules/prefer-string-schema-with-trim.cjs");
|
|
26
25
|
const require_prefer_trim_before_string_length_checks = require("./rules/prefer-trim-before-string-length-checks.cjs");
|
|
27
26
|
const require_require_brand_type_parameter = require("./rules/require-brand-type-parameter.cjs");
|
|
28
27
|
const require_require_error_message = require("./rules/require-error-message.cjs");
|
|
29
|
-
const require_require_schema_suffix = require("./rules/require-schema-suffix.cjs");
|
|
30
28
|
const require_schema_error_property_style = require("./rules/schema-error-property-style.cjs");
|
|
31
29
|
//#region src/index.ts
|
|
32
30
|
const eslintPluginZod = {
|
|
@@ -57,22 +55,17 @@ const eslintPluginZod = {
|
|
|
57
55
|
"prefer-enum-over-literal-union": require_prefer_enum_over_literal_union.preferEnumOverLiteralUnion,
|
|
58
56
|
"prefer-meta": require_prefer_meta.preferMeta,
|
|
59
57
|
"prefer-meta-last": require_prefer_meta_last.preferMetaLast,
|
|
60
|
-
"prefer-namespace-import": require_prefer_namespace_import.preferNamespaceImport,
|
|
61
58
|
"prefer-string-schema-with-trim": require_prefer_string_schema_with_trim.preferStringSchemaWithTrim,
|
|
62
59
|
"prefer-trim-before-string-length-checks": require_prefer_trim_before_string_length_checks.preferTrimBeforeStringLengthChecks,
|
|
63
60
|
"require-brand-type-parameter": require_require_brand_type_parameter.requireBrandTypeParameter,
|
|
64
61
|
"require-error-message": require_require_error_message.requireErrorMessage,
|
|
65
|
-
"require-schema-suffix": require_require_schema_suffix.requireSchemaSuffix,
|
|
66
62
|
"schema-error-property-style": require_schema_error_property_style.schemaErrorPropertyStyle
|
|
67
63
|
}
|
|
68
64
|
};
|
|
69
|
-
const
|
|
65
|
+
const recommendedConfig = {
|
|
70
66
|
name: `${require_meta.PLUGIN_NAME}/recommended`,
|
|
71
67
|
files: ["**/*.{js,mjs,cjs,jsx,mjsx,ts,tsx,mtsx}"],
|
|
72
|
-
plugins: { zod: eslintPluginZod }
|
|
73
|
-
};
|
|
74
|
-
const recommendedConfig = {
|
|
75
|
-
...baseConfig,
|
|
68
|
+
plugins: { zod: eslintPluginZod },
|
|
76
69
|
rules: {
|
|
77
70
|
"zod/array-style": "error",
|
|
78
71
|
"zod/consistent-import": "error",
|
|
@@ -97,26 +90,13 @@ const recommendedConfig = {
|
|
|
97
90
|
"zod/require-error-message": "error"
|
|
98
91
|
}
|
|
99
92
|
};
|
|
100
|
-
const recommendedConfigMini = {
|
|
101
|
-
...baseConfig,
|
|
102
|
-
rules: {
|
|
103
|
-
"zod/consistent-schema-var-name": "error",
|
|
104
|
-
"zod/no-any-schema": "error",
|
|
105
|
-
"zod/prefer-meta": "error",
|
|
106
|
-
"zod/require-brand-type-parameter": "error",
|
|
107
|
-
"zod/require-error-message": "error"
|
|
108
|
-
}
|
|
109
|
-
};
|
|
110
93
|
var src_default = {
|
|
111
94
|
...eslintPluginZod,
|
|
112
|
-
configs: {
|
|
113
|
-
recommended: recommendedConfig,
|
|
114
|
-
recommendedMini: recommendedConfigMini
|
|
115
|
-
}
|
|
95
|
+
configs: { recommended: recommendedConfig }
|
|
116
96
|
};
|
|
117
97
|
/**
|
|
118
98
|
* why `satisfies`?
|
|
119
|
-
* @see https://github.com/marcalexiei/eslint-
|
|
99
|
+
* @see https://github.com/marcalexiei/eslint-zod/issues/49
|
|
120
100
|
*/
|
|
121
101
|
//#endregion
|
|
122
102
|
module.exports = src_default;
|
package/dist/index.d.cts
CHANGED
package/dist/index.d.mts
CHANGED
package/dist/index.mjs
CHANGED
|
@@ -21,12 +21,10 @@ import { noUnknownSchema } from "./rules/no-unknown-schema.mjs";
|
|
|
21
21
|
import { preferEnumOverLiteralUnion } from "./rules/prefer-enum-over-literal-union.mjs";
|
|
22
22
|
import { preferMetaLast } from "./rules/prefer-meta-last.mjs";
|
|
23
23
|
import { preferMeta } from "./rules/prefer-meta.mjs";
|
|
24
|
-
import { preferNamespaceImport } from "./rules/prefer-namespace-import.mjs";
|
|
25
24
|
import { preferStringSchemaWithTrim } from "./rules/prefer-string-schema-with-trim.mjs";
|
|
26
25
|
import { preferTrimBeforeStringLengthChecks } from "./rules/prefer-trim-before-string-length-checks.mjs";
|
|
27
26
|
import { requireBrandTypeParameter } from "./rules/require-brand-type-parameter.mjs";
|
|
28
27
|
import { requireErrorMessage } from "./rules/require-error-message.mjs";
|
|
29
|
-
import { requireSchemaSuffix } from "./rules/require-schema-suffix.mjs";
|
|
30
28
|
import { schemaErrorPropertyStyle } from "./rules/schema-error-property-style.mjs";
|
|
31
29
|
//#region src/index.ts
|
|
32
30
|
const eslintPluginZod = {
|
|
@@ -57,22 +55,17 @@ const eslintPluginZod = {
|
|
|
57
55
|
"prefer-enum-over-literal-union": preferEnumOverLiteralUnion,
|
|
58
56
|
"prefer-meta": preferMeta,
|
|
59
57
|
"prefer-meta-last": preferMetaLast,
|
|
60
|
-
"prefer-namespace-import": preferNamespaceImport,
|
|
61
58
|
"prefer-string-schema-with-trim": preferStringSchemaWithTrim,
|
|
62
59
|
"prefer-trim-before-string-length-checks": preferTrimBeforeStringLengthChecks,
|
|
63
60
|
"require-brand-type-parameter": requireBrandTypeParameter,
|
|
64
61
|
"require-error-message": requireErrorMessage,
|
|
65
|
-
"require-schema-suffix": requireSchemaSuffix,
|
|
66
62
|
"schema-error-property-style": schemaErrorPropertyStyle
|
|
67
63
|
}
|
|
68
64
|
};
|
|
69
|
-
const
|
|
65
|
+
const recommendedConfig = {
|
|
70
66
|
name: `${PLUGIN_NAME}/recommended`,
|
|
71
67
|
files: ["**/*.{js,mjs,cjs,jsx,mjsx,ts,tsx,mtsx}"],
|
|
72
|
-
plugins: { zod: eslintPluginZod }
|
|
73
|
-
};
|
|
74
|
-
const recommendedConfig = {
|
|
75
|
-
...baseConfig,
|
|
68
|
+
plugins: { zod: eslintPluginZod },
|
|
76
69
|
rules: {
|
|
77
70
|
"zod/array-style": "error",
|
|
78
71
|
"zod/consistent-import": "error",
|
|
@@ -97,26 +90,13 @@ const recommendedConfig = {
|
|
|
97
90
|
"zod/require-error-message": "error"
|
|
98
91
|
}
|
|
99
92
|
};
|
|
100
|
-
const recommendedConfigMini = {
|
|
101
|
-
...baseConfig,
|
|
102
|
-
rules: {
|
|
103
|
-
"zod/consistent-schema-var-name": "error",
|
|
104
|
-
"zod/no-any-schema": "error",
|
|
105
|
-
"zod/prefer-meta": "error",
|
|
106
|
-
"zod/require-brand-type-parameter": "error",
|
|
107
|
-
"zod/require-error-message": "error"
|
|
108
|
-
}
|
|
109
|
-
};
|
|
110
93
|
var src_default = {
|
|
111
94
|
...eslintPluginZod,
|
|
112
|
-
configs: {
|
|
113
|
-
recommended: recommendedConfig,
|
|
114
|
-
recommendedMini: recommendedConfigMini
|
|
115
|
-
}
|
|
95
|
+
configs: { recommended: recommendedConfig }
|
|
116
96
|
};
|
|
117
97
|
/**
|
|
118
98
|
* why `satisfies`?
|
|
119
|
-
* @see https://github.com/marcalexiei/eslint-
|
|
99
|
+
* @see https://github.com/marcalexiei/eslint-zod/issues/49
|
|
120
100
|
*/
|
|
121
101
|
//#endregion
|
|
122
102
|
export { src_default as default };
|
package/dist/meta.cjs
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
require("./_virtual/_rolldown/runtime.cjs");
|
|
2
2
|
let node_fs = require("node:fs");
|
|
3
3
|
//#region src/meta.ts
|
|
4
|
-
const { name: PLUGIN_NAME, version: PLUGIN_VERSION,
|
|
5
|
-
/** @see https://github.com/marcalexiei/eslint-plugin-zod/pull/97 */
|
|
6
|
-
const PLUGIN_HOMEPAGE = homepage.replace(/#[^#]*$/, "");
|
|
4
|
+
const { name: PLUGIN_NAME, version: PLUGIN_VERSION, repository } = JSON.parse((0, node_fs.readFileSync)(new URL("../package.json", require("url").pathToFileURL(__filename).href), "utf8"));
|
|
7
5
|
function getRuleURL(ruleID) {
|
|
8
|
-
return `${
|
|
6
|
+
return `${repository.url}/blob/HEAD/${repository.directory}/docs/rules/${ruleID}.md`;
|
|
9
7
|
}
|
|
10
8
|
//#endregion
|
|
11
9
|
exports.PLUGIN_NAME = PLUGIN_NAME;
|
package/dist/meta.mjs
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
2
|
//#region src/meta.ts
|
|
3
|
-
const { name: PLUGIN_NAME, version: PLUGIN_VERSION,
|
|
4
|
-
/** @see https://github.com/marcalexiei/eslint-plugin-zod/pull/97 */
|
|
5
|
-
const PLUGIN_HOMEPAGE = homepage.replace(/#[^#]*$/, "");
|
|
3
|
+
const { name: PLUGIN_NAME, version: PLUGIN_VERSION, repository } = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
|
|
6
4
|
function getRuleURL(ruleID) {
|
|
7
|
-
return `${
|
|
5
|
+
return `${repository.url}/blob/HEAD/${repository.directory}/docs/rules/${ruleID}.md`;
|
|
8
6
|
}
|
|
9
7
|
//#endregion
|
|
10
8
|
export { PLUGIN_NAME, PLUGIN_VERSION, getRuleURL };
|
|
@@ -1,18 +1,16 @@
|
|
|
1
|
+
require("../_virtual/_rolldown/runtime.cjs");
|
|
1
2
|
const require_create_plugin_rule = require("../utils/create-plugin-rule.cjs");
|
|
2
|
-
|
|
3
|
+
let _eslint_zod_utils = require("@eslint-zod/utils");
|
|
3
4
|
//#region src/rules/array-style.ts
|
|
4
5
|
const ZOD_ARRAY_STYLES = ["function", "method"];
|
|
5
6
|
const defaultOptions = { style: "function" };
|
|
6
|
-
const {
|
|
7
|
+
const { trackZodSchemaImports } = (0, _eslint_zod_utils.createZodSchemaImportTrack)(_eslint_zod_utils.zodImportScope);
|
|
7
8
|
const arrayStyle = require_create_plugin_rule.createZodPluginRule({
|
|
8
9
|
name: "array-style",
|
|
9
10
|
meta: {
|
|
10
11
|
type: "suggestion",
|
|
11
12
|
fixable: "code",
|
|
12
|
-
docs: {
|
|
13
|
-
zodImportAllowedSource,
|
|
14
|
-
description: "Enforce consistent Zod array style"
|
|
15
|
-
},
|
|
13
|
+
docs: { description: "Enforce consistent Zod array style" },
|
|
16
14
|
messages: {
|
|
17
15
|
useFunction: "Use z.array(schema) instead of schema.array().",
|
|
18
16
|
useMethod: "Use schema.array() instead of z.array(schema)."
|
|
@@ -1,18 +1,15 @@
|
|
|
1
1
|
import { createZodPluginRule } from "../utils/create-plugin-rule.mjs";
|
|
2
|
-
import { createZodSchemaImportTrack } from "
|
|
2
|
+
import { createZodSchemaImportTrack, zodImportScope } from "@eslint-zod/utils";
|
|
3
3
|
//#region src/rules/array-style.ts
|
|
4
4
|
const ZOD_ARRAY_STYLES = ["function", "method"];
|
|
5
5
|
const defaultOptions = { style: "function" };
|
|
6
|
-
const {
|
|
6
|
+
const { trackZodSchemaImports } = createZodSchemaImportTrack(zodImportScope);
|
|
7
7
|
const arrayStyle = createZodPluginRule({
|
|
8
8
|
name: "array-style",
|
|
9
9
|
meta: {
|
|
10
10
|
type: "suggestion",
|
|
11
11
|
fixable: "code",
|
|
12
|
-
docs: {
|
|
13
|
-
zodImportAllowedSource,
|
|
14
|
-
description: "Enforce consistent Zod array style"
|
|
15
|
-
},
|
|
12
|
+
docs: { description: "Enforce consistent Zod array style" },
|
|
16
13
|
messages: {
|
|
17
14
|
useFunction: "Use z.array(schema) instead of schema.array().",
|
|
18
15
|
useMethod: "Use schema.array() instead of z.array(schema)."
|
|
@@ -1,15 +1,13 @@
|
|
|
1
|
+
require("../_virtual/_rolldown/runtime.cjs");
|
|
1
2
|
const require_create_plugin_rule = require("../utils/create-plugin-rule.cjs");
|
|
2
|
-
|
|
3
|
+
let _eslint_zod_utils = require("@eslint-zod/utils");
|
|
3
4
|
//#region src/rules/consistent-import-source.ts
|
|
4
5
|
const consistentImportSource = require_create_plugin_rule.createZodPluginRule({
|
|
5
6
|
name: "consistent-import-source",
|
|
6
7
|
meta: {
|
|
7
8
|
hasSuggestions: true,
|
|
8
9
|
type: "suggestion",
|
|
9
|
-
docs: {
|
|
10
|
-
zodImportAllowedSource: "all",
|
|
11
|
-
description: "Enforce consistent source from Zod imports"
|
|
12
|
-
},
|
|
10
|
+
docs: { description: "Enforce consistent source from Zod imports" },
|
|
13
11
|
messages: {
|
|
14
12
|
sourceNotAllowed: "\"{{source}}\" is not allowed. Available values are: {{sources}}",
|
|
15
13
|
replaceSource: "Replace \"{{invalid}}\" with \"{{valid}}\""
|
|
@@ -21,7 +19,7 @@ const consistentImportSource = require_create_plugin_rule.createZodPluginRule({
|
|
|
21
19
|
description: "An array of allowed Zod import sources.",
|
|
22
20
|
items: {
|
|
23
21
|
type: "string",
|
|
24
|
-
enum: [...
|
|
22
|
+
enum: [..._eslint_zod_utils.zodImportScope.sources]
|
|
25
23
|
},
|
|
26
24
|
minItems: 1,
|
|
27
25
|
uniqueItems: true
|
|
@@ -33,7 +31,7 @@ const consistentImportSource = require_create_plugin_rule.createZodPluginRule({
|
|
|
33
31
|
create(context, [{ sources }]) {
|
|
34
32
|
return { ImportDeclaration(node) {
|
|
35
33
|
const sourceValue = node.source.value;
|
|
36
|
-
if (!
|
|
34
|
+
if (!_eslint_zod_utils.zodImportScope.isAllowed(sourceValue)) return;
|
|
37
35
|
if (sources.includes(sourceValue)) return;
|
|
38
36
|
context.report({
|
|
39
37
|
node,
|
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
import { createZodPluginRule } from "../utils/create-plugin-rule.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { zodImportScope } from "@eslint-zod/utils";
|
|
3
3
|
//#region src/rules/consistent-import-source.ts
|
|
4
4
|
const consistentImportSource = createZodPluginRule({
|
|
5
5
|
name: "consistent-import-source",
|
|
6
6
|
meta: {
|
|
7
7
|
hasSuggestions: true,
|
|
8
8
|
type: "suggestion",
|
|
9
|
-
docs: {
|
|
10
|
-
zodImportAllowedSource: "all",
|
|
11
|
-
description: "Enforce consistent source from Zod imports"
|
|
12
|
-
},
|
|
9
|
+
docs: { description: "Enforce consistent source from Zod imports" },
|
|
13
10
|
messages: {
|
|
14
11
|
sourceNotAllowed: "\"{{source}}\" is not allowed. Available values are: {{sources}}",
|
|
15
12
|
replaceSource: "Replace \"{{invalid}}\" with \"{{valid}}\""
|
|
@@ -21,7 +18,7 @@ const consistentImportSource = createZodPluginRule({
|
|
|
21
18
|
description: "An array of allowed Zod import sources.",
|
|
22
19
|
items: {
|
|
23
20
|
type: "string",
|
|
24
|
-
enum: [...
|
|
21
|
+
enum: [...zodImportScope.sources]
|
|
25
22
|
},
|
|
26
23
|
minItems: 1,
|
|
27
24
|
uniqueItems: true
|
|
@@ -33,7 +30,7 @@ const consistentImportSource = createZodPluginRule({
|
|
|
33
30
|
create(context, [{ sources }]) {
|
|
34
31
|
return { ImportDeclaration(node) {
|
|
35
32
|
const sourceValue = node.source.value;
|
|
36
|
-
if (!
|
|
33
|
+
if (!zodImportScope.isAllowed(sourceValue)) return;
|
|
37
34
|
if (sources.includes(sourceValue)) return;
|
|
38
35
|
context.report({
|
|
39
36
|
node,
|
|
@@ -1,58 +1,12 @@
|
|
|
1
1
|
require("../_virtual/_rolldown/runtime.cjs");
|
|
2
2
|
const require_create_plugin_rule = require("../utils/create-plugin-rule.cjs");
|
|
3
|
-
|
|
4
|
-
let _typescript_eslint_utils = require("@typescript-eslint/utils");
|
|
3
|
+
let _eslint_zod_utils = require("@eslint-zod/utils");
|
|
5
4
|
//#region src/rules/consistent-import.ts
|
|
6
|
-
const IMPORT_SYNTAXES = ["namespace", "named"];
|
|
7
|
-
/**
|
|
8
|
-
* Determines whether the first import in a group is valid for a given import
|
|
9
|
-
* syntax (`named` or `namespace`), taking into account whether the group
|
|
10
|
-
* contains only type imports.
|
|
11
|
-
*
|
|
12
|
-
* Rules enforced:
|
|
13
|
-
* - For `named` syntax:
|
|
14
|
-
* - The first import must have exactly one specifier
|
|
15
|
-
* - That specifier must be a named import of identifier `z`
|
|
16
|
-
* - For `namespace` syntax:
|
|
17
|
-
* - The first import must have exactly one namespace specifier
|
|
18
|
-
* - If the group contains only type imports, the first import must explicitly
|
|
19
|
-
* be declared as `import type`
|
|
20
|
-
*
|
|
21
|
-
* @param group - Metadata describing the import group
|
|
22
|
-
* @param syntax - Expected import syntax for the group
|
|
23
|
-
* @returns `true` if the first import matches the expected syntax and type rules
|
|
24
|
-
*/
|
|
25
|
-
function isGroupFirstImportKindValidForSyntax(group, syntax) {
|
|
26
|
-
const { hasOnlyTypeImports, nodes } = group;
|
|
27
|
-
const [firstImportNode] = nodes;
|
|
28
|
-
const { specifiers, importKind } = firstImportNode;
|
|
29
|
-
if (specifiers.length !== 1) return false;
|
|
30
|
-
const [specifier] = specifiers;
|
|
31
|
-
if (!(syntax === "named" ? specifier.type === _typescript_eslint_utils.AST_NODE_TYPES.ImportSpecifier && specifier.imported.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier && specifier.imported.name === "z" : specifier.type === _typescript_eslint_utils.AST_NODE_TYPES.ImportNamespaceSpecifier)) return false;
|
|
32
|
-
if (hasOnlyTypeImports) return importKind === "type";
|
|
33
|
-
return true;
|
|
34
|
-
}
|
|
35
|
-
function shouldIdentifierBeRenamed(node) {
|
|
36
|
-
if (node.parent.type === _typescript_eslint_utils.AST_NODE_TYPES.ImportSpecifier) return false;
|
|
37
|
-
if (node.parent.type === _typescript_eslint_utils.AST_NODE_TYPES.MemberExpression && node.parent.object.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier && node.parent.object.name !== node.name) return false;
|
|
38
|
-
return true;
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* From a given specifiers retrieve the most significant to use when creating an alias import
|
|
42
|
-
*/
|
|
43
|
-
function getNamespaceAliasNameFrom(node) {
|
|
44
|
-
if (node.type === _typescript_eslint_utils.AST_NODE_TYPES.ImportDefaultSpecifier || node.type === _typescript_eslint_utils.AST_NODE_TYPES.ImportNamespaceSpecifier) return node.local.name;
|
|
45
|
-
if (node.imported.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier && node.imported.name === "z") return node.local.name;
|
|
46
|
-
return null;
|
|
47
|
-
}
|
|
48
5
|
const consistentImport = require_create_plugin_rule.createZodPluginRule({
|
|
49
6
|
name: "consistent-import",
|
|
50
7
|
meta: {
|
|
51
8
|
type: "problem",
|
|
52
|
-
docs: {
|
|
53
|
-
zodImportAllowedSource: "all",
|
|
54
|
-
description: "Enforce a consistent import style for Zod"
|
|
55
|
-
},
|
|
9
|
+
docs: { description: "Enforce a consistent import style for Zod" },
|
|
56
10
|
fixable: "code",
|
|
57
11
|
messages: {
|
|
58
12
|
changeImportSyntax: "Use a {{syntax}} import for Zod.",
|
|
@@ -64,7 +18,7 @@ const consistentImport = require_create_plugin_rule.createZodPluginRule({
|
|
|
64
18
|
properties: { syntax: {
|
|
65
19
|
description: "Specifies the import syntax to use for Zod.",
|
|
66
20
|
type: "string",
|
|
67
|
-
enum: IMPORT_SYNTAXES
|
|
21
|
+
enum: _eslint_zod_utils.IMPORT_SYNTAXES
|
|
68
22
|
} },
|
|
69
23
|
additionalProperties: false
|
|
70
24
|
}]
|
|
@@ -77,8 +31,8 @@ const consistentImport = require_create_plugin_rule.createZodPluginRule({
|
|
|
77
31
|
return {
|
|
78
32
|
ImportDeclaration(node) {
|
|
79
33
|
const { source, importKind } = node;
|
|
80
|
-
if (!
|
|
81
|
-
|
|
34
|
+
if (!_eslint_zod_utils.zodImportScope.isAllowed(source.value)) return;
|
|
35
|
+
importGroups[source.value] ??= {
|
|
82
36
|
hasOnlyTypeImports: true,
|
|
83
37
|
nodes: []
|
|
84
38
|
};
|
|
@@ -98,7 +52,7 @@ const consistentImport = require_create_plugin_rule.createZodPluginRule({
|
|
|
98
52
|
let namespaceAliasName = null;
|
|
99
53
|
for (const specifier of nodes.flatMap((it) => it.specifiers)) {
|
|
100
54
|
if (!namespaceAliasName) {
|
|
101
|
-
namespaceAliasName = getNamespaceAliasNameFrom(specifier);
|
|
55
|
+
namespaceAliasName = (0, _eslint_zod_utils.getNamespaceAliasNameFrom)(specifier);
|
|
102
56
|
if (namespaceAliasName) continue;
|
|
103
57
|
}
|
|
104
58
|
nodesWithVariablesToUpdate.push(specifier);
|
|
@@ -110,7 +64,7 @@ const consistentImport = require_create_plugin_rule.createZodPluginRule({
|
|
|
110
64
|
namespaceAliasNameIndex += 1;
|
|
111
65
|
}
|
|
112
66
|
}
|
|
113
|
-
if (!isGroupFirstImportKindValidForSyntax(importGroup, syntax)) context.report({
|
|
67
|
+
if (!(0, _eslint_zod_utils.isGroupFirstImportKindValidForSyntax)(importGroup, syntax)) context.report({
|
|
114
68
|
node: firstImportNode,
|
|
115
69
|
messageId: "changeImportSyntax",
|
|
116
70
|
data: { syntax },
|
|
@@ -127,7 +81,7 @@ const consistentImport = require_create_plugin_rule.createZodPluginRule({
|
|
|
127
81
|
const allReferences = nodesWithVariablesToUpdate.flatMap((it) => sourceCode.getDeclaredVariables(it)).flatMap((it) => it.references);
|
|
128
82
|
for (const ref of allReferences) {
|
|
129
83
|
const { identifier } = ref;
|
|
130
|
-
if (shouldIdentifierBeRenamed(identifier)) context.report({
|
|
84
|
+
if ((0, _eslint_zod_utils.shouldIdentifierBeRenamed)(identifier)) context.report({
|
|
131
85
|
node: identifier,
|
|
132
86
|
messageId: "convertUsage",
|
|
133
87
|
data: { syntax },
|