Skip to content

fix: handle z.brand() in zod-to-valibot codemod#1516

Open
sueun-dev wants to merge 1 commit into
open-circle:mainfrom
sueun-dev:fix/codemod-brand
Open

fix: handle z.brand() in zod-to-valibot codemod#1516
sueun-dev wants to merge 1 commit into
open-circle:mainfrom
sueun-dev:fix/codemod-brand

Conversation

@sueun-dev

@sueun-dev sueun-dev commented Jun 21, 2026

Copy link
Copy Markdown

Fixes #1501

The zod-to-valibot codemod didn't recognize .brand(), so z.string().brand("StationNumber") was emitted as v.string()("StationNumber") — a schema called as a function, which doesn't compile.

brand is now handled as a validator, mapping z.<schema>().brand(name) to v.pipe(v.<schema>(), v.brand(name)):

  • added brand to ZOD_VALIDATORS and a transformBrand that emits v.brand(...)
  • added a brand test fixture (string and number brands, plus one chained with .min())

This covers the runtime-argument form .brand("X") from the issue. The type-only form .brand<"X">() carries no runtime value and the validator transform only receives runtime arguments, so it's left out of scope here.

Tested with vitest (72 passing, including the new brand fixture).

Summary by CodeRabbit

  • New Features
    • Added support for converting Zod branded schemas to Valibot branded schemas in the codemod.

The codemod did not recognize .brand(), so z.string().brand("X") was
emitted as v.string()("X"), which does not compile. Handle brand as a
validator that maps z.<schema>().brand(name) to
v.pipe(v.<schema>(), v.brand(name)), and add a brand test fixture.

Fixes open-circle#1501
Copilot AI review requested due to automatic review settings June 21, 2026 06:41
@dosubot dosubot Bot added size:S This PR changes 10-29 lines, ignoring generated files. fix A smaller enhancement or bug fix labels Jun 21, 2026
@coderabbitai

coderabbitai Bot commented Jun 21, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

The pull request adds support for transforming Zod's .brand() validator into the equivalent Valibot v.brand() action within the zod-to-valibot codemod. A new transformBrand function is introduced that constructs a JSCodeshift CallExpression for <valibotIdentifier>.brand(...args). This function is exported through the validators barrel modules and integrated into toValibotActionExp via a new case 'brand' branch. The string 'brand' is also added to the ZOD_VALIDATORS constant. Test fixtures covering three branded schemas (plain string, number, and non-empty string) are added alongside a new test registration entry.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: adding support for z.brand() in the zod-to-valibot codemod.
Linked Issues check ✅ Passed The PR fully addresses issue #1501 by implementing transformBrand to convert z.brand() calls to v.pipe(v.schema(), v.brand()) format, fixing the broken output.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing brand support: test fixtures, validator registration, transformation logic, and test setup integration.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes the @valibot/zod-to-valibot codemod’s handling of Zod’s .brand() so it no longer emits a schema as a callable function (e.g. v.string()("StationNumber")), and instead converts it into a Valibot pipeline action (v.pipe(..., v.brand(...))), matching Valibot’s API.

Changes:

  • Added brand as a recognized Zod validator and mapped it to v.brand(...) in the validator transform switch.
  • Introduced a new transformBrand validator transform and exported it via the validators barrel files.
  • Added a brand test fixture and included it in the codemod’s test suite.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
