Skip to content

Conversation

@leocaan
Copy link

@leocaan leocaan commented Dec 23, 2025

Description

  • 升级 zod 依赖版本至 4.1.13 并移除已弃用的 zod-defaults 包
  • 升级 vee-validate 到 5.0.0-beta.0 版本并移除其 zod 集成依赖
  • 使用markRaw包装zod模式以提高性能,并降低form-ui处理代码的复杂度

Type of change

Please delete options that are not relevant.

  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

Checklist

ℹ️ Check all checkboxes - this will indicate that you have done everything in accordance with the rules in CONTRIBUTING.

  • If you introduce new functionality, document it. You can run documentation with pnpm run docs:dev command.
  • Run the tests with pnpm test.
  • Changes in changelog are generated from PR name. Please, make sure that it explains your changes in an understandable manner. Please, prefix changeset messages with feat:, fix:, perf:, docs:, or chore:.
  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

Summary by CodeRabbit

  • Refactor

    • Enhanced form validation system across authentication and profile settings views.
    • Improved form schema handling and default value extraction logic.
  • Chores

    • Updated form validation dependencies with upgraded Zod and vee-validate versions.
    • Removed unused validation integration packages.
  • Documentation

    • Updated form validation examples and component documentation to reflect new patterns.

✏️ Tip: You can customize this high-level summary in your review settings.

- 移除对zod-defaults依赖项的依赖。
- 优化表单字段必填校验逻辑,改用 Zod schema 的 safeParse 方法替代 isOptional 判断。
- 将表单验证逻辑从使用Zod内部类型名改为使用公开的def.type属性,并更新相关辅助函数命名以更清晰地反映其功能。
- 重构 Zod 模式辅助函数以简化类型定义并增强默认值提取逻辑。
- 将表单验证规则类型从 ZodTypeAny 更改为 ZodType 以提升类型精确度。
- 重构表单初始化逻辑,移除直接处理 Zod 模式的默认值提取,改由专用辅助函数处理。
- 升级 zod 依赖版本至 4.1.13 并移除已弃用的 zod-defaults 包。
- 升级 zod 依赖版本并移除 zod-defaults 包。
- Zod schema 是普通对象,不应被 Vue 响应式系统处理。
- 移除对 @vee-validate/zod 依赖包的引用
- 移除对 vee-validate/zod 的类型转换依赖,直接返回原始校验规则。
- 将 forEach 替换为 map 以正确返回表单形状数组。
- 升级 vee-validate 到 5.0.0-beta.0 版本并移除其 zod 集成依赖。
@changeset-bot
Copy link

changeset-bot bot commented Dec 23, 2025

⚠️ No Changeset found

Latest commit: 86735a3

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 23, 2025

📝 Walkthrough

Walkthrough

The PR refactors form validation across the codebase by wrapping Zod schemas with Vue's markRaw() to prevent reactivity tracking, replacing validation error property keys from "message" to "error", and refactoring core form infrastructure by removing @vee-validate/zod dependency while implementing custom Zod schema handling.

Changes

