eslint-plugin-zod 3.0.1 → 3.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.
package/README.md CHANGED
@@ -26,27 +26,29 @@
26
26
  💼 Configurations enabled in.\
27
27
  ✅ Set in the `recommended` configuration.\
28
28
  🔧 Automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/user-guide/command-line-interface#--fix).\
29
- 💡 Manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions).
30
-
31
- | Name                             | Description | 💼 | 🔧 | 💡 |
32
- | :--------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------- | :-- | :-- | :-- |
33
- | [array-style](docs/rules/array-style.md) | Enforce consistent Zod array style | | 🔧 | |
34
- | [consistent-import-source](docs/rules/consistent-import-source.md) | Enforce consistent source from Zod imports | | | 💡 |
35
- | [consistent-object-schema-type](docs/rules/consistent-object-schema-type.md) | Enforce consistent usage of Zod schema methods | | | 💡 |
36
- | [no-any-schema](docs/rules/no-any-schema.md) | Disallow usage of `z.any()` in Zod schemas || | 💡 |
37
- | [no-empty-custom-schema](docs/rules/no-empty-custom-schema.md) | Disallow usage of `z.custom()` without arguments | | | |
38
- | [no-number-schema-with-int](docs/rules/no-number-schema-with-int.md) | Disallow usage of `z.number().int()` as it is considered legacy | ✅ | 🔧 | |
39
- | [no-optional-and-default-together](docs/rules/no-optional-and-default-together.md) | Disallow using both `.optional()` and `.default()` on the same Zod schema | ✅ | 🔧 | |
40
- | [no-throw-in-refine](docs/rules/no-throw-in-refine.md) | Disallow throwing errors directly inside Zod refine callbacks | ✅ | | |
41
- | [no-unknown-schema](docs/rules/no-unknown-schema.md) | Disallow usage of `z.unknown()` in Zod schemas | | | |
42
- | [prefer-enum-over-literal-union](docs/rules/prefer-enum-over-literal-union.md) | Prefer `z.enum()` over `z.union()` when all members are string literals. | ✅ | 🔧 | |
43
- | [prefer-meta](docs/rules/prefer-meta.md) | Enforce usage of `.meta()` over `.describe()` | | 🔧 | |
44
- | [prefer-meta-last](docs/rules/prefer-meta-last.md) | Enforce `.meta()` as last method | ✅ | 🔧 | |
45
- | [prefer-namespace-import](docs/rules/prefer-namespace-import.md) | Enforce importing zod as a namespace import (`import * as z from 'zod'`) | ✅ | 🔧 | |
46
- | [require-brand-type-parameter](docs/rules/require-brand-type-parameter.md) | Require type parameter on `.brand()` functions | ✅ | | 💡 |
47
- | [require-error-message](docs/rules/require-error-message.md) | Enforce that custom refinements include an error message | | 🔧 | |
48
- | [require-schema-suffix](docs/rules/require-schema-suffix.md) | Require schema suffix when declaring a Zod schema | ✅ | | |
49
- | [schema-error-property-style](docs/rules/schema-error-property-style.md) | Enforce consistent style for error messages in Zod schema validation (using ESQuery patterns) | | | |
29
+ 💡 Manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions).\
30
+ ❌ Deprecated.
31
+
32
+ | Name                             | Description | 💼 | 🔧 | 💡 | |
33
+ | :--------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------- | :-- | :-- | :-- | :-- |
34
+ | [array-style](docs/rules/array-style.md) | Enforce consistent Zod array style | | 🔧 | | |
35
+ | [consistent-import](docs/rules/consistent-import.md) | Enforce a consistent import style for Zod | ✅ | 🔧 | | |
36
+ | [consistent-import-source](docs/rules/consistent-import-source.md) | Enforce consistent source from Zod imports | | | 💡 | |
37
+ | [consistent-object-schema-type](docs/rules/consistent-object-schema-type.md) | Enforce consistent usage of Zod schema methods | | | 💡 | |
38
+ | [no-any-schema](docs/rules/no-any-schema.md) | Disallow usage of `z.any()` in Zod schemas | ✅ | | 💡 | |
39
+ | [no-empty-custom-schema](docs/rules/no-empty-custom-schema.md) | Disallow usage of `z.custom()` without arguments | ✅ | | | |
40
+ | [no-number-schema-with-int](docs/rules/no-number-schema-with-int.md) | Disallow usage of `z.number().int()` as it is considered legacy | ✅ | 🔧 | | |
41
+ | [no-optional-and-default-together](docs/rules/no-optional-and-default-together.md) | Disallow using both `.optional()` and `.default()` on the same Zod schema || 🔧 | | |
42
+ | [no-throw-in-refine](docs/rules/no-throw-in-refine.md) | Disallow throwing errors directly inside Zod refine callbacks | ✅ | | | |
43
+ | [no-unknown-schema](docs/rules/no-unknown-schema.md) | Disallow usage of `z.unknown()` in Zod schemas | | | | |
44
+ | [prefer-enum-over-literal-union](docs/rules/prefer-enum-over-literal-union.md) | Prefer `z.enum()` over `z.union()` when all members are string literals. | ✅ | 🔧 | | |
45
+ | [prefer-meta](docs/rules/prefer-meta.md) | Enforce usage of `.meta()` over `.describe()` | ✅ | 🔧 | | |
46
+ | [prefer-meta-last](docs/rules/prefer-meta-last.md) | Enforce `.meta()` as last method | ✅ | 🔧 | | |
47
+ | [prefer-namespace-import](docs/rules/prefer-namespace-import.md) | Enforce importing zod as a namespace import (`import * as z from 'zod'`) | | 🔧 | | ❌ |
48
+ | [require-brand-type-parameter](docs/rules/require-brand-type-parameter.md) | Require type parameter on `.brand()` functions | ✅ | | 💡 | |
49
+ | [require-error-message](docs/rules/require-error-message.md) | Enforce that custom refinements include an error message | ✅ | 🔧 | | |
50
+ | [require-schema-suffix](docs/rules/require-schema-suffix.md) | Require schema suffix when declaring a Zod schema | ✅ | | | |
51
+ | [schema-error-property-style](docs/rules/schema-error-property-style.md) | Enforce consistent style for error messages in Zod schema validation (using ESQuery patterns) | | | | |
50
52
 
51
53
  <!-- end auto-generated rules list -->
52
54
 
package/dist/index.cjs CHANGED
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const meta_js_1 = require("./meta.cjs");
4
4
  const array_style_js_1 = require("./rules/array-style.cjs");
5
5
  const consistent_import_source_js_1 = require("./rules/consistent-import-source.cjs");
