eslint-plugin-zod 4.11.0 → 4.12.1

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.
@@ -1,5 +1,7 @@
1
1
  const require_create_plugin_rule = require("../utils/create-plugin-rule.cjs");
2
+ const require_has_zod_runtime_import_root = require("../utils/has-zod-runtime-import-root.cjs");
2
3
  let _eslint_zod_utils = require("@eslint-zod/utils");
4
+ let _typescript_eslint_utils = require("@typescript-eslint/utils");
3
5
  const arrayStyle = require_create_plugin_rule.createZodPluginRule({
4
6
  name: "array-style",
5
7
  meta: {
@@ -25,6 +27,7 @@ const arrayStyle = require_create_plugin_rule.createZodPluginRule({
25
27
  const { sourceCode } = context;
26
28
  const { createSchemaVisitor, collectZodChainMethods } = _eslint_zod_utils.zodImportScope.createTracker();
27
29
  return createSchemaVisitor({ onSchema(node, zodSchemaMeta) {
30
+ if (!require_has_zod_runtime_import_root.hasZodRuntimeImportRoot(node, sourceCode)) return;
28
31
  const { schemaDecl, schemaType } = zodSchemaMeta;
29
32
  if (style === "method") {
30
33
  if (schemaType === "array") {
@@ -34,9 +37,10 @@ const arrayStyle = require_create_plugin_rule.createZodPluginRule({
34
37
  messageId: "useMethod",
35
38
  fix(fixer) {
36
39
  const arrayCall = collectZodChainMethods(node).find((c) => c.name === "array");
37
- if (!arrayCall) return null;
38
- const arg = arrayCall.node.arguments.at(0);
39
- if (!arg) return null;
40
+ if (arrayCall?.node.arguments.length !== 1 || arrayCall.node.typeArguments || arrayCall.node.optional || arrayCall.node.callee.type === _typescript_eslint_utils.AST_NODE_TYPES.MemberExpression && arrayCall.node.callee.optional) return null;
41
+ const [arg] = arrayCall.node.arguments;
42
+ if (arg.type !== _typescript_eslint_utils.AST_NODE_TYPES.Identifier && arg.type !== _typescript_eslint_utils.AST_NODE_TYPES.MemberExpression && arg.type !== _typescript_eslint_utils.AST_NODE_TYPES.CallExpression) return null;
43
+ if (sourceCode.getCommentsInside(arrayCall.node).some((comment) => comment.range[0] < arg.range[0] || comment.range[1] > arg.range[1])) return null;
40
44
  const argText = sourceCode.getText(arg);
41
45
  return fixer.replaceText(arrayCall.node, `${argText}.array()`);
42
46
  }
@@ -1,5 +1,7 @@
1
1
  import { createZodPluginRule } from "../utils/create-plugin-rule.mjs";
2
+ import { hasZodRuntimeImportRoot } from "../utils/has-zod-runtime-import-root.mjs";
2
3
  import { zodImportScope } from "@eslint-zod/utils";
4
+ import { AST_NODE_TYPES } from "@typescript-eslint/utils";
3
5
  const arrayStyle = createZodPluginRule({
4
6
  name: "array-style",
5
7
  meta: {
@@ -25,6 +27,7 @@ const arrayStyle = createZodPluginRule({
25
27
  const { sourceCode } = context;
26
28
  const { createSchemaVisitor, collectZodChainMethods } = zodImportScope.createTracker();
27
29
  return createSchemaVisitor({ onSchema(node, zodSchemaMeta) {
30
+ if (!hasZodRuntimeImportRoot(node, sourceCode)) return;
28
31
  const { schemaDecl, schemaType } = zodSchemaMeta;
29
32
  if (style === "method") {
30
33
  if (schemaType === "array") {
@@ -34,9 +37,10 @@ const arrayStyle = createZodPluginRule({
34
37
  messageId: "useMethod",
35
38
  fix(fixer) {
36
39
  const arrayCall = collectZodChainMethods(node).find((c) => c.name === "array");
37
- if (!arrayCall) return null;
38
- const arg = arrayCall.node.arguments.at(0);
39
- if (!arg) return null;
40
+ if (arrayCall?.node.arguments.length !== 1 || arrayCall.node.typeArguments || arrayCall.node.optional || arrayCall.node.callee.type === AST_NODE_TYPES.MemberExpression && arrayCall.node.callee.optional) return null;
41
+ const [arg] = arrayCall.node.arguments;
42
+ if (arg.type !== AST_NODE_TYPES.Identifier && arg.type !== AST_NODE_TYPES.MemberExpression && arg.type !== AST_NODE_TYPES.CallExpression) return null;
43
+ if (sourceCode.getCommentsInside(arrayCall.node).some((comment) => comment.range[0] < arg.range[0] || comment.range[1] > arg.range[1])) return null;
40
44
  const argText = sourceCode.getText(arg);
41
45
  return fixer.replaceText(arrayCall.node, `${argText}.array()`);
42
46
  }
@@ -1,6 +1,5 @@
1
1
  const require_create_plugin_rule = require("../utils/create-plugin-rule.cjs");
2
2
  let _eslint_zod_utils = require("@eslint-zod/utils");
3
- let _typescript_eslint_utils = require("@typescript-eslint/utils");
4
3
  let _eslint_zod_utils_rule_builders_no_transform_in_record_key = require("@eslint-zod/utils/rule-builders/no-transform-in-record-key");
5
4
  //#region src/rules/no-transform-in-record-key.ts
6
5
  const TRANSFORM_METHODS = [
@@ -17,10 +16,7 @@ const noTransformInRecordKey = require_create_plugin_rule.createZodPluginRule({
17
16
  schema: []
18
17
  },
19
18
  defaultOptions: [],
20
- create: (0, _eslint_zod_utils_rule_builders_no_transform_in_record_key.buildNoTransformInRecordKeyCreate)(_eslint_zod_utils.zodImportScope, { findTransformNode(keySchema, { collectZodChainMethods }) {
21
- if (keySchema.type !== _typescript_eslint_utils.AST_NODE_TYPES.CallExpression) return null;
22
- return collectZodChainMethods(keySchema).some((method) => TRANSFORM_METHODS.includes(method.name)) ? keySchema : null;
23
- } })
19
+ create: (0, _eslint_zod_utils_rule_builders_no_transform_in_record_key.buildNoTransformInRecordKeyCreate)(_eslint_zod_utils.zodImportScope, TRANSFORM_METHODS)
24
20
  });
25
21
  //#endregion
26
22
  exports.noTransformInRecordKey = noTransformInRecordKey;
@@ -1,6 +1,5 @@
1
1
  import { createZodPluginRule } from "../utils/create-plugin-rule.mjs";
2
2
  import { ZOD_MUTATING_CHECK_NAMES, zodImportScope } from "@eslint-zod/utils";
3
- import { AST_NODE_TYPES } from "@typescript-eslint/utils";
4
3
  import { buildNoTransformInRecordKeyCreate } from "@eslint-zod/utils/rule-builders/no-transform-in-record-key";
5
4
  //#region src/rules/no-transform-in-record-key.ts
6
5
  const TRANSFORM_METHODS = [
@@ -17,10 +16,7 @@ const noTransformInRecordKey = createZodPluginRule({
17
16
  schema: []
18
17
  },
19
18
  defaultOptions: [],
20
- create: buildNoTransformInRecordKeyCreate(zodImportScope, { findTransformNode(keySchema, { collectZodChainMethods }) {
21
- if (keySchema.type !== AST_NODE_TYPES.CallExpression) return null;
22
- return collectZodChainMethods(keySchema).some((method) => TRANSFORM_METHODS.includes(method.name)) ? keySchema : null;
23
- } })
19
+ create: buildNoTransformInRecordKeyCreate(zodImportScope, TRANSFORM_METHODS)
24
20
  });
25
21
  //#endregion
26
22
  export { noTransformInRecordKey };
@@ -0,0 +1,21 @@
1
+ let _eslint_zod_utils = require("@eslint-zod/utils");
2
+ let _typescript_eslint_utils = require("@typescript-eslint/utils");
3
+ //#region src/utils/has-zod-runtime-import-root.ts
4
+ /**
5
+ * Whether the identifier a chain starts from resolves to a runtime zod import.
6
+ * Bails on a root that is shadowed, re-assigned, type-only, or imported from another source —
7
+ * every case where a fix would rewrite code that is not zod, or reference a binding erased at runtime.
8
+ */
9
+ function hasZodRuntimeImportRoot(node, sourceCode) {
10
+ let root = node;
11
+ while (root.type === _typescript_eslint_utils.AST_NODE_TYPES.CallExpression || root.type === _typescript_eslint_utils.AST_NODE_TYPES.MemberExpression) root = root.type === _typescript_eslint_utils.AST_NODE_TYPES.CallExpression ? root.callee : root.object;
12
+ if (root.type !== _typescript_eslint_utils.AST_NODE_TYPES.Identifier) return false;
13
+ const variable = _typescript_eslint_utils.ASTUtils.findVariable(sourceCode.getScope(root), root);
14
+ if (variable?.defs.length !== 1) return false;
15
+ const [definition] = variable.defs;
16
+ if (definition.type !== _typescript_eslint_utils.TSESLint.Scope.DefinitionType.ImportBinding || definition.parent.type !== _typescript_eslint_utils.AST_NODE_TYPES.ImportDeclaration || definition.parent.importKind === "type" || !_eslint_zod_utils.zodImportScope.isAllowed(definition.parent.source.value)) return false;
17
+ const specifier = definition.node;
18
+ return specifier.type === _typescript_eslint_utils.AST_NODE_TYPES.ImportDefaultSpecifier || specifier.type === _typescript_eslint_utils.AST_NODE_TYPES.ImportNamespaceSpecifier || specifier.type === _typescript_eslint_utils.AST_NODE_TYPES.ImportSpecifier && specifier.importKind !== "type";
19
+ }
20
+ //#endregion
21
+ exports.hasZodRuntimeImportRoot = hasZodRuntimeImportRoot;
@@ -0,0 +1,21 @@
1
+ import { zodImportScope } from "@eslint-zod/utils";
2
+ import { ASTUtils, AST_NODE_TYPES, TSESLint } from "@typescript-eslint/utils";
3
+ //#region src/utils/has-zod-runtime-import-root.ts
4
+ /**
5
+ * Whether the identifier a chain starts from resolves to a runtime zod import.
6
+ * Bails on a root that is shadowed, re-assigned, type-only, or imported from another source —
7
+ * every case where a fix would rewrite code that is not zod, or reference a binding erased at runtime.
8
+ */
9
+ function hasZodRuntimeImportRoot(node, sourceCode) {
10
+ let root = node;
11
+ while (root.type === AST_NODE_TYPES.CallExpression || root.type === AST_NODE_TYPES.MemberExpression) root = root.type === AST_NODE_TYPES.CallExpression ? root.callee : root.object;
12
+ if (root.type !== AST_NODE_TYPES.Identifier) return false;
13
+ const variable = ASTUtils.findVariable(sourceCode.getScope(root), root);
14
+ if (variable?.defs.length !== 1) return false;
15
+ const [definition] = variable.defs;
16
+ if (definition.type !== TSESLint.Scope.DefinitionType.ImportBinding || definition.parent.type !== AST_NODE_TYPES.ImportDeclaration || definition.parent.importKind === "type" || !zodImportScope.isAllowed(definition.parent.source.value)) return false;
17
+ const specifier = definition.node;
18
+ return specifier.type === AST_NODE_TYPES.ImportDefaultSpecifier || specifier.type === AST_NODE_TYPES.ImportNamespaceSpecifier || specifier.type === AST_NODE_TYPES.ImportSpecifier && specifier.importKind !== "type";
19
+ }
20
+ //#endregion
21
+ export { hasZodRuntimeImportRoot };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-zod",
3
- "version": "4.11.0",
3
+ "version": "4.12.1",
4
4
  "description": "ESLint plugin that adds custom linting rules to enforce best practices when using Zod",
5
5
  "keywords": [
6
6
  "eslint",
@@ -39,9 +39,10 @@
39
39
  },
40
40
  "dependencies": {
41
41
  "@typescript-eslint/utils": "^8.67.0",
42
- "@eslint-zod/utils": "3.2.0"
42
+ "@eslint-zod/utils": "4.0.0"
43
43
  },
44
44
  "devDependencies": {
45
+ "@arethetypeswrong/cli": "0.18.5",
45
46
  "@typescript-eslint/rule-tester": "8.67.0",
46
47
  "dedent": "1.7.2",
47
48
  "eslint-doc-generator": "3.7.0",
@@ -70,6 +71,7 @@
70
71
  },
71
72
  "scripts": {
72
73
  "build": "tsdown",
74
+ "lint:publish": "attw --pack .",
73
75
  "build:docs": "pnpm run build && eslint-doc-generator",
74
76
  "lint:docs": "eslint-doc-generator --check",
75
77
  "test": "vitest"