Cohort / File(s) Summary
Authentication form files - Ant Design
apps/web-antd/src/views/_core/authentication/code-login.vue, forget-password.vue, login.vue, register.vue
Wrapped validation rules with markRaw() and replaced error message keys from message to error across phone number, code, email, username, password, captcha, and checkbox fields.
Authentication form files - Element Plus
apps/web-ele/src/views/_core/authentication/*
Same pattern as Ant Design variant: wrapped all validation rules with markRaw() and migrated messageerror keys across authentication forms.
Authentication form files - Naive UI
apps/web-naive/src/views/_core/authentication/*
Consistent markRaw() wrapping and messageerror migration across code-login, forget-password, login, and register forms.
Authentication form files - TDesign
apps/web-tdesign/src/views/_core/authentication/*
Applied same validation refactoring pattern: markRaw() wrapping and error key migration across all authentication forms.
Profile password settings
apps/web-antd/src/views/_core/profile/password-setting.vue, apps/web-ele/..., apps/web-naive/..., apps/web-tdesign/...
Wrapped confirmation password validation in markRaw(), replaced required_error/message with min(1, { error: ... }) and refine error messages.
Core form infrastructure
packages/@core/ui-kit/form-ui/package.json, form-field.vue, form.vue, helper.ts, types.ts, use-form-context.ts
Removed @vee-validate/zod and zod-defaults dependencies; replaced toTypedSchema usage with custom Zod schema handling; refactored helper functions (getBaseRules_byZodSchema, getDefaultValue_byZodSchema, getCustomDefaultValue_byZodSchema); replaced ZodTypeAny with ZodType in types; rewrote default value and rule extraction logic.
Lock screen widgets
packages/effects/layouts/src/widgets/lock-screen/lock-screen-modal.vue, lock-screen.vue
Applied markRaw() wrapping and messageerror migration to password validation rules.
Playground and demo forms
playground/src/views/_core/authentication/*, playground/src/views/_core/profile/password-setting.vue, playground/src/views/examples/form/*, playground/src/views/system/dept/data.ts, playground/src/views/system/menu/modules/form.vue
Comprehensive updates with markRaw() wrapping, error key migration, and in some cases structured error object usage for complex validation scenarios.
Documentation
docs/src/components/common-ui/vben-form.md, docs/src/demos/vben-form/rules/index.vue
Updated code examples to demonstrate markRaw() wrapping and { error: ... } usage in validation schemas.
Workspace configuration
pnpm-workspace.yaml
Removed @vee-validate/zod catalog entry, upgraded Zod from ^3.25.67 to ^4.1.13, upgraded vee-validate to ^5.0.0-beta.0, and removed zod-defaults.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

The changes span 40+ files with a mix of homogeneous repetitive patterns (markRaw() wrapping and messageerror across UI frameworks) and substantive structural refactoring in the core form-ui package (dependency removal, helper function signature changes, custom Zod schema handling logic). Reviewers must verify consistency across the distributed changes and validate the correctness of the new form infrastructure handling, particularly for default value extraction and schema rule processing.

Possibly related PRs

Suggested labels

chore, refactor, form-validation

Suggested reviewers

  • anncwb
  • vince292007
  • mynetfan

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description check ✅ Passed The description covers key changes (zod 4.1.13 upgrade, vee-validate 5.0.0-beta.0, markRaw usage), marks it as breaking change, and confirms documentation and testing updates.
Title check ✅ Passed The title clearly and specifically summarizes the main change: upgrading zod to version 4.1.13 and addressing AI-suggested improvements (markRaw wrapping, error message key changes).
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

♻️ Duplicate comments (4)
apps/web-antd/src/views/_core/authentication/code-login.vue (1)

48-52: Same verification needed for the error parameter.

This has the same concern as the phoneNumber validation above - verify that Zod 4's error parameter accepts string values directly.

apps/web-ele/src/views/_core/authentication/forget-password.vue (1)

5-5: Same changes as web-tdesign variant.

This file shows identical changes to the web-tdesign forget-password.vue file. Please refer to the review comments on that file regarding markRaw usage and verification of the error parameter.

Also applies to: 23-28

apps/web-naive/src/views/_core/authentication/forget-password.vue (1)

5-5: Same changes as other variants.

This file shows identical changes to the web-tdesign and web-ele forget-password.vue files. Please refer to the review comments on the web-tdesign file regarding markRaw usage and verification of the error parameter.

Also applies to: 23-28

apps/web-antd/src/views/_core/authentication/forget-password.vue (1)

5-5: Same changes as other variants.

This file shows identical changes to the other forget-password.vue variants. Please refer to the review comments on the web-tdesign file regarding markRaw usage and verification of the error parameter.

Also applies to: 23-28

🧹 Nitpick comments (2)
playground/src/views/examples/form/custom.vue (1)

70-74: Consider explicit boolean conversion for the regex validation.

The .match() method returns RegExpMatchArray | null, which relies on truthy/falsy conversion within the refine predicate. For better clarity and type safety, explicitly convert to boolean.

🔎 Proposed refactor with explicit boolean conversion
         .refine(
-          (v) => v[1]?.match(/^1[3-9]\d{9}$/),
+          (v) => !!v[1]?.match(/^1[3-9]\d{9}$/),
           // 使用全角空格占位,将错误提示文字挤到手机号码输入框的下面
           { error: '       号码格式不正确' },
         ),
apps/web-naive/src/views/_core/authentication/register.vue (1)

83-87: Optional refactor: Simplify boolean refinement.

The !!value double negation is redundant since value is already a boolean. Consider simplifying:

🔎 Proposed simplification
       rules: markRaw(
         z
           .boolean()
-          .refine((value) => !!value, { error: $t('authentication.agreeTip') }),
+          .refine((value) => value === true, { error: $t('authentication.agreeTip') }),
       ),
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a1bb132 and 86735a3.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (41)
  • apps/web-antd/src/views/_core/authentication/code-login.vue
  • apps/web-antd/src/views/_core/authentication/forget-password.vue
  • apps/web-antd/src/views/_core/authentication/login.vue
  • apps/web-antd/src/views/_core/authentication/register.vue
  • apps/web-antd/src/views/_core/profile/password-setting.vue
  • apps/web-ele/src/views/_core/authentication/code-login.vue
  • apps/web-ele/src/views/_core/authentication/forget-password.vue
  • apps/web-ele/src/views/_core/authentication/login.vue
  • apps/web-ele/src/views/_core/authentication/register.vue
  • apps/web-ele/src/views/_core/profile/password-setting.vue
  • apps/web-naive/src/views/_core/authentication/code-login.vue
  • apps/web-naive/src/views/_core/authentication/forget-password.vue
  • apps/web-naive/src/views/_core/authentication/login.vue
  • apps/web-naive/src/views/_core/authentication/register.vue
  • apps/web-naive/src/views/_core/profile/password-setting.vue
  • apps/web-tdesign/src/views/_core/authentication/code-login.vue
  • apps/web-tdesign/src/views/_core/authentication/forget-password.vue
  • apps/web-tdesign/src/views/_core/authentication/login.vue
  • apps/web-tdesign/src/views/_core/authentication/register.vue
  • apps/web-tdesign/src/views/_core/profile/password-setting.vue
  • docs/src/components/common-ui/vben-form.md
  • docs/src/demos/vben-form/rules/index.vue
  • packages/@core/ui-kit/form-ui/package.json
  • packages/@core/ui-kit/form-ui/src/form-render/form-field.vue
  • packages/@core/ui-kit/form-ui/src/form-render/form.vue
  • packages/@core/ui-kit/form-ui/src/form-render/helper.ts
  • packages/@core/ui-kit/form-ui/src/types.ts
  • packages/@core/ui-kit/form-ui/src/use-form-context.ts
  • packages/effects/layouts/src/widgets/lock-screen/lock-screen-modal.vue
  • packages/effects/layouts/src/widgets/lock-screen/lock-screen.vue
  • playground/src/views/_core/authentication/code-login.vue
  • playground/src/views/_core/authentication/forget-password.vue
  • playground/src/views/_core/authentication/login.vue
  • playground/src/views/_core/authentication/register.vue
  • playground/src/views/_core/profile/password-setting.vue
  • playground/src/views/examples/form/basic.vue
  • playground/src/views/examples/form/custom.vue
  • playground/src/views/examples/form/rules.vue
  • playground/src/views/system/dept/data.ts
  • playground/src/views/system/menu/modules/form.vue
  • pnpm-workspace.yaml
🧰 Additional context used
🧠 Learnings (5)
📚 Learning: 2025-02-23T04:21:24.691Z
Learnt from: mynetfan
Repo: vbenjs/vue-vben-admin PR: 5587
File: playground/src/views/examples/loading/index.vue:15-18
Timestamp: 2025-02-23T04:21:24.691Z
Learning: Chinese text in the description of the loading component example (`playground/src/views/examples/loading/index.vue`) is intentionally kept without i18n support.

Applied to files:

  • packages/effects/layouts/src/widgets/lock-screen/lock-screen.vue
📚 Learning: 2024-11-05T10:34:13.846Z
Learnt from: ArthurDarkstone
Repo: vbenjs/vue-vben-admin PR: 4807
File: docs/src/components/common-ui/vben-vxe-table.md:65-84
Timestamp: 2024-11-05T10:34:13.846Z
Learning: In `docs/src/components/common-ui/vben-vxe-table.md`, the code examples are provided within markdown scripts for documentation and do not require import statements or explicit type annotations.

Applied to files:

  • playground/src/views/_core/authentication/code-login.vue
  • playground/src/views/examples/form/rules.vue
  • playground/src/views/system/dept/data.ts
  • docs/src/demos/vben-form/rules/index.vue
  • playground/src/views/system/menu/modules/form.vue
📚 Learning: 2024-12-04T04:41:30.161Z
Learnt from: mynetfan
Repo: vbenjs/vue-vben-admin PR: 5013
File: docs/src/components/layout-ui/page.md:31-31
Timestamp: 2024-12-04T04:41:30.161Z
Learning: 在 Vben Admin 项目的 `Page` 组件中,`extra` 内容仅通过 slots 提供,没有对应的 prop 属性。

Applied to files:

  • playground/src/views/examples/form/rules.vue
📚 Learning: 2024-12-09T04:41:58.914Z
Learnt from: mynetfan
Repo: vbenjs/vue-vben-admin PR: 5075
File: packages/effects/common-ui/src/components/api-select/api-select.vue:61-62
Timestamp: 2024-12-09T04:41:58.914Z
Learning: 在文件 `packages/effects/common-ui/src/components/api-select/api-select.vue` 的组件 `ApiSelect` 中,`childrenField` 的默认值设置为空字符串是有意的,因为并非所有组件都使用树形数据。

Applied to files:

  • playground/src/views/examples/form/rules.vue
  • docs/src/demos/vben-form/rules/index.vue
  • playground/src/views/system/menu/modules/form.vue
📚 Learning: 2025-01-15T04:29:13.944Z
Learnt from: mynetfan
Repo: vbenjs/vue-vben-admin PR: 5397
File: playground/src/bootstrap.ts:23-30
Timestamp: 2025-01-15T04:29:13.944Z
Learning: In the Vue-Vben-Admin project, commented code in bootstrap.ts showing modal and drawer configuration examples should be preserved as reference documentation, even after moving to CSS variables for z-index management.

Applied to files:

  • apps/web-tdesign/src/views/_core/authentication/code-login.vue
🧬 Code graph analysis (3)
playground/src/views/system/dept/data.ts (1)
packages/locales/src/index.ts (1)
  • $t (13-13)
packages/@core/ui-kit/form-ui/src/form-render/helper.ts (1)
packages/@core/base/shared/src/utils/inference.ts (2)
  • isString (161-161)
  • isObject (160-160)
packages/@core/ui-kit/form-ui/src/use-form-context.ts (1)
packages/@core/ui-kit/form-ui/src/form-render/helper.ts (1)
  • getCustomDefaultValue_byZodSchema (57-106)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: Test (windows-latest)
  • GitHub Check: Check (windows-latest)
  • GitHub Check: post-update (windows-latest)
  • GitHub Check: post-update (ubuntu-latest)
  • GitHub Check: Check (windows-latest)
  • GitHub Check: Test (windows-latest)
  • GitHub Check: post-update (windows-latest)
🔇 Additional comments (67)
apps/web-antd/src/views/_core/profile/password-setting.vue (1)

4-4: LGTM! Zod 4 migration applied correctly.

The changes correctly implement the Zod 4 upgrade:

  1. markRaw wrapper (lines 42-49): Prevents Vue's reactivity system from tracking the Zod schema, which improves performance by avoiding unnecessary deep reactive conversions on complex Zod internal structures.

  2. Error key migration (lines 45, 47): The switch from message to error aligns with Zod 4's unified error customization API, replacing the fragmented message/required_error pattern from Zod 3.

Both changes follow the documented Zod 4 patterns and the PR's stated objectives for performance optimization and API modernization.

Also applies to: 42-49

apps/web-ele/src/views/_core/profile/password-setting.vue (1)

4-4: LGTM! Consistent with the Antd variant.

The changes are identical to the web-antd variant and correctly implement the Zod 4 migration with markRaw wrapper and unified error parameter.

Also applies to: 42-49

apps/web-naive/src/views/_core/profile/password-setting.vue (1)

4-4: LGTM! Consistent with other UI variants.

The changes correctly implement the Zod 4 migration pattern with markRaw wrapper and unified error parameter, consistent with the Antd and Element variants.

Also applies to: 42-49

apps/web-tdesign/src/views/_core/profile/password-setting.vue (1)

4-4: LGTM! Consistent with other UI variants.

The changes correctly implement the Zod 4 migration pattern with markRaw wrapper and unified error parameter, maintaining consistency across all four UI framework adapters.

Also applies to: 42-49

apps/web-antd/src/views/_core/authentication/code-login.vue (2)

5-5: LGTM! Correct import for performance optimization.

Adding markRaw is the right approach for preventing Vue's reactivity system from wrapping Zod schemas, which improves performance.


24-31: No issue found. Zod 4's error parameter accepts string values directly, as demonstrated throughout the official documentation. The code correctly uses { error: $t('authentication.mobileTip') } and { error: $t('authentication.mobileErrortip') }, which aligns with Zod 4's unified error API.

apps/web-tdesign/src/views/_core/authentication/forget-password.vue (2)

5-5: Good addition of markRaw import.

The import aligns with the PR's performance optimization goal to prevent Vue's reactivity system from tracking Zod schema objects.


23-28: No changes needed. Zod 4 accepts plain strings for the error parameter in validation methods, as shown in the official documentation examples. In Zod 4, the error parameter unifies what were previously separate message and errorMap parameters, allowing both string and function approaches interchangeably. The code correctly uses direct strings like { error: $t('authentication.emailTip') } for localized error messages.

packages/effects/layouts/src/widgets/lock-screen/lock-screen-modal.vue (2)

4-4: LGTM: Import addition for performance optimization.

The addition of markRaw to the Vue imports is correct and necessary for wrapping Zod schemas to prevent unnecessary reactivity tracking.


46-50: Code pattern is correct for Zod 4.

The markRaw wrapping prevents Vue reactivity overhead on Zod schemas. The error parameter correctly uses direct string assignment ({ error: $t(...) }), which is the standard Zod 4 syntax for simple error messages. Function syntax is only needed when accessing validation issue details.

playground/src/views/examples/form/basic.vue (2)

4-4: LGTM! Appropriate import for performance optimization.

Adding markRaw to prevent Vue's reactivity system from tracking Zod schemas is a good performance optimization, as validation schemas don't need reactivity.


237-239: No issues found. Zod 4's .refine() method correctly accepts the error parameter with a direct string value, as shown in the official documentation with examples like .refine((val) => val.length > 8, { error: "Too short!" }). In Zod 4, the parameter was renamed from message to error, and while the message parameter is still supported, it is deprecated. The code in the file uses the correct modern Zod 4 syntax.

playground/src/views/_core/profile/password-setting.vue (1)

42-49: Excellent use of markRaw for performance optimization.

The markRaw wrapper prevents Vue's reactivity system from tracking Zod schema objects, which aligns perfectly with the PR objectives. The error parameter syntax is also correct; Zod 4 accepts string values directly in the error parameter.

apps/web-tdesign/src/views/_core/authentication/code-login.vue (2)

5-5: Good addition of markRaw import for performance optimization.

The markRaw import is correctly used to wrap Zod schemas (lines 24 and 48), preventing Vue's reactivity system from tracking these validation objects unnecessarily, which improves performance.


24-31: No changes needed. Zod 4 supports plain strings for the error parameter, as shown in official documentation examples like z.string().min(5, { error: "Too short!" }). The error param optionally accepts a function, but string values are also valid. The code's use of { error: $t('authentication.mobileTip') } follows the correct and documented pattern.

playground/src/views/system/menu/modules/form.vue (4)

8-8: LGTM!

Good addition of markRaw import. Wrapping Zod schemas with markRaw is the correct approach to prevent Vue's reactivity system from tracking these objects, improving performance.


53-75: LGTM!

Proper use of markRaw wrapping and Zod 4's unified error parameter. The async refinement correctly validates uniqueness by returning false when the name already exists.


138-168: LGTM!

Well-structured validation chain with proper Zod 4 syntax. The path validation correctly enforces format constraints and uniqueness.


268-268: LGTM!

Good use of Zod 4's standalone z.url() schema with unified error customization.

playground/src/views/_core/authentication/forget-password.vue (2)

4-4: Good performance optimization with markRaw.

Wrapping the Zod schema with markRaw() is the correct approach to prevent Vue's reactivity system from tracking the immutable Zod object, which improves performance.

Also applies to: 22-27


25-26: No action required—validation syntax is correct for Zod 4.

In Zod 4, the error parameter unified what were separate message (string) and errorMap (function) parameters in v3. The message parameter is still supported but deprecated. Both .min() and .email() methods support the { error: string } syntax, making the current implementation correct.

apps/web-antd/src/views/_core/authentication/register.vue (4)

5-5: Good addition of markRaw import.

Importing markRaw is appropriate for wrapping Zod schemas to prevent Vue's reactivity system from unnecessarily tracking these objects, which improves performance.


23-25: Excellent use of markRaw for performance optimization.

The consistent wrapping of Zod schemas with markRaw() correctly prevents Vue's reactivity system from tracking the internal structure of Zod validation objects. This is a proper implementation of the performance optimization mentioned in the PR objectives.

Also applies to: 40-42, 52-59, 83-87


49-61: Dynamic password confirmation validation looks correct.

The implementation correctly uses the dependencies pattern to dynamically validate that the confirmation password matches the main password field. The triggerFields configuration ensures re-validation when the password changes, which provides proper user feedback.


23-25: No issues found. The validation rules correctly use { error: string } format, which is supported in Zod 4.1.13 alongside the function format.

playground/src/views/examples/form/rules.vue (5)

2-2: LGTM! Good performance optimization.

Importing markRaw from Vue to wrap Zod schemas is the correct approach to prevent Vue's reactivity system from deeply tracking validation schemas, which improves performance.


54-54: LGTM! Correct Zod 4 default value handling.

The combination of .default() and .optional() is valid in Zod 4, where defaults are now applied even inside optional fields, as documented in the library specifications.


155-155: LGTM! Correct checkbox validation logic.

The .refine((value) => value) correctly validates that the checkbox must be checked (true) before the form can be submitted. The markRaw wrapping is appropriate.


201-219: LGTM! Correct async validation implementation.

The async validation logic is correctly implemented:

  • Checks minimum length first (.min(3))
  • Then performs async username existence check via .refine()
  • Correctly returns !exists to validate that the username is available
  • The 1-second delay properly simulates an API call

The markRaw wrapping is appropriate for the entire schema.


63-63: > Likely an incorrect or invalid review comment.

apps/web-ele/src/views/_core/authentication/register.vue (5)

5-5: LGTM! Appropriate import for performance optimization.

Adding markRaw to the imports is correct. This enables wrapping Zod schemas to prevent Vue's reactivity system from tracking them, which improves performance as validation schemas don't need reactivity.


23-25: LGTM! Correct migration to Zod 4 API.

The migration from message: to error: aligns with Zod 4's unified error customization API, and wrapping with markRaw prevents unnecessary reactivity tracking.


40-42: LGTM! Consistent with Zod 4 migration.

The password field validation follows the same correct pattern as the username field, using the unified error parameter and markRaw wrapper.


83-87: LGTM! Correct boolean validation with Zod 4.

The checkbox validation properly uses Zod 4's unified error parameter with .refine() and is appropriately wrapped with markRaw for performance optimization.


52-59: The Zod 4 API migration is correct and the dynamic markRaw pattern is appropriate.

The code correctly uses Zod 4's unified error parameter in both .min() and .refine(). The dynamic schema creation within dependencies.rules() is necessary because the validation logic closes over the current password value. Using markRaw() here is the correct optimization, as it prevents Vue from tracking Zod schemas, which are immutable objects that don't need reactivity. This pattern aligns with the rest of the codebase (lines 23, 40, 83).

apps/web-ele/src/views/_core/authentication/code-login.vue (3)

5-5: LGTM! Correct import for performance optimization.

Adding markRaw to the imports is necessary for wrapping Zod schemas to prevent Vue's reactivity system from tracking their internal properties, which improves performance.


48-52: LGTM! Same pattern as phoneNumber validation.

The code validation follows the same pattern as the phoneNumber field with markRaw wrapper and error parameter. The same verification request from the previous comment applies here.


24-31: Implementation correctly uses Zod 4 error parameter syntax.

In Zod 4, the separate message (string) and errorMap (function) parameters from v3 have been unified as the error parameter, which optionally accepts a function but also accepts string values directly. The pattern { error: "string value" } is standard usage for both .min() and other validators. The code correctly uses { error: $t('...') } where the translation function returns a string, following the documented Zod 4 pattern. No changes needed.

playground/src/views/_core/authentication/code-login.vue (2)

5-5: Good addition of markRaw import.

Adding markRaw to the imports is appropriate for wrapping Zod schemas to prevent Vue's reactivity system from tracking them, which improves performance.


44-51: Error parameter syntax in Zod 4 is correct and requires no changes.

Zod 4 explicitly supports passing a string directly to the error parameter: z.string().min(5, { error: "Too short!" }). The error param optionally accepts a function, meaning both syntaxes are valid. In Zod v3, there were separate params for message (a string) and errorMap (a function). These have been unified in Zod 4 as error.

The code pattern { error: $t('...') } used in the validation schemas at lines 44-51 and 87-91 is correct and fully supported by Zod 4.1.13. The markRaw() wrapper is also appropriate for preventing Vue reactivity tracking on the validation schema.

Likely an incorrect or invalid review comment.

playground/src/views/examples/form/custom.vue (2)

64-75: LGTM! Successful migration to Zod 4 with markRaw optimization.

The migration correctly wraps the Zod schema with markRaw() to prevent Vue reactivity tracking, which improves performance as noted in the PR objectives. The use of the unified { error: '...' } parameter in refinements aligns with Zod 4's new error customization API.


67-67: No action needed. The .length(2, 'message') syntax is valid in Zod 4. Zod functions and schema methods accept custom errors both as bare strings and within error objects, with both .length(7, 'String must be exactly 7 characters') and the object format being supported. The message parameter is still supported but deprecated, meaning bare strings remain a valid option for constraint methods.

apps/web-tdesign/src/views/_core/authentication/register.vue (2)

5-5: LGTM: Import addition for performance optimization.

The markRaw import is correctly added to support wrapping Zod schemas, preventing Vue's reactivity system from unnecessarily tracking schema objects.


23-25: Zod 4 migration correctly implemented with proper error API usage and Vue optimization.

All validation schemas have been properly updated to Zod 4's unified error parameter:

  • Migrated from separate message/errorMap parameters to the unified error parameter, as specified in Zod 4
  • Wrapped with markRaw() to prevent Vue's reactive conversion overhead on schema objects
  • Dynamic validation for confirm password correctly returns a new wrapped schema based on runtime values
  • Boolean refinement for policy agreement properly enforces required checkbox validation

vee-validate v5 beta provides first-class Zod support without requiring the @vee-validate/zod companion package, aligning with the dependency removal.

Runtime verification is recommended given the major version upgrades (Zod to 4.1.13, vee-validate to 5.0.0-beta.0).

apps/web-naive/src/views/_core/authentication/code-login.vue (3)

5-5: LGTM: markRaw import added for schema optimization.

The addition of markRaw aligns with the performance optimization strategy to prevent Vue's reactivity system from tracking static Zod schemas.


48-52: LGTM: Code field validation correctly updated for Zod v4.

The validation rule follows the same correct pattern as the phoneNumber field, using the unified error parameter and markRaw wrapping.


24-31: Correctly migrated to Zod v4 with proper error handling and performance optimization.

The error parameter replaces the deprecated message parameter in Zod v4, which is correctly implemented across all validation rules. Using markRaw() prevents Vue's reactivity system from tracking the schema, avoiding performance overhead when dealing with static validation objects. The phone number validation logic (minimum 1 character + 11-digit regex) is correctly structured, and this pattern is consistently applied throughout the authentication views.

apps/web-naive/src/views/_core/authentication/register.vue (3)

5-5: LGTM: Performance optimization import.

Adding markRaw import is correct and necessary to prevent Vue from tracking Zod schema objects, which improves performance as intended by this PR.


52-60: LGTM: Confirm password validation logic is correct.

The dynamic validation using dependencies.rules correctly implements password confirmation logic. The markRaw wrapper is properly placed around the returned schema, and triggerFields: ['password'] ensures re-validation when the password field changes.


23-25: No changes needed. Zod 4 accepts both string values and functions for the error parameter—the code at lines 23-25 and others (40-42, 52-59, 83-87) is correct as written.

Likely an incorrect or invalid review comment.

packages/effects/layouts/src/widgets/lock-screen/lock-screen.vue (1)

2-2: LGTM! Zod v4 migration correctly applied.

The changes correctly implement Zod v4's unified error parameter and use markRaw to prevent Vue from making the schema reactive, which improves performance.

Also applies to: 54-56

docs/src/components/common-ui/vben-form.md (1)

546-570: LGTM! Documentation correctly demonstrates Zod v4 usage patterns.

The documentation examples are updated consistently with:

  • markRaw wrapping to prevent Vue reactivity
  • error parameter instead of message (Zod v4 unified error customization)
  • Various validation patterns (basic, optional, union, refine)

This provides clear guidance for developers migrating to Zod v4.

playground/src/views/system/dept/data.ts (1)

7-7: LGTM! Zod v4 validation rules correctly implemented.

The form validation rules are properly migrated:

  • markRaw wrapping prevents unnecessary Vue reactivity overhead
  • error key replaces message per Zod v4 API
  • Internationalized error messages preserved
  • Validation logic (min/max length) remains unchanged

Also applies to: 22-37, 75-82

packages/@core/ui-kit/form-ui/package.json (1)

48-48: LGTM! Dependency cleanup aligns with Zod v4 and vee-validate v5.

The removal of @vee-validate/zod and zod-defaults is correct:

  • vee-validate v5 provides direct Zod integration
  • Zod v4 has improved default value handling (.default() and .prefault() methods)
  • Simpler dependency tree reduces maintenance burden
docs/src/demos/vben-form/rules/index.vue (1)

2-2: LGTM! Demo correctly illustrates Zod v4 validation patterns.

The form validation demo is properly updated:

  • markRaw wrapping applied consistently
  • error parameter used instead of message (Zod v4 API)
  • Email validation uses object syntax: .email({ error: '...' })
  • Default values with optional chaining preserved

Also applies to: 53-53, 62-62, 74-74

playground/src/views/_core/authentication/register.vue (1)

5-5: LGTM! Authentication form validation correctly migrated to Zod v4.

All validation rules are properly updated:

  • Static rules wrapped with markRaw and use error key
  • Dynamic rules (in dependencies.rules) also return markRaw-wrapped schemas
  • Custom validation with .refine() uses error parameter correctly
  • Validation logic and control flow preserved

Also applies to: 23-25, 40-42, 52-59, 83-87

packages/@core/ui-kit/form-ui/src/types.ts (1)

2-2: LGTM! Type refinement from ZodTypeAny to ZodType improves type safety.

The change from ZodTypeAny to ZodType provides:

  • More specific type constraints for form validation rules
  • Better type inference in TypeScript
  • Alignment with Zod v4's improved type system

This is a beneficial refinement that enhances type safety across the form infrastructure.

Also applies to: 54-54, 75-75

pnpm-workspace.yaml (2)

173-173: Test vee-validate 5.0.0-beta.0 thoroughly before production use.

While vee-validate v5 brings built-in support for Zod and other Standard Schema libraries, verify that:

  1. Critical form validation flows work correctly with your Zod schemas
  2. You're prepared for potential breaking changes in future beta releases, as this is pre-release software

194-194: Zod v4.1.13 migration is complete across the codebase. All schema definitions consistently use the v4 error: syntax instead of v3's message:, with no deprecated patterns remaining.

apps/web-naive/src/views/_core/authentication/login.vue (1)

41-94: LGTM! Zod v4 migration correctly applied.

The changes correctly implement Zod v4's unified error customization using the error parameter, replacing the deprecated message key. Wrapping schemas with markRaw prevents Vue's reactivity system from deeply tracking Zod objects, which is a good performance optimization for validation rules.

The pattern is consistently applied across all fields:

  • selectAccount: String validation with default and optional chaining
  • username and password: Required string validations
  • captcha: Boolean refinement with custom error message

Note: This same pattern is correctly applied across all login views (web-naive, web-ele, web-antd, web-tdesign, playground).

packages/@core/ui-kit/form-ui/src/form-render/form-field.vue (2)

135-157: Simplified fieldRules logic looks good.

The removal of toTypedSchema and the simplified rules handling aligns with the migration away from @vee-validate/zod. The logic correctly:

  • Returns null when the field is not visible
  • Handles string-based rules
  • Unwraps optional schemas when required
  • Preserves the original schema when optional

108-133: Clarify whether internal Zod API access is acceptable for this use case.

In Zod v4, the ._def property moved to ._zod.def, so the code's use of zodSchema._zod.def.innerType follows the correct v4 pattern. However, this internal structure is subject to change and not comprehensively documented—it's considered relevant to library authors but not part of the stable public API. Unlike ZodOptional which has a public .unwrap() method, ZodDefault has no documented public method for accessing its inner type, making this implementation fragile to future Zod updates.

packages/@core/ui-kit/form-ui/src/form-render/form.vue (1)

62-91: LGTM! Clean refactor with improved type safety.

The refactored shapes computation is much clearer and properly leverages the new Zod helper functions:

  • getDefaultValue_byZodSchema for extracting defaults from schemas
  • getBaseRules_byZodSchema for unwrapping schema layers
  • safeParse(undefined).success for determining optionality

The explicit handling of string vs. ZodType rules improves type safety and makes the code more maintainable. The logic correctly:

  1. Preserves explicit defaultValue from schema
  2. Extracts defaults from Zod schemas when available
  3. Determines required state based on schema validation
  4. Stores base rules for validation
packages/@core/ui-kit/form-ui/src/use-form-context.ts (1)

45-63: LGTM! Simplified default value generation.

The refactored generateInitialValues function is much cleaner and properly delegates to the getCustomDefaultValue_byZodSchema helper. The logic correctly:

  1. Prioritizes explicit defaultValue from schema definitions
  2. Falls back to Zod schema-based defaults for non-string rules
  3. Only sets values when defaults are defined (undefined check)

The change from Reflect.has(item, 'defaultValue') to 'defaultValue' in item is acceptable for this use case, though note that the in operator checks the prototype chain while Reflect.has does not. Since these are plain schema objects, this difference should not cause issues.

The removal of complex Zod object merging logic in favor of the dedicated helper function significantly improves maintainability.

packages/@core/ui-kit/form-ui/src/form-render/helper.ts (3)

1-11: Imports look good.

The updated imports properly reflect the Zod 4 types needed for the refactored helper functions.


89-98: The .shape property is a documented public API in Zod 4 and is the correct way to access object properties. The official Zod migration guide explicitly shows accessing .shape directly: "use z.object(A.shape)". While Zod 4 moved the internal ._def property to ._zod.def, this is an internal change and doesn't affect user-facing APIs. The code correctly accesses the shape property and requires no changes.

Likely an incorrect or invalid review comment.


64-101: String format detection incomplete for Zod 4 standalone schemas

In Zod 4, standalone schema methods like z.uuid() are now separate top-level schemas rather than string refinements. The code's comment on line 64 claims it covers z.email() via a type === 'string' check, but Zod 4 implements these as separate schema classes ($ZodEmail, $ZodUUID, etc.) with their own type discriminators. This means the switch statement will not catch these standalone formats.

Additionally, the ._def property is now moved to ._zod.def, and while lines 72, 75, 93 correctly use this pattern, the type checking logic needs enhancement to detect all string-based schemas (both z.string() and standalone formats like z.email(), z.uuid(), z.ipv4()).

Comment on lines +40 to +42
rules: markRaw(
z.string().min(1, { error: $t('authentication.passwordTip') }),
),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Enforce minimum password length of at least 8 characters.

The password validation currently accepts passwords as short as 1 character (z.string().min(1, ...)), which is insufficient for security. NIST SP 800-63-3 guidelines require a minimum of 8 characters for standard passwords. While the component includes a password strength indicator, this provides UI feedback only and cannot substitute for proper validation. Ensure server-side validation enforces at least 8 characters minimum (preferably 12+ per OWASP standards).

🤖 Prompt for AI Agents
In apps/web-naive/src/views/_core/authentication/register.vue around lines 40 to
42, the password schema currently uses z.string().min(1, ...) which allows
1-character passwords; update the validation to require a minimum of 8
characters by changing the schema minimum to 8 (or higher if desired) and adjust
the translated error key/message accordingly; also ensure the same minimum
requirement is enforced server-side to match client validation.

Comment on lines +22 to +27
// For ZodDefault, there's no public unwrap method.
// Accessing _def.innerType is necessary but relies on Zod 4 internals.
// ⚠️ This assumes Zod v4.x. Update if migrating to a future major version.
if (schema instanceof ZodDefault) {
return getBaseRules_byZodSchema(schema._zod.def.innerType as ZodType);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cat -n packages/@core/ui-kit/form-ui/src/form-render/helper.ts | head -40

Repository: vbenjs/vue-vben-admin

Length of output: 1473


🏁 Script executed:

# Check for Zod version in package.json
rg '"zod"' package.json -A2 -B2

Repository: vbenjs/vue-vben-admin

Length of output: 47


🏁 Script executed:

# Look for other usages of ZodDefault and _def or _zod patterns
rg -n 'schema\._(?:zod\.def|def)' --type=ts

Repository: vbenjs/vue-vben-admin

Length of output: 401


🌐 Web query:

Zod 4.1.13 ZodDefault schema inner type property access

💡 Result:

Short answer: use the ZodDefault unwrap() helper (or its internals) to get the inner schema.

Examples (Zod v4.1.x):

  • Preferred: call .unwrap()
    const s = z.string().default("x");
    const inner = s.unwrap(); // ZodString
    console.log(inner.parse("y"));

  • Internals (not recommended but available): s._zod.def.innerType or s._def.innerType (works in 4.1.x builds).
    const innerViaDef = (s as any)._zod.def.innerType;
    console.log(innerViaDef._def.type);

References: Zod internals and ZodDefault implementation showing .unwrap() and ._zod.def.innerType. [1][2]

Sources
[1] Zod core internals docs.
[2] Zod v4 classic schemas implementation (ZodDefault).


Use public .unwrap() API instead of relying on internal properties.

The comment states ZodDefault has "no public unwrap method," but ZodDefault does provide a .unwrap() method. While schema._zod.def.innerType works in Zod 4.1.13, the code should use the public API:

if (schema instanceof ZodDefault) {
  return getBaseRules_byZodSchema(schema.unwrap() as ZodType);
}

This eliminates reliance on internal properties and removes the version-specific dependency comment. Apply the same fix to lines 46 and 60.

🤖 Prompt for AI Agents
In packages/@core/ui-kit/form-ui/src/form-render/helper.ts around lines 22-27
(and also apply the same change at lines ~46 and ~60), replace usages of the
internal _zod.def.innerType access with the public unwrap() API: call
schema.unwrap() and pass that (cast to ZodType if needed) into
getBaseRules_byZodSchema, and remove the comment about assuming Zod v4 internals
since relying on the public .unwrap() eliminates that dependency.

Comment on lines +45 to +47
if (schema instanceof ZodDefault) {
return schema._zod.def.defaultValue;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Same _zod.def access issue.

Line 46 has the same problematic pattern: schema._zod.def.defaultValue. This should likely be schema._def.defaultValue() or similar, depending on the actual Zod 4 API.

🤖 Prompt for AI Agents
In packages/@core/ui-kit/form-ui/src/form-render/helper.ts around lines 45 to
47, replace the unsafe access to the internal _zod.def.defaultValue with the
correct Zod v4 internal shape by using schema._def.defaultValue and invoking it
if it's a function; specifically, read schema._def.defaultValue, if typeof that
is 'function' call it to get the default, otherwise return it directly, avoiding
use of schema._zod.def.

Comment on lines +58 to 62
if (schema instanceof ZodDefault || schema instanceof ZodOptional) {
return getCustomDefaultValue_byZodSchema(
schema._zod.def.innerType as ZodType,
);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: _zod.def access pattern repeated.

Line 60 continues the same problematic _zod.def.innerType pattern identified earlier. This will cause the same runtime failures.

🤖 Prompt for AI Agents
In packages/@core/ui-kit/form-ui/src/form-render/helper.ts around lines 58 to
62, the code is again accessing the private _zod.def.innerType which causes
runtime failures; replace that access with the correct public/internal Zod def
property (use schema._def.innerType) and cast to ZodType as needed, i.e., obtain
the inner type from schema._def.innerType for both ZodDefault and ZodOptional
before passing it to getCustomDefaultValue_byZodSchema.

Comment on lines +69 to +85
case 'intersection': {
// 对于交集类型,从schema 提取默认值
const leftDefaultValue = getCustomDefaultValue_byZodSchema(
(schema as ZodIntersection)._zod.def.left as ZodType,
);
const rightDefaultValue = getCustomDefaultValue_byZodSchema(
(schema as ZodIntersection)._zod.def.right as ZodType,
);

// 如果左右两边都能提取默认值,合并它们
if (isObject(leftDefaultValue) && isObject(rightDefaultValue)) {
return { ...leftDefaultValue, ...rightDefaultValue };
}

// 否则优先使用左边的默认值
return leftDefaultValue ?? rightDefaultValue;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: _zod.def pattern in intersection handling.

Lines 72 and 75 access _zod.def.left and _zod.def.right for intersection types. This continues the same incorrect property access pattern that will cause runtime failures.

🤖 Prompt for AI Agents
packages/@core/ui-kit/form-ui/src/form-render/helper.ts lines 69-85: the code
incorrectly accesses internal intersection schema fields via (schema as
ZodIntersection)._zod.def.left/right which will crash at runtime; change the
access to the correct Zod internals (use (schema as ZodIntersection)._def.left
and (schema as ZodIntersection)._def.right) and cast those to ZodType before
passing to getCustomDefaultValue_byZodSchema, keeping the existing merge logic
unchanged.

Comment on lines +182 to +206
rules: markRaw(
z
.string()
.min(2, {
error: $t('ui.formRules.minLength', [$t('system.menu.path'), 2]),
})
.max(100, {
error: $t('ui.formRules.maxLength', [$t('system.menu.path'), 100]),
})
.refine(
(value: string) => {
return value.startsWith('/');
},
{
error: $t('ui.formRules.startWith', [$t('system.menu.path'), '/']),
},
)
.refine(
async (value: string) => {
return await isMenuPathExists(value, formData.value?.id);
},
{ error: $t('system.menu.activePathMustExist') },
)
.optional(),
),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Error messages reference wrong field label.

The error messages on lines 186, 189, and 196 use $t('system.menu.path'), but this field is activePath with label $t('system.menu.activePath'). This appears to be a copy-paste oversight that could confuse users when validation fails.

🔎 Proposed fix
     rules: markRaw(
       z
         .string()
         .min(2, {
-          error: $t('ui.formRules.minLength', [$t('system.menu.path'), 2]),
+          error: $t('ui.formRules.minLength', [$t('system.menu.activePath'), 2]),
         })
         .max(100, {
-          error: $t('ui.formRules.maxLength', [$t('system.menu.path'), 100]),
+          error: $t('ui.formRules.maxLength', [$t('system.menu.activePath'), 100]),
         })
         .refine(
           (value: string) => {
             return value.startsWith('/');
           },
           {
-            error: $t('ui.formRules.startWith', [$t('system.menu.path'), '/']),
+            error: $t('ui.formRules.startWith', [$t('system.menu.activePath'), '/']),
           },
         )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
rules: markRaw(
z
.string()
.min(2, {
error: $t('ui.formRules.minLength', [$t('system.menu.path'), 2]),
})
.max(100, {
error: $t('ui.formRules.maxLength', [$t('system.menu.path'), 100]),
})
.refine(
(value: string) => {
return value.startsWith('/');
},
{
error: $t('ui.formRules.startWith', [$t('system.menu.path'), '/']),
},
)
.refine(
async (value: string) => {
return await isMenuPathExists(value, formData.value?.id);
},
{ error: $t('system.menu.activePathMustExist') },
)
.optional(),
),
rules: markRaw(
z
.string()
.min(2, {
error: $t('ui.formRules.minLength', [$t('system.menu.activePath'), 2]),
})
.max(100, {
error: $t('ui.formRules.maxLength', [$t('system.menu.activePath'), 100]),
})
.refine(
(value: string) => {
return value.startsWith('/');
},
{
error: $t('ui.formRules.startWith', [$t('system.menu.activePath'), '/']),
},
)
.refine(
async (value: string) => {
return await isMenuPathExists(value, formData.value?.id);
},
{ error: $t('system.menu.activePathMustExist') },
)
.optional(),
),
🤖 Prompt for AI Agents
In playground/src/views/system/menu/modules/form.vue around lines 182 to 206,
the validation error messages reference the wrong label key
($t('system.menu.path')) for the activePath field; replace those occurrences
(lines ~186, ~189, ~196) with $t('system.menu.activePath') so the
min/max/startWith messages use the correct field label while leaving the
isMenuPathExists error key unchanged.

@aonoa aonoa changed the title 升级 zod 依赖版本至 4.1.13,已处理AI提示 chore: 升级 zod 依赖版本至 4.1.13,已处理AI提示 Dec 27, 2025
@jinmao88
Copy link
Collaborator

jinmao88 commented Jan 6, 2026

这个有点破坏性更新,有兼容的方法么

@leocaan
Copy link
Author

leocaan commented Jan 16, 2026

主要是zod的v4版本升级改动极大,并且4.0 和之后的小版本间也有些版本兼容。之所以做这次zod相关的升级是因为现在前后端都用TS了,后端bun用到的hono,drizzle等都和zod v4绑定了。为了保持前后端引用包的一致性,建议还是对vben做zod v4的升级。顺便提一句,AI提出的这些issue,基本都是它自己在v4和v4小版本间混乱了的原因造成的。

@jinmao88
Copy link
Collaborator

我的意思是 如果原项目用V3的zod 升级V4需要改动很多

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants