mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-22 07:02:16 +03:00
fix(cli): generated combo PATCH sends literal {id} — resolve $ref params + requestBody (#10955) (#11013)
⭐5 — Fix(#10955): generator de CLI não resolvia $ref em parâmetros do OpenAPI (bug em 20 lugares do spec), PATCH combo sem requestBody. TDD RED→GREEN, gates completos (file-size/complexity/cognitive/changelog/typecheck/lint/docs-all) todos OK. UNSTABLE é o base-red inherited #9985.
This commit is contained in:
committed by
GitHub
parent
60829241fd
commit
effc542a6a
@@ -156,8 +156,11 @@ const IGNORE_FROM_CODE = new Set([
|
||||
// X11/Wayland display server vars used by tray heuristic (isTraySupported).
|
||||
"DISPLAY",
|
||||
"WAYLAND_DISPLAY",
|
||||
// Build-time override for OpenAPI spec path used by generate-api-commands.mjs.
|
||||
// Build-time overrides for generate-api-commands.mjs (spec input / commands output dir).
|
||||
// OPENAPI_OUT_DIR exists so tests/unit/cli-api-generator-ref-params.test.ts can regenerate
|
||||
// into a scratch dir instead of the real bin/cli/api-commands/ tree.
|
||||
"OPENAPI_SPEC",
|
||||
"OPENAPI_OUT_DIR",
|
||||
// Aliases for documented vars handled via fallback ordering.
|
||||
"API_KEY",
|
||||
"APP_URL",
|
||||
|
||||
@@ -11,7 +11,7 @@ import * as yaml from "js-yaml";
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const ROOT = join(__dirname, "..", "..");
|
||||
const SPEC_PATH = process.env.OPENAPI_SPEC || join(ROOT, "docs/openapi.yaml");
|
||||
const OUT_DIR = join(ROOT, "bin/cli/api-commands");
|
||||
const OUT_DIR = process.env.OPENAPI_OUT_DIR || join(ROOT, "bin/cli/api-commands");
|
||||
|
||||
// Operations already covered by hand-crafted commands — skip in generated output.
|
||||
const IGNORED_OP_IDS = new Set([
|
||||
@@ -51,6 +51,29 @@ if (!existsSync(OUT_DIR)) mkdirSync(OUT_DIR, { recursive: true });
|
||||
|
||||
const spec = yaml.load(readFileSync(SPEC_PATH, "utf8"));
|
||||
|
||||
// Minimal, scoped $ref resolver — only follows refs into components/parameters.
|
||||
// This is not a generic dereferencer (no cycle handling, no cross-file refs):
|
||||
// OpenAPI `parameters` entries in this spec only ever $ref a component parameter
|
||||
// (see docs/openapi.yaml → components/parameters/ResourceId), so a full
|
||||
// dereferencer would be scope creep. Without this, `p.in === "path"` silently
|
||||
// drops every $ref'd path parameter (a bare `{ $ref }` object has no `.in`),
|
||||
// which is what let generated PATCH/DELETE combo commands lose --id (#10955).
|
||||
const PARAM_REF_PREFIX = "#/components/parameters/";
|
||||
function resolveParam(p) {
|
||||
if (p && typeof p === "object" && typeof p.$ref === "string") {
|
||||
if (!p.$ref.startsWith(PARAM_REF_PREFIX)) {
|
||||
throw new Error(`Unsupported parameter $ref (only ${PARAM_REF_PREFIX}* is resolved): ${p.$ref}`);
|
||||
}
|
||||
const name = p.$ref.slice(PARAM_REF_PREFIX.length);
|
||||
const resolved = spec.components?.parameters?.[name];
|
||||
if (!resolved) {
|
||||
throw new Error(`Unresolvable parameter $ref: ${p.$ref}`);
|
||||
}
|
||||
return resolved;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/** @type {Record<string, Array<{path: string, method: string, opId: string, op: object}>>} */
|
||||
const byTag = {};
|
||||
|
||||
@@ -89,7 +112,7 @@ for (const [tag, ops] of Object.entries(byTag)) {
|
||||
|
||||
for (const { path, method, opId, op } of ops) {
|
||||
const cmdName = kebab(opId);
|
||||
const params = op.parameters || [];
|
||||
const params = (op.parameters || []).map(resolveParam);
|
||||
const pathParams = params.filter((p) => p.in === "path");
|
||||
const queryParams = params.filter((p) => p.in === "query");
|
||||
const hasBody = !!op.requestBody;
|
||||
|
||||
Reference in New Issue
Block a user