@kubb/oas 4.31.1 → 4.31.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +84 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +83 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/utils.spec.ts +59 -5
- package/src/utils.ts +114 -1
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@ import { a as __require, i as __name, n as __esmMin, o as __toCommonJS, r as __e
|
|
|
2
2
|
import jsonpointer from "jsonpointer";
|
|
3
3
|
import BaseOas from "oas";
|
|
4
4
|
import { matchesMimeType } from "oas/utils";
|
|
5
|
+
import fs from "node:fs";
|
|
5
6
|
import path from "node:path";
|
|
6
7
|
import { pascalCase } from "@kubb/core/transformers";
|
|
7
8
|
import { URLPath } from "@kubb/core/utils";
|
|
@@ -4391,9 +4392,90 @@ function getDefaultValue(schema) {
|
|
|
4391
4392
|
}
|
|
4392
4393
|
if (schema.type === "object" || schema.properties) return "{}";
|
|
4393
4394
|
}
|
|
4395
|
+
/**
|
|
4396
|
+
* Recursively collect all external local-file $ref prefixes (e.g. "api-definitions.yml")
|
|
4397
|
+
* from an object tree. URL refs (http/https) are ignored.
|
|
4398
|
+
*/
|
|
4399
|
+
function collectExternalFilePaths(obj, files) {
|
|
4400
|
+
if (!obj || typeof obj !== "object") return;
|
|
4401
|
+
if (Array.isArray(obj)) {
|
|
4402
|
+
for (const item of obj) collectExternalFilePaths(item, files);
|
|
4403
|
+
return;
|
|
4404
|
+
}
|
|
4405
|
+
for (const [key, value] of Object.entries(obj)) if (key === "$ref" && typeof value === "string") {
|
|
4406
|
+
const hashIdx = value.indexOf("#");
|
|
4407
|
+
const filePart = hashIdx > 0 ? value.slice(0, hashIdx) : hashIdx === -1 ? value : "";
|
|
4408
|
+
if (filePart && !filePart.startsWith("http://") && !filePart.startsWith("https://")) files.add(filePart);
|
|
4409
|
+
} else collectExternalFilePaths(value, files);
|
|
4410
|
+
}
|
|
4411
|
+
/**
|
|
4412
|
+
* Replace all $refs that start with `externalFile#` with the corresponding
|
|
4413
|
+
* internal ref (i.e. just the fragment part, `#/...`).
|
|
4414
|
+
*/
|
|
4415
|
+
function replaceExternalRefsInPlace(obj, externalFile) {
|
|
4416
|
+
if (!obj || typeof obj !== "object") return;
|
|
4417
|
+
if (Array.isArray(obj)) {
|
|
4418
|
+
for (const item of obj) replaceExternalRefsInPlace(item, externalFile);
|
|
4419
|
+
return;
|
|
4420
|
+
}
|
|
4421
|
+
const record = obj;
|
|
4422
|
+
for (const key of Object.keys(record)) {
|
|
4423
|
+
const value = record[key];
|
|
4424
|
+
if (key === "$ref" && typeof value === "string" && value.startsWith(`${externalFile}#`)) record[key] = value.slice(externalFile.length);
|
|
4425
|
+
else if (value && typeof value === "object") replaceExternalRefsInPlace(value, externalFile);
|
|
4426
|
+
}
|
|
4427
|
+
}
|
|
4428
|
+
/**
|
|
4429
|
+
* Before bundling, scan the main spec file for external local-file references and merge
|
|
4430
|
+
* their `components` sections into the main document. This ensures that schemas defined
|
|
4431
|
+
* in external files (e.g. `api-definitions.yml#/components/schemas/Parcel`) end up in
|
|
4432
|
+
* `#/components/schemas/Parcel` of the bundled output, rather than being inlined as
|
|
4433
|
+
* anonymous path-based refs.
|
|
4434
|
+
*
|
|
4435
|
+
* Returns the merged document, or `null` if no external file components were found.
|
|
4436
|
+
*/
|
|
4437
|
+
function mergeExternalFileComponents(mainFilePath) {
|
|
4438
|
+
let mainContent;
|
|
4439
|
+
try {
|
|
4440
|
+
mainContent = fs.readFileSync(mainFilePath, "utf-8");
|
|
4441
|
+
} catch {
|
|
4442
|
+
return null;
|
|
4443
|
+
}
|
|
4444
|
+
const mainDoc = import_yaml.parse(mainContent);
|
|
4445
|
+
if (!mainDoc || typeof mainDoc !== "object") return null;
|
|
4446
|
+
const mainDir = path.dirname(mainFilePath);
|
|
4447
|
+
const externalFiles = /* @__PURE__ */ new Set();
|
|
4448
|
+
collectExternalFilePaths(mainDoc, externalFiles);
|
|
4449
|
+
if (externalFiles.size === 0) return null;
|
|
4450
|
+
let hasMergedComponents = false;
|
|
4451
|
+
for (const externalFile of externalFiles) {
|
|
4452
|
+
const externalFilePath = path.resolve(mainDir, externalFile);
|
|
4453
|
+
let externalContent;
|
|
4454
|
+
try {
|
|
4455
|
+
externalContent = fs.readFileSync(externalFilePath, "utf-8");
|
|
4456
|
+
} catch {
|
|
4457
|
+
continue;
|
|
4458
|
+
}
|
|
4459
|
+
const externalDoc = import_yaml.parse(externalContent);
|
|
4460
|
+
if (!externalDoc?.components || typeof externalDoc.components !== "object") continue;
|
|
4461
|
+
const mainComponents = mainDoc.components ?? {};
|
|
4462
|
+
mainDoc.components = mainComponents;
|
|
4463
|
+
for (const [componentType, components] of Object.entries(externalDoc.components)) {
|
|
4464
|
+
if (!components || typeof components !== "object") continue;
|
|
4465
|
+
mainComponents[componentType] = {
|
|
4466
|
+
...components,
|
|
4467
|
+
...mainComponents[componentType] ?? {}
|
|
4468
|
+
};
|
|
4469
|
+
hasMergedComponents = true;
|
|
4470
|
+
}
|
|
4471
|
+
}
|
|
4472
|
+
if (!hasMergedComponents) return null;
|
|
4473
|
+
for (const externalFile of externalFiles) replaceExternalRefsInPlace(mainDoc, externalFile);
|
|
4474
|
+
return mainDoc;
|
|
4475
|
+
}
|
|
4394
4476
|
async function parse(pathOrApi, { oasClass = Oas, enablePaths = true } = {}) {
|
|
4395
4477
|
if (typeof pathOrApi === "string" && !pathOrApi.match(/\n/) && !pathOrApi.match(/^\s*\{/) && enablePaths) try {
|
|
4396
|
-
return parse(await bundle(pathOrApi), {
|
|
4478
|
+
return parse(await bundle(mergeExternalFileComponents(pathOrApi) ?? pathOrApi), {
|
|
4397
4479
|
oasClass,
|
|
4398
4480
|
enablePaths
|
|
4399
4481
|
});
|