codemod/zod-to-valibot/src/transform/schemas-and-links/validators/index.ts Re-exports the new brand validator transform.
codemod/zod-to-valibot/src/transform/schemas-and-links/validators/brand/index.ts Adds barrel export for the new brand validator module.
codemod/zod-to-valibot/src/transform/schemas-and-links/validators/brand/brand.ts Implements transformBrand emitting v.brand(...).
codemod/zod-to-valibot/src/transform/schemas-and-links/schemas-and-links.ts Wires brand into toValibotActionExp via transformBrand.
codemod/zod-to-valibot/src/transform/schemas-and-links/constants.ts Adds brand to ZOD_VALIDATORS so it’s recognized in chains.
codemod/zod-to-valibot/src/test-setup.test.ts Includes the new brand fixture in the codemod tests.
codemod/zod-to-valibot/testfixtures/brand/input.ts Fixture input demonstrating .brand() usage (including chaining with .min()).
codemod/zod-to-valibot/testfixtures/brand/output.ts Fixture output expecting v.pipe(..., v.brand(...)).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +3 to +10
export function transformBrand(
valibotIdentifier: string,
args: j.CallExpression['arguments']
) {
return j.callExpression(
j.memberExpression(j.identifier(valibotIdentifier), j.identifier('brand')),
args
);

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f6f154fb83

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

) {
return j.callExpression(
j.memberExpression(j.identifier(valibotIdentifier), j.identifier('brand')),
args

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve generic-only brand names

When the input uses the supported Zod v3/v4 form where the brand is only in the generic, such as .brand<'UserId'>(), args is empty, so passing args through here emits v.brand(). Valibot's brand API requires a name argument, which leaves the migrated code type-invalid and fails to preserve the nominal brand for this common Zod style; derive the literal from the call's type parameters or avoid transforming zero-argument brands.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
codemod/zod-to-valibot/src/transform/schemas-and-links/validators/brand/brand.ts (1)

3-11: ⚡ Quick win

Add required JSDoc and pure-factory annotation.

transformBrand is exported in codemod/** and appears pure, so it should include both the required JSDoc and // @NO_SIDE_EFFECTS`` marker.

Suggested patch
 import j from 'jscodeshift';
 
+/**
+ * Transforms Zod `.brand(...)` to a Valibot `v.brand(...)` action call.
+ */
+// `@__NO_SIDE_EFFECTS__`
 export function transformBrand(
   valibotIdentifier: string,
   args: j.CallExpression['arguments']
 ) {

As per coding guidelines, {library,packages,codemod}/**/*.{ts,tsx,js,jsx}: JSDoc required on exported functions (first overload only for overload sets) and Add // @NO_SIDE_EFFECTS comment before pure factory functions for tree-shaking optimization.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@codemod/zod-to-valibot/src/transform/schemas-and-links/validators/brand/brand.ts`
around lines 3 - 11, The exported function transformBrand is missing required
documentation and tree-shaking optimization markers. Add a JSDoc comment block
above the transformBrand function that describes what it does, and add a //
`@__NO_SIDE_EFFECTS__` comment immediately before the function declaration to mark
it as a pure factory function for tree-shaking optimization, as required by the
coding guidelines for exported functions in the codemod directory.

Source: Coding guidelines

codemod/zod-to-valibot/src/transform/schemas-and-links/validators/brand/index.ts (1)

1-1: ⚡ Quick win

Use .ts extension in the local re-export path.

Update the re-export path to satisfy the ESM import rule enforced by ESLint.

Suggested patch
-export * from './brand';
+export * from './brand.ts';

As per coding guidelines, **/*.{ts,tsx,js,jsx}: Use ESM with .ts extensions in imports (enforced by ESLint).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@codemod/zod-to-valibot/src/transform/schemas-and-links/validators/brand/index.ts`
at line 1, In the export statement, update the re-export path from './brand' to
'./brand.ts' to include the .ts extension. This satisfies the ESM import rule
enforced by ESLint which requires explicit file extensions in import paths for
better compatibility with ES modules.

Source: Coding guidelines

codemod/zod-to-valibot/src/transform/schemas-and-links/validators/index.ts (1)

2-2: ⚡ Quick win

Align the new validator re-export with .ts extension imports.

This new local re-export should use a .ts extension to comply with the project’s ESM import rule.

Suggested patch
-export * from './brand';
+export * from './brand.ts';

As per coding guidelines, **/*.{ts,tsx,js,jsx}: Use ESM with .ts extensions in imports (enforced by ESLint).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@codemod/zod-to-valibot/src/transform/schemas-and-links/validators/index.ts`
at line 2, The re-export statement for the brand validator is missing the `.ts`
file extension, which violates the project's ESM import rule that requires
explicit `.ts` extensions. Update the export statement to include the `.ts`
extension when re-exporting from the './brand' module to comply with the ESLint
coding guidelines.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In
`@codemod/zod-to-valibot/src/transform/schemas-and-links/validators/brand/brand.ts`:
- Around line 3-11: The exported function transformBrand is missing required
documentation and tree-shaking optimization markers. Add a JSDoc comment block
above the transformBrand function that describes what it does, and add a //
`@__NO_SIDE_EFFECTS__` comment immediately before the function declaration to mark
it as a pure factory function for tree-shaking optimization, as required by the
coding guidelines for exported functions in the codemod directory.

In
`@codemod/zod-to-valibot/src/transform/schemas-and-links/validators/brand/index.ts`:
- Line 1: In the export statement, update the re-export path from './brand' to
'./brand.ts' to include the .ts extension. This satisfies the ESM import rule
enforced by ESLint which requires explicit file extensions in import paths for
better compatibility with ES modules.

In `@codemod/zod-to-valibot/src/transform/schemas-and-links/validators/index.ts`:
- Line 2: The re-export statement for the brand validator is missing the `.ts`
file extension, which violates the project's ESM import rule that requires
explicit `.ts` extensions. Update the export statement to include the `.ts`
extension when re-exporting from the './brand' module to comply with the ESLint
coding guidelines.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7d1668ce-8ea1-4aec-afe9-adabca03ca05

📥 Commits

Reviewing files that changed from the base of the PR and between 1f9b183 and f6f154f.

📒 Files selected for processing (8)
  • codemod/zod-to-valibot/__testfixtures__/brand/input.ts
  • codemod/zod-to-valibot/__testfixtures__/brand/output.ts
  • codemod/zod-to-valibot/src/test-setup.test.ts
  • codemod/zod-to-valibot/src/transform/schemas-and-links/constants.ts
  • codemod/zod-to-valibot/src/transform/schemas-and-links/schemas-and-links.ts
  • codemod/zod-to-valibot/src/transform/schemas-and-links/validators/brand/brand.ts
  • codemod/zod-to-valibot/src/transform/schemas-and-links/validators/brand/index.ts
  • codemod/zod-to-valibot/src/transform/schemas-and-links/validators/index.ts

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

No issues found across 8 files

Re-trigger cubic

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

Labels

fix A smaller enhancement or bug fix size:S This PR changes 10-29 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Codemod breaks z.brand

2 participants