Skip to content

fix: handle property names with percent signs in JSON Pointers - #2828

Open
chatman-media wants to merge 1 commit into
openapi-ts:mainfrom
chatman-media:fix/percent-sign-property-name
Open

fix: handle property names with percent signs in JSON Pointers#2828
chatman-media wants to merge 1 commit into
openapi-ts:mainfrom
chatman-media:fix/percent-sign-property-name

Conversation

@chatman-media

Copy link
Copy Markdown

Changes

Fixes #2251.

A schema property name containing a literal percent sign (e.g. "25%") crashes codegen with URIError: URI malformed whenever that property resolves to an object:

components:
  schemas:
    response:
      type: object
      properties:
        "25%":
          type: object
          properties:
            color:
              type: string

Root cause

createRef builds JSON Pointer paths by escaping each segment with Redocly's escapePointer, which escapes ~ and / but does not percent-encode. When a nested object is transformed, the accumulated path (e.g. #/components/schemas/response/25%) is fed back into parseRef, whose unescapePointer runs decodeURIComponent on each segment. decodeURIComponent("25%") throws URIError: URI malformed, crashing the whole run.

The same parseRef round-trip is used in several places (createRef, oapiRef, enum-name generation, discriminator property inference), so any of them could hit this with a %-containing key.

Fix

Add a small resilient parseRef wrapper (in src/lib/ts.ts) that delegates to Redocly's parseRef, but on failure falls back to parsing the pointer without decodeURIComponent — and per segment, only decodes when it can, otherwise returns the raw segment. This mirrors the asymmetry of escapePointer (which never percent-encodes), so:

  • Literal % segments (e.g. 25%) pass through unchanged instead of throwing.
  • Legitimately percent-encoded segments (e.g. %7Bid%7D -> {id}) still decode correctly.

All internal parseRef call sites now use this wrapper.

How to Review

  • The behavioral regression test is in test/transform/schema-object/object.test.ts ("property name with percent sign (nested object)"). It throws URIError: URI malformed on main and passes with this change.
  • Unit tests for the wrapper are in test/lib/ts.test.ts (describe("parseRef")): confirms normal parsing, percent-decoding, and no-throw on a bare %.
  • pnpm test passes for the openapi-typescript package.

Checklist

  • Unit tests updated
  • docs/ updated (if necessary) — n/a
  • pnpm run update:examples run — n/a (no example schema output changes)
  • Changeset added (.changeset/percent-sign-property-name.md)
A schema property name containing a literal percent sign (e.g. "25%")
crashed codegen with "URIError: URI malformed" whenever the property
resolved to an object, because the accumulated path was re-parsed through
Redocly's parseRef -> decodeURIComponent.

Wrap parseRef so a failed decodeURIComponent falls back to the raw,
un-decoded pointer segment (mirroring escapePointer, which does not
percent-encode). Valid percent-encoded segments still decode correctly.

Closes openapi-ts#2251
@chatman-media
chatman-media requested a review from a team as a code owner June 13, 2026 15:34
@changeset-bot

changeset-bot Bot commented Jun 13, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 63b2f98

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
openapi-typescript Patch

Not sure what this means? Click here to learn what changesets are.

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

@netlify

netlify Bot commented Jun 13, 2026

Copy link
Copy Markdown

👷 Deploy request for openapi-ts pending review.

Visit the deploys page to approve it

Name Link
🔨 Latest commit 63b2f98
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant