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,62 @@
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/no-any-schema.ts
5
+ const { zodImportAllowedSource, trackZodSchemaImports } = createZodSchemaImportTrack("zod-mini");
6
+ const noAnySchema = createZodMiniPluginRule({
7
+ name: "no-any-schema",
8
+ meta: {
9
+ hasSuggestions: true,
10
+ type: "suggestion",
11
+ docs: {
12
+ zodImportAllowedSource,
13
+ description: "Disallow usage of `z.any()` in Zod Mini schemas"
14
+ },
15
+ messages: {
16
+ noZAny: "Using `z.any()` is not allowed. Please use a more specific schema.",
17
+ useUnknown: "Replace `z.any()` with `z.unknown()`"
18
+ },
19
+ schema: []
20
+ },
21
+ defaultOptions: [],
22
+ create(context) {
23
+ const { importDeclarationListener, detectZodSchemaRootNode, collectZodChainMethods } = trackZodSchemaImports();
24
+ return {
25
+ ImportDeclaration: importDeclarationListener,
26
+ CallExpression(node) {
27
+ if (detectZodSchemaRootNode(node)?.schemaType !== "any") return;
28
+ const { callee } = node;
29
+ if (callee.type === AST_NODE_TYPES.Identifier) {
30
+ context.report({
31
+ node,
32
+ messageId: "noZAny"
33
+ });
34
+ return;
35
+ }
36
+ if (callee.type === AST_NODE_TYPES.MemberExpression) {
37
+ const [{ node: schemaMethod }] = collectZodChainMethods(node);
38
+ const schemaMethodCallee = schemaMethod.callee;
39
+ if (schemaMethodCallee.type === AST_NODE_TYPES.MemberExpression && schemaMethodCallee.property.type === AST_NODE_TYPES.Identifier) {
40
+ context.report({
41
+ node,
42
+ messageId: "noZAny",
43
+ suggest: [{
44
+ messageId: "useUnknown",
45
+ fix(fixer) {
46
+ return fixer.replaceText(schemaMethodCallee.property, "unknown");
47
+ }
48
+ }]
49
+ });
50
+ return;
51
+ }
52
+ context.report({
53
+ node,
54
+ messageId: "noZAny"
55
+ });
56
+ }
57
+ }
58
+ };
59
+ }
60
+ });
61
+ //#endregion
62
+ export { noAnySchema };
@@ -0,0 +1,36 @@
1
+ require("../_virtual/_rolldown/runtime.cjs");
2
+ const require_create_plugin_rule = require("../utils/create-plugin-rule.cjs");
3
+ //#region src/rules/no-empty-custom-schema.ts
4
+ const { zodImportAllowedSource, trackZodSchemaImports } = (0, require("@eslint-zod/utils").createZodSchemaImportTrack)("zod-mini");
5
+ const noEmptyCustomSchema = require_create_plugin_rule.createZodMiniPluginRule({
6
+ name: "no-empty-custom-schema",
7
+ meta: {
8
+ hasSuggestions: false,
9
+ type: "suggestion",
10
+ docs: {
11
+ zodImportAllowedSource,
12
+ description: "Disallow usage of `z.custom()` without arguments"
13
+ },
14
+ messages: { noEmptyCustomSchema: "You should provide a validate function within `z.custom()`" },
15
+ schema: []
16
+ },
17
+ defaultOptions: [],
18
+ create(context) {
19
+ const { importDeclarationListener, detectZodSchemaRootNode, collectZodChainMethods } = trackZodSchemaImports();
20
+ return {
21
+ ImportDeclaration: importDeclarationListener,
22
+ CallExpression(node) {
23
+ const zodSchemaMeta = detectZodSchemaRootNode(node);
24
+ if (!zodSchemaMeta) return;
25
+ if (zodSchemaMeta.schemaType !== "custom") return;
26
+ const customCallNode = collectZodChainMethods(node).find((method) => method.name === "custom")?.node;
27
+ if (customCallNode?.arguments.length === 0) context.report({
28
+ node: customCallNode,
29
+ messageId: "noEmptyCustomSchema"
30
+ });
31
+ }
32
+ };
33
+ }
34
+ });
35
+ //#endregion
36
+ exports.noEmptyCustomSchema = noEmptyCustomSchema;
@@ -0,0 +1,36 @@
1
+ import { createZodMiniPluginRule } from "../utils/create-plugin-rule.mjs";
2
+ import { createZodSchemaImportTrack } from "@eslint-zod/utils";
3
+ //#region src/rules/no-empty-custom-schema.ts
4
+ const { zodImportAllowedSource, trackZodSchemaImports } = createZodSchemaImportTrack("zod-mini");
5
+ const noEmptyCustomSchema = createZodMiniPluginRule({
6
+ name: "no-empty-custom-schema",
7
+ meta: {
8
+ hasSuggestions: false,
9
+ type: "suggestion",
10
+ docs: {
11
+ zodImportAllowedSource,
12
+ description: "Disallow usage of `z.custom()` without arguments"
13
+ },
14
+ messages: { noEmptyCustomSchema: "You should provide a validate function within `z.custom()`" },
15
+ schema: []
16
+ },
17
+ defaultOptions: [],
18
+ create(context) {
19
+ const { importDeclarationListener, detectZodSchemaRootNode, collectZodChainMethods } = trackZodSchemaImports();
20
+ return {
21
+ ImportDeclaration: importDeclarationListener,
22
+ CallExpression(node) {
23
+ const zodSchemaMeta = detectZodSchemaRootNode(node);
24
+ if (!zodSchemaMeta) return;
25
+ if (zodSchemaMeta.schemaType !== "custom") return;
26
+ const customCallNode = collectZodChainMethods(node).find((method) => method.name === "custom")?.node;
27
+ if (customCallNode?.arguments.length === 0) context.report({
28
+ node: customCallNode,
29
+ messageId: "noEmptyCustomSchema"
30
+ });
31
+ }
32
+ };
33
+ }
34
+ });
35
+ //#endregion
36
+ export { noEmptyCustomSchema };
@@ -0,0 +1,31 @@
1
+ require("../_virtual/_rolldown/runtime.cjs");
2
+ const require_create_plugin_rule = require("../utils/create-plugin-rule.cjs");
3
+ //#region src/rules/no-unknown-schema.ts
4
+ const { zodImportAllowedSource, trackZodSchemaImports } = (0, require("@eslint-zod/utils").createZodSchemaImportTrack)("zod-mini");
5
+ const noUnknownSchema = require_create_plugin_rule.createZodMiniPluginRule({
6
+ name: "no-unknown-schema",
7
+ meta: {
8
+ type: "suggestion",
9
+ docs: {
10
+ zodImportAllowedSource,
11
+ description: "Disallow usage of `z.unknown()` in Zod Mini schemas"
12
+ },
13
+ messages: { noZUnknown: "Using `z.unknown()` is not allowed. Please use a more specific schema." },
14
+ schema: []
15
+ },
16
+ defaultOptions: [],
17
+ create(context) {
18
+ const { importDeclarationListener, detectZodSchemaRootNode } = trackZodSchemaImports();
19
+ return {
20
+ ImportDeclaration: importDeclarationListener,
21
+ CallExpression(node) {
22
+ if (detectZodSchemaRootNode(node)?.schemaType === "unknown") context.report({
23
+ node,
24
+ messageId: "noZUnknown"
25
+ });
26
+ }
27
+ };
28
+ }
29
+ });
30
+ //#endregion
31
+ exports.noUnknownSchema = noUnknownSchema;
@@ -0,0 +1,31 @@
1
+ import { createZodMiniPluginRule } from "../utils/create-plugin-rule.mjs";
2
+ import { createZodSchemaImportTrack } from "@eslint-zod/utils";
3
+ //#region src/rules/no-unknown-schema.ts
4
+ const { zodImportAllowedSource, trackZodSchemaImports } = createZodSchemaImportTrack("zod-mini");
5
+ const noUnknownSchema = createZodMiniPluginRule({
6
+ name: "no-unknown-schema",
7
+ meta: {
8
+ type: "suggestion",
9
+ docs: {
10
+ zodImportAllowedSource,
11
+ description: "Disallow usage of `z.unknown()` in Zod Mini schemas"
12
+ },
13
+ messages: { noZUnknown: "Using `z.unknown()` is not allowed. Please use a more specific schema." },
14
+ schema: []
15
+ },
16
+ defaultOptions: [],
17
+ create(context) {
18
+ const { importDeclarationListener, detectZodSchemaRootNode } = trackZodSchemaImports();
19
+ return {
20
+ ImportDeclaration: importDeclarationListener,
21
+ CallExpression(node) {
22
+ if (detectZodSchemaRootNode(node)?.schemaType === "unknown") context.report({
23
+ node,
24
+ messageId: "noZUnknown"
25
+ });
26
+ }
27
+ };
28
+ }
29
+ });
30
+ //#endregion
31
+ export { noUnknownSchema };
@@ -0,0 +1,46 @@
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/prefer-meta.ts
6
+ const { zodImportAllowedSource, trackZodSchemaImports } = (0, _eslint_zod_utils.createZodSchemaImportTrack)("zod-mini");
7
+ const preferMeta = require_create_plugin_rule.createZodMiniPluginRule({
8
+ name: "prefer-meta",
9
+ meta: {
10
+ type: "suggestion",
11
+ fixable: "code",
12
+ docs: {
13
+ zodImportAllowedSource,
14
+ description: "Enforce usage of `z.meta()` over `z.describe()`"
15
+ },
16
+ messages: { preferMeta: "The `z.describe()` function still exists for compatibility with Zod 3, but `z.meta()` is now the recommended approach." },
17
+ schema: []
18
+ },
19
+ defaultOptions: [],
20
+ create(context) {
21
+ const { importDeclarationListener, isZodNamespace, getNamedImportOriginal } = trackZodSchemaImports();
22
+ return {
23
+ ImportDeclaration: importDeclarationListener,
24
+ CallExpression(node) {
25
+ const { callee } = node;
26
+ if (callee.type === _typescript_eslint_utils.AST_NODE_TYPES.MemberExpression && callee.property.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier && callee.property.name === "describe" && callee.object.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier && isZodNamespace(callee.object.name)) {
27
+ const [describeArg] = node.arguments;
28
+ context.report({
29
+ node,
30
+ messageId: "preferMeta",
31
+ fix(fixer) {
32
+ return [fixer.replaceText(callee.property, "meta"), fixer.replaceText(describeArg, `{ description: ${context.sourceCode.getText(describeArg)} }`)];
33
+ }
34
+ });
35
+ return;
36
+ }
37
+ if (callee.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier && getNamedImportOriginal(callee.name) === "describe") context.report({
38
+ node,
39
+ messageId: "preferMeta"
40
+ });
41
+ }
42
+ };
43
+ }
44
+ });
45
+ //#endregion
46
+ exports.preferMeta = preferMeta;
@@ -0,0 +1,45 @@
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/prefer-meta.ts
5
+ const { zodImportAllowedSource, trackZodSchemaImports } = createZodSchemaImportTrack("zod-mini");
6
+ const preferMeta = createZodMiniPluginRule({
7
+ name: "prefer-meta",
8
+ meta: {
9
+ type: "suggestion",
10
+ fixable: "code",
11
+ docs: {
12
+ zodImportAllowedSource,
13
+ description: "Enforce usage of `z.meta()` over `z.describe()`"
14
+ },
15
+ messages: { preferMeta: "The `z.describe()` function still exists for compatibility with Zod 3, but `z.meta()` is now the recommended approach." },
16
+ schema: []
17
+ },
18
+ defaultOptions: [],
19
+ create(context) {
20
+ const { importDeclarationListener, isZodNamespace, getNamedImportOriginal } = trackZodSchemaImports();
21
+ return {
22
+ ImportDeclaration: importDeclarationListener,
23
+ CallExpression(node) {
24
+ const { callee } = node;
25
+ if (callee.type === AST_NODE_TYPES.MemberExpression && callee.property.type === AST_NODE_TYPES.Identifier && callee.property.name === "describe" && callee.object.type === AST_NODE_TYPES.Identifier && isZodNamespace(callee.object.name)) {
26
+ const [describeArg] = node.arguments;
27
+ context.report({
28
+ node,
29
+ messageId: "preferMeta",
30
+ fix(fixer) {
31
+ return [fixer.replaceText(callee.property, "meta"), fixer.replaceText(describeArg, `{ description: ${context.sourceCode.getText(describeArg)} }`)];
32
+ }
33
+ });
34
+ return;
35
+ }
36
+ if (callee.type === AST_NODE_TYPES.Identifier && getNamedImportOriginal(callee.name) === "describe") context.report({
37
+ node,
38
+ messageId: "preferMeta"
39
+ });
40
+ }
41
+ };
42
+ }
43
+ });
44
+ //#endregion
45
+ export { preferMeta };
@@ -0,0 +1,117 @@
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/prefer-namespace-import.ts
6
+ function isGroupFirstImportTypeNamespace(group) {
7
+ const { hasOnlyTypeImports, nodes: [firstImportNode] } = group;
8
+ const { specifiers } = firstImportNode;
9
+ if (specifiers.length === 1 && specifiers[0].type === _typescript_eslint_utils.AST_NODE_TYPES.ImportNamespaceSpecifier) if (hasOnlyTypeImports) {
10
+ if (firstImportNode.importKind === "type") return true;
11
+ } else return true;
12
+ return false;
13
+ }
14
+ function shouldIdentifierBeRenamed(node) {
15
+ if (node.parent.type === _typescript_eslint_utils.AST_NODE_TYPES.ImportSpecifier) return false;
16
+ if (node.parent.type === _typescript_eslint_utils.AST_NODE_TYPES.MemberExpression && node.parent.object.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier && node.parent.object.name !== node.name) return false;
17
+ return true;
18
+ }
19
+ /**
20
+ * From a given specifiers retrieve the most significant to use when creating an alias import
21
+ */
22
+ function getNamespaceAliasNameFrom(node) {
23
+ if (node.type === _typescript_eslint_utils.AST_NODE_TYPES.ImportDefaultSpecifier || node.type === _typescript_eslint_utils.AST_NODE_TYPES.ImportNamespaceSpecifier) return node.local.name;
24
+ if (node.imported.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier && node.imported.name === "z") return node.local.name;
25
+ return null;
26
+ }
27
+ const preferNamespaceImport = require_create_plugin_rule.createZodMiniPluginRule({
28
+ name: "prefer-namespace-import",
29
+ meta: {
30
+ type: "suggestion",
31
+ deprecated: { message: "Use `zod-mini/consistent-import` with `{ syntax: 'namespace' }`" },
32
+ docs: {
33
+ zodImportAllowedSource: "zod-mini",
34
+ description: "Enforce importing zod/mini as a namespace import (`import * as z from 'zod/mini'`)"
35
+ },
36
+ fixable: "code",
37
+ messages: {
38
+ useNamespace: "Import Zod Mini with a namespace import",
39
+ removeDuplicate: "Zod Mini is already imported via namespace import",
40
+ convertUsage: "Convert to namespace usage"
41
+ },
42
+ schema: []
43
+ },
44
+ defaultOptions: [],
45
+ create(context) {
46
+ const { sourceCode } = context;
47
+ const importGroups = {};
48
+ return {
49
+ ImportDeclaration(node) {
50
+ const { source, importKind } = node;
51
+ if (!(0, _eslint_zod_utils.isZodImportSource)(source.value, "zod-mini")) return;
52
+ if (!importGroups[source.value]) importGroups[source.value] = {
53
+ hasOnlyTypeImports: true,
54
+ nodes: []
55
+ };
56
+ if (importGroups[source.value].hasOnlyTypeImports && importKind === "value") importGroups[source.value].hasOnlyTypeImports = false;
57
+ importGroups[source.value].nodes.push(node);
58
+ },
59
+ "Program:exit": function() {
60
+ let namespaceAliasNameIndex = 0;
61
+ for (const importGroup of Object.values(importGroups)) {
62
+ const { hasOnlyTypeImports, nodes } = importGroup;
63
+ const [firstImportNode, ...othersImportNodes] = nodes;
64
+ /**
65
+ * Variable to track all specifiers that later are used by {@link getDeclaredVariables}
66
+ * to add the namespace prefix
67
+ */
68
+ const nodesWithVariablesToUpdate = [];
69
+ let namespaceAliasName = null;
70
+ for (const specifier of nodes.flatMap((it) => it.specifiers)) {
71
+ if (!namespaceAliasName) {
72
+ namespaceAliasName = getNamespaceAliasNameFrom(specifier);
73
+ if (namespaceAliasName) continue;
74
+ }
75
+ nodesWithVariablesToUpdate.push(specifier);
76
+ }
77
+ if (!namespaceAliasName) {
78
+ namespaceAliasName = "z";
79
+ if (namespaceAliasNameIndex > 0) {
80
+ namespaceAliasName = `z${namespaceAliasNameIndex}`;
81
+ namespaceAliasNameIndex += 1;
82
+ }
83
+ }
84
+ if (!isGroupFirstImportTypeNamespace(importGroup)) context.report({
85
+ node: firstImportNode,
86
+ messageId: "useNamespace",
87
+ fix(fixer) {
88
+ const newImportText = `import ${hasOnlyTypeImports ? "type " : ""}* as ${namespaceAliasName} from ${firstImportNode.source.raw};`;
89
+ return fixer.replaceText(firstImportNode, newImportText);
90
+ }
91
+ });
92
+ const allReferences = nodesWithVariablesToUpdate.flatMap((it) => sourceCode.getDeclaredVariables(it)).flatMap((it) => it.references);
93
+ for (const ref of allReferences) {
94
+ const { identifier } = ref;
95
+ if (shouldIdentifierBeRenamed(identifier)) context.report({
96
+ node: identifier,
97
+ messageId: "convertUsage",
98
+ fix(fixer) {
99
+ const newId = `${namespaceAliasName}.${identifier.name}`;
100
+ return fixer.replaceText(identifier, newId);
101
+ }
102
+ });
103
+ }
104
+ for (const extraImport of othersImportNodes) context.report({
105
+ node: extraImport,
106
+ messageId: "removeDuplicate",
107
+ fix(fixer) {
108
+ return fixer.removeRange(extraImport.range);
109
+ }
110
+ });
111
+ }
112
+ }
113
+ };
114
+ }
115
+ });
116
+ //#endregion
117
+ exports.preferNamespaceImport = preferNamespaceImport;
@@ -0,0 +1,116 @@
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/prefer-namespace-import.ts
5
+ function isGroupFirstImportTypeNamespace(group) {
6
+ const { hasOnlyTypeImports, nodes: [firstImportNode] } = group;
7
+ const { specifiers } = firstImportNode;
8
+ if (specifiers.length === 1 && specifiers[0].type === AST_NODE_TYPES.ImportNamespaceSpecifier) if (hasOnlyTypeImports) {
9
+ if (firstImportNode.importKind === "type") return true;
10
+ } else return true;
11
+ return false;
12
+ }
13
+ function shouldIdentifierBeRenamed(node) {
14
+ if (node.parent.type === AST_NODE_TYPES.ImportSpecifier) return false;
15
+ if (node.parent.type === AST_NODE_TYPES.MemberExpression && node.parent.object.type === AST_NODE_TYPES.Identifier && node.parent.object.name !== node.name) return false;
16
+ return true;
17
+ }
18
+ /**
19
+ * From a given specifiers retrieve the most significant to use when creating an alias import
20
+ */
21
+ function getNamespaceAliasNameFrom(node) {
22
+ if (node.type === AST_NODE_TYPES.ImportDefaultSpecifier || node.type === AST_NODE_TYPES.ImportNamespaceSpecifier) return node.local.name;
23
+ if (node.imported.type === AST_NODE_TYPES.Identifier && node.imported.name === "z") return node.local.name;
24
+ return null;
25
+ }
26
+ const preferNamespaceImport = createZodMiniPluginRule({
27
+ name: "prefer-namespace-import",
28
+ meta: {
29
+ type: "suggestion",
30
+ deprecated: { message: "Use `zod-mini/consistent-import` with `{ syntax: 'namespace' }`" },
31
+ docs: {
32
+ zodImportAllowedSource: "zod-mini",
33
+ description: "Enforce importing zod/mini as a namespace import (`import * as z from 'zod/mini'`)"
34
+ },
35
+ fixable: "code",
36
+ messages: {
37
+ useNamespace: "Import Zod Mini with a namespace import",
38
+ removeDuplicate: "Zod Mini is already imported via namespace import",
39
+ convertUsage: "Convert to namespace usage"
40
+ },
41
+ schema: []
42
+ },
43
+ defaultOptions: [],
44
+ create(context) {
45
+ const { sourceCode } = context;
46
+ const importGroups = {};
47
+ return {
48
+ ImportDeclaration(node) {
49
+ const { source, importKind } = node;
50
+ if (!isZodImportSource(source.value, "zod-mini")) return;
51
+ if (!importGroups[source.value]) importGroups[source.value] = {
52
+ hasOnlyTypeImports: true,
53
+ nodes: []
54
+ };
55
+ if (importGroups[source.value].hasOnlyTypeImports && importKind === "value") importGroups[source.value].hasOnlyTypeImports = false;
56
+ importGroups[source.value].nodes.push(node);
57
+ },
58
+ "Program:exit": function() {
59
+ let namespaceAliasNameIndex = 0;
60
+ for (const importGroup of Object.values(importGroups)) {
61
+ const { hasOnlyTypeImports, nodes } = importGroup;
62
+ const [firstImportNode, ...othersImportNodes] = nodes;
63
+ /**
64
+ * Variable to track all specifiers that later are used by {@link getDeclaredVariables}
65
+ * to add the namespace prefix
66
+ */
67
+ const nodesWithVariablesToUpdate = [];
68
+ let namespaceAliasName = null;
69
+ for (const specifier of nodes.flatMap((it) => it.specifiers)) {
70
+ if (!namespaceAliasName) {
71
+ namespaceAliasName = getNamespaceAliasNameFrom(specifier);
72
+ if (namespaceAliasName) continue;
73
+ }
74
+ nodesWithVariablesToUpdate.push(specifier);
75
+ }
76
+ if (!namespaceAliasName) {
77
+ namespaceAliasName = "z";
78
+ if (namespaceAliasNameIndex > 0) {
79
+ namespaceAliasName = `z${namespaceAliasNameIndex}`;
80
+ namespaceAliasNameIndex += 1;
81
+ }
82
+ }
83
+ if (!isGroupFirstImportTypeNamespace(importGroup)) context.report({
84
+ node: firstImportNode,
85
+ messageId: "useNamespace",
86
+ fix(fixer) {
87
+ const newImportText = `import ${hasOnlyTypeImports ? "type " : ""}* as ${namespaceAliasName} from ${firstImportNode.source.raw};`;
88
+ return fixer.replaceText(firstImportNode, newImportText);
89
+ }
90
+ });
91
+ const allReferences = nodesWithVariablesToUpdate.flatMap((it) => sourceCode.getDeclaredVariables(it)).flatMap((it) => it.references);
92
+ for (const ref of allReferences) {
93
+ const { identifier } = ref;
94
+ if (shouldIdentifierBeRenamed(identifier)) context.report({
95
+ node: identifier,
96
+ messageId: "convertUsage",
97
+ fix(fixer) {
98
+ const newId = `${namespaceAliasName}.${identifier.name}`;
99
+ return fixer.replaceText(identifier, newId);
100
+ }
101
+ });
102
+ }
103
+ for (const extraImport of othersImportNodes) context.report({
104
+ node: extraImport,
105
+ messageId: "removeDuplicate",
106
+ fix(fixer) {
107
+ return fixer.removeRange(extraImport.range);
108
+ }
109
+ });
110
+ }
111
+ }
112
+ };
113
+ }
114
+ });
115
+ //#endregion
116
+ export { preferNamespaceImport };
@@ -0,0 +1,49 @@
1
+ require("../_virtual/_rolldown/runtime.cjs");
2
+ const require_create_plugin_rule = require("../utils/create-plugin-rule.cjs");
3
+ //#region src/rules/require-brand-type-parameter.ts
4
+ const { zodImportAllowedSource, trackZodSchemaImports } = (0, require("@eslint-zod/utils").createZodSchemaImportTrack)("zod-mini");
5
+ const requireBrandTypeParameter = require_create_plugin_rule.createZodMiniPluginRule({
6
+ name: "require-brand-type-parameter",
7
+ meta: {
8
+ hasSuggestions: true,
9
+ type: "problem",
10
+ docs: {
11
+ zodImportAllowedSource,
12
+ description: "Require type parameter on `.brand()` functions"
13
+ },
14
+ messages: {
15
+ missingTypeParameter: "Type parameter is required when using `.brand()`",
16
+ removeBrandFunction: "Brand is a static-only construct. If not parameter is required consider removal"
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) return;
28
+ const brandMethod = collectZodChainMethods(zodSchemaMeta.node).find((it) => it.name === "brand");
29
+ if (!brandMethod) return;
30
+ const brandNode = brandMethod.node;
31
+ const { typeArguments } = brandNode;
32
+ if (typeArguments && typeArguments.params.length > 0) return;
33
+ const brandCalleeNode = brandNode.callee;
34
+ context.report({
35
+ messageId: "missingTypeParameter",
36
+ node: brandCalleeNode.property,
37
+ suggest: [{
38
+ messageId: "removeBrandFunction",
39
+ fix(fixer) {
40
+ return fixer.removeRange([brandCalleeNode.object.range[1], brandNode.range[1]]);
41
+ }
42
+ }]
43
+ });
44
+ }
45
+ };
46
+ }
47
+ });
48
+ //#endregion
49
+ exports.requireBrandTypeParameter = requireBrandTypeParameter;
@@ -0,0 +1,49 @@
1
+ import { createZodMiniPluginRule } from "../utils/create-plugin-rule.mjs";
2
+ import { createZodSchemaImportTrack } from "@eslint-zod/utils";
3
+ //#region src/rules/require-brand-type-parameter.ts
4
+ const { zodImportAllowedSource, trackZodSchemaImports } = createZodSchemaImportTrack("zod-mini");
5
+ const requireBrandTypeParameter = createZodMiniPluginRule({
6
+ name: "require-brand-type-parameter",
7
+ meta: {
8
+ hasSuggestions: true,
9
+ type: "problem",
10
+ docs: {
11
+ zodImportAllowedSource,
12
+ description: "Require type parameter on `.brand()` functions"
13
+ },
14
+ messages: {
15
+ missingTypeParameter: "Type parameter is required when using `.brand()`",
16
+ removeBrandFunction: "Brand is a static-only construct. If not parameter is required consider removal"
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) return;
28
+ const brandMethod = collectZodChainMethods(zodSchemaMeta.node).find((it) => it.name === "brand");
29
+ if (!brandMethod) return;
30
+ const brandNode = brandMethod.node;
31
+ const { typeArguments } = brandNode;
32
+ if (typeArguments && typeArguments.params.length > 0) return;
33
+ const brandCalleeNode = brandNode.callee;
34
+ context.report({
35
+ messageId: "missingTypeParameter",
36
+ node: brandCalleeNode.property,
37
+ suggest: [{
38
+ messageId: "removeBrandFunction",
39
+ fix(fixer) {
40
+ return fixer.removeRange([brandCalleeNode.object.range[1], brandNode.range[1]]);
41
+ }
42
+ }]
43
+ });
44
+ }
45
+ };
46
+ }
47
+ });
48
+ //#endregion
49
+ export { requireBrandTypeParameter };