Skip to content

fix: decode URI-encoded names in operation dependencies to prevent missing filtered operations#3782

Merged
mrlubos merged 3 commits intomainfrom
copilot/fix-missing-operations-filtering
Apr 17, 2026
Merged

fix: decode URI-encoded names in operation dependencies to prevent missing filtered operations#3782
mrlubos merged 3 commits intomainfrom
copilot/fix-missing-operations-filtering

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 16, 2026

When filtering by tags or operations, operations whose response schemas had names containing URL-unsafe characters (e.g. generic types like PaginatedList<ClientItem>) were silently dropped from the output.

Root cause

The JSON schema ref-parser's url.resolve() uses the URL constructor, which percent-encodes characters like < and > in hash fragments. A $ref of #/components/schemas/PaginatedList<ClientItem> becomes #/components/schemas/PaginatedList%3CClientItem%3E in the bundled spec.

buildGraph stores the encoded form as the dependency pointer, but buildResourceMetadata builds schema keys from direct object traversal (no encoding). In getDependencies, the encoded name produced schema/PaginatedList%3CClientItem%3E — which never matched schema/PaginatedList<ClientItem> in resourceMetadata.schemas. collectOperations then saw an unresolvable dependency and skipped the operation entirely.

Without filters, filterSpec is never called, so this mismatch was invisible.

Changes

  • packages/shared/src/openApi/shared/graph/meta.ts — apply decodeURI() to the name extracted from each transitive dependency pointer before constructing the namespace key, consistent with how refToName() works elsewhere.

  • packages/shared/src/openApi/shared/graph/__tests__/meta.test.ts — new tests covering:

    • getDependencies producing decoded keys when the graph contains URL-encoded $ref pointers
    • End-to-end: tag-filtered output correctly includes operations referencing schemas with angle-bracket names

@bolt-new-by-stackblitz
Copy link
Copy Markdown

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

Copilot AI linked an issue Apr 16, 2026 that may be closed by this pull request
@vercel
Copy link
Copy Markdown

vercel bot commented Apr 16, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hey-api-docs Ready Ready Preview, Comment Apr 17, 2026 4:44am

Request Review

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 16, 2026

🦋 Changeset detected

Latest commit: 290c14f

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

This PR includes changesets to release 4 packages
Name Type
@hey-api/json-schema-ref-parser Patch
@hey-api/openapi-ts Patch
@hey-api/shared Patch
@hey-api/openapi-python 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

Copy link
Copy Markdown
Contributor

@pullfrog pullfrog bot left a comment

Choose a reason for hiding this comment

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

This is a draft PR with zero file changes — there is nothing to review yet. The branch has a single empty "Initial plan" commit identical to main.

The linked issue (#3779) describes operations being dropped when using tag/operation filters on specs with diamond-shaped $ref targets (e.g. PaginatedListItems<ClientResponse>). The angle brackets in the schema name likely cause a lookup failure during $ref resolution in the filtering pass.

Will re-review once code is pushed.

Pullfrog  | Fix it ➔View workflow run𝕏

@pullfrog
Copy link
Copy Markdown
Contributor

pullfrog bot commented Apr 16, 2026

TL;DR — Fixes the root cause of URI-encoded $ref names (e.g. PaginatedListItems%3CClientResponse%3E) by decoding them inside @hey-api/json-schema-ref-parser at emit time, then removes all the scattered decodeURI workarounds that were previously applied downstream across the parser and schema plugins. This ensures names with angle brackets, unicode, and other URL-unsafe characters are preserved correctly throughout the pipeline, preventing operations from being silently dropped when filtering by tag/operation. Linked to #3779.

Key changes

  • Decode $ref values at the source in json-schema-ref-parser — Applies decodeURI() in bundle.ts and dereference.ts where $ref strings are written back, so downstream consumers receive decoded names.
  • Remove downstream decodeURI workarounds across parsers and plugins — Strips 7 scattered decodeURI calls (and their "didn't investigate why" comments) from ref.ts, path.ts, the 2.0.x/3.0.x/3.1.x schema parsers, and the @hey-api/schemas plugin.
  • Fix $ref resolution for OneOfAllOfIssueWritable — Snapshot updates show the Writable suffix now correctly propagates through $ref strings (e.g. Generic.Schema.Duplicate.Issue1[System.Boolean]Writable`), and Zod schemas reorder declarations to reference the correct writable variants.
  • Convert arrow functions to function declarations in schemas plugin — Style-only change affecting all 10 helper functions in plugin.ts.
  • Add Pointer round-trip and bundling tests — New tests in pointer.test.ts and bundle.test.ts verify that generic (<>) and unicode names survive the joinparse cycle and appear decoded in bundled output.

Summary | 158 files | 3 commits | base: maincopilot/fix-missing-operations-filtering


Decode at the source in json-schema-ref-parser

Before: Pointer.join encodes URL-unsafe characters (e.g. <%3C), and the encoded form leaked into bundled/dereferenced $ref strings. Downstream code applied decodeURI in 7 separate places as workarounds.
After: bundle.ts and dereference.ts now call decodeURI() when writing $ref values back to the schema, so every $ref in the output uses the original decoded name.

The fix targets three code paths in the ref parser: internal ref remapping, circular ref handling, and direct circular dereferencing. Each applies decodeURI() to entry.hash, entry.pathFromRoot, or pathFromRoot respectively.

Why not fix Pointer.join itself? Pointer.join uses encodeURI to produce valid JSON Pointers per RFC 6901, which requires encoding. The correct fix is to decode at the boundary where refs are written back to the schema, preserving the internal encoding for resolution while exposing human-readable names in output.

bundle.ts · dereference.ts


Remove downstream decodeURI workarounds

Before: refToName, resolveRef, pathToName, and all three version-specific parseRef functions each called decodeURI with a comment noting the root cause was unknown.
After: All seven workarounds removed — $ref values arrive already decoded from the ref parser.

File Removed call
ref.tsrefToName decodeURI(name)name
ref.tsresolveRef decodeURI($ref) before path parsing
path.tspathToName decodeURI(names.join('-'))names.join('-')
2.0.x/parser/schema.ts decodeURI(schema.$ref) in parseRef
3.0.x/parser/schema.ts decodeURI(schema.$ref) in parseRef
3.1.x/parser/schema.ts decodeURI(schema.$ref) in parseRef
schemas/plugin.ts Three decodeURI(schema.$ref) calls across draft-04, draft-05, and 2020-12 converters

ref.ts · path.ts · schemas/plugin.ts


Snapshot updates across types, schemas, and Zod validators

Before: OneOfAllOfIssueWritable referenced un-suffixed generic schema types (e.g. GenericSchemaDuplicateIssue1SystemBoolean) and the Zod zOneOfAllOfIssueWritable schema was emitted before its dependencies.
After: References correctly resolve to ...Writable variants, and Zod output reorders declarations so zOneOfAllOfIssueWritable appears after its dependencies.

~150 snapshot files updated with identical one-line $ref and type reference corrections across all client/plugin/Zod snapshot configurations for both 3.0.x and 3.1.x.


New ref-parser tests for generic and unicode names

Before: No test coverage for component names containing <> or unicode characters through the bundle pipeline.
After: Four new test cases verify Pointer round-tripping and end-to-end bundling for names like PaginatedListItems<ClientResponse> and Überschrift.

bundle.test.ts · pointer.test.ts

Pullfrog  | View workflow run | via Pullfrog𝕏

Copilot AI changed the title [WIP] Fix missing operations when filtering in OpenAPI specification fix: decode URI-encoded names in operation dependencies to prevent missing filtered operations Apr 16, 2026
Copilot AI requested a review from mrlubos April 16, 2026 10:12
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Apr 16, 2026

Open in StackBlitz

@hey-api/codegen-core

npm i https://pkg.pr.new/@hey-api/codegen-core@3782

@hey-api/json-schema-ref-parser

npm i https://pkg.pr.new/@hey-api/json-schema-ref-parser@3782

@hey-api/nuxt

npm i https://pkg.pr.new/@hey-api/nuxt@3782

@hey-api/openapi-ts

npm i https://pkg.pr.new/@hey-api/openapi-ts@3782

@hey-api/shared

npm i https://pkg.pr.new/@hey-api/shared@3782

@hey-api/spec-types

npm i https://pkg.pr.new/@hey-api/spec-types@3782

@hey-api/types

npm i https://pkg.pr.new/@hey-api/types@3782

@hey-api/vite-plugin

npm i https://pkg.pr.new/@hey-api/vite-plugin@3782

commit: 290c14f

@codecov
Copy link
Copy Markdown

codecov bot commented Apr 16, 2026

Codecov Report

❌ Patch coverage is 12.50000% with 14 lines in your changes missing coverage. Please review.
✅ Project coverage is 40.07%. Comparing base (adb5e15) to head (290c14f).
⚠️ Report is 6 commits behind head on main.

Files with missing lines Patch % Lines
.../openapi-ts/src/plugins/@hey-api/schemas/plugin.ts 0.00% 8 Missing ⚠️
packages/shared/src/utils/ref.ts 0.00% 2 Missing ⚠️
packages/json-schema-ref-parser/src/bundle.ts 50.00% 1 Missing ⚠️
packages/shared/src/openApi/2.0.x/parser/schema.ts 0.00% 1 Missing ⚠️
packages/shared/src/openApi/3.0.x/parser/schema.ts 0.00% 1 Missing ⚠️
packages/shared/src/openApi/3.1.x/parser/schema.ts 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3782      +/-   ##
==========================================
- Coverage   40.08%   40.07%   -0.02%     
==========================================
  Files         522      522              
  Lines       19323    19311      -12     
  Branches     5767     5766       -1     
==========================================
- Hits         7746     7738       -8     
+ Misses       9374     9371       -3     
+ Partials     2203     2202       -1     
Flag Coverage Δ
unittests 40.07% <12.50%> (-0.02%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@mrlubos mrlubos force-pushed the copilot/fix-missing-operations-filtering branch from c3a1063 to 290c14f Compare April 17, 2026 04:43
@mrlubos mrlubos marked this pull request as ready for review April 17, 2026 04:43
@dosubot dosubot bot added size:S This PR changes 10-29 lines, ignoring generated files. bug 🔥 Broken or incorrect behavior. labels Apr 17, 2026
@dosubot dosubot bot added the lgtm This PR has been approved by a maintainer label Apr 17, 2026
Copy link
Copy Markdown
Contributor

@pullfrog pullfrog bot left a comment

Choose a reason for hiding this comment

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

Important

The core fix is correct and well-tested at the ref-parser level, but the PR description is stale (describes the first commit's approach, not the final one) and there are unrelated stylistic changes bundled in.

Summary: The second commit correctly moves URI decoding to the source — the three points in json-schema-ref-parser where entry.hash, entry.pathFromRoot, and pathFromRoot are written into $ref values. This eliminates the need for decodeURI() workarounds scattered across the downstream codebase (schema parsers, refToName, pathToName, resolveRef, schemas plugin). The new ref-parser tests cover both internal refs with generic names (<>) and external refs with unicode names. Snapshot changes are consistent and correct — the OneOfAllOfIssueWritable refs now properly resolve to the ...Writable variants.

One latent edge case to note (not blocking): decodeURI() does not decode URI-reserved characters (#, &, +, =). If a schema name contained any of these, Pointer.join() would encode them via encodeURIComponent() but decodeURI() would leave them encoded. decodeURIComponent() cannot be used here since it would break # in the path. This is acceptable for now since such schema names are extremely rare.

Task list (9/9 completed)
  • Read diff TOC and identify key areas of change
  • Review core logic changes (ref.ts, path.ts, schema parsers)
  • Review json-schema-ref-parser changes (bundle.ts, dereference.ts, tests)
  • Review schemas plugin changes
  • Review snapshot changes for correctness
  • Review changeset
  • Verify decodeURI vs decodeURIComponent concern
  • Self-critique and finalize review
  • Submit review

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run𝕏

Comment thread packages/openapi-ts/src/plugins/@hey-api/schemas/plugin.ts
Comment thread .changeset/kind-terms-greet.md
@mrlubos mrlubos merged commit 1a33cb2 into main Apr 17, 2026
10 of 12 checks passed
@mrlubos mrlubos deleted the copilot/fix-missing-operations-filtering branch April 17, 2026 04:48
@hey-api hey-api bot mentioned this pull request Apr 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug 🔥 Broken or incorrect behavior. lgtm This PR has been approved by a maintainer size:S This PR changes 10-29 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Missing operations when filtering

2 participants