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,152 @@
1
+ import { createZodMiniPluginRule } from "../utils/create-plugin-rule.mjs";
2
+ import { isZodImportSource } from "@eslint-zod/utils";
3
+ import { AST_NODE_TYPES } from "@typescript-eslint/utils";
4
+ //#region src/rules/consistent-import.ts
5
+ const IMPORT_SYNTAXES = ["namespace", "named"];
6
+ /**
7
+ * Determines whether the first import in a group is valid for a given import
8
+ * syntax (`named` or `namespace`), taking into account whether the group
9
+ * contains only type imports.
10
+ *
11
+ * Rules enforced:
12
+ * - For `named` syntax:
13
+ * - The first import must have exactly one specifier
14
+ * - That specifier must be a named import of identifier `z`
15
+ * - For `namespace` syntax:
16
+ * - The first import must have exactly one namespace specifier
17
+ * - If the group contains only type imports, the first import must explicitly
18
+ * be declared as `import type`
19
+ *
20
+ * @param group - Metadata describing the import group
21
+ * @param syntax - Expected import syntax for the group
22
+ * @returns `true` if the first import matches the expected syntax and type rules
23
+ */
24
+ function isGroupFirstImportKindValidForSyntax(group, syntax) {
25
+ const { hasOnlyTypeImports, nodes } = group;
26
+ const [firstImportNode] = nodes;
27
+ const { specifiers, importKind } = firstImportNode;
28
+ if (specifiers.length !== 1) return false;
29
+ const [specifier] = specifiers;
30
+ if (!(syntax === "named" ? specifier.type === AST_NODE_TYPES.ImportSpecifier && specifier.imported.type === AST_NODE_TYPES.Identifier && specifier.imported.name === "z" : specifier.type === AST_NODE_TYPES.ImportNamespaceSpecifier)) return false;
31
+ if (hasOnlyTypeImports) return importKind === "type";
32
+ return true;
33
+ }
34
+ function shouldIdentifierBeRenamed(node) {
35
+ if (node.parent.type === AST_NODE_TYPES.ImportSpecifier) return false;
36
+ if (node.parent.type === AST_NODE_TYPES.MemberExpression && node.parent.object.type === AST_NODE_TYPES.Identifier && node.parent.object.name !== node.name) return false;
37
+ return true;
38
+ }
39
+ /**
40
+ * From a given specifiers retrieve the most significant to use when creating an alias import
41
+ */
42
+ function getNamespaceAliasNameFrom(node) {
43
+ if (node.type === AST_NODE_TYPES.ImportDefaultSpecifier || node.type === AST_NODE_TYPES.ImportNamespaceSpecifier) return node.local.name;
44
+ if (node.imported.type === AST_NODE_TYPES.Identifier && node.imported.name === "z") return node.local.name;
45
+ return null;
46
+ }
47
+ const consistentImport = createZodMiniPluginRule({
48
+ name: "consistent-import",
49
+ meta: {
50
+ type: "problem",
51
+ docs: {
52
+ zodImportAllowedSource: "zod-mini",
53
+ description: "Enforce a consistent import style for Zod Mini"
54
+ },
55
+ fixable: "code",
56
+ messages: {
57
+ changeImportSyntax: "Use a {{syntax}} import for Zod Mini.",
58
+ removeDuplicate: "Remove duplicate Zod Mini import; Zod Mini is already imported.",
59
+ convertUsage: "Update Zod Mini usage to match the {{syntax}} import syntax."
60
+ },
61
+ schema: [{
62
+ type: "object",
63
+ properties: { syntax: {
64
+ description: "Specifies the import syntax to use for Zod Mini.",
65
+ type: "string",
66
+ enum: IMPORT_SYNTAXES
67
+ } },
68
+ additionalProperties: false
69
+ }]
70
+ },
71
+ defaultOptions: [{ syntax: "namespace" }],
72
+ create(context, [options]) {
73
+ const { syntax } = options;
74
+ const { sourceCode } = context;
75
+ const importGroups = {};
76
+ return {
77
+ ImportDeclaration(node) {
78
+ const { source, importKind } = node;
79
+ if (!isZodImportSource(source.value, "zod-mini")) return;
80
+ if (!importGroups[source.value]) importGroups[source.value] = {
81
+ hasOnlyTypeImports: true,
82
+ nodes: []
83
+ };
84
+ if (importGroups[source.value].hasOnlyTypeImports && importKind === "value") importGroups[source.value].hasOnlyTypeImports = false;
85
+ importGroups[source.value].nodes.push(node);
86
+ },
87
+ "Program:exit": function() {
88
+ let namespaceAliasNameIndex = 0;
89
+ for (const importGroup of Object.values(importGroups)) {
90
+ const { hasOnlyTypeImports, nodes } = importGroup;
91
+ const [firstImportNode, ...othersImportNodes] = nodes;
92
+ /**
93
+ * Variable to track all specifiers that later are used by {@link getDeclaredVariables}
94
+ * to add the namespace prefix
95
+ */
96
+ const nodesWithVariablesToUpdate = [];
97
+ let namespaceAliasName = null;
98
+ for (const specifier of nodes.flatMap((it) => it.specifiers)) {
99
+ if (!namespaceAliasName) {
100
+ namespaceAliasName = getNamespaceAliasNameFrom(specifier);
101
+ if (namespaceAliasName) continue;
102
+ }
103
+ nodesWithVariablesToUpdate.push(specifier);
104
+ }
105
+ if (!namespaceAliasName) {
106
+ namespaceAliasName = "z";
107
+ if (namespaceAliasNameIndex > 0) {
108
+ namespaceAliasName = `z${namespaceAliasNameIndex}`;
109
+ namespaceAliasNameIndex += 1;
110
+ }
111
+ }
112
+ if (!isGroupFirstImportKindValidForSyntax(importGroup, syntax)) context.report({
113
+ node: firstImportNode,
114
+ messageId: "changeImportSyntax",
115
+ data: { syntax },
116
+ fix(fixer) {
117
+ const importTypeKeyword = hasOnlyTypeImports ? "type " : "";
118
+ let importSpecifier;
119
+ if (syntax === "named") if (namespaceAliasName === "z") importSpecifier = "{ z }";
120
+ else importSpecifier = `{ z as ${namespaceAliasName} }`;
121
+ else importSpecifier = `* as ${namespaceAliasName}`;
122
+ const newImportText = `import ${importTypeKeyword}${importSpecifier} from ${firstImportNode.source.raw};`;
123
+ return fixer.replaceText(firstImportNode, newImportText);
124
+ }
125
+ });
126
+ const allReferences = nodesWithVariablesToUpdate.flatMap((it) => sourceCode.getDeclaredVariables(it)).flatMap((it) => it.references);
127
+ for (const ref of allReferences) {
128
+ const { identifier } = ref;
129
+ if (shouldIdentifierBeRenamed(identifier)) context.report({
130
+ node: identifier,
131
+ messageId: "convertUsage",
132
+ data: { syntax },
133
+ fix(fixer) {
134
+ const newId = `${namespaceAliasName}.${identifier.name}`;
135
+ return fixer.replaceText(identifier, newId);
136
+ }
137
+ });
138
+ }
139
+ for (const extraImport of othersImportNodes) context.report({
140
+ node: extraImport,
141
+ messageId: "removeDuplicate",
142
+ fix(fixer) {
143
+ return fixer.removeRange(extraImport.range);
144
+ }
145
+ });
146
+ }
147
+ }
148
+ };
149
+ }
150
+ });
151
+ //#endregion
152
+ export { consistentImport };
@@ -0,0 +1,82 @@
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/consistent-object-schema-type.ts
6
+ const ZOD_OBJECT_METHODS = [
7
+ "object",
8
+ "looseObject",
9
+ "strictObject"
10
+ ];
11
+ const defaultOptions = { allow: ["object"] };
12
+ const { zodImportAllowedSource, trackZodSchemaImports } = (0, _eslint_zod_utils.createZodSchemaImportTrack)("zod-mini");
13
+ const consistentObjectSchemaType = require_create_plugin_rule.createZodMiniPluginRule({
14
+ name: "consistent-object-schema-type",
15
+ meta: {
16
+ hasSuggestions: true,
17
+ type: "suggestion",
18
+ docs: {
19
+ zodImportAllowedSource,
20
+ description: "Enforce consistent usage of Zod Mini schema methods"
21
+ },
22
+ messages: {
23
+ consistentMethod: "Inconsistent Zod Mini object schema method '{{actual}}'. Allowed: {{allowedList}}.",
24
+ useMethod: "Replace with '{{expected}}'."
25
+ },
26
+ schema: [{
27
+ type: "object",
28
+ properties: { allow: {
29
+ type: "array",
30
+ description: "Decides which object methods are allowed",
31
+ items: {
32
+ type: "string",
33
+ enum: [...ZOD_OBJECT_METHODS]
34
+ },
35
+ minItems: 1,
36
+ uniqueItems: true
37
+ } },
38
+ additionalProperties: false
39
+ }]
40
+ },
41
+ defaultOptions: [defaultOptions],
42
+ create(context, [{ allow: allowedList }]) {
43
+ const { importDeclarationListener, detectZodSchemaRootNode } = trackZodSchemaImports();
44
+ return {
45
+ ImportDeclaration: importDeclarationListener,
46
+ CallExpression(node) {
47
+ const schemaType = detectZodSchemaRootNode(node)?.schemaType;
48
+ if (!schemaType || !ZOD_OBJECT_METHODS.includes(schemaType)) return;
49
+ if (allowedList.includes(schemaType)) return;
50
+ const { callee } = node;
51
+ if (callee.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier) {
52
+ context.report({
53
+ node,
54
+ messageId: "consistentMethod",
55
+ data: {
56
+ actual: schemaType,
57
+ allowedList: allowedList.join(",")
58
+ }
59
+ });
60
+ return;
61
+ }
62
+ if (callee.type === _typescript_eslint_utils.AST_NODE_TYPES.MemberExpression) context.report({
63
+ node,
64
+ messageId: "consistentMethod",
65
+ data: {
66
+ actual: schemaType,
67
+ allowedList: allowedList.join(",")
68
+ },
69
+ suggest: allowedList.map((it) => ({
70
+ messageId: "useMethod",
71
+ data: { expected: it },
72
+ fix(fixer) {
73
+ return fixer.replaceText(callee.property, it);
74
+ }
75
+ }))
76
+ });
77
+ }
78
+ };
79
+ }
80
+ });
81
+ //#endregion
82
+ exports.consistentObjectSchemaType = consistentObjectSchemaType;
@@ -0,0 +1,81 @@
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/consistent-object-schema-type.ts
5
+ const ZOD_OBJECT_METHODS = [
6
+ "object",
7
+ "looseObject",
8
+ "strictObject"
9
+ ];
10
+ const defaultOptions = { allow: ["object"] };
11
+ const { zodImportAllowedSource, trackZodSchemaImports } = createZodSchemaImportTrack("zod-mini");
12
+ const consistentObjectSchemaType = createZodMiniPluginRule({
13
+ name: "consistent-object-schema-type",
14
+ meta: {
15
+ hasSuggestions: true,
16
+ type: "suggestion",
17
+ docs: {
18
+ zodImportAllowedSource,
19
+ description: "Enforce consistent usage of Zod Mini schema methods"
20
+ },
21
+ messages: {
22
+ consistentMethod: "Inconsistent Zod Mini object schema method '{{actual}}'. Allowed: {{allowedList}}.",
23
+ useMethod: "Replace with '{{expected}}'."
24
+ },
25
+ schema: [{
26
+ type: "object",
27
+ properties: { allow: {
28
+ type: "array",
29
+ description: "Decides which object methods are allowed",
30
+ items: {
31
+ type: "string",
32
+ enum: [...ZOD_OBJECT_METHODS]
33
+ },
34
+ minItems: 1,
35
+ uniqueItems: true
36
+ } },
37
+ additionalProperties: false
38
+ }]
39
+ },
40
+ defaultOptions: [defaultOptions],
41
+ create(context, [{ allow: allowedList }]) {
42
+ const { importDeclarationListener, detectZodSchemaRootNode } = trackZodSchemaImports();
43
+ return {
44
+ ImportDeclaration: importDeclarationListener,
45
+ CallExpression(node) {
46
+ const schemaType = detectZodSchemaRootNode(node)?.schemaType;
47
+ if (!schemaType || !ZOD_OBJECT_METHODS.includes(schemaType)) return;
48
+ if (allowedList.includes(schemaType)) return;
49
+ const { callee } = node;
50
+ if (callee.type === AST_NODE_TYPES.Identifier) {
51
+ context.report({
52
+ node,
53
+ messageId: "consistentMethod",
54
+ data: {
55
+ actual: schemaType,
56
+ allowedList: allowedList.join(",")
57
+ }
58
+ });
59
+ return;
60
+ }
61
+ if (callee.type === AST_NODE_TYPES.MemberExpression) context.report({
62
+ node,
63
+ messageId: "consistentMethod",
64
+ data: {
65
+ actual: schemaType,
66
+ allowedList: allowedList.join(",")
67
+ },
68
+ suggest: allowedList.map((it) => ({
69
+ messageId: "useMethod",
70
+ data: { expected: it },
71
+ fix(fixer) {
72
+ return fixer.replaceText(callee.property, it);
73
+ }
74
+ }))
75
+ });
76
+ }
77
+ };
78
+ }
79
+ });
80
+ //#endregion
81
+ export { consistentObjectSchemaType };
@@ -0,0 +1,70 @@
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/consistent-schema-output-type-style.ts
6
+ const ZOD_SCHEMA_TYPE_STYLES = ["infer", "output"];
7
+ const { zodImportAllowedSource, trackZodSchemaImports } = (0, _eslint_zod_utils.createZodSchemaImportTrack)("zod-mini");
8
+ const consistentSchemaOutputTypeStyle = require_create_plugin_rule.createZodMiniPluginRule({
9
+ name: "consistent-schema-output-type-style",
10
+ meta: {
11
+ type: "suggestion",
12
+ fixable: "code",
13
+ docs: {
14
+ zodImportAllowedSource,
15
+ description: "Enforce consistent use of z.infer or z.output for schema type inference"
16
+ },
17
+ messages: {
18
+ useInfer: "Use infer instead of output.",
19
+ useOutput: "Use output instead of infer."
20
+ },
21
+ schema: [{
22
+ type: "object",
23
+ properties: { style: {
24
+ description: "Decides which style to use for schema type inference",
25
+ type: "string",
26
+ enum: [...ZOD_SCHEMA_TYPE_STYLES]
27
+ } },
28
+ additionalProperties: false
29
+ }]
30
+ },
31
+ defaultOptions: [{ style: "output" }],
32
+ create(context, [{ style }]) {
33
+ const { importDeclarationListener, isZodNamespace, getNamedImportOriginal, getNamedImportLocal } = trackZodSchemaImports();
34
+ return {
35
+ ImportDeclaration: importDeclarationListener,
36
+ TSTypeReference(node) {
37
+ const { typeName } = node;
38
+ if (typeName.type === _typescript_eslint_utils.AST_NODE_TYPES.TSQualifiedName) {
39
+ const { left, right } = typeName;
40
+ if (left.type !== _typescript_eslint_utils.AST_NODE_TYPES.Identifier || !isZodNamespace(left.name)) return;
41
+ const usedStyle = right.name;
42
+ if (usedStyle !== "infer" && usedStyle !== "output" || usedStyle === style) return;
43
+ context.report({
44
+ node: right,
45
+ messageId: style === "infer" ? "useInfer" : "useOutput",
46
+ fix(fixer) {
47
+ return fixer.replaceText(right, style);
48
+ }
49
+ });
50
+ return;
51
+ }
52
+ if (typeName.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier) {
53
+ const originalName = getNamedImportOriginal(typeName.name);
54
+ if (originalName !== "infer" && originalName !== "output" || originalName === style) return;
55
+ const targetLocalName = getNamedImportLocal(style);
56
+ context.report({
57
+ node: typeName,
58
+ messageId: style === "infer" ? "useInfer" : "useOutput",
59
+ fix(fixer) {
60
+ if (!targetLocalName || targetLocalName === "infer") return null;
61
+ return fixer.replaceText(typeName, targetLocalName);
62
+ }
63
+ });
64
+ }
65
+ }
66
+ };
67
+ }
68
+ });
69
+ //#endregion
70
+ exports.consistentSchemaOutputTypeStyle = consistentSchemaOutputTypeStyle;
@@ -0,0 +1,69 @@
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/consistent-schema-output-type-style.ts
5
+ const ZOD_SCHEMA_TYPE_STYLES = ["infer", "output"];
6
+ const { zodImportAllowedSource, trackZodSchemaImports } = createZodSchemaImportTrack("zod-mini");
7
+ const consistentSchemaOutputTypeStyle = createZodMiniPluginRule({
8
+ name: "consistent-schema-output-type-style",
9
+ meta: {
10
+ type: "suggestion",
11
+ fixable: "code",
12
+ docs: {
13
+ zodImportAllowedSource,
14
+ description: "Enforce consistent use of z.infer or z.output for schema type inference"
15
+ },
16
+ messages: {
17
+ useInfer: "Use infer instead of output.",
18
+ useOutput: "Use output instead of infer."
19
+ },
20
+ schema: [{
21
+ type: "object",
22
+ properties: { style: {
23
+ description: "Decides which style to use for schema type inference",
24
+ type: "string",
25
+ enum: [...ZOD_SCHEMA_TYPE_STYLES]
26
+ } },
27
+ additionalProperties: false
28
+ }]
29
+ },
30
+ defaultOptions: [{ style: "output" }],
31
+ create(context, [{ style }]) {
32
+ const { importDeclarationListener, isZodNamespace, getNamedImportOriginal, getNamedImportLocal } = trackZodSchemaImports();
33
+ return {
34
+ ImportDeclaration: importDeclarationListener,
35
+ TSTypeReference(node) {
36
+ const { typeName } = node;
37
+ if (typeName.type === AST_NODE_TYPES.TSQualifiedName) {
38
+ const { left, right } = typeName;
39
+ if (left.type !== AST_NODE_TYPES.Identifier || !isZodNamespace(left.name)) return;
40
+ const usedStyle = right.name;
41
+ if (usedStyle !== "infer" && usedStyle !== "output" || usedStyle === style) return;
42
+ context.report({
43
+ node: right,
44
+ messageId: style === "infer" ? "useInfer" : "useOutput",
45
+ fix(fixer) {
46
+ return fixer.replaceText(right, style);
47
+ }
48
+ });
49
+ return;
50
+ }
51
+ if (typeName.type === AST_NODE_TYPES.Identifier) {
52
+ const originalName = getNamedImportOriginal(typeName.name);
53
+ if (originalName !== "infer" && originalName !== "output" || originalName === style) return;
54
+ const targetLocalName = getNamedImportLocal(style);
55
+ context.report({
56
+ node: typeName,
57
+ messageId: style === "infer" ? "useInfer" : "useOutput",
58
+ fix(fixer) {
59
+ if (!targetLocalName || targetLocalName === "infer") return null;
60
+ return fixer.replaceText(typeName, targetLocalName);
61
+ }
62
+ });
63
+ }
64
+ }
65
+ };
66
+ }
67
+ });
68
+ //#endregion
69
+ export { consistentSchemaOutputTypeStyle };
@@ -0,0 +1,76 @@
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/consistent-schema-var-name.ts
6
+ const { zodImportAllowedSource, trackZodSchemaImports } = (0, _eslint_zod_utils.createZodSchemaImportTrack)("zod-mini");
7
+ const consistentSchemaVarName = require_create_plugin_rule.createZodMiniPluginRule({
8
+ name: "consistent-schema-var-name",
9
+ meta: {
10
+ type: "suggestion",
11
+ docs: {
12
+ zodImportAllowedSource,
13
+ description: "Enforce a consistent naming convention for Zod Mini schema variables"
14
+ },
15
+ messages: { invalidName: "Rename this Zod Mini schema to \"{{expected}}\"" },
16
+ schema: [{
17
+ type: "object",
18
+ properties: {
19
+ before: {
20
+ type: "string",
21
+ description: "The required prefix for Zod Mini schema variables"
22
+ },
23
+ after: {
24
+ type: "string",
25
+ description: "The required suffix for Zod Mini schema variables"
26
+ }
27
+ },
28
+ additionalProperties: false
29
+ }]
30
+ },
31
+ defaultOptions: [{ after: "Schema" }],
32
+ create(context, [{ before = "", after = "" }]) {
33
+ const { importDeclarationListener, detectZodSchemaRootNode, collectZodChainMethods } = trackZodSchemaImports();
34
+ return {
35
+ ImportDeclaration: importDeclarationListener,
36
+ VariableDeclarator(node) {
37
+ const initNode = node.init;
38
+ if (initNode?.type !== _typescript_eslint_utils.AST_NODE_TYPES.CallExpression || !detectZodSchemaRootNode(initNode)) return;
39
+ const chainMethods = collectZodChainMethods(initNode).map((it) => it.name);
40
+ if ([
41
+ "parse",
42
+ "parseAsync",
43
+ "safeParse",
44
+ "safeParseAsync",
45
+ "spa",
46
+ "encode",
47
+ "encodeAsync",
48
+ "decode",
49
+ "decodeAsync",
50
+ "safeEncode",
51
+ "safeEncodeAsync",
52
+ "safeDecode",
53
+ "safeDecodeAsync",
54
+ "codec",
55
+ "treeifyError",
56
+ "prettifyError",
57
+ "formatError",
58
+ "flattenError"
59
+ ].some((it) => chainMethods.includes(it))) return;
60
+ if (node.id.type !== _typescript_eslint_utils.AST_NODE_TYPES.Identifier) return;
61
+ const { name } = node.id;
62
+ const validPrefix = !before || name.startsWith(before);
63
+ const validSuffix = !after || name.endsWith(after);
64
+ if (validPrefix && validSuffix) return;
65
+ const expected = (validPrefix ? "" : before) + name + (validSuffix ? "" : after);
66
+ context.report({
67
+ node,
68
+ messageId: "invalidName",
69
+ data: { expected }
70
+ });
71
+ }
72
+ };
73
+ }
74
+ });
75
+ //#endregion
76
+ exports.consistentSchemaVarName = consistentSchemaVarName;
@@ -0,0 +1,75 @@
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/consistent-schema-var-name.ts
5
+ const { zodImportAllowedSource, trackZodSchemaImports } = createZodSchemaImportTrack("zod-mini");
6
+ const consistentSchemaVarName = createZodMiniPluginRule({
7
+ name: "consistent-schema-var-name",
8
+ meta: {
9
+ type: "suggestion",
10
+ docs: {
11
+ zodImportAllowedSource,
12
+ description: "Enforce a consistent naming convention for Zod Mini schema variables"
13
+ },
14
+ messages: { invalidName: "Rename this Zod Mini schema to \"{{expected}}\"" },
15
+ schema: [{
16
+ type: "object",
17
+ properties: {
18
+ before: {
19
+ type: "string",
20
+ description: "The required prefix for Zod Mini schema variables"
21
+ },
22
+ after: {
23
+ type: "string",
24
+ description: "The required suffix for Zod Mini schema variables"
25
+ }
26
+ },
27
+ additionalProperties: false
28
+ }]
29
+ },
30
+ defaultOptions: [{ after: "Schema" }],
31
+ create(context, [{ before = "", after = "" }]) {
32
+ const { importDeclarationListener, detectZodSchemaRootNode, collectZodChainMethods } = trackZodSchemaImports();
33
+ return {
34
+ ImportDeclaration: importDeclarationListener,
35
+ VariableDeclarator(node) {
36
+ const initNode = node.init;
37
+ if (initNode?.type !== AST_NODE_TYPES.CallExpression || !detectZodSchemaRootNode(initNode)) return;
38
+ const chainMethods = collectZodChainMethods(initNode).map((it) => it.name);
39
+ if ([
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
+ "treeifyError",
55
+ "prettifyError",
56
+ "formatError",
57
+ "flattenError"
58
+ ].some((it) => chainMethods.includes(it))) return;
59
+ if (node.id.type !== AST_NODE_TYPES.Identifier) return;
60
+ const { name } = node.id;
61
+ const validPrefix = !before || name.startsWith(before);
62
+ const validSuffix = !after || name.endsWith(after);
63
+ if (validPrefix && validSuffix) return;
64
+ const expected = (validPrefix ? "" : before) + name + (validSuffix ? "" : after);
65
+ context.report({
66
+ node,
67
+ messageId: "invalidName",
68
+ data: { expected }
69
+ });
70
+ }
71
+ };
72
+ }
73
+ });
74
+ //#endregion
75
+ export { consistentSchemaVarName };
@@ -0,0 +1,63 @@
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/no-any-schema.ts
6
+ const { zodImportAllowedSource, trackZodSchemaImports } = (0, _eslint_zod_utils.createZodSchemaImportTrack)("zod-mini");
7
+ const noAnySchema = require_create_plugin_rule.createZodMiniPluginRule({
8
+ name: "no-any-schema",
9
+ meta: {
10
+ hasSuggestions: true,
11
+ type: "suggestion",
12
+ docs: {
13
+ zodImportAllowedSource,
14
+ description: "Disallow usage of `z.any()` in Zod Mini schemas"
15
+ },
16
+ messages: {
17
+ noZAny: "Using `z.any()` is not allowed. Please use a more specific schema.",
18
+ useUnknown: "Replace `z.any()` with `z.unknown()`"
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)?.schemaType !== "any") return;
29
+ const { callee } = node;
30
+ if (callee.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier) {
31
+ context.report({
32
+ node,
33
+ messageId: "noZAny"
34
+ });
35
+ return;
36
+ }
37
+ if (callee.type === _typescript_eslint_utils.AST_NODE_TYPES.MemberExpression) {
38
+ const [{ node: schemaMethod }] = collectZodChainMethods(node);
39
+ const schemaMethodCallee = schemaMethod.callee;
40
+ if (schemaMethodCallee.type === _typescript_eslint_utils.AST_NODE_TYPES.MemberExpression && schemaMethodCallee.property.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier) {
41
+ context.report({
42
+ node,
43
+ messageId: "noZAny",
44
+ suggest: [{
45
+ messageId: "useUnknown",
46
+ fix(fixer) {
47
+ return fixer.replaceText(schemaMethodCallee.property, "unknown");
48
+ }
49
+ }]
50
+ });
51
+ return;
52
+ }
53
+ context.report({
54
+ node,
55
+ messageId: "noZAny"
56
+ });
57
+ }
58
+ }
59
+ };
60
+ }
61
+ });
62
+ //#endregion
63
+ exports.noAnySchema = noAnySchema;