eslint-plugin-zod-mini 0.1.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.
Files changed (109) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +149 -0
  3. package/dist/_virtual/_rolldown/runtime.cjs +23 -0
  4. package/dist/index.cjs +62 -0
  5. package/dist/index.d.cts +22 -0
  6. package/dist/index.d.mts +23 -0
  7. package/dist/index.mjs +62 -0
  8. package/dist/meta.cjs +12 -0
  9. package/dist/meta.mjs +9 -0
  10. package/dist/rules/consistent-import-source.cjs +61 -0
  11. package/dist/rules/consistent-import-source.mjs +60 -0
  12. package/dist/rules/consistent-import.cjs +153 -0
  13. package/dist/rules/consistent-import.mjs +152 -0
  14. package/dist/rules/consistent-object-schema-type.cjs +82 -0
  15. package/dist/rules/consistent-object-schema-type.mjs +81 -0
  16. package/dist/rules/consistent-schema-output-type-style.cjs +70 -0
  17. package/dist/rules/consistent-schema-output-type-style.mjs +69 -0
  18. package/dist/rules/consistent-schema-var-name.cjs +76 -0
  19. package/dist/rules/consistent-schema-var-name.mjs +75 -0
  20. package/dist/rules/no-any-schema.cjs +63 -0
  21. package/dist/rules/no-any-schema.mjs +62 -0
  22. package/dist/rules/no-empty-custom-schema.cjs +36 -0
  23. package/dist/rules/no-empty-custom-schema.mjs +36 -0
  24. package/dist/rules/no-unknown-schema.cjs +31 -0
  25. package/dist/rules/no-unknown-schema.mjs +31 -0
  26. package/dist/rules/prefer-meta.cjs +46 -0
  27. package/dist/rules/prefer-meta.mjs +45 -0
  28. package/dist/rules/prefer-namespace-import.cjs +117 -0
  29. package/dist/rules/prefer-namespace-import.mjs +116 -0
  30. package/dist/rules/require-brand-type-parameter.cjs +49 -0
  31. package/dist/rules/require-brand-type-parameter.mjs +49 -0
  32. package/dist/rules/require-error-message.cjs +85 -0
  33. package/dist/rules/require-error-message.mjs +84 -0
  34. package/dist/rules/require-schema-suffix.cjs +69 -0
  35. package/dist/rules/require-schema-suffix.mjs +68 -0
  36. package/dist/rules/schema-error-property-style.cjs +96 -0
  37. package/dist/rules/schema-error-property-style.mjs +94 -0
  38. package/dist/src/index.d.ts +21 -0
  39. package/dist/src/index.js +56 -0
  40. package/dist/src/meta.d.ts +3 -0
  41. package/dist/src/meta.js +8 -0
  42. package/dist/src/rules/consistent-import-source.d.ts +11 -0
  43. package/dist/src/rules/consistent-import-source.js +64 -0
  44. package/dist/src/rules/consistent-import-source.spec.d.ts +1 -0
  45. package/dist/src/rules/consistent-import-source.spec.js +103 -0
  46. package/dist/src/rules/consistent-import.d.ts +12 -0
  47. package/dist/src/rules/consistent-import.js +176 -0
  48. package/dist/src/rules/consistent-import.spec.d.ts +1 -0
  49. package/dist/src/rules/consistent-import.spec.js +194 -0
  50. package/dist/src/rules/consistent-object-schema-type.d.ts +13 -0
  51. package/dist/src/rules/consistent-object-schema-type.js +82 -0
  52. package/dist/src/rules/consistent-object-schema-type.spec.d.ts +1 -0
  53. package/dist/src/rules/consistent-object-schema-type.spec.js +138 -0
  54. package/dist/src/rules/consistent-schema-output-type-style.d.ts +12 -0
  55. package/dist/src/rules/consistent-schema-output-type-style.js +81 -0
  56. package/dist/src/rules/consistent-schema-output-type-style.spec.d.ts +1 -0
  57. package/dist/src/rules/consistent-schema-output-type-style.spec.js +128 -0
  58. package/dist/src/rules/consistent-schema-var-name.d.ts +10 -0
  59. package/dist/src/rules/consistent-schema-var-name.js +86 -0
  60. package/dist/src/rules/consistent-schema-var-name.spec.d.ts +1 -0
  61. package/dist/src/rules/consistent-schema-var-name.spec.js +130 -0
  62. package/dist/src/rules/no-any-schema.d.ts +6 -0
  63. package/dist/src/rules/no-any-schema.js +65 -0
  64. package/dist/src/rules/no-any-schema.spec.d.ts +1 -0
  65. package/dist/src/rules/no-any-schema.spec.js +155 -0
  66. package/dist/src/rules/no-empty-custom-schema.d.ts +5 -0
  67. package/dist/src/rules/no-empty-custom-schema.js +43 -0
  68. package/dist/src/rules/no-empty-custom-schema.spec.d.ts +1 -0
  69. package/dist/src/rules/no-empty-custom-schema.spec.js +97 -0
  70. package/dist/src/rules/no-unknown-schema.d.ts +5 -0
  71. package/dist/src/rules/no-unknown-schema.js +33 -0
  72. package/dist/src/rules/no-unknown-schema.spec.d.ts +1 -0
  73. package/dist/src/rules/no-unknown-schema.spec.js +75 -0
  74. package/dist/src/rules/prefer-meta.d.ts +5 -0
  75. package/dist/src/rules/prefer-meta.js +51 -0
  76. package/dist/src/rules/prefer-meta.spec.d.ts +1 -0
  77. package/dist/src/rules/prefer-meta.spec.js +118 -0
  78. package/dist/src/rules/prefer-namespace-import.d.ts +5 -0
  79. package/dist/src/rules/prefer-namespace-import.js +146 -0
  80. package/dist/src/rules/prefer-namespace-import.spec.d.ts +1 -0
  81. package/dist/src/rules/prefer-namespace-import.spec.js +100 -0
  82. package/dist/src/rules/require-brand-type-parameter.d.ts +6 -0
  83. package/dist/src/rules/require-brand-type-parameter.js +58 -0
  84. package/dist/src/rules/require-brand-type-parameter.spec.d.ts +1 -0
  85. package/dist/src/rules/require-brand-type-parameter.spec.js +157 -0
  86. package/dist/src/rules/require-error-message.d.ts +5 -0
  87. package/dist/src/rules/require-error-message.js +103 -0
  88. package/dist/src/rules/require-error-message.spec.d.ts +1 -0
  89. package/dist/src/rules/require-error-message.spec.js +161 -0
  90. package/dist/src/rules/require-schema-suffix.d.ts +9 -0
  91. package/dist/src/rules/require-schema-suffix.js +79 -0
  92. package/dist/src/rules/require-schema-suffix.spec.d.ts +1 -0
  93. package/dist/src/rules/require-schema-suffix.spec.js +131 -0
  94. package/dist/src/rules/schema-error-property-style.d.ts +10 -0
  95. package/dist/src/rules/schema-error-property-style.js +102 -0
  96. package/dist/src/rules/schema-error-property-style.spec.d.ts +1 -0
  97. package/dist/src/rules/schema-error-property-style.spec.js +134 -0
  98. package/dist/src/utils/create-plugin-rule.d.ts +8 -0
  99. package/dist/src/utils/create-plugin-rule.js +3 -0
  100. package/dist/tests/setup.d.ts +1 -0
  101. package/dist/tests/setup.js +12 -0
  102. package/dist/tsconfig.tsbuildinfo +1 -0
  103. package/dist/tsdown.config.d.ts +2 -0
  104. package/dist/tsdown.config.js +11 -0
  105. package/dist/utils/create-plugin-rule.cjs +6 -0
  106. package/dist/utils/create-plugin-rule.mjs +6 -0
  107. package/dist/vitest.config.d.ts +2 -0
  108. package/dist/vitest.config.js +7 -0
  109. package/package.json +80 -0
