Repository navigation
Resolve parameters embedded in path segments - #1669
Conversation
sserrata
left a comment
There was a problem hiding this comment.
Thanks. The embedded path parameter cases are handled, but the internal variable names appear in user-visible output. Please address the inline items. Consider doing this in the plugin's Postman conversion or building the path from api.path, so that the theme does not need to undo the converter's {{name}} format.
| if (!substituted || resolved === "") return resolved; | ||
|
|
||
| // Bind once so a leading colon in the value cannot be interpreted again. | ||
| let key = `__openapi_path_${index}`; |
There was a problem hiding this comment.
Every resolved embedded segment becomes :__openapi_path_N. Raw URL output (getRaw(), toString(true), toJSON(), code snippets) then shows /records/:__openapi_path_1 and not /records/9527:publish. Use the internal variable only when the resolved value starts with :.
| ); | ||
| postman.url.path = postman.url.path?.map((segment, index) => { | ||
| let substituted = false; | ||
| const resolved = segment.replace(/\{\{([^{}]+)\}\}/g, (token, name) => { |
There was a problem hiding this comment.
The regex replaces every {{name}} token whose name matches a path param. A literal collection-variable token is also replaced, and a converter change can stop the fix with no error.
|
|
||
| // Bind once so a leading colon in the value cannot be interpreted again. | ||
| let key = `__openapi_path_${index}`; | ||
| while (postman.url.variables.has(key)) key += "_"; |
There was a problem hiding this comment.
The collision check looks only at url.variables. A native :__openapi_path_N segment that has no variable gets the injected value. Use a key that cannot collide.
| let substituted = false; | ||
| const resolved = segment.replace(/\{\{([^{}]+)\}\}/g, (token, name) => { | ||
| const value = values.get(name); | ||
| if (typeof value !== "string") return token; |
There was a problem hiding this comment.
Embedded params with no value stay as {{id}}, but native params fall back to the example. The URL and the snippets then show both formats.
| substituted = true; | ||
| return value; | ||
| }); | ||
| if (!substituted || resolved === "") return resolved; |
There was a problem hiding this comment.
An empty value in a middle segment gives /records//items. The test covers only the trailing segment.
| * ========================================================================== */ | ||
|
|
||
| // eslint-disable-next-line import/no-extraneous-dependencies | ||
| import { processOpenapiFile } from "docusaurus-plugin-openapi-docs/src/openapi/openapi"; |
There was a problem hiding this comment.
The theme test now imports plugin source at runtime and uses toBeInstanceOf(sdk.Request) across two package copies. It runs a full conversion for each of about 21 cases. Use inline sdk.Request fixtures, or cache the conversion by template.
sserrata
left a comment
There was a problem hiding this comment.
Thanks for the update. The internal variable names are now gone. One behavior change must be reverted before merge:
| fallback !== null && | ||
| String(fallback) !== "" | ||
| ? String(fallback) | ||
| : `{{${name}}}`; |
There was a problem hiding this comment.
Behavior change for all endpoints: pathTemplate is now always passed, so an unfilled path param shows as {{petId}} in place of :petId. This happens in snippets and in the sent URL (/pets/%7B%7BpetId%7D%7D). It affects every existing site. Please keep the earlier :name output for unfilled params, and change only the embedded-parameter case.
| } | ||
| const value = values.get(name); | ||
| if (value !== undefined && value !== null && String(value) !== "") { | ||
| return String(value); |
There was a problem hiding this comment.
The value goes into the segment without encoding. With /records/{id}:publish and id = a?b, the path becomes /records/a and the query becomes b:publish. A # moves the rest into the fragment. Encode reserved characters (/, ?, #) in the value.
| postman.url.path = path.split("/").map((segment) => | ||
| segment.replace(/\{([^{}]+)\}/g, (token, name, offset) => { | ||
| // Only OpenAPI placeholders are path parameters; collection tokens are literal. | ||
| if ( |
There was a problem hiding this comment.
The adjacent-brace check leaves {id} unresolved in /a/{{id} or /a/{id}}, and the user gets no warning.
|
|
||
| if (pathTemplate === undefined) return; | ||
|
|
||
| const values = new Map( |
There was a problem hiding this comment.
When pathTemplate is set, the variables are assimilated, read back and cleared, and fallbackValues (line 113) is built even when it is not used. Build one value map and resolve from it.
| request ?? | ||
| new sdk.Request({ url: "http://example.com/pets/:petId", method: "GET" }); | ||
| return buildPostmanRequest(postman, { | ||
| pathTemplate: request && requestTemplates.get(request), |
There was a problem hiding this comment.
The tests get pathTemplate through a hidden WeakMap. Pass it explicitly in the options so that the dependency is visible. The & { pathTemplate?: string } on line 15 is also not necessary.
sserrata
left a comment
There was a problem hiding this comment.
Thanks. All review items are addressed, and unfilled path params keep the earlier :name output.
|
Visit the preview URL for this PR (updated for commit 1b8a7d2): https://docusaurus-openapi-36b86--pr1669-cnv47t9r.web.app (expires Mon, 09 Nov 2026 18:50:39 GMT) 🔥 via Firebase Hosting GitHub Action 🌎 Sign: bf293780ee827f578864d92193b8c2866acd459f |
📸 Visual Diff ReportSnapshot comparison against https://docusaurus-openapi.tryingpan.dev/
✅ No visual regressions detected. Updated at 2026-11-02T18:57:28.213Z · run 41172014882 |
|
This PR now conflicts with |
Keep both the scalar query serialization fix and the pathTemplate handling from PaloAltoNetworks#1669. setPathParams now takes normalized path params plus an optional path template, and the call site passes normalizeParams(pathParams) and pathTemplate. Also clear the two import/order warnings with eslint --fix.
Refs #621. The binding fix in #1311 does not resolve parameters embedded in a segment, such as
/records/{id}:publish.Pass the original
api.pathexplicitly to request and snippet builders. Use the authored path for embedded parameters and literal collection tokens; ordinary standalone parameters retain the SDK's:namerepresentation and bindings. Inserted/,?and#are encoded. Bindings are cleared only on the materialized clone, and the original request remains unchanged. Unclosed parameters warn and retain the converted path; adjacent extra braces keep their literal text.Include the main-branch changes through #1677, preserving its body-error handling in both consumers. An explicit string annotation fixes type inference in the new upstream Jest project; the emitted builder JavaScript is unchanged by that annotation.
Validation on Node 26.5.0/macOS: full
yarn testpasses 353 tests across 16 suites. All three packages build without cache; strict changed-file ESLint, Prettier and diff checks pass. The existing path-parameter fixtures remain unchanged.Required full
yarn lintstill exits 2 at the existing Cypresscypress/globalsconfiguration error. No browser or hosted CI matrix result is claimed.