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,161 @@
1
+ import { RuleTester } from '@typescript-eslint/rule-tester';
2
+ import dedent from 'dedent';
3
+ import { requireErrorMessage } from './require-error-message.js';
4
+ const ruleTester = new RuleTester();
5
+ ruleTester.run(requireErrorMessage.name, requireErrorMessage, {
6
+ valid: [
7
+ {
8
+ name: 'object with error property (namespace import)',
9
+ code: dedent `
10
+ import * as z from 'zod/mini';
11
+ z.string().check(z.refine(() => true, { error: "error msg" }));
12
+ `,
13
+ },
14
+ {
15
+ name: 'object with error property (named import)',
16
+ code: dedent `
17
+ import { string, refine } from 'zod/mini';
18
+ string().check(refine(() => true, { error: "error msg" }));
19
+ `,
20
+ },
21
+ {
22
+ name: 'object with error property (named z import)',
23
+ code: dedent `
24
+ import { z } from 'zod/mini';
25
+ z.string().check(z.refine(() => true, { error: "error msg" }));
26
+ `,
27
+ },
28
+ {
29
+ name: 'string error message',
30
+ code: dedent `
31
+ import * as z from 'zod/mini';
32
+ z.string().check(z.refine(() => true, "error msg"));
33
+ `,
34
+ },
35
+ {
36
+ name: 'multiple chained checks with error',
37
+ code: dedent `
38
+ import * as z from 'zod/mini';
39
+ z.string()
40
+ .check(z.refine(() => true, { error: "error msg 1" }))
41
+ .check(z.refine(() => true, { error: "error msg 2" }));
42
+ `,
43
+ },
44
+ {
45
+ name: 'not triggered on zod import',
46
+ code: dedent `
47
+ import * as z from 'zod';
48
+ z.string().refine(() => true);
49
+ `,
50
+ },
51
+ ],
52
+ invalid: [
53
+ {
54
+ name: 'missing error message parameter',
55
+ code: dedent `
56
+ import * as z from 'zod/mini';
57
+ z.string().check(z.refine(() => true));
58
+ `,
59
+ errors: [{ messageId: 'requireErrorMessage' }],
60
+ output: null,
61
+ },
62
+ {
63
+ name: 'missing error message (named import)',
64
+ code: dedent `
65
+ import { string, refine } from 'zod/mini';
66
+ string().check(refine(() => true));
67
+ `,
68
+ errors: [{ messageId: 'requireErrorMessage' }],
69
+ output: null,
70
+ },
71
+ {
72
+ name: 'object without error message',
73
+ code: dedent `
74
+ import * as z from 'zod/mini';
75
+ z.string().check(z.refine(() => true, { abort: true }));
76
+ `,
77
+ errors: [{ messageId: 'requireErrorMessage' }],
78
+ output: null,
79
+ },
80
+ {
81
+ name: 'deprecated message property',
82
+ code: dedent `
83
+ import * as z from 'zod/mini';
84
+ z.string().check(z.refine(() => true, { message: "hello" }));
85
+ `,
86
+ errors: [{ messageId: 'preferError' }],
87
+ output: dedent `
88
+ import * as z from 'zod/mini';
89
+ z.string().check(z.refine(() => true, { error: "hello" }));
90
+ `,
91
+ },
92
+ {
93
+ name: 'both message and error — remove message',
94
+ code: dedent `
95
+ import * as z from 'zod/mini';
96
+ z.string().check(z.refine(() => true, { message: "hello", error: "hello" }));
97
+ `,
98
+ errors: [{ messageId: 'removeMessage' }],
99
+ output: dedent `
100
+ import * as z from 'zod/mini';
101
+ z.string().check(z.refine(() => true, { error: "hello" }));
102
+ `,
103
+ },
104
+ {
105
+ name: 'zod/v4-mini import',
106
+ code: dedent `
107
+ import * as z from 'zod/v4-mini';
108
+ z.string().check(z.refine(() => true));
109
+ `,
110
+ errors: [{ messageId: 'requireErrorMessage' }],
111
+ output: null,
112
+ },
113
+ ],
114
+ });
115
+ ruleTester.run(`${requireErrorMessage.name} (custom)`, requireErrorMessage, {
116
+ valid: [
117
+ {
118
+ name: 'object with error property',
119
+ code: dedent `
120
+ import * as z from 'zod/mini';
121
+ z.custom(() => true, { error: "hello there" });
122
+ `,
123
+ },
124
+ {
125
+ name: 'string error message',
126
+ code: dedent `
127
+ import * as z from 'zod/mini';
128
+ z.custom(() => true, "error msg");
129
+ `,
130
+ },
131
+ ],
132
+ invalid: [
133
+ {
134
+ name: 'missing error message parameter',
135
+ code: dedent `
136
+ import * as z from 'zod/mini';
137
+ z.custom(() => true)
138
+ `,
139
+ errors: [{ messageId: 'requireErrorMessage' }],
140
+ output: null,
141
+ },
142
+ {
143
+ name: 'missing error message parameter (named)',
144
+ code: dedent `
145
+ import { custom } from 'zod/mini';
146
+ custom(() => true)
147
+ `,
148
+ errors: [{ messageId: 'requireErrorMessage' }],
149
+ output: null,
150
+ },
151
+ {
152
+ name: 'object without error message',
153
+ code: dedent `
154
+ import * as z from 'zod/mini';
155
+ z.custom(() => true, { abort: true });
156
+ `,
157
+ errors: [{ messageId: 'requireErrorMessage' }],
158
+ output: null,
159
+ },
160
+ ],
161
+ });
@@ -0,0 +1,9 @@
1
+ interface Options {
2
+ suffix: string;
3
+ }
4
+ export declare const requireSchemaSuffix: import("@typescript-eslint/utils/ts-eslint").RuleModule<"noSchemaSuffix", [Options], {
5
+ zodImportAllowedSource: "all" | "zod" | "zod-mini";
6
+ }, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
7
+ name: string;
8
+ };
9
+ export {};
@@ -0,0 +1,79 @@
1
+ import { createZodSchemaImportTrack } from '@eslint-zod/utils';
2
+ import { AST_NODE_TYPES } from '@typescript-eslint/utils';
3
+ import { createZodMiniPluginRule } from '../utils/create-plugin-rule.js';
4
+ const { zodImportAllowedSource, trackZodSchemaImports, } = createZodSchemaImportTrack('zod-mini');
5
+ export const requireSchemaSuffix = createZodMiniPluginRule({
6
+ name: 'require-schema-suffix',
7
+ meta: {
8
+ type: 'suggestion',
9
+ deprecated: {
10
+ message: 'Use `zod-mini/consistent-schema-var-name`',
11
+ },
12
+ docs: {
13
+ zodImportAllowedSource,
14
+ description: 'Require schema suffix when declaring a Zod Mini schema',
15
+ },
16
+ messages: {
17
+ noSchemaSuffix: 'Use the "{{suffix}}" suffix for Zod Mini schemas. Rename this to "{{expected}}"',
18
+ },
19
+ schema: [
20
+ {
21
+ type: 'object',
22
+ properties: {
23
+ suffix: {
24
+ type: 'string',
25
+ description: 'The required suffix for Zod Mini schema variables',
26
+ },
27
+ },
28
+ additionalProperties: false,
29
+ },
30
+ ],
31
+ },
32
+ defaultOptions: [{ suffix: 'Schema' }],
33
+ create(context, [{ suffix }]) {
34
+ const { importDeclarationListener, detectZodSchemaRootNode, collectZodChainMethods, } = trackZodSchemaImports();
35
+ return {
36
+ ImportDeclaration: importDeclarationListener,
37
+ VariableDeclarator(node) {
38
+ const initNode = node.init;
39
+ if ((initNode === null || initNode === void 0 ? void 0 : initNode.type) !== AST_NODE_TYPES.CallExpression ||
40
+ !detectZodSchemaRootNode(initNode)) {
41
+ return;
42
+ }
43
+ const chainMethods = collectZodChainMethods(initNode).map((it) => it.name);
44
+ const methodsThatProduceSomethingThatShouldNotBeValidated = [
45
+ 'parse',
46
+ 'parseAsync',
47
+ 'safeParse',
48
+ 'safeParseAsync',
49
+ 'spa',
50
+ 'encode',
51
+ 'encodeAsync',
52
+ 'decode',
53
+ 'decodeAsync',
54
+ 'safeEncode',
55
+ 'safeEncodeAsync',
56
+ 'safeDecode',
57
+ 'safeDecodeAsync',
58
+ 'codec',
59
+ 'treeifyError',
60
+ 'prettifyError',
61
+ 'formatError',
62
+ 'flattenError',
63
+ ];
64
+ if (methodsThatProduceSomethingThatShouldNotBeValidated.some((it) => chainMethods.includes(it))) {
65
+ return;
66
+ }
67
+ if (node.id.type !== AST_NODE_TYPES.Identifier ||
68
+ node.id.name.endsWith(suffix)) {
69
+ return;
70
+ }
71
+ context.report({
72
+ node,
73
+ messageId: 'noSchemaSuffix',
74
+ data: { suffix, expected: `${node.id.name}${suffix}` },
75
+ });
76
+ },
77
+ };
78
+ },
79
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,131 @@
1
+ import { RuleTester } from '@typescript-eslint/rule-tester';
2
+ import dedent from 'dedent';
3
+ import { requireSchemaSuffix } from './require-schema-suffix.js';
4
+ const ruleTester = new RuleTester();
5
+ ruleTester.run(requireSchemaSuffix.name, requireSchemaSuffix, {
6
+ valid: [
7
+ {
8
+ name: 'valid (default suffix)',
9
+ code: dedent `
10
+ import * as z from 'zod/mini';
11
+ const userSchema = z.string();
12
+ `,
13
+ },
14
+ {
15
+ name: 'valid with multiple declarations',
16
+ code: dedent `
17
+ import * as z from 'zod/mini';
18
+ const userSchema = z.string(), addressSchema = z.object({ street: z.string() });
19
+ `,
20
+ },
21
+ {
22
+ name: 'with parse()',
23
+ code: dedent `
24
+ import * as z from 'zod/mini';
25
+ const value = z.string().parse("asd")
26
+ `,
27
+ },
28
+ {
29
+ name: 'custom suffix',
30
+ code: dedent `
31
+ import * as z from 'zod/mini';
32
+ const userVar = z.string()
33
+ `,
34
+ options: [{ suffix: 'Var' }],
35
+ },
36
+ {
37
+ name: 'not triggered on zod import',
38
+ code: dedent `
39
+ import * as z from 'zod';
40
+ const myVar = z.string();
41
+ `,
42
+ },
43
+ {
44
+ name: 'ignores non-zod/mini values',
45
+ code: dedent `
46
+ import * as z from 'zod/mini';
47
+ const myVar = 1
48
+ `,
49
+ },
50
+ {
51
+ name: 'zod/v4-mini import',
52
+ code: dedent `
53
+ import * as z from 'zod/v4-mini';
54
+ const userSchema = z.string();
55
+ `,
56
+ },
57
+ ],
58
+ invalid: [
59
+ {
60
+ name: 'namespace (missing suffix)',
61
+ code: dedent `
62
+ import * as z from 'zod/mini';
63
+ const myVar = z.string();
64
+ `,
65
+ errors: [
66
+ {
67
+ messageId: 'noSchemaSuffix',
68
+ data: { suffix: 'Schema', expected: 'myVarSchema' },
69
+ },
70
+ ],
71
+ output: null,
72
+ },
73
+ {
74
+ name: 'named import (missing suffix)',
75
+ code: dedent `
76
+ import { string } from 'zod/mini';
77
+ const myVar = string();
78
+ `,
79
+ errors: [
80
+ {
81
+ messageId: 'noSchemaSuffix',
82
+ data: { suffix: 'Schema', expected: 'myVarSchema' },
83
+ },
84
+ ],
85
+ output: null,
86
+ },
87
+ {
88
+ name: 'chained method (missing suffix)',
89
+ code: dedent `
90
+ import * as z from 'zod/mini';
91
+ const myVar = z.string().check(z.min(1));
92
+ `,
93
+ errors: [
94
+ {
95
+ messageId: 'noSchemaSuffix',
96
+ data: { suffix: 'Schema', expected: 'myVarSchema' },
97
+ },
98
+ ],
99
+ output: null,
100
+ },
101
+ {
102
+ name: 'custom suffix (missing)',
103
+ code: dedent `
104
+ import * as z from 'zod/mini';
105
+ const myString = z.string()
106
+ `,
107
+ options: [{ suffix: '_schema' }],
108
+ errors: [
109
+ {
110
+ messageId: 'noSchemaSuffix',
111
+ data: { suffix: '_schema', expected: 'myString_schema' },
112
+ },
113
+ ],
114
+ output: null,
115
+ },
116
+ {
117
+ name: 'zod/v4-mini import (missing suffix)',
118
+ code: dedent `
119
+ import * as z from 'zod/v4-mini';
120
+ const myVar = z.string();
121
+ `,
122
+ errors: [
123
+ {
124
+ messageId: 'noSchemaSuffix',
125
+ data: { suffix: 'Schema', expected: 'myVarSchema' },
126
+ },
127
+ ],
128
+ output: null,
129
+ },
130
+ ],
131
+ });
@@ -0,0 +1,10 @@
1
+ type MessageIds = 'invalidStyle' | 'invalidSelector';
2
+ export declare const schemaErrorPropertyStyle: import("@typescript-eslint/utils/ts-eslint").RuleModule<MessageIds, [{
3
+ selector: string;
4
+ example: string;
5
+ }], {
6
+ zodImportAllowedSource: "all" | "zod" | "zod-mini";
7
+ }, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
8
+ name: string;
9
+ };
10
+ export {};
@@ -0,0 +1,102 @@
1
+ import { createZodSchemaImportTrack } from '@eslint-zod/utils';
2
+ import { AST_NODE_TYPES } from '@typescript-eslint/utils';
3
+ import esquery from 'esquery';
4
+ import { createZodMiniPluginRule } from '../utils/create-plugin-rule.js';
5
+ const { zodImportAllowedSource, trackZodSchemaImports, } = createZodSchemaImportTrack('zod-mini');
6
+ export const schemaErrorPropertyStyle = createZodMiniPluginRule({
7
+ name: 'schema-error-property-style',
8
+ meta: {
9
+ type: 'suggestion',
10
+ docs: {
11
+ zodImportAllowedSource,
12
+ description: 'Enforce consistent style for error messages in Zod Mini schema validation (using ESQuery patterns)',
13
+ },
14
+ messages: {
15
+ invalidSelector: 'Invalid ESQuery selector: "{{selector}}"',
16
+ invalidStyle: 'Error message must follow the pattern "{{selector}}" (e.g., {{example}}). Found: {{actual}}.',
17
+ },
18
+ schema: [
19
+ {
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
+ },
35
+ defaultOptions: [
36
+ { selector: 'Literal,TemplateLiteral', example: "'error message'" },
37
+ ],
38
+ create(context, [{ selector, example }]) {
39
+ const { importDeclarationListener, detectZodSchemaRootNode, collectZodChainMethods, } = trackZodSchemaImports();
40
+ try {
41
+ esquery.parse(selector);
42
+ }
43
+ catch (_a) {
44
+ context.report({
45
+ loc: { line: 1, column: 0 },
46
+ messageId: 'invalidSelector',
47
+ data: { selector },
48
+ });
49
+ return {};
50
+ }
51
+ return {
52
+ ImportDeclaration: importDeclarationListener,
53
+ CallExpression(node) {
54
+ const zodSchemaMeta = detectZodSchemaRootNode(node);
55
+ if (!zodSchemaMeta) {
56
+ return;
57
+ }
58
+ if (zodSchemaMeta.schemaType !== 'custom' &&
59
+ !collectZodChainMethods(node).some((it) => it.name === 'refine')) {
60
+ return;
61
+ }
62
+ if (node.arguments.length < 2) {
63
+ return;
64
+ }
65
+ let errorMessageNode;
66
+ const [, params] = node.arguments;
67
+ switch (params.type) {
68
+ case AST_NODE_TYPES.Literal:
69
+ case AST_NODE_TYPES.TemplateLiteral:
70
+ errorMessageNode = params;
71
+ break;
72
+ case AST_NODE_TYPES.ObjectExpression:
73
+ for (const property of params.properties) {
74
+ if (property.type === AST_NODE_TYPES.Property &&
75
+ property.key.type === AST_NODE_TYPES.Identifier &&
76
+ property.key.name === 'error') {
77
+ errorMessageNode = property.value;
78
+ break;
79
+ }
80
+ }
81
+ break;
82
+ }
83
+ if (!errorMessageNode) {
84
+ return;
85
+ }
86
+ const match = esquery.matches(errorMessageNode, esquery.parse(selector), errorMessageNode);
87
+ if (match) {
88
+ return;
89
+ }
90
+ context.report({
91
+ node,
92
+ messageId: 'invalidStyle',
93
+ data: {
94
+ selector,
95
+ example,
96
+ actual: context.sourceCode.getText(errorMessageNode),
97
+ },
98
+ });
99
+ },
100
+ };
101
+ },
102
+ });
@@ -0,0 +1,134 @@
1
+ import { RuleTester } from '@typescript-eslint/rule-tester';
2
+ import dedent from 'dedent';
3
+ import { schemaErrorPropertyStyle } from './schema-error-property-style.js';
4
+ const ruleTester = new RuleTester();
5
+ ruleTester.run(schemaErrorPropertyStyle.name, schemaErrorPropertyStyle, {
6
+ valid: [
7
+ {
8
+ name: 'default option (namespace import)',
9
+ code: dedent `
10
+ import * as z from 'zod/mini';
11
+ z.custom(() => true, { error: "my error" })
12
+ `,
13
+ },
14
+ {
15
+ name: 'default option (named import)',
16
+ code: dedent `
17
+ import { custom } from 'zod/mini';
18
+ custom(() => true, { error: "my error" })
19
+ `,
20
+ },
21
+ {
22
+ name: 'default option (named z import)',
23
+ code: dedent `
24
+ import { z } from 'zod/mini';
25
+ z.custom(() => true, { error: "my error" })
26
+ `,
27
+ },
28
+ {
29
+ name: 'not triggered on zod import',
30
+ code: dedent `
31
+ import { custom } from 'zod';
32
+ custom(() => true, { error: () => "my error" })
33
+ `,
34
+ },
35
+ {
36
+ name: 'template string',
37
+ code: dedent `
38
+ import * as z from 'zod/mini';
39
+ z.custom(() => true, \`asd\`);
40
+ `,
41
+ },
42
+ ],
43
+ invalid: [
44
+ {
45
+ name: 'arrow function error value',
46
+ code: dedent `
47
+ import * as z from 'zod/mini';
48
+ z.custom(() => true, { error: () => "my error" })
49
+ `,
50
+ errors: [
51
+ {
52
+ messageId: 'invalidStyle',
53
+ data: {
54
+ selector: 'Literal,TemplateLiteral',
55
+ example: "'error message'",
56
+ actual: '() => "my error"',
57
+ },
58
+ },
59
+ ],
60
+ output: null,
61
+ },
62
+ {
63
+ name: 'invalid ESQuery selector',
64
+ options: [{ selector: '>!asd', example: 'test' }],
65
+ code: dedent `
66
+ import * as z from 'zod/mini';
67
+ z.custom(() => true, \`template string\`)
68
+ `,
69
+ errors: [
70
+ {
71
+ messageId: 'invalidSelector',
72
+ data: { selector: '>!asd' },
73
+ },
74
+ ],
75
+ output: null,
76
+ },
77
+ {
78
+ name: 'zod/v4-mini import',
79
+ code: dedent `
80
+ import * as z from 'zod/v4-mini';
81
+ z.custom(() => true, { error: () => "my error" })
82
+ `,
83
+ errors: [
84
+ {
85
+ messageId: 'invalidStyle',
86
+ data: {
87
+ selector: 'Literal,TemplateLiteral',
88
+ example: "'error message'",
89
+ actual: '() => "my error"',
90
+ },
91
+ },
92
+ ],
93
+ output: null,
94
+ },
95
+ ],
96
+ });
97
+ ruleTester.run(`${schemaErrorPropertyStyle.name} (refine)`, schemaErrorPropertyStyle, {
98
+ valid: [
99
+ {
100
+ name: 'default option',
101
+ code: dedent `
102
+ import * as z from 'zod/mini';
103
+ z.string().check(z.refine(() => true, { error: "my error" }));
104
+ `,
105
+ },
106
+ {
107
+ name: 'template string',
108
+ code: dedent `
109
+ import * as z from 'zod/mini';
110
+ z.string().check(z.refine(() => true, \`asd\`));
111
+ `,
112
+ },
113
+ ],
114
+ invalid: [
115
+ {
116
+ name: 'arrow function error value',
117
+ code: dedent `
118
+ import * as z from 'zod/mini';
119
+ z.string().check(z.refine(() => true, { error: () => "my error" }))
120
+ `,
121
+ errors: [
122
+ {
123
+ messageId: 'invalidStyle',
124
+ data: {
125
+ selector: 'Literal,TemplateLiteral',
126
+ example: "'error message'",
127
+ actual: '() => "my error"',
128
+ },
129
+ },
130
+ ],
131
+ output: null,
132
+ },
133
+ ],
134
+ });
@@ -0,0 +1,8 @@
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+ export declare const createZodMiniPluginRule: <Options extends readonly unknown[], MessageIds extends string>({ meta, name, ...rule }: Readonly<ESLintUtils.RuleWithMetaAndName<Options, MessageIds, {
3
+ zodImportAllowedSource: "all" | "zod" | "zod-mini";
4
+ }>>) => ESLintUtils.RuleModule<MessageIds, Options, {
5
+ zodImportAllowedSource: "all" | "zod" | "zod-mini";
6
+ }, ESLintUtils.RuleListener> & {
7
+ name: string;
8
+ };
@@ -0,0 +1,3 @@
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+ import { getRuleURL } from '../meta.js';
3
+ export const createZodMiniPluginRule = ESLintUtils.RuleCreator(getRuleURL);
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,12 @@
1
+ import { RuleTester } from '@typescript-eslint/rule-tester';
2
+ import { afterAll, describe, it } from 'vitest';
3
+ RuleTester.describe = (...args) => {
4
+ describe(...args);
5
+ };
6
+ RuleTester.describeSkip = (...args) => {
7
+ describe.skip(...args);
8
+ };
9
+ RuleTester.it = it;
10
+ RuleTester.itOnly = it.only;
11
+ RuleTester.itSkip = it.skip;
12
+ RuleTester.afterAll = afterAll;