@hey-api/shared 0.4.0 โ 0.4.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.d.mts +15 -9
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +191 -189
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -6
package/dist/index.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import open from "open";
|
|
|
5
5
|
import { sync } from "cross-spawn";
|
|
6
6
|
import * as semver from "semver";
|
|
7
7
|
import { getResolvedInput, sendRequest } from "@hey-api/json-schema-ref-parser";
|
|
8
|
-
import { fromRef, ref } from "@hey-api/codegen-core";
|
|
8
|
+
import { fromRef, log, ref } from "@hey-api/codegen-core";
|
|
9
9
|
import { EOL } from "node:os";
|
|
10
10
|
//#region src/tsConfig.ts
|
|
11
11
|
function findPackageJson(initialDir) {
|
|
@@ -628,13 +628,21 @@ function getLogs(userLogs) {
|
|
|
628
628
|
//#endregion
|
|
629
629
|
//#region src/config/output/postprocess.ts
|
|
630
630
|
function postprocessOutput(config, postProcessors, jobPrefix) {
|
|
631
|
+
if (!fs.existsSync(config.path) || !fs.readdirSync(config.path).length) return;
|
|
631
632
|
for (const processor of config.postProcess) {
|
|
632
633
|
const resolved = typeof processor === "string" ? postProcessors[processor] : processor;
|
|
633
634
|
if (!resolved) continue;
|
|
634
635
|
const name = resolved.name ?? resolved.command;
|
|
635
636
|
const args = resolved.args.map((arg) => arg.replace("{{path}}", config.path));
|
|
636
637
|
console.log(`${jobPrefix}๐งน Running ${colors.cyanBright(name)}`);
|
|
637
|
-
sync(resolved.command, args);
|
|
638
|
+
const result = sync(resolved.command, args);
|
|
639
|
+
if (result.error) throw new ConfigError(`Post-processor "${name}" failed to run: ${result.error.message}`);
|
|
640
|
+
if (result.status !== null && result.status !== 0) {
|
|
641
|
+
let message = `Post-processor "${name}" exited with code ${result.status}`;
|
|
642
|
+
const stderr = result.stderr?.toString().trim();
|
|
643
|
+
if (stderr) message += `:\n${stderr}`;
|
|
644
|
+
throw new ConfigError(message);
|
|
645
|
+
}
|
|
638
646
|
}
|
|
639
647
|
}
|
|
640
648
|
//#endregion
|
|
@@ -1294,28 +1302,28 @@ function operationToId({ context, count = 1, id, method, path, state }) {
|
|
|
1294
1302
|
//#endregion
|
|
1295
1303
|
//#region src/debug/ir.ts
|
|
1296
1304
|
const indent = (level) => " ".repeat(level);
|
|
1297
|
-
const log = (message, level) => console.log(`${indent(level ?? 0)}${message}`);
|
|
1305
|
+
const log$1 = (message, level) => console.log(`${indent(level ?? 0)}${message}`);
|
|
1298
1306
|
const print = (ir, options = {}) => {
|
|
1299
1307
|
const { depth = 2, section = "all", verbosity = "summary" } = options;
|
|
1300
1308
|
const printObject = (obj, level, kind = "generic") => {
|
|
1301
1309
|
if (verbosity === "summary" && obj && typeof obj === "object") if (kind === "responses") {
|
|
1302
1310
|
const count = Object.keys(obj).length;
|
|
1303
1311
|
const noun = count === 1 ? "code" : "codes";
|
|
1304
|
-
log(`responses: ${colors.yellow(`${count} ${noun}`)}`, level);
|
|
1305
|
-
} else if (kind === "requestBody") log(`requestBody: ${Object.keys(obj).join(", ")}`, level);
|
|
1306
|
-
else if (kind === "schema") log(`schema keys: ${Object.keys(obj).join(", ")}`, level);
|
|
1307
|
-
else log(`keys: ${Object.keys(obj).join(", ")}`, level);
|
|
1308
|
-
else log(JSON.stringify(obj, null, depth), level);
|
|
1312
|
+
log$1(`responses: ${colors.yellow(`${count} ${noun}`)}`, level);
|
|
1313
|
+
} else if (kind === "requestBody") log$1(`requestBody: ${Object.keys(obj).join(", ")}`, level);
|
|
1314
|
+
else if (kind === "schema") log$1(`schema keys: ${Object.keys(obj).join(", ")}`, level);
|
|
1315
|
+
else log$1(`keys: ${Object.keys(obj).join(", ")}`, level);
|
|
1316
|
+
else log$1(JSON.stringify(obj, null, depth), level);
|
|
1309
1317
|
};
|
|
1310
1318
|
const printPathItem = (key, item, base = 1) => {
|
|
1311
1319
|
if ("$ref" in item) {
|
|
1312
|
-
log(`${colors.cyan(key)} is a $ref โ ${colors.yellow(item.$ref)}`, base);
|
|
1320
|
+
log$1(`${colors.cyan(key)} is a $ref โ ${colors.yellow(item.$ref)}`, base);
|
|
1313
1321
|
return;
|
|
1314
1322
|
}
|
|
1315
1323
|
for (const method of Object.keys(item)) {
|
|
1316
1324
|
if (!httpMethods.includes(method)) continue;
|
|
1317
1325
|
const operation = item[method];
|
|
1318
|
-
log(`${colors.green(method.toUpperCase())} ${colors.cyan(key)} (${colors.magenta(operation.operationId ?? "")})`, base);
|
|
1326
|
+
log$1(`${colors.green(method.toUpperCase())} ${colors.cyan(key)} (${colors.magenta(operation.operationId ?? "")})`, base);
|
|
1319
1327
|
if (operation.body) printObject(operation.body, base + 1, "requestBody");
|
|
1320
1328
|
if (operation.responses) printObject(operation.responses, base + 1, "responses");
|
|
1321
1329
|
}
|
|
@@ -1324,20 +1332,20 @@ const print = (ir, options = {}) => {
|
|
|
1324
1332
|
for (const section of sections) switch (section) {
|
|
1325
1333
|
case "components":
|
|
1326
1334
|
if (ir.components?.schemas) {
|
|
1327
|
-
log(`Components: ${Object.keys(ir.components.schemas).length} schemas`);
|
|
1335
|
+
log$1(`Components: ${Object.keys(ir.components.schemas).length} schemas`);
|
|
1328
1336
|
for (const [, schema] of Object.entries(ir.components.schemas)) printObject(schema, 1, "schema");
|
|
1329
1337
|
}
|
|
1330
1338
|
break;
|
|
1331
1339
|
case "paths": {
|
|
1332
1340
|
const paths = ir.paths || {};
|
|
1333
|
-
log(`paths (${Object.keys(paths).length} items):`);
|
|
1341
|
+
log$1(`paths (${Object.keys(paths).length} items):`);
|
|
1334
1342
|
for (const [path, item] of Object.entries(paths)) printPathItem(path, item);
|
|
1335
1343
|
break;
|
|
1336
1344
|
}
|
|
1337
1345
|
case "servers": break;
|
|
1338
1346
|
case "webhooks": {
|
|
1339
1347
|
const webhooks = ir.webhooks || {};
|
|
1340
|
-
log(`webhooks (${Object.keys(webhooks).length} items):`);
|
|
1348
|
+
log$1(`webhooks (${Object.keys(webhooks).length} items):`);
|
|
1341
1349
|
for (const [path, item] of Object.entries(webhooks)) printPathItem(path, item);
|
|
1342
1350
|
break;
|
|
1343
1351
|
}
|
|
@@ -1540,24 +1548,38 @@ var MinHeap = class {
|
|
|
1540
1548
|
* added to the graph.
|
|
1541
1549
|
*/
|
|
1542
1550
|
const walkDeclarations = (graph, callback, options) => {
|
|
1543
|
-
const pointers = Array.from(graph.nodes.keys());
|
|
1544
1551
|
if (options?.preferGroups && options.preferGroups.length) {
|
|
1545
|
-
const
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
if (
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
+
const preferGroupsSet = new Set(options.preferGroups);
|
|
1553
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
1554
|
+
const unmatched = [];
|
|
1555
|
+
for (const pointer of graph.nodes.keys()) {
|
|
1556
|
+
if (options.matchPointerToGroup) {
|
|
1557
|
+
const result = options.matchPointerToGroup(pointer);
|
|
1558
|
+
if (result.matched) {
|
|
1559
|
+
if (preferGroupsSet.has(result.kind)) {
|
|
1560
|
+
let bucket = buckets.get(result.kind);
|
|
1561
|
+
if (!bucket) {
|
|
1562
|
+
bucket = [];
|
|
1563
|
+
buckets.set(result.kind, bucket);
|
|
1564
|
+
}
|
|
1565
|
+
bucket.push(pointer);
|
|
1566
|
+
} else unmatched.push(pointer);
|
|
1567
|
+
continue;
|
|
1568
|
+
}
|
|
1552
1569
|
}
|
|
1570
|
+
unmatched.push(pointer);
|
|
1553
1571
|
}
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1572
|
+
const emittedGroups = /* @__PURE__ */ new Set();
|
|
1573
|
+
for (const kind of options.preferGroups) {
|
|
1574
|
+
if (emittedGroups.has(kind)) continue;
|
|
1575
|
+
emittedGroups.add(kind);
|
|
1576
|
+
const pointers = buckets.get(kind);
|
|
1577
|
+
if (pointers) for (const pointer of pointers) callback(pointer, graph.nodes.get(pointer));
|
|
1557
1578
|
}
|
|
1579
|
+
for (const pointer of unmatched) callback(pointer, graph.nodes.get(pointer));
|
|
1558
1580
|
return;
|
|
1559
1581
|
}
|
|
1560
|
-
for (const pointer of
|
|
1582
|
+
for (const [pointer, node] of graph.nodes) callback(pointer, node);
|
|
1561
1583
|
};
|
|
1562
1584
|
/**
|
|
1563
1585
|
* Walks the nodes of the graph in topological order (dependencies before dependents).
|
|
@@ -1569,36 +1591,32 @@ const walkDeclarations = (graph, callback, options) => {
|
|
|
1569
1591
|
*/
|
|
1570
1592
|
const walkTopological = (graph, callback, options) => {
|
|
1571
1593
|
const pointers = Array.from(graph.nodes.keys());
|
|
1572
|
-
const baseIndex = /* @__PURE__ */ new Map();
|
|
1573
|
-
pointers.forEach((pointer, index) => baseIndex.set(pointer, index));
|
|
1574
1594
|
const declIndex = /* @__PURE__ */ new Map();
|
|
1575
|
-
for (const pointer of pointers) {
|
|
1576
|
-
const composite = (options?.getPointerPriority?.(pointer) ?? 10) * 1e6 + (baseIndex.get(pointer) ?? 0);
|
|
1577
|
-
declIndex.set(pointer, composite);
|
|
1578
|
-
}
|
|
1579
1595
|
const depsOf = /* @__PURE__ */ new Map();
|
|
1580
|
-
|
|
1596
|
+
const inDegree = /* @__PURE__ */ new Map();
|
|
1597
|
+
const dependents = /* @__PURE__ */ new Map();
|
|
1598
|
+
const heap = new MinHeap(declIndex);
|
|
1599
|
+
pointers.forEach((pointer, index) => {
|
|
1600
|
+
const priority = options?.getPointerPriority?.(pointer) ?? 10;
|
|
1601
|
+
declIndex.set(pointer, priority * 1e6 + index);
|
|
1581
1602
|
const raw = graph.subtreeDependencies?.get(pointer) ?? /* @__PURE__ */ new Set();
|
|
1582
|
-
const
|
|
1603
|
+
const deps = /* @__PURE__ */ new Set();
|
|
1583
1604
|
for (const rawPointer of raw) {
|
|
1584
1605
|
if (rawPointer === pointer) continue;
|
|
1585
|
-
if (graph.nodes.has(rawPointer))
|
|
1606
|
+
if (graph.nodes.has(rawPointer)) deps.add(rawPointer);
|
|
1586
1607
|
}
|
|
1587
|
-
depsOf.set(pointer,
|
|
1588
|
-
}
|
|
1589
|
-
const inDegree = /* @__PURE__ */ new Map();
|
|
1590
|
-
const dependents = /* @__PURE__ */ new Map();
|
|
1591
|
-
for (const pointer of pointers) inDegree.set(pointer, 0);
|
|
1592
|
-
for (const [pointer, deps] of depsOf) {
|
|
1608
|
+
depsOf.set(pointer, deps);
|
|
1593
1609
|
inDegree.set(pointer, deps.size);
|
|
1594
1610
|
for (const d of deps) {
|
|
1595
|
-
|
|
1596
|
-
|
|
1611
|
+
let dep = dependents.get(d);
|
|
1612
|
+
if (!dep) {
|
|
1613
|
+
dep = /* @__PURE__ */ new Set();
|
|
1614
|
+
dependents.set(d, dep);
|
|
1615
|
+
}
|
|
1616
|
+
dep.add(pointer);
|
|
1597
1617
|
}
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
const heap = new MinHeap(declIndex);
|
|
1601
|
-
for (const pointer of pointers) if ((inDegree.get(pointer) ?? 0) === 0) heap.push(pointer);
|
|
1618
|
+
if (deps.size === 0) heap.push(pointer);
|
|
1619
|
+
});
|
|
1602
1620
|
const emitted = /* @__PURE__ */ new Set();
|
|
1603
1621
|
const order = [];
|
|
1604
1622
|
while (!heap.isEmpty()) {
|
|
@@ -1615,7 +1633,7 @@ const walkTopological = (graph, callback, options) => {
|
|
|
1615
1633
|
}
|
|
1616
1634
|
}
|
|
1617
1635
|
const remaining = pointers.filter((pointer) => !emitted.has(pointer));
|
|
1618
|
-
|
|
1636
|
+
remaining.sort((a, b) => declIndex.get(a) - declIndex.get(b));
|
|
1619
1637
|
for (const pointer of remaining) {
|
|
1620
1638
|
emitted.add(pointer);
|
|
1621
1639
|
order.push(pointer);
|
|
@@ -1634,16 +1652,27 @@ const walkTopological = (graph, callback, options) => {
|
|
|
1634
1652
|
}
|
|
1635
1653
|
return options.preferGroups.length;
|
|
1636
1654
|
};
|
|
1655
|
+
const orderIndex = /* @__PURE__ */ new Map();
|
|
1656
|
+
for (let i = 0; i < order.length; i++) orderIndex.set(order[i], i);
|
|
1657
|
+
const groupCache = /* @__PURE__ */ new Map();
|
|
1658
|
+
const getCachedGroup = (pointer) => {
|
|
1659
|
+
let g = groupCache.get(pointer);
|
|
1660
|
+
if (g === void 0) {
|
|
1661
|
+
g = getGroup(pointer);
|
|
1662
|
+
groupCache.set(pointer, g);
|
|
1663
|
+
}
|
|
1664
|
+
return g;
|
|
1665
|
+
};
|
|
1637
1666
|
const proposed = [...order].sort((a, b) => {
|
|
1638
|
-
const ga =
|
|
1639
|
-
const gb =
|
|
1640
|
-
return ga !== gb ? ga - gb :
|
|
1667
|
+
const ga = getCachedGroup(a);
|
|
1668
|
+
const gb = getCachedGroup(b);
|
|
1669
|
+
return ga !== gb ? ga - gb : orderIndex.get(a) - orderIndex.get(b);
|
|
1641
1670
|
});
|
|
1642
1671
|
const proposedIndex = /* @__PURE__ */ new Map();
|
|
1643
1672
|
for (let i = 0; i < proposed.length; i++) proposedIndex.set(proposed[i], i);
|
|
1644
1673
|
if (!(() => {
|
|
1645
1674
|
for (const [node, deps] of depsOf) for (const dep of deps) {
|
|
1646
|
-
if (
|
|
1675
|
+
if (getCachedGroup(dep) <= getCachedGroup(node)) continue;
|
|
1647
1676
|
if (proposedIndex.get(dep) >= proposedIndex.get(node)) return true;
|
|
1648
1677
|
}
|
|
1649
1678
|
return false;
|
|
@@ -1719,15 +1748,12 @@ const getIrPointerPriority = (pointer) => {
|
|
|
1719
1748
|
};
|
|
1720
1749
|
//#endregion
|
|
1721
1750
|
//#region src/utils/ref.ts
|
|
1722
|
-
const jsonPointerSlash = /~1/g;
|
|
1723
|
-
const jsonPointerTilde = /~0/g;
|
|
1724
1751
|
/**
|
|
1725
1752
|
* Returns the reusable component name from `$ref`.
|
|
1726
1753
|
*/
|
|
1727
1754
|
function refToName($ref) {
|
|
1728
1755
|
const path = jsonPointerToPath($ref);
|
|
1729
|
-
|
|
1730
|
-
return decodeURI(name);
|
|
1756
|
+
return path[path.length - 1];
|
|
1731
1757
|
}
|
|
1732
1758
|
/**
|
|
1733
1759
|
* Encodes a path segment for use in a JSON Pointer (RFC 6901).
|
|
@@ -1742,7 +1768,7 @@ function refToName($ref) {
|
|
|
1742
1768
|
* @returns The encoded segment as a string.
|
|
1743
1769
|
*/
|
|
1744
1770
|
function encodeJsonPointerSegment(segment) {
|
|
1745
|
-
return String(segment).
|
|
1771
|
+
return String(segment).replaceAll("~", "~0").replaceAll("/", "~1");
|
|
1746
1772
|
}
|
|
1747
1773
|
/**
|
|
1748
1774
|
* Converts a JSON Pointer string (RFC 6901) to an array of path segments.
|
|
@@ -1760,7 +1786,7 @@ function jsonPointerToPath(pointer) {
|
|
|
1760
1786
|
if (clean.startsWith("#")) clean = clean.slice(1);
|
|
1761
1787
|
if (clean.startsWith("/")) clean = clean.slice(1);
|
|
1762
1788
|
if (!clean) return [];
|
|
1763
|
-
return clean.split("/").map((part) => part.
|
|
1789
|
+
return clean.split("/").map((part) => part.replaceAll("~1", "/").replaceAll("~0", "~"));
|
|
1764
1790
|
}
|
|
1765
1791
|
/**
|
|
1766
1792
|
* Normalizes a JSON Pointer string to a canonical form.
|
|
@@ -1810,7 +1836,7 @@ function isTopLevelComponent(refOrPath) {
|
|
|
1810
1836
|
return false;
|
|
1811
1837
|
}
|
|
1812
1838
|
function resolveRef({ $ref, spec }) {
|
|
1813
|
-
const path = jsonPointerToPath(
|
|
1839
|
+
const path = jsonPointerToPath($ref);
|
|
1814
1840
|
let current = spec;
|
|
1815
1841
|
for (const part of path) {
|
|
1816
1842
|
const segment = part;
|
|
@@ -2576,7 +2602,11 @@ function collectOperations({ filters, parameters, requestBodies, resourceMetadat
|
|
|
2576
2602
|
case "body": return !requestBodies.has(dependency);
|
|
2577
2603
|
case "parameter": return !parameters.has(dependency);
|
|
2578
2604
|
case "response": return !responses.has(dependency);
|
|
2579
|
-
case "schema":
|
|
2605
|
+
case "schema":
|
|
2606
|
+
if (schemas.has(dependency)) return false;
|
|
2607
|
+
if (filters.schemas.exclude.has(dependency)) return true;
|
|
2608
|
+
schemas.add(dependency);
|
|
2609
|
+
return false;
|
|
2580
2610
|
default: return false;
|
|
2581
2611
|
}
|
|
2582
2612
|
})) continue;
|
|
@@ -3261,24 +3291,25 @@ const propertiesRequiredByDefaultTransform = ({ spec }) => {
|
|
|
3261
3291
|
*/
|
|
3262
3292
|
const deepEqual = (a, b) => {
|
|
3263
3293
|
if (a === b) return true;
|
|
3264
|
-
if (a
|
|
3265
|
-
|
|
3266
|
-
if (
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
if (
|
|
3271
|
-
|
|
3294
|
+
if (!a || !b || typeof a !== "object" || typeof b !== "object") return false;
|
|
3295
|
+
if (a.constructor !== b.constructor) return false;
|
|
3296
|
+
if (Array.isArray(a)) {
|
|
3297
|
+
const arrA = a;
|
|
3298
|
+
const arrB = b;
|
|
3299
|
+
let len = arrA.length;
|
|
3300
|
+
if (len !== arrB.length) return false;
|
|
3301
|
+
while (len--) if (!deepEqual(arrA[len], arrB[len])) return false;
|
|
3272
3302
|
return true;
|
|
3273
3303
|
}
|
|
3274
3304
|
const objA = a;
|
|
3275
3305
|
const objB = b;
|
|
3276
|
-
|
|
3277
|
-
const
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3306
|
+
let len = 0;
|
|
3307
|
+
for (const key in objA) if (Object.hasOwn(objA, key)) {
|
|
3308
|
+
++len;
|
|
3309
|
+
if (!Object.hasOwn(objB, key)) return false;
|
|
3310
|
+
if (!deepEqual(objA[key], objB[key])) return false;
|
|
3311
|
+
}
|
|
3312
|
+
return Object.keys(objB).length === len;
|
|
3282
3313
|
};
|
|
3283
3314
|
//#endregion
|
|
3284
3315
|
//#region src/openApi/shared/utils/graph.ts
|
|
@@ -3356,85 +3387,35 @@ const collectPointerDependencies = ({ cache, graph, pointer, visited }) => {
|
|
|
3356
3387
|
};
|
|
3357
3388
|
};
|
|
3358
3389
|
/**
|
|
3359
|
-
* Propagates scopes through the graph using a
|
|
3360
|
-
*
|
|
3361
|
-
*
|
|
3390
|
+
* Propagates scopes through the graph using a multi-pass linear scan.
|
|
3391
|
+
*
|
|
3392
|
+
* Nodes are visited in reverse DFS-pre-order (bottom-up): children tend to
|
|
3393
|
+
* appear before their parents so each node can push its scopes to its parent
|
|
3394
|
+
* within the same pass. For typical OpenAPI specs (components declared after
|
|
3395
|
+
* paths) $ref targets also appear before $ref sources in this order, meaning
|
|
3396
|
+
* both tree propagation and $ref propagation usually converge in a single pass.
|
|
3362
3397
|
*
|
|
3363
|
-
*
|
|
3364
|
-
*
|
|
3365
|
-
*
|
|
3366
|
-
*
|
|
3398
|
+
* The outer `while (changed)` loop guarantees correctness for any ordering:
|
|
3399
|
+
* it re-runs until no new scope values were added anywhere. Because scopes
|
|
3400
|
+
* can only grow (at most 3 values: 'normal', 'read', 'write'), the loop
|
|
3401
|
+
* terminates in at most a handful of passes even for pathological specs.
|
|
3367
3402
|
*
|
|
3368
|
-
* @param graph - The Graph structure containing nodes
|
|
3403
|
+
* @param graph - The Graph structure containing nodes and dependencies.
|
|
3369
3404
|
*/
|
|
3370
3405
|
const propagateScopes = (graph) => {
|
|
3371
|
-
const
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
* @param nodeInfo - The NodeInfo of the node
|
|
3381
|
-
* @param childPointer - (Optional) The pointer of the child, used to detect combinator parents
|
|
3382
|
-
*/
|
|
3383
|
-
const notifyAllDependents = (pointer, nodeInfo, childPointer) => {
|
|
3384
|
-
if (nodeInfo.parentPointer) worklist.add(nodeInfo.parentPointer);
|
|
3385
|
-
const reverseNodeDependencies = graph.reverseNodeDependencies.get(pointer);
|
|
3386
|
-
if (reverseNodeDependencies) for (const dependentPointer of reverseNodeDependencies) worklist.add(dependentPointer);
|
|
3387
|
-
if (childPointer) {
|
|
3388
|
-
const combinatorChildMatch = childPointer.match(/(.*)\/(allOf|anyOf|oneOf)\/\d+$/);
|
|
3389
|
-
if (combinatorChildMatch) {
|
|
3390
|
-
const combinatorParentPointer = combinatorChildMatch[1];
|
|
3391
|
-
if (combinatorParentPointer) worklist.add(combinatorParentPointer);
|
|
3392
|
-
}
|
|
3393
|
-
}
|
|
3394
|
-
};
|
|
3395
|
-
/**
|
|
3396
|
-
* Propagates scopes from a child node to its parent node.
|
|
3397
|
-
* If the parent's scopes change, notifies all dependents.
|
|
3398
|
-
*
|
|
3399
|
-
* @param pointer - The parent node's pointer
|
|
3400
|
-
* @param nodeInfo - The parent node's NodeInfo
|
|
3401
|
-
* @param childPointer - The child node's pointer
|
|
3402
|
-
*/
|
|
3403
|
-
const propagateChildScopes = (pointer, nodeInfo, childPointer) => {
|
|
3404
|
-
if (!nodeInfo?.scopes) return;
|
|
3405
|
-
const childInfo = graph.nodes.get(childPointer);
|
|
3406
|
-
if (!childInfo?.scopes) return;
|
|
3407
|
-
if (propagateScopesToNode(childInfo, nodeInfo)) notifyAllDependents(pointer, nodeInfo, childPointer);
|
|
3408
|
-
};
|
|
3409
|
-
while (worklist.size > 0) {
|
|
3410
|
-
const pointer = worklist.values().next().value;
|
|
3411
|
-
worklist.delete(pointer);
|
|
3412
|
-
const nodeInfo = graph.nodes.get(pointer);
|
|
3413
|
-
if (!nodeInfo) continue;
|
|
3414
|
-
if (!nodeInfo.scopes) nodeInfo.scopes = /* @__PURE__ */ new Set();
|
|
3415
|
-
const node = nodeInfo.node;
|
|
3416
|
-
for (const [keyword, type] of childSchemaRelationships) {
|
|
3417
|
-
if (!node || typeof node !== "object" || !(keyword in node)) continue;
|
|
3418
|
-
const value = node[keyword];
|
|
3419
|
-
if (type === "array" && value instanceof Array) for (let index = 0; index < value.length; index++) propagateChildScopes(pointer, nodeInfo, `${pointer}/${keyword}/${index}`);
|
|
3420
|
-
else if (type === "objectMap" && typeof value === "object" && value !== null && !(value instanceof Array)) for (const key of Object.keys(value)) propagateChildScopes(pointer, nodeInfo, `${pointer}/${keyword}/${key}`);
|
|
3421
|
-
else if (type === "single" && typeof value === "object" && value !== null) propagateChildScopes(pointer, nodeInfo, `${pointer}/${keyword}`);
|
|
3422
|
-
else if (type === "singleOrArray") {
|
|
3423
|
-
if (value instanceof Array) for (let index = 0; index < value.length; index++) propagateChildScopes(pointer, nodeInfo, `${pointer}/${keyword}/${index}`);
|
|
3424
|
-
else if (typeof value === "object" && value !== null) propagateChildScopes(pointer, nodeInfo, `${pointer}/${keyword}`);
|
|
3406
|
+
const nodesBottomUp = [...graph.nodes].reverse();
|
|
3407
|
+
let changed = true;
|
|
3408
|
+
while (changed) {
|
|
3409
|
+
changed = false;
|
|
3410
|
+
for (const [pointer, nodeInfo] of nodesBottomUp) {
|
|
3411
|
+
const nodeDeps = graph.nodeDependencies.get(pointer);
|
|
3412
|
+
if (nodeDeps) for (const depPointer of nodeDeps) {
|
|
3413
|
+
const depInfo = graph.nodes.get(depPointer);
|
|
3414
|
+
if (depInfo?.scopes && propagateScopesToNode(depInfo, nodeInfo)) changed = true;
|
|
3425
3415
|
}
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
const depNode = graph.nodes.get(depPointer);
|
|
3430
|
-
if (depNode?.scopes) {
|
|
3431
|
-
if (propagateScopesToNode(depNode, nodeInfo)) notifyAllDependents(pointer, nodeInfo);
|
|
3432
|
-
}
|
|
3433
|
-
}
|
|
3434
|
-
if (nodeInfo.parentPointer) {
|
|
3435
|
-
const parentInfo = graph.nodes.get(nodeInfo.parentPointer);
|
|
3436
|
-
if (parentInfo) {
|
|
3437
|
-
if (propagateScopesToNode(nodeInfo, parentInfo)) notifyAllDependents(nodeInfo.parentPointer, parentInfo);
|
|
3416
|
+
if (nodeInfo.scopes && nodeInfo.parentPointer) {
|
|
3417
|
+
const parentInfo = graph.nodes.get(nodeInfo.parentPointer);
|
|
3418
|
+
if (parentInfo && propagateScopesToNode(nodeInfo, parentInfo)) changed = true;
|
|
3438
3419
|
}
|
|
3439
3420
|
}
|
|
3440
3421
|
}
|
|
@@ -3459,52 +3440,29 @@ const propagateScopesToNode = (fromNodeInfo, toNodeInfo) => {
|
|
|
3459
3440
|
return changed;
|
|
3460
3441
|
};
|
|
3461
3442
|
/**
|
|
3462
|
-
* Seeds each node in the graph with its local access scope(s) based on its own properties.
|
|
3463
|
-
* - 'read' if readOnly: true
|
|
3464
|
-
* - 'write' if writeOnly: true
|
|
3465
|
-
* - 'normal' if node is an object property
|
|
3466
|
-
*
|
|
3467
|
-
* Only non-array objects are considered for scope seeding.
|
|
3468
|
-
*
|
|
3469
|
-
* @param nodes - Map of JSON Pointer to NodeInfo.
|
|
3470
|
-
*/
|
|
3471
|
-
const seedLocalScopes = (nodes) => {
|
|
3472
|
-
for (const [pointer, nodeInfo] of nodes) {
|
|
3473
|
-
const { node } = nodeInfo;
|
|
3474
|
-
if (typeof node !== "object" || node === null || node instanceof Array) continue;
|
|
3475
|
-
if ("readOnly" in node && node.readOnly === true) nodeInfo.scopes = new Set(["read"]);
|
|
3476
|
-
else if ("writeOnly" in node && node.writeOnly === true) nodeInfo.scopes = new Set(["write"]);
|
|
3477
|
-
else if (pointer.match(/\/properties\/[^/]+$/)) nodeInfo.scopes = new Set(["normal"]);
|
|
3478
|
-
}
|
|
3479
|
-
};
|
|
3480
|
-
/**
|
|
3481
3443
|
* Builds a graph of all nodes in an OpenAPI spec, indexed by normalized JSON Pointer,
|
|
3482
3444
|
* and tracks all $ref dependencies and reverse dependencies between nodes.
|
|
3483
3445
|
*
|
|
3484
3446
|
* - All keys in the returned maps are normalized JSON Pointers (RFC 6901, always starting with '#').
|
|
3485
3447
|
* - The `nodes` map allows fast lookup of any node and its parent/key context.
|
|
3486
3448
|
* - The `dependencies` map records, for each node, the set of normalized pointers it references via $ref.
|
|
3487
|
-
* - The `reverseNodeDependencies` map records, for each node, the set of nodes that reference it via $ref.
|
|
3488
3449
|
* - After construction, all nodes will have their local and propagated scopes annotated.
|
|
3489
3450
|
*
|
|
3490
3451
|
* @param root The root object (e.g., the OpenAPI spec)
|
|
3491
3452
|
* @returns An object with:
|
|
3492
3453
|
* - nodes: Map from normalized JSON Pointer string to NodeInfo
|
|
3493
3454
|
* - dependencies: Map from normalized JSON Pointer string to Set of referenced normalized JSON Pointers
|
|
3494
|
-
* - reverseNodeDependencies: Map from normalized JSON Pointer string to Set of referencing normalized JSON Pointers
|
|
3495
3455
|
*/
|
|
3496
3456
|
function buildGraph(root, logger) {
|
|
3497
3457
|
const eventBuildGraph = logger.timeEvent("build-graph");
|
|
3498
3458
|
const graph = {
|
|
3499
3459
|
nodeDependencies: /* @__PURE__ */ new Map(),
|
|
3500
3460
|
nodes: /* @__PURE__ */ new Map(),
|
|
3501
|
-
reverseNodeDependencies: /* @__PURE__ */ new Map(),
|
|
3502
3461
|
subtreeDependencies: /* @__PURE__ */ new Map(),
|
|
3503
3462
|
transitiveDependencies: /* @__PURE__ */ new Map()
|
|
3504
3463
|
};
|
|
3505
|
-
const walk = ({ key, node, parentPointer,
|
|
3464
|
+
const walk = ({ key, node, parentPointer, pointer }) => {
|
|
3506
3465
|
if (typeof node !== "object" || node === null) return;
|
|
3507
|
-
const pointer = pathToJsonPointer(path);
|
|
3508
3466
|
let deprecated;
|
|
3509
3467
|
let tags;
|
|
3510
3468
|
if (typeof node === "object" && node !== null) {
|
|
@@ -3514,7 +3472,7 @@ function buildGraph(root, logger) {
|
|
|
3514
3472
|
if (!graph.nodeDependencies.has(pointer)) graph.nodeDependencies.set(pointer, /* @__PURE__ */ new Set());
|
|
3515
3473
|
graph.nodeDependencies.get(pointer).add(refPointer);
|
|
3516
3474
|
}
|
|
3517
|
-
if ("tags" in node && node.tags
|
|
3475
|
+
if ("tags" in node && Array.isArray(node.tags)) tags = new Set(node.tags.filter((tag) => typeof tag === "string"));
|
|
3518
3476
|
}
|
|
3519
3477
|
graph.nodes.set(pointer, {
|
|
3520
3478
|
deprecated,
|
|
@@ -3523,24 +3481,24 @@ function buildGraph(root, logger) {
|
|
|
3523
3481
|
parentPointer,
|
|
3524
3482
|
tags
|
|
3525
3483
|
});
|
|
3526
|
-
if (node
|
|
3484
|
+
if (Array.isArray(node)) node.forEach((item, index) => walk({
|
|
3527
3485
|
key: index,
|
|
3528
3486
|
node: item,
|
|
3529
3487
|
parentPointer: pointer,
|
|
3530
|
-
|
|
3488
|
+
pointer: pointer + "/" + encodeJsonPointerSegment(index)
|
|
3531
3489
|
}));
|
|
3532
3490
|
else for (const [childKey, value] of Object.entries(node)) walk({
|
|
3533
3491
|
key: childKey,
|
|
3534
3492
|
node: value,
|
|
3535
3493
|
parentPointer: pointer,
|
|
3536
|
-
|
|
3494
|
+
pointer: pointer + "/" + encodeJsonPointerSegment(childKey)
|
|
3537
3495
|
});
|
|
3538
3496
|
};
|
|
3539
3497
|
walk({
|
|
3540
3498
|
key: null,
|
|
3541
3499
|
node: root,
|
|
3542
3500
|
parentPointer: null,
|
|
3543
|
-
|
|
3501
|
+
pointer: "#"
|
|
3544
3502
|
});
|
|
3545
3503
|
const cache = {
|
|
3546
3504
|
parentToChildren: /* @__PURE__ */ new Map(),
|
|
@@ -3549,15 +3507,25 @@ function buildGraph(root, logger) {
|
|
|
3549
3507
|
};
|
|
3550
3508
|
for (const [pointer, nodeInfo] of graph.nodes) {
|
|
3551
3509
|
const parent = nodeInfo.parentPointer;
|
|
3552
|
-
if (
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3510
|
+
if (parent) {
|
|
3511
|
+
let arr = cache.parentToChildren.get(parent);
|
|
3512
|
+
if (!arr) {
|
|
3513
|
+
arr = [];
|
|
3514
|
+
cache.parentToChildren.set(parent, arr);
|
|
3515
|
+
}
|
|
3516
|
+
arr.push(pointer);
|
|
3517
|
+
}
|
|
3518
|
+
const { node } = nodeInfo;
|
|
3519
|
+
if (typeof node === "object" && node !== null && !Array.isArray(node)) if ("readOnly" in node && node.readOnly === true) nodeInfo.scopes = new Set(["read"]);
|
|
3520
|
+
else if ("writeOnly" in node && node.writeOnly === true) nodeInfo.scopes = new Set(["write"]);
|
|
3521
|
+
else {
|
|
3522
|
+
const lastSlash = pointer.lastIndexOf("/");
|
|
3523
|
+
if (lastSlash > 0) {
|
|
3524
|
+
const prevSlash = pointer.lastIndexOf("/", lastSlash - 1);
|
|
3525
|
+
if (prevSlash >= 0 && pointer.slice(prevSlash + 1, lastSlash) === "properties") nodeInfo.scopes = new Set(["normal"]);
|
|
3526
|
+
}
|
|
3527
|
+
}
|
|
3559
3528
|
}
|
|
3560
|
-
seedLocalScopes(graph.nodes);
|
|
3561
3529
|
propagateScopes(graph);
|
|
3562
3530
|
annotateChildScopes(graph.nodes);
|
|
3563
3531
|
for (const pointer of graph.nodes.keys()) {
|
|
@@ -4616,7 +4584,7 @@ function parseRef$2({ context, schema, state }) {
|
|
|
4616
4584
|
return irSchema;
|
|
4617
4585
|
}
|
|
4618
4586
|
}
|
|
4619
|
-
irSchema.$ref =
|
|
4587
|
+
irSchema.$ref = schema.$ref;
|
|
4620
4588
|
irSchema.$ref = irSchema.$ref.replace(/#\/definitions\/([^/]+)/g, "#/components/schemas/$1");
|
|
4621
4589
|
if (!state.circularReferenceTracker.has(schema.$ref)) {
|
|
4622
4590
|
const refSchema = context.resolveRef(schema.$ref);
|
|
@@ -5872,6 +5840,7 @@ function parseAnyOf$1({ context, schema, state }) {
|
|
|
5872
5840
|
logicalOperator: "and"
|
|
5873
5841
|
};
|
|
5874
5842
|
}
|
|
5843
|
+
if (schema.discriminator && irSchema.logicalOperator === "or") irSchema.discriminator = { propertyName: schema.discriminator.propertyName };
|
|
5875
5844
|
return irSchema;
|
|
5876
5845
|
}
|
|
5877
5846
|
function parseEnum$1({ context, schema, state }) {
|
|
@@ -5964,6 +5933,7 @@ function parseOneOf$1({ context, schema, state }) {
|
|
|
5964
5933
|
logicalOperator: "and"
|
|
5965
5934
|
};
|
|
5966
5935
|
}
|
|
5936
|
+
if (schema.discriminator && irSchema.logicalOperator === "or") irSchema.discriminator = { propertyName: schema.discriminator.propertyName };
|
|
5967
5937
|
return irSchema;
|
|
5968
5938
|
}
|
|
5969
5939
|
function parseRef$1({ context, schema, state }) {
|
|
@@ -5982,7 +5952,7 @@ function parseRef$1({ context, schema, state }) {
|
|
|
5982
5952
|
}
|
|
5983
5953
|
}
|
|
5984
5954
|
const irSchema = {};
|
|
5985
|
-
irSchema.$ref =
|
|
5955
|
+
irSchema.$ref = schema.$ref;
|
|
5986
5956
|
if (!state.circularReferenceTracker.has(schema.$ref)) {
|
|
5987
5957
|
const refSchema = context.resolveRef(schema.$ref);
|
|
5988
5958
|
const originalRef = state.$ref;
|
|
@@ -7264,6 +7234,7 @@ function parseAnyOf({ context, schema, state }) {
|
|
|
7264
7234
|
logicalOperator: "and"
|
|
7265
7235
|
};
|
|
7266
7236
|
}
|
|
7237
|
+
if (schema.discriminator && irSchema.logicalOperator === "or") irSchema.discriminator = { propertyName: schema.discriminator.propertyName };
|
|
7267
7238
|
return irSchema;
|
|
7268
7239
|
}
|
|
7269
7240
|
function parseEnum({ context, schema, state }) {
|
|
@@ -7359,6 +7330,7 @@ function parseOneOf({ context, schema, state }) {
|
|
|
7359
7330
|
logicalOperator: "and"
|
|
7360
7331
|
};
|
|
7361
7332
|
}
|
|
7333
|
+
if (schema.discriminator && irSchema.logicalOperator === "or") irSchema.discriminator = { propertyName: schema.discriminator.propertyName };
|
|
7362
7334
|
return irSchema;
|
|
7363
7335
|
}
|
|
7364
7336
|
function parseRef({ context, schema, state }) {
|
|
@@ -7382,7 +7354,7 @@ function parseRef({ context, schema, state }) {
|
|
|
7382
7354
|
schema
|
|
7383
7355
|
});
|
|
7384
7356
|
const irRefSchema = {};
|
|
7385
|
-
irRefSchema.$ref =
|
|
7357
|
+
irRefSchema.$ref = schema.$ref;
|
|
7386
7358
|
if (!state.circularReferenceTracker.has(schema.$ref)) {
|
|
7387
7359
|
const refSchema = context.resolveRef(schema.$ref);
|
|
7388
7360
|
const originalRef = state.$ref;
|
|
@@ -8508,6 +8480,36 @@ async function patchOpenApiSpec({ patchOptions, spec: _spec }) {
|
|
|
8508
8480
|
}
|
|
8509
8481
|
}
|
|
8510
8482
|
//#endregion
|
|
8483
|
+
//#region src/plugins/duplicate.ts
|
|
8484
|
+
function stableStringify(value) {
|
|
8485
|
+
return JSON.stringify(value, (_, v) => {
|
|
8486
|
+
if (typeof v === "function") return `[function:${v.toString()}]`;
|
|
8487
|
+
if (v && typeof v === "object" && !Array.isArray(v)) return Object.fromEntries(Object.entries(v).sort(([a], [b]) => a.localeCompare(b)));
|
|
8488
|
+
return v;
|
|
8489
|
+
});
|
|
8490
|
+
}
|
|
8491
|
+
function normalizePluginEntry(plugin) {
|
|
8492
|
+
if (typeof plugin === "string") return {
|
|
8493
|
+
name: plugin,
|
|
8494
|
+
serialized: "{}"
|
|
8495
|
+
};
|
|
8496
|
+
const { name, ...config } = plugin;
|
|
8497
|
+
return {
|
|
8498
|
+
name,
|
|
8499
|
+
serialized: stableStringify(config)
|
|
8500
|
+
};
|
|
8501
|
+
}
|
|
8502
|
+
function warnOnConflictingDuplicatePlugins(plugins) {
|
|
8503
|
+
const seen = /* @__PURE__ */ new Map();
|
|
8504
|
+
for (const plugin of plugins) {
|
|
8505
|
+
const { name, serialized } = normalizePluginEntry(plugin);
|
|
8506
|
+
if (!name) continue;
|
|
8507
|
+
const previous = seen.get(name);
|
|
8508
|
+
if (previous !== void 0 && previous !== serialized) log.warn(`Plugin "${name}" is configured multiple times. Only the last instance will take effect.`);
|
|
8509
|
+
seen.set(name, serialized);
|
|
8510
|
+
}
|
|
8511
|
+
}
|
|
8512
|
+
//#endregion
|
|
8511
8513
|
//#region src/plugins/shared/utils/config.ts
|
|
8512
8514
|
const definePluginConfig = (defaultConfig) => (userConfig) => ({
|
|
8513
8515
|
...defaultConfig,
|
|
@@ -8711,9 +8713,9 @@ function pathToName(path, options) {
|
|
|
8711
8713
|
} else if (STRUCTURAL_SUFFIX[segment]) names.push(STRUCTURAL_SUFFIX[segment]);
|
|
8712
8714
|
index++;
|
|
8713
8715
|
}
|
|
8714
|
-
return
|
|
8716
|
+
return names.join("-");
|
|
8715
8717
|
}
|
|
8716
8718
|
//#endregion
|
|
8717
|
-
export { ConfigError, ConfigValidationError, Context, HeyApiError, InputError, IntentContext, JobError, MinHeap, OperationPath, OperationStrategy, PluginInstance, addItemsToSchema, applyNaming, buildGraph, buildSymbolIn, checkNodeVersion, childContext, compileInputPath, createOperationKey, createSchemaProcessor, createSchemaWalker, debugTools, deduplicateSchema, defaultPaginationKeywords, definePluginConfig, dependencyFactory, encodeJsonPointerSegment, ensureDirSync, escapeComment, findPackageJson, findTsConfigPath, getInput, getInputError, getLogs, getParser, getSpec, hasOperationDataRequired, hasParameterGroupObjectRequired, hasParametersObjectRequired, heyApiRegistryBaseUrl, inputToApiRegistry, isEnvironment, isTopLevelComponent, jsonPointerToPath, loadPackageJson, logCrashReport, logInputPaths, mappers, normalizeJsonPointer, openGitHubIssueWithCrashReport, operationPagination, operationResponsesMap, outputHeaderToPrefix, parameterWithPagination, parseOpenApiSpec, parseUrl, parseV2_0_X, parseV3_0_X, parseV3_1_X, patchOpenApiSpec, pathToJsonPointer, pathToName, postprocessOutput, printCliIntro, printCrashReport, refToName, requestValidatorLayers, resolveNaming, resolveRef, resolveSource, resolveValidatorLayer, satisfies, shouldReportCrash, statusCodeToGroup, toCase, utils, valueToObject };
|
|
8719
|
+
export { ConfigError, ConfigValidationError, Context, HeyApiError, InputError, IntentContext, JobError, MinHeap, OperationPath, OperationStrategy, PluginInstance, addItemsToSchema, applyNaming, buildGraph, buildSymbolIn, checkNodeVersion, childContext, compileInputPath, createOperationKey, createSchemaProcessor, createSchemaWalker, debugTools, deduplicateSchema, defaultPaginationKeywords, definePluginConfig, dependencyFactory, encodeJsonPointerSegment, ensureDirSync, escapeComment, findPackageJson, findTsConfigPath, getInput, getInputError, getLogs, getParser, getSpec, hasOperationDataRequired, hasParameterGroupObjectRequired, hasParametersObjectRequired, heyApiRegistryBaseUrl, inputToApiRegistry, isEnvironment, isTopLevelComponent, jsonPointerToPath, loadPackageJson, logCrashReport, logInputPaths, mappers, normalizeJsonPointer, openGitHubIssueWithCrashReport, operationPagination, operationResponsesMap, outputHeaderToPrefix, parameterWithPagination, parseOpenApiSpec, parseUrl, parseV2_0_X, parseV3_0_X, parseV3_1_X, patchOpenApiSpec, pathToJsonPointer, pathToName, postprocessOutput, printCliIntro, printCrashReport, refToName, requestValidatorLayers, resolveNaming, resolveRef, resolveSource, resolveValidatorLayer, satisfies, shouldReportCrash, statusCodeToGroup, toCase, utils, valueToObject, warnOnConflictingDuplicatePlugins };
|
|
8718
8720
|
|
|
8719
8721
|
//# sourceMappingURL=index.mjs.map
|