oxlint-plugin-react-doctor 0.2.11-dev.b5cf767 → 0.2.11-dev.b65b157

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/dist/index.d.ts CHANGED
@@ -5542,6 +5542,74 @@ declare const REACT_DOCTOR_RULES: readonly [{
5542
5542
  readonly recommendation?: string;
5543
5543
  readonly create: (context: RuleContext) => RuleVisitors;
5544
5544
  };
5545
+ }, {
5546
+ readonly key: "react-doctor/zod-v4-no-deprecated-error-apis";
5547
+ readonly id: "zod-v4-no-deprecated-error-apis";
5548
+ readonly source: "react-doctor";
5549
+ readonly originallyExternal: false;
5550
+ readonly rule: {
5551
+ readonly framework: "global";
5552
+ readonly category: "Architecture";
5553
+ readonly id: string;
5554
+ readonly severity: RuleSeverity;
5555
+ readonly requires?: ReadonlyArray<string>;
5556
+ readonly disabledBy?: ReadonlyArray<string>;
5557
+ readonly tags?: ReadonlyArray<string>;
5558
+ readonly defaultEnabled?: boolean;
5559
+ readonly recommendation?: string;
5560
+ readonly create: (context: RuleContext) => RuleVisitors;
5561
+ };
5562
+ }, {
5563
+ readonly key: "react-doctor/zod-v4-no-deprecated-error-customization";
5564
+ readonly id: "zod-v4-no-deprecated-error-customization";
5565
+ readonly source: "react-doctor";
5566
+ readonly originallyExternal: false;
5567
+ readonly rule: {
5568
+ readonly framework: "global";
5569
+ readonly category: "Architecture";
5570
+ readonly id: string;
5571
+ readonly severity: RuleSeverity;
5572
+ readonly requires?: ReadonlyArray<string>;
5573
+ readonly disabledBy?: ReadonlyArray<string>;
5574
+ readonly tags?: ReadonlyArray<string>;
5575
+ readonly defaultEnabled?: boolean;
5576
+ readonly recommendation?: string;
5577
+ readonly create: (context: RuleContext) => RuleVisitors;
5578
+ };
5579
+ }, {
5580
+ readonly key: "react-doctor/zod-v4-no-deprecated-schema-apis";
5581
+ readonly id: "zod-v4-no-deprecated-schema-apis";
5582
+ readonly source: "react-doctor";
5583
+ readonly originallyExternal: false;
5584
+ readonly rule: {
5585
+ readonly framework: "global";
5586
+ readonly category: "Architecture";
5587
+ readonly id: string;
5588
+ readonly severity: RuleSeverity;
5589
+ readonly requires?: ReadonlyArray<string>;
5590
+ readonly disabledBy?: ReadonlyArray<string>;
5591
+ readonly tags?: ReadonlyArray<string>;
5592
+ readonly defaultEnabled?: boolean;
5593
+ readonly recommendation?: string;
5594
+ readonly create: (context: RuleContext) => RuleVisitors;
5595
+ };
5596
+ }, {
5597
+ readonly key: "react-doctor/zod-v4-prefer-top-level-string-formats";
5598
+ readonly id: "zod-v4-prefer-top-level-string-formats";
5599
+ readonly source: "react-doctor";
5600
+ readonly originallyExternal: false;
5601
+ readonly rule: {
5602
+ readonly framework: "global";
5603
+ readonly category: "Architecture";
5604
+ readonly id: string;
5605
+ readonly severity: RuleSeverity;
5606
+ readonly requires?: ReadonlyArray<string>;
5607
+ readonly disabledBy?: ReadonlyArray<string>;
5608
+ readonly tags?: ReadonlyArray<string>;
5609
+ readonly defaultEnabled?: boolean;
5610
+ readonly recommendation?: string;
5611
+ readonly create: (context: RuleContext) => RuleVisitors;
5612
+ };
5545
5613
  }];
