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,138 @@
1
+ import { RuleTester } from '@typescript-eslint/rule-tester';
2
+ import dedent from 'dedent';
3
+ import { consistentObjectSchemaType } from './consistent-object-schema-type.js';
4
+ const ruleTester = new RuleTester();
5
+ ruleTester.run(consistentObjectSchemaType.name, consistentObjectSchemaType, {
6
+ valid: [
7
+ {
8
+ name: 'namespace import',
9
+ code: dedent `
10
+ import * as z from 'zod/mini';
11
+ z.object({})
12
+ `,
13
+ },
14
+ {
15
+ name: 'named import',
16
+ code: dedent `
17
+ import { object } from 'zod/mini';
18
+ object({})
19
+ `,
20
+ },
21
+ {
22
+ name: 'named z import',
23
+ code: dedent `
24
+ import { z } from 'zod/mini';
25
+ z.object({})
26
+ `,
27
+ },
28
+ {
29
+ name: 'nested with allowed methods',
30
+ options: [{ allow: ['looseObject', 'strictObject'] }],
31
+ code: dedent `
32
+ import * as z from 'zod/mini';
33
+ z.looseObject({ test: z.strictObject({}) })
34
+ `,
35
+ },
36
+ {
37
+ name: 'not triggered on zod import',
38
+ code: dedent `
39
+ import * as z from 'zod';
40
+ z.looseObject({})
41
+ `,
42
+ },
43
+ {
44
+ name: 'zod/v4-mini import',
45
+ code: dedent `
46
+ import * as z from 'zod/v4-mini';
47
+ z.object({})
48
+ `,
49
+ },
50
+ ],
51
+ invalid: [
52
+ {
53
+ name: 'namespace import — looseObject not allowed by default',
54
+ code: dedent `
55
+ import * as z from 'zod/mini';
56
+ z.looseObject({})
57
+ `,
58
+ errors: [
59
+ {
60
+ messageId: 'consistentMethod',
61
+ data: { actual: 'looseObject', allowedList: 'object' },
62
+ suggestions: [
63
+ {
64
+ messageId: 'useMethod',
65
+ data: { expected: 'object' },
66
+ output: dedent `
67
+ import * as z from 'zod/mini';
68
+ z.object({})
69
+ `,
70
+ },
71
+ ],
72
+ },
73
+ ],
74
+ output: null,
75
+ },
76
+ {
77
+ name: 'named import — no suggestion for Identifier callee',
78
+ code: dedent `
79
+ import { looseObject } from 'zod/mini';
80
+ looseObject()
81
+ `,
82
+ errors: [
83
+ {
84
+ messageId: 'consistentMethod',
85
+ data: { actual: 'looseObject', allowedList: 'object' },
86
+ },
87
+ ],
88
+ output: null,
89
+ },
90
+ {
91
+ name: 'nested looseObject',
92
+ code: dedent `
93
+ import * as z from 'zod/mini';
94
+ z.object({ test: z.looseObject({}) })
95
+ `,
96
+ errors: [
97
+ {
98
+ messageId: 'consistentMethod',
99
+ data: { actual: 'looseObject', allowedList: 'object' },
100
+ suggestions: [
101
+ {
102
+ messageId: 'useMethod',
103
+ data: { expected: 'object' },
104
+ output: dedent `
105
+ import * as z from 'zod/mini';
106
+ z.object({ test: z.object({}) })
107
+ `,
108
+ },
109
+ ],
110
+ },
111
+ ],
112
+ },
113
+ {
114
+ name: 'zod/v4-mini import',
115
+ code: dedent `
116
+ import * as z from 'zod/v4-mini';
117
+ z.looseObject({})
118
+ `,
119
+ errors: [
120
+ {
121
+ messageId: 'consistentMethod',
122
+ data: { actual: 'looseObject', allowedList: 'object' },
123
+ suggestions: [
124
+ {
125
+ messageId: 'useMethod',
126
+ data: { expected: 'object' },
127
+ output: dedent `
128
+ import * as z from 'zod/v4-mini';
129
+ z.object({})
130
+ `,
131
+ },
132
+ ],
133
+ },
134
+ ],
135
+ output: null,
136
+ },
137
+ ],
138
+ });
@@ -0,0 +1,12 @@
1
+ declare const ZOD_SCHEMA_TYPE_STYLES: readonly ["infer", "output"];
2
+ type SchemaTypeStyle = (typeof ZOD_SCHEMA_TYPE_STYLES)[number];
3
+ interface Options {
4
+ style: SchemaTypeStyle;
5
+ }
6
+ type MessageIds = 'useInfer' | 'useOutput';
7
+ export declare const consistentSchemaOutputTypeStyle: import("@typescript-eslint/utils/ts-eslint").RuleModule<MessageIds, [Options], {
8
+ zodImportAllowedSource: "all" | "zod" | "zod-mini";
9
+ }, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
10
+ name: string;
11
+ };
12
+ export {};
@@ -0,0 +1,81 @@
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 ZOD_SCHEMA_TYPE_STYLES = ['infer', 'output'];
5
+ const { zodImportAllowedSource, trackZodSchemaImports, } = createZodSchemaImportTrack('zod-mini');
6
+ export const consistentSchemaOutputTypeStyle = createZodMiniPluginRule({
7
+ name: 'consistent-schema-output-type-style',
8
+ meta: {
9
+ type: 'suggestion',
10
+ fixable: 'code',
11
+ docs: {
12
+ zodImportAllowedSource,
13
+ description: 'Enforce consistent use of z.infer or z.output for schema type inference',
14
+ },
15
+ messages: {
16
+ useInfer: 'Use infer instead of output.',
17
+ useOutput: 'Use output instead of infer.',
18
+ },
19
+ schema: [
20
+ {
21
+ type: 'object',
22
+ properties: {
23
+ style: {
24
+ description: 'Decides which style to use for schema type inference',
25
+ type: 'string',
26
+ enum: [...ZOD_SCHEMA_TYPE_STYLES],
27
+ },
28
+ },
29
+ additionalProperties: false,
30
+ },
31
+ ],
32
+ },
33
+ defaultOptions: [{ style: 'output' }],
34
+ create(context, [{ style }]) {
35
+ const { importDeclarationListener, isZodNamespace, getNamedImportOriginal, getNamedImportLocal, } = trackZodSchemaImports();
36
+ return {
37
+ ImportDeclaration: importDeclarationListener,
38
+ TSTypeReference(node) {
39
+ const { typeName } = node;
40
+ if (typeName.type === AST_NODE_TYPES.TSQualifiedName) {
41
+ const { left, right } = typeName;
42
+ if (left.type !== AST_NODE_TYPES.Identifier ||
43
+ !isZodNamespace(left.name)) {
44
+ return;
45
+ }
46
+ const usedStyle = right.name;
47
+ if ((usedStyle !== 'infer' && usedStyle !== 'output') ||
48
+ usedStyle === style) {
49
+ return;
50
+ }
51
+ context.report({
52
+ node: right,
53
+ messageId: style === 'infer' ? 'useInfer' : 'useOutput',
54
+ fix(fixer) {
55
+ return fixer.replaceText(right, style);
56
+ },
57
+ });
58
+ return;
59
+ }
60
+ if (typeName.type === AST_NODE_TYPES.Identifier) {
61
+ const originalName = getNamedImportOriginal(typeName.name);
62
+ if ((originalName !== 'infer' && originalName !== 'output') ||
63
+ originalName === style) {
64
+ return;
65
+ }
66
+ const targetLocalName = getNamedImportLocal(style);
67
+ context.report({
68
+ node: typeName,
69
+ messageId: style === 'infer' ? 'useInfer' : 'useOutput',
70
+ fix(fixer) {
71
+ if (!targetLocalName || targetLocalName === 'infer') {
72
+ return null;
73
+ }
74
+ return fixer.replaceText(typeName, targetLocalName);
75
+ },
76
+ });
77
+ }
78
+ },
79
+ };
80
+ },
81
+ });
@@ -0,0 +1,128 @@
1
+ import { RuleTester } from '@typescript-eslint/rule-tester';
2
+ import dedent from 'dedent';
3
+ import { consistentSchemaOutputTypeStyle } from './consistent-schema-output-type-style.js';
4
+ const ruleTester = new RuleTester();
5
+ ruleTester.run(`${consistentSchemaOutputTypeStyle.name} (output)`, consistentSchemaOutputTypeStyle, {
6
+ valid: [
7
+ {
8
+ name: 'namespace import',
9
+ code: dedent `
10
+ import * as z from 'zod/mini';
11
+ type SchemaType = z.output<typeof UserSchema>;
12
+ `,
13
+ },
14
+ {
15
+ name: 'named z import',
16
+ code: dedent `
17
+ import { z } from 'zod/mini';
18
+ type SchemaType = z.output<typeof UserSchema>;
19
+ `,
20
+ },
21
+ {
22
+ name: 'zod/v4-mini import',
23
+ code: dedent `
24
+ import * as z from 'zod/v4-mini';
25
+ type SchemaType = z.output<typeof UserSchema>;
26
+ `,
27
+ },
28
+ {
29
+ name: 'non-zod/mini import',
30
+ code: dedent `
31
+ import * as z from '@custom';
32
+ type SchemaType = z.infer<typeof UserSchema>;
33
+ `,
34
+ },
35
+ {
36
+ name: 'not triggered on zod import',
37
+ code: dedent `
38
+ import * as z from 'zod';
39
+ type SchemaType = z.infer<typeof UserSchema>;
40
+ `,
41
+ },
42
+ ],
43
+ invalid: [
44
+ {
45
+ name: 'namespace import',
46
+ code: dedent `
47
+ import * as z from 'zod/mini';
48
+ type SchemaType = z.infer<typeof UserSchema>;
49
+ `,
50
+ errors: [{ messageId: 'useOutput' }],
51
+ output: dedent `
52
+ import * as z from 'zod/mini';
53
+ type SchemaType = z.output<typeof UserSchema>;
54
+ `,
55
+ },
56
+ {
57
+ name: 'named z import',
58
+ code: dedent `
59
+ import { z } from 'zod/mini';
60
+ type SchemaType = z.infer<typeof UserSchema>;
61
+ `,
62
+ errors: [{ messageId: 'useOutput' }],
63
+ output: dedent `
64
+ import { z } from 'zod/mini';
65
+ type SchemaType = z.output<typeof UserSchema>;
66
+ `,
67
+ },
68
+ {
69
+ name: 'aliased namespace import',
70
+ code: dedent `
71
+ import * as myZ from 'zod/mini';
72
+ type SchemaType = myZ.infer<typeof UserSchema>;
73
+ `,
74
+ errors: [{ messageId: 'useOutput' }],
75
+ output: dedent `
76
+ import * as myZ from 'zod/mini';
77
+ type SchemaType = myZ.output<typeof UserSchema>;
78
+ `,
79
+ },
80
+ {
81
+ name: 'zod/v4-mini import',
82
+ code: dedent `
83
+ import * as z from 'zod/v4-mini';
84
+ type SchemaType = z.infer<typeof UserSchema>;
85
+ `,
86
+ errors: [{ messageId: 'useOutput' }],
87
+ output: dedent `
88
+ import * as z from 'zod/v4-mini';
89
+ type SchemaType = z.output<typeof UserSchema>;
90
+ `,
91
+ },
92
+ ],
93
+ });
94
+ ruleTester.run(`${consistentSchemaOutputTypeStyle.name} (infer)`, consistentSchemaOutputTypeStyle, {
95
+ valid: [
96
+ {
97
+ name: 'namespace import',
98
+ code: dedent `
99
+ import * as z from 'zod/mini';
100
+ type SchemaType = z.infer<typeof UserSchema>;
101
+ `,
102
+ options: [{ style: 'infer' }],
103
+ },
104
+ {
105
+ name: 'not triggered on zod import',
106
+ code: dedent `
107
+ import * as z from 'zod';
108
+ type SchemaType = z.output<typeof UserSchema>;
109
+ `,
110
+ options: [{ style: 'infer' }],
111
+ },
112
+ ],
113
+ invalid: [
114
+ {
115
+ name: 'namespace import',
116
+ code: dedent `
117
+ import * as z from 'zod/mini';
118
+ type SchemaType = z.output<typeof UserSchema>;
119
+ `,
120
+ options: [{ style: 'infer' }],
121
+ errors: [{ messageId: 'useInfer' }],
122
+ output: dedent `
123
+ import * as z from 'zod/mini';
124
+ type SchemaType = z.infer<typeof UserSchema>;
125
+ `,
126
+ },
127
+ ],
128
+ });
@@ -0,0 +1,10 @@
1
+ interface Options {
2
+ before?: string;
3
+ after?: string;
4
+ }
5
+ export declare const consistentSchemaVarName: import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidName", [Options], {
6
+ zodImportAllowedSource: "all" | "zod" | "zod-mini";
7
+ }, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
8
+ name: string;
9
+ };
10
+ export {};
@@ -0,0 +1,86 @@
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 consistentSchemaVarName = createZodMiniPluginRule({
6
+ name: 'consistent-schema-var-name',
7
+ meta: {
8
+ type: 'suggestion',
9
+ docs: {
10
+ zodImportAllowedSource,
11
+ description: 'Enforce a consistent naming convention for Zod Mini schema variables',
12
+ },
13
+ messages: {
14
+ invalidName: 'Rename this Zod Mini schema to "{{expected}}"',
15
+ },
16
+ schema: [
17
+ {
18
+ type: 'object',
19
+ properties: {
20
+ before: {
21
+ type: 'string',
22
+ description: 'The required prefix for Zod Mini schema variables',
23
+ },
24
+ after: {
25
+ type: 'string',
26
+ description: 'The required suffix for Zod Mini schema variables',
27
+ },
28
+ },
29
+ additionalProperties: false,
30
+ },
31
+ ],
32
+ },
33
+ defaultOptions: [{ after: 'Schema' }],
34
+ create(context, [{ before = '', after = '' }]) {
35
+ const { importDeclarationListener, detectZodSchemaRootNode, collectZodChainMethods, } = trackZodSchemaImports();
36
+ return {
37
+ ImportDeclaration: importDeclarationListener,
38
+ VariableDeclarator(node) {
39
+ const initNode = node.init;
40
+ if ((initNode === null || initNode === void 0 ? void 0 : initNode.type) !== AST_NODE_TYPES.CallExpression ||
41
+ !detectZodSchemaRootNode(initNode)) {
42
+ return;
43
+ }
44
+ const chainMethods = collectZodChainMethods(initNode).map((it) => it.name);
45
+ const methodsThatProduceSomethingThatShouldNotBeValidated = [
46
+ 'parse',
47
+ 'parseAsync',
48
+ 'safeParse',
49
+ 'safeParseAsync',
50
+ 'spa',
51
+ 'encode',
52
+ 'encodeAsync',
53
+ 'decode',
54
+ 'decodeAsync',
55
+ 'safeEncode',
56
+ 'safeEncodeAsync',
57
+ 'safeDecode',
58
+ 'safeDecodeAsync',
59
+ 'codec',
60
+ 'treeifyError',
61
+ 'prettifyError',
62
+ 'formatError',
63
+ 'flattenError',
64
+ ];
65
+ if (methodsThatProduceSomethingThatShouldNotBeValidated.some((it) => chainMethods.includes(it))) {
66
+ return;
67
+ }
68
+ if (node.id.type !== AST_NODE_TYPES.Identifier) {
69
+ return;
70
+ }
71
+ const { name } = node.id;
72
+ const validPrefix = !before || name.startsWith(before);
73
+ const validSuffix = !after || name.endsWith(after);
74
+ if (validPrefix && validSuffix) {
75
+ return;
76
+ }
77
+ const expected = (validPrefix ? '' : before) + name + (validSuffix ? '' : after);
78
+ context.report({
79
+ node,
80
+ messageId: 'invalidName',
81
+ data: { expected },
82
+ });
83
+ },
84
+ };
85
+ },
86
+ });
@@ -0,0 +1,130 @@
1
+ import { RuleTester } from '@typescript-eslint/rule-tester';
2
+ import dedent from 'dedent';
3
+ import { consistentSchemaVarName } from './consistent-schema-var-name.js';
4
+ const ruleTester = new RuleTester();
5
+ ruleTester.run(consistentSchemaVarName.name, consistentSchemaVarName, {
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: 'named import',
16
+ code: dedent `
17
+ import { string } from 'zod/mini';
18
+ const userSchema = string();
19
+ `,
20
+ },
21
+ {
22
+ name: 'named z import',
23
+ code: dedent `
24
+ import { z } from 'zod/mini';
25
+ const userSchema = z.string();
26
+ `,
27
+ },
28
+ {
29
+ name: 'with parse()',
30
+ code: dedent `
31
+ import * as z from 'zod/mini';
32
+ const value = z.string().parse("asd")
33
+ `,
34
+ },
35
+ {
36
+ name: 'ignores non-zod/mini',
37
+ code: dedent `
38
+ import * as z from 'zod/mini';
39
+ const myVar = 1
40
+ `,
41
+ },
42
+ {
43
+ name: 'not triggered on zod import',
44
+ code: dedent `
45
+ import * as z from 'zod';
46
+ const myVar = z.string();
47
+ `,
48
+ },
49
+ {
50
+ name: 'custom suffix',
51
+ code: dedent `
52
+ import * as z from 'zod/mini';
53
+ const userVar = z.string();
54
+ `,
55
+ options: [{ after: 'Var' }],
56
+ },
57
+ {
58
+ name: 'prefix only',
59
+ code: dedent `
60
+ import * as z from 'zod/mini';
61
+ const $user = z.string();
62
+ `,
63
+ options: [{ before: '$', after: '' }],
64
+ },
65
+ {
66
+ name: 'both prefix and suffix',
67
+ code: dedent `
68
+ import * as z from 'zod/mini';
69
+ const $userSchema = z.string();
70
+ `,
71
+ options: [{ before: '$', after: 'Schema' }],
72
+ },
73
+ {
74
+ name: 'zod/v4-mini import',
75
+ code: dedent `
76
+ import * as z from 'zod/v4-mini';
77
+ const userSchema = z.string();
78
+ `,
79
+ },
80
+ ],
81
+ invalid: [
82
+ {
83
+ name: 'namespace (missing suffix)',
84
+ code: dedent `
85
+ import * as z from 'zod/mini';
86
+ const myVar = z.string();
87
+ `,
88
+ errors: [{ messageId: 'invalidName', data: { expected: 'myVarSchema' } }],
89
+ output: null,
90
+ },
91
+ {
92
+ name: 'named import (missing suffix)',
93
+ code: dedent `
94
+ import { string } from 'zod/mini';
95
+ const myVar = string();
96
+ `,
97
+ errors: [{ messageId: 'invalidName', data: { expected: 'myVarSchema' } }],
98
+ output: null,
99
+ },
100
+ {
101
+ name: 'missing prefix only',
102
+ code: dedent `
103
+ import * as z from 'zod/mini';
104
+ const user = z.string();
105
+ `,
106
+ options: [{ before: '$', after: '' }],
107
+ errors: [{ messageId: 'invalidName', data: { expected: '$user' } }],
108
+ output: null,
109
+ },
110
+ {
111
+ name: 'missing both prefix and suffix',
112
+ code: dedent `
113
+ import * as z from 'zod/mini';
114
+ const user = z.string();
115
+ `,
116
+ options: [{ before: '$', after: 'Schema' }],
117
+ errors: [{ messageId: 'invalidName', data: { expected: '$userSchema' } }],
118
+ output: null,
119
+ },
120
+ {
121
+ name: 'zod/v4-mini import (missing suffix)',
122
+ code: dedent `
123
+ import * as z from 'zod/v4-mini';
124
+ const myVar = z.string();
125
+ `,
126
+ errors: [{ messageId: 'invalidName', data: { expected: 'myVarSchema' } }],
127
+ output: null,
128
+ },
129
+ ],
130
+ });
@@ -0,0 +1,6 @@
1
+ import type { TSESLint } from '@typescript-eslint/utils';
2
+ export declare const noAnySchema: TSESLint.RuleModule<"noZAny" | "useUnknown", [], {
3
+ zodImportAllowedSource: "all" | "zod" | "zod-mini";
4
+ }, TSESLint.RuleListener> & {
5
+ name: string;
6
+ };
@@ -0,0 +1,65 @@
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 noAnySchema = createZodMiniPluginRule({
6
+ name: 'no-any-schema',
7
+ meta: {
8
+ hasSuggestions: true,
9
+ type: 'suggestion',
10
+ docs: {
11
+ zodImportAllowedSource,
12
+ description: 'Disallow usage of `z.any()` in Zod Mini schemas',
13
+ },
14
+ messages: {
15
+ noZAny: 'Using `z.any()` is not allowed. Please use a more specific schema.',
16
+ useUnknown: 'Replace `z.any()` with `z.unknown()`',
17
+ },
18
+ schema: [],
19
+ },
20
+ defaultOptions: [],
21
+ create(context) {
22
+ const { importDeclarationListener, detectZodSchemaRootNode, collectZodChainMethods, } = trackZodSchemaImports();
23
+ return {
24
+ ImportDeclaration: importDeclarationListener,
25
+ CallExpression(node) {
26
+ const zodSchemaMeta = detectZodSchemaRootNode(node);
27
+ if ((zodSchemaMeta === null || zodSchemaMeta === void 0 ? void 0 : zodSchemaMeta.schemaType) !== 'any') {
28
+ return;
29
+ }
30
+ const { callee } = node;
31
+ if (callee.type === AST_NODE_TYPES.Identifier) {
32
+ context.report({
33
+ node,
34
+ messageId: 'noZAny',
35
+ });
36
+ return;
37
+ }
38
+ if (callee.type === AST_NODE_TYPES.MemberExpression) {
39
+ const [{ node: schemaMethod }] = collectZodChainMethods(node);
40
+ const schemaMethodCallee = schemaMethod.callee;
41
+ if (schemaMethodCallee.type === AST_NODE_TYPES.MemberExpression &&
42
+ schemaMethodCallee.property.type === AST_NODE_TYPES.Identifier) {
43
+ context.report({
44
+ node,
45
+ messageId: 'noZAny',
46
+ suggest: [
47
+ {
48
+ messageId: 'useUnknown',
49
+ fix(fixer) {
50
+ return fixer.replaceText(schemaMethodCallee.property, 'unknown');
51
+ },
52
+ },
53
+ ],
54
+ });
55
+ return;
56
+ }
57
+ context.report({
58
+ node,
59
+ messageId: 'noZAny',
60
+ });
61
+ }
62
+ },
63
+ };
64
+ },
65
+ });
@@ -0,0 +1 @@
1
+ export {};