@kubb/ast 5.18.7 → 5.19.0
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 +173 -102
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -2
- package/dist/index.d.ts +9 -2
- package/dist/index.js +173 -102
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -46,11 +46,37 @@ let node_crypto = require("node:crypto");
|
|
|
46
46
|
* `const refs = memo(refCache, node, () => collectRefs(node))`
|
|
47
47
|
*/
|
|
48
48
|
function memo(store, key, compute) {
|
|
49
|
-
|
|
49
|
+
const cached = store.get(key);
|
|
50
|
+
if (cached !== void 0 || store.has(key)) return cached;
|
|
50
51
|
const value = compute();
|
|
51
52
|
store.set(key, value);
|
|
52
53
|
return value;
|
|
53
54
|
}
|
|
55
|
+
function createStore({ weak, max } = {}) {
|
|
56
|
+
if (weak) return /* @__PURE__ */ new WeakMap();
|
|
57
|
+
const entry = /* @__PURE__ */ new Map();
|
|
58
|
+
if (max === void 0) return entry;
|
|
59
|
+
const set = (key, value) => {
|
|
60
|
+
if (entry.size >= max) entry.clear();
|
|
61
|
+
entry.set(key, value);
|
|
62
|
+
};
|
|
63
|
+
if (max !== 1) return {
|
|
64
|
+
has: (key) => entry.has(key),
|
|
65
|
+
get: (key) => entry.get(key),
|
|
66
|
+
set
|
|
67
|
+
};
|
|
68
|
+
const touch = (key) => {
|
|
69
|
+
if (!entry.has(key)) return false;
|
|
70
|
+
set(key, entry.get(key));
|
|
71
|
+
return true;
|
|
72
|
+
};
|
|
73
|
+
return {
|
|
74
|
+
has: touch,
|
|
75
|
+
get: (key) => touch(key) ? entry.get(key) : void 0,
|
|
76
|
+
set
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
memo.create = createStore;
|
|
54
80
|
// src/constants.ts
|
|
55
81
|
/**
|
|
56
82
|
* Node kind discriminators used by every AST node (for example `node.kind === nodeKinds.text`).
|
|
@@ -321,14 +347,17 @@ function walkSchema(node, through, visit) {
|
|
|
321
347
|
* ```
|
|
322
348
|
*/
|
|
323
349
|
function getSchemaLiteralValues$1(node) {
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
350
|
+
return memo(literalValues, node, () => {
|
|
351
|
+
const values = /* @__PURE__ */ new Set();
|
|
352
|
+
walkSchema(node, "union", (current) => {
|
|
353
|
+
if (current.type !== "enum") return;
|
|
354
|
+
for (const { value } of current.namedEnumValues ?? current.enumValues?.map((value) => ({ value })) ?? []) values.add(value);
|
|
355
|
+
});
|
|
356
|
+
return Object.freeze([...values]);
|
|
328
357
|
});
|
|
329
|
-
return [...values];
|
|
330
358
|
}
|
|
331
359
|
__name(getSchemaLiteralValues$1, "getSchemaLiteralValues");
|
|
360
|
+
const literalValues = memo.create({ weak: true });
|
|
332
361
|
function collectPropertyNames(node) {
|
|
333
362
|
const names = /* @__PURE__ */ new Set();
|
|
334
363
|
walkSchema(node, "intersection", (current) => {
|
|
@@ -477,24 +506,6 @@ function isNode(value) {
|
|
|
477
506
|
function isNodeRecord(value) {
|
|
478
507
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
479
508
|
}
|
|
480
|
-
/**
|
|
481
|
-
* Returns the immediate traversable children of `node`.
|
|
482
|
-
*
|
|
483
|
-
* @example
|
|
484
|
-
* ```ts
|
|
485
|
-
* const children = getChildren(operationNode, true)
|
|
486
|
-
* // returns parameters, the request body, and responses
|
|
487
|
-
* ```
|
|
488
|
-
*/
|
|
489
|
-
function getChildren(node, recurse) {
|
|
490
|
-
if (node.kind === nodeKinds$1.schema && !recurse) return [];
|
|
491
|
-
const children = [];
|
|
492
|
-
visitChildNodes(node, (child) => {
|
|
493
|
-
children.push(child);
|
|
494
|
-
return false;
|
|
495
|
-
});
|
|
496
|
-
return children;
|
|
497
|
-
}
|
|
498
509
|
function isNeverPrinted({ node, key }) {
|
|
499
510
|
if (node.kind !== nodeKinds$1.schema) return false;
|
|
500
511
|
if (key === "contains" && (node.type === "array" || node.type === "tuple")) return node.contains?.min === 0 && node.contains.max === void 0;
|
|
@@ -502,41 +513,63 @@ function isNeverPrinted({ node, key }) {
|
|
|
502
513
|
return false;
|
|
503
514
|
}
|
|
504
515
|
/**
|
|
516
|
+
* Child keys of a schema walked with `checks: true`: the shape keys, then {@link schemaCheckKeys}.
|
|
517
|
+
*/
|
|
518
|
+
const SCHEMA_CHECK_VISITOR_KEYS = [...VISITOR_KEYS.Schema, ...schemaCheckKeys];
|
|
519
|
+
function visitOnce(child, seen, visit) {
|
|
520
|
+
if (seen.first === void 0) {
|
|
521
|
+
seen.first = child;
|
|
522
|
+
return visit(child);
|
|
523
|
+
}
|
|
524
|
+
if (seen.first === child || seen.rest?.has(child)) return false;
|
|
525
|
+
(seen.rest ??= /* @__PURE__ */ new Set()).add(child);
|
|
526
|
+
return visit(child);
|
|
527
|
+
}
|
|
528
|
+
function visitRecord(value, seen, visit) {
|
|
529
|
+
for (const name in value) {
|
|
530
|
+
if (!Object.hasOwn(value, name)) continue;
|
|
531
|
+
const item = value[name];
|
|
532
|
+
if (isNode(item) && visitOnce(item, seen, visit)) return true;
|
|
533
|
+
}
|
|
534
|
+
return false;
|
|
535
|
+
}
|
|
536
|
+
/**
|
|
505
537
|
* Calls `visit` for each direct child node and stops at the first call that returns `true`.
|
|
506
538
|
* With `checks: true`, a schema's {@link schemaCheckKeys} fields are walked too, except checks that cannot fail.
|
|
507
539
|
*/
|
|
508
540
|
function visitChildNodes(node, visit, { checks = false } = {}) {
|
|
509
|
-
const
|
|
541
|
+
const withChecks = checks && node.kind === nodeKinds$1.schema;
|
|
542
|
+
const keys = withChecks ? SCHEMA_CHECK_VISITOR_KEYS : VISITOR_KEYS[node.kind];
|
|
510
543
|
if (!keys) return false;
|
|
511
544
|
const record = node;
|
|
512
|
-
|
|
513
|
-
const visitOnce = (child) => !seen.has(child) && (seen.add(child), visit(child));
|
|
514
|
-
const visitRecord = (value) => {
|
|
515
|
-
for (const name in value) {
|
|
516
|
-
if (!Object.hasOwn(value, name)) continue;
|
|
517
|
-
const item = value[name];
|
|
518
|
-
if (isNode(item) && visitOnce(item)) return true;
|
|
519
|
-
}
|
|
520
|
-
return false;
|
|
521
|
-
};
|
|
545
|
+
let seen;
|
|
522
546
|
for (const key of keys) {
|
|
523
|
-
|
|
547
|
+
const value = record[key];
|
|
548
|
+
if (value === void 0 || value === null) continue;
|
|
549
|
+
if (withChecks && isNeverPrinted({
|
|
524
550
|
node,
|
|
525
551
|
key
|
|
526
552
|
})) continue;
|
|
527
|
-
|
|
553
|
+
seen ??= {
|
|
554
|
+
first: void 0,
|
|
555
|
+
rest: void 0
|
|
556
|
+
};
|
|
528
557
|
if (Array.isArray(value)) {
|
|
529
|
-
for (const item of value) if (isNode(item) ? visitOnce(item) : isNodeRecord(item) && visitRecord(item)) return true;
|
|
558
|
+
for (const item of value) if (isNode(item) ? visitOnce(item, seen, visit) : isNodeRecord(item) && visitRecord(item, seen, visit)) return true;
|
|
530
559
|
continue;
|
|
531
560
|
}
|
|
532
561
|
if (isNode(value)) {
|
|
533
|
-
if (visitOnce(value)) return true;
|
|
562
|
+
if (visitOnce(value, seen, visit)) return true;
|
|
534
563
|
continue;
|
|
535
564
|
}
|
|
536
|
-
if (isNodeRecord(value) && visitRecord(value)) return true;
|
|
565
|
+
if (isNodeRecord(value) && visitRecord(value, seen, visit)) return true;
|
|
537
566
|
}
|
|
538
567
|
return false;
|
|
539
568
|
}
|
|
569
|
+
const notFound = {
|
|
570
|
+
found: void 0,
|
|
571
|
+
low: Number.POSITIVE_INFINITY
|
|
572
|
+
};
|
|
540
573
|
/**
|
|
541
574
|
* Finds the first schema that matches `predicate` in depth-first order. Set `followRefs` to include resolved ref targets.
|
|
542
575
|
*
|
|
@@ -547,28 +580,68 @@ function visitChildNodes(node, visit, { checks = false } = {}) {
|
|
|
547
580
|
* })
|
|
548
581
|
* ```
|
|
549
582
|
*/
|
|
550
|
-
function findSchema$1(node, { predicate, followRefs = false }) {
|
|
551
|
-
const
|
|
552
|
-
const
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
if (seen.has(current)) return void 0;
|
|
557
|
-
seen.add(current);
|
|
558
|
-
if (current.type === "ref" && current.schema) {
|
|
559
|
-
const found = walk(current.schema);
|
|
560
|
-
if (found) return found;
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
let found;
|
|
583
|
+
function findSchema$1(node, { predicate, followRefs = false, cache }) {
|
|
584
|
+
const state = followRefs ? /* @__PURE__ */ new Map() : void 0;
|
|
585
|
+
const pending = [];
|
|
586
|
+
let order = 0;
|
|
587
|
+
const walkChildren = (current, initial) => {
|
|
588
|
+
let result = initial;
|
|
565
589
|
visitChildNodes(current, (child) => {
|
|
566
|
-
|
|
567
|
-
|
|
590
|
+
const next = walk(child);
|
|
591
|
+
result = next.found || next.low < result.low ? next : result;
|
|
592
|
+
return next.found !== void 0;
|
|
568
593
|
});
|
|
569
|
-
|
|
594
|
+
return result;
|
|
595
|
+
};
|
|
596
|
+
const walkSchema = (current) => {
|
|
597
|
+
const target = state && current.type === "ref" && current.schema ? walk(current.schema) : notFound;
|
|
598
|
+
if (target.found) return target;
|
|
599
|
+
return walkChildren(current, target);
|
|
570
600
|
};
|
|
571
|
-
|
|
601
|
+
const walk = (current) => {
|
|
602
|
+
if (current.kind !== nodeKinds$1.schema) return walkChildren(current, notFound);
|
|
603
|
+
const cached = cache?.get(current);
|
|
604
|
+
if (cached === null) return notFound;
|
|
605
|
+
if (cached) return {
|
|
606
|
+
found: cached,
|
|
607
|
+
low: Number.POSITIVE_INFINITY
|
|
608
|
+
};
|
|
609
|
+
if (predicate(current)) {
|
|
610
|
+
cache?.set(current, current);
|
|
611
|
+
return {
|
|
612
|
+
found: current,
|
|
613
|
+
low: Number.POSITIVE_INFINITY
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
const known = state?.get(current);
|
|
617
|
+
if (known !== void 0) return {
|
|
618
|
+
found: void 0,
|
|
619
|
+
low: known
|
|
620
|
+
};
|
|
621
|
+
const index = order++;
|
|
622
|
+
const start = pending.length;
|
|
623
|
+
state?.set(current, index);
|
|
624
|
+
const result = walkSchema(current);
|
|
625
|
+
if (result.found) {
|
|
626
|
+
cache?.set(current, result.found);
|
|
627
|
+
return result;
|
|
628
|
+
}
|
|
629
|
+
if (!state) {
|
|
630
|
+
cache?.set(current, null);
|
|
631
|
+
return notFound;
|
|
632
|
+
}
|
|
633
|
+
if (result.low < index) {
|
|
634
|
+
state.set(current, result.low);
|
|
635
|
+
pending.push(current);
|
|
636
|
+
return result;
|
|
637
|
+
}
|
|
638
|
+
for (const done of [...pending.splice(start), current]) {
|
|
639
|
+
state.set(done, Number.POSITIVE_INFINITY);
|
|
640
|
+
cache?.set(done, null);
|
|
641
|
+
}
|
|
642
|
+
return notFound;
|
|
643
|
+
};
|
|
644
|
+
return walk(node).found;
|
|
572
645
|
}
|
|
573
646
|
__name(findSchema$1, "findSchema");
|
|
574
647
|
/**
|
|
@@ -632,15 +705,16 @@ function transformChildren(node, visitor, recurse) {
|
|
|
632
705
|
if (!keys) return node;
|
|
633
706
|
const record = node;
|
|
634
707
|
let updates;
|
|
635
|
-
|
|
708
|
+
let done;
|
|
636
709
|
const transformOnce = (child) => {
|
|
710
|
+
done ??= /* @__PURE__ */ new Map();
|
|
637
711
|
const next = done.get(child) ?? transformNode(child, visitor, recurse, node);
|
|
638
712
|
done.set(child, next);
|
|
639
713
|
return next;
|
|
640
714
|
};
|
|
641
715
|
for (const key of keys) {
|
|
642
|
-
if (!(key in record)) continue;
|
|
643
716
|
const value = record[key];
|
|
717
|
+
if (value === void 0 || value === null) continue;
|
|
644
718
|
if (Array.isArray(value)) {
|
|
645
719
|
let mapped;
|
|
646
720
|
for (const [i, item] of value.entries()) {
|
|
@@ -697,7 +771,11 @@ __name(collect$1, "collect");
|
|
|
697
771
|
function collectInto(node, visitor, recurse, parent, result) {
|
|
698
772
|
const v = applyVisitor(node, visitor, parent);
|
|
699
773
|
if (v != null) result.push(v);
|
|
700
|
-
|
|
774
|
+
if (node.kind === nodeKinds$1.schema && !recurse) return;
|
|
775
|
+
visitChildNodes(node, (child) => {
|
|
776
|
+
collectInto(child, visitor, recurse, node, result);
|
|
777
|
+
return false;
|
|
778
|
+
});
|
|
701
779
|
}
|
|
702
780
|
// src/utils/refs.ts
|
|
703
781
|
/**
|
|
@@ -706,21 +784,17 @@ function collectInto(node, visitor, recurse, parent, result) {
|
|
|
706
784
|
* (RFC 6901), so `a~1b~0c` names the component `a/b~c`.
|
|
707
785
|
*/
|
|
708
786
|
function refName$1(ref) {
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
if (refNames.size >= memoLimit) refNames.clear();
|
|
718
|
-
refNames.set(ref, name);
|
|
719
|
-
return name;
|
|
787
|
+
return memo(refNames, ref, () => {
|
|
788
|
+
const segment = ref.split("/").at(-1) ?? ref;
|
|
789
|
+
let decoded = segment;
|
|
790
|
+
try {
|
|
791
|
+
decoded = decodeURIComponent(segment);
|
|
792
|
+
} catch {}
|
|
793
|
+
return decoded.replaceAll("~1", "/").replaceAll("~0", "~");
|
|
794
|
+
});
|
|
720
795
|
}
|
|
721
796
|
__name(refName$1, "refName");
|
|
722
|
-
const refNames =
|
|
723
|
-
const memoLimit = 1e5;
|
|
797
|
+
const refNames = memo.create({ max: 1e5 });
|
|
724
798
|
/**
|
|
725
799
|
* Resolves the emitted name of the schema a ref node points at. Prefers `targetName` (set when
|
|
726
800
|
* the referenced schema was renamed, e.g. to break a collision), then the last segment of `ref`,
|
|
@@ -806,11 +880,11 @@ function isBareRef$1(node, keysToOmit) {
|
|
|
806
880
|
}
|
|
807
881
|
__name(isBareRef$1, "isBareRef");
|
|
808
882
|
// src/utils/schemaGraph.ts
|
|
809
|
-
const refEntries =
|
|
810
|
-
const checkRefEntries =
|
|
811
|
-
const schemaRefs =
|
|
812
|
-
const importedRefNames =
|
|
813
|
-
const importedCheckRefNames =
|
|
883
|
+
const refEntries = memo.create({ weak: true });
|
|
884
|
+
const checkRefEntries = memo.create({ weak: true });
|
|
885
|
+
const schemaRefs = memo.create({ weak: true });
|
|
886
|
+
const importedRefNames = memo.create({ weak: true });
|
|
887
|
+
const importedCheckRefNames = memo.create({ weak: true });
|
|
814
888
|
/**
|
|
815
889
|
* Walks a node's subtree once and lists every ref it holds, in traversal order, as the resolved
|
|
816
890
|
* name plus whether the ref carries a `$ref` pointer. Memoized per node and per `checks` mode, so
|
|
@@ -1032,27 +1106,25 @@ function getBaseURL(server) {
|
|
|
1032
1106
|
if (!server || server.variables || server.url.includes("{") || !server.url.includes("://")) return void 0;
|
|
1033
1107
|
return URL.canParse(server.url) ? server.url : void 0;
|
|
1034
1108
|
}
|
|
1035
|
-
const parametersByNode =
|
|
1109
|
+
const parametersByNode = memo.create({ weak: true });
|
|
1036
1110
|
/** The operation's parameters by location, with a `querystring` parameter in `query`. A repeated name keeps its first parameter. */
|
|
1037
1111
|
function groupParameters(node) {
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
}
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
};
|
|
1054
|
-
parametersByNode.set(node, groups);
|
|
1055
|
-
return groups;
|
|
1112
|
+
return memo(parametersByNode, node, () => {
|
|
1113
|
+
const group = (...locations) => {
|
|
1114
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1115
|
+
return locations.flatMap((location) => node.parameters.filter((param) => {
|
|
1116
|
+
if (param.in !== location || seen.has(param.name)) return false;
|
|
1117
|
+
seen.add(param.name);
|
|
1118
|
+
return true;
|
|
1119
|
+
}));
|
|
1120
|
+
};
|
|
1121
|
+
return {
|
|
1122
|
+
path: group("path"),
|
|
1123
|
+
query: group("query", "querystring"),
|
|
1124
|
+
header: group("header"),
|
|
1125
|
+
cookie: group("cookie")
|
|
1126
|
+
};
|
|
1127
|
+
});
|
|
1056
1128
|
}
|
|
1057
1129
|
// src/nodes/schema.ts
|
|
1058
1130
|
/**
|
|
@@ -1458,12 +1530,11 @@ function combineImports(imports, exports, source) {
|
|
|
1458
1530
|
const exportedNames = new Set(exports.flatMap((e) => Array.isArray(e.name) ? e.name : e.name ? [e.name] : []));
|
|
1459
1531
|
const identifiers = source && imports.length > INDEX_ABOVE_IMPORTS ? new Set(source.match(IDENTIFIER_RUN)) : null;
|
|
1460
1532
|
const isUsed = (importName) => !source || identifiers?.has(importName) || source.includes(importName) || exportedNames.has(importName);
|
|
1461
|
-
const importNameMemo =
|
|
1533
|
+
const importNameMemo = memo.create();
|
|
1462
1534
|
const canonicalizeName = (n) => {
|
|
1463
1535
|
if (typeof n === "string") return n;
|
|
1464
1536
|
const key = `${n.propertyName}:${n.name ?? ""}`;
|
|
1465
|
-
|
|
1466
|
-
return importNameMemo.get(key);
|
|
1537
|
+
return memo(importNameMemo, key, () => n);
|
|
1467
1538
|
};
|
|
1468
1539
|
const pathsWithUsedNamedImport = /* @__PURE__ */ new Set();
|
|
1469
1540
|
for (const node of imports) if (Array.isArray(node.name) && node.name.some((item) => isUsed(importLocalName(item)))) pathsWithUsedNamedImport.add(node.path);
|