@kubb/ast 5.0.0-alpha.67 → 5.0.0-alpha.69
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 +776 -664
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +72 -1
- package/dist/index.js +773 -665
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +12 -1
- package/src/utils.ts +132 -0
package/dist/index.js
CHANGED
|
@@ -358,212 +358,527 @@ isKind("FunctionParameter");
|
|
|
358
358
|
isKind("ParameterGroup");
|
|
359
359
|
isKind("FunctionParameters");
|
|
360
360
|
//#endregion
|
|
361
|
-
//#region src/
|
|
362
|
-
const plainStringTypes = new Set([
|
|
363
|
-
"string",
|
|
364
|
-
"uuid",
|
|
365
|
-
"email",
|
|
366
|
-
"url",
|
|
367
|
-
"datetime"
|
|
368
|
-
]);
|
|
361
|
+
//#region src/refs.ts
|
|
369
362
|
/**
|
|
370
|
-
* Returns
|
|
371
|
-
* (base from the referenced definition) with any usage-site sibling fields set directly
|
|
372
|
-
* on the ref node (description, readOnly, nullable, deprecated, etc.).
|
|
363
|
+
* Returns the last path segment of a reference string.
|
|
373
364
|
*
|
|
374
|
-
*
|
|
365
|
+
* Example: `#/components/schemas/Pet` becomes `Pet`.
|
|
375
366
|
*
|
|
376
|
-
*
|
|
367
|
+
* @example
|
|
368
|
+
* ```ts
|
|
369
|
+
* extractRefName('#/components/schemas/Pet') // 'Pet'
|
|
370
|
+
* ```
|
|
377
371
|
*/
|
|
378
|
-
function
|
|
379
|
-
|
|
380
|
-
if (!ref) return node;
|
|
381
|
-
if (!ref.schema) return node;
|
|
382
|
-
const { kind: _kind, type: _type, name: _name, ref: _ref, schema: _schema, ...overrides } = ref;
|
|
383
|
-
const definedOverrides = Object.fromEntries(Object.entries(overrides).filter(([, v]) => v !== void 0));
|
|
384
|
-
return createSchema({
|
|
385
|
-
...ref.schema,
|
|
386
|
-
...definedOverrides
|
|
387
|
-
});
|
|
372
|
+
function extractRefName(ref) {
|
|
373
|
+
return ref.split("/").at(-1) ?? ref;
|
|
388
374
|
}
|
|
375
|
+
//#endregion
|
|
376
|
+
//#region src/visitor.ts
|
|
389
377
|
/**
|
|
390
|
-
*
|
|
378
|
+
* Creates a small async concurrency limiter.
|
|
391
379
|
*
|
|
392
|
-
*
|
|
393
|
-
* - `date` and `time` are plain strings when their `representation` is `'string'` rather than `'date'`.
|
|
380
|
+
* At most `concurrency` tasks are in flight at once. Extra tasks are queued.
|
|
394
381
|
*
|
|
395
382
|
* @example
|
|
396
383
|
* ```ts
|
|
397
|
-
*
|
|
398
|
-
*
|
|
384
|
+
* const limit = createLimit(2)
|
|
385
|
+
* for (const task of [taskA, taskB, taskC]) {
|
|
386
|
+
* await limit(() => task())
|
|
387
|
+
* }
|
|
388
|
+
* // only 2 tasks run at the same time
|
|
399
389
|
* ```
|
|
400
390
|
*/
|
|
401
|
-
function
|
|
402
|
-
|
|
403
|
-
const
|
|
404
|
-
|
|
405
|
-
|
|
391
|
+
function createLimit(concurrency) {
|
|
392
|
+
let active = 0;
|
|
393
|
+
const queue = [];
|
|
394
|
+
function next() {
|
|
395
|
+
if (active < concurrency && queue.length > 0) {
|
|
396
|
+
active++;
|
|
397
|
+
queue.shift()();
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
return function limit(fn) {
|
|
401
|
+
return new Promise((resolve, reject) => {
|
|
402
|
+
queue.push(() => {
|
|
403
|
+
Promise.resolve(fn()).then(resolve, reject).finally(() => {
|
|
404
|
+
active--;
|
|
405
|
+
next();
|
|
406
|
+
});
|
|
407
|
+
});
|
|
408
|
+
next();
|
|
409
|
+
});
|
|
410
|
+
};
|
|
406
411
|
}
|
|
407
412
|
/**
|
|
408
|
-
*
|
|
409
|
-
*
|
|
410
|
-
* The input array is not mutated.
|
|
411
|
-
* If `casing` is not set, the original array is returned unchanged.
|
|
413
|
+
* Returns the immediate traversable children of `node`.
|
|
412
414
|
*
|
|
413
|
-
*
|
|
414
|
-
*
|
|
415
|
-
* `
|
|
415
|
+
* For `Schema` nodes, children (`properties`, `items`, `members`, and non-boolean
|
|
416
|
+
* `additionalProperties`) are only included
|
|
417
|
+
* when `recurse` is `true`; shallow mode skips them.
|
|
416
418
|
*
|
|
417
419
|
* @example
|
|
418
420
|
* ```ts
|
|
419
|
-
* const
|
|
420
|
-
*
|
|
421
|
-
* // cased[0].name === 'petId'
|
|
421
|
+
* const children = getChildren(operationNode, true)
|
|
422
|
+
* // returns parameters, requestBody schema (if present), and responses
|
|
422
423
|
* ```
|
|
423
424
|
*/
|
|
424
|
-
function
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
return
|
|
429
|
-
...
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
425
|
+
function getChildren(node, recurse) {
|
|
426
|
+
switch (node.kind) {
|
|
427
|
+
case "Input": return [...node.schemas, ...node.operations];
|
|
428
|
+
case "Output": return [];
|
|
429
|
+
case "Operation": return [
|
|
430
|
+
...node.parameters,
|
|
431
|
+
...node.requestBody?.content?.flatMap((c) => c.schema ? [c.schema] : []) ?? [],
|
|
432
|
+
...node.responses
|
|
433
|
+
];
|
|
434
|
+
case "Schema": {
|
|
435
|
+
const children = [];
|
|
436
|
+
if (!recurse) return [];
|
|
437
|
+
if ("properties" in node && node.properties.length > 0) children.push(...node.properties);
|
|
438
|
+
if ("items" in node && node.items) children.push(...node.items);
|
|
439
|
+
if ("members" in node && node.members) children.push(...node.members);
|
|
440
|
+
if ("additionalProperties" in node && node.additionalProperties && node.additionalProperties !== true) children.push(node.additionalProperties);
|
|
441
|
+
return children;
|
|
442
|
+
}
|
|
443
|
+
case "Property": return [node.schema];
|
|
444
|
+
case "Parameter": return [node.schema];
|
|
445
|
+
case "Response": return node.schema ? [node.schema] : [];
|
|
446
|
+
case "FunctionParameter":
|
|
447
|
+
case "ParameterGroup":
|
|
448
|
+
case "FunctionParameters":
|
|
449
|
+
case "Type": return [];
|
|
450
|
+
default: return [];
|
|
451
|
+
}
|
|
433
452
|
}
|
|
434
453
|
/**
|
|
435
|
-
*
|
|
454
|
+
* Depth-first traversal for side effects. Visitor return values are ignored.
|
|
455
|
+
* Sibling nodes at each level are visited concurrently up to `options.concurrency`
|
|
456
|
+
* (default: `WALK_CONCURRENCY`).
|
|
436
457
|
*
|
|
437
458
|
* @example
|
|
438
459
|
* ```ts
|
|
439
|
-
*
|
|
440
|
-
*
|
|
460
|
+
* await walk(root, {
|
|
461
|
+
* operation(node) {
|
|
462
|
+
* console.log(node.operationId)
|
|
463
|
+
* },
|
|
464
|
+
* })
|
|
441
465
|
* ```
|
|
442
|
-
*/
|
|
443
|
-
function createDiscriminantNode({ propertyName, value }) {
|
|
444
|
-
return createSchema({
|
|
445
|
-
type: "object",
|
|
446
|
-
primitive: "object",
|
|
447
|
-
properties: [createProperty({
|
|
448
|
-
name: propertyName,
|
|
449
|
-
schema: createSchema({
|
|
450
|
-
type: "enum",
|
|
451
|
-
primitive: "string",
|
|
452
|
-
enumValues: [value]
|
|
453
|
-
}),
|
|
454
|
-
required: true
|
|
455
|
-
})]
|
|
456
|
-
});
|
|
457
|
-
}
|
|
458
|
-
function resolveParamsType({ node, param, resolver }) {
|
|
459
|
-
if (!resolver) return createParamsType({
|
|
460
|
-
variant: "reference",
|
|
461
|
-
name: param.schema.primitive ?? "unknown"
|
|
462
|
-
});
|
|
463
|
-
const individualName = resolver.resolveParamName(node, param);
|
|
464
|
-
const groupLocation = param.in === "path" || param.in === "query" || param.in === "header" ? param.in : void 0;
|
|
465
|
-
const groupResolvers = {
|
|
466
|
-
path: resolver.resolvePathParamsName,
|
|
467
|
-
query: resolver.resolveQueryParamsName,
|
|
468
|
-
header: resolver.resolveHeaderParamsName
|
|
469
|
-
};
|
|
470
|
-
const groupName = groupLocation ? groupResolvers[groupLocation].call(resolver, node, param) : void 0;
|
|
471
|
-
if (groupName && groupName !== individualName) return createParamsType({
|
|
472
|
-
variant: "member",
|
|
473
|
-
base: groupName,
|
|
474
|
-
key: param.name
|
|
475
|
-
});
|
|
476
|
-
return createParamsType({
|
|
477
|
-
variant: "reference",
|
|
478
|
-
name: individualName
|
|
479
|
-
});
|
|
480
|
-
}
|
|
481
|
-
/**
|
|
482
|
-
* Converts an {@link OperationNode} into a {@link FunctionParametersNode}.
|
|
483
|
-
*
|
|
484
|
-
* Centralizes the per-plugin `getParams()` pattern. Provide a `resolver` for
|
|
485
|
-
* type resolution and `extraParams` for plugin-specific trailing parameters.
|
|
486
466
|
*
|
|
487
467
|
* @example
|
|
488
468
|
* ```ts
|
|
489
|
-
*
|
|
490
|
-
*
|
|
491
|
-
* pathParamsType: 'inline',
|
|
492
|
-
* resolver: tsResolver,
|
|
493
|
-
* extraParams: [createFunctionParameter({ name: 'options', type: createParamsType({ variant: 'reference', name: 'Partial<RequestOptions>' }), default: '{}' })],
|
|
494
|
-
* })
|
|
469
|
+
* // Visit only the current node
|
|
470
|
+
* await walk(root, { depth: 'shallow', root: () => {} })
|
|
495
471
|
* ```
|
|
496
472
|
*/
|
|
497
|
-
function
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
473
|
+
async function walk(node, options) {
|
|
474
|
+
return _walk(node, options, (options.depth ?? visitorDepths.deep) === visitorDepths.deep, createLimit(options.concurrency ?? 30), void 0);
|
|
475
|
+
}
|
|
476
|
+
async function _walk(node, visitor, recurse, limit, parent) {
|
|
477
|
+
switch (node.kind) {
|
|
478
|
+
case "Input":
|
|
479
|
+
await limit(() => visitor.input?.(node, { parent }));
|
|
480
|
+
break;
|
|
481
|
+
case "Output":
|
|
482
|
+
await limit(() => visitor.output?.(node, { parent }));
|
|
483
|
+
break;
|
|
484
|
+
case "Operation":
|
|
485
|
+
await limit(() => visitor.operation?.(node, { parent }));
|
|
486
|
+
break;
|
|
487
|
+
case "Schema":
|
|
488
|
+
await limit(() => visitor.schema?.(node, { parent }));
|
|
489
|
+
break;
|
|
490
|
+
case "Property":
|
|
491
|
+
await limit(() => visitor.property?.(node, { parent }));
|
|
492
|
+
break;
|
|
493
|
+
case "Parameter":
|
|
494
|
+
await limit(() => visitor.parameter?.(node, { parent }));
|
|
495
|
+
break;
|
|
496
|
+
case "Response":
|
|
497
|
+
await limit(() => visitor.response?.(node, { parent }));
|
|
498
|
+
break;
|
|
499
|
+
case "FunctionParameter":
|
|
500
|
+
case "ParameterGroup":
|
|
501
|
+
case "FunctionParameters": break;
|
|
502
|
+
}
|
|
503
|
+
const children = getChildren(node, recurse);
|
|
504
|
+
for (const child of children) await _walk(child, visitor, recurse, limit, node);
|
|
505
|
+
}
|
|
506
|
+
function transform(node, options) {
|
|
507
|
+
const { depth, parent, ...visitor } = options;
|
|
508
|
+
const recurse = (depth ?? visitorDepths.deep) === visitorDepths.deep;
|
|
509
|
+
switch (node.kind) {
|
|
510
|
+
case "Input": {
|
|
511
|
+
let input = node;
|
|
512
|
+
const replaced = visitor.input?.(input, { parent });
|
|
513
|
+
if (replaced) input = replaced;
|
|
514
|
+
return {
|
|
515
|
+
...input,
|
|
516
|
+
schemas: input.schemas.map((s) => transform(s, {
|
|
517
|
+
...options,
|
|
518
|
+
parent: input
|
|
519
|
+
})),
|
|
520
|
+
operations: input.operations.map((op) => transform(op, {
|
|
521
|
+
...options,
|
|
522
|
+
parent: input
|
|
523
|
+
}))
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
case "Output": {
|
|
527
|
+
let output = node;
|
|
528
|
+
const replaced = visitor.output?.(output, { parent });
|
|
529
|
+
if (replaced) output = replaced;
|
|
530
|
+
return output;
|
|
531
|
+
}
|
|
532
|
+
case "Operation": {
|
|
533
|
+
let op = node;
|
|
534
|
+
const replaced = visitor.operation?.(op, { parent });
|
|
535
|
+
if (replaced) op = replaced;
|
|
536
|
+
return {
|
|
537
|
+
...op,
|
|
538
|
+
parameters: op.parameters.map((p) => transform(p, {
|
|
539
|
+
...options,
|
|
540
|
+
parent: op
|
|
541
|
+
})),
|
|
542
|
+
requestBody: op.requestBody ? {
|
|
543
|
+
...op.requestBody,
|
|
544
|
+
content: op.requestBody.content?.map((c) => ({
|
|
545
|
+
...c,
|
|
546
|
+
schema: c.schema ? transform(c.schema, {
|
|
547
|
+
...options,
|
|
548
|
+
parent: op
|
|
549
|
+
}) : void 0
|
|
550
|
+
}))
|
|
551
|
+
} : void 0,
|
|
552
|
+
responses: op.responses.map((r) => transform(r, {
|
|
553
|
+
...options,
|
|
554
|
+
parent: op
|
|
555
|
+
}))
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
case "Schema": {
|
|
559
|
+
let schema = node;
|
|
560
|
+
const replaced = visitor.schema?.(schema, { parent });
|
|
561
|
+
if (replaced) schema = replaced;
|
|
562
|
+
const childOptions = {
|
|
563
|
+
...options,
|
|
564
|
+
parent: schema
|
|
565
|
+
};
|
|
566
|
+
return {
|
|
567
|
+
...schema,
|
|
568
|
+
..."properties" in schema && recurse ? { properties: schema.properties.map((p) => transform(p, childOptions)) } : {},
|
|
569
|
+
..."items" in schema && recurse ? { items: schema.items?.map((i) => transform(i, childOptions)) } : {},
|
|
570
|
+
..."members" in schema && recurse ? { members: schema.members?.map((m) => transform(m, childOptions)) } : {},
|
|
571
|
+
..."additionalProperties" in schema && recurse && schema.additionalProperties && schema.additionalProperties !== true ? { additionalProperties: transform(schema.additionalProperties, childOptions) } : {}
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
case "Property": {
|
|
575
|
+
let prop = node;
|
|
576
|
+
const replaced = visitor.property?.(prop, { parent });
|
|
577
|
+
if (replaced) prop = replaced;
|
|
578
|
+
return createProperty({
|
|
579
|
+
...prop,
|
|
580
|
+
schema: transform(prop.schema, {
|
|
581
|
+
...options,
|
|
582
|
+
parent: prop
|
|
583
|
+
})
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
case "Parameter": {
|
|
587
|
+
let param = node;
|
|
588
|
+
const replaced = visitor.parameter?.(param, { parent });
|
|
589
|
+
if (replaced) param = replaced;
|
|
590
|
+
return createParameter({
|
|
591
|
+
...param,
|
|
592
|
+
schema: transform(param.schema, {
|
|
593
|
+
...options,
|
|
594
|
+
parent: param
|
|
595
|
+
})
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
case "Response": {
|
|
599
|
+
let response = node;
|
|
600
|
+
const replaced = visitor.response?.(response, { parent });
|
|
601
|
+
if (replaced) response = replaced;
|
|
602
|
+
return {
|
|
603
|
+
...response,
|
|
604
|
+
schema: transform(response.schema, {
|
|
605
|
+
...options,
|
|
606
|
+
parent: response
|
|
607
|
+
})
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
|
+
case "FunctionParameter":
|
|
611
|
+
case "ParameterGroup":
|
|
612
|
+
case "FunctionParameters":
|
|
613
|
+
case "Type": return node;
|
|
614
|
+
default: return node;
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
/**
|
|
618
|
+
* Runs a depth-first synchronous collection pass.
|
|
619
|
+
*
|
|
620
|
+
* Non-`undefined` values returned by visitor callbacks are appended to the result.
|
|
621
|
+
*
|
|
622
|
+
* @example
|
|
623
|
+
* ```ts
|
|
624
|
+
* const ids = collect(root, {
|
|
625
|
+
* operation(node) {
|
|
626
|
+
* return node.operationId
|
|
627
|
+
* },
|
|
628
|
+
* })
|
|
629
|
+
* ```
|
|
630
|
+
*
|
|
631
|
+
* @example
|
|
632
|
+
* ```ts
|
|
633
|
+
* // Collect from only the current node
|
|
634
|
+
* const values = collect(root, { depth: 'shallow', root: () => 'root' })
|
|
635
|
+
* ```
|
|
636
|
+
*/
|
|
637
|
+
function collect(node, options) {
|
|
638
|
+
const { depth, parent, ...visitor } = options;
|
|
639
|
+
const recurse = (depth ?? visitorDepths.deep) === visitorDepths.deep;
|
|
640
|
+
const results = [];
|
|
641
|
+
let v;
|
|
642
|
+
switch (node.kind) {
|
|
643
|
+
case "Input":
|
|
644
|
+
v = visitor.input?.(node, { parent });
|
|
645
|
+
break;
|
|
646
|
+
case "Output":
|
|
647
|
+
v = visitor.output?.(node, { parent });
|
|
648
|
+
break;
|
|
649
|
+
case "Operation":
|
|
650
|
+
v = visitor.operation?.(node, { parent });
|
|
651
|
+
break;
|
|
652
|
+
case "Schema":
|
|
653
|
+
v = visitor.schema?.(node, { parent });
|
|
654
|
+
break;
|
|
655
|
+
case "Property":
|
|
656
|
+
v = visitor.property?.(node, { parent });
|
|
657
|
+
break;
|
|
658
|
+
case "Parameter":
|
|
659
|
+
v = visitor.parameter?.(node, { parent });
|
|
660
|
+
break;
|
|
661
|
+
case "Response":
|
|
662
|
+
v = visitor.response?.(node, { parent });
|
|
663
|
+
break;
|
|
664
|
+
case "FunctionParameter":
|
|
665
|
+
case "ParameterGroup":
|
|
666
|
+
case "FunctionParameters": break;
|
|
667
|
+
}
|
|
668
|
+
if (v !== void 0) results.push(v);
|
|
669
|
+
for (const child of getChildren(node, recurse)) for (const item of collect(child, {
|
|
670
|
+
...options,
|
|
671
|
+
parent: node
|
|
672
|
+
})) results.push(item);
|
|
673
|
+
return results;
|
|
674
|
+
}
|
|
675
|
+
//#endregion
|
|
676
|
+
//#region src/utils.ts
|
|
677
|
+
const plainStringTypes = new Set([
|
|
678
|
+
"string",
|
|
679
|
+
"uuid",
|
|
680
|
+
"email",
|
|
681
|
+
"url",
|
|
682
|
+
"datetime"
|
|
683
|
+
]);
|
|
684
|
+
/**
|
|
685
|
+
* Returns a merged schema view for a ref node, combining the resolved `node.schema`
|
|
686
|
+
* (base from the referenced definition) with any usage-site sibling fields set directly
|
|
687
|
+
* on the ref node (description, readOnly, nullable, deprecated, etc.).
|
|
688
|
+
*
|
|
689
|
+
* Usage-site fields take precedence over the resolved schema's own fields when both are defined.
|
|
690
|
+
*
|
|
691
|
+
* For non-ref nodes the node itself is returned unchanged.
|
|
692
|
+
*/
|
|
693
|
+
function syncSchemaRef(node) {
|
|
694
|
+
const ref = narrowSchema(node, "ref");
|
|
695
|
+
if (!ref) return node;
|
|
696
|
+
if (!ref.schema) return node;
|
|
697
|
+
const { kind: _kind, type: _type, name: _name, ref: _ref, schema: _schema, ...overrides } = ref;
|
|
698
|
+
const definedOverrides = Object.fromEntries(Object.entries(overrides).filter(([, v]) => v !== void 0));
|
|
699
|
+
return createSchema({
|
|
700
|
+
...ref.schema,
|
|
701
|
+
...definedOverrides
|
|
702
|
+
});
|
|
703
|
+
}
|
|
704
|
+
/**
|
|
705
|
+
* Returns `true` when a schema is emitted as a plain `string` type.
|
|
706
|
+
*
|
|
707
|
+
* - `string`, `uuid`, `email`, `url`, `datetime` are always plain strings.
|
|
708
|
+
* - `date` and `time` are plain strings when their `representation` is `'string'` rather than `'date'`.
|
|
709
|
+
*
|
|
710
|
+
* @example
|
|
711
|
+
* ```ts
|
|
712
|
+
* isStringType(createSchema({ type: 'uuid' })) // true
|
|
713
|
+
* isStringType(createSchema({ type: 'date', representation: 'date' })) // false
|
|
714
|
+
* ```
|
|
715
|
+
*/
|
|
716
|
+
function isStringType(node) {
|
|
717
|
+
if (plainStringTypes.has(node.type)) return true;
|
|
718
|
+
const temporal = narrowSchema(node, "date") ?? narrowSchema(node, "time");
|
|
719
|
+
if (temporal) return temporal.representation !== "date";
|
|
720
|
+
return false;
|
|
721
|
+
}
|
|
722
|
+
/**
|
|
723
|
+
* Applies casing rules to parameter names and returns a new parameter array.
|
|
724
|
+
*
|
|
725
|
+
* The input array is not mutated.
|
|
726
|
+
* If `casing` is not set, the original array is returned unchanged.
|
|
727
|
+
*
|
|
728
|
+
* Use this before passing parameters to schema builders so that property keys
|
|
729
|
+
* in generated output match the desired casing while preserving
|
|
730
|
+
* `OperationNode.parameters` for other consumers.
|
|
731
|
+
*
|
|
732
|
+
* @example
|
|
733
|
+
* ```ts
|
|
734
|
+
* const params = [createParameter({ name: 'pet_id', in: 'query', schema: createSchema({ type: 'string' }) })]
|
|
735
|
+
* const cased = caseParams(params, 'camelcase')
|
|
736
|
+
* // cased[0].name === 'petId'
|
|
737
|
+
* ```
|
|
738
|
+
*/
|
|
739
|
+
function caseParams(params, casing) {
|
|
740
|
+
if (!casing) return params;
|
|
741
|
+
return params.map((param) => {
|
|
742
|
+
const transformed = casing === "camelcase" || !isValidVarName(param.name) ? camelCase(param.name) : param.name;
|
|
743
|
+
return {
|
|
744
|
+
...param,
|
|
745
|
+
name: transformed
|
|
746
|
+
};
|
|
747
|
+
});
|
|
748
|
+
}
|
|
749
|
+
/**
|
|
750
|
+
* Creates a single-property object schema used as a discriminator literal.
|
|
751
|
+
*
|
|
752
|
+
* @example
|
|
753
|
+
* ```ts
|
|
754
|
+
* createDiscriminantNode({ propertyName: 'type', value: 'dog' })
|
|
755
|
+
* // -> { type: 'object', properties: [{ name: 'type', required: true, schema: enum('dog') }] }
|
|
756
|
+
* ```
|
|
757
|
+
*/
|
|
758
|
+
function createDiscriminantNode({ propertyName, value }) {
|
|
759
|
+
return createSchema({
|
|
760
|
+
type: "object",
|
|
761
|
+
primitive: "object",
|
|
762
|
+
properties: [createProperty({
|
|
763
|
+
name: propertyName,
|
|
764
|
+
schema: createSchema({
|
|
765
|
+
type: "enum",
|
|
766
|
+
primitive: "string",
|
|
767
|
+
enumValues: [value]
|
|
768
|
+
}),
|
|
769
|
+
required: true
|
|
770
|
+
})]
|
|
771
|
+
});
|
|
772
|
+
}
|
|
773
|
+
function resolveParamsType({ node, param, resolver }) {
|
|
774
|
+
if (!resolver) return createParamsType({
|
|
775
|
+
variant: "reference",
|
|
776
|
+
name: param.schema.primitive ?? "unknown"
|
|
777
|
+
});
|
|
778
|
+
const individualName = resolver.resolveParamName(node, param);
|
|
779
|
+
const groupLocation = param.in === "path" || param.in === "query" || param.in === "header" ? param.in : void 0;
|
|
780
|
+
const groupResolvers = {
|
|
781
|
+
path: resolver.resolvePathParamsName,
|
|
782
|
+
query: resolver.resolveQueryParamsName,
|
|
783
|
+
header: resolver.resolveHeaderParamsName
|
|
784
|
+
};
|
|
785
|
+
const groupName = groupLocation ? groupResolvers[groupLocation].call(resolver, node, param) : void 0;
|
|
786
|
+
if (groupName && groupName !== individualName) return createParamsType({
|
|
787
|
+
variant: "member",
|
|
788
|
+
base: groupName,
|
|
789
|
+
key: param.name
|
|
790
|
+
});
|
|
791
|
+
return createParamsType({
|
|
792
|
+
variant: "reference",
|
|
793
|
+
name: individualName
|
|
794
|
+
});
|
|
795
|
+
}
|
|
796
|
+
/**
|
|
797
|
+
* Converts an {@link OperationNode} into a {@link FunctionParametersNode}.
|
|
798
|
+
*
|
|
799
|
+
* Centralizes the per-plugin `getParams()` pattern. Provide a `resolver` for
|
|
800
|
+
* type resolution and `extraParams` for plugin-specific trailing parameters.
|
|
801
|
+
*
|
|
802
|
+
* @example
|
|
803
|
+
* ```ts
|
|
804
|
+
* const params = createOperationParams(node, {
|
|
805
|
+
* paramsType: 'inline',
|
|
806
|
+
* pathParamsType: 'inline',
|
|
807
|
+
* resolver: tsResolver,
|
|
808
|
+
* extraParams: [createFunctionParameter({ name: 'options', type: createParamsType({ variant: 'reference', name: 'Partial<RequestOptions>' }), default: '{}' })],
|
|
809
|
+
* })
|
|
810
|
+
* ```
|
|
811
|
+
*/
|
|
812
|
+
function createOperationParams(node, options) {
|
|
813
|
+
const { paramsType, pathParamsType, paramsCasing, resolver, pathParamsDefault, extraParams = [], paramNames, typeWrapper } = options;
|
|
814
|
+
const dataName = paramNames?.data ?? "data";
|
|
815
|
+
const paramsName = paramNames?.params ?? "params";
|
|
816
|
+
const headersName = paramNames?.headers ?? "headers";
|
|
817
|
+
const pathName = paramNames?.path ?? "pathParams";
|
|
818
|
+
const wrapType = (type) => createParamsType({
|
|
819
|
+
variant: "reference",
|
|
820
|
+
name: typeWrapper ? typeWrapper(type) : type
|
|
821
|
+
});
|
|
822
|
+
const wrapTypeNode = (type) => type.kind === "ParamsType" && type.variant === "reference" ? wrapType(type.name) : type;
|
|
823
|
+
const casedParams = caseParams(node.parameters, paramsCasing);
|
|
824
|
+
const pathParams = casedParams.filter((p) => p.in === "path");
|
|
825
|
+
const queryParams = casedParams.filter((p) => p.in === "query");
|
|
826
|
+
const headerParams = casedParams.filter((p) => p.in === "header");
|
|
827
|
+
const bodyType = node.requestBody?.content?.[0]?.schema ? wrapType(resolver?.resolveDataName(node) ?? "unknown") : void 0;
|
|
828
|
+
const bodyRequired = node.requestBody?.required ?? false;
|
|
829
|
+
const queryGroupType = resolver ? resolveGroupType({
|
|
830
|
+
node,
|
|
831
|
+
params: queryParams,
|
|
832
|
+
groupMethod: resolver.resolveQueryParamsName,
|
|
833
|
+
resolver
|
|
834
|
+
}) : void 0;
|
|
835
|
+
const headerGroupType = resolver ? resolveGroupType({
|
|
836
|
+
node,
|
|
837
|
+
params: headerParams,
|
|
838
|
+
groupMethod: resolver.resolveHeaderParamsName,
|
|
839
|
+
resolver
|
|
840
|
+
}) : void 0;
|
|
841
|
+
const params = [];
|
|
842
|
+
if (paramsType === "object") {
|
|
843
|
+
const children = [
|
|
844
|
+
...pathParams.map((p) => {
|
|
845
|
+
const type = resolveParamsType({
|
|
846
|
+
node,
|
|
847
|
+
param: p,
|
|
848
|
+
resolver
|
|
849
|
+
});
|
|
850
|
+
return createFunctionParameter({
|
|
851
|
+
name: p.name,
|
|
852
|
+
type: wrapTypeNode(type),
|
|
853
|
+
optional: !p.required
|
|
854
|
+
});
|
|
855
|
+
}),
|
|
856
|
+
...bodyType ? [createFunctionParameter({
|
|
857
|
+
name: dataName,
|
|
858
|
+
type: bodyType,
|
|
859
|
+
optional: !bodyRequired
|
|
860
|
+
})] : [],
|
|
861
|
+
...buildGroupParam({
|
|
862
|
+
name: paramsName,
|
|
863
|
+
node,
|
|
864
|
+
params: queryParams,
|
|
865
|
+
groupType: queryGroupType,
|
|
866
|
+
resolver,
|
|
867
|
+
wrapType
|
|
868
|
+
}),
|
|
869
|
+
...buildGroupParam({
|
|
870
|
+
name: headersName,
|
|
871
|
+
node,
|
|
872
|
+
params: headerParams,
|
|
873
|
+
groupType: headerGroupType,
|
|
874
|
+
resolver,
|
|
875
|
+
wrapType
|
|
876
|
+
})
|
|
877
|
+
];
|
|
878
|
+
if (children.length) params.push(createParameterGroup({
|
|
879
|
+
properties: children,
|
|
880
|
+
default: children.every((c) => c.optional) ? "{}" : void 0
|
|
881
|
+
}));
|
|
567
882
|
} else {
|
|
568
883
|
if (pathParams.length) if (pathParamsType === "inlineSpread") {
|
|
569
884
|
const spreadType = resolver?.resolvePathParamsName(node, pathParams[0]) ?? void 0;
|
|
@@ -827,6 +1142,114 @@ function extractStringsFromNodes(nodes) {
|
|
|
827
1142
|
return parts.join("\n");
|
|
828
1143
|
}).filter(Boolean).join("\n");
|
|
829
1144
|
}
|
|
1145
|
+
/**
|
|
1146
|
+
* Resolves the referenced schema name of a `ref` node, falling back through
|
|
1147
|
+
* `ref` → `name` → nested `schema.name`. Returns `undefined` for non-ref
|
|
1148
|
+
* nodes or when no name can be resolved.
|
|
1149
|
+
*
|
|
1150
|
+
* @example
|
|
1151
|
+
* ```ts
|
|
1152
|
+
* resolveRefName({ kind: 'Schema', type: 'ref', ref: '#/components/schemas/Pet' })
|
|
1153
|
+
* // => 'Pet'
|
|
1154
|
+
* ```
|
|
1155
|
+
*/
|
|
1156
|
+
function resolveRefName(node) {
|
|
1157
|
+
if (!node || node.type !== "ref") return void 0;
|
|
1158
|
+
if (node.ref) return extractRefName(node.ref) ?? node.name ?? node.schema?.name ?? void 0;
|
|
1159
|
+
return node.name ?? node.schema?.name ?? void 0;
|
|
1160
|
+
}
|
|
1161
|
+
/**
|
|
1162
|
+
* Recursively collects every named schema referenced (transitively) from
|
|
1163
|
+
* `node` via `ref` edges. Refs are followed by name only — the resolved
|
|
1164
|
+
* `node.schema` of a ref is not traversed inline.
|
|
1165
|
+
*
|
|
1166
|
+
* @example
|
|
1167
|
+
* ```ts
|
|
1168
|
+
* const refs = collectReferencedSchemaNames(petSchema)
|
|
1169
|
+
* // => Set { 'Cat', 'Dog' }
|
|
1170
|
+
* ```
|
|
1171
|
+
*/
|
|
1172
|
+
function collectReferencedSchemaNames(node, out = /* @__PURE__ */ new Set()) {
|
|
1173
|
+
if (!node) return out;
|
|
1174
|
+
collect(node, { schema(child) {
|
|
1175
|
+
if (child.type === "ref") {
|
|
1176
|
+
const name = resolveRefName(child);
|
|
1177
|
+
if (name) out.add(name);
|
|
1178
|
+
}
|
|
1179
|
+
} });
|
|
1180
|
+
return out;
|
|
1181
|
+
}
|
|
1182
|
+
/**
|
|
1183
|
+
* Identifies every named schema that participates in a circular dependency
|
|
1184
|
+
* chain — including direct self-loops (e.g. `TreeNode → TreeNode`) and indirect
|
|
1185
|
+
* cycles spanning multiple schemas (e.g. `Pet → Cat → Pet`).
|
|
1186
|
+
*
|
|
1187
|
+
* The returned set contains schema names. Plugins that translate schemas into
|
|
1188
|
+
* a host language can use this to wrap recursive positions in a deferred
|
|
1189
|
+
* construct (lazy getter, `z.lazy(() => …)`, etc.) and avoid runtime stack
|
|
1190
|
+
* overflows when the generated code is executed.
|
|
1191
|
+
*
|
|
1192
|
+
* Refs are followed by name only — `node.schema` (the resolved referent) is
|
|
1193
|
+
* not traversed inline, which keeps the algorithm linear in the size of the
|
|
1194
|
+
* schema graph.
|
|
1195
|
+
*
|
|
1196
|
+
* @example
|
|
1197
|
+
* ```ts
|
|
1198
|
+
* const circular = findCircularSchemas(inputNode.schemas)
|
|
1199
|
+
* if (circular.has('Pet')) {
|
|
1200
|
+
* // emit lazy wrapper for any property whose schema references Pet
|
|
1201
|
+
* }
|
|
1202
|
+
* ```
|
|
1203
|
+
*/
|
|
1204
|
+
function findCircularSchemas(schemas) {
|
|
1205
|
+
const graph = /* @__PURE__ */ new Map();
|
|
1206
|
+
for (const schema of schemas) {
|
|
1207
|
+
if (!schema.name) continue;
|
|
1208
|
+
graph.set(schema.name, collectReferencedSchemaNames(schema));
|
|
1209
|
+
}
|
|
1210
|
+
const circular = /* @__PURE__ */ new Set();
|
|
1211
|
+
for (const start of graph.keys()) {
|
|
1212
|
+
const visited = /* @__PURE__ */ new Set();
|
|
1213
|
+
const stack = [...graph.get(start) ?? []];
|
|
1214
|
+
while (stack.length > 0) {
|
|
1215
|
+
const node = stack.pop();
|
|
1216
|
+
if (node === start) {
|
|
1217
|
+
circular.add(start);
|
|
1218
|
+
break;
|
|
1219
|
+
}
|
|
1220
|
+
if (visited.has(node)) continue;
|
|
1221
|
+
visited.add(node);
|
|
1222
|
+
const next = graph.get(node);
|
|
1223
|
+
if (next) for (const r of next) stack.push(r);
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
return circular;
|
|
1227
|
+
}
|
|
1228
|
+
/**
|
|
1229
|
+
* Returns true when `node` (or anything nested within it) carries a `ref`
|
|
1230
|
+
* whose resolved name belongs to `circularSchemas`.
|
|
1231
|
+
*
|
|
1232
|
+
* When `excludeName` is provided, refs to that name are ignored — useful
|
|
1233
|
+
* when self-references are already handled separately from cross-schema
|
|
1234
|
+
* cycles (e.g. the faker plugin emits `undefined as any` for direct
|
|
1235
|
+
* self-recursion but a lazy getter for indirect cycles).
|
|
1236
|
+
*
|
|
1237
|
+
* @example
|
|
1238
|
+
* ```ts
|
|
1239
|
+
* const circular = findCircularSchemas(schemas)
|
|
1240
|
+
* if (containsCircularRef(property.schema, { circularSchemas: circular, excludeName: 'Pet' })) {
|
|
1241
|
+
* // emit `get foo() { return fakeCat() }` instead of eager call
|
|
1242
|
+
* }
|
|
1243
|
+
* ```
|
|
1244
|
+
*/
|
|
1245
|
+
function containsCircularRef(node, { circularSchemas, excludeName }) {
|
|
1246
|
+
if (!node || circularSchemas.size === 0) return false;
|
|
1247
|
+
return collect(node, { schema(child) {
|
|
1248
|
+
if (child.type !== "ref") return void 0;
|
|
1249
|
+
const name = resolveRefName(child);
|
|
1250
|
+
return name && name !== excludeName && circularSchemas.has(name) ? true : void 0;
|
|
1251
|
+
} }).length > 0;
|
|
1252
|
+
}
|
|
830
1253
|
//#endregion
|
|
831
1254
|
//#region src/factory.ts
|
|
832
1255
|
/**
|
|
@@ -1295,545 +1718,230 @@ function createFile(input) {
|
|
|
1295
1718
|
*/
|
|
1296
1719
|
function createConst(props) {
|
|
1297
1720
|
return {
|
|
1298
|
-
...props,
|
|
1299
|
-
kind: "Const"
|
|
1300
|
-
};
|
|
1301
|
-
}
|
|
1302
|
-
/**
|
|
1303
|
-
* Creates a `TypeNode` representing a TypeScript `type` alias declaration.
|
|
1304
|
-
*
|
|
1305
|
-
* Mirrors the `Type` component from `@kubb/renderer-jsx`.
|
|
1306
|
-
* The component's `children` are represented as `nodes`.
|
|
1307
|
-
*
|
|
1308
|
-
* @example Simple type alias
|
|
1309
|
-
* ```ts
|
|
1310
|
-
* createType({ name: 'Pet' })
|
|
1311
|
-
* // type Pet = ...
|
|
1312
|
-
* ```
|
|
1313
|
-
*
|
|
1314
|
-
* @example Exported type with JSDoc
|
|
1315
|
-
* ```ts
|
|
1316
|
-
* createType({
|
|
1317
|
-
* name: 'PetStatus',
|
|
1318
|
-
* export: true,
|
|
1319
|
-
* JSDoc: { comments: ['@description Status of a pet'] },
|
|
1320
|
-
* })
|
|
1321
|
-
* // export type PetStatus = ...
|
|
1322
|
-
* ```
|
|
1323
|
-
*/
|
|
1324
|
-
function createType(props) {
|
|
1325
|
-
return {
|
|
1326
|
-
...props,
|
|
1327
|
-
kind: "Type"
|
|
1328
|
-
};
|
|
1329
|
-
}
|
|
1330
|
-
/**
|
|
1331
|
-
* Creates a `FunctionNode` representing a TypeScript `function` declaration.
|
|
1332
|
-
*
|
|
1333
|
-
* Mirrors the `Function` component from `@kubb/renderer-jsx`.
|
|
1334
|
-
* The component's `children` are represented as `nodes`.
|
|
1335
|
-
*
|
|
1336
|
-
* @example Simple function
|
|
1337
|
-
* ```ts
|
|
1338
|
-
* createFunction({ name: 'getPet' })
|
|
1339
|
-
* // function getPet() { ... }
|
|
1340
|
-
* ```
|
|
1341
|
-
*
|
|
1342
|
-
* @example Exported async function with return type
|
|
1343
|
-
* ```ts
|
|
1344
|
-
* createFunction({ name: 'fetchPet', export: true, async: true, returnType: 'Pet' })
|
|
1345
|
-
* // export async function fetchPet(): Promise<Pet> { ... }
|
|
1346
|
-
* ```
|
|
1347
|
-
*
|
|
1348
|
-
* @example Function with generics and params
|
|
1349
|
-
* ```ts
|
|
1350
|
-
* createFunction({
|
|
1351
|
-
* name: 'identity',
|
|
1352
|
-
* export: true,
|
|
1353
|
-
* generics: ['T'],
|
|
1354
|
-
* params: 'value: T',
|
|
1355
|
-
* returnType: 'T',
|
|
1356
|
-
* })
|
|
1357
|
-
* // export function identity<T>(value: T): T { ... }
|
|
1358
|
-
* ```
|
|
1359
|
-
*/
|
|
1360
|
-
function createFunction(props) {
|
|
1361
|
-
return {
|
|
1362
|
-
...props,
|
|
1363
|
-
kind: "Function"
|
|
1364
|
-
};
|
|
1365
|
-
}
|
|
1366
|
-
/**
|
|
1367
|
-
* Creates an `ArrowFunctionNode` representing a TypeScript arrow function.
|
|
1368
|
-
*
|
|
1369
|
-
* Mirrors the `Function.Arrow` component from `@kubb/renderer-jsx`.
|
|
1370
|
-
* The component's `children` are represented as `nodes`.
|
|
1371
|
-
*
|
|
1372
|
-
* @example Simple arrow function
|
|
1373
|
-
* ```ts
|
|
1374
|
-
* createArrowFunction({ name: 'getPet' })
|
|
1375
|
-
* // const getPet = () => { ... }
|
|
1376
|
-
* ```
|
|
1377
|
-
*
|
|
1378
|
-
* @example Single-line exported arrow function
|
|
1379
|
-
* ```ts
|
|
1380
|
-
* createArrowFunction({ name: 'double', export: true, params: 'n: number', singleLine: true })
|
|
1381
|
-
* // export const double = (n: number) => ...
|
|
1382
|
-
* ```
|
|
1383
|
-
*
|
|
1384
|
-
* @example Async arrow function with generics
|
|
1385
|
-
* ```ts
|
|
1386
|
-
* createArrowFunction({
|
|
1387
|
-
* name: 'fetchPet',
|
|
1388
|
-
* export: true,
|
|
1389
|
-
* async: true,
|
|
1390
|
-
* generics: ['T'],
|
|
1391
|
-
* params: 'id: string',
|
|
1392
|
-
* returnType: 'T',
|
|
1393
|
-
* })
|
|
1394
|
-
* // export const fetchPet = async <T>(id: string): Promise<T> => { ... }
|
|
1395
|
-
* ```
|
|
1396
|
-
*/
|
|
1397
|
-
function createArrowFunction(props) {
|
|
1398
|
-
return {
|
|
1399
|
-
...props,
|
|
1400
|
-
kind: "ArrowFunction"
|
|
1401
|
-
};
|
|
1402
|
-
}
|
|
1403
|
-
/**
|
|
1404
|
-
* Creates a {@link TextNode} representing a raw string fragment in the source output.
|
|
1405
|
-
*
|
|
1406
|
-
* Use this instead of bare strings when building `nodes` arrays so that every
|
|
1407
|
-
* entry in the array is a typed {@link CodeNode}.
|
|
1408
|
-
*
|
|
1409
|
-
* @example
|
|
1410
|
-
* ```ts
|
|
1411
|
-
* createText('return fetch(id)')
|
|
1412
|
-
* // { kind: 'Text', value: 'return fetch(id)' }
|
|
1413
|
-
* ```
|
|
1414
|
-
*/
|
|
1415
|
-
function createText(value) {
|
|
1416
|
-
return {
|
|
1417
|
-
value,
|
|
1418
|
-
kind: "Text"
|
|
1419
|
-
};
|
|
1420
|
-
}
|
|
1421
|
-
/**
|
|
1422
|
-
* Creates a {@link BreakNode} representing a line break in the source output.
|
|
1423
|
-
*
|
|
1424
|
-
* Corresponds to `<br/>` in JSX components. Prints as an empty string which,
|
|
1425
|
-
* when joined with `\n` by `printNodes`, produces a blank line.
|
|
1426
|
-
*
|
|
1427
|
-
* @example
|
|
1428
|
-
* ```ts
|
|
1429
|
-
* createBreak()
|
|
1430
|
-
* // { kind: 'Break' }
|
|
1431
|
-
* ```
|
|
1432
|
-
*/
|
|
1433
|
-
function createBreak() {
|
|
1434
|
-
return { kind: "Break" };
|
|
1435
|
-
}
|
|
1436
|
-
/**
|
|
1437
|
-
* Creates a {@link JsxNode} representing a raw JSX fragment in the source output.
|
|
1438
|
-
*
|
|
1439
|
-
* Use this to embed JSX markup (including fragments `<>…</>`) directly in generated code.
|
|
1440
|
-
*
|
|
1441
|
-
* @example
|
|
1442
|
-
* ```ts
|
|
1443
|
-
* createJsx('<>\n <a href={href}>Open</a>\n</>')
|
|
1444
|
-
* // { kind: 'Jsx', value: '<>\n <a href={href}>Open</a>\n</>' }
|
|
1445
|
-
* ```
|
|
1446
|
-
*/
|
|
1447
|
-
function createJsx(value) {
|
|
1448
|
-
return {
|
|
1449
|
-
value,
|
|
1450
|
-
kind: "Jsx"
|
|
1721
|
+
...props,
|
|
1722
|
+
kind: "Const"
|
|
1451
1723
|
};
|
|
1452
1724
|
}
|
|
1453
|
-
//#endregion
|
|
1454
|
-
//#region src/printer.ts
|
|
1455
1725
|
/**
|
|
1456
|
-
* Creates a
|
|
1457
|
-
*
|
|
1458
|
-
* This function wraps a builder and makes options optional at call sites.
|
|
1459
|
-
*
|
|
1460
|
-
* The builder receives resolved options and returns:
|
|
1461
|
-
* - `name` — a unique identifier for the printer
|
|
1462
|
-
* - `options` — options stored on the returned printer instance
|
|
1463
|
-
* - `nodes` — a map of `SchemaType` → handler functions that convert a `SchemaNode` to `TOutput`
|
|
1464
|
-
* - `print` _(optional)_ — top-level override exposed as `printer.print`
|
|
1465
|
-
* - Inside this function, use `this.transform(node)` to dispatch to the `nodes` map
|
|
1466
|
-
* - This keeps recursion safe and avoids self-calls
|
|
1726
|
+
* Creates a `TypeNode` representing a TypeScript `type` alias declaration.
|
|
1467
1727
|
*
|
|
1468
|
-
*
|
|
1728
|
+
* Mirrors the `Type` component from `@kubb/renderer-jsx`.
|
|
1729
|
+
* The component's `children` are represented as `nodes`.
|
|
1469
1730
|
*
|
|
1470
|
-
* @example
|
|
1731
|
+
* @example Simple type alias
|
|
1471
1732
|
* ```ts
|
|
1472
|
-
*
|
|
1473
|
-
*
|
|
1474
|
-
* export const zodPrinter = definePrinter<PrinterZod>((options) => ({
|
|
1475
|
-
* name: 'zod',
|
|
1476
|
-
* options: { strict: options.strict ?? true },
|
|
1477
|
-
* nodes: {
|
|
1478
|
-
* string: () => 'z.string()',
|
|
1479
|
-
* object(node) {
|
|
1480
|
-
* const props = node.properties.map(p => `${p.name}: ${this.transform(p.schema)}`).join(', ')
|
|
1481
|
-
* return `z.object({ ${props} })`
|
|
1482
|
-
* },
|
|
1483
|
-
* },
|
|
1484
|
-
* }))
|
|
1733
|
+
* createType({ name: 'Pet' })
|
|
1734
|
+
* // type Pet = ...
|
|
1485
1735
|
* ```
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
return createPrinterFactory((node) => node.type)(build);
|
|
1489
|
-
}
|
|
1490
|
-
/**
|
|
1491
|
-
* Generic printer-factory function used by `definePrinter` and `defineFunctionPrinter`.
|
|
1492
|
-
**
|
|
1493
|
-
* @example
|
|
1736
|
+
*
|
|
1737
|
+
* @example Exported type with JSDoc
|
|
1494
1738
|
* ```ts
|
|
1495
|
-
*
|
|
1496
|
-
*
|
|
1497
|
-
*
|
|
1739
|
+
* createType({
|
|
1740
|
+
* name: 'PetStatus',
|
|
1741
|
+
* export: true,
|
|
1742
|
+
* JSDoc: { comments: ['@description Status of a pet'] },
|
|
1743
|
+
* })
|
|
1744
|
+
* // export type PetStatus = ...
|
|
1498
1745
|
* ```
|
|
1499
1746
|
*/
|
|
1500
|
-
function
|
|
1501
|
-
return
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
const context = {
|
|
1505
|
-
options: resolvedOptions,
|
|
1506
|
-
transform: (node) => {
|
|
1507
|
-
const key = getKey(node);
|
|
1508
|
-
if (key === void 0) return null;
|
|
1509
|
-
const handler = nodes[key];
|
|
1510
|
-
if (!handler) return null;
|
|
1511
|
-
return handler.call(context, node);
|
|
1512
|
-
}
|
|
1513
|
-
};
|
|
1514
|
-
return {
|
|
1515
|
-
name,
|
|
1516
|
-
options: resolvedOptions,
|
|
1517
|
-
transform: context.transform,
|
|
1518
|
-
print: printOverride ? printOverride.bind(context) : context.transform
|
|
1519
|
-
};
|
|
1520
|
-
};
|
|
1747
|
+
function createType(props) {
|
|
1748
|
+
return {
|
|
1749
|
+
...props,
|
|
1750
|
+
kind: "Type"
|
|
1521
1751
|
};
|
|
1522
1752
|
}
|
|
1523
|
-
//#endregion
|
|
1524
|
-
//#region src/refs.ts
|
|
1525
1753
|
/**
|
|
1526
|
-
*
|
|
1754
|
+
* Creates a `FunctionNode` representing a TypeScript `function` declaration.
|
|
1527
1755
|
*
|
|
1528
|
-
*
|
|
1756
|
+
* Mirrors the `Function` component from `@kubb/renderer-jsx`.
|
|
1757
|
+
* The component's `children` are represented as `nodes`.
|
|
1529
1758
|
*
|
|
1530
|
-
* @example
|
|
1759
|
+
* @example Simple function
|
|
1531
1760
|
* ```ts
|
|
1532
|
-
*
|
|
1761
|
+
* createFunction({ name: 'getPet' })
|
|
1762
|
+
* // function getPet() { ... }
|
|
1533
1763
|
* ```
|
|
1534
|
-
*/
|
|
1535
|
-
function extractRefName(ref) {
|
|
1536
|
-
return ref.split("/").at(-1) ?? ref;
|
|
1537
|
-
}
|
|
1538
|
-
//#endregion
|
|
1539
|
-
//#region src/visitor.ts
|
|
1540
|
-
/**
|
|
1541
|
-
* Creates a small async concurrency limiter.
|
|
1542
1764
|
*
|
|
1543
|
-
*
|
|
1765
|
+
* @example Exported async function with return type
|
|
1766
|
+
* ```ts
|
|
1767
|
+
* createFunction({ name: 'fetchPet', export: true, async: true, returnType: 'Pet' })
|
|
1768
|
+
* // export async function fetchPet(): Promise<Pet> { ... }
|
|
1769
|
+
* ```
|
|
1544
1770
|
*
|
|
1545
|
-
* @example
|
|
1771
|
+
* @example Function with generics and params
|
|
1546
1772
|
* ```ts
|
|
1547
|
-
*
|
|
1548
|
-
*
|
|
1549
|
-
*
|
|
1550
|
-
*
|
|
1551
|
-
*
|
|
1773
|
+
* createFunction({
|
|
1774
|
+
* name: 'identity',
|
|
1775
|
+
* export: true,
|
|
1776
|
+
* generics: ['T'],
|
|
1777
|
+
* params: 'value: T',
|
|
1778
|
+
* returnType: 'T',
|
|
1779
|
+
* })
|
|
1780
|
+
* // export function identity<T>(value: T): T { ... }
|
|
1552
1781
|
* ```
|
|
1553
1782
|
*/
|
|
1554
|
-
function
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
if (active < concurrency && queue.length > 0) {
|
|
1559
|
-
active++;
|
|
1560
|
-
queue.shift()();
|
|
1561
|
-
}
|
|
1562
|
-
}
|
|
1563
|
-
return function limit(fn) {
|
|
1564
|
-
return new Promise((resolve, reject) => {
|
|
1565
|
-
queue.push(() => {
|
|
1566
|
-
Promise.resolve(fn()).then(resolve, reject).finally(() => {
|
|
1567
|
-
active--;
|
|
1568
|
-
next();
|
|
1569
|
-
});
|
|
1570
|
-
});
|
|
1571
|
-
next();
|
|
1572
|
-
});
|
|
1783
|
+
function createFunction(props) {
|
|
1784
|
+
return {
|
|
1785
|
+
...props,
|
|
1786
|
+
kind: "Function"
|
|
1573
1787
|
};
|
|
1574
1788
|
}
|
|
1575
1789
|
/**
|
|
1576
|
-
*
|
|
1790
|
+
* Creates an `ArrowFunctionNode` representing a TypeScript arrow function.
|
|
1577
1791
|
*
|
|
1578
|
-
*
|
|
1579
|
-
* `
|
|
1580
|
-
* when `recurse` is `true`; shallow mode skips them.
|
|
1792
|
+
* Mirrors the `Function.Arrow` component from `@kubb/renderer-jsx`.
|
|
1793
|
+
* The component's `children` are represented as `nodes`.
|
|
1581
1794
|
*
|
|
1582
|
-
* @example
|
|
1795
|
+
* @example Simple arrow function
|
|
1583
1796
|
* ```ts
|
|
1584
|
-
*
|
|
1585
|
-
* //
|
|
1797
|
+
* createArrowFunction({ name: 'getPet' })
|
|
1798
|
+
* // const getPet = () => { ... }
|
|
1586
1799
|
* ```
|
|
1587
|
-
*/
|
|
1588
|
-
function getChildren(node, recurse) {
|
|
1589
|
-
switch (node.kind) {
|
|
1590
|
-
case "Input": return [...node.schemas, ...node.operations];
|
|
1591
|
-
case "Output": return [];
|
|
1592
|
-
case "Operation": return [
|
|
1593
|
-
...node.parameters,
|
|
1594
|
-
...node.requestBody?.content?.flatMap((c) => c.schema ? [c.schema] : []) ?? [],
|
|
1595
|
-
...node.responses
|
|
1596
|
-
];
|
|
1597
|
-
case "Schema": {
|
|
1598
|
-
const children = [];
|
|
1599
|
-
if (!recurse) return [];
|
|
1600
|
-
if ("properties" in node && node.properties.length > 0) children.push(...node.properties);
|
|
1601
|
-
if ("items" in node && node.items) children.push(...node.items);
|
|
1602
|
-
if ("members" in node && node.members) children.push(...node.members);
|
|
1603
|
-
if ("additionalProperties" in node && node.additionalProperties && node.additionalProperties !== true) children.push(node.additionalProperties);
|
|
1604
|
-
return children;
|
|
1605
|
-
}
|
|
1606
|
-
case "Property": return [node.schema];
|
|
1607
|
-
case "Parameter": return [node.schema];
|
|
1608
|
-
case "Response": return node.schema ? [node.schema] : [];
|
|
1609
|
-
case "FunctionParameter":
|
|
1610
|
-
case "ParameterGroup":
|
|
1611
|
-
case "FunctionParameters":
|
|
1612
|
-
case "Type": return [];
|
|
1613
|
-
default: return [];
|
|
1614
|
-
}
|
|
1615
|
-
}
|
|
1616
|
-
/**
|
|
1617
|
-
* Depth-first traversal for side effects. Visitor return values are ignored.
|
|
1618
|
-
* Sibling nodes at each level are visited concurrently up to `options.concurrency`
|
|
1619
|
-
* (default: `WALK_CONCURRENCY`).
|
|
1620
1800
|
*
|
|
1621
|
-
* @example
|
|
1801
|
+
* @example Single-line exported arrow function
|
|
1622
1802
|
* ```ts
|
|
1623
|
-
*
|
|
1624
|
-
*
|
|
1625
|
-
* console.log(node.operationId)
|
|
1626
|
-
* },
|
|
1627
|
-
* })
|
|
1803
|
+
* createArrowFunction({ name: 'double', export: true, params: 'n: number', singleLine: true })
|
|
1804
|
+
* // export const double = (n: number) => ...
|
|
1628
1805
|
* ```
|
|
1629
1806
|
*
|
|
1630
|
-
* @example
|
|
1807
|
+
* @example Async arrow function with generics
|
|
1631
1808
|
* ```ts
|
|
1632
|
-
*
|
|
1633
|
-
*
|
|
1809
|
+
* createArrowFunction({
|
|
1810
|
+
* name: 'fetchPet',
|
|
1811
|
+
* export: true,
|
|
1812
|
+
* async: true,
|
|
1813
|
+
* generics: ['T'],
|
|
1814
|
+
* params: 'id: string',
|
|
1815
|
+
* returnType: 'T',
|
|
1816
|
+
* })
|
|
1817
|
+
* // export const fetchPet = async <T>(id: string): Promise<T> => { ... }
|
|
1634
1818
|
* ```
|
|
1635
1819
|
*/
|
|
1636
|
-
|
|
1637
|
-
return
|
|
1820
|
+
function createArrowFunction(props) {
|
|
1821
|
+
return {
|
|
1822
|
+
...props,
|
|
1823
|
+
kind: "ArrowFunction"
|
|
1824
|
+
};
|
|
1638
1825
|
}
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
case "Parameter":
|
|
1657
|
-
await limit(() => visitor.parameter?.(node, { parent }));
|
|
1658
|
-
break;
|
|
1659
|
-
case "Response":
|
|
1660
|
-
await limit(() => visitor.response?.(node, { parent }));
|
|
1661
|
-
break;
|
|
1662
|
-
case "FunctionParameter":
|
|
1663
|
-
case "ParameterGroup":
|
|
1664
|
-
case "FunctionParameters": break;
|
|
1665
|
-
}
|
|
1666
|
-
const children = getChildren(node, recurse);
|
|
1667
|
-
for (const child of children) await _walk(child, visitor, recurse, limit, node);
|
|
1826
|
+
/**
|
|
1827
|
+
* Creates a {@link TextNode} representing a raw string fragment in the source output.
|
|
1828
|
+
*
|
|
1829
|
+
* Use this instead of bare strings when building `nodes` arrays so that every
|
|
1830
|
+
* entry in the array is a typed {@link CodeNode}.
|
|
1831
|
+
*
|
|
1832
|
+
* @example
|
|
1833
|
+
* ```ts
|
|
1834
|
+
* createText('return fetch(id)')
|
|
1835
|
+
* // { kind: 'Text', value: 'return fetch(id)' }
|
|
1836
|
+
* ```
|
|
1837
|
+
*/
|
|
1838
|
+
function createText(value) {
|
|
1839
|
+
return {
|
|
1840
|
+
value,
|
|
1841
|
+
kind: "Text"
|
|
1842
|
+
};
|
|
1668
1843
|
}
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
operations: input.operations.map((op) => transform(op, {
|
|
1684
|
-
...options,
|
|
1685
|
-
parent: input
|
|
1686
|
-
}))
|
|
1687
|
-
};
|
|
1688
|
-
}
|
|
1689
|
-
case "Output": {
|
|
1690
|
-
let output = node;
|
|
1691
|
-
const replaced = visitor.output?.(output, { parent });
|
|
1692
|
-
if (replaced) output = replaced;
|
|
1693
|
-
return output;
|
|
1694
|
-
}
|
|
1695
|
-
case "Operation": {
|
|
1696
|
-
let op = node;
|
|
1697
|
-
const replaced = visitor.operation?.(op, { parent });
|
|
1698
|
-
if (replaced) op = replaced;
|
|
1699
|
-
return {
|
|
1700
|
-
...op,
|
|
1701
|
-
parameters: op.parameters.map((p) => transform(p, {
|
|
1702
|
-
...options,
|
|
1703
|
-
parent: op
|
|
1704
|
-
})),
|
|
1705
|
-
requestBody: op.requestBody ? {
|
|
1706
|
-
...op.requestBody,
|
|
1707
|
-
content: op.requestBody.content?.map((c) => ({
|
|
1708
|
-
...c,
|
|
1709
|
-
schema: c.schema ? transform(c.schema, {
|
|
1710
|
-
...options,
|
|
1711
|
-
parent: op
|
|
1712
|
-
}) : void 0
|
|
1713
|
-
}))
|
|
1714
|
-
} : void 0,
|
|
1715
|
-
responses: op.responses.map((r) => transform(r, {
|
|
1716
|
-
...options,
|
|
1717
|
-
parent: op
|
|
1718
|
-
}))
|
|
1719
|
-
};
|
|
1720
|
-
}
|
|
1721
|
-
case "Schema": {
|
|
1722
|
-
let schema = node;
|
|
1723
|
-
const replaced = visitor.schema?.(schema, { parent });
|
|
1724
|
-
if (replaced) schema = replaced;
|
|
1725
|
-
const childOptions = {
|
|
1726
|
-
...options,
|
|
1727
|
-
parent: schema
|
|
1728
|
-
};
|
|
1729
|
-
return {
|
|
1730
|
-
...schema,
|
|
1731
|
-
..."properties" in schema && recurse ? { properties: schema.properties.map((p) => transform(p, childOptions)) } : {},
|
|
1732
|
-
..."items" in schema && recurse ? { items: schema.items?.map((i) => transform(i, childOptions)) } : {},
|
|
1733
|
-
..."members" in schema && recurse ? { members: schema.members?.map((m) => transform(m, childOptions)) } : {},
|
|
1734
|
-
..."additionalProperties" in schema && recurse && schema.additionalProperties && schema.additionalProperties !== true ? { additionalProperties: transform(schema.additionalProperties, childOptions) } : {}
|
|
1735
|
-
};
|
|
1736
|
-
}
|
|
1737
|
-
case "Property": {
|
|
1738
|
-
let prop = node;
|
|
1739
|
-
const replaced = visitor.property?.(prop, { parent });
|
|
1740
|
-
if (replaced) prop = replaced;
|
|
1741
|
-
return createProperty({
|
|
1742
|
-
...prop,
|
|
1743
|
-
schema: transform(prop.schema, {
|
|
1744
|
-
...options,
|
|
1745
|
-
parent: prop
|
|
1746
|
-
})
|
|
1747
|
-
});
|
|
1748
|
-
}
|
|
1749
|
-
case "Parameter": {
|
|
1750
|
-
let param = node;
|
|
1751
|
-
const replaced = visitor.parameter?.(param, { parent });
|
|
1752
|
-
if (replaced) param = replaced;
|
|
1753
|
-
return createParameter({
|
|
1754
|
-
...param,
|
|
1755
|
-
schema: transform(param.schema, {
|
|
1756
|
-
...options,
|
|
1757
|
-
parent: param
|
|
1758
|
-
})
|
|
1759
|
-
});
|
|
1760
|
-
}
|
|
1761
|
-
case "Response": {
|
|
1762
|
-
let response = node;
|
|
1763
|
-
const replaced = visitor.response?.(response, { parent });
|
|
1764
|
-
if (replaced) response = replaced;
|
|
1765
|
-
return {
|
|
1766
|
-
...response,
|
|
1767
|
-
schema: transform(response.schema, {
|
|
1768
|
-
...options,
|
|
1769
|
-
parent: response
|
|
1770
|
-
})
|
|
1771
|
-
};
|
|
1772
|
-
}
|
|
1773
|
-
case "FunctionParameter":
|
|
1774
|
-
case "ParameterGroup":
|
|
1775
|
-
case "FunctionParameters":
|
|
1776
|
-
case "Type": return node;
|
|
1777
|
-
default: return node;
|
|
1778
|
-
}
|
|
1844
|
+
/**
|
|
1845
|
+
* Creates a {@link BreakNode} representing a line break in the source output.
|
|
1846
|
+
*
|
|
1847
|
+
* Corresponds to `<br/>` in JSX components. Prints as an empty string which,
|
|
1848
|
+
* when joined with `\n` by `printNodes`, produces a blank line.
|
|
1849
|
+
*
|
|
1850
|
+
* @example
|
|
1851
|
+
* ```ts
|
|
1852
|
+
* createBreak()
|
|
1853
|
+
* // { kind: 'Break' }
|
|
1854
|
+
* ```
|
|
1855
|
+
*/
|
|
1856
|
+
function createBreak() {
|
|
1857
|
+
return { kind: "Break" };
|
|
1779
1858
|
}
|
|
1780
1859
|
/**
|
|
1781
|
-
*
|
|
1860
|
+
* Creates a {@link JsxNode} representing a raw JSX fragment in the source output.
|
|
1782
1861
|
*
|
|
1783
|
-
*
|
|
1862
|
+
* Use this to embed JSX markup (including fragments `<>…</>`) directly in generated code.
|
|
1784
1863
|
*
|
|
1785
1864
|
* @example
|
|
1786
1865
|
* ```ts
|
|
1787
|
-
*
|
|
1788
|
-
*
|
|
1789
|
-
* return node.operationId
|
|
1790
|
-
* },
|
|
1791
|
-
* })
|
|
1866
|
+
* createJsx('<>\n <a href={href}>Open</a>\n</>')
|
|
1867
|
+
* // { kind: 'Jsx', value: '<>\n <a href={href}>Open</a>\n</>' }
|
|
1792
1868
|
* ```
|
|
1869
|
+
*/
|
|
1870
|
+
function createJsx(value) {
|
|
1871
|
+
return {
|
|
1872
|
+
value,
|
|
1873
|
+
kind: "Jsx"
|
|
1874
|
+
};
|
|
1875
|
+
}
|
|
1876
|
+
//#endregion
|
|
1877
|
+
//#region src/printer.ts
|
|
1878
|
+
/**
|
|
1879
|
+
* Creates a schema printer factory.
|
|
1880
|
+
*
|
|
1881
|
+
* This function wraps a builder and makes options optional at call sites.
|
|
1882
|
+
*
|
|
1883
|
+
* The builder receives resolved options and returns:
|
|
1884
|
+
* - `name` — a unique identifier for the printer
|
|
1885
|
+
* - `options` — options stored on the returned printer instance
|
|
1886
|
+
* - `nodes` — a map of `SchemaType` → handler functions that convert a `SchemaNode` to `TOutput`
|
|
1887
|
+
* - `print` _(optional)_ — top-level override exposed as `printer.print`
|
|
1888
|
+
* - Inside this function, use `this.transform(node)` to dispatch to the `nodes` map
|
|
1889
|
+
* - This keeps recursion safe and avoids self-calls
|
|
1890
|
+
*
|
|
1891
|
+
* When no `print` override is provided, `printer.print` falls back to `printer.transform` (the node-level dispatcher).
|
|
1892
|
+
*
|
|
1893
|
+
* @example Basic usage — Zod schema printer
|
|
1894
|
+
* ```ts
|
|
1895
|
+
* type PrinterZod = PrinterFactoryOptions<'zod', { strict?: boolean }, string>
|
|
1793
1896
|
*
|
|
1897
|
+
* export const zodPrinter = definePrinter<PrinterZod>((options) => ({
|
|
1898
|
+
* name: 'zod',
|
|
1899
|
+
* options: { strict: options.strict ?? true },
|
|
1900
|
+
* nodes: {
|
|
1901
|
+
* string: () => 'z.string()',
|
|
1902
|
+
* object(node) {
|
|
1903
|
+
* const props = node.properties.map(p => `${p.name}: ${this.transform(p.schema)}`).join(', ')
|
|
1904
|
+
* return `z.object({ ${props} })`
|
|
1905
|
+
* },
|
|
1906
|
+
* },
|
|
1907
|
+
* }))
|
|
1908
|
+
* ```
|
|
1909
|
+
*/
|
|
1910
|
+
function definePrinter(build) {
|
|
1911
|
+
return createPrinterFactory((node) => node.type)(build);
|
|
1912
|
+
}
|
|
1913
|
+
/**
|
|
1914
|
+
* Generic printer-factory function used by `definePrinter` and `defineFunctionPrinter`.
|
|
1915
|
+
**
|
|
1794
1916
|
* @example
|
|
1795
1917
|
* ```ts
|
|
1796
|
-
*
|
|
1797
|
-
*
|
|
1918
|
+
* export const defineFunctionPrinter = createPrinterFactory<FunctionNode, FunctionNodeType, FunctionNodeByType>(
|
|
1919
|
+
* (node) => kindToHandlerKey[node.kind],
|
|
1920
|
+
* )
|
|
1798
1921
|
* ```
|
|
1799
1922
|
*/
|
|
1800
|
-
function
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
v = visitor.parameter?.(node, { parent });
|
|
1823
|
-
break;
|
|
1824
|
-
case "Response":
|
|
1825
|
-
v = visitor.response?.(node, { parent });
|
|
1826
|
-
break;
|
|
1827
|
-
case "FunctionParameter":
|
|
1828
|
-
case "ParameterGroup":
|
|
1829
|
-
case "FunctionParameters": break;
|
|
1830
|
-
}
|
|
1831
|
-
if (v !== void 0) results.push(v);
|
|
1832
|
-
for (const child of getChildren(node, recurse)) for (const item of collect(child, {
|
|
1833
|
-
...options,
|
|
1834
|
-
parent: node
|
|
1835
|
-
})) results.push(item);
|
|
1836
|
-
return results;
|
|
1923
|
+
function createPrinterFactory(getKey) {
|
|
1924
|
+
return function(build) {
|
|
1925
|
+
return (options) => {
|
|
1926
|
+
const { name, options: resolvedOptions, nodes, print: printOverride } = build(options ?? {});
|
|
1927
|
+
const context = {
|
|
1928
|
+
options: resolvedOptions,
|
|
1929
|
+
transform: (node) => {
|
|
1930
|
+
const key = getKey(node);
|
|
1931
|
+
if (key === void 0) return null;
|
|
1932
|
+
const handler = nodes[key];
|
|
1933
|
+
if (!handler) return null;
|
|
1934
|
+
return handler.call(context, node);
|
|
1935
|
+
}
|
|
1936
|
+
};
|
|
1937
|
+
return {
|
|
1938
|
+
name,
|
|
1939
|
+
options: resolvedOptions,
|
|
1940
|
+
transform: context.transform,
|
|
1941
|
+
print: printOverride ? printOverride.bind(context) : context.transform
|
|
1942
|
+
};
|
|
1943
|
+
};
|
|
1944
|
+
};
|
|
1837
1945
|
}
|
|
1838
1946
|
//#endregion
|
|
1839
1947
|
//#region src/resolvers.ts
|
|
@@ -1971,6 +2079,6 @@ function setEnumName(propNode, parentName, propName, enumSuffix) {
|
|
|
1971
2079
|
return propNode;
|
|
1972
2080
|
}
|
|
1973
2081
|
//#endregion
|
|
1974
|
-
export { caseParams, childName, collect, collectImports, 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, findDiscriminator, httpMethods, isInputNode, isOperationNode, isOutputNode, isScalarPrimitive, isSchemaNode, isStringType, mediaTypes, mergeAdjacentObjects, narrowSchema, nodeKinds, schemaTypes, setDiscriminatorEnum, setEnumName, simplifyUnion, syncOptionality, syncSchemaRef, transform, walk };
|
|
2082
|
+
export { caseParams, childName, collect, collectImports, collectReferencedSchemaNames, 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 };
|
|
1975
2083
|
|
|
1976
2084
|
//# sourceMappingURL=index.js.map
|