Skip to content

fix(zod): escape newlines in $ref description with generateReusableSchemas#3528

Merged
melloware merged 2 commits into
orval-labs:masterfrom
z4o4z:fix/3517-zod-ref-describe-newlines
Jun 3, 2026
Merged

fix(zod): escape newlines in $ref description with generateReusableSchemas#3528
melloware merged 2 commits into
orval-labs:masterfrom
z4o4z:fix/3517-zod-ref-describe-newlines

Conversation

@z4o4z
Copy link
Copy Markdown
Contributor

@z4o4z z4o4z commented Jun 2, 2026

Summary

Fixes #3517.

With output.override.zod.generateReusableSchemas: true, when an object property is a $ref to a reusable component and carries a multi-line description, orval emitted ReferencedSchema.describe("…") using double quotes around the raw, unescaped description. The literal newlines broke the string literal, producing invalid TypeScript:

x.zod.schemas.ts(15,46): error TS1002: Unterminated string literal.

Sibling primitive fields with the same multi-line description were emitted correctly (single-quoted, \n-escaped) — orval already had a working escaper; the $ref + .describe() path just wasn't using it.

Root cause

packages/zod/src/index.ts — the chainable-sibling path for $refs used:

functions.push(['describe', `"${escape(siblingSchema.description)}"`]);

escape() only escapes quote characters, not newlines, and the result was wrapped in double quotes. This construct is only produced in generateReusableSchemas mode, which is why it didn't surface before.

Fix

Use the same single-quoted, fully JS-escaped form as the primitive description path (pushDescriptionOrMeta):

functions.push(['describe', `'${jsStringEscape(siblingSchema.description)}'`]);

Now $ref siblings and primitive fields are escaped identically:

"sub": UserId.describe('Subject identifier.\n\nMust be normalized first.'),

Tests

  • Updated the existing $ref description test to expect the single-quoted form.
  • Added regression test escapes newlines in a multi-line description sibling on a $ref (#3517), verified to fail before the fix and pass after.
  • Full @orval/zod suite passes (204 tests).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Generated Zod validation schemas now emit description strings as single-quoted, fully JS-escaped literals, ensuring special characters and newlines are represented safely.
  • Tests

    • Added a regression test verifying multi-line descriptions are emitted with escaped newline characters so generated code remains single-line and valid.

…hemas

When `generateReusableSchemas: true` and an object property is a $ref with a
multi-line `description` sibling, the description was emitted as
`Name.describe("…raw text…")` via `escape()`, which only escapes quote chars.
Multi-line descriptions produced literal newlines inside a double-quoted string
literal, generating invalid TypeScript (TS1002 unterminated string literal).

Use the same single-quoted, fully JS-escaped form as the primitive description
path (`jsStringEscape`), so `$ref` siblings and primitive fields are escaped
identically.

Fixes orval-labs#3517

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 2, 2026 17:16
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 2, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8e8dcb95-9466-48f9-9992-6b71703df7c4

📥 Commits

Reviewing files that changed from the base of the PR and between b6f98dc and 696b4b3.

📒 Files selected for processing (1)
  • packages/zod/src/zod.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/zod/src/zod.test.ts

📝 Walkthrough

Walkthrough

The PR fixes a TypeScript compilation error when generateReusableSchemas is enabled: $ref fields with multi-line descriptions now emit properly escaped single-quoted .describe() strings instead of malformed double-quoted strings with unescaped newlines.

Changes

Zod $ref description escaping

Layer / File(s) Summary
String escaping and quoting for .describe() arguments
packages/zod/src/index.ts, packages/zod/src/zod.test.ts
applyChainableSiblings now uses jsStringEscape(...) and single-quoted string literals when emitting sibling .describe() arguments. Tests updated: existing expectation switched to single quotes and a new regression test (#3517) asserts multi-line descriptions are emitted with \n\n escaped.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Suggested reviewers

  • melloware

🐰 I nibbled at newline seams,
single quotes now mend the dreams.
Escaped lines hop safe and sound,
generated code compiles—huzzah! 🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main fix: escaping newlines in $ref descriptions when using generateReusableSchemas in the Zod integration.
Linked Issues check ✅ Passed The changes fully address the linked issue #3517 by implementing jsStringEscape for $ref descriptions and adding a regression test.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing the $ref description escaping issue; no extraneous modifications are present.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR updates how .describe(...) is emitted for $ref schemas with a sibling description, ensuring multiline descriptions are properly JS-escaped (preventing raw newlines from breaking the generated TS).

Changes:

  • Switch $ref sibling description emission from escape(...) + double quotes to jsStringEscape(...) + single quotes.
  • Add a regression test covering multiline $ref sibling descriptions and update an existing expectation to match the new quoting.

Reviewed changes

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

File Description
packages/zod/src/index.ts Fixes $ref sibling description string escaping to avoid emitting raw newlines in generated code.
packages/zod/src/zod.test.ts Updates/extends tests to assert correct single-quoted, newline-escaped .describe(...) output.

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

Comment thread packages/zod/src/index.ts
Comment on lines 283 to 292
if (typeof siblingSchema.description === 'string') {
functions.push(['describe', `"${escape(siblingSchema.description)}"`]);
// Use the same single-quoted, fully JS-escaped form as the primitive
// description path (see `pushDescriptionOrMeta`). `escape` only escapes
// quote chars, so a multi-line description would emit raw newlines and
// break the generated string literal (TS1002).
functions.push([
'describe',
`'${jsStringEscape(siblingSchema.description)}'`,
]);
}
@melloware melloware added the zod Zod schema client related issue label Jun 2, 2026
Copy link
Copy Markdown
Collaborator

@melloware melloware left a comment

Choose a reason for hiding this comment

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

Build is failing

@z4o4z z4o4z requested a review from melloware June 3, 2026 19:03
@melloware melloware merged commit 6f82953 into orval-labs:master Jun 3, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

zod Zod schema client related issue

Projects

None yet

Development

Successfully merging this pull request may close these issues.

generateReusableSchemas (zod): $ref field with multi-line description emits unescaped newlines → TS1002 Unterminated string literal

3 participants