5546
5614
  declare const EXTERNAL_RULES: readonly [{
5547
5615
  readonly key: "react-hooks-js/set-state-in-render";
@@ -11014,6 +11082,74 @@ declare const RULES: readonly [{
11014
11082
  readonly recommendation?: string;
11015
11083
  readonly create: (context: RuleContext) => RuleVisitors;
11016
11084
  };
11085
+ }, {
11086
+ readonly key: "react-doctor/zod-v4-no-deprecated-error-apis";
11087
+ readonly id: "zod-v4-no-deprecated-error-apis";
11088
+ readonly source: "react-doctor";
11089
+ readonly originallyExternal: false;
11090
+ readonly rule: {
11091
+ readonly framework: "global";
11092
+ readonly category: "Architecture";
11093
+ readonly id: string;
11094
+ readonly severity: RuleSeverity;
11095
+ readonly requires?: ReadonlyArray<string>;
11096
+ readonly disabledBy?: ReadonlyArray<string>;
11097
+ readonly tags?: ReadonlyArray<string>;
11098
+ readonly defaultEnabled?: boolean;
11099
+ readonly recommendation?: string;
11100
+ readonly create: (context: RuleContext) => RuleVisitors;
11101
+ };
11102
+ }, {
11103
+ readonly key: "react-doctor/zod-v4-no-deprecated-error-customization";
11104
+ readonly id: "zod-v4-no-deprecated-error-customization";
11105
+ readonly source: "react-doctor";
11106
+ readonly originallyExternal: false;
11107
+ readonly rule: {
11108
+ readonly framework: "global";
11109
+ readonly category: "Architecture";
11110
+ readonly id: string;
11111
+ readonly severity: RuleSeverity;
11112
+ readonly requires?: ReadonlyArray<string>;
11113
+ readonly disabledBy?: ReadonlyArray<string>;
11114
+ readonly tags?: ReadonlyArray<string>;
11115
+ readonly defaultEnabled?: boolean;
11116
+ readonly recommendation?: string;
11117
+ readonly create: (context: RuleContext) => RuleVisitors;
11118
+ };
11119
+ }, {
11120
+ readonly key: "react-doctor/zod-v4-no-deprecated-schema-apis";
11121
+ readonly id: "zod-v4-no-deprecated-schema-apis";
11122
+ readonly source: "react-doctor";
11123
+ readonly originallyExternal: false;
11124
+ readonly rule: {
11125
+ readonly framework: "global";
11126
+ readonly category: "Architecture";
11127
+ readonly id: string;
11128
+ readonly severity: RuleSeverity;
11129
+ readonly requires?: ReadonlyArray<string>;
11130
+ readonly disabledBy?: ReadonlyArray<string>;
11131
+ readonly tags?: ReadonlyArray<string>;
11132
+ readonly defaultEnabled?: boolean;
11133
+ readonly recommendation?: string;
11134
+ readonly create: (context: RuleContext) => RuleVisitors;
11135
+ };
11136
+ }, {
11137
+ readonly key: "react-doctor/zod-v4-prefer-top-level-string-formats";
11138
+ readonly id: "zod-v4-prefer-top-level-string-formats";
11139
+ readonly source: "react-doctor";
11140
+ readonly originallyExternal: false;
11141
+ readonly rule: {
11142
+ readonly framework: "global";
11143
+ readonly category: "Architecture";
11144
+ readonly id: string;
11145
+ readonly severity: RuleSeverity;
11146
+ readonly requires?: ReadonlyArray<string>;
11147
+ readonly disabledBy?: ReadonlyArray<string>;
11148
+ readonly tags?: ReadonlyArray<string>;
11149
+ readonly defaultEnabled?: boolean;
11150
+ readonly recommendation?: string;
11151
+ readonly create: (context: RuleContext) => RuleVisitors;
11152
+ };
11017
11153
  }, {
11018
11154
  readonly key: "react-hooks-js/set-state-in-render";
11019
11155
  readonly source: "react-compiler";
package/dist/index.js CHANGED
@@ -33358,6 +33358,410 @@ const voidDomElementsNoChildren = defineRule({
33358
33358
  })
33359
33359
  });
33360
33360
  //#endregion
33361
+ //#region src/plugin/rules/zod/utils/zod-ast.ts
33362
+ const ZOD_MODULE = "zod";
33363
+ const getStaticPropertyName = (member) => {
33364
+ const property = member.property;
33365
+ if (!member.computed && isNodeOfType(property, "Identifier")) return property.name;
33366
+ if (member.computed && isNodeOfType(property, "Literal") && typeof property.value === "string") return property.value;
33367
+ return null;
33368
+ };
33369
+ const getImportInfoForIdentifier = (identifier) => {
33370
+ const specifier = findVariableInitializer(identifier, identifier.name)?.initializer;
33371
+ if (!specifier) return null;
33372
+ const declaration = specifier.parent;
33373
+ if (!declaration || !isNodeOfType(declaration, "ImportDeclaration")) return null;
33374
+ if (declaration.source?.value !== ZOD_MODULE) return null;
33375
+ if (isNodeOfType(specifier, "ImportNamespaceSpecifier")) return {
33376
+ imported: null,
33377
+ isDefault: false,
33378
+ isNamespace: true
33379
+ };
33380
+ if (isNodeOfType(specifier, "ImportDefaultSpecifier")) return {
33381
+ imported: null,
33382
+ isDefault: true,
33383
+ isNamespace: false
33384
+ };
33385
+ if (isNodeOfType(specifier, "ImportSpecifier")) {
33386
+ const imported = specifier.imported;
33387
+ if (isNodeOfType(imported, "Identifier")) return {
33388
+ imported: imported.name,
33389
+ isDefault: false,
33390
+ isNamespace: false
33391
+ };
33392
+ if (isNodeOfType(imported, "Literal") && typeof imported.value === "string") return {
33393
+ imported: imported.value,
33394
+ isDefault: false,
33395
+ isNamespace: false
33396
+ };
33397
+ }
33398
+ return null;
33399
+ };
33400
+ const isZodNamespaceIdentifier = (node) => {
33401
+ const inner = stripParenExpression(node);
33402
+ if (!isNodeOfType(inner, "Identifier")) return false;
33403
+ const info = getImportInfoForIdentifier(inner);
33404
+ return Boolean(info && (info.isNamespace || info.isDefault || info.imported === "z"));
33405
+ };
33406
+ const getZodNamedImport = (node) => {
33407
+ const inner = stripParenExpression(node);
33408
+ if (!isNodeOfType(inner, "Identifier")) return null;
33409
+ const info = getImportInfoForIdentifier(inner);
33410
+ if (!info || info.isNamespace || info.isDefault) return null;
33411
+ return info.imported;
33412
+ };
33413
+ const getZodNamespaceMemberName = (node) => {
33414
+ const inner = stripParenExpression(node);
33415
+ if (!isNodeOfType(inner, "MemberExpression")) return null;
33416
+ if (!isZodNamespaceIdentifier(inner.object)) return null;
33417
+ return getStaticPropertyName(inner);
33418
+ };
33419
+ const isZodFactoryCall = (callExpression, factoryNames) => {
33420
+ const factoryName = getZodFactoryCallName(callExpression);
33421
+ return factoryName !== null && factoryNames.has(factoryName);
33422
+ };
33423
+ const getZodFactoryCallName = (callExpression) => {
33424
+ const callee = stripParenExpression(callExpression.callee);
33425
+ if (isNodeOfType(callee, "Identifier")) return getZodNamedImport(callee);
33426
+ if (!isNodeOfType(callee, "MemberExpression")) return null;
33427
+ const memberName = getStaticPropertyName(callee);
33428
+ if (memberName === null) return null;
33429
+ if (!isZodNamespaceIdentifier(callee.object)) return null;
33430
+ return memberName;
33431
+ };
33432
+ const getMethodCall = (callExpression) => {
33433
+ const callee = stripParenExpression(callExpression.callee);
33434
+ if (!isNodeOfType(callee, "MemberExpression")) return null;
33435
+ const methodName = getStaticPropertyName(callee);
33436
+ if (!methodName) return null;
33437
+ return {
33438
+ methodName,
33439
+ receiver: callee.object
33440
+ };
33441
+ };
33442
+ const isDirectMethodCallOnZodFactory = (callExpression, factoryNames, methodNames) => {
33443
+ const methodCall = getMethodCall(callExpression);
33444
+ if (!methodCall || !methodNames.has(methodCall.methodName)) return false;
33445
+ const receiver = stripParenExpression(methodCall.receiver);
33446
+ return isNodeOfType(receiver, "CallExpression") && isZodFactoryCall(receiver, factoryNames);
33447
+ };
33448
+ const isObjectExpressionWithAnyProperty = (node, propertyNames) => {
33449
+ if (!node) return false;
33450
+ const inner = stripParenExpression(node);
33451
+ if (!isNodeOfType(inner, "ObjectExpression")) return false;
33452
+ return inner.properties.some((property) => {
33453
+ if (!isNodeOfType(property, "Property")) return false;
33454
+ const key = property.key;
33455
+ if (isNodeOfType(key, "Identifier")) return propertyNames.has(key.name);
33456
+ return isNodeOfType(key, "Literal") && typeof key.value === "string" && propertyNames.has(key.value);
33457
+ });
33458
+ };
33459
+ //#endregion
33460
+ //#region src/plugin/rules/zod/zod-v4-no-deprecated-error-apis.ts
33461
+ const DEPRECATED_ZOD_ERROR_MEMBERS = new Set([
33462
+ "addIssue",
33463
+ "addIssues",
33464
+ "errors",
33465
+ "flatten",
33466
+ "formErrors",
33467
+ "format"
33468
+ ]);
33469
+ const ZOD_ERROR_API_MESSAGE = "Zod 4 removes or deprecates this ZodError API; use `error.issues` or the new top-level error formatting helpers.";
33470
+ const isZodErrorReference = (node) => {
33471
+ const inner = stripParenExpression(node);
33472
+ if (isNodeOfType(inner, "Identifier")) return getZodNamedImport(inner) === "ZodError";
33473
+ if (!isNodeOfType(inner, "MemberExpression")) return false;
33474
+ return getZodNamespaceMemberName(inner) === "ZodError";
33475
+ };
33476
+ const isDirectZodErrorValue = (node) => {
33477
+ const inner = stripParenExpression(node);
33478
+ if (isNodeOfType(inner, "NewExpression")) return isZodErrorReference(inner.callee);
33479
+ if (!isNodeOfType(inner, "CallExpression")) return false;
33480
+ const methodCall = getMethodCall(inner);
33481
+ return methodCall?.methodName === "create" && isZodErrorReference(methodCall.receiver);
33482
+ };
33483
+ const isDeprecatedZodErrorMemberAccess = (node) => {
33484
+ if (!isNodeOfType(node, "MemberExpression")) return false;
33485
+ const memberExpression = node;
33486
+ const propertyName = getStaticPropertyName(memberExpression);
33487
+ return propertyName !== null && DEPRECATED_ZOD_ERROR_MEMBERS.has(propertyName) && isDirectZodErrorValue(memberExpression.object);
33488
+ };
33489
+ const isZodErrorCreateCall = (callExpression) => {
33490
+ const methodCall = getMethodCall(callExpression);
33491
+ return methodCall?.methodName === "create" && isZodErrorReference(methodCall.receiver);
33492
+ };
33493
+ const isReceiverOfDeprecatedZodErrorMember = (callExpression) => {
33494
+ const parent = callExpression.parent;
33495
+ if (!parent || !isNodeOfType(parent, "MemberExpression")) return false;
33496
+ if (stripParenExpression(parent.object) !== callExpression) return false;
33497
+ return isDeprecatedZodErrorMemberAccess(parent);
33498
+ };
33499
+ const zodV4NoDeprecatedErrorApis = defineRule({
33500
+ id: "zod-v4-no-deprecated-error-apis",
33501
+ requires: ["zod:4"],
33502
+ tags: ["migration-hint"],
33503
+ severity: "warn",
33504
+ recommendation: "Replace deprecated ZodError helpers with the Zod 4 functions: `z.treeifyError()`, `z.flattenError()`, `z.prettifyError()`, or direct `error.issues` access.",
33505
+ create: (context) => ({
33506
+ CallExpression(node) {
33507
+ if (isZodErrorCreateCall(node) && isReceiverOfDeprecatedZodErrorMember(node)) return;
33508
+ if (!isZodErrorCreateCall(node) && !isDeprecatedZodErrorMemberAccess(node.callee)) return;
33509
+ context.report({
33510
+ node,
33511
+ message: ZOD_ERROR_API_MESSAGE
33512
+ });
33513
+ },
33514
+ MemberExpression(node) {
33515
+ const parent = node.parent;
33516
+ if (parent && isNodeOfType(parent, "CallExpression") && stripParenExpression(parent.callee) === node) return;
33517
+ if (!isDeprecatedZodErrorMemberAccess(node)) return;
33518
+ context.report({
33519
+ node,
33520
+ message: ZOD_ERROR_API_MESSAGE
33521
+ });
33522
+ }
33523
+ })
33524
+ });
33525
+ //#endregion
33526
+ //#region src/plugin/rules/zod/zod-v4-no-deprecated-error-customization.ts
33527
+ const ZOD_FACTORIES_WITH_ERROR_PARAMS = new Set([
33528
+ "any",
33529
+ "array",
33530
+ "bigint",
33531
+ "boolean",
33532
+ "date",
33533
+ "enum",
33534
+ "literal",
33535
+ "map",
33536
+ "nativeEnum",
33537
+ "never",
33538
+ "null",
33539
+ "number",
33540
+ "object",
33541
+ "record",
33542
+ "set",
33543
+ "string",
33544
+ "tuple",
33545
+ "undefined",
33546
+ "union",
33547
+ "unknown",
33548
+ "void"
33549
+ ]);
33550
+ const DROPPED_ERROR_OPTION_PROPERTIES = new Set([
33551
+ "errorMap",
33552
+ "invalid_type_error",
33553
+ "required_error"
33554
+ ]);
33555
+ const FACTORIES_WITH_LEGACY_FIRST_ARG_MESSAGE = new Set([
33556
+ "bigint",
33557
+ "boolean",
33558
+ "date",
33559
+ "number",
33560
+ "string"
33561
+ ]);
33562
+ const ERROR_MAP_PROPERTY = new Set(["errorMap"]);
33563
+ const PARSE_METHODS = new Set([
33564
+ "parse",
33565
+ "safeParse",
33566
+ "parseAsync",
33567
+ "safeParseAsync"
33568
+ ]);
33569
+ const firstArgumentIsMessageString = (callExpression) => {
33570
+ const firstArgument = callExpression.arguments[0];
33571
+ const inner = firstArgument ? stripParenExpression(firstArgument) : null;
33572
+ return Boolean(inner && isNodeOfType(inner, "Literal") && typeof inner.value === "string");
33573
+ };
33574
+ const factoryUsesDeprecatedErrorParameter = (callExpression) => {
33575
+ const factoryName = getZodFactoryCallName(callExpression);
33576
+ if (factoryName === null || !ZOD_FACTORIES_WITH_ERROR_PARAMS.has(factoryName)) return false;
33577
+ return FACTORIES_WITH_LEGACY_FIRST_ARG_MESSAGE.has(factoryName) && firstArgumentIsMessageString(callExpression) || callExpression.arguments.some((argument) => isObjectExpressionWithAnyProperty(argument, DROPPED_ERROR_OPTION_PROPERTIES));
33578
+ };
33579
+ const parseCallUsesErrorMap = (callExpression) => {
33580
+ const methodCall = getMethodCall(callExpression);
33581
+ if (!methodCall || !PARSE_METHODS.has(methodCall.methodName)) return false;
33582
+ const receiver = stripParenExpression(methodCall.receiver);
33583
+ if (!isNodeOfType(receiver, "CallExpression")) return false;
33584
+ if (!isZodFactoryCall(receiver, ZOD_FACTORIES_WITH_ERROR_PARAMS)) return false;
33585
+ return isObjectExpressionWithAnyProperty(callExpression.arguments[1], ERROR_MAP_PROPERTY);
33586
+ };
33587
+ const zodV4NoDeprecatedErrorCustomization = defineRule({
33588
+ id: "zod-v4-no-deprecated-error-customization",
33589
+ requires: ["zod:4"],
33590
+ tags: ["migration-hint"],
33591
+ severity: "warn",
33592
+ recommendation: "Use Zod 4's unified `{ error }` callback/object customization instead of string message parameters, `invalid_type_error`, `required_error`, or `errorMap`.",
33593
+ create: (context) => ({ CallExpression(node) {
33594
+ if (!factoryUsesDeprecatedErrorParameter(node) && !parseCallUsesErrorMap(node)) return;
33595
+ context.report({
33596
+ node,
33597
+ message: "Zod 4 replaces message parameters, `invalid_type_error`, `required_error`, and `errorMap` with the unified `error` API."
33598
+ });
33599
+ } })
33600
+ });
33601
+ //#endregion
33602
+ //#region src/plugin/rules/zod/zod-v4-no-deprecated-schema-apis.ts
33603
+ const OBJECT_FACTORY = new Set(["object"]);
33604
+ const OBJECT_METHODS = new Set([
33605
+ "deepPartial",
33606
+ "merge",
33607
+ "nonstrict",
33608
+ "passthrough",
33609
+ "strict",
33610
+ "strip"
33611
+ ]);
33612
+ const NUMBER_FACTORY = new Set(["number"]);
33613
+ const NUMBER_METHODS = new Set(["safe"]);
33614
+ const FUNCTION_FACTORY = new Set(["function"]);
33615
+ const FUNCTION_CHAIN_METHODS = new Set(["args", "returns"]);
33616
+ const DEPRECATED_TOP_LEVEL_FACTORIES = new Set([
33617
+ "nativeEnum",
33618
+ "ostring",
33619
+ "onumber",
33620
+ "oboolean",
33621
+ "oarray",
33622
+ "promise"
33623
+ ]);
33624
+ const FACTORIES_WITH_DROPPED_CREATE = new Set([
33625
+ "any",
33626
+ "array",
33627
+ "bigint",
33628
+ "boolean",
33629
+ "date",
33630
+ "enum",
33631
+ "function",
33632
+ "literal",
33633
+ "map",
33634
+ "nativeEnum",
33635
+ "never",
33636
+ "null",
33637
+ "number",
33638
+ "object",
33639
+ "optional",
33640
+ "promise",
33641
+ "record",
33642
+ "set",
33643
+ "string",
33644
+ "tuple",
33645
+ "undefined",
33646
+ "union",
33647
+ "unknown",
33648
+ "void"
33649
+ ]);
33650
+ const ENUM_PROPERTY_ALIASES = new Set(["Enum", "Values"]);
33651
+ const ENUM_FACTORY = new Set(["enum"]);
33652
+ const RECORD_FACTORY = new Set(["record"]);
33653
+ const LITERAL_FACTORY = new Set(["literal"]);
33654
+ const reportSchemaMigration = (context, node) => {
33655
+ context.report({
33656
+ node,
33657
+ message: "This Zod API is deprecated or changed in Zod 4; migrate to the recommended Zod 4 schema API."
33658
+ });
33659
+ };
33660
+ const isCallToDeprecatedTopLevelFactory = (callExpression) => isZodFactoryCall(callExpression, DEPRECATED_TOP_LEVEL_FACTORIES);
33661
+ const isCallToDroppedCreateFactory = (callExpression) => {
33662
+ const methodCall = getMethodCall(callExpression);
33663
+ if (!methodCall || methodCall.methodName !== "create") return false;
33664
+ const receiver = stripParenExpression(methodCall.receiver);
33665
+ const namespaceMemberName = getZodNamespaceMemberName(receiver);
33666
+ if (namespaceMemberName !== null) return FACTORIES_WITH_DROPPED_CREATE.has(namespaceMemberName);
33667
+ if (!isNodeOfType(receiver, "Identifier")) return false;
33668
+ const imported = getZodNamedImport(receiver);
33669
+ return imported !== null && FACTORIES_WITH_DROPPED_CREATE.has(imported);
33670
+ };
33671
+ const isSingleArgumentRecordCall = (callExpression) => callExpression.arguments.length === 1 && isZodFactoryCall(callExpression, RECORD_FACTORY);
33672
+ const isDeprecatedFunctionChainCall = (callExpression) => isDirectMethodCallOnZodFactory(callExpression, FUNCTION_FACTORY, FUNCTION_CHAIN_METHODS);
33673
+ const isSymbolLiteralArgument = (node) => {
33674
+ if (!node) return false;
33675
+ const inner = stripParenExpression(node);
33676
+ if (isNodeOfType(inner, "CallExpression")) {
33677
+ const callee = stripParenExpression(inner.callee);
33678
+ return isNodeOfType(callee, "Identifier") && callee.name === "Symbol";
33679
+ }
33680
+ if (!isNodeOfType(inner, "MemberExpression")) return false;
33681
+ const object = stripParenExpression(inner.object);
33682
+ return isNodeOfType(object, "Identifier") && object.name === "Symbol";
33683
+ };
33684
+ const isLiteralSymbolCall = (callExpression) => callExpression.arguments.length > 0 && isZodFactoryCall(callExpression, LITERAL_FACTORY) && isSymbolLiteralArgument(callExpression.arguments[0]);
33685
+ const isDroppedEnumAliasAccess = (memberExpression) => {
33686
+ const propertyName = getStaticPropertyName(memberExpression);
33687
+ if (propertyName === null || !ENUM_PROPERTY_ALIASES.has(propertyName)) return false;
33688
+ const receiver = stripParenExpression(memberExpression.object);
33689
+ return isNodeOfType(receiver, "CallExpression") && isZodFactoryCall(receiver, ENUM_FACTORY);
33690
+ };
33691
+ const isRefineSecondArgumentFunction = (callExpression) => {
33692
+ const methodCall = getMethodCall(callExpression);
33693
+ if (!methodCall || methodCall.methodName !== "refine") return false;
33694
+ const receiver = stripParenExpression(methodCall.receiver);
33695
+ if (!isNodeOfType(receiver, "CallExpression")) return false;
33696
+ if (!isZodFactoryCall(receiver, FACTORIES_WITH_DROPPED_CREATE)) return false;
33697
+ const secondArgument = callExpression.arguments[1];
33698
+ return isNodeOfType(secondArgument, "FunctionExpression") || isNodeOfType(secondArgument, "ArrowFunctionExpression");
33699
+ };
33700
+ const isZodNamespaceImportMemberCreate = (memberExpression) => {
33701
+ if (getStaticPropertyName(memberExpression) !== "create") return false;
33702
+ const receiver = stripParenExpression(memberExpression.object);
33703
+ if (!isNodeOfType(receiver, "MemberExpression")) return false;
33704
+ const factoryName = getStaticPropertyName(receiver);
33705
+ return factoryName !== null && FACTORIES_WITH_DROPPED_CREATE.has(factoryName) && isZodNamespaceIdentifier(receiver.object);
33706
+ };
33707
+ const zodV4NoDeprecatedSchemaApis = defineRule({
33708
+ id: "zod-v4-no-deprecated-schema-apis",
33709
+ requires: ["zod:4"],
33710
+ tags: ["migration-hint"],
33711
+ severity: "warn",
33712
+ recommendation: "Migrate Zod 4 schema APIs that were deprecated, changed, or removed: use top-level factories such as `z.enum()`, object helpers such as `z.strictObject()`, the new `z.function({ input, output })` form, and explicit key/value schemas for `z.record()`.",
33713
+ create: (context) => ({
33714
+ CallExpression(node) {
33715
+ if (isCallToDeprecatedTopLevelFactory(node) || isCallToDroppedCreateFactory(node) || isSingleArgumentRecordCall(node) || isLiteralSymbolCall(node) || isDeprecatedFunctionChainCall(node) || isDirectMethodCallOnZodFactory(node, OBJECT_FACTORY, OBJECT_METHODS) || isDirectMethodCallOnZodFactory(node, NUMBER_FACTORY, NUMBER_METHODS) || isRefineSecondArgumentFunction(node)) reportSchemaMigration(context, node);
33716
+ },
33717
+ MemberExpression(node) {
33718
+ const parent = node.parent;
33719
+ if (parent && isNodeOfType(parent, "CallExpression") && stripParenExpression(parent.callee) === node) return;
33720
+ if (isDroppedEnumAliasAccess(node) || isZodNamespaceImportMemberCreate(node)) reportSchemaMigration(context, node);
33721
+ }
33722
+ })
33723
+ });
33724
+ //#endregion
33725
+ //#region src/plugin/rules/zod/zod-v4-prefer-top-level-string-formats.ts
33726
+ const ZOD_STRING_FACTORY = new Set(["string"]);
33727
+ const STRING_FORMAT_METHODS = new Set([
33728
+ "base64",
33729
+ "base64url",
33730
+ "cidr",
33731
+ "cidrv4",
33732
+ "cidrv6",
33733
+ "cuid",
33734
+ "cuid2",
33735
+ "date",
33736
+ "datetime",
33737
+ "duration",
33738
+ "email",
33739
+ "emoji",
33740
+ "ip",
33741
+ "ipv4",
33742
+ "ipv6",
33743
+ "jwt",
33744
+ "nanoid",
33745
+ "time",
33746
+ "ulid",
33747
+ "url",
33748
+ "uuid"
33749
+ ]);
33750
+ const zodV4PreferTopLevelStringFormats = defineRule({
33751
+ id: "zod-v4-prefer-top-level-string-formats",
33752
+ requires: ["zod:4"],
33753
+ tags: ["migration-hint"],
33754
+ severity: "warn",
33755
+ recommendation: "Replace deprecated `z.string().<format>()` calls with Zod 4 top-level string format APIs like `z.email()`, `z.uuid()`, `z.ipv4()`, or `z.cidrv4()`.",
33756
+ create: (context) => ({ CallExpression(node) {
33757
+ if (!isDirectMethodCallOnZodFactory(node, ZOD_STRING_FACTORY, STRING_FORMAT_METHODS)) return;
33758
+ context.report({
33759
+ node,
33760
+ message: "Zod 4 deprecates string format methods on `z.string()`; use the matching top-level Zod format API instead."
33761
+ });
33762
+ } })
33763
+ });
33764
+ //#endregion
33361
33765
  //#region src/plugin/rule-registry.ts
33362
33766
  const reactDoctorRules = [
33363
33767
  {
@@ -36894,6 +37298,50 @@ const reactDoctorRules = [
36894
37298
  framework: "global",
36895
37299
  category: "Correctness"
36896
37300
  }
37301
+ },
37302
+ {
37303
+ key: "react-doctor/zod-v4-no-deprecated-error-apis",
37304
+ id: "zod-v4-no-deprecated-error-apis",
37305
+ source: "react-doctor",
37306
+ originallyExternal: false,
37307
+ rule: {
37308
+ ...zodV4NoDeprecatedErrorApis,
37309
+ framework: "global",
37310
+ category: "Architecture"
37311
+ }
37312
+ },
37313
+ {
37314
+ key: "react-doctor/zod-v4-no-deprecated-error-customization",
37315
+ id: "zod-v4-no-deprecated-error-customization",
37316
+ source: "react-doctor",
37317
+ originallyExternal: false,
37318
+ rule: {
37319
+ ...zodV4NoDeprecatedErrorCustomization,
37320
+ framework: "global",
37321
+ category: "Architecture"
37322
+ }
37323
+ },
37324
+ {
37325
+ key: "react-doctor/zod-v4-no-deprecated-schema-apis",
37326
+ id: "zod-v4-no-deprecated-schema-apis",
37327
+ source: "react-doctor",
37328
+ originallyExternal: false,
37329
+ rule: {
37330
+ ...zodV4NoDeprecatedSchemaApis,
37331
+ framework: "global",
37332
+ category: "Architecture"
37333
+ }
37334
+ },
37335
+ {
37336
+ key: "react-doctor/zod-v4-prefer-top-level-string-formats",
37337
+ id: "zod-v4-prefer-top-level-string-formats",
37338
+ source: "react-doctor",
37339
+ originallyExternal: false,
37340
+ rule: {
37341
+ ...zodV4PreferTopLevelStringFormats,
37342
+ framework: "global",
37343
+ category: "Architecture"
37344
+ }
36897
37345
  }
36898
37346
  ];
36899
37347
  const ruleRegistry = Object.fromEntries(reactDoctorRules.map((rule) => [rule.id, rule.rule]));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oxlint-plugin-react-doctor",
3
- "version": "0.2.11-dev.b5cf767",
3
+ "version": "0.2.11-dev.b65b157",
4
4
  "description": "oxlint plugin for React Doctor: diagnose React codebases for security, performance, correctness, accessibility, bundle-size, and architecture issues",
5
5
  "keywords": [
6
6
  "accessibility",