eslint-plugin-zod 4.10.0 → 4.12.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
@@ -63,6 +63,7 @@ Find out more about [Oxlint's `jsPLugins`](https://oxc.rs/docs/guide/usage/linte
63
63
  | [no-unnecessary-readonly](docs/rules/no-unnecessary-readonly.md) | Disallow `.readonly()` on schemas whose output is already immutable | | 🔧 | | |
64
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. | ✅ | 🔧 | | |
65
65
  | [prefer-loose-object](docs/rules/prefer-loose-object.md) | Prefer `z.looseObject()` over `z.object().passthrough()` and `z.object().loose()` | ✅ | 🔧 | | |
66
+ | [prefer-map-set-size-over-min-max](docs/rules/prefer-map-set-size-over-min-max.md) | Prefer `.size(n)` over `.min(n).max(n)` with the same value on a set or map schema | | 🔧 | | |
66
67
  | [prefer-meta](docs/rules/prefer-meta.md) | Enforce usage of `.meta()` over `.describe()` | ✅ | 🔧 | | |
67
68
  | [prefer-meta-last](docs/rules/prefer-meta-last.md) | Enforce `.meta()` as last method | ✅ | 🔧 | | |
68
69
  | [prefer-nullish](docs/rules/prefer-nullish.md) | Enforce `.nullish()` instead of combining `.optional()` and `.nullable()` | ✅ | 🔧 | | |
package/dist/index.cjs CHANGED
@@ -28,6 +28,7 @@ const require_no_unknown_schema = require("./rules/no-unknown-schema.cjs");
28
28
  const require_no_unnecessary_readonly = require("./rules/no-unnecessary-readonly.cjs");
29
29
  const require_prefer_enum_over_literal_union = require("./rules/prefer-enum-over-literal-union.cjs");
30
30
  const require_prefer_loose_object = require("./rules/prefer-loose-object.cjs");
31
+ const require_prefer_map_set_size_over_min_max = require("./rules/prefer-map-set-size-over-min-max.cjs");
31
32
  const require_prefer_meta_last = require("./rules/prefer-meta-last.cjs");
32
33
  const require_prefer_meta = require("./rules/prefer-meta.cjs");
33
34
  const require_prefer_nullish = require("./rules/prefer-nullish.cjs");
@@ -76,6 +77,7 @@ const eslintPluginZod = {
76
77
  "no-unnecessary-readonly": require_no_unnecessary_readonly.noUnnecessaryReadonly,
77
78
  "prefer-enum-over-literal-union": require_prefer_enum_over_literal_union.preferEnumOverLiteralUnion,
78
79
  "prefer-loose-object": require_prefer_loose_object.preferLooseObject,
80
+ "prefer-map-set-size-over-min-max": require_prefer_map_set_size_over_min_max.preferMapSetSizeOverMinMax,
79
81
  "prefer-meta": require_prefer_meta.preferMeta,
80
82
  "prefer-meta-last": require_prefer_meta_last.preferMetaLast,
81
83
  "prefer-nullish": require_prefer_nullish.preferNullish,
package/dist/index.mjs CHANGED
@@ -28,6 +28,7 @@ import { noUnknownSchema } from "./rules/no-unknown-schema.mjs";
28
28
  import { noUnnecessaryReadonly } from "./rules/no-unnecessary-readonly.mjs";
29
29
  import { preferEnumOverLiteralUnion } from "./rules/prefer-enum-over-literal-union.mjs";
30
30
  import { preferLooseObject } from "./rules/prefer-loose-object.mjs";
31
+ import { preferMapSetSizeOverMinMax } from "./rules/prefer-map-set-size-over-min-max.mjs";
31
32
  import { preferMetaLast } from "./rules/prefer-meta-last.mjs";
32
33
  import { preferMeta } from "./rules/prefer-meta.mjs";
33
34
  import { preferNullish } from "./rules/prefer-nullish.mjs";
@@ -76,6 +77,7 @@ const eslintPluginZod = {
76
77
  "no-unnecessary-readonly": noUnnecessaryReadonly,
77
78
  "prefer-enum-over-literal-union": preferEnumOverLiteralUnion,
78
79
  "prefer-loose-object": preferLooseObject,
80
+ "prefer-map-set-size-over-min-max": preferMapSetSizeOverMinMax,
79
81
  "prefer-meta": preferMeta,
80
82
  "prefer-meta-last": preferMetaLast,
81
83
  "prefer-nullish": preferNullish,
@@ -1,5 +1,6 @@
1
1
  const require_create_plugin_rule = require("../utils/create-plugin-rule.cjs");
2
2
  let _eslint_zod_utils = require("@eslint-zod/utils");
3
+ let _eslint_zod_utils_rule_patterns_prefer_top_level_factory = require("@eslint-zod/utils/rule-patterns/prefer-top-level-factory");
3
4
  //#region src/rules/no-number-schema-with-int.ts
4
5
  const noNumberSchemaWithInt = require_create_plugin_rule.createZodPluginRule({
5
6
  name: "no-number-schema-with-int",
@@ -11,34 +12,15 @@ const noNumberSchemaWithInt = require_create_plugin_rule.createZodPluginRule({
11
12
  schema: []
12
13
  },
13
14
  defaultOptions: [],
14
- create(context) {
15
- const { sourceCode } = context;
16
- const { createSchemaVisitor, collectZodChainMethods } = _eslint_zod_utils.zodImportScope.createTracker();
17
- return createSchemaVisitor({
18
- schemaType: "number",
19
- onSchema(node, zodSchemaMeta) {
20
- const methods = collectZodChainMethods(node);
21
- const intIndex = methods.findIndex((m) => m.name === "int");
22
- if (intIndex === -1) return;
23
- const numberIndex = methods.findIndex((m) => m.name === "number");
24
- context.report({
25
- node,
26
- messageId: "removeNumber",
27
- fix(fixer) {
28
- if (zodSchemaMeta.schemaDecl === "named") return null;
29
- return (0, _eslint_zod_utils.buildZodChainReplacementFix)({
30
- sourceCode,
31
- fixer,
32
- methods,
33
- fromIndex: numberIndex,
34
- toIndex: intIndex,
35
- toMethodName: "int"
36
- });
37
- }
38
- });
39
- }
40
- });
41
- }
15
+ create: (0, _eslint_zod_utils_rule_patterns_prefer_top_level_factory.buildPreferTopLevelFactoryCreate)({
16
+ scope: _eslint_zod_utils.zodImportScope,
17
+ factoryName: "number",
18
+ replacements: [{
19
+ sourceMethodName: "int",
20
+ replacementMethodName: "int"
21
+ }],
22
+ messageId: "removeNumber"
23
+ })
42
24
  });
43
25
  //#endregion
44
26
  exports.noNumberSchemaWithInt = noNumberSchemaWithInt;
@@ -1,5 +1,6 @@
1
1
  import { createZodPluginRule } from "../utils/create-plugin-rule.mjs";
2
- import { buildZodChainReplacementFix, zodImportScope } from "@eslint-zod/utils";
2
+ import { zodImportScope } from "@eslint-zod/utils";
3
+ import { buildPreferTopLevelFactoryCreate } from "@eslint-zod/utils/rule-patterns/prefer-top-level-factory";
3
4
  //#region src/rules/no-number-schema-with-int.ts
4
5
  const noNumberSchemaWithInt = createZodPluginRule({
5
6
  name: "no-number-schema-with-int",
@@ -11,34 +12,15 @@ const noNumberSchemaWithInt = createZodPluginRule({
11
12
  schema: []
12
13
  },
13
14
  defaultOptions: [],
14
- create(context) {
15
- const { sourceCode } = context;
16
- const { createSchemaVisitor, collectZodChainMethods } = zodImportScope.createTracker();
17
- return createSchemaVisitor({
18
- schemaType: "number",
19
- onSchema(node, zodSchemaMeta) {
20
- const methods = collectZodChainMethods(node);
21
- const intIndex = methods.findIndex((m) => m.name === "int");
22
- if (intIndex === -1) return;
23
- const numberIndex = methods.findIndex((m) => m.name === "number");
24
- context.report({
25
- node,
26
- messageId: "removeNumber",
27
- fix(fixer) {
28
- if (zodSchemaMeta.schemaDecl === "named") return null;
29
- return buildZodChainReplacementFix({
30
- sourceCode,
31
- fixer,
32
- methods,
33
- fromIndex: numberIndex,
34
- toIndex: intIndex,
35
- toMethodName: "int"
36
- });
37
- }
38
- });
39
- }
40
- });
41
- }
15
+ create: buildPreferTopLevelFactoryCreate({
16
+ scope: zodImportScope,
17
+ factoryName: "number",
18
+ replacements: [{
19
+ sourceMethodName: "int",
20
+ replacementMethodName: "int"
21
+ }],
22
+ messageId: "removeNumber"
23
+ })
42
24
  });
43
25
  //#endregion
44
26
  export { noNumberSchemaWithInt };
@@ -1,5 +1,6 @@
1
1
  const require_create_plugin_rule = require("../utils/create-plugin-rule.cjs");
2
2
  let _eslint_zod_utils = require("@eslint-zod/utils");
3
+ let _eslint_zod_utils_rule_patterns_prefer_top_level_factory = require("@eslint-zod/utils/rule-patterns/prefer-top-level-factory");
3
4
  //#region src/rules/no-number-schema-with-safe.ts
4
5
  const noNumberSchemaWithSafe = require_create_plugin_rule.createZodPluginRule({
5
6
  name: "no-number-schema-with-safe",
@@ -11,33 +12,15 @@ const noNumberSchemaWithSafe = require_create_plugin_rule.createZodPluginRule({
11
12
  schema: []
12
13
  },
13
14
  defaultOptions: [],
14
- create(context) {
15
- const { sourceCode } = context;
16
- const { createSchemaVisitor, collectZodChainMethods } = _eslint_zod_utils.zodImportScope.createTracker();
17
- return createSchemaVisitor({
18
- schemaType: "number",
19
- onSchema(node, zodSchemaMeta) {
20
- if (!(0, _eslint_zod_utils.getZodChainedMethodNames)(zodSchemaMeta).includes("safe")) return;
21
- const methods = collectZodChainMethods(node);
22
- const safeIndex = methods.findIndex((m, index) => index > 0 && m.name === "safe");
23
- context.report({
24
- node,
25
- messageId: "useInt",
26
- fix(fixer) {
27
- if (zodSchemaMeta.schemaDecl === "named" || safeIndex === -1) return null;
28
- return (0, _eslint_zod_utils.buildZodChainReplacementFix)({
29
- sourceCode,
30
- fixer,
31
- methods,
32
- fromIndex: 0,
33
- toIndex: safeIndex,
34
- toMethodName: "int"
35
- });
36
- }
37
- });
38
- }
39
- });
40
- }
15
+ create: (0, _eslint_zod_utils_rule_patterns_prefer_top_level_factory.buildPreferTopLevelFactoryCreate)({
16
+ scope: _eslint_zod_utils.zodImportScope,
17
+ factoryName: "number",
18
+ replacements: [{
19
+ sourceMethodName: "safe",
20
+ replacementMethodName: "int"
21
+ }],
22
+ messageId: "useInt"
23
+ })
41
24
  });
42
25
  //#endregion
43
26
  exports.noNumberSchemaWithSafe = noNumberSchemaWithSafe;
@@ -1,5 +1,6 @@
1
1
  import { createZodPluginRule } from "../utils/create-plugin-rule.mjs";
2
- import { buildZodChainReplacementFix, getZodChainedMethodNames, zodImportScope } from "@eslint-zod/utils";
2
+ import { zodImportScope } from "@eslint-zod/utils";
3
+ import { buildPreferTopLevelFactoryCreate } from "@eslint-zod/utils/rule-patterns/prefer-top-level-factory";
3
4
  //#region src/rules/no-number-schema-with-safe.ts
4
5
  const noNumberSchemaWithSafe = createZodPluginRule({
5
6
  name: "no-number-schema-with-safe",
@@ -11,33 +12,15 @@ const noNumberSchemaWithSafe = createZodPluginRule({
11
12
  schema: []
12
13
  },
13
14
  defaultOptions: [],
14
- create(context) {
15
- const { sourceCode } = context;
16
- const { createSchemaVisitor, collectZodChainMethods } = zodImportScope.createTracker();
17
- return createSchemaVisitor({
18
- schemaType: "number",
19
- onSchema(node, zodSchemaMeta) {
20
- if (!getZodChainedMethodNames(zodSchemaMeta).includes("safe")) return;
21
- const methods = collectZodChainMethods(node);
22
- const safeIndex = methods.findIndex((m, index) => index > 0 && m.name === "safe");
23
- context.report({
24
- node,
25
- messageId: "useInt",
26
- fix(fixer) {
27
- if (zodSchemaMeta.schemaDecl === "named" || safeIndex === -1) return null;
28
- return buildZodChainReplacementFix({
29
- sourceCode,
30
- fixer,
31
- methods,
32
- fromIndex: 0,
33
- toIndex: safeIndex,
34
- toMethodName: "int"
35
- });
36
- }
37
- });
38
- }
39
- });
40
- }
15
+ create: buildPreferTopLevelFactoryCreate({
16
+ scope: zodImportScope,
17
+ factoryName: "number",
18
+ replacements: [{
19
+ sourceMethodName: "safe",
20
+ replacementMethodName: "int"
21
+ }],
22
+ messageId: "useInt"
23
+ })
41
24
  });
42
25
  //#endregion
43
26
  export { noNumberSchemaWithSafe };
@@ -1,5 +1,6 @@
1
1
  const require_create_plugin_rule = require("../utils/create-plugin-rule.cjs");
2
2
  let _eslint_zod_utils = require("@eslint-zod/utils");
3
+ let _eslint_zod_utils_rule_patterns_prefer_top_level_factory = require("@eslint-zod/utils/rule-patterns/prefer-top-level-factory");
3
4
  //#region src/rules/no-string-schema-with-uuid.ts
4
5
  const noStringSchemaWithUuid = require_create_plugin_rule.createZodPluginRule({
5
6
  name: "no-string-schema-with-uuid",
@@ -15,34 +16,15 @@ const noStringSchemaWithUuid = require_create_plugin_rule.createZodPluginRule({
15
16
  schema: []
16
17
  },
17
18
  defaultOptions: [],
18
- create(context) {
19
- const { sourceCode } = context;
20
- const { createSchemaVisitor, collectZodChainMethods } = _eslint_zod_utils.zodImportScope.createTracker();
21
- return createSchemaVisitor({
22
- schemaType: "string",
23
- onSchema(node, zodSchemaMeta) {
24
- const methods = collectZodChainMethods(node);
25
- const uuidIndex = methods.findIndex((m) => m.name === "uuid");
26
- if (uuidIndex === -1) return;
27
- const stringIndex = methods.findIndex((m) => m.name === "string");
28
- context.report({
29
- node,
30
- messageId: "useUuid",
31
- fix(fixer) {
32
- if (zodSchemaMeta.schemaDecl === "named") return null;
33
- return (0, _eslint_zod_utils.buildZodChainReplacementFix)({
34
- sourceCode,
35
- fixer,
36
- methods,
37
- fromIndex: stringIndex,
38
- toIndex: uuidIndex,
39
- toMethodName: "uuid"
40
- });
41
- }
42
- });
43
- }
44
- });
45
- }
19
+ create: (0, _eslint_zod_utils_rule_patterns_prefer_top_level_factory.buildPreferTopLevelFactoryCreate)({
20
+ scope: _eslint_zod_utils.zodImportScope,
21
+ factoryName: "string",
22
+ replacements: [{
23
+ sourceMethodName: "uuid",
24
+ replacementMethodName: "uuid"
25
+ }],
26
+ messageId: "useUuid"
27
+ })
46
28
  });
47
29
  //#endregion
48
30
  exports.noStringSchemaWithUuid = noStringSchemaWithUuid;
@@ -1,5 +1,6 @@
1
1
  import { createZodPluginRule } from "../utils/create-plugin-rule.mjs";
2
- import { buildZodChainReplacementFix, zodImportScope } from "@eslint-zod/utils";
2
+ import { zodImportScope } from "@eslint-zod/utils";
3
+ import { buildPreferTopLevelFactoryCreate } from "@eslint-zod/utils/rule-patterns/prefer-top-level-factory";
3
4
  //#region src/rules/no-string-schema-with-uuid.ts
4
5
  const noStringSchemaWithUuid = createZodPluginRule({
5
6
  name: "no-string-schema-with-uuid",
@@ -15,34 +16,15 @@ const noStringSchemaWithUuid = createZodPluginRule({
15
16
  schema: []
16
17
  },
17
18
  defaultOptions: [],
18
- create(context) {
19
- const { sourceCode } = context;
20
- const { createSchemaVisitor, collectZodChainMethods } = zodImportScope.createTracker();
21
- return createSchemaVisitor({
22
- schemaType: "string",
23
- onSchema(node, zodSchemaMeta) {
24
- const methods = collectZodChainMethods(node);
25
- const uuidIndex = methods.findIndex((m) => m.name === "uuid");
26
- if (uuidIndex === -1) return;
27
- const stringIndex = methods.findIndex((m) => m.name === "string");
28
- context.report({
29
- node,
30
- messageId: "useUuid",
31
- fix(fixer) {
32
- if (zodSchemaMeta.schemaDecl === "named") return null;
33
- return buildZodChainReplacementFix({
34
- sourceCode,
35
- fixer,
36
- methods,
37
- fromIndex: stringIndex,
38
- toIndex: uuidIndex,
39
- toMethodName: "uuid"
40
- });
41
- }
42
- });
43
- }
44
- });
45
- }
19
+ create: buildPreferTopLevelFactoryCreate({
20
+ scope: zodImportScope,
21
+ factoryName: "string",
22
+ replacements: [{
23
+ sourceMethodName: "uuid",
24
+ replacementMethodName: "uuid"
25
+ }],
26
+ messageId: "useUuid"
27
+ })
46
28
  });
47
29
  //#endregion
48
30
  export { noStringSchemaWithUuid };
@@ -0,0 +1,23 @@
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_patterns_collapse_equal_bounds = require("@eslint-zod/utils/rule-patterns/collapse-equal-bounds");
4
+ //#region src/rules/prefer-map-set-size-over-min-max.ts
5
+ const preferMapSetSizeOverMinMax = require_create_plugin_rule.createZodPluginRule({
6
+ name: "prefer-map-set-size-over-min-max",
7
+ meta: {
8
+ type: "suggestion",
9
+ fixable: "code",
10
+ docs: { description: "Prefer `.size(n)` over `.min(n).max(n)` with the same value on a set or map schema" },
11
+ messages: { preferMapSetSize: "Use `.size(n)` instead of `.min(n)` and `.max(n)` with the same value." },
12
+ schema: []
13
+ },
14
+ defaultOptions: [],
15
+ create: (0, _eslint_zod_utils_rule_patterns_collapse_equal_bounds.buildCollapseEqualBoundsCreate)({
16
+ scope: _eslint_zod_utils.zodImportScope,
17
+ baseTypes: ["set", "map"],
18
+ domain: "size",
19
+ messageId: "preferMapSetSize"
20
+ })
21
+ });
22
+ //#endregion
23
+ exports.preferMapSetSizeOverMinMax = preferMapSetSizeOverMinMax;
@@ -0,0 +1,23 @@
1
+ import { createZodPluginRule } from "../utils/create-plugin-rule.mjs";
2
+ import { zodImportScope } from "@eslint-zod/utils";
3
+ import { buildCollapseEqualBoundsCreate } from "@eslint-zod/utils/rule-patterns/collapse-equal-bounds";
4
+ //#region src/rules/prefer-map-set-size-over-min-max.ts
5
+ const preferMapSetSizeOverMinMax = createZodPluginRule({
6
+ name: "prefer-map-set-size-over-min-max",
7
+ meta: {
8
+ type: "suggestion",
9
+ fixable: "code",
10
+ docs: { description: "Prefer `.size(n)` over `.min(n).max(n)` with the same value on a set or map schema" },
11
+ messages: { preferMapSetSize: "Use `.size(n)` instead of `.min(n)` and `.max(n)` with the same value." },
12
+ schema: []
13
+ },
14
+ defaultOptions: [],
15
+ create: buildCollapseEqualBoundsCreate({
16
+ scope: zodImportScope,
17
+ baseTypes: ["set", "map"],
18
+ domain: "size",
19
+ messageId: "preferMapSetSize"
20
+ })
21
+ });
22
+ //#endregion
23
+ export { preferMapSetSizeOverMinMax };
@@ -1,12 +1,9 @@
1
1
  const require_create_plugin_rule = require("../utils/create-plugin-rule.cjs");
2
2
  let _eslint_zod_utils = require("@eslint-zod/utils");
3
+ let _eslint_zod_utils_rule_patterns_prefer_top_level_factory = require("@eslint-zod/utils/rule-patterns/prefer-top-level-factory");
3
4
  //#region src/rules/prefer-top-level-string-formats.ts
4
5
  const TOP_LEVEL_STRING_FORMATS_URL = "https://zod.dev/v4?id=top-level-string-formats";
5
6
  const ZOD_STRING_FORMAT_METHOD_NAMES = _eslint_zod_utils.ZOD_STRING_FORMAT_METHODS.map(({ sourceMethodName }) => sourceMethodName);
6
- const ZOD_STRING_FORMAT_METHODS_BY_SOURCE = Object.fromEntries(_eslint_zod_utils.ZOD_STRING_FORMAT_METHODS.map((format) => [format.sourceMethodName, format]));
7
- function isZodStringFormatMethodName(value) {
8
- return ZOD_STRING_FORMAT_METHOD_NAMES.includes(value);
9
- }
10
7
  const preferTopLevelStringFormats = require_create_plugin_rule.createZodPluginRule({
11
8
  name: "prefer-top-level-string-formats",
12
9
  meta: {
@@ -33,39 +30,13 @@ const preferTopLevelStringFormats = require_create_plugin_rule.createZodPluginRu
33
30
  },
34
31
  defaultOptions: [{}],
35
32
  create(context, [{ ignore = [] }]) {
36
- const { sourceCode } = context;
37
- const ignoredMethods = new Set(ignore);
38
- const { createSchemaVisitor, collectZodChainMethods } = _eslint_zod_utils.zodImportScope.createTracker();
39
- return createSchemaVisitor({
40
- schemaType: "string",
41
- onSchema(node, zodSchemaMeta) {
42
- const methods = collectZodChainMethods(node);
43
- const stringIndex = methods.findIndex((method) => method.name === "string");
44
- if (stringIndex === -1) return;
45
- const formatMethod = methods.find((method, index) => index > stringIndex && isZodStringFormatMethodName(method.name) && !ignoredMethods.has(method.name));
46
- if (!formatMethod) return;
47
- const { replacementMethodName, sourceMethodName } = ZOD_STRING_FORMAT_METHODS_BY_SOURCE[formatMethod.name];
48
- context.report({
49
- node,
50
- messageId: "preferTopLevelStringFormat",
51
- data: {
52
- replacementMethod: replacementMethodName,
53
- sourceMethod: sourceMethodName
54
- },
55
- fix(fixer) {
56
- if (zodSchemaMeta.schemaDecl === "named") return null;
57
- return (0, _eslint_zod_utils.buildZodChainReplacementFix)({
58
- sourceCode,
59
- fixer,
60
- methods,
61
- fromIndex: stringIndex,
62
- toIndex: methods.indexOf(formatMethod),
63
- toMethodName: replacementMethodName
64
- });
65
- }
66
- });
67
- }
68
- });
33
+ return (0, _eslint_zod_utils_rule_patterns_prefer_top_level_factory.buildPreferTopLevelFactoryCreate)({
34
+ scope: _eslint_zod_utils.zodImportScope,
35
+ factoryName: "string",
36
+ replacements: _eslint_zod_utils.ZOD_STRING_FORMAT_METHODS,
37
+ messageId: "preferTopLevelStringFormat",
38
+ ignore
39
+ })(context);
69
40
  }
70
41
  });
71
42
  //#endregion
@@ -1,12 +1,9 @@
1
1
  import { createZodPluginRule } from "../utils/create-plugin-rule.mjs";
2
- import { ZOD_STRING_FORMAT_METHODS, buildZodChainReplacementFix, zodImportScope } from "@eslint-zod/utils";
2
+ import { ZOD_STRING_FORMAT_METHODS, zodImportScope } from "@eslint-zod/utils";
3
+ import { buildPreferTopLevelFactoryCreate } from "@eslint-zod/utils/rule-patterns/prefer-top-level-factory";
3
4
  //#region src/rules/prefer-top-level-string-formats.ts
4
5
  const TOP_LEVEL_STRING_FORMATS_URL = "https://zod.dev/v4?id=top-level-string-formats";
5
6
  const ZOD_STRING_FORMAT_METHOD_NAMES = ZOD_STRING_FORMAT_METHODS.map(({ sourceMethodName }) => sourceMethodName);
6
- const ZOD_STRING_FORMAT_METHODS_BY_SOURCE = Object.fromEntries(ZOD_STRING_FORMAT_METHODS.map((format) => [format.sourceMethodName, format]));
7
- function isZodStringFormatMethodName(value) {
8
- return ZOD_STRING_FORMAT_METHOD_NAMES.includes(value);
9
- }
10
7
  const preferTopLevelStringFormats = createZodPluginRule({
11
8
  name: "prefer-top-level-string-formats",
12
9
  meta: {
@@ -33,39 +30,13 @@ const preferTopLevelStringFormats = createZodPluginRule({
33
30
  },
34
31
  defaultOptions: [{}],
35
32
  create(context, [{ ignore = [] }]) {
36
- const { sourceCode } = context;
37
- const ignoredMethods = new Set(ignore);
38
- const { createSchemaVisitor, collectZodChainMethods } = zodImportScope.createTracker();
39
- return createSchemaVisitor({
40
- schemaType: "string",
41
- onSchema(node, zodSchemaMeta) {
42
- const methods = collectZodChainMethods(node);
43
- const stringIndex = methods.findIndex((method) => method.name === "string");
44
- if (stringIndex === -1) return;
45
- const formatMethod = methods.find((method, index) => index > stringIndex && isZodStringFormatMethodName(method.name) && !ignoredMethods.has(method.name));
46
- if (!formatMethod) return;
47
- const { replacementMethodName, sourceMethodName } = ZOD_STRING_FORMAT_METHODS_BY_SOURCE[formatMethod.name];
48
- context.report({
49
- node,
50
- messageId: "preferTopLevelStringFormat",
51
- data: {
52
- replacementMethod: replacementMethodName,
53
- sourceMethod: sourceMethodName
54
- },
55
- fix(fixer) {
56
- if (zodSchemaMeta.schemaDecl === "named") return null;
57
- return buildZodChainReplacementFix({
58
- sourceCode,
59
- fixer,
60
- methods,
61
- fromIndex: stringIndex,
62
- toIndex: methods.indexOf(formatMethod),
63
- toMethodName: replacementMethodName
64
- });
65
- }
66
- });
67
- }
68
- });
33
+ return buildPreferTopLevelFactoryCreate({
34
+ scope: zodImportScope,
35
+ factoryName: "string",
36
+ replacements: ZOD_STRING_FORMAT_METHODS,
37
+ messageId: "preferTopLevelStringFormat",
38
+ ignore
39
+ })(context);
69
40
  }
70
41
  });
71
42
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-zod",
3
- "version": "4.10.0",
3
+ "version": "4.12.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.67.0",
42
- "@eslint-zod/utils": "3.1.0"
42
+ "@eslint-zod/utils": "3.3.0"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@typescript-eslint/rule-tester": "8.67.0",