eslint-plugin-zod 4.7.1 → 4.8.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 CHANGED
@@ -42,6 +42,7 @@ Find out more about [Oxlint's `jsPLugins`](https://oxc.rs/docs/guide/usage/linte
42
42
  | [consistent-schema-var-name](docs/rules/consistent-schema-var-name.md) | Enforce a consistent naming convention for Zod schema variables | ✅ | | | |
43
43
  | [no-any-schema](docs/rules/no-any-schema.md) | Disallow usage of `z.any()` in Zod schemas | ✅ | | 💡 | |
44
44
  | [no-coerce-boolean](docs/rules/no-coerce-boolean.md) | Disallow `z.coerce.boolean()` because it treats any non-empty string as `true`. | ✅ | | 💡 | |
45
+ | [no-conflicting-checks](docs/rules/no-conflicting-checks.md) | Disallow check combinations that can never match, are redundant, or do not apply to the schema type | | | | |
45
46
  | [no-duplicate-schema-methods](docs/rules/no-duplicate-schema-methods.md) | Disallow calling the same schema method more than once in a single chain | ✅ | | | |
46
47
  | [no-empty-custom-schema](docs/rules/no-empty-custom-schema.md) | Disallow usage of `z.custom()` without arguments | ✅ | | | |
47
48
  | [no-native-enum](docs/rules/no-native-enum.md) | Disallow deprecated `z.nativeEnum()` in favor of `z.enum()`. | ✅ | 🔧 | | |
@@ -59,6 +60,7 @@ Find out more about [Oxlint's `jsPLugins`](https://oxc.rs/docs/guide/usage/linte
59
60
  | [no-throw-in-refine](docs/rules/no-throw-in-refine.md) | Disallow throwing errors directly inside Zod refine callbacks | ✅ | | | |
60
61
  | [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 | | | | |
61
62
  | [no-unknown-schema](docs/rules/no-unknown-schema.md) | Disallow usage of `z.unknown()` in Zod schemas | | | | |
63
+ | [no-unnecessary-readonly](docs/rules/no-unnecessary-readonly.md) | Disallow `.readonly()` on schemas whose output is already immutable | | 🔧 | | |
62
64
  | [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. | ✅ | 🔧 | | |
63
65
  | [prefer-loose-object](docs/rules/prefer-loose-object.md) | Prefer `z.looseObject()` over `z.object().passthrough()` and `z.object().loose()` | ✅ | 🔧 | | |
64
66
  | [prefer-meta](docs/rules/prefer-meta.md) | Enforce usage of `.meta()` over `.describe()` | ✅ | 🔧 | | |
@@ -67,6 +69,7 @@ Find out more about [Oxlint's `jsPLugins`](https://oxc.rs/docs/guide/usage/linte
67
69
  | [prefer-string-schema-with-trim](docs/rules/prefer-string-schema-with-trim.md) | Enforce `z.string().trim()` to prevent accidental leading/trailing whitespace | ✅ | 🔧 | | |
68
70
  | [prefer-top-level-string-formats](docs/rules/prefer-top-level-string-formats.md) | Prefer top-level string format schemas over deprecated `z.string().<format>()` methods | ✅ | 🔧 | | |
69
71
  | [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 | ✅ | 🔧 | | |
72
+ | [prefer-tuple-over-array-length](docs/rules/prefer-tuple-over-array-length.md) | Prefer `z.tuple()` over a length-constrained `z.array()` so the length is preserved in the inferred type. | | 🔧 | | |
70
73
  | [require-brand-type-parameter](docs/rules/require-brand-type-parameter.md) | Require type parameter on `.brand()` functions | ✅ | | 💡 | |
71
74
  | [require-error-message](docs/rules/require-error-message.md) | Enforce that custom refinements include an error message | ✅ | 🔧 | | |
72
75
  | [schema-error-property-style](docs/rules/schema-error-property-style.md) | Enforce consistent style for error messages in Zod schema validation (using ESQuery patterns) | | | | |
package/dist/index.cjs CHANGED
@@ -7,6 +7,7 @@ const require_consistent_schema_output_type_style = require("./rules/consistent-
7
7
  const require_consistent_schema_var_name = require("./rules/consistent-schema-var-name.cjs");
8
8
  const require_no_any_schema = require("./rules/no-any-schema.cjs");
9
9
  const require_no_coerce_boolean = require("./rules/no-coerce-boolean.cjs");
10
+ const require_no_conflicting_checks = require("./rules/no-conflicting-checks.cjs");
10
11
  const require_no_duplicate_schema_methods = require("./rules/no-duplicate-schema-methods.cjs");
11
12
  const require_no_empty_custom_schema = require("./rules/no-empty-custom-schema.cjs");
12
13
  const require_no_native_enum = require("./rules/no-native-enum.cjs");
@@ -24,6 +25,7 @@ const require_no_string_schema_with_uuid = require("./rules/no-string-schema-wit
24
25
  const require_no_throw_in_refine = require("./rules/no-throw-in-refine.cjs");
25
26
  const require_no_transform_in_record_key = require("./rules/no-transform-in-record-key.cjs");
26
27
  const require_no_unknown_schema = require("./rules/no-unknown-schema.cjs");
28
+ const require_no_unnecessary_readonly = require("./rules/no-unnecessary-readonly.cjs");
27
29
  const require_prefer_enum_over_literal_union = require("./rules/prefer-enum-over-literal-union.cjs");
28
30
  const require_prefer_loose_object = require("./rules/prefer-loose-object.cjs");
29
31
  const require_prefer_meta_last = require("./rules/prefer-meta-last.cjs");
@@ -32,6 +34,7 @@ const require_prefer_strict_object = require("./rules/prefer-strict-object.cjs")
32
34
  const require_prefer_string_schema_with_trim = require("./rules/prefer-string-schema-with-trim.cjs");
33
35
  const require_prefer_top_level_string_formats = require("./rules/prefer-top-level-string-formats.cjs");
34
36
  const require_prefer_trim_before_string_length_checks = require("./rules/prefer-trim-before-string-length-checks.cjs");
37
+ const require_prefer_tuple_over_array_length = require("./rules/prefer-tuple-over-array-length.cjs");
35
38
  const require_require_brand_type_parameter = require("./rules/require-brand-type-parameter.cjs");
36
39
  const require_require_error_message = require("./rules/require-error-message.cjs");
37
40
  const require_schema_error_property_style = require("./rules/schema-error-property-style.cjs");
@@ -50,6 +53,7 @@ const eslintPluginZod = {
50
53
  "consistent-schema-output-type-style": require_consistent_schema_output_type_style.consistentSchemaOutputTypeStyle,
51
54
  "no-any-schema": require_no_any_schema.noAnySchema,
52
55
  "no-coerce-boolean": require_no_coerce_boolean.noCoerceBoolean,
56
+ "no-conflicting-checks": require_no_conflicting_checks.noConflictingChecks,
53
57
  "no-duplicate-schema-methods": require_no_duplicate_schema_methods.noDuplicateSchemaMethods,
54
58
  "no-empty-custom-schema": require_no_empty_custom_schema.noEmptyCustomSchema,
55
59
  "no-native-enum": require_no_native_enum.noNativeEnum,
@@ -67,6 +71,7 @@ const eslintPluginZod = {
67
71
  "no-throw-in-refine": require_no_throw_in_refine.noThrowInRefine,
68
72
  "no-transform-in-record-key": require_no_transform_in_record_key.noTransformInRecordKey,
69
73
  "no-unknown-schema": require_no_unknown_schema.noUnknownSchema,
74
+ "no-unnecessary-readonly": require_no_unnecessary_readonly.noUnnecessaryReadonly,
70
75
  "prefer-enum-over-literal-union": require_prefer_enum_over_literal_union.preferEnumOverLiteralUnion,
71
76
  "prefer-loose-object": require_prefer_loose_object.preferLooseObject,
72
77
  "prefer-meta": require_prefer_meta.preferMeta,
@@ -75,6 +80,7 @@ const eslintPluginZod = {
75
80
  "prefer-top-level-string-formats": require_prefer_top_level_string_formats.preferTopLevelStringFormats,
76
81
  "prefer-string-schema-with-trim": require_prefer_string_schema_with_trim.preferStringSchemaWithTrim,
77
82
  "prefer-trim-before-string-length-checks": require_prefer_trim_before_string_length_checks.preferTrimBeforeStringLengthChecks,
83
+ "prefer-tuple-over-array-length": require_prefer_tuple_over_array_length.preferTupleOverArrayLength,
78
84
  "require-brand-type-parameter": require_require_brand_type_parameter.requireBrandTypeParameter,
79
85
  "require-error-message": require_require_error_message.requireErrorMessage,
80
86
  "schema-error-property-style": require_schema_error_property_style.schemaErrorPropertyStyle
package/dist/index.mjs CHANGED
@@ -7,6 +7,7 @@ import { consistentSchemaOutputTypeStyle } from "./rules/consistent-schema-outpu
7
7
  import { consistentSchemaVarName } from "./rules/consistent-schema-var-name.mjs";
8
8
  import { noAnySchema } from "./rules/no-any-schema.mjs";
9
9
  import { noCoerceBoolean } from "./rules/no-coerce-boolean.mjs";
10
+ import { noConflictingChecks } from "./rules/no-conflicting-checks.mjs";
10
11
  import { noDuplicateSchemaMethods } from "./rules/no-duplicate-schema-methods.mjs";
11
12
  import { noEmptyCustomSchema } from "./rules/no-empty-custom-schema.mjs";
12
13
  import { noNativeEnum } from "./rules/no-native-enum.mjs";
@@ -24,6 +25,7 @@ import { noStringSchemaWithUuid } from "./rules/no-string-schema-with-uuid.mjs";
24
25
  import { noThrowInRefine } from "./rules/no-throw-in-refine.mjs";
25
26
  import { noTransformInRecordKey } from "./rules/no-transform-in-record-key.mjs";
26
27
  import { noUnknownSchema } from "./rules/no-unknown-schema.mjs";
28
+ import { noUnnecessaryReadonly } from "./rules/no-unnecessary-readonly.mjs";
27
29
  import { preferEnumOverLiteralUnion } from "./rules/prefer-enum-over-literal-union.mjs";
28
30
  import { preferLooseObject } from "./rules/prefer-loose-object.mjs";
29
31
  import { preferMetaLast } from "./rules/prefer-meta-last.mjs";
@@ -32,6 +34,7 @@ import { preferStrictObject } from "./rules/prefer-strict-object.mjs";
32
34
  import { preferStringSchemaWithTrim } from "./rules/prefer-string-schema-with-trim.mjs";
33
35
  import { preferTopLevelStringFormats } from "./rules/prefer-top-level-string-formats.mjs";
34
36
  import { preferTrimBeforeStringLengthChecks } from "./rules/prefer-trim-before-string-length-checks.mjs";
37
+ import { preferTupleOverArrayLength } from "./rules/prefer-tuple-over-array-length.mjs";
35
38
  import { requireBrandTypeParameter } from "./rules/require-brand-type-parameter.mjs";
36
39
  import { requireErrorMessage } from "./rules/require-error-message.mjs";
37
40
  import { schemaErrorPropertyStyle } from "./rules/schema-error-property-style.mjs";
@@ -50,6 +53,7 @@ const eslintPluginZod = {
50
53
  "consistent-schema-output-type-style": consistentSchemaOutputTypeStyle,
51
54
  "no-any-schema": noAnySchema,
52
55
  "no-coerce-boolean": noCoerceBoolean,
56
+ "no-conflicting-checks": noConflictingChecks,
53
57
  "no-duplicate-schema-methods": noDuplicateSchemaMethods,
54
58
  "no-empty-custom-schema": noEmptyCustomSchema,
55
59
  "no-native-enum": noNativeEnum,
@@ -67,6 +71,7 @@ const eslintPluginZod = {
67
71
  "no-throw-in-refine": noThrowInRefine,
68
72
  "no-transform-in-record-key": noTransformInRecordKey,
69
73
  "no-unknown-schema": noUnknownSchema,
74
+ "no-unnecessary-readonly": noUnnecessaryReadonly,
70
75
  "prefer-enum-over-literal-union": preferEnumOverLiteralUnion,
71
76
  "prefer-loose-object": preferLooseObject,
72
77
  "prefer-meta": preferMeta,
@@ -75,6 +80,7 @@ const eslintPluginZod = {
75
80
  "prefer-top-level-string-formats": preferTopLevelStringFormats,
76
81
  "prefer-string-schema-with-trim": preferStringSchemaWithTrim,
77
82
  "prefer-trim-before-string-length-checks": preferTrimBeforeStringLengthChecks,
83
+ "prefer-tuple-over-array-length": preferTupleOverArrayLength,
78
84
  "require-brand-type-parameter": requireBrandTypeParameter,
79
85
  "require-error-message": requireErrorMessage,
80
86
  "schema-error-property-style": schemaErrorPropertyStyle
@@ -0,0 +1,44 @@
1
+ const require_create_plugin_rule = require("../utils/create-plugin-rule.cjs");
2
+ let _eslint_zod_utils = require("@eslint-zod/utils");
3
+ let _eslint_zod_utils_rule_builders_no_conflicting_checks = require("@eslint-zod/utils/rule-builders/no-conflicting-checks");
4
+ //#region src/rules/no-conflicting-checks.ts
5
+ const noConflictingChecks = require_create_plugin_rule.createZodPluginRule({
6
+ name: "no-conflicting-checks",
7
+ meta: {
8
+ type: "problem",
9
+ docs: { description: "Disallow check combinations that can never match, are redundant, or do not apply to the schema type" },
10
+ messages: {
11
+ impossibleCase: "This schema can never match: `{{first}}` conflicts with `{{second}}`.",
12
+ redundantCheck: "`{{redundant}}` is redundant: `{{by}}` already implies it.",
13
+ confusingCombination: "Combining `{{first}}` and `{{second}}` is almost certainly a mistake.",
14
+ pointlessCheck: "`{{check}}` is pointless here: {{reason}}.",
15
+ inapplicableCheck: "`{{check}}` does not apply to a `{{baseType}}` schema: it will silently no-op or reject every value."
16
+ },
17
+ schema: [{
18
+ type: "object",
19
+ properties: {
20
+ checkImpossibleCases: {
21
+ description: "Report provably unsatisfiable combinations — the schema can never match",
22
+ type: "boolean"
23
+ },
24
+ checkConfusingCases: {
25
+ description: "Report technically valid but almost certainly mistaken combinations",
26
+ type: "boolean"
27
+ },
28
+ checkInapplicableChecks: {
29
+ description: "Report checks that don't apply to the schema's base type",
30
+ type: "boolean"
31
+ }
32
+ },
33
+ additionalProperties: false
34
+ }]
35
+ },
36
+ defaultOptions: [{
37
+ checkImpossibleCases: true,
38
+ checkConfusingCases: true,
39
+ checkInapplicableChecks: true
40
+ }],
41
+ create: (0, _eslint_zod_utils_rule_builders_no_conflicting_checks.buildNoConflictingChecksCreate)(_eslint_zod_utils.zodImportScope)
42
+ });
43
+ //#endregion
44
+ exports.noConflictingChecks = noConflictingChecks;
@@ -0,0 +1,44 @@
1
+ import { createZodPluginRule } from "../utils/create-plugin-rule.mjs";
2
+ import { zodImportScope } from "@eslint-zod/utils";
3
+ import { buildNoConflictingChecksCreate } from "@eslint-zod/utils/rule-builders/no-conflicting-checks";
4
+ //#region src/rules/no-conflicting-checks.ts
5
+ const noConflictingChecks = createZodPluginRule({
6
+ name: "no-conflicting-checks",
7
+ meta: {
8
+ type: "problem",
9
+ docs: { description: "Disallow check combinations that can never match, are redundant, or do not apply to the schema type" },
10
+ messages: {
11
+ impossibleCase: "This schema can never match: `{{first}}` conflicts with `{{second}}`.",
12
+ redundantCheck: "`{{redundant}}` is redundant: `{{by}}` already implies it.",
13
+ confusingCombination: "Combining `{{first}}` and `{{second}}` is almost certainly a mistake.",
14
+ pointlessCheck: "`{{check}}` is pointless here: {{reason}}.",
15
+ inapplicableCheck: "`{{check}}` does not apply to a `{{baseType}}` schema: it will silently no-op or reject every value."
16
+ },
17
+ schema: [{
18
+ type: "object",
19
+ properties: {
20
+ checkImpossibleCases: {
21
+ description: "Report provably unsatisfiable combinations — the schema can never match",
22
+ type: "boolean"
23
+ },
24
+ checkConfusingCases: {
25
+ description: "Report technically valid but almost certainly mistaken combinations",
26
+ type: "boolean"
27
+ },
28
+ checkInapplicableChecks: {
29
+ description: "Report checks that don't apply to the schema's base type",
30
+ type: "boolean"
31
+ }
32
+ },
33
+ additionalProperties: false
34
+ }]
35
+ },
36
+ defaultOptions: [{
37
+ checkImpossibleCases: true,
38
+ checkConfusingCases: true,
39
+ checkInapplicableChecks: true
40
+ }],
41
+ create: buildNoConflictingChecksCreate(zodImportScope)
42
+ });
43
+ //#endregion
44
+ export { noConflictingChecks };
@@ -0,0 +1,18 @@
1
+ const require_create_plugin_rule = require("../utils/create-plugin-rule.cjs");
2
+ let _eslint_zod_utils = require("@eslint-zod/utils");
3
+ let _eslint_zod_utils_rule_builders_no_unnecessary_readonly = require("@eslint-zod/utils/rule-builders/no-unnecessary-readonly");
4
+ //#region src/rules/no-unnecessary-readonly.ts
5
+ const noUnnecessaryReadonly = require_create_plugin_rule.createZodPluginRule({
6
+ name: "no-unnecessary-readonly",
7
+ meta: {
8
+ type: "suggestion",
9
+ fixable: "code",
10
+ docs: { description: "Disallow `.readonly()` on schemas whose output is already immutable" },
11
+ messages: { unnecessaryReadonly: "`readonly` has no effect on an already-immutable schema; remove it." },
12
+ schema: []
13
+ },
14
+ defaultOptions: [],
15
+ create: (0, _eslint_zod_utils_rule_builders_no_unnecessary_readonly.buildNoUnnecessaryReadonlyCreate)(_eslint_zod_utils.zodImportScope)
16
+ });
17
+ //#endregion
18
+ exports.noUnnecessaryReadonly = noUnnecessaryReadonly;
@@ -0,0 +1,18 @@
1
+ import { createZodPluginRule } from "../utils/create-plugin-rule.mjs";
2
+ import { zodImportScope } from "@eslint-zod/utils";
3
+ import { buildNoUnnecessaryReadonlyCreate } from "@eslint-zod/utils/rule-builders/no-unnecessary-readonly";
4
+ //#region src/rules/no-unnecessary-readonly.ts
5
+ const noUnnecessaryReadonly = createZodPluginRule({
6
+ name: "no-unnecessary-readonly",
7
+ meta: {
8
+ type: "suggestion",
9
+ fixable: "code",
10
+ docs: { description: "Disallow `.readonly()` on schemas whose output is already immutable" },
11
+ messages: { unnecessaryReadonly: "`readonly` has no effect on an already-immutable schema; remove it." },
12
+ schema: []
13
+ },
14
+ defaultOptions: [],
15
+ create: buildNoUnnecessaryReadonlyCreate(zodImportScope)
16
+ });
17
+ //#endregion
18
+ export { noUnnecessaryReadonly };
@@ -0,0 +1,18 @@
1
+ const require_create_plugin_rule = require("../utils/create-plugin-rule.cjs");
2
+ let _eslint_zod_utils = require("@eslint-zod/utils");
3
+ let _eslint_zod_utils_rule_builders_prefer_tuple_over_array_length = require("@eslint-zod/utils/rule-builders/prefer-tuple-over-array-length");
4
+ //#region src/rules/prefer-tuple-over-array-length.ts
5
+ const preferTupleOverArrayLength = require_create_plugin_rule.createZodPluginRule({
6
+ name: "prefer-tuple-over-array-length",
7
+ meta: {
8
+ type: "suggestion",
9
+ fixable: "code",
10
+ docs: { description: "Prefer `z.tuple()` over a length-constrained `z.array()` so the length is preserved in the inferred type." },
11
+ messages: { preferTuple: "Prefer `z.tuple()` over a length-constrained `z.array()` so the length is preserved in the inferred type." },
12
+ schema: []
13
+ },
14
+ defaultOptions: [],
15
+ create: (0, _eslint_zod_utils_rule_builders_prefer_tuple_over_array_length.buildPreferTupleOverArrayLengthCreate)(_eslint_zod_utils.zodImportScope)
16
+ });
17
+ //#endregion
18
+ exports.preferTupleOverArrayLength = preferTupleOverArrayLength;
@@ -0,0 +1,18 @@
1
+ import { createZodPluginRule } from "../utils/create-plugin-rule.mjs";
2
+ import { zodImportScope } from "@eslint-zod/utils";
3
+ import { buildPreferTupleOverArrayLengthCreate } from "@eslint-zod/utils/rule-builders/prefer-tuple-over-array-length";
4
+ //#region src/rules/prefer-tuple-over-array-length.ts
5
+ const preferTupleOverArrayLength = createZodPluginRule({
6
+ name: "prefer-tuple-over-array-length",
7
+ meta: {
8
+ type: "suggestion",
9
+ fixable: "code",
10
+ docs: { description: "Prefer `z.tuple()` over a length-constrained `z.array()` so the length is preserved in the inferred type." },
11
+ messages: { preferTuple: "Prefer `z.tuple()` over a length-constrained `z.array()` so the length is preserved in the inferred type." },
12
+ schema: []
13
+ },
14
+ defaultOptions: [],
15
+ create: buildPreferTupleOverArrayLengthCreate(zodImportScope)
16
+ });
17
+ //#endregion
18
+ export { preferTupleOverArrayLength };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-zod",
3
- "version": "4.7.1",
3
+ "version": "4.8.0",
4
4
  "description": "ESLint plugin that adds custom linting rules to enforce best practices when using Zod",
5
5
  "keywords": [
6
6
  "eslint",
@@ -39,7 +39,7 @@
39
39
  },
40
40
  "dependencies": {
41
41
  "@typescript-eslint/utils": "^8.62.0",
42
- "@eslint-zod/utils": "2.3.0"
42
+ "@eslint-zod/utils": "2.4.0"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@marcalexiei/prettier-config": "2.0.0",