6
+ const consistent_import_js_1 = require("./rules/consistent-import.cjs");
6
7
  const consistent_object_schema_type_js_1 = require("./rules/consistent-object-schema-type.cjs");
7
8
  const no_any_schema_js_1 = require("./rules/no-any-schema.cjs");
8
9
  const no_empty_custom_schema_js_1 = require("./rules/no-empty-custom-schema.cjs");
@@ -26,6 +27,7 @@ const eslintPluginZod = {
26
27
  rules: {
27
28
  'array-style': array_style_js_1.arrayStyle,
28
29
  'consistent-import-source': consistent_import_source_js_1.consistentImportSource,
30
+ 'consistent-import': consistent_import_js_1.consistentImport,
29
31
  'consistent-object-schema-type': consistent_object_schema_type_js_1.consistentObjectSchemaType,
30
32
  'no-any-schema': no_any_schema_js_1.noAnySchema,
31
33
  'no-empty-custom-schema': no_empty_custom_schema_js_1.noEmptyCustomSchema,
@@ -51,6 +53,7 @@ const recommendedConfig = {
51
53
  },
52
54
  rules: {
53
55
  'zod/array-style': 'error',
56
+ 'zod/consistent-import': 'error',
54
57
  'zod/no-any-schema': 'error',
55
58
  'zod/no-empty-custom-schema': 'error',
56
59
  'zod/no-number-schema-with-int': 'error',
@@ -59,7 +62,6 @@ const recommendedConfig = {
59
62
  'zod/prefer-enum-over-literal-union': 'error',
60
63
  'zod/prefer-meta': 'error',
61
64
  'zod/prefer-meta-last': 'error',
62
- 'zod/prefer-namespace-import': 'error',
63
65
  'zod/require-brand-type-parameter': 'error',
64
66
  'zod/require-error-message': 'error',
65
67
  'zod/require-schema-suffix': 'error',
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { PLUGIN_NAME, PLUGIN_VERSION } from "./meta.js";
2
2
  import { arrayStyle } from "./rules/array-style.js";
3
3
  import { consistentImportSource } from "./rules/consistent-import-source.js";
4
+ import { consistentImport } from "./rules/consistent-import.js";
4
5
  import { consistentObjectSchemaType } from "./rules/consistent-object-schema-type.js";
5
6
  import { noAnySchema } from "./rules/no-any-schema.js";
6
7
  import { noEmptyCustomSchema } from "./rules/no-empty-custom-schema.js";
@@ -24,6 +25,7 @@ const eslintPluginZod = {
24
25
  rules: {
25
26
  'array-style': arrayStyle,
26
27
  'consistent-import-source': consistentImportSource,
28
+ 'consistent-import': consistentImport,
27
29
  'consistent-object-schema-type': consistentObjectSchemaType,
28
30
  'no-any-schema': noAnySchema,
29
31
  'no-empty-custom-schema': noEmptyCustomSchema,
@@ -49,6 +51,7 @@ const recommendedConfig = {
49
51
  },
50
52
  rules: {
51
53
  'zod/array-style': 'error',
54
+ 'zod/consistent-import': 'error',
52
55
  'zod/no-any-schema': 'error',
53
56
  'zod/no-empty-custom-schema': 'error',
54
57
  'zod/no-number-schema-with-int': 'error',
@@ -57,7 +60,6 @@ const recommendedConfig = {
57
60
  'zod/prefer-enum-over-literal-union': 'error',
58
61
  'zod/prefer-meta': 'error',
59
62
  'zod/prefer-meta-last': 'error',
60
- 'zod/prefer-namespace-import': 'error',
61
63
  'zod/require-brand-type-parameter': 'error',
62
64
  'zod/require-error-message': 'error',
63
65
  'zod/require-schema-suffix': 'error',
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.arrayStyle = void 0;
4
4
  const utils_1 = require("@typescript-eslint/utils");
5
5
  const meta_js_1 = require("../meta.cjs");
6
- const is_zod_expression_js_1 = require("../utils/is-zod-expression.cjs");
7
6
  const track_zod_schema_imports_js_1 = require("../utils/track-zod-schema-imports.cjs");
8
7
  const ZOD_ARRAY_STYLES = ['function', 'method'];
9
8
  const defaultOptions = { style: 'function' };
@@ -74,14 +73,17 @@ exports.arrayStyle = utils_1.ESLintUtils.RuleCreator(meta_js_1.getRuleURL)({
74
73
  }
75
74
  return;
76
75
  }
77
- const { callee } = node;
78
- if ((0, is_zod_expression_js_1.isZodExpressionEndingWithMethod)(callee, 'array') &&
79
- node.arguments.length === 0) {
76
+ const methods = collectZodChainMethods(node);
77
+ const arrayMethod = methods.find((it) => it.name === 'array' &&
78
+ it.node.arguments.length === 0);
79
+ if (arrayMethod) {
80
+ const arrayNode = arrayMethod.node;
80
81
  if (schemaDecl === 'namespace') {
81
82
  context.report({
82
83
  node,
83
84
  messageId: 'useFunction',
84
85
  fix(fixer) {
86
+ const callee = arrayNode.callee;
85
87
  const objText = sourceCode.getText(callee.object);
86
88
  return fixer.replaceText(node, `z.array(${objText})`);
87
89
  },
@@ -1,6 +1,5 @@
1
1
  import { ESLintUtils } from '@typescript-eslint/utils';
2
2
  import { getRuleURL } from "../meta.js";
3
- import { isZodExpressionEndingWithMethod } from "../utils/is-zod-expression.js";
4
3
  import { trackZodSchemaImports } from "../utils/track-zod-schema-imports.js";
5
4
  const ZOD_ARRAY_STYLES = ['function', 'method'];
6
5
  const defaultOptions = { style: 'function' };
@@ -71,14 +70,17 @@ export const arrayStyle = ESLintUtils.RuleCreator(getRuleURL)({
71
70
  }
72
71
  return;
73
72
  }
74
- const { callee } = node;
75
- if (isZodExpressionEndingWithMethod(callee, 'array') &&
76
- node.arguments.length === 0) {
73
+ const methods = collectZodChainMethods(node);
74
+ const arrayMethod = methods.find((it) => it.name === 'array' &&
75
+ it.node.arguments.length === 0);
76
+ if (arrayMethod) {
77
+ const arrayNode = arrayMethod.node;
77
78
  if (schemaDecl === 'namespace') {
78
79
  context.report({
79
80
  node,
80
81
  messageId: 'useFunction',
81
82
  fix(fixer) {
83
+ const callee = arrayNode.callee;
82
84
  const objText = sourceCode.getText(callee.object);
83
85
  return fixer.replaceText(node, `z.array(${objText})`);
84
86
  },
@@ -0,0 +1,178 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.consistentImport = void 0;
4
+ const utils_1 = require("@typescript-eslint/utils");
5
+ const meta_js_1 = require("../meta.cjs");
6
+ const is_zod_import_source_js_1 = require("../utils/is-zod-import-source.cjs");
7
+ const IMPORT_SYNTAXES = ['namespace', 'named'];
8
+ function isGroupFirstImportKindValidForSyntax(group, syntax) {
9
+ const { hasOnlyTypeImports, nodes } = group;
10
+ const [firstImportNode] = nodes;
11
+ const { specifiers, importKind } = firstImportNode;
12
+ if (specifiers.length !== 1) {
13
+ return false;
14
+ }
15
+ const [specifier] = specifiers;
16
+ const isValidForSyntax = syntax === 'named'
17
+ ? specifier.type === utils_1.AST_NODE_TYPES.ImportSpecifier &&
18
+ specifier.imported.type === utils_1.AST_NODE_TYPES.Identifier &&
19
+ specifier.imported.name === 'z'
20
+ : specifier.type === utils_1.AST_NODE_TYPES.ImportNamespaceSpecifier;
21
+ if (!isValidForSyntax) {
22
+ return false;
23
+ }
24
+ if (hasOnlyTypeImports) {
25
+ return importKind === 'type';
26
+ }
27
+ return true;
28
+ }
29
+ function shouldIdentifierBeRenamed(node) {
30
+ if (node.parent.type === utils_1.AST_NODE_TYPES.ImportSpecifier) {
31
+ return false;
32
+ }
33
+ if (node.parent.type === utils_1.AST_NODE_TYPES.MemberExpression &&
34
+ node.parent.object.type === utils_1.AST_NODE_TYPES.Identifier &&
35
+ node.parent.object.name !== node.name) {
36
+ return false;
37
+ }
38
+ return true;
39
+ }
40
+ function getNamespaceAliasNameFrom(node) {
41
+ if (node.type === utils_1.AST_NODE_TYPES.ImportDefaultSpecifier ||
42
+ node.type === utils_1.AST_NODE_TYPES.ImportNamespaceSpecifier) {
43
+ return node.local.name;
44
+ }
45
+ if (node.imported.type === utils_1.AST_NODE_TYPES.Identifier &&
46
+ node.imported.name === 'z') {
47
+ return node.local.name;
48
+ }
49
+ return null;
50
+ }
51
+ exports.consistentImport = utils_1.ESLintUtils.RuleCreator(meta_js_1.getRuleURL)({
52
+ name: 'consistent-import',
53
+ meta: {
54
+ type: 'problem',
55
+ docs: {
56
+ description: 'Enforce a consistent import style for Zod',
57
+ },
58
+ fixable: 'code',
59
+ messages: {
60
+ changeImportSyntax: 'Use a {{syntax}} import for Zod.',
61
+ removeDuplicate: 'Remove duplicate Zod import; Zod is already imported.',
62
+ convertUsage: 'Update Zod usage to match the {{syntax}} import syntax.',
63
+ },
64
+ schema: [
65
+ {
66
+ type: 'object',
67
+ properties: {
68
+ syntax: {
69
+ description: 'Specifies the import syntax to use for Zod.',
70
+ type: 'string',
71
+ enum: IMPORT_SYNTAXES,
72
+ },
73
+ },
74
+ additionalProperties: false,
75
+ },
76
+ ],
77
+ },
78
+ defaultOptions: [{ syntax: 'namespace' }],
79
+ create(context, [options]) {
80
+ const { syntax } = options;
81
+ const { sourceCode } = context;
82
+ const importGroups = {};
83
+ return {
84
+ ImportDeclaration(node) {
85
+ const { source, importKind } = node;
86
+ if (!(0, is_zod_import_source_js_1.isZodImportSource)(source.value)) {
87
+ return;
88
+ }
89
+ if (!importGroups[source.value]) {
90
+ importGroups[source.value] = {
91
+ hasOnlyTypeImports: true,
92
+ nodes: [],
93
+ };
94
+ }
95
+ if (importGroups[source.value].hasOnlyTypeImports &&
96
+ importKind === 'value') {
97
+ importGroups[source.value].hasOnlyTypeImports = false;
98
+ }
99
+ importGroups[source.value].nodes.push(node);
100
+ },
101
+ 'Program:exit': function () {
102
+ let namespaceAliasNameIndex = 0;
103
+ for (const importGroup of Object.values(importGroups)) {
104
+ const { hasOnlyTypeImports, nodes } = importGroup;
105
+ const [firstImportNode, ...othersImportNodes] = nodes;
106
+ const nodesWithVariablesToUpdate = [];
107
+ let namespaceAliasName = null;
108
+ for (const specifier of nodes.flatMap((it) => it.specifiers)) {
109
+ if (!namespaceAliasName) {
110
+ namespaceAliasName = getNamespaceAliasNameFrom(specifier);
111
+ if (namespaceAliasName) {
112
+ continue;
113
+ }
114
+ }
115
+ nodesWithVariablesToUpdate.push(specifier);
116
+ }
117
+ if (!namespaceAliasName) {
118
+ namespaceAliasName = 'z';
119
+ if (namespaceAliasNameIndex > 0) {
120
+ namespaceAliasName = `z${namespaceAliasNameIndex}`;
121
+ namespaceAliasNameIndex += 1;
122
+ }
123
+ }
124
+ const isFirstImportValid = isGroupFirstImportKindValidForSyntax(importGroup, syntax);
125
+ if (!isFirstImportValid) {
126
+ context.report({
127
+ node: firstImportNode,
128
+ messageId: 'changeImportSyntax',
129
+ data: { syntax },
130
+ fix(fixer) {
131
+ const importTypeKeyword = hasOnlyTypeImports ? 'type ' : '';
132
+ let importSpecifier;
133
+ if (syntax === 'named') {
134
+ if (namespaceAliasName === 'z') {
135
+ importSpecifier = '{ z }';
136
+ }
137
+ else {
138
+ importSpecifier = `{ z as ${namespaceAliasName} }`;
139
+ }
140
+ }
141
+ else {
142
+ importSpecifier = `* as ${namespaceAliasName}`;
143
+ }
144
+ const newImportText = `import ${importTypeKeyword}${importSpecifier} from ${firstImportNode.source.raw};`;
145
+ return fixer.replaceText(firstImportNode, newImportText);
146
+ },
147
+ });
148
+ }
149
+ const allVariables = nodesWithVariablesToUpdate.flatMap((it) => sourceCode.getDeclaredVariables(it));
150
+ const allReferences = allVariables.flatMap((it) => it.references);
151
+ for (const ref of allReferences) {
152
+ const { identifier } = ref;
153
+ if (shouldIdentifierBeRenamed(identifier)) {
154
+ context.report({
155
+ node: identifier,
156
+ messageId: 'convertUsage',
157
+ data: { syntax },
158
+ fix(fixer) {
159
+ const newId = `${namespaceAliasName}.${identifier.name}`;
160
+ return fixer.replaceText(identifier, newId);
161
+ },
162
+ });
163
+ }
164
+ }
165
+ for (const extraImport of othersImportNodes) {
166
+ context.report({
167
+ node: extraImport,
168
+ messageId: 'removeDuplicate',
169
+ fix(fixer) {
170
+ return fixer.removeRange(extraImport.range);
171
+ },
172
+ });
173
+ }
174
+ }
175
+ },
176
+ };
177
+ },
178
+ });
@@ -0,0 +1,11 @@
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+ declare const IMPORT_SYNTAXES: readonly ["namespace", "named"];
3
+ type ImportSyntax = (typeof IMPORT_SYNTAXES)[number];
4
+ interface Options {
5
+ syntax: ImportSyntax;
6
+ }
7
+ type MessageIds = 'changeImportSyntax' | 'removeDuplicate' | 'convertUsage';
8
+ export declare const consistentImport: ESLintUtils.RuleModule<MessageIds, [Options], unknown, ESLintUtils.RuleListener> & {
9
+ name: string;
10
+ };
11
+ export {};
@@ -0,0 +1,11 @@
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+ declare const IMPORT_SYNTAXES: readonly ["namespace", "named"];
3
+ type ImportSyntax = (typeof IMPORT_SYNTAXES)[number];
4
+ interface Options {
5
+ syntax: ImportSyntax;
6
+ }
7
+ type MessageIds = 'changeImportSyntax' | 'removeDuplicate' | 'convertUsage';
8
+ export declare const consistentImport: ESLintUtils.RuleModule<MessageIds, [Options], unknown, ESLintUtils.RuleListener> & {
9
+ name: string;
10
+ };
11
+ export {};
@@ -0,0 +1,175 @@
1
+ import { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/utils';
2
+ import { getRuleURL } from "../meta.js";
3
+ import { isZodImportSource } from "../utils/is-zod-import-source.js";
4
+ const IMPORT_SYNTAXES = ['namespace', 'named'];
5
+ function isGroupFirstImportKindValidForSyntax(group, syntax) {
6
+ const { hasOnlyTypeImports, nodes } = group;
7
+ const [firstImportNode] = nodes;
8
+ const { specifiers, importKind } = firstImportNode;
9
+ if (specifiers.length !== 1) {
10
+ return false;
11
+ }
12
+ const [specifier] = specifiers;
13
+ const isValidForSyntax = syntax === 'named'
14
+ ? specifier.type === AST_NODE_TYPES.ImportSpecifier &&
15
+ specifier.imported.type === AST_NODE_TYPES.Identifier &&
16
+ specifier.imported.name === 'z'
17
+ : specifier.type === AST_NODE_TYPES.ImportNamespaceSpecifier;
18
+ if (!isValidForSyntax) {
19
+ return false;
20
+ }
21
+ if (hasOnlyTypeImports) {
22
+ return importKind === 'type';
23
+ }
24
+ return true;
25
+ }
26
+ function shouldIdentifierBeRenamed(node) {
27
+ if (node.parent.type === AST_NODE_TYPES.ImportSpecifier) {
28
+ return false;
29
+ }
30
+ if (node.parent.type === AST_NODE_TYPES.MemberExpression &&
31
+ node.parent.object.type === AST_NODE_TYPES.Identifier &&
32
+ node.parent.object.name !== node.name) {
33
+ return false;
34
+ }
35
+ return true;
36
+ }
37
+ function getNamespaceAliasNameFrom(node) {
38
+ if (node.type === AST_NODE_TYPES.ImportDefaultSpecifier ||
39
+ node.type === AST_NODE_TYPES.ImportNamespaceSpecifier) {
40
+ return node.local.name;
41
+ }
42
+ if (node.imported.type === AST_NODE_TYPES.Identifier &&
43
+ node.imported.name === 'z') {
44
+ return node.local.name;
45
+ }
46
+ return null;
47
+ }
48
+ export const consistentImport = ESLintUtils.RuleCreator(getRuleURL)({
49
+ name: 'consistent-import',
50
+ meta: {
51
+ type: 'problem',
52
+ docs: {
53
+ description: 'Enforce a consistent import style for Zod',
54
+ },
55
+ fixable: 'code',
56
+ messages: {
57
+ changeImportSyntax: 'Use a {{syntax}} import for Zod.',
58
+ removeDuplicate: 'Remove duplicate Zod import; Zod is already imported.',
59
+ convertUsage: 'Update Zod usage to match the {{syntax}} import syntax.',
60
+ },
61
+ schema: [
62
+ {
63
+ type: 'object',
64
+ properties: {
65
+ syntax: {
66
+ description: 'Specifies the import syntax to use for Zod.',
67
+ type: 'string',
68
+ enum: IMPORT_SYNTAXES,
69
+ },
70
+ },
71
+ additionalProperties: false,
72
+ },
73
+ ],
74
+ },
75
+ defaultOptions: [{ syntax: 'namespace' }],
76
+ create(context, [options]) {
77
+ const { syntax } = options;
78
+ const { sourceCode } = context;
79
+ const importGroups = {};
80
+ return {
81
+ ImportDeclaration(node) {
82
+ const { source, importKind } = node;
83
+ if (!isZodImportSource(source.value)) {
84
+ return;
85
+ }
86
+ if (!importGroups[source.value]) {
87
+ importGroups[source.value] = {
88
+ hasOnlyTypeImports: true,
89
+ nodes: [],
90
+ };
91
+ }
92
+ if (importGroups[source.value].hasOnlyTypeImports &&
93
+ importKind === 'value') {
94
+ importGroups[source.value].hasOnlyTypeImports = false;
95
+ }
96
+ importGroups[source.value].nodes.push(node);
97
+ },
98
+ 'Program:exit': function () {
99
+ let namespaceAliasNameIndex = 0;
100
+ for (const importGroup of Object.values(importGroups)) {
101
+ const { hasOnlyTypeImports, nodes } = importGroup;
102
+ const [firstImportNode, ...othersImportNodes] = nodes;
103
+ const nodesWithVariablesToUpdate = [];
104
+ let namespaceAliasName = null;
105
+ for (const specifier of nodes.flatMap((it) => it.specifiers)) {
106
+ if (!namespaceAliasName) {
107
+ namespaceAliasName = getNamespaceAliasNameFrom(specifier);
108
+ if (namespaceAliasName) {
109
+ continue;
110
+ }
111
+ }
112
+ nodesWithVariablesToUpdate.push(specifier);
113
+ }
114
+ if (!namespaceAliasName) {
115
+ namespaceAliasName = 'z';
116
+ if (namespaceAliasNameIndex > 0) {
117
+ namespaceAliasName = `z${namespaceAliasNameIndex}`;
118
+ namespaceAliasNameIndex += 1;
119
+ }
120
+ }
121
+ const isFirstImportValid = isGroupFirstImportKindValidForSyntax(importGroup, syntax);
122
+ if (!isFirstImportValid) {
123
+ context.report({
124
+ node: firstImportNode,
125
+ messageId: 'changeImportSyntax',
126
+ data: { syntax },
127
+ fix(fixer) {
128
+ const importTypeKeyword = hasOnlyTypeImports ? 'type ' : '';
129
+ let importSpecifier;
130
+ if (syntax === 'named') {
131
+ if (namespaceAliasName === 'z') {
132
+ importSpecifier = '{ z }';
133
+ }
134
+ else {
135
+ importSpecifier = `{ z as ${namespaceAliasName} }`;
136
+ }
137
+ }
138
+ else {
139
+ importSpecifier = `* as ${namespaceAliasName}`;
140
+ }
141
+ const newImportText = `import ${importTypeKeyword}${importSpecifier} from ${firstImportNode.source.raw};`;
142
+ return fixer.replaceText(firstImportNode, newImportText);
143
+ },
144
+ });
145
+ }
146
+ const allVariables = nodesWithVariablesToUpdate.flatMap((it) => sourceCode.getDeclaredVariables(it));
147
+ const allReferences = allVariables.flatMap((it) => it.references);
148
+ for (const ref of allReferences) {
149
+ const { identifier } = ref;
150
+ if (shouldIdentifierBeRenamed(identifier)) {
151
+ context.report({
152
+ node: identifier,
153
+ messageId: 'convertUsage',
154
+ data: { syntax },
155
+ fix(fixer) {
156
+ const newId = `${namespaceAliasName}.${identifier.name}`;
157
+ return fixer.replaceText(identifier, newId);
158
+ },
159
+ });
160
+ }
161
+ }
162
+ for (const extraImport of othersImportNodes) {
163
+ context.report({
164
+ node: extraImport,
165
+ messageId: 'removeDuplicate',
166
+ fix(fixer) {
167
+ return fixer.removeRange(extraImport.range);
168
+ },
169
+ });
170
+ }
171
+ }
172
+ },
173
+ };
174
+ },
175
+ });
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.noNumberSchemaWithInt = void 0;
4
4
  const utils_1 = require("@typescript-eslint/utils");
5
5
  const meta_js_1 = require("../meta.cjs");
6
- const get_outermost_call_js_1 = require("../utils/get-outermost-call.cjs");
7
6
  const track_zod_schema_imports_js_1 = require("../utils/track-zod-schema-imports.cjs");
8
7
  exports.noNumberSchemaWithInt = utils_1.ESLintUtils.RuleCreator(meta_js_1.getRuleURL)({
9
8
  name: 'no-number-schema-with-int',
@@ -25,26 +24,18 @@ exports.noNumberSchemaWithInt = utils_1.ESLintUtils.RuleCreator(meta_js_1.getRul
25
24
  return {
26
25
  ImportDeclaration: importDeclarationListener,
27
26
  CallExpression(node) {
28
- var _a;
29
- const outer = (_a = (0, get_outermost_call_js_1.getOutermostCall)(node)) !== null && _a !== void 0 ? _a : node;
30
- const zodSchemaMeta = detectZodSchemaRootNode(outer);
31
- if (!zodSchemaMeta) {
27
+ const zodSchemaMeta = detectZodSchemaRootNode(node);
28
+ if ((zodSchemaMeta === null || zodSchemaMeta === void 0 ? void 0 : zodSchemaMeta.schemaType) !== 'number') {
32
29
  return;
33
30
  }
34
- if (zodSchemaMeta.schemaType !== 'number') {
35
- return;
36
- }
37
- const methods = collectZodChainMethods(outer);
31
+ const methods = collectZodChainMethods(node);
38
32
  const numberIndex = methods.findIndex((m) => m.name === 'number');
39
33
  const intIndex = methods.findIndex((m) => m.name === 'int');
40
34
  if (numberIndex === -1 || intIndex === -1) {
41
35
  return;
42
36
  }
43
- const numberMethod = methods[numberIndex];
44
- const intMethod = methods[intIndex];
45
- if (node !== intMethod.node) {
46
- return;
47
- }
37
+ const numberNode = methods[numberIndex].node;
38
+ const intNode = methods[intIndex].node;
48
39
  if (zodSchemaMeta.schemaDecl === 'named') {
49
40
  context.report({
50
41
  node,
@@ -56,8 +47,6 @@ exports.noNumberSchemaWithInt = utils_1.ESLintUtils.RuleCreator(meta_js_1.getRul
56
47
  node,
57
48
  messageId: 'removeNumber',
58
49
  fix(fixer) {
59
- const numberNode = numberMethod.node;
60
- const intNode = intMethod.node;
61
50
  const numberCallee = numberNode.callee;
62
51
  const prefixObj = numberCallee.object;
63
52
  const prefixText = sourceCode.getText(prefixObj);
@@ -1,6 +1,5 @@
1
1
  import { ESLintUtils } from '@typescript-eslint/utils';
2
2
  import { getRuleURL } from "../meta.js";
3
- import { getOutermostCall } from "../utils/get-outermost-call.js";
4
3
  import { trackZodSchemaImports } from "../utils/track-zod-schema-imports.js";
5
4
  export const noNumberSchemaWithInt = ESLintUtils.RuleCreator(getRuleURL)({
6
5
  name: 'no-number-schema-with-int',
@@ -22,26 +21,18 @@ export const noNumberSchemaWithInt = ESLintUtils.RuleCreator(getRuleURL)({
22
21
  return {
23
22
  ImportDeclaration: importDeclarationListener,
24
23
  CallExpression(node) {
25
- var _a;
26
- const outer = (_a = getOutermostCall(node)) !== null && _a !== void 0 ? _a : node;
27
- const zodSchemaMeta = detectZodSchemaRootNode(outer);
28
- if (!zodSchemaMeta) {
24
+ const zodSchemaMeta = detectZodSchemaRootNode(node);
25
+ if ((zodSchemaMeta === null || zodSchemaMeta === void 0 ? void 0 : zodSchemaMeta.schemaType) !== 'number') {
29
26
  return;
30
27
  }
31
- if (zodSchemaMeta.schemaType !== 'number') {
32
- return;
33
- }
34
- const methods = collectZodChainMethods(outer);
28
+ const methods = collectZodChainMethods(node);
35
29
  const numberIndex = methods.findIndex((m) => m.name === 'number');
36
30
  const intIndex = methods.findIndex((m) => m.name === 'int');
37
31
  if (numberIndex === -1 || intIndex === -1) {
38
32
  return;
39
33
  }
40
- const numberMethod = methods[numberIndex];
41
- const intMethod = methods[intIndex];
42
- if (node !== intMethod.node) {
43
- return;
44
- }
34
+ const numberNode = methods[numberIndex].node;
35
+ const intNode = methods[intIndex].node;
45
36
  if (zodSchemaMeta.schemaDecl === 'named') {
46
37
  context.report({
47
38
  node,
@@ -53,8 +44,6 @@ export const noNumberSchemaWithInt = ESLintUtils.RuleCreator(getRuleURL)({
53
44
  node,
54
45
  messageId: 'removeNumber',
55
46
  fix(fixer) {
56
- const numberNode = numberMethod.node;
57
- const intNode = intMethod.node;
58
47
  const numberCallee = numberNode.callee;
59
48
  const prefixObj = numberCallee.object;
60
49
  const prefixText = sourceCode.getText(prefixObj);
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.noThrowInRefine = void 0;
4
4
  const utils_1 = require("@typescript-eslint/utils");
5
5
  const meta_js_1 = require("../meta.cjs");
6
- const is_zod_expression_js_1 = require("../utils/is-zod-expression.cjs");
7
6
  const track_zod_schema_imports_js_1 = require("../utils/track-zod-schema-imports.cjs");
8
7
  exports.noThrowInRefine = utils_1.ESLintUtils.RuleCreator(meta_js_1.getRuleURL)({
9
8
  name: 'no-throw-in-refine',
@@ -19,7 +18,7 @@ exports.noThrowInRefine = utils_1.ESLintUtils.RuleCreator(meta_js_1.getRuleURL)(
19
18
  },
20
19
  defaultOptions: [],
21
20
  create(context) {
22
- const { importDeclarationListener, detectZodSchemaRootNode, } = (0, track_zod_schema_imports_js_1.trackZodSchemaImports)();
21
+ const { importDeclarationListener, detectZodSchemaRootNode, collectZodChainMethods, } = (0, track_zod_schema_imports_js_1.trackZodSchemaImports)();
23
22
  function checkNode(node) {
24
23
  if (!node) {
25
24
  return;
@@ -71,12 +70,15 @@ exports.noThrowInRefine = utils_1.ESLintUtils.RuleCreator(meta_js_1.getRuleURL)(
71
70
  if (!zodSchemaMeta) {
72
71
  return;
73
72
  }
74
- if ((0, is_zod_expression_js_1.isZodExpressionEndingWithMethod)(node.callee, 'refine')) {
75
- const [callback] = node.arguments;
76
- if (callback.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression ||
77
- callback.type === utils_1.AST_NODE_TYPES.FunctionExpression) {
78
- checkNode(callback.body);
79
- }
73
+ const methods = collectZodChainMethods(node);
74
+ const refineMethod = methods.find((it) => it.name === 'refine');
75
+ if (!refineMethod) {
76
+ return;
77
+ }
78
+ const [callback] = refineMethod.node.arguments;
79
+ if (callback.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression ||
80
+ callback.type === utils_1.AST_NODE_TYPES.FunctionExpression) {
81
+ checkNode(callback.body);
80
82
  }
81
83
  },
82
84
  };
@@ -1,6 +1,5 @@
1
1
  import { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/utils';
2
2
  import { getRuleURL } from "../meta.js";
3
- import { isZodExpressionEndingWithMethod } from "../utils/is-zod-expression.js";
4
3
  import { trackZodSchemaImports } from "../utils/track-zod-schema-imports.js";
5
4
  export const noThrowInRefine = ESLintUtils.RuleCreator(getRuleURL)({
6
5
  name: 'no-throw-in-refine',
@@ -16,7 +15,7 @@ export const noThrowInRefine = ESLintUtils.RuleCreator(getRuleURL)({
16
15
  },
17
16
  defaultOptions: [],
18
17
  create(context) {
19
- const { importDeclarationListener, detectZodSchemaRootNode, } = trackZodSchemaImports();
18
+ const { importDeclarationListener, detectZodSchemaRootNode, collectZodChainMethods, } = trackZodSchemaImports();
20
19
  function checkNode(node) {
21
20
  if (!node) {
22
21
  return;
@@ -68,12 +67,15 @@ export const noThrowInRefine = ESLintUtils.RuleCreator(getRuleURL)({
68
67
  if (!zodSchemaMeta) {
69
68
  return;
70
69
  }
71
- if (isZodExpressionEndingWithMethod(node.callee, 'refine')) {
72
- const [callback] = node.arguments;
73
- if (callback.type === AST_NODE_TYPES.ArrowFunctionExpression ||
74
- callback.type === AST_NODE_TYPES.FunctionExpression) {
75
- checkNode(callback.body);
76
- }
70
+ const methods = collectZodChainMethods(node);
71
+ const refineMethod = methods.find((it) => it.name === 'refine');
72
+ if (!refineMethod) {
73
+ return;
74
+ }
75
+ const [callback] = refineMethod.node.arguments;
76
+ if (callback.type === AST_NODE_TYPES.ArrowFunctionExpression ||
77
+ callback.type === AST_NODE_TYPES.FunctionExpression) {
78
+ checkNode(callback.body);
77
79
  }
78
80
  },
79
81
  };
@@ -19,7 +19,7 @@ exports.preferEnumOverLiteralUnion = utils_1.ESLintUtils.RuleCreator(meta_js_1.g
19
19
  },
20
20
  defaultOptions: [],
21
21
  create(context) {
22
- const { importDeclarationListener, detectZodSchemaRootNode, } = (0, track_zod_schema_imports_js_1.trackZodSchemaImports)();
22
+ const { importDeclarationListener, detectZodSchemaRootNode, collectZodChainMethods, } = (0, track_zod_schema_imports_js_1.trackZodSchemaImports)();
23
23
  return {
24
24
  ImportDeclaration: importDeclarationListener,
25
25
  CallExpression(node) {
@@ -27,7 +27,13 @@ exports.preferEnumOverLiteralUnion = utils_1.ESLintUtils.RuleCreator(meta_js_1.g
27
27
  if ((zodSchema === null || zodSchema === void 0 ? void 0 : zodSchema.schemaType) !== 'union') {
28
28
  return;
29
29
  }
30
- const unionArgument = node.arguments.at(0);
30
+ const methods = collectZodChainMethods(zodSchema.node);
31
+ const union = methods.find((it) => it.name === 'union');
32
+ if (!union) {
33
+ return;
34
+ }
35
+ const unionNode = union.node;
36
+ const unionArgument = unionNode.arguments.at(0);
31
37
  if ((unionArgument === null || unionArgument === void 0 ? void 0 : unionArgument.type) !== utils_1.AST_NODE_TYPES.ArrayExpression) {
32
38
  return;
33
39
  }
@@ -61,8 +67,8 @@ exports.preferEnumOverLiteralUnion = utils_1.ESLintUtils.RuleCreator(meta_js_1.g
61
67
  messageId: 'useEnum',
62
68
  fix(fixer) {
63
69
  return [
64
- fixer.replaceText(node.callee.property, 'enum'),
65
- fixer.replaceText(node.arguments[0], `[${zodLiteralStrings.join(', ')}]`),
70
+ fixer.replaceText(unionNode.callee.property, 'enum'),
71
+ fixer.replaceText(unionNode.arguments[0], `[${zodLiteralStrings.join(', ')}]`),
66
72
  ];
67
73
  },
68
74
  });
@@ -16,7 +16,7 @@ export const preferEnumOverLiteralUnion = ESLintUtils.RuleCreator(getRuleURL)({
16
16
  },
17
17
  defaultOptions: [],
18
18
  create(context) {
19
- const { importDeclarationListener, detectZodSchemaRootNode, } = trackZodSchemaImports();
19
+ const { importDeclarationListener, detectZodSchemaRootNode, collectZodChainMethods, } = trackZodSchemaImports();
20
20
  return {
21
21
  ImportDeclaration: importDeclarationListener,
22
22
  CallExpression(node) {
@@ -24,7 +24,13 @@ export const preferEnumOverLiteralUnion = ESLintUtils.RuleCreator(getRuleURL)({
24
24
  if ((zodSchema === null || zodSchema === void 0 ? void 0 : zodSchema.schemaType) !== 'union') {
25
25
  return;
26
26
  }
27
- const unionArgument = node.arguments.at(0);
27
+ const methods = collectZodChainMethods(zodSchema.node);
28
+ const union = methods.find((it) => it.name === 'union');
29
+ if (!union) {
30
+ return;
31
+ }
32
+ const unionNode = union.node;
33
+ const unionArgument = unionNode.arguments.at(0);
28
34
  if ((unionArgument === null || unionArgument === void 0 ? void 0 : unionArgument.type) !== AST_NODE_TYPES.ArrayExpression) {
29
35
  return;
30
36
  }
@@ -58,8 +64,8 @@ export const preferEnumOverLiteralUnion = ESLintUtils.RuleCreator(getRuleURL)({
58
64
  messageId: 'useEnum',
59
65
  fix(fixer) {
60
66
  return [
61
- fixer.replaceText(node.callee.property, 'enum'),
62
- fixer.replaceText(node.arguments[0], `[${zodLiteralStrings.join(', ')}]`),
67
+ fixer.replaceText(unionNode.callee.property, 'enum'),
68
+ fixer.replaceText(unionNode.arguments[0], `[${zodLiteralStrings.join(', ')}]`),
63
69
  ];
64
70
  },
65
71
  });
@@ -3,8 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.preferMetaLast = void 0;
4
4
  const utils_1 = require("@typescript-eslint/utils");
5
5
  const meta_js_1 = require("../meta.cjs");
6
- const get_outermost_call_js_1 = require("../utils/get-outermost-call.cjs");
7
- const is_zod_expression_js_1 = require("../utils/is-zod-expression.cjs");
8
6
  const track_zod_schema_imports_js_1 = require("../utils/track-zod-schema-imports.cjs");
9
7
  exports.preferMetaLast = utils_1.ESLintUtils.RuleCreator(meta_js_1.getRuleURL)({
10
8
  name: 'prefer-meta-last',
@@ -23,19 +21,11 @@ exports.preferMetaLast = utils_1.ESLintUtils.RuleCreator(meta_js_1.getRuleURL)({
23
21
  return {
24
22
  ImportDeclaration: importDeclarationListener,
25
23
  CallExpression(node) {
26
- if (node.callee.type !== utils_1.AST_NODE_TYPES.MemberExpression ||
27
- !(0, is_zod_expression_js_1.isZodExpressionEndingWithMethod)(node.callee, 'meta')) {
28
- return;
29
- }
30
- const outer = (0, get_outermost_call_js_1.getOutermostCall)(node);
31
- if (!outer) {
32
- return;
33
- }
34
- const zodSchemaMeta = detectZodSchemaRootNode(outer);
35
- const chain = collectZodChainMethods(outer);
24
+ const zodSchemaMeta = detectZodSchemaRootNode(node);
36
25
  if (!zodSchemaMeta) {
37
26
  return;
38
27
  }
28
+ const chain = collectZodChainMethods(node);
39
29
  const metaIndex = chain.findIndex((c) => c.name === 'meta');
40
30
  if (metaIndex === -1) {
41
31
  return;
@@ -1,7 +1,5 @@
1
- import { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/utils';
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
2
  import { getRuleURL } from "../meta.js";
3
- import { getOutermostCall } from "../utils/get-outermost-call.js";
4
- import { isZodExpressionEndingWithMethod } from "../utils/is-zod-expression.js";
5
3
  import { trackZodSchemaImports } from "../utils/track-zod-schema-imports.js";
6
4
  export const preferMetaLast = ESLintUtils.RuleCreator(getRuleURL)({
7
5
  name: 'prefer-meta-last',
@@ -20,19 +18,11 @@ export const preferMetaLast = ESLintUtils.RuleCreator(getRuleURL)({
20
18
  return {
21
19
  ImportDeclaration: importDeclarationListener,
22
20
  CallExpression(node) {
23
- if (node.callee.type !== AST_NODE_TYPES.MemberExpression ||
24
- !isZodExpressionEndingWithMethod(node.callee, 'meta')) {
25
- return;
26
- }
27
- const outer = getOutermostCall(node);
28
- if (!outer) {
29
- return;
30
- }
31
- const zodSchemaMeta = detectZodSchemaRootNode(outer);
32
- const chain = collectZodChainMethods(outer);
21
+ const zodSchemaMeta = detectZodSchemaRootNode(node);
33
22
  if (!zodSchemaMeta) {
34
23
  return;
35
24
  }
25
+ const chain = collectZodChainMethods(node);
36
26
  const metaIndex = chain.findIndex((c) => c.name === 'meta');
37
27
  if (metaIndex === -1) {
38
28
  return;
@@ -46,6 +46,9 @@ exports.preferNamespaceImport = utils_1.ESLintUtils.RuleCreator(meta_js_1.getRul
46
46
  name: 'prefer-namespace-import',
47
47
  meta: {
48
48
  type: 'suggestion',
49
+ deprecated: {
50
+ message: "Use `zod/consistent-import` with `{ syntax: 'namespace' }`",
51
+ },
49
52
  docs: {
50
53
  description: "Enforce importing zod as a namespace import (`import * as z from 'zod'`)",
51
54
  },
@@ -1,4 +1,4 @@
1
1
  import { ESLintUtils } from '@typescript-eslint/utils';
2
- export declare const preferNamespaceImport: ESLintUtils.RuleModule<"useNamespace" | "removeDuplicate" | "convertUsage", [], unknown, ESLintUtils.RuleListener> & {
2
+ export declare const preferNamespaceImport: ESLintUtils.RuleModule<"removeDuplicate" | "convertUsage" | "useNamespace", [], unknown, ESLintUtils.RuleListener> & {
3
3
  name: string;
4
4
  };
@@ -1,4 +1,4 @@
1
1
  import { ESLintUtils } from '@typescript-eslint/utils';
2
- export declare const preferNamespaceImport: ESLintUtils.RuleModule<"useNamespace" | "removeDuplicate" | "convertUsage", [], unknown, ESLintUtils.RuleListener> & {
2
+ export declare const preferNamespaceImport: ESLintUtils.RuleModule<"removeDuplicate" | "convertUsage" | "useNamespace", [], unknown, ESLintUtils.RuleListener> & {
3
3
  name: string;
4
4
  };
@@ -43,6 +43,9 @@ export const preferNamespaceImport = ESLintUtils.RuleCreator(getRuleURL)({
43
43
  name: 'prefer-namespace-import',
44
44
  meta: {
45
45
  type: 'suggestion',
46
+ deprecated: {
47
+ message: "Use `zod/consistent-import` with `{ syntax: 'namespace' }`",
48
+ },
46
49
  docs: {
47
50
  description: "Enforce importing zod as a namespace import (`import * as z from 'zod'`)",
48
51
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-zod",
3
- "version": "3.0.1",
3
+ "version": "3.1.0",
4
4
  "type": "module",
5
5
  "description": "ESLint plugin that adds custom linting rules to enforce best practices when using Zod",
6
6
  "engines": {
@@ -62,18 +62,20 @@
62
62
  "@marcalexiei/prettier-config": "1.1.4",
63
63
  "@types/esquery": "1.5.4",
64
64
  "@types/node": "24.10.1",
65
- "@typescript-eslint/rule-tester": "8.51.0",
66
- "@vitest/eslint-plugin": "1.6.4",
65
+ "@typescript-eslint/rule-tester": "8.54.0",
66
+ "@vitest/eslint-plugin": "1.6.6",
67
67
  "dedent": "1.7.1",
68
68
  "eslint": "9.39.2",
69
69
  "eslint-doc-generator": "3.0.2",
70
- "eslint-plugin-eslint-plugin": "7.2.0",
71
- "eslint-plugin-n": "17.23.1",
72
- "knip": "5.79.0",
73
- "prettier": "3.7.4",
70
+ "eslint-import-resolver-typescript": "4.4.4",
71
+ "eslint-plugin-eslint-plugin": "7.3.0",
72
+ "eslint-plugin-import-x": "4.16.1",
73
+ "eslint-plugin-n": "17.23.2",
74
+ "knip": "5.83.0",
75
+ "prettier": "3.8.1",
74
76
  "typescript": "5.9.3",
75
- "typescript-eslint": "8.51.0",
76
- "vitest": "4.0.16",
77
+ "typescript-eslint": "8.54.0",
78
+ "vitest": "4.0.18",
77
79
  "zshy": "0.7.0"
78
80
  },
79
81
  "scripts": {
@@ -1,14 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getOutermostCall = getOutermostCall;
4
- const utils_1 = require("@typescript-eslint/utils");
5
- function getOutermostCall(node) {
6
- var _a;
7
- let current = node;
8
- while (((_a = current.parent) === null || _a === void 0 ? void 0 : _a.type) === utils_1.AST_NODE_TYPES.MemberExpression &&
9
- current.parent.object === current &&
10
- current.parent.parent.type === utils_1.AST_NODE_TYPES.CallExpression) {
11
- current = current.parent.parent;
12
- }
13
- return current.type === utils_1.AST_NODE_TYPES.CallExpression ? current : null;
14
- }
@@ -1,2 +0,0 @@
1
- import type { TSESTree } from '@typescript-eslint/utils';
2
- export declare function getOutermostCall(node: TSESTree.Node): TSESTree.CallExpression | null;
@@ -1,2 +0,0 @@
1
- import type { TSESTree } from '@typescript-eslint/utils';
2
- export declare function getOutermostCall(node: TSESTree.Node): TSESTree.CallExpression | null;
@@ -1,11 +0,0 @@
1
- import { AST_NODE_TYPES } from '@typescript-eslint/utils';
2
- export function getOutermostCall(node) {
3
- var _a;
4
- let current = node;
5
- while (((_a = current.parent) === null || _a === void 0 ? void 0 : _a.type) === AST_NODE_TYPES.MemberExpression &&
6
- current.parent.object === current &&
7
- current.parent.parent.type === AST_NODE_TYPES.CallExpression) {
8
- current = current.parent.parent;
9
- }
10
- return current.type === AST_NODE_TYPES.CallExpression ? current : null;
11
- }
@@ -1,14 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isZodExpressionEndingWithMethod = isZodExpressionEndingWithMethod;
4
- const utils_1 = require("@typescript-eslint/utils");
5
- function isZodExpressionEndingWithMethod(node, propName) {
6
- if (node.type !== utils_1.AST_NODE_TYPES.MemberExpression) {
7
- return false;
8
- }
9
- if (node.property.type === utils_1.AST_NODE_TYPES.Identifier &&
10
- node.property.name === propName) {
11
- return true;
12
- }
13
- return false;
14
- }
@@ -1,2 +0,0 @@
1
- import type { TSESTree } from '@typescript-eslint/utils';
2
- export declare function isZodExpressionEndingWithMethod(node: TSESTree.Node, propName: string): node is TSESTree.MemberExpression;
@@ -1,2 +0,0 @@
1
- import type { TSESTree } from '@typescript-eslint/utils';
2
- export declare function isZodExpressionEndingWithMethod(node: TSESTree.Node, propName: string): node is TSESTree.MemberExpression;
@@ -1,11 +0,0 @@
1
- import { AST_NODE_TYPES } from '@typescript-eslint/utils';
2
- export function isZodExpressionEndingWithMethod(node, propName) {
3
- if (node.type !== AST_NODE_TYPES.MemberExpression) {
4
- return false;
5
- }
6
- if (node.property.type === AST_NODE_TYPES.Identifier &&
7
- node.property.name === propName) {
8
- return true;
9
- }
10
- return false;
11
- }