eslint-plugin-zod 1.3.0 → 3.0.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 (104) hide show
  1. package/LICENSE +19 -22
  2. package/README.md +84 -56
  3. package/dist/index.cjs +71 -0
  4. package/dist/index.d.cts +21 -0
  5. package/dist/index.d.ts +21 -0
  6. package/dist/index.js +68 -0
  7. package/dist/meta.cjs +13 -0
  8. package/dist/meta.d.cts +3 -0
  9. package/dist/meta.d.ts +3 -0
  10. package/dist/meta.js +8 -0
  11. package/dist/rules/array-style.cjs +99 -0
  12. package/dist/rules/array-style.d.cts +10 -0
  13. package/dist/rules/array-style.d.ts +10 -0
  14. package/dist/rules/array-style.js +96 -0
  15. package/dist/rules/consistent-import-source.cjs +73 -0
  16. package/dist/rules/consistent-import-source.d.cts +10 -0
  17. package/dist/rules/consistent-import-source.d.ts +10 -0
  18. package/dist/rules/consistent-import-source.js +70 -0
  19. package/dist/rules/consistent-object-schema-type.cjs +83 -0
  20. package/dist/rules/consistent-object-schema-type.d.cts +11 -0
  21. package/dist/rules/consistent-object-schema-type.d.ts +11 -0
  22. package/dist/rules/consistent-object-schema-type.js +80 -0
  23. package/dist/rules/no-any-schema.cjs +66 -0
  24. package/dist/rules/no-any-schema.d.cts +4 -0
  25. package/dist/rules/no-any-schema.d.ts +4 -0
  26. package/dist/rules/no-any-schema.js +63 -0
  27. package/dist/rules/no-empty-custom-schema.cjs +40 -0
  28. package/dist/rules/no-empty-custom-schema.d.cts +4 -0
  29. package/dist/rules/no-empty-custom-schema.d.ts +4 -0
  30. package/dist/rules/no-empty-custom-schema.js +37 -0
  31. package/dist/rules/no-number-schema-with-int.cjs +78 -0
  32. package/dist/rules/no-number-schema-with-int.d.cts +4 -0
  33. package/dist/rules/no-number-schema-with-int.d.ts +4 -0
  34. package/dist/rules/no-number-schema-with-int.js +75 -0
  35. package/dist/rules/no-optional-and-default-together.cjs +80 -0
  36. package/dist/rules/no-optional-and-default-together.d.cts +11 -0
  37. package/dist/rules/no-optional-and-default-together.d.ts +11 -0
  38. package/dist/rules/no-optional-and-default-together.js +77 -0
  39. package/dist/rules/no-throw-in-refine.cjs +84 -0
  40. package/dist/rules/no-throw-in-refine.d.cts +4 -0
  41. package/dist/rules/no-throw-in-refine.d.ts +4 -0
  42. package/dist/rules/no-throw-in-refine.js +81 -0
  43. package/dist/rules/no-unknown-schema.cjs +35 -0
  44. package/dist/rules/no-unknown-schema.d.cts +4 -0
  45. package/dist/rules/no-unknown-schema.d.ts +4 -0
  46. package/dist/rules/no-unknown-schema.js +32 -0
  47. package/dist/rules/prefer-enum-over-literal-union.cjs +72 -0
  48. package/dist/rules/prefer-enum-over-literal-union.d.cts +4 -0
  49. package/dist/rules/prefer-enum-over-literal-union.d.ts +4 -0
  50. package/dist/rules/prefer-enum-over-literal-union.js +69 -0
  51. package/dist/rules/prefer-meta-last.cjs +71 -0
  52. package/dist/rules/prefer-meta-last.d.cts +4 -0
  53. package/dist/rules/prefer-meta-last.d.ts +4 -0
  54. package/dist/rules/prefer-meta-last.js +68 -0
  55. package/dist/rules/prefer-meta.cjs +48 -0
  56. package/dist/rules/prefer-meta.d.cts +4 -0
  57. package/dist/rules/prefer-meta.d.ts +4 -0
  58. package/dist/rules/prefer-meta.js +45 -0
  59. package/dist/rules/prefer-namespace-import.cjs +145 -0
  60. package/dist/rules/prefer-namespace-import.d.cts +4 -0
  61. package/dist/rules/prefer-namespace-import.d.ts +4 -0
  62. package/dist/rules/prefer-namespace-import.js +142 -0
  63. package/dist/rules/require-brand-type-parameter.cjs +60 -0
  64. package/dist/rules/require-brand-type-parameter.d.cts +4 -0
  65. package/dist/rules/require-brand-type-parameter.d.ts +4 -0
  66. package/dist/rules/require-brand-type-parameter.js +57 -0
  67. package/dist/rules/require-error-message.cjs +101 -0
  68. package/dist/rules/require-error-message.d.cts +4 -0
  69. package/dist/rules/require-error-message.d.ts +4 -0
  70. package/dist/rules/require-error-message.js +98 -0
  71. package/dist/rules/require-schema-suffix.cjs +73 -0
  72. package/dist/rules/require-schema-suffix.d.cts +8 -0
  73. package/dist/rules/require-schema-suffix.d.ts +8 -0
  74. package/dist/rules/require-schema-suffix.js +70 -0
  75. package/dist/rules/schema-error-property-style.cjs +106 -0
  76. package/dist/rules/schema-error-property-style.d.cts +9 -0
  77. package/dist/rules/schema-error-property-style.d.ts +9 -0
  78. package/dist/rules/schema-error-property-style.js +100 -0
  79. package/dist/utils/detect-zod-schema-root-node.cjs +104 -0
  80. package/dist/utils/detect-zod-schema-root-node.d.cts +10 -0
  81. package/dist/utils/detect-zod-schema-root-node.d.ts +10 -0
  82. package/dist/utils/detect-zod-schema-root-node.js +101 -0
  83. package/dist/utils/get-outermost-call.cjs +14 -0
  84. package/dist/utils/get-outermost-call.d.cts +2 -0
  85. package/dist/utils/get-outermost-call.d.ts +2 -0
  86. package/dist/utils/get-outermost-call.js +11 -0
  87. package/dist/utils/is-zod-expression.cjs +14 -0
  88. package/dist/utils/is-zod-expression.d.cts +2 -0
  89. package/dist/utils/is-zod-expression.d.ts +2 -0
  90. package/dist/utils/is-zod-expression.js +11 -0
  91. package/dist/utils/is-zod-import-source.cjs +6 -0
  92. package/dist/utils/is-zod-import-source.d.cts +1 -0
  93. package/dist/utils/is-zod-import-source.d.ts +1 -0
  94. package/dist/utils/is-zod-import-source.js +3 -0
  95. package/dist/utils/track-zod-schema-imports.cjs +61 -0
  96. package/dist/utils/track-zod-schema-imports.d.cts +13 -0
  97. package/dist/utils/track-zod-schema-imports.d.ts +13 -0
  98. package/dist/utils/track-zod-schema-imports.js +58 -0
  99. package/package.json +82 -38
  100. package/dist/src/index.d.ts +0 -31
  101. package/dist/src/index.js +0 -14
  102. package/dist/src/rules/requireStrict.d.ts +0 -24
  103. package/dist/src/rules/requireStrict.js +0 -69
  104. package/tsconfig.json +0 -28
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.requireBrandTypeParameter = void 0;
4
+ const utils_1 = require("@typescript-eslint/utils");
5
+ const meta_js_1 = require("../meta.cjs");
6
+ const track_zod_schema_imports_js_1 = require("../utils/track-zod-schema-imports.cjs");
7
+ exports.requireBrandTypeParameter = utils_1.ESLintUtils.RuleCreator(meta_js_1.getRuleURL)({
8
+ name: 'require-brand-type-parameter',
9
+ meta: {
10
+ hasSuggestions: true,
11
+ type: 'problem',
12
+ docs: {
13
+ description: 'Require type parameter on `.brand()` functions',
14
+ },
15
+ messages: {
16
+ missingTypeParameter: 'Type parameter is required when using `.brand()`',
17
+ removeBrandFunction: 'Brand is a static-only construct. If not parameter is required consider removal',
18
+ },
19
+ schema: [],
20
+ },
21
+ defaultOptions: [],
22
+ create(context) {
23
+ const { importDeclarationListener, detectZodSchemaRootNode, collectZodChainMethods, } = (0, track_zod_schema_imports_js_1.trackZodSchemaImports)();
24
+ return {
25
+ ImportDeclaration: importDeclarationListener,
26
+ CallExpression(node) {
27
+ const zodSchemaMeta = detectZodSchemaRootNode(node);
28
+ if (!zodSchemaMeta) {
29
+ return;
30
+ }
31
+ const methods = collectZodChainMethods(zodSchemaMeta.node);
32
+ const brandMethod = methods.find((it) => it.name === 'brand');
33
+ if (!brandMethod) {
34
+ return;
35
+ }
36
+ const brandNode = brandMethod.node;
37
+ const { typeArguments } = brandNode;
38
+ if (typeArguments && typeArguments.params.length > 0) {
39
+ return;
40
+ }
41
+ const brandCalleeNode = brandNode.callee;
42
+ context.report({
43
+ messageId: 'missingTypeParameter',
44
+ node: brandCalleeNode.property,
45
+ suggest: [
46
+ {
47
+ messageId: 'removeBrandFunction',
48
+ fix(fixer) {
49
+ return fixer.removeRange([
50
+ brandCalleeNode.object.range[1],
51
+ brandNode.range[1],
52
+ ]);
53
+ },
54
+ },
55
+ ],
56
+ });
57
+ },
58
+ };
59
+ },
60
+ });
@@ -0,0 +1,4 @@
1
+ import type { TSESLint } from '@typescript-eslint/utils';
2
+ export declare const requireBrandTypeParameter: TSESLint.RuleModule<"missingTypeParameter" | "removeBrandFunction", [], unknown, TSESLint.RuleListener> & {
3
+ name: string;
4
+ };
@@ -0,0 +1,4 @@
1
+ import type { TSESLint } from '@typescript-eslint/utils';
2
+ export declare const requireBrandTypeParameter: TSESLint.RuleModule<"missingTypeParameter" | "removeBrandFunction", [], unknown, TSESLint.RuleListener> & {
3
+ name: string;
4
+ };
@@ -0,0 +1,57 @@
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+ import { getRuleURL } from "../meta.js";
3
+ import { trackZodSchemaImports } from "../utils/track-zod-schema-imports.js";
4
+ export const requireBrandTypeParameter = ESLintUtils.RuleCreator(getRuleURL)({
5
+ name: 'require-brand-type-parameter',
6
+ meta: {
7
+ hasSuggestions: true,
8
+ type: 'problem',
9
+ docs: {
10
+ description: 'Require type parameter on `.brand()` functions',
11
+ },
12
+ messages: {
13
+ missingTypeParameter: 'Type parameter is required when using `.brand()`',
14
+ removeBrandFunction: 'Brand is a static-only construct. If not parameter is required consider removal',
15
+ },
16
+ schema: [],
17
+ },
18
+ defaultOptions: [],
19
+ create(context) {
20
+ const { importDeclarationListener, detectZodSchemaRootNode, collectZodChainMethods, } = trackZodSchemaImports();
21
+ return {
22
+ ImportDeclaration: importDeclarationListener,
23
+ CallExpression(node) {
24
+ const zodSchemaMeta = detectZodSchemaRootNode(node);
25
+ if (!zodSchemaMeta) {
26
+ return;
27
+ }
28
+ const methods = collectZodChainMethods(zodSchemaMeta.node);
29
+ const brandMethod = methods.find((it) => it.name === 'brand');
30
+ if (!brandMethod) {
31
+ return;
32
+ }
33
+ const brandNode = brandMethod.node;
34
+ const { typeArguments } = brandNode;
35
+ if (typeArguments && typeArguments.params.length > 0) {
36
+ return;
37
+ }
38
+ const brandCalleeNode = brandNode.callee;
39
+ context.report({
40
+ messageId: 'missingTypeParameter',
41
+ node: brandCalleeNode.property,
42
+ suggest: [
43
+ {
44
+ messageId: 'removeBrandFunction',
45
+ fix(fixer) {
46
+ return fixer.removeRange([
47
+ brandCalleeNode.object.range[1],
48
+ brandNode.range[1],
49
+ ]);
50
+ },
51
+ },
52
+ ],
53
+ });
54
+ },
55
+ };
56
+ },
57
+ });
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.requireErrorMessage = void 0;
4
+ const utils_1 = require("@typescript-eslint/utils");
5
+ const meta_js_1 = require("../meta.cjs");
6
+ const track_zod_schema_imports_js_1 = require("../utils/track-zod-schema-imports.cjs");
7
+ exports.requireErrorMessage = utils_1.ESLintUtils.RuleCreator(meta_js_1.getRuleURL)({
8
+ name: 'require-error-message',
9
+ meta: {
10
+ type: 'suggestion',
11
+ fixable: 'code',
12
+ docs: {
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, } = (0, track_zod_schema_imports_js_1.trackZodSchemaImports)();
25
+ return {
26
+ ImportDeclaration: importDeclarationListener,
27
+ CallExpression(node) {
28
+ const zodSchemaMeta = detectZodSchemaRootNode(node);
29
+ if (!zodSchemaMeta) {
30
+ return;
31
+ }
32
+ const refine = collectZodChainMethods(node).find((it) => it.name === 'refine' || it.name === 'custom');
33
+ if (!refine) {
34
+ return;
35
+ }
36
+ const refineNode = refine.node;
37
+ if (refineNode.arguments.length < 2) {
38
+ context.report({
39
+ messageId: 'requireErrorMessage',
40
+ node: node.callee,
41
+ });
42
+ return;
43
+ }
44
+ const [, params] = refineNode.arguments;
45
+ if (params.type === utils_1.AST_NODE_TYPES.Literal) {
46
+ return;
47
+ }
48
+ if (params.type === utils_1.AST_NODE_TYPES.ObjectExpression) {
49
+ let errorPropertyNode;
50
+ let messagePropertyNode;
51
+ for (const property of params.properties) {
52
+ if (property.type === utils_1.AST_NODE_TYPES.Property &&
53
+ property.key.type === utils_1.AST_NODE_TYPES.Identifier) {
54
+ if (property.key.name === 'error') {
55
+ errorPropertyNode = property;
56
+ }
57
+ if (property.key.name === 'message') {
58
+ messagePropertyNode = property;
59
+ }
60
+ if (errorPropertyNode && messagePropertyNode) {
61
+ break;
62
+ }
63
+ }
64
+ }
65
+ if (errorPropertyNode && messagePropertyNode) {
66
+ context.report({
67
+ messageId: 'removeMessage',
68
+ node: messagePropertyNode,
69
+ fix(fixer) {
70
+ const { sourceCode } = context;
71
+ const nextToken = sourceCode.getTokenAfter(messagePropertyNode);
72
+ let [, end] = messagePropertyNode.range;
73
+ if ((nextToken === null || nextToken === void 0 ? void 0 : nextToken.value) === ',') {
74
+ end = nextToken.range[1];
75
+ }
76
+ return fixer.removeRange([messagePropertyNode.range[0], end]);
77
+ },
78
+ });
79
+ return;
80
+ }
81
+ if (messagePropertyNode && !errorPropertyNode) {
82
+ context.report({
83
+ messageId: 'preferError',
84
+ node: params,
85
+ fix(fixer) {
86
+ return fixer.replaceTextRange(messagePropertyNode.key.range, 'error');
87
+ },
88
+ });
89
+ return;
90
+ }
91
+ if (!errorPropertyNode) {
92
+ context.report({
93
+ messageId: 'requireErrorMessage',
94
+ node: params,
95
+ });
96
+ }
97
+ }
98
+ },
99
+ };
100
+ },
101
+ });
@@ -0,0 +1,4 @@
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+ export declare const requireErrorMessage: ESLintUtils.RuleModule<"requireErrorMessage" | "preferError" | "removeMessage", [], unknown, ESLintUtils.RuleListener> & {
3
+ name: string;
4
+ };
@@ -0,0 +1,4 @@
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+ export declare const requireErrorMessage: ESLintUtils.RuleModule<"requireErrorMessage" | "preferError" | "removeMessage", [], unknown, ESLintUtils.RuleListener> & {
3
+ name: string;
4
+ };
@@ -0,0 +1,98 @@
1
+ import { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/utils';
2
+ import { getRuleURL } from "../meta.js";
3
+ import { trackZodSchemaImports } from "../utils/track-zod-schema-imports.js";
4
+ export const requireErrorMessage = ESLintUtils.RuleCreator(getRuleURL)({
5
+ name: 'require-error-message',
6
+ meta: {
7
+ type: 'suggestion',
8
+ fixable: 'code',
9
+ docs: {
10
+ description: 'Enforce that custom refinements include an error message',
11
+ },
12
+ messages: {
13
+ requireErrorMessage: 'Custom refinements must include an error message',
14
+ preferError: 'Use the "error" property instead of the deprecated "message" property',
15
+ removeMessage: 'The "message" property is deprecated; use "error"',
16
+ },
17
+ schema: [],
18
+ },
19
+ defaultOptions: [],
20
+ create(context) {
21
+ const { importDeclarationListener, detectZodSchemaRootNode, collectZodChainMethods, } = trackZodSchemaImports();
22
+ return {
23
+ ImportDeclaration: importDeclarationListener,
24
+ CallExpression(node) {
25
+ const zodSchemaMeta = detectZodSchemaRootNode(node);
26
+ if (!zodSchemaMeta) {
27
+ return;
28
+ }
29
+ const refine = collectZodChainMethods(node).find((it) => it.name === 'refine' || it.name === 'custom');
30
+ if (!refine) {
31
+ return;
32
+ }
33
+ const refineNode = refine.node;
34
+ if (refineNode.arguments.length < 2) {
35
+ context.report({
36
+ messageId: 'requireErrorMessage',
37
+ node: node.callee,
38
+ });
39
+ return;
40
+ }
41
+ const [, params] = refineNode.arguments;
42
+ if (params.type === AST_NODE_TYPES.Literal) {
43
+ return;
44
+ }
45
+ if (params.type === AST_NODE_TYPES.ObjectExpression) {
46
+ let errorPropertyNode;
47
+ let messagePropertyNode;
48
+ for (const property of params.properties) {
49
+ if (property.type === AST_NODE_TYPES.Property &&
50
+ property.key.type === AST_NODE_TYPES.Identifier) {
51
+ if (property.key.name === 'error') {
52
+ errorPropertyNode = property;
53
+ }
54
+ if (property.key.name === 'message') {
55
+ messagePropertyNode = property;
56
+ }
57
+ if (errorPropertyNode && messagePropertyNode) {
58
+ break;
59
+ }
60
+ }
61
+ }
62
+ if (errorPropertyNode && messagePropertyNode) {
63
+ context.report({
64
+ messageId: 'removeMessage',
65
+ node: messagePropertyNode,
66
+ fix(fixer) {
67
+ const { sourceCode } = context;
68
+ const nextToken = sourceCode.getTokenAfter(messagePropertyNode);
69
+ let [, end] = messagePropertyNode.range;
70
+ if ((nextToken === null || nextToken === void 0 ? void 0 : nextToken.value) === ',') {
71
+ end = nextToken.range[1];
72
+ }
73
+ return fixer.removeRange([messagePropertyNode.range[0], end]);
74
+ },
75
+ });
76
+ return;
77
+ }
78
+ if (messagePropertyNode && !errorPropertyNode) {
79
+ context.report({
80
+ messageId: 'preferError',
81
+ node: params,
82
+ fix(fixer) {
83
+ return fixer.replaceTextRange(messagePropertyNode.key.range, 'error');
84
+ },
85
+ });
86
+ return;
87
+ }
88
+ if (!errorPropertyNode) {
89
+ context.report({
90
+ messageId: 'requireErrorMessage',
91
+ node: params,
92
+ });
93
+ }
94
+ }
95
+ },
96
+ };
97
+ },
98
+ });
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.requireSchemaSuffix = void 0;
4
+ const utils_1 = require("@typescript-eslint/utils");
5
+ const meta_js_1 = require("../meta.cjs");
6
+ const track_zod_schema_imports_js_1 = require("../utils/track-zod-schema-imports.cjs");
7
+ exports.requireSchemaSuffix = utils_1.ESLintUtils.RuleCreator(meta_js_1.getRuleURL)({
8
+ name: 'require-schema-suffix',
9
+ meta: {
10
+ type: 'suggestion',
11
+ docs: {
12
+ description: 'Require schema suffix when declaring a Zod schema',
13
+ },
14
+ messages: {
15
+ noSchemaSuffix: 'Use the "{{suffix}}" suffix for Zod schemas. Rename this to "{{expected}}"',
16
+ },
17
+ schema: [
18
+ {
19
+ type: 'object',
20
+ properties: {
21
+ suffix: {
22
+ type: 'string',
23
+ description: 'The required suffix for Zod schema variables',
24
+ },
25
+ },
26
+ additionalProperties: false,
27
+ },
28
+ ],
29
+ },
30
+ defaultOptions: [{ suffix: 'Schema' }],
31
+ create(context, [{ suffix }]) {
32
+ const { importDeclarationListener, detectZodSchemaRootNode, collectZodChainMethods, } = (0, track_zod_schema_imports_js_1.trackZodSchemaImports)();
33
+ return {
34
+ ImportDeclaration: importDeclarationListener,
35
+ VariableDeclarator(node) {
36
+ const initNode = node.init;
37
+ if ((initNode === null || initNode === void 0 ? void 0 : initNode.type) !== utils_1.AST_NODE_TYPES.CallExpression ||
38
+ !detectZodSchemaRootNode(initNode)) {
39
+ return;
40
+ }
41
+ const chainMethods = collectZodChainMethods(initNode).map((it) => it.name);
42
+ const methodsThatProduceSomethingThatShouldNotBeValidated = [
43
+ 'parse',
44
+ 'parseAsync',
45
+ 'safeParse',
46
+ 'safeParseAsync',
47
+ 'spa',
48
+ 'encode',
49
+ 'encodeAsync',
50
+ 'decode',
51
+ 'decodeAsync',
52
+ 'safeEncode',
53
+ 'safeEncodeAsync',
54
+ 'safeDecode',
55
+ 'safeDecodeAsync',
56
+ 'codec',
57
+ ];
58
+ if (methodsThatProduceSomethingThatShouldNotBeValidated.some((it) => chainMethods.includes(it))) {
59
+ return;
60
+ }
61
+ if (node.id.type !== utils_1.AST_NODE_TYPES.Identifier ||
62
+ node.id.name.endsWith(suffix)) {
63
+ return;
64
+ }
65
+ context.report({
66
+ node,
67
+ messageId: 'noSchemaSuffix',
68
+ data: { suffix, expected: `${node.id.name}${suffix}` },
69
+ });
70
+ },
71
+ };
72
+ },
73
+ });
@@ -0,0 +1,8 @@
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+ interface Options {
3
+ suffix: string;
4
+ }
5
+ export declare const requireSchemaSuffix: ESLintUtils.RuleModule<"noSchemaSuffix", [Options], unknown, ESLintUtils.RuleListener> & {
6
+ name: string;
7
+ };
8
+ export {};
@@ -0,0 +1,8 @@
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+ interface Options {
3
+ suffix: string;
4
+ }
5
+ export declare const requireSchemaSuffix: ESLintUtils.RuleModule<"noSchemaSuffix", [Options], unknown, ESLintUtils.RuleListener> & {
6
+ name: string;
7
+ };
8
+ export {};
@@ -0,0 +1,70 @@
1
+ import { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/utils';
2
+ import { getRuleURL } from "../meta.js";
3
+ import { trackZodSchemaImports } from "../utils/track-zod-schema-imports.js";
4
+ export const requireSchemaSuffix = ESLintUtils.RuleCreator(getRuleURL)({
5
+ name: 'require-schema-suffix',
6
+ meta: {
7
+ type: 'suggestion',
8
+ docs: {
9
+ description: 'Require schema suffix when declaring a Zod schema',
10
+ },
11
+ messages: {
12
+ noSchemaSuffix: 'Use the "{{suffix}}" suffix for Zod schemas. Rename this to "{{expected}}"',
13
+ },
14
+ schema: [
15
+ {
16
+ type: 'object',
17
+ properties: {
18
+ suffix: {
19
+ type: 'string',
20
+ description: 'The required suffix for Zod schema variables',
21
+ },
22
+ },
23
+ additionalProperties: false,
24
+ },
25
+ ],
26
+ },
27
+ defaultOptions: [{ suffix: 'Schema' }],
28
+ create(context, [{ suffix }]) {
29
+ const { importDeclarationListener, detectZodSchemaRootNode, collectZodChainMethods, } = trackZodSchemaImports();
30
+ return {
31
+ ImportDeclaration: importDeclarationListener,
32
+ VariableDeclarator(node) {
33
+ const initNode = node.init;
34
+ if ((initNode === null || initNode === void 0 ? void 0 : initNode.type) !== AST_NODE_TYPES.CallExpression ||
35
+ !detectZodSchemaRootNode(initNode)) {
36
+ return;
37
+ }
38
+ const chainMethods = collectZodChainMethods(initNode).map((it) => it.name);
39
+ const methodsThatProduceSomethingThatShouldNotBeValidated = [
40
+ 'parse',
41
+ 'parseAsync',
42
+ 'safeParse',
43
+ 'safeParseAsync',
44
+ 'spa',
45
+ 'encode',
46
+ 'encodeAsync',
47
+ 'decode',
48
+ 'decodeAsync',
49
+ 'safeEncode',
50
+ 'safeEncodeAsync',
51
+ 'safeDecode',
52
+ 'safeDecodeAsync',
53
+ 'codec',
54
+ ];
55
+ if (methodsThatProduceSomethingThatShouldNotBeValidated.some((it) => chainMethods.includes(it))) {
56
+ return;
57
+ }
58
+ if (node.id.type !== AST_NODE_TYPES.Identifier ||
59
+ node.id.name.endsWith(suffix)) {
60
+ return;
61
+ }
62
+ context.report({
63
+ node,
64
+ messageId: 'noSchemaSuffix',
65
+ data: { suffix, expected: `${node.id.name}${suffix}` },
66
+ });
67
+ },
68
+ };
69
+ },
70
+ });
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.schemaErrorPropertyStyle = void 0;
7
+ const utils_1 = require("@typescript-eslint/utils");
8
+ const esquery_1 = __importDefault(require("esquery"));
9
+ const meta_js_1 = require("../meta.cjs");
10
+ const track_zod_schema_imports_js_1 = require("../utils/track-zod-schema-imports.cjs");
11
+ exports.schemaErrorPropertyStyle = utils_1.ESLintUtils.RuleCreator(meta_js_1.getRuleURL)({
12
+ name: 'schema-error-property-style',
13
+ meta: {
14
+ type: 'suggestion',
15
+ docs: {
16
+ description: 'Enforce consistent style for error messages in Zod schema validation (using ESQuery patterns)',
17
+ },
18
+ messages: {
19
+ invalidSelector: 'Invalid ESQuery selector: "{{selector}}"',
20
+ invalidStyle: 'Error message must follow the pattern "{{selector}}" (e.g., {{example}}). Found: {{actual}}.',
21
+ },
22
+ schema: [
23
+ {
24
+ type: 'object',
25
+ properties: {
26
+ selector: {
27
+ description: 'An ESQuery string to match the required pattern',
28
+ type: 'string',
29
+ },
30
+ example: {
31
+ description: 'Example code to help the user understand the required pattern',
32
+ type: 'string',
33
+ },
34
+ },
35
+ additionalProperties: false,
36
+ },
37
+ ],
38
+ },
39
+ defaultOptions: [
40
+ { selector: 'Literal,TemplateLiteral', example: "'error message'" },
41
+ ],
42
+ create(context, [{ selector, example }]) {
43
+ const { importDeclarationListener, detectZodSchemaRootNode, collectZodChainMethods, } = (0, track_zod_schema_imports_js_1.trackZodSchemaImports)();
44
+ try {
45
+ esquery_1.default.parse(selector);
46
+ }
47
+ catch (_a) {
48
+ context.report({
49
+ loc: { line: 1, column: 0 },
50
+ messageId: 'invalidSelector',
51
+ data: { selector },
52
+ });
53
+ return {};
54
+ }
55
+ return {
56
+ ImportDeclaration: importDeclarationListener,
57
+ CallExpression(node) {
58
+ const zodSchemaMeta = detectZodSchemaRootNode(node);
59
+ if (!zodSchemaMeta) {
60
+ return;
61
+ }
62
+ if (zodSchemaMeta.schemaType !== 'custom' &&
63
+ !collectZodChainMethods(node).some((it) => it.name === 'refine')) {
64
+ return;
65
+ }
66
+ if (node.arguments.length < 2) {
67
+ return;
68
+ }
69
+ let errorMessageNode;
70
+ const [, params] = node.arguments;
71
+ switch (params.type) {
72
+ case utils_1.AST_NODE_TYPES.Literal:
73
+ case utils_1.AST_NODE_TYPES.TemplateLiteral:
74
+ errorMessageNode = params;
75
+ break;
76
+ case utils_1.AST_NODE_TYPES.ObjectExpression:
77
+ for (const property of params.properties) {
78
+ if (property.type === utils_1.AST_NODE_TYPES.Property &&
79
+ property.key.type === utils_1.AST_NODE_TYPES.Identifier &&
80
+ property.key.name === 'error') {
81
+ errorMessageNode = property.value;
82
+ break;
83
+ }
84
+ }
85
+ break;
86
+ }
87
+ if (!errorMessageNode) {
88
+ return;
89
+ }
90
+ const match = esquery_1.default.matches(errorMessageNode, esquery_1.default.parse(selector), errorMessageNode);
91
+ if (match) {
92
+ return;
93
+ }
94
+ context.report({
95
+ node,
96
+ messageId: 'invalidStyle',
97
+ data: {
98
+ selector,
99
+ example,
100
+ actual: context.sourceCode.getText(errorMessageNode),
101
+ },
102
+ });
103
+ },
104
+ };
105
+ },
106
+ });
@@ -0,0 +1,9 @@
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+ type MessageIds = 'invalidStyle' | 'invalidSelector';
3
+ export declare const schemaErrorPropertyStyle: ESLintUtils.RuleModule<MessageIds, [{
4
+ selector: string;
5
+ example: string;
6
+ }], unknown, ESLintUtils.RuleListener> & {
7
+ name: string;
8
+ };
9
+ export {};
@@ -0,0 +1,9 @@
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+ type MessageIds = 'invalidStyle' | 'invalidSelector';
3
+ export declare const schemaErrorPropertyStyle: ESLintUtils.RuleModule<MessageIds, [{
4
+ selector: string;
5
+ example: string;
6
+ }], unknown, ESLintUtils.RuleListener> & {
7
+ name: string;
8
+ };
9
+ export {};