@kubb/ast 5.0.0-beta.2 → 5.0.0-beta.21
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/README.md +1 -1
- package/dist/index.cjs +270 -206
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +118 -95
- package/dist/index.js +268 -207
- package/dist/index.js.map +1 -1
- package/package.json +3 -4
- package/src/factory.ts +15 -0
- package/src/guards.ts +3 -3
- package/src/index.ts +3 -2
- package/src/nodes/index.ts +1 -1
- package/src/nodes/operation.ts +1 -1
- package/src/nodes/response.ts +1 -1
- package/src/nodes/root.ts +72 -10
- package/src/nodes/schema.ts +9 -3
- package/src/printer.ts +15 -16
- package/src/refs.ts +4 -2
- package/src/resolvers.ts +4 -4
- package/src/transformers.ts +20 -15
- package/src/types.ts +1 -0
- package/src/utils.ts +89 -56
- package/src/visitor.ts +133 -181
package/dist/index.js
CHANGED
|
@@ -265,6 +265,46 @@ function pascalCase(text, { isFile, prefix = "", suffix = "" } = {}) {
|
|
|
265
265
|
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true);
|
|
266
266
|
}
|
|
267
267
|
//#endregion
|
|
268
|
+
//#region ../../internals/utils/src/promise.ts
|
|
269
|
+
/**
|
|
270
|
+
* Wraps `factory` with a keyed cache backed by the provided store.
|
|
271
|
+
*
|
|
272
|
+
* Pass a `WeakMap` for object keys (results are GC-eligible when the key is
|
|
273
|
+
* collected) or a `Map` for primitive keys. For multi-argument functions,
|
|
274
|
+
* nest two `memoize` calls — the outer keyed by the first argument, the
|
|
275
|
+
* inner (created once per outer miss) keyed by the second.
|
|
276
|
+
*
|
|
277
|
+
* Because the cache is owned by the caller, it can be shared, inspected, or
|
|
278
|
+
* cleared independently of the memoized function.
|
|
279
|
+
*
|
|
280
|
+
* @example Single WeakMap key
|
|
281
|
+
* ```ts
|
|
282
|
+
* const cache = new WeakMap<SchemaNode, Set<string>>()
|
|
283
|
+
* const getRefs = memoize(cache, (node) => collectRefs(node))
|
|
284
|
+
* ```
|
|
285
|
+
*
|
|
286
|
+
* @example Single Map key (primitive)
|
|
287
|
+
* ```ts
|
|
288
|
+
* const cache = new Map<string, Resolver>()
|
|
289
|
+
* const getResolver = memoize(cache, (name) => buildResolver(name))
|
|
290
|
+
* ```
|
|
291
|
+
*
|
|
292
|
+
* @example Two-level (object + primitive)
|
|
293
|
+
* ```ts
|
|
294
|
+
* const outer = new WeakMap<Params[], Map<string, Params[]>>()
|
|
295
|
+
* const fn = memoize(outer, (params) => memoize(new Map(), (key) => transform(params, key)))
|
|
296
|
+
* fn(params)('camelcase')
|
|
297
|
+
* ```
|
|
298
|
+
*/
|
|
299
|
+
function memoize(store, factory) {
|
|
300
|
+
return (key) => {
|
|
301
|
+
if (store.has(key)) return store.get(key);
|
|
302
|
+
const value = factory(key);
|
|
303
|
+
store.set(key, value);
|
|
304
|
+
return value;
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
//#endregion
|
|
268
308
|
//#region ../../internals/utils/src/reserved.ts
|
|
269
309
|
/**
|
|
270
310
|
* JavaScript and Java reserved words.
|
|
@@ -392,11 +432,11 @@ function trimExtName(text) {
|
|
|
392
432
|
* @example
|
|
393
433
|
* ```ts
|
|
394
434
|
* const schema = createSchema({ type: 'string' })
|
|
395
|
-
* const stringNode = narrowSchema(schema, 'string') // StringSchemaNode |
|
|
435
|
+
* const stringNode = narrowSchema(schema, 'string') // StringSchemaNode | null
|
|
396
436
|
* ```
|
|
397
437
|
*/
|
|
398
438
|
function narrowSchema(node, type) {
|
|
399
|
-
return node?.type === type ? node :
|
|
439
|
+
return node?.type === type ? node : null;
|
|
400
440
|
}
|
|
401
441
|
function isKind(kind) {
|
|
402
442
|
return (node) => node.kind === kind;
|
|
@@ -445,12 +485,6 @@ const isOperationNode = isKind("Operation");
|
|
|
445
485
|
* ```
|
|
446
486
|
*/
|
|
447
487
|
const isSchemaNode = isKind("Schema");
|
|
448
|
-
isKind("Property");
|
|
449
|
-
isKind("Parameter");
|
|
450
|
-
isKind("Response");
|
|
451
|
-
isKind("FunctionParameter");
|
|
452
|
-
isKind("ParameterGroup");
|
|
453
|
-
isKind("FunctionParameters");
|
|
454
488
|
//#endregion
|
|
455
489
|
//#region src/refs.ts
|
|
456
490
|
/**
|
|
@@ -516,32 +550,40 @@ function createLimit(concurrency) {
|
|
|
516
550
|
* // returns parameters, requestBody schema (if present), and responses
|
|
517
551
|
* ```
|
|
518
552
|
*/
|
|
519
|
-
function getChildren(node, recurse) {
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
const
|
|
530
|
-
if (!recurse) return [];
|
|
531
|
-
if ("properties" in node && node.properties.length > 0) children.push(...node.properties);
|
|
532
|
-
if ("items" in node && node.items) children.push(...node.items);
|
|
533
|
-
if ("members" in node && node.members) children.push(...node.members);
|
|
534
|
-
if ("additionalProperties" in node && node.additionalProperties && node.additionalProperties !== true) children.push(node.additionalProperties);
|
|
535
|
-
return children;
|
|
553
|
+
function* getChildren(node, recurse) {
|
|
554
|
+
if (node.kind === "Input") {
|
|
555
|
+
yield* node.schemas;
|
|
556
|
+
yield* node.operations;
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
if (node.kind === "Output") return;
|
|
560
|
+
if (node.kind === "Operation") {
|
|
561
|
+
yield* node.parameters;
|
|
562
|
+
if (node.requestBody?.content) {
|
|
563
|
+
for (const c of node.requestBody.content) if (c.schema) yield c.schema;
|
|
536
564
|
}
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
565
|
+
yield* node.responses;
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
if (node.kind === "Schema") {
|
|
569
|
+
if (!recurse) return;
|
|
570
|
+
if ("properties" in node && node.properties.length > 0) yield* node.properties;
|
|
571
|
+
if ("items" in node && node.items) yield* node.items;
|
|
572
|
+
if ("members" in node && node.members) yield* node.members;
|
|
573
|
+
if ("additionalProperties" in node && node.additionalProperties && node.additionalProperties !== true) yield node.additionalProperties;
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
576
|
+
if (node.kind === "Property") {
|
|
577
|
+
yield node.schema;
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
580
|
+
if (node.kind === "Parameter") {
|
|
581
|
+
yield node.schema;
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
if (node.kind === "Response") {
|
|
585
|
+
if (node.schema) yield node.schema;
|
|
586
|
+
return;
|
|
545
587
|
}
|
|
546
588
|
}
|
|
547
589
|
/**
|
|
@@ -590,9 +632,6 @@ async function _walk(node, visitor, recurse, limit, parent) {
|
|
|
590
632
|
case "Response":
|
|
591
633
|
await limit(() => visitor.response?.(node, { parent }));
|
|
592
634
|
break;
|
|
593
|
-
case "FunctionParameter":
|
|
594
|
-
case "ParameterGroup":
|
|
595
|
-
case "FunctionParameters": break;
|
|
596
635
|
}
|
|
597
636
|
const children = getChildren(node, recurse);
|
|
598
637
|
for (const child of children) await _walk(child, visitor, recurse, limit, node);
|
|
@@ -600,118 +639,95 @@ async function _walk(node, visitor, recurse, limit, parent) {
|
|
|
600
639
|
function transform(node, options) {
|
|
601
640
|
const { depth, parent, ...visitor } = options;
|
|
602
641
|
const recurse = (depth ?? visitorDepths.deep) === visitorDepths.deep;
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
parent: op
|
|
635
|
-
})),
|
|
636
|
-
requestBody: op.requestBody ? {
|
|
637
|
-
...op.requestBody,
|
|
638
|
-
content: op.requestBody.content?.map((c) => ({
|
|
639
|
-
...c,
|
|
640
|
-
schema: c.schema ? transform(c.schema, {
|
|
641
|
-
...options,
|
|
642
|
-
parent: op
|
|
643
|
-
}) : void 0
|
|
644
|
-
}))
|
|
645
|
-
} : void 0,
|
|
646
|
-
responses: op.responses.map((r) => transform(r, {
|
|
647
|
-
...options,
|
|
648
|
-
parent: op
|
|
642
|
+
if (node.kind === "Input") {
|
|
643
|
+
const input = visitor.input?.(node, { parent }) ?? node;
|
|
644
|
+
return {
|
|
645
|
+
...input,
|
|
646
|
+
schemas: input.schemas.map((s) => transform(s, {
|
|
647
|
+
...options,
|
|
648
|
+
parent: input
|
|
649
|
+
})),
|
|
650
|
+
operations: input.operations.map((op) => transform(op, {
|
|
651
|
+
...options,
|
|
652
|
+
parent: input
|
|
653
|
+
}))
|
|
654
|
+
};
|
|
655
|
+
}
|
|
656
|
+
if (node.kind === "Output") return visitor.output?.(node, { parent }) ?? node;
|
|
657
|
+
if (node.kind === "Operation") {
|
|
658
|
+
const op = visitor.operation?.(node, { parent }) ?? node;
|
|
659
|
+
return {
|
|
660
|
+
...op,
|
|
661
|
+
parameters: op.parameters.map((p) => transform(p, {
|
|
662
|
+
...options,
|
|
663
|
+
parent: op
|
|
664
|
+
})),
|
|
665
|
+
requestBody: op.requestBody ? {
|
|
666
|
+
...op.requestBody,
|
|
667
|
+
content: op.requestBody.content?.map((c) => ({
|
|
668
|
+
...c,
|
|
669
|
+
schema: c.schema ? transform(c.schema, {
|
|
670
|
+
...options,
|
|
671
|
+
parent: op
|
|
672
|
+
}) : void 0
|
|
649
673
|
}))
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
case "Schema": {
|
|
653
|
-
let schema = node;
|
|
654
|
-
const replaced = visitor.schema?.(schema, { parent });
|
|
655
|
-
if (replaced) schema = replaced;
|
|
656
|
-
const childOptions = {
|
|
674
|
+
} : void 0,
|
|
675
|
+
responses: op.responses.map((r) => transform(r, {
|
|
657
676
|
...options,
|
|
658
|
-
parent:
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
}
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
...param,
|
|
686
|
-
schema: transform(param.schema, {
|
|
687
|
-
...options,
|
|
688
|
-
parent: param
|
|
689
|
-
})
|
|
690
|
-
});
|
|
691
|
-
}
|
|
692
|
-
case "Response": {
|
|
693
|
-
let response = node;
|
|
694
|
-
const replaced = visitor.response?.(response, { parent });
|
|
695
|
-
if (replaced) response = replaced;
|
|
696
|
-
return {
|
|
697
|
-
...response,
|
|
698
|
-
schema: transform(response.schema, {
|
|
699
|
-
...options,
|
|
700
|
-
parent: response
|
|
701
|
-
})
|
|
702
|
-
};
|
|
703
|
-
}
|
|
704
|
-
case "FunctionParameter":
|
|
705
|
-
case "ParameterGroup":
|
|
706
|
-
case "FunctionParameters":
|
|
707
|
-
case "Type": return node;
|
|
708
|
-
default: return node;
|
|
677
|
+
parent: op
|
|
678
|
+
}))
|
|
679
|
+
};
|
|
680
|
+
}
|
|
681
|
+
if (node.kind === "Schema") {
|
|
682
|
+
const schema = visitor.schema?.(node, { parent }) ?? node;
|
|
683
|
+
const childOptions = {
|
|
684
|
+
...options,
|
|
685
|
+
parent: schema
|
|
686
|
+
};
|
|
687
|
+
return {
|
|
688
|
+
...schema,
|
|
689
|
+
..."properties" in schema && recurse ? { properties: schema.properties.map((p) => transform(p, childOptions)) } : {},
|
|
690
|
+
..."items" in schema && recurse ? { items: schema.items?.map((i) => transform(i, childOptions)) } : {},
|
|
691
|
+
..."members" in schema && recurse ? { members: schema.members?.map((m) => transform(m, childOptions)) } : {},
|
|
692
|
+
..."additionalProperties" in schema && recurse && schema.additionalProperties && schema.additionalProperties !== true ? { additionalProperties: transform(schema.additionalProperties, childOptions) } : {}
|
|
693
|
+
};
|
|
694
|
+
}
|
|
695
|
+
if (node.kind === "Property") {
|
|
696
|
+
const prop = visitor.property?.(node, { parent }) ?? node;
|
|
697
|
+
return createProperty({
|
|
698
|
+
...prop,
|
|
699
|
+
schema: transform(prop.schema, {
|
|
700
|
+
...options,
|
|
701
|
+
parent: prop
|
|
702
|
+
})
|
|
703
|
+
});
|
|
709
704
|
}
|
|
705
|
+
if (node.kind === "Parameter") {
|
|
706
|
+
const param = visitor.parameter?.(node, { parent }) ?? node;
|
|
707
|
+
return createParameter({
|
|
708
|
+
...param,
|
|
709
|
+
schema: transform(param.schema, {
|
|
710
|
+
...options,
|
|
711
|
+
parent: param
|
|
712
|
+
})
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
if (node.kind === "Response") {
|
|
716
|
+
const response = visitor.response?.(node, { parent }) ?? node;
|
|
717
|
+
return {
|
|
718
|
+
...response,
|
|
719
|
+
schema: transform(response.schema, {
|
|
720
|
+
...options,
|
|
721
|
+
parent: response
|
|
722
|
+
})
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
return node;
|
|
710
726
|
}
|
|
711
727
|
/**
|
|
712
728
|
* Runs a depth-first synchronous collection pass.
|
|
713
729
|
*
|
|
714
|
-
* Non-`
|
|
730
|
+
* Non-`null` values returned by visitor callbacks are appended to the result.
|
|
715
731
|
*
|
|
716
732
|
* @example
|
|
717
733
|
* ```ts
|
|
@@ -728,10 +744,9 @@ function transform(node, options) {
|
|
|
728
744
|
* const values = collect(root, { depth: 'shallow', root: () => 'root' })
|
|
729
745
|
* ```
|
|
730
746
|
*/
|
|
731
|
-
function
|
|
747
|
+
function* collectLazy(node, options) {
|
|
732
748
|
const { depth, parent, ...visitor } = options;
|
|
733
749
|
const recurse = (depth ?? visitorDepths.deep) === visitorDepths.deep;
|
|
734
|
-
const results = [];
|
|
735
750
|
let v;
|
|
736
751
|
switch (node.kind) {
|
|
737
752
|
case "Input":
|
|
@@ -755,16 +770,15 @@ function collect(node, options) {
|
|
|
755
770
|
case "Response":
|
|
756
771
|
v = visitor.response?.(node, { parent });
|
|
757
772
|
break;
|
|
758
|
-
case "FunctionParameter":
|
|
759
|
-
case "ParameterGroup":
|
|
760
|
-
case "FunctionParameters": break;
|
|
761
773
|
}
|
|
762
|
-
if (v
|
|
763
|
-
for (const child of getChildren(node, recurse))
|
|
774
|
+
if (v != null) yield v;
|
|
775
|
+
for (const child of getChildren(node, recurse)) yield* collectLazy(child, {
|
|
764
776
|
...options,
|
|
765
777
|
parent: node
|
|
766
|
-
})
|
|
767
|
-
|
|
778
|
+
});
|
|
779
|
+
}
|
|
780
|
+
function collect(node, options) {
|
|
781
|
+
return Array.from(collectLazy(node, options));
|
|
768
782
|
}
|
|
769
783
|
//#endregion
|
|
770
784
|
//#region src/utils.ts
|
|
@@ -818,15 +832,16 @@ function isStringType(node) {
|
|
|
818
832
|
* the desired casing while preserving `OperationNode.parameters` for other consumers.
|
|
819
833
|
* The input array is not mutated. When `casing` is not set, the original array is returned unchanged.
|
|
820
834
|
*/
|
|
835
|
+
const caseParamsMemo = memoize(/* @__PURE__ */ new WeakMap(), (params) => memoize(/* @__PURE__ */ new Map(), (casing) => params.map((param) => {
|
|
836
|
+
const transformed = casing === "camelcase" || !isValidVarName(param.name) ? camelCase(param.name) : param.name;
|
|
837
|
+
return {
|
|
838
|
+
...param,
|
|
839
|
+
name: transformed
|
|
840
|
+
};
|
|
841
|
+
})));
|
|
821
842
|
function caseParams(params, casing) {
|
|
822
843
|
if (!casing) return params;
|
|
823
|
-
return params
|
|
824
|
-
const transformed = casing === "camelcase" || !isValidVarName(param.name) ? camelCase(param.name) : param.name;
|
|
825
|
-
return {
|
|
826
|
-
...param,
|
|
827
|
-
name: transformed
|
|
828
|
-
};
|
|
829
|
-
});
|
|
844
|
+
return caseParamsMemo(params)(casing);
|
|
830
845
|
}
|
|
831
846
|
/**
|
|
832
847
|
* Creates a single-property object schema used as a discriminator literal.
|
|
@@ -955,7 +970,7 @@ function createOperationParams(node, options) {
|
|
|
955
970
|
}));
|
|
956
971
|
} else {
|
|
957
972
|
if (pathParams.length) if (pathParamsType === "inlineSpread") {
|
|
958
|
-
const spreadType = resolver?.resolvePathParamsName(node, pathParams[0])
|
|
973
|
+
const spreadType = resolver?.resolvePathParamsName(node, pathParams[0]);
|
|
959
974
|
params.push(createFunctionParameter({
|
|
960
975
|
name: pathName,
|
|
961
976
|
type: spreadType ? wrapType(spreadType) : void 0,
|
|
@@ -1031,13 +1046,13 @@ function buildGroupParam({ name, node, params, groupType, resolver, wrapType })
|
|
|
1031
1046
|
}
|
|
1032
1047
|
/**
|
|
1033
1048
|
* Derives a {@link ParamGroupType} from the resolver's group method.
|
|
1034
|
-
* Returns `
|
|
1049
|
+
* Returns `null` when the group name equals the individual param name (no real group).
|
|
1035
1050
|
*/
|
|
1036
1051
|
function resolveGroupType({ node, params, groupMethod, resolver }) {
|
|
1037
|
-
if (!params.length) return;
|
|
1052
|
+
if (!params.length) return null;
|
|
1038
1053
|
const firstParam = params[0];
|
|
1039
1054
|
const groupName = groupMethod.call(resolver, node, firstParam);
|
|
1040
|
-
if (groupName === resolver.resolveParamName(node, firstParam)) return;
|
|
1055
|
+
if (groupName === resolver.resolveParamName(node, firstParam)) return null;
|
|
1041
1056
|
const allOptional = params.every((p) => !p.required);
|
|
1042
1057
|
return {
|
|
1043
1058
|
type: createParamsType({
|
|
@@ -1157,6 +1172,13 @@ function combineExports(exports) {
|
|
|
1157
1172
|
function combineImports(imports, exports, source) {
|
|
1158
1173
|
const exportedNames = new Set(exports.flatMap((e) => Array.isArray(e.name) ? e.name : e.name ? [e.name] : []));
|
|
1159
1174
|
const isUsed = (importName) => !source || source.includes(importName) || exportedNames.has(importName);
|
|
1175
|
+
const importNameMemo = /* @__PURE__ */ new Map();
|
|
1176
|
+
const canonicalizeName = (n) => {
|
|
1177
|
+
if (typeof n === "string") return n;
|
|
1178
|
+
const key = `${n.propertyName}:${n.name ?? ""}`;
|
|
1179
|
+
if (!importNameMemo.has(key)) importNameMemo.set(key, n);
|
|
1180
|
+
return importNameMemo.get(key);
|
|
1181
|
+
};
|
|
1160
1182
|
const result = [];
|
|
1161
1183
|
const namedByPath = /* @__PURE__ */ new Map();
|
|
1162
1184
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -1170,7 +1192,7 @@ function combineImports(imports, exports, source) {
|
|
|
1170
1192
|
const { path, isTypeOnly } = curr;
|
|
1171
1193
|
let { name } = curr;
|
|
1172
1194
|
if (Array.isArray(name)) {
|
|
1173
|
-
name = [...new Set(name)].filter((item) => typeof item === "string" ? isUsed(item) : isUsed(item.name ?? item.propertyName));
|
|
1195
|
+
name = [...new Set(name.map(canonicalizeName))].filter((item) => typeof item === "string" ? isUsed(item) : isUsed(item.name ?? item.propertyName));
|
|
1174
1196
|
if (!name.length) continue;
|
|
1175
1197
|
const key = pathTypeKey(path, isTypeOnly);
|
|
1176
1198
|
const existing = namedByPath.get(key);
|
|
@@ -1223,7 +1245,7 @@ function extractStringsFromNodes(nodes) {
|
|
|
1223
1245
|
/**
|
|
1224
1246
|
* Resolves the schema name of a ref node, falling back through `ref` → `name` → nested `schema.name`.
|
|
1225
1247
|
*
|
|
1226
|
-
* Returns `
|
|
1248
|
+
* Returns `null` for non-ref nodes or when no name can be resolved. Use this to get a schema's
|
|
1227
1249
|
* identifier for type definitions or error messages.
|
|
1228
1250
|
*
|
|
1229
1251
|
* @example
|
|
@@ -1233,9 +1255,9 @@ function extractStringsFromNodes(nodes) {
|
|
|
1233
1255
|
* ```
|
|
1234
1256
|
*/
|
|
1235
1257
|
function resolveRefName(node) {
|
|
1236
|
-
if (!node || node.type !== "ref") return
|
|
1237
|
-
if (node.ref) return extractRefName(node.ref) ?? node.name ?? node.schema?.name ??
|
|
1238
|
-
return node.name ?? node.schema?.name ??
|
|
1258
|
+
if (!node || node.type !== "ref") return null;
|
|
1259
|
+
if (node.ref) return extractRefName(node.ref) ?? node.name ?? node.schema?.name ?? null;
|
|
1260
|
+
return node.name ?? node.schema?.name ?? null;
|
|
1239
1261
|
}
|
|
1240
1262
|
/**
|
|
1241
1263
|
* Collects every named schema referenced (transitively) from a node via ref edges.
|
|
@@ -1257,14 +1279,19 @@ function resolveRefName(node) {
|
|
|
1257
1279
|
* }
|
|
1258
1280
|
* ```
|
|
1259
1281
|
*/
|
|
1260
|
-
|
|
1261
|
-
|
|
1282
|
+
const collectSchemaRefs = memoize(/* @__PURE__ */ new WeakMap(), (node) => {
|
|
1283
|
+
const refs = /* @__PURE__ */ new Set();
|
|
1262
1284
|
collect(node, { schema(child) {
|
|
1263
1285
|
if (child.type === "ref") {
|
|
1264
1286
|
const name = resolveRefName(child);
|
|
1265
|
-
if (name)
|
|
1287
|
+
if (name) refs.add(name);
|
|
1266
1288
|
}
|
|
1267
1289
|
} });
|
|
1290
|
+
return refs;
|
|
1291
|
+
});
|
|
1292
|
+
function collectReferencedSchemaNames(node, out = /* @__PURE__ */ new Set()) {
|
|
1293
|
+
if (!node) return out;
|
|
1294
|
+
for (const name of collectSchemaRefs(node)) out.add(name);
|
|
1268
1295
|
return out;
|
|
1269
1296
|
}
|
|
1270
1297
|
/**
|
|
@@ -1280,10 +1307,10 @@ function collectReferencedSchemaNames(node, out = /* @__PURE__ */ new Set()) {
|
|
|
1280
1307
|
*
|
|
1281
1308
|
* @example Only generate schemas referenced by included operations
|
|
1282
1309
|
* ```ts
|
|
1283
|
-
* const includedOps =
|
|
1284
|
-
* const allowed = collectUsedSchemaNames(includedOps,
|
|
1310
|
+
* const includedOps = operations.filter(op => resolver.resolveOptions(op, { options, include }) !== null)
|
|
1311
|
+
* const allowed = collectUsedSchemaNames(includedOps, schemas)
|
|
1285
1312
|
*
|
|
1286
|
-
* for (const schema of
|
|
1313
|
+
* for (const schema of schemas) {
|
|
1287
1314
|
* if (schema.name && !allowed.has(schema.name)) continue
|
|
1288
1315
|
* // … generate schema
|
|
1289
1316
|
* }
|
|
@@ -1291,11 +1318,12 @@ function collectReferencedSchemaNames(node, out = /* @__PURE__ */ new Set()) {
|
|
|
1291
1318
|
*
|
|
1292
1319
|
* @example Check whether a specific schema is needed
|
|
1293
1320
|
* ```ts
|
|
1294
|
-
* const allowed = collectUsedSchemaNames(includedOps,
|
|
1321
|
+
* const allowed = collectUsedSchemaNames(includedOps, schemas)
|
|
1295
1322
|
* allowed.has('OrderStatus') // false when no included operation references OrderStatus
|
|
1296
1323
|
* ```
|
|
1297
1324
|
*/
|
|
1298
|
-
|
|
1325
|
+
const collectUsedSchemaNamesMemo = memoize(/* @__PURE__ */ new WeakMap(), (ops) => memoize(/* @__PURE__ */ new WeakMap(), (schemas) => computeUsedSchemaNames(ops, schemas)));
|
|
1326
|
+
function computeUsedSchemaNames(operations, schemas) {
|
|
1299
1327
|
const schemaMap = /* @__PURE__ */ new Map();
|
|
1300
1328
|
for (const schema of schemas) if (schema.name) schemaMap.set(schema.name, schema);
|
|
1301
1329
|
const result = /* @__PURE__ */ new Set();
|
|
@@ -1307,22 +1335,17 @@ function collectUsedSchemaNames(operations, schemas) {
|
|
|
1307
1335
|
if (namedSchema) visitSchema(namedSchema);
|
|
1308
1336
|
}
|
|
1309
1337
|
}
|
|
1310
|
-
for (const op of operations) for (const schema of
|
|
1338
|
+
for (const op of operations) for (const schema of collectLazy(op, {
|
|
1311
1339
|
depth: "shallow",
|
|
1312
1340
|
schema: (node) => node
|
|
1313
1341
|
})) visitSchema(schema);
|
|
1314
1342
|
return result;
|
|
1315
1343
|
}
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
* Refs are followed by name only, keeping the algorithm linear in the schema graph size.
|
|
1322
|
-
*
|
|
1323
|
-
* @note Call this once on the full schema graph, then use `containsCircularRef()` to check individual schemas.
|
|
1324
|
-
*/
|
|
1325
|
-
function findCircularSchemas(schemas) {
|
|
1344
|
+
function collectUsedSchemaNames(operations, schemas) {
|
|
1345
|
+
return collectUsedSchemaNamesMemo(operations)(schemas);
|
|
1346
|
+
}
|
|
1347
|
+
const EMPTY_CIRCULAR_SET = /* @__PURE__ */ new Set();
|
|
1348
|
+
const findCircularSchemasMemo = memoize(/* @__PURE__ */ new WeakMap(), (schemas) => {
|
|
1326
1349
|
const graph = /* @__PURE__ */ new Map();
|
|
1327
1350
|
for (const schema of schemas) {
|
|
1328
1351
|
if (!schema.name) continue;
|
|
@@ -1345,6 +1368,19 @@ function findCircularSchemas(schemas) {
|
|
|
1345
1368
|
}
|
|
1346
1369
|
}
|
|
1347
1370
|
return circular;
|
|
1371
|
+
});
|
|
1372
|
+
/**
|
|
1373
|
+
* Identifies all schemas that participate in circular dependency chains, including direct self-loops.
|
|
1374
|
+
*
|
|
1375
|
+
* Returns a Set of schema names with circular dependencies. Use this to wrap recursive schema positions
|
|
1376
|
+
* in deferred constructs (lazy getter, `z.lazy(() => …)`) to prevent infinite recursion when generated code runs.
|
|
1377
|
+
* Refs are followed by name only, keeping the algorithm linear in the schema graph size.
|
|
1378
|
+
*
|
|
1379
|
+
* @note Call this once on the full schema graph, then use `containsCircularRef()` to check individual schemas.
|
|
1380
|
+
*/
|
|
1381
|
+
function findCircularSchemas(schemas) {
|
|
1382
|
+
if (schemas.length === 0) return EMPTY_CIRCULAR_SET;
|
|
1383
|
+
return findCircularSchemasMemo(schemas);
|
|
1348
1384
|
}
|
|
1349
1385
|
/**
|
|
1350
1386
|
* Type guard returning `true` when a schema or anything nested within it contains a ref to a circular schema.
|
|
@@ -1356,11 +1392,12 @@ function findCircularSchemas(schemas) {
|
|
|
1356
1392
|
*/
|
|
1357
1393
|
function containsCircularRef(node, { circularSchemas, excludeName }) {
|
|
1358
1394
|
if (!node || circularSchemas.size === 0) return false;
|
|
1359
|
-
|
|
1360
|
-
if (child.type !== "ref") return
|
|
1395
|
+
for (const _ of collectLazy(node, { schema(child) {
|
|
1396
|
+
if (child.type !== "ref") return null;
|
|
1361
1397
|
const name = resolveRefName(child);
|
|
1362
|
-
return name && name !== excludeName && circularSchemas.has(name) ? true :
|
|
1363
|
-
} })
|
|
1398
|
+
return name && name !== excludeName && circularSchemas.has(name) ? true : null;
|
|
1399
|
+
} })) return true;
|
|
1400
|
+
return false;
|
|
1364
1401
|
}
|
|
1365
1402
|
//#endregion
|
|
1366
1403
|
//#region src/factory.ts
|
|
@@ -1397,11 +1434,31 @@ function createInput(overrides = {}) {
|
|
|
1397
1434
|
return {
|
|
1398
1435
|
schemas: [],
|
|
1399
1436
|
operations: [],
|
|
1437
|
+
meta: {
|
|
1438
|
+
circularNames: [],
|
|
1439
|
+
enumNames: []
|
|
1440
|
+
},
|
|
1400
1441
|
...overrides,
|
|
1401
1442
|
kind: "Input"
|
|
1402
1443
|
};
|
|
1403
1444
|
}
|
|
1404
1445
|
/**
|
|
1446
|
+
* Creates an `InputStreamNode` from pre-built `AsyncIterable` sources.
|
|
1447
|
+
*
|
|
1448
|
+
* @example
|
|
1449
|
+
* ```ts
|
|
1450
|
+
* const node = createStreamInput(schemasIterable, operationsIterable, { title: 'My API' })
|
|
1451
|
+
* ```
|
|
1452
|
+
*/
|
|
1453
|
+
function createStreamInput(schemas, operations, meta) {
|
|
1454
|
+
return {
|
|
1455
|
+
kind: "Input",
|
|
1456
|
+
schemas,
|
|
1457
|
+
operations,
|
|
1458
|
+
meta
|
|
1459
|
+
};
|
|
1460
|
+
}
|
|
1461
|
+
/**
|
|
1405
1462
|
* Creates an `OutputNode` with a stable default for `files`.
|
|
1406
1463
|
*
|
|
1407
1464
|
* @example
|
|
@@ -2040,7 +2097,7 @@ function createPrinterFactory(getKey) {
|
|
|
2040
2097
|
options: resolvedOptions,
|
|
2041
2098
|
transform: (node) => {
|
|
2042
2099
|
const key = getKey(node);
|
|
2043
|
-
if (key ===
|
|
2100
|
+
if (key === null) return null;
|
|
2044
2101
|
const handler = nodes[key];
|
|
2045
2102
|
if (!handler) return null;
|
|
2046
2103
|
return handler.call(context, node);
|
|
@@ -2077,10 +2134,10 @@ function enumPropName(parentName, propName, enumSuffix) {
|
|
|
2077
2134
|
function collectImports({ node, nameMapping, resolve }) {
|
|
2078
2135
|
return collect(node, { schema(schemaNode) {
|
|
2079
2136
|
const schemaRef = narrowSchema(schemaNode, "ref");
|
|
2080
|
-
if (!schemaRef?.ref) return;
|
|
2137
|
+
if (!schemaRef?.ref) return null;
|
|
2081
2138
|
const rawName = extractRefName(schemaRef.ref);
|
|
2082
2139
|
const result = resolve(nameMapping.get(rawName) ?? rawName);
|
|
2083
|
-
if (!result) return;
|
|
2140
|
+
if (!result) return null;
|
|
2084
2141
|
return result;
|
|
2085
2142
|
} });
|
|
2086
2143
|
}
|
|
@@ -2134,23 +2191,27 @@ function setDiscriminatorEnum({ node, propertyName, values, enumName }) {
|
|
|
2134
2191
|
* ])
|
|
2135
2192
|
* ```
|
|
2136
2193
|
*/
|
|
2137
|
-
function
|
|
2138
|
-
|
|
2194
|
+
function* mergeAdjacentObjectsLazy(members) {
|
|
2195
|
+
let acc;
|
|
2196
|
+
for (const member of members) {
|
|
2139
2197
|
const objectMember = narrowSchema(member, "object");
|
|
2140
|
-
if (objectMember && !objectMember.name) {
|
|
2141
|
-
const
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
...
|
|
2146
|
-
properties: [...previousObject.properties ?? [], ...objectMember.properties ?? []]
|
|
2198
|
+
if (objectMember && !objectMember.name && acc !== void 0) {
|
|
2199
|
+
const accObject = narrowSchema(acc, "object");
|
|
2200
|
+
if (accObject && !accObject.name) {
|
|
2201
|
+
acc = createSchema({
|
|
2202
|
+
...accObject,
|
|
2203
|
+
properties: [...accObject.properties ?? [], ...objectMember.properties ?? []]
|
|
2147
2204
|
});
|
|
2148
|
-
|
|
2205
|
+
continue;
|
|
2149
2206
|
}
|
|
2150
2207
|
}
|
|
2151
|
-
acc
|
|
2152
|
-
|
|
2153
|
-
}
|
|
2208
|
+
if (acc !== void 0) yield acc;
|
|
2209
|
+
acc = member;
|
|
2210
|
+
}
|
|
2211
|
+
if (acc !== void 0) yield acc;
|
|
2212
|
+
}
|
|
2213
|
+
function mergeAdjacentObjects(members) {
|
|
2214
|
+
return [...mergeAdjacentObjectsLazy(members)];
|
|
2154
2215
|
}
|
|
2155
2216
|
/**
|
|
2156
2217
|
* Removes enum members that are covered by broader scalar primitives in the same union.
|
|
@@ -2182,7 +2243,7 @@ function setEnumName(propNode, parentName, propName, enumSuffix) {
|
|
|
2182
2243
|
const enumNode = narrowSchema(propNode, "enum");
|
|
2183
2244
|
if (enumNode?.primitive === "boolean") return {
|
|
2184
2245
|
...propNode,
|
|
2185
|
-
name:
|
|
2246
|
+
name: null
|
|
2186
2247
|
};
|
|
2187
2248
|
if (enumNode) return {
|
|
2188
2249
|
...propNode,
|
|
@@ -2191,6 +2252,6 @@ function setEnumName(propNode, parentName, propName, enumSuffix) {
|
|
|
2191
2252
|
return propNode;
|
|
2192
2253
|
}
|
|
2193
2254
|
//#endregion
|
|
2194
|
-
export { caseParams, childName, collect, collectImports, collectReferencedSchemaNames, collectUsedSchemaNames, containsCircularRef, createArrowFunction, createBreak, createConst, createDiscriminantNode, createExport, createFile, createFunction, createFunctionParameter, createFunctionParameters, createImport, createInput, createJsx, createOperation, createOperationParams, createOutput, createParameter, createParameterGroup, createParamsType, createPrinterFactory, createProperty, createResponse, createSchema, createSource, createText, createType, definePrinter, enumPropName, extractRefName, extractStringsFromNodes, findCircularSchemas, findDiscriminator, httpMethods, isInputNode, isOperationNode, isOutputNode, isScalarPrimitive, isSchemaNode, isStringType, mediaTypes, mergeAdjacentObjects, narrowSchema, nodeKinds, resolveRefName, schemaTypes, setDiscriminatorEnum, setEnumName, simplifyUnion, syncOptionality, syncSchemaRef, transform, walk };
|
|
2255
|
+
export { caseParams, childName, collect, collectImports, collectLazy, collectReferencedSchemaNames, collectUsedSchemaNames, containsCircularRef, createArrowFunction, createBreak, createConst, createDiscriminantNode, createExport, createFile, createFunction, createFunctionParameter, createFunctionParameters, createImport, createInput, createJsx, createOperation, createOperationParams, createOutput, createParameter, createParameterGroup, createParamsType, createPrinterFactory, createProperty, createResponse, createSchema, createSource, createStreamInput, createText, createType, definePrinter, enumPropName, extractRefName, extractStringsFromNodes, findCircularSchemas, findDiscriminator, httpMethods, isInputNode, isOperationNode, isOutputNode, isScalarPrimitive, isSchemaNode, isStringType, mediaTypes, mergeAdjacentObjects, mergeAdjacentObjectsLazy, narrowSchema, nodeKinds, resolveRefName, schemaTypes, setDiscriminatorEnum, setEnumName, simplifyUnion, syncOptionality, syncSchemaRef, transform, walk };
|
|
2195
2256
|
|
|
2196
2257
|
//# sourceMappingURL=index.js.map
|