@@ -0,0 +1,85 @@
1
+ require("../_virtual/_rolldown/runtime.cjs");
2
+ const require_create_plugin_rule = require("../utils/create-plugin-rule.cjs");
3
+ let _eslint_zod_utils = require("@eslint-zod/utils");
4
+ let _typescript_eslint_utils = require("@typescript-eslint/utils");
5
+ //#region src/rules/require-error-message.ts
6
+ const { zodImportAllowedSource, trackZodSchemaImports } = (0, _eslint_zod_utils.createZodSchemaImportTrack)("zod-mini");
7
+ const requireErrorMessage = require_create_plugin_rule.createZodMiniPluginRule({
8
+ name: "require-error-message",
9
+ meta: {
10
+ type: "suggestion",
11
+ fixable: "code",
12
+ docs: {
13
+ zodImportAllowedSource,
14
+ description: "Enforce that custom refinements include an error message"
15
+ },
16
+ messages: {
17
+ requireErrorMessage: "Custom refinements must include an error message",
18
+ preferError: "Use the \"error\" property instead of the deprecated \"message\" property",
19
+ removeMessage: "The \"message\" property is deprecated; use \"error\""
20
+ },
21
+ schema: []
22
+ },
23
+ defaultOptions: [],
24
+ create(context) {
25
+ const { importDeclarationListener, detectZodSchemaRootNode, collectZodChainMethods } = trackZodSchemaImports();
26
+ return {
27
+ ImportDeclaration: importDeclarationListener,
28
+ CallExpression(node) {
29
+ if (!detectZodSchemaRootNode(node)) return;
30
+ const refines = collectZodChainMethods(node).filter((it) => it.name === "refine" || it.name === "custom");
31
+ if (refines.length === 0) return;
32
+ for (const refine of refines) {
33
+ const refineNode = refine.node;
34
+ if (refineNode.arguments.length < 2) {
35
+ context.report({
36
+ messageId: "requireErrorMessage",
37
+ node: refineNode
38
+ });
39
+ continue;
40
+ }
41
+ const [, params] = refineNode.arguments;
42
+ if (params.type === _typescript_eslint_utils.AST_NODE_TYPES.Literal) continue;
43
+ if (params.type !== _typescript_eslint_utils.AST_NODE_TYPES.ObjectExpression) continue;
44
+ let errorPropertyNode;
45
+ let messagePropertyNode;
46
+ for (const property of params.properties) if (property.type === _typescript_eslint_utils.AST_NODE_TYPES.Property && property.key.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier) {
47
+ if (property.key.name === "error") errorPropertyNode = property;
48
+ if (property.key.name === "message") messagePropertyNode = property;
49
+ if (errorPropertyNode && messagePropertyNode) break;
50
+ }
51
+ if (errorPropertyNode && messagePropertyNode) {
52
+ context.report({
53
+ messageId: "removeMessage",
54
+ node: messagePropertyNode,
55
+ fix(fixer) {
56
+ const { sourceCode } = context;
57
+ const nextToken = sourceCode.getTokenAfter(messagePropertyNode);
58
+ let [, end] = messagePropertyNode.range;
59
+ if (nextToken?.value === ",") end = nextToken.range[1];
60
+ return fixer.removeRange([messagePropertyNode.range[0], end]);
61
+ }
62
+ });
63
+ continue;
64
+ }
65
+ if (messagePropertyNode && !errorPropertyNode) {
66
+ context.report({
67
+ messageId: "preferError",
68
+ node: params,
69
+ fix(fixer) {
70
+ return fixer.replaceTextRange(messagePropertyNode.key.range, "error");
71
+ }
72
+ });
73
+ continue;
74
+ }
75
+ if (!errorPropertyNode) context.report({
76
+ messageId: "requireErrorMessage",
77
+ node: params
78
+ });
79
+ }
80
+ }
81
+ };
82
+ }
83
+ });
84
+ //#endregion
85
+ exports.requireErrorMessage = requireErrorMessage;
@@ -0,0 +1,84 @@
1
+ import { createZodMiniPluginRule } from "../utils/create-plugin-rule.mjs";
2
+ import { createZodSchemaImportTrack } from "@eslint-zod/utils";
3
+ import { AST_NODE_TYPES } from "@typescript-eslint/utils";
4
+ //#region src/rules/require-error-message.ts
5
+ const { zodImportAllowedSource, trackZodSchemaImports } = createZodSchemaImportTrack("zod-mini");
6
+ const requireErrorMessage = createZodMiniPluginRule({
7
+ name: "require-error-message",
8
+ meta: {
9
+ type: "suggestion",
10
+ fixable: "code",
11
+ docs: {
12
+ zodImportAllowedSource,
13
+ description: "Enforce that custom refinements include an error message"
14
+ },
15
+ messages: {
16
+ requireErrorMessage: "Custom refinements must include an error message",
17
+ preferError: "Use the \"error\" property instead of the deprecated \"message\" property",
18
+ removeMessage: "The \"message\" property is deprecated; use \"error\""
19
+ },
20
+ schema: []
21
+ },
22
+ defaultOptions: [],
23
+ create(context) {
24
+ const { importDeclarationListener, detectZodSchemaRootNode, collectZodChainMethods } = trackZodSchemaImports();
25
+ return {
26
+ ImportDeclaration: importDeclarationListener,
27
+ CallExpression(node) {
28
+ if (!detectZodSchemaRootNode(node)) return;
29
+ const refines = collectZodChainMethods(node).filter((it) => it.name === "refine" || it.name === "custom");
30
+ if (refines.length === 0) return;
31
+ for (const refine of refines) {
32
+ const refineNode = refine.node;
33
+ if (refineNode.arguments.length < 2) {
34
+ context.report({
35
+ messageId: "requireErrorMessage",
36
+ node: refineNode
37
+ });
38
+ continue;
39
+ }
40
+ const [, params] = refineNode.arguments;
41
+ if (params.type === AST_NODE_TYPES.Literal) continue;
42
+ if (params.type !== AST_NODE_TYPES.ObjectExpression) continue;
43
+ let errorPropertyNode;
44
+ let messagePropertyNode;
45
+ for (const property of params.properties) if (property.type === AST_NODE_TYPES.Property && property.key.type === AST_NODE_TYPES.Identifier) {
46
+ if (property.key.name === "error") errorPropertyNode = property;
47
+ if (property.key.name === "message") messagePropertyNode = property;
48
+ if (errorPropertyNode && messagePropertyNode) break;
49
+ }
50
+ if (errorPropertyNode && messagePropertyNode) {
51
+ context.report({
52
+ messageId: "removeMessage",
53
+ node: messagePropertyNode,
54
+ fix(fixer) {
55
+ const { sourceCode } = context;
56
+ const nextToken = sourceCode.getTokenAfter(messagePropertyNode);
57
+ let [, end] = messagePropertyNode.range;
58
+ if (nextToken?.value === ",") end = nextToken.range[1];
59
+ return fixer.removeRange([messagePropertyNode.range[0], end]);
60
+ }
61
+ });
62
+ continue;
63
+ }
64
+ if (messagePropertyNode && !errorPropertyNode) {
65
+ context.report({
66
+ messageId: "preferError",
67
+ node: params,
68
+ fix(fixer) {
69
+ return fixer.replaceTextRange(messagePropertyNode.key.range, "error");
70
+ }
71
+ });
72
+ continue;
73
+ }
74
+ if (!errorPropertyNode) context.report({
75
+ messageId: "requireErrorMessage",
76
+ node: params
77
+ });
78
+ }
79
+ }
80
+ };
81
+ }
82
+ });
83
+ //#endregion
84
+ export { requireErrorMessage };
@@ -0,0 +1,69 @@
1
+ require("../_virtual/_rolldown/runtime.cjs");
2
+ const require_create_plugin_rule = require("../utils/create-plugin-rule.cjs");
3
+ let _eslint_zod_utils = require("@eslint-zod/utils");
4
+ let _typescript_eslint_utils = require("@typescript-eslint/utils");
5
+ //#region src/rules/require-schema-suffix.ts
6
+ const { zodImportAllowedSource, trackZodSchemaImports } = (0, _eslint_zod_utils.createZodSchemaImportTrack)("zod-mini");
7
+ const requireSchemaSuffix = require_create_plugin_rule.createZodMiniPluginRule({
8
+ name: "require-schema-suffix",
9
+ meta: {
10
+ type: "suggestion",
11
+ deprecated: { message: "Use `zod-mini/consistent-schema-var-name`" },
12
+ docs: {
13
+ zodImportAllowedSource,
14
+ description: "Require schema suffix when declaring a Zod Mini schema"
15
+ },
16
+ messages: { noSchemaSuffix: "Use the \"{{suffix}}\" suffix for Zod Mini schemas. Rename this to \"{{expected}}\"" },
17
+ schema: [{
18
+ type: "object",
19
+ properties: { suffix: {
20
+ type: "string",
21
+ description: "The required suffix for Zod Mini schema variables"
22
+ } },
23
+ additionalProperties: false
24
+ }]
25
+ },
26
+ defaultOptions: [{ suffix: "Schema" }],
27
+ create(context, [{ suffix }]) {
28
+ const { importDeclarationListener, detectZodSchemaRootNode, collectZodChainMethods } = trackZodSchemaImports();
29
+ return {
30
+ ImportDeclaration: importDeclarationListener,
31
+ VariableDeclarator(node) {
32
+ const initNode = node.init;
33
+ if (initNode?.type !== _typescript_eslint_utils.AST_NODE_TYPES.CallExpression || !detectZodSchemaRootNode(initNode)) return;
34
+ const chainMethods = collectZodChainMethods(initNode).map((it) => it.name);
35
+ if ([
36
+ "parse",
37
+ "parseAsync",
38
+ "safeParse",
39
+ "safeParseAsync",
40
+ "spa",
41
+ "encode",
42
+ "encodeAsync",
43
+ "decode",
44
+ "decodeAsync",
45
+ "safeEncode",
46
+ "safeEncodeAsync",
47
+ "safeDecode",
48
+ "safeDecodeAsync",
49
+ "codec",
50
+ "treeifyError",
51
+ "prettifyError",
52
+ "formatError",
53
+ "flattenError"
54
+ ].some((it) => chainMethods.includes(it))) return;
55
+ if (node.id.type !== _typescript_eslint_utils.AST_NODE_TYPES.Identifier || node.id.name.endsWith(suffix)) return;
56
+ context.report({
57
+ node,
58
+ messageId: "noSchemaSuffix",
59
+ data: {
60
+ suffix,
61
+ expected: `${node.id.name}${suffix}`
62
+ }
63
+ });
64
+ }
65
+ };
66
+ }
67
+ });
68
+ //#endregion
69
+ exports.requireSchemaSuffix = requireSchemaSuffix;
@@ -0,0 +1,68 @@
1
+ import { createZodMiniPluginRule } from "../utils/create-plugin-rule.mjs";
2
+ import { createZodSchemaImportTrack } from "@eslint-zod/utils";
3
+ import { AST_NODE_TYPES } from "@typescript-eslint/utils";
4
+ //#region src/rules/require-schema-suffix.ts
5
+ const { zodImportAllowedSource, trackZodSchemaImports } = createZodSchemaImportTrack("zod-mini");
6
+ const requireSchemaSuffix = createZodMiniPluginRule({
7
+ name: "require-schema-suffix",
8
+ meta: {
9
+ type: "suggestion",
10
+ deprecated: { message: "Use `zod-mini/consistent-schema-var-name`" },
11
+ docs: {
12
+ zodImportAllowedSource,
13
+ description: "Require schema suffix when declaring a Zod Mini schema"
14
+ },
15
+ messages: { noSchemaSuffix: "Use the \"{{suffix}}\" suffix for Zod Mini schemas. Rename this to \"{{expected}}\"" },
16
+ schema: [{
17
+ type: "object",
18
+ properties: { suffix: {
19
+ type: "string",
20
+ description: "The required suffix for Zod Mini schema variables"
21
+ } },
22
+ additionalProperties: false
23
+ }]
24
+ },
25
+ defaultOptions: [{ suffix: "Schema" }],
26
+ create(context, [{ suffix }]) {
27
+ const { importDeclarationListener, detectZodSchemaRootNode, collectZodChainMethods } = trackZodSchemaImports();
28
+ return {
29
+ ImportDeclaration: importDeclarationListener,
30
+ VariableDeclarator(node) {
31
+ const initNode = node.init;
32
+ if (initNode?.type !== AST_NODE_TYPES.CallExpression || !detectZodSchemaRootNode(initNode)) return;
33
+ const chainMethods = collectZodChainMethods(initNode).map((it) => it.name);
34
+ if ([
35
+ "parse",
36
+ "parseAsync",
37
+ "safeParse",
38
+ "safeParseAsync",
39
+ "spa",
40
+ "encode",
41
+ "encodeAsync",
42
+ "decode",
43
+ "decodeAsync",
44
+ "safeEncode",
45
+ "safeEncodeAsync",
46
+ "safeDecode",
47
+ "safeDecodeAsync",
48
+ "codec",
49
+ "treeifyError",
50
+ "prettifyError",
51
+ "formatError",
52
+ "flattenError"
53
+ ].some((it) => chainMethods.includes(it))) return;
54
+ if (node.id.type !== AST_NODE_TYPES.Identifier || node.id.name.endsWith(suffix)) return;
55
+ context.report({
56
+ node,
57
+ messageId: "noSchemaSuffix",
58
+ data: {
59
+ suffix,
60
+ expected: `${node.id.name}${suffix}`
61
+ }
62
+ });
63
+ }
64
+ };
65
+ }
66
+ });
67
+ //#endregion
68
+ export { requireSchemaSuffix };
@@ -0,0 +1,96 @@
1
+ const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
2
+ const require_create_plugin_rule = require("../utils/create-plugin-rule.cjs");
3
+ let _eslint_zod_utils = require("@eslint-zod/utils");
4
+ let _typescript_eslint_utils = require("@typescript-eslint/utils");
5
+ let esquery = require("esquery");
6
+ esquery = require_runtime.__toESM(esquery, 1);
7
+ //#region src/rules/schema-error-property-style.ts
8
+ const { zodImportAllowedSource, trackZodSchemaImports } = (0, _eslint_zod_utils.createZodSchemaImportTrack)("zod-mini");
9
+ const schemaErrorPropertyStyle = require_create_plugin_rule.createZodMiniPluginRule({
10
+ name: "schema-error-property-style",
11
+ meta: {
12
+ type: "suggestion",
13
+ docs: {
14
+ zodImportAllowedSource,
15
+ description: "Enforce consistent style for error messages in Zod Mini schema validation (using ESQuery patterns)"
16
+ },
17
+ messages: {
18
+ invalidSelector: "Invalid ESQuery selector: \"{{selector}}\"",
19
+ invalidStyle: "Error message must follow the pattern \"{{selector}}\" (e.g., {{example}}). Found: {{actual}}."
20
+ },
21
+ schema: [{
22
+ type: "object",
23
+ properties: {
24
+ selector: {
25
+ description: "An ESQuery string to match the required pattern",
26
+ type: "string"
27
+ },
28
+ example: {
29
+ description: "Example code to help the user understand the required pattern",
30
+ type: "string"
31
+ }
32
+ },
33
+ additionalProperties: false
34
+ }]
35
+ },
36
+ defaultOptions: [{
37
+ selector: "Literal,TemplateLiteral",
38
+ example: "'error message'"
39
+ }],
40
+ create(context, [{ selector, example }]) {
41
+ const { importDeclarationListener, detectZodSchemaRootNode, collectZodChainMethods } = trackZodSchemaImports();
42
+ /**
43
+ * Parsing `selector` to ensure it is valid,
44
+ * if not report an error and return empty rule listener
45
+ */
46
+ try {
47
+ esquery.default.parse(selector);
48
+ } catch {
49
+ context.report({
50
+ loc: {
51
+ line: 1,
52
+ column: 0
53
+ },
54
+ messageId: "invalidSelector",
55
+ data: { selector }
56
+ });
57
+ return {};
58
+ }
59
+ return {
60
+ ImportDeclaration: importDeclarationListener,
61
+ CallExpression(node) {
62
+ const zodSchemaMeta = detectZodSchemaRootNode(node);
63
+ if (!zodSchemaMeta) return;
64
+ if (zodSchemaMeta.schemaType !== "custom" && !collectZodChainMethods(node).some((it) => it.name === "refine")) return;
65
+ if (node.arguments.length < 2) return;
66
+ let errorMessageNode;
67
+ const [, params] = node.arguments;
68
+ switch (params.type) {
69
+ case _typescript_eslint_utils.AST_NODE_TYPES.Literal:
70
+ case _typescript_eslint_utils.AST_NODE_TYPES.TemplateLiteral:
71
+ errorMessageNode = params;
72
+ break;
73
+ case _typescript_eslint_utils.AST_NODE_TYPES.ObjectExpression:
74
+ for (const property of params.properties) if (property.type === _typescript_eslint_utils.AST_NODE_TYPES.Property && property.key.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier && property.key.name === "error") {
75
+ errorMessageNode = property.value;
76
+ break;
77
+ }
78
+ break;
79
+ }
80
+ if (!errorMessageNode) return;
81
+ if (esquery.default.matches(errorMessageNode, esquery.default.parse(selector), errorMessageNode)) return;
82
+ context.report({
83
+ node,
84
+ messageId: "invalidStyle",
85
+ data: {
86
+ selector,
87
+ example,
88
+ actual: context.sourceCode.getText(errorMessageNode)
89
+ }
90
+ });
91
+ }
92
+ };
93
+ }
94
+ });
95
+ //#endregion
96
+ exports.schemaErrorPropertyStyle = schemaErrorPropertyStyle;
@@ -0,0 +1,94 @@
1
+ import { createZodMiniPluginRule } from "../utils/create-plugin-rule.mjs";
2
+ import { createZodSchemaImportTrack } from "@eslint-zod/utils";
3
+ import { AST_NODE_TYPES } from "@typescript-eslint/utils";
4
+ import esquery from "esquery";
5
+ //#region src/rules/schema-error-property-style.ts
6
+ const { zodImportAllowedSource, trackZodSchemaImports } = createZodSchemaImportTrack("zod-mini");
7
+ const schemaErrorPropertyStyle = createZodMiniPluginRule({
8
+ name: "schema-error-property-style",
9
+ meta: {
10
+ type: "suggestion",
11
+ docs: {
12
+ zodImportAllowedSource,
13
+ description: "Enforce consistent style for error messages in Zod Mini schema validation (using ESQuery patterns)"
14
+ },
15
+ messages: {
16
+ invalidSelector: "Invalid ESQuery selector: \"{{selector}}\"",
17
+ invalidStyle: "Error message must follow the pattern \"{{selector}}\" (e.g., {{example}}). Found: {{actual}}."
18
+ },
19
+ schema: [{
20
+ type: "object",
21
+ properties: {
22
+ selector: {
23
+ description: "An ESQuery string to match the required pattern",
24
+ type: "string"
25
+ },
26
+ example: {
27
+ description: "Example code to help the user understand the required pattern",
28
+ type: "string"
29
+ }
30
+ },
31
+ additionalProperties: false
32
+ }]
33
+ },
34
+ defaultOptions: [{
35
+ selector: "Literal,TemplateLiteral",
36
+ example: "'error message'"
37
+ }],
38
+ create(context, [{ selector, example }]) {
39
+ const { importDeclarationListener, detectZodSchemaRootNode, collectZodChainMethods } = trackZodSchemaImports();
40
+ /**
41
+ * Parsing `selector` to ensure it is valid,
42
+ * if not report an error and return empty rule listener
43
+ */
44
+ try {
45
+ esquery.parse(selector);
46
+ } catch {
47
+ context.report({
48
+ loc: {
49
+ line: 1,
50
+ column: 0
51
+ },
52
+ messageId: "invalidSelector",
53
+ data: { selector }
54
+ });
55
+ return {};
56
+ }
57
+ return {
58
+ ImportDeclaration: importDeclarationListener,
59
+ CallExpression(node) {
60
+ const zodSchemaMeta = detectZodSchemaRootNode(node);
61
+ if (!zodSchemaMeta) return;
62
+ if (zodSchemaMeta.schemaType !== "custom" && !collectZodChainMethods(node).some((it) => it.name === "refine")) return;
63
+ if (node.arguments.length < 2) return;
64
+ let errorMessageNode;
65
+ const [, params] = node.arguments;
66
+ switch (params.type) {
67
+ case AST_NODE_TYPES.Literal:
68
+ case AST_NODE_TYPES.TemplateLiteral:
69
+ errorMessageNode = params;
70
+ break;
71
+ case AST_NODE_TYPES.ObjectExpression:
72
+ for (const property of params.properties) if (property.type === AST_NODE_TYPES.Property && property.key.type === AST_NODE_TYPES.Identifier && property.key.name === "error") {
73
+ errorMessageNode = property.value;
74
+ break;
75
+ }
76
+ break;
77
+ }
78
+ if (!errorMessageNode) return;
79
+ if (esquery.matches(errorMessageNode, esquery.parse(selector), errorMessageNode)) return;
80
+ context.report({
81
+ node,
82
+ messageId: "invalidStyle",
83
+ data: {
84
+ selector,
85
+ example,
86
+ actual: context.sourceCode.getText(errorMessageNode)
87
+ }
88
+ });
89
+ }
90
+ };
91
+ }
92
+ });
93
+ //#endregion
94
+ export { schemaErrorPropertyStyle };
@@ -0,0 +1,21 @@
1
+ interface CompatibleConfig {
2
+ name?: string;
3
+ rules?: object;
4
+ plugins?: Record<string, CompatiblePlugin>;
5
+ }
6
+ interface CompatiblePlugin {
7
+ meta: {
8
+ name: string;
9
+ version: string;
10
+ };
11
+ }
12
+ declare const _default: {
13
+ configs: {
14
+ recommended: CompatibleConfig;
15
+ };
16
+ meta: {
17
+ name: string;
18
+ version: string;
19
+ };
20
+ };
21
+ export default _default;
@@ -0,0 +1,56 @@
1
+ import { PLUGIN_NAME, PLUGIN_VERSION } from './meta.js';
2
+ import { consistentImportSource } from './rules/consistent-import-source.js';
3
+ import { consistentImport } from './rules/consistent-import.js';
4
+ import { consistentObjectSchemaType } from './rules/consistent-object-schema-type.js';
5
+ import { consistentSchemaOutputTypeStyle } from './rules/consistent-schema-output-type-style.js';
6
+ import { consistentSchemaVarName } from './rules/consistent-schema-var-name.js';
7
+ import { noAnySchema } from './rules/no-any-schema.js';
8
+ import { noEmptyCustomSchema } from './rules/no-empty-custom-schema.js';
9
+ import { noUnknownSchema } from './rules/no-unknown-schema.js';
10
+ import { preferMeta } from './rules/prefer-meta.js';
11
+ import { preferNamespaceImport } from './rules/prefer-namespace-import.js';
12
+ import { requireBrandTypeParameter } from './rules/require-brand-type-parameter.js';
13
+ import { requireErrorMessage } from './rules/require-error-message.js';
14
+ import { requireSchemaSuffix } from './rules/require-schema-suffix.js';
15
+ import { schemaErrorPropertyStyle } from './rules/schema-error-property-style.js';
16
+ const eslintPluginZodMini = {
17
+ meta: {
18
+ name: PLUGIN_NAME,
19
+ version: PLUGIN_VERSION,
20
+ },
21
+ rules: {
22
+ 'consistent-import': consistentImport,
23
+ 'consistent-import-source': consistentImportSource,
24
+ 'consistent-object-schema-type': consistentObjectSchemaType,
25
+ 'consistent-schema-output-type-style': consistentSchemaOutputTypeStyle,
26
+ 'consistent-schema-var-name': consistentSchemaVarName,
27
+ 'no-any-schema': noAnySchema,
28
+ 'no-empty-custom-schema': noEmptyCustomSchema,
29
+ 'no-unknown-schema': noUnknownSchema,
30
+ 'prefer-meta': preferMeta,
31
+ 'prefer-namespace-import': preferNamespaceImport,
32
+ 'require-brand-type-parameter': requireBrandTypeParameter,
33
+ 'require-error-message': requireErrorMessage,
34
+ 'require-schema-suffix': requireSchemaSuffix,
35
+ 'schema-error-property-style': schemaErrorPropertyStyle,
36
+ },
37
+ };
38
+ const baseConfig = {
39
+ name: `${PLUGIN_NAME}/recommended`,
40
+ files: ['**/*.{js,mjs,cjs,jsx,mjsx,ts,tsx,mtsx}'],
41
+ plugins: {
42
+ 'zod-mini': eslintPluginZodMini,
43
+ },
44
+ };
45
+ const recommendedConfig = Object.assign(Object.assign({}, baseConfig), { rules: {
46
+ 'zod-mini/consistent-import': 'error',
47
+ 'zod-mini/consistent-schema-var-name': 'error',
48
+ 'zod-mini/no-any-schema': 'error',
49
+ 'zod-mini/no-empty-custom-schema': 'error',
50
+ 'zod-mini/prefer-meta': 'error',
51
+ 'zod-mini/require-brand-type-parameter': 'error',
52
+ 'zod-mini/require-error-message': 'error',
53
+ } });
54
+ export default Object.assign(Object.assign({}, eslintPluginZodMini), { configs: {
55
+ recommended: recommendedConfig,
56
+ } });
@@ -0,0 +1,3 @@
1
+ declare const PLUGIN_NAME: string, PLUGIN_VERSION: string;
2
+ export { PLUGIN_NAME, PLUGIN_VERSION };
3
+ export declare function getRuleURL(ruleID: string): string;
@@ -0,0 +1,8 @@
1
+ import { readFileSync } from 'node:fs';
2
+ const packageJSON = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
3
+ const { name: PLUGIN_NAME, version: PLUGIN_VERSION, homepage } = packageJSON;
4
+ export { PLUGIN_NAME, PLUGIN_VERSION };
5
+ const PLUGIN_HOMEPAGE = homepage.replace(/#[^#]*$/, '');
6
+ export function getRuleURL(ruleID) {
7
+ return `${PLUGIN_HOMEPAGE}/blob/v${PLUGIN_VERSION}/docs/rules/${ruleID}.md`;
8
+ }
@@ -0,0 +1,11 @@
1
+ import type { ZodImportSource } from '@eslint-zod/utils';
2
+ import type { TSESLint } from '@typescript-eslint/utils';
3
+ type MessageIds = 'sourceNotAllowed' | 'replaceSource';
4
+ export declare const consistentImportSource: TSESLint.RuleModule<MessageIds, [{
5
+ sources: Array<ZodImportSource>;
6
+ }], {
7
+ zodImportAllowedSource: "all" | "zod" | "zod-mini";
8
+ }, TSESLint.RuleListener> & {
9
+ name: string;
10
+ };
11
+ export {};
@@ -0,0 +1,64 @@
1
+ import { ZOD_IMPORT_SOURCES } from '@eslint-zod/utils';
2
+ import { createZodMiniPluginRule } from '../utils/create-plugin-rule.js';
3
+ export const consistentImportSource = createZodMiniPluginRule({
4
+ name: 'consistent-import-source',
5
+ meta: {
6
+ hasSuggestions: true,
7
+ type: 'suggestion',
8
+ docs: {
9
+ zodImportAllowedSource: 'zod-mini',
10
+ description: 'Enforce consistent source from Zod Mini imports',
11
+ },
12
+ messages: {
13
+ sourceNotAllowed: '"{{source}}" is not allowed. Available values are: {{sources}}',
14
+ replaceSource: 'Replace "{{invalid}}" with "{{valid}}"',
15
+ },
16
+ schema: [
17
+ {
18
+ type: 'object',
19
+ properties: {
20
+ sources: {
21
+ type: 'array',
22
+ description: 'An array of allowed Zod import sources.',
23
+ items: {
24
+ type: 'string',
25
+ enum: [...ZOD_IMPORT_SOURCES],
26
+ },
27
+ minItems: 1,
28
+ uniqueItems: true,
29
+ },
30
+ },
31
+ additionalProperties: false,
32
+ },
33
+ ],
34
+ },
35
+ defaultOptions: [{ sources: ['zod/mini'] }],
36
+ create(context, [{ sources }]) {
37
+ return {
38
+ ImportDeclaration(node) {
39
+ const sourceValue = node.source.value;
40
+ if (!sourceValue.startsWith('zod')) {
41
+ return;
42
+ }
43
+ if (sources.includes(sourceValue)) {
44
+ return;
45
+ }
46
+ context.report({
47
+ node,
48
+ messageId: 'sourceNotAllowed',
49
+ data: {
50
+ source: sourceValue,
51
+ sources: sources.map((s) => `"${s}"`).join(', '),
52
+ },
53
+ suggest: sources.map((it) => ({
54
+ messageId: 'replaceSource',
55
+ data: { valid: it, invalid: sourceValue },
56
+ fix(fixer) {
57
+ return fixer.replaceText(node.source, node.source.raw.replace(sourceValue, it));
58
+ },
59
+ })),
60
+ });
61
+ },
62
+ };
63
+ },
64
+ });
@@ -0,0 +1 @@
1
+ export {};