@kubb/plugin-ts 5.1.0-canary.20261023T200213 → 5.2.0-canary.20261024T091509

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 CHANGED
@@ -18,11 +18,11 @@ var __exportAll = (all, no_symbols) => {
18
18
  return target;
19
19
  };
20
20
  //#endregion
21
- let _kubb_parser_ts = require("@kubb/parser-ts");
22
21
  let kubb_jsx = require("kubb/jsx");
23
- let node_module = require("node:module");
24
22
  let kubb_kit = require("kubb/kit");
23
+ let yuku_codegen = require("yuku-codegen");
25
24
  let kubb_jsx_jsx_runtime = require("kubb/jsx/jsx-runtime");
25
+ let _kubb_parser_ts = require("@kubb/parser-ts");
26
26
  //#region ../../internals/utils/src/casing.ts
27
27
  /**
28
28
  * Shared implementation for camelCase and PascalCase conversion.
@@ -322,6 +322,7 @@ var factory_exports = /* @__PURE__ */ __exportAll({
322
322
  createIntersectionDeclaration: () => createIntersectionDeclaration,
323
323
  createOmitDeclaration: () => createOmitDeclaration,
324
324
  createPropertySignature: () => createPropertySignature,
325
+ createRaw: () => createRaw,
325
326
  createTypeDeclaration: () => createTypeDeclaration,
326
327
  createTypeLiteralNode: () => createTypeLiteralNode,
327
328
  createTypeReferenceNode: () => createTypeReferenceNode,
@@ -329,84 +330,113 @@ var factory_exports = /* @__PURE__ */ __exportAll({
329
330
  createUrlTemplateType: () => createUrlTemplateType,
330
331
  dateOrStringNode: () => dateOrStringNode,
331
332
  isNonNullable: () => isNonNullable$1,
332
- isUnionTypeNode: () => isUnionTypeNode,
333
333
  keywordTypeNodes: () => keywordTypeNodes,
334
- modifiers: () => modifiers,
334
+ print: () => print,
335
335
  wrapNullableOptional: () => wrapNullableOptional
336
336
  });
337
- /**
338
- * Loaded with `require`, not `import`. When ESM imports a CommonJS package, Node keeps a second
339
- * copy of its source to detect named exports, and for TypeScript that copy is about 9 MB.
340
- */
341
- const typescript = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href)("@typescript/typescript6");
342
- const { SyntaxKind, factory } = typescript;
343
337
  function isNumber(value) {
344
338
  return typeof value === "number" && !Number.isNaN(value);
345
339
  }
346
- /**
347
- * TypeScript AST modifiers for the `export` keyword.
348
- */
349
- const modifiers = { export: factory.createModifier(typescript.SyntaxKind.ExportKeyword) };
350
- const isUnionTypeNode = typescript.isUnionTypeNode;
351
340
  function isNonNullable$1(value) {
352
341
  return value !== null && value !== void 0;
353
342
  }
354
343
  __name(isNonNullable$1, "isNonNullable");
355
- function isValidIdentifier(str) {
356
- if (!str.length || str.trim() !== str) return false;
357
- let ch = str.codePointAt(0);
358
- if (!typescript.isIdentifierStart(ch, typescript.ScriptTarget.Latest)) return false;
359
- for (let i = ch > 65535 ? 2 : 1; i < str.length; i += ch > 65535 ? 2 : 1) {
360
- ch = str.codePointAt(i);
361
- if (!typescript.isIdentifierPart(ch, typescript.ScriptTarget.Latest)) return false;
362
- }
363
- return true;
344
+ /**
345
+ * Prints `node` as TypeScript source with single quotes and two-space indentation.
346
+ */
347
+ function print(node) {
348
+ return (0, yuku_codegen.generate)(node, { quotes: "single" }).code;
349
+ }
350
+ /**
351
+ * Wraps already printed TypeScript, such as a user override result, so it can sit inside a node tree.
352
+ * Parentheses keep a union or function type intact when it lands inside an array or intersection.
353
+ */
354
+ function createRaw(text) {
355
+ const name = {
356
+ type: "TSTypeReference",
357
+ typeName: identifier(text),
358
+ typeArguments: null
359
+ };
360
+ return /[|&?]|=>/.test(text) ? {
361
+ type: "TSParenthesizedType",
362
+ typeAnnotation: name
363
+ } : name;
364
+ }
365
+ function identifier(name) {
366
+ return {
367
+ type: "Identifier",
368
+ name
369
+ };
370
+ }
371
+ function literal(value) {
372
+ return {
373
+ type: "Literal",
374
+ value
375
+ };
376
+ }
377
+ function createLiteralType(value) {
378
+ return {
379
+ type: "TSLiteralType",
380
+ literal: literal(value)
381
+ };
382
+ }
383
+ /**
384
+ * Whether `name` can be written as a bare property name instead of a quoted string.
385
+ */
386
+ function isValidIdentifier(name) {
387
+ return /^[\p{ID_Start}$_][\p{ID_Continue}$‌‍]*$/u.test(name);
364
388
  }
389
+ /**
390
+ * A property or enum member name, quoted when it is not a valid identifier.
391
+ */
365
392
  function propertyName(name) {
366
- if (typeof name === "string") return isValidIdentifier(name) ? factory.createIdentifier(name) : factory.createStringLiteral(name);
367
- return name;
393
+ return isValidIdentifier(name) ? identifier(name) : literal(name);
368
394
  }
369
- const questionToken = factory.createToken(typescript.SyntaxKind.QuestionToken);
370
395
  /**
371
- * Creates a question token for optional type annotations.
372
- * Pass `true` to use the cached token, or provide a pre-created token.
396
+ * Indents every non-empty line of `text` by two spaces.
373
397
  */
374
- function createQuestionToken(token) {
375
- if (!token) return;
376
- if (token === true) return questionToken;
377
- return token;
398
+ function indent(text) {
399
+ return text.split("\n").map((line) => line ? ` ${line}` : line).join("\n");
378
400
  }
379
401
  /**
380
- * Creates a TypeScript intersection type node from multiple type nodes.
381
- * Returns the single node if only one is provided, or wraps in parentheses if requested.
402
+ * Creates a TypeScript intersection type.
403
+ * Returns the single type if only one is provided. `yuku-codegen` adds the parentheses a union member needs.
382
404
  */
383
405
  function createIntersectionDeclaration({ nodes, withParentheses }) {
384
406
  if (!nodes.length) return null;
385
407
  if (nodes.length === 1) return nodes[0] || null;
386
- const node = factory.createIntersectionTypeNode(nodes);
387
- if (withParentheses) return factory.createParenthesizedType(node);
388
- return node;
408
+ const node = {
409
+ type: "TSIntersectionType",
410
+ types: nodes
411
+ };
412
+ return withParentheses ? {
413
+ type: "TSParenthesizedType",
414
+ typeAnnotation: node
415
+ } : node;
389
416
  }
390
417
  /**
391
- * Creates a TypeScript array type node.
418
+ * Creates a TypeScript array type.
392
419
  * Use `arrayType: 'array'` for bracket syntax (`T[]`), or `'generic'` for `Array<T>`.
393
420
  *
394
421
  * @example Array bracket syntax
395
- * `createArrayDeclaration({ nodes: [stringType], arrayType: 'array' }) // → string[]`
422
+ * `createArrayDeclaration({ nodes: [string], arrayType: 'array' }) // → string[]`
396
423
  *
397
424
  * @example Generic Array syntax
398
- * `createArrayDeclaration({ nodes: [stringType], arrayType: 'generic' }) // → Array<string>`
425
+ * `createArrayDeclaration({ nodes: [string], arrayType: 'generic' }) // → Array<string>`
399
426
  */
400
427
  function createArrayDeclaration({ nodes, arrayType = "array" }) {
401
- if (!nodes.length) return factory.createTupleTypeNode([]);
402
- if (nodes.length === 1) {
403
- const node = nodes[0];
404
- if (arrayType === "generic") return factory.createTypeReferenceNode(factory.createIdentifier("Array"), [node]);
405
- return factory.createArrayTypeNode(node);
406
- }
407
- const unionType = factory.createUnionTypeNode(nodes);
408
- if (arrayType === "generic") return factory.createTypeReferenceNode(factory.createIdentifier("Array"), [unionType]);
409
- return factory.createArrayTypeNode(factory.createParenthesizedType(unionType));
428
+ if (!nodes.length) return {
429
+ type: "TSTupleType",
430
+ elementTypes: []
431
+ };
432
+ const node = nodes.length === 1 ? nodes[0] : {
433
+ type: "TSUnionType",
434
+ types: nodes
435
+ };
436
+ return arrayType === "generic" ? createTypeReferenceNode("Array", [node]) : {
437
+ type: "TSArrayType",
438
+ elementType: node
439
+ };
410
440
  }
411
441
  /**
412
442
  * Minimum nodes length of 2
@@ -416,60 +446,115 @@ function createArrayDeclaration({ nodes, arrayType = "array" }) {
416
446
  function createUnionDeclaration({ nodes, withParentheses }) {
417
447
  if (!nodes.length) return keywordTypeNodes.any;
418
448
  if (nodes.length === 1) return nodes[0];
419
- const node = factory.createUnionTypeNode(nodes);
420
- if (withParentheses) return factory.createParenthesizedType(node);
421
- return node;
449
+ const node = {
450
+ type: "TSUnionType",
451
+ types: nodes
452
+ };
453
+ return withParentheses ? {
454
+ type: "TSParenthesizedType",
455
+ typeAnnotation: node
456
+ } : node;
422
457
  }
423
458
  /**
424
459
  * Creates a TypeScript property signature for object/interface members.
425
460
  * Supports optional markers, readonly modifiers, and type annotations.
426
461
  */
427
- function createPropertySignature({ readOnly, modifiers = [], name, questionToken, type }) {
428
- return factory.createPropertySignature([...modifiers, readOnly ? factory.createToken(typescript.SyntaxKind.ReadonlyKeyword) : void 0].filter((modifier) => modifier !== void 0), propertyName(name), createQuestionToken(questionToken), type);
462
+ function createPropertySignature({ readOnly, name, questionToken, type }) {
463
+ return {
464
+ type: "TSPropertySignature",
465
+ key: propertyName(name),
466
+ computed: false,
467
+ optional: !!questionToken,
468
+ readonly: !!readOnly,
469
+ static: false,
470
+ typeAnnotation: type ? {
471
+ type: "TSTypeAnnotation",
472
+ typeAnnotation: type
473
+ } : null
474
+ };
429
475
  }
430
476
  /**
431
- * Attaches JSDoc comments to an AST node as synthetic leading comments.
432
- * Filters out undefined comments before attaching.
433
- *
434
- * @see https://github.com/microsoft/TypeScript/issues/44151
477
+ * Attaches a JSDoc block built from `comments` to `node`, dropping empty comments.
435
478
  */
436
479
  function appendJSDocToNode({ node, comments }) {
437
- const filteredComments = comments.filter(Boolean);
438
- if (!filteredComments.length) return node;
439
- const text = filteredComments.flatMap((comment = "") => comment.split(/\r?\n/)).reduce((acc = "", comment = "") => {
440
- return `${acc}\n * ${comment.replaceAll("*/", "*\\/")}`;
441
- }, "*");
442
- return typescript.addSyntheticLeadingComment(node, typescript.SyntaxKind.MultiLineCommentTrivia, `${text || "*"}\n`, true);
480
+ const lines = comments.filter(Boolean).flatMap((comment = "") => comment.split(/\r?\n/));
481
+ if (!lines.length) return node;
482
+ const value = `*\n${lines.map((line) => ` * ${line.replaceAll("*/", "*\\/")}`.trimEnd()).join("\n")}\n `;
483
+ return {
484
+ ...node,
485
+ comments: [{
486
+ type: "Block",
487
+ value,
488
+ position: "before",
489
+ sameLine: false
490
+ }]
491
+ };
443
492
  }
444
493
  /**
445
- * Creates a TypeScript index signature for dynamic property access.
446
- * Defines the key type (default: `string`) and value type on an object.
494
+ * Creates a TypeScript type literal (anonymous object type) with one member per line.
447
495
  */
448
- function createIndexSignature(type, { modifiers, indexName = "key", indexType = factory.createKeywordTypeNode(typescript.SyntaxKind.StringKeyword) } = {}) {
449
- return factory.createIndexSignature(modifiers, [factory.createParameterDeclaration(void 0, void 0, indexName, void 0, indexType)], type);
496
+ function createTypeLiteralNode(members) {
497
+ return {
498
+ type: "TSTypeLiteral",
499
+ members
500
+ };
501
+ }
502
+ /**
503
+ * Creates a TypeScript type reference (e.g., `Array<string>`, `Record<K, V>`).
504
+ */
505
+ function createTypeReferenceNode(name, typeArguments) {
506
+ return {
507
+ type: "TSTypeReference",
508
+ typeName: identifier(name),
509
+ typeArguments: typeArguments?.length ? {
510
+ type: "TSTypeParameterInstantiation",
511
+ params: typeArguments
512
+ } : null
513
+ };
514
+ }
515
+ function exportNamed(declaration, exportKind) {
516
+ return {
517
+ type: "ExportNamedDeclaration",
518
+ declaration,
519
+ specifiers: [],
520
+ source: null,
521
+ attributes: [],
522
+ exportKind
523
+ };
450
524
  }
451
525
  /**
452
- * Creates a TypeScript type declaration as either a type alias or interface.
453
- * Intelligently selects the syntax based on the type structure and attaches JSDoc comments.
526
+ * Prints a TypeScript type declaration as either a type alias or interface.
527
+ * Uses interface syntax only when requested and the type is an object literal, and attaches JSDoc comments.
454
528
  */
455
529
  function createTypeDeclaration({ syntax, isExportable, comments, name, type }) {
456
- if (syntax === "interface" && typescript.isTypeLiteralNode(type)) return appendJSDocToNode({
457
- node: factory.createInterfaceDeclaration(isExportable ? [modifiers.export] : [], name, void 0, void 0, [...type.members]),
458
- comments
459
- });
460
- return appendJSDocToNode({
461
- node: factory.createTypeAliasDeclaration(isExportable ? [modifiers.export] : [], name, void 0, type),
530
+ const declaration = syntax === "interface" && type.type === "TSTypeLiteral" ? {
531
+ type: "TSInterfaceDeclaration",
532
+ declare: false,
533
+ id: identifier(name),
534
+ typeParameters: null,
535
+ extends: [],
536
+ body: {
537
+ type: "TSInterfaceBody",
538
+ body: type.members
539
+ }
540
+ } : {
541
+ type: "TSTypeAliasDeclaration",
542
+ declare: false,
543
+ id: identifier(name),
544
+ typeParameters: null,
545
+ typeAnnotation: type
546
+ };
547
+ return print(appendJSDocToNode({
548
+ node: isExportable ? exportNamed(declaration, "type") : declaration,
462
549
  comments
463
- });
550
+ }));
464
551
  }
465
552
  /**
466
- * Converts an enum member value to a literal expression. Numbers become numeric literals (negatives use a prefix
467
- * minus, as `createNumericLiteral` rejects them) unless `asNumber` is `false`, which emits the string form.
553
+ * Converts an enum member value to a literal. Numbers become numeric literals unless `asNumber` is `false`,
554
+ * which emits the string form.
468
555
  */
469
556
  function valueToExpression(value, asNumber = isNumber(value)) {
470
- if (typeof value === "boolean") return value ? factory.createTrue() : factory.createFalse();
471
- if (asNumber && isNumber(value)) return value < 0 ? factory.createPrefixUnaryExpression(SyntaxKind.MinusToken, factory.createNumericLiteral(Math.abs(value))) : factory.createNumericLiteral(value);
472
- return factory.createStringLiteral(value.toString());
557
+ return literal(typeof value === "boolean" || asNumber && isNumber(value) ? value : value.toString());
473
558
  }
474
559
  /**
475
560
  * Apply casing transformation to enum keys
@@ -484,7 +569,7 @@ function applyEnumKeyCasing(key, casing = "none") {
484
569
  }
485
570
  /**
486
571
  * Creates a TypeScript enum declaration or equivalent construct in various formats.
487
- * Returns a tuple of [name node, type node] - name node may be undefined for certain types.
572
+ * Returns a tuple of [name declaration, type declaration] - the name declaration may be undefined for certain types.
488
573
  *
489
574
  * @example
490
575
  * ```ts
@@ -497,126 +582,135 @@ function applyEnumKeyCasing(key, casing = "none") {
497
582
  * ```
498
583
  */
499
584
  function createEnumDeclaration({ type = "enum", name, typeName, enums, enumKeyCasing = "none" }) {
500
- if (type === "literal" || type === "inlineLiteral") return [void 0, factory.createTypeAliasDeclaration([factory.createToken(typescript.SyntaxKind.ExportKeyword)], factory.createIdentifier(typeName), void 0, factory.createUnionTypeNode(enums.map(([_key, value]) => {
501
- if (isNumber(value)) {
502
- if (value < 0) return factory.createLiteralTypeNode(factory.createPrefixUnaryExpression(typescript.SyntaxKind.MinusToken, factory.createNumericLiteral(Math.abs(value))));
503
- return factory.createLiteralTypeNode(factory.createNumericLiteral(value?.toString()));
504
- }
505
- if (typeof value === "boolean") return factory.createLiteralTypeNode(value ? factory.createTrue() : factory.createFalse());
506
- if (value !== null && value !== void 0) return factory.createLiteralTypeNode(factory.createStringLiteral(value.toString()));
507
- }).filter((node) => node !== void 0)))];
508
- if (type === "enum" || type === "constEnum") return [void 0, factory.createEnumDeclaration([factory.createToken(typescript.SyntaxKind.ExportKeyword), type === "constEnum" ? factory.createToken(typescript.SyntaxKind.ConstKeyword) : void 0].filter((modifier) => modifier !== void 0), factory.createIdentifier(typeName), enums.map(([key, value, description]) => {
509
- const initializer = valueToExpression(value, Number.parseInt(value.toString(), 10) === value);
510
- if (isNumber(Number.parseInt(key.toString(), 10))) {
511
- const casingKey = applyEnumKeyCasing(`${typeName}_${key}`, enumKeyCasing);
512
- return appendJSDocToNode({
513
- node: factory.createEnumMember(propertyName(casingKey), initializer),
514
- comments: [description]
515
- });
516
- }
517
- if (key !== null && key !== void 0) {
518
- const casingKey = applyEnumKeyCasing(key.toString(), enumKeyCasing);
585
+ const typeAlias = (annotation) => createTypeDeclaration({
586
+ syntax: "type",
587
+ isExportable: true,
588
+ name: typeName,
589
+ comments: [],
590
+ type: annotation
591
+ });
592
+ if (type === "literal" || type === "inlineLiteral") {
593
+ const members = enums.map(([_key, value]) => isNonNullable$1(value) ? {
594
+ type: "TSLiteralType",
595
+ literal: valueToExpression(value)
596
+ } : void 0).filter(isNonNullable$1);
597
+ return [void 0, typeAlias(members.length ? createUnionDeclaration({ nodes: members }) : keywordTypeNodes.never)];
598
+ }
599
+ if (type === "enum" || type === "constEnum") {
600
+ const members = enums.map(([key, value, description]) => {
601
+ const initializer = valueToExpression(value, Number.parseInt(value.toString(), 10) === value);
602
+ const memberName = isNumber(Number.parseInt(key.toString(), 10)) ? `${typeName}_${key}` : key?.toString();
603
+ if (memberName === void 0) return void 0;
519
604
  return appendJSDocToNode({
520
- node: factory.createEnumMember(propertyName(casingKey), initializer),
605
+ node: {
606
+ type: "TSEnumMember",
607
+ id: propertyName(applyEnumKeyCasing(memberName, enumKeyCasing)),
608
+ initializer
609
+ },
521
610
  comments: [description]
522
611
  });
523
- }
524
- }).filter((member) => member !== void 0))];
612
+ }).filter(isNonNullable$1);
613
+ return [void 0, print(exportNamed({
614
+ type: "TSEnumDeclaration",
615
+ declare: false,
616
+ const: type === "constEnum",
617
+ id: identifier(typeName),
618
+ body: {
619
+ type: "TSEnumBody",
620
+ members
621
+ }
622
+ }, "value"))];
623
+ }
525
624
  const identifierName = name;
526
- if (enums.length === 0) return [void 0, factory.createTypeAliasDeclaration([factory.createToken(typescript.SyntaxKind.ExportKeyword)], factory.createIdentifier(typeName), void 0, factory.createKeywordTypeNode(typescript.SyntaxKind.NeverKeyword))];
527
- return [factory.createVariableStatement([factory.createToken(typescript.SyntaxKind.ExportKeyword)], factory.createVariableDeclarationList([factory.createVariableDeclaration(factory.createIdentifier(identifierName), void 0, void 0, factory.createAsExpression(factory.createObjectLiteralExpression(enums.map(([key, value, description]) => {
528
- const initializer = valueToExpression(value);
529
- if (key !== null && key !== void 0) {
530
- const casingKey = applyEnumKeyCasing(key.toString(), enumKeyCasing);
531
- return appendJSDocToNode({
532
- node: factory.createPropertyAssignment(propertyName(casingKey), initializer),
533
- comments: [description]
534
- });
625
+ if (enums.length === 0) return [void 0, typeAlias(keywordTypeNodes.never)];
626
+ const properties = enums.map(([key, value, description]) => {
627
+ if (key === null || key === void 0) return void 0;
628
+ return print(appendJSDocToNode({
629
+ node: {
630
+ type: "Property",
631
+ kind: "init",
632
+ key: propertyName(applyEnumKeyCasing(key.toString(), enumKeyCasing)),
633
+ value: valueToExpression(value),
634
+ computed: false,
635
+ method: false,
636
+ shorthand: false
637
+ },
638
+ comments: [description]
639
+ }));
640
+ }).filter(isNonNullable$1);
641
+ const query = {
642
+ type: "TSTypeQuery",
643
+ exprName: identifier(identifierName),
644
+ typeArguments: null
645
+ };
646
+ return [`export const ${identifierName} = {\n${properties.map(indent).join(",\n")},\n} as const;`, typeAlias({
647
+ type: "TSIndexedAccessType",
648
+ objectType: {
649
+ type: "TSParenthesizedType",
650
+ typeAnnotation: query
651
+ },
652
+ indexType: {
653
+ type: "TSTypeOperator",
654
+ operator: "keyof",
655
+ typeAnnotation: query
535
656
  }
536
- }).filter((property) => property !== void 0), true), factory.createTypeReferenceNode(factory.createIdentifier("const"), void 0)))], typescript.NodeFlags.Const)), factory.createTypeAliasDeclaration([factory.createToken(typescript.SyntaxKind.ExportKeyword)], factory.createIdentifier(typeName), void 0, factory.createIndexedAccessTypeNode(factory.createParenthesizedType(factory.createTypeQueryNode(factory.createIdentifier(identifierName), void 0)), factory.createTypeOperatorNode(typescript.SyntaxKind.KeyOfKeyword, factory.createTypeQueryNode(factory.createIdentifier(identifierName), void 0))))];
657
+ })];
537
658
  }
538
659
  /**
539
- * Creates a TypeScript `Omit<T, Keys>` type reference node.
660
+ * Creates a TypeScript `Omit<T, Keys>` type reference.
540
661
  * Optionally wraps the type in `NonNullable<T>` if `nonNullable` is true.
541
662
  */
542
663
  function createOmitDeclaration({ keys, type, nonNullable }) {
543
- const node = nonNullable ? factory.createTypeReferenceNode(factory.createIdentifier("NonNullable"), [type]) : type;
544
- if (Array.isArray(keys)) return factory.createTypeReferenceNode(factory.createIdentifier("Omit"), [node, factory.createUnionTypeNode(keys.map((key) => {
545
- return factory.createLiteralTypeNode(factory.createStringLiteral(key));
546
- }))]);
547
- return factory.createTypeReferenceNode(factory.createIdentifier("Omit"), [node, factory.createLiteralTypeNode(factory.createStringLiteral(keys))]);
664
+ return createTypeReferenceNode("Omit", [nonNullable ? createTypeReferenceNode("NonNullable", [type]) : type, createUnionDeclaration({ nodes: [keys].flat().map(createLiteralType) })]);
548
665
  }
549
666
  /**
550
- * Pre-built TypeScript keyword type nodes for common primitive types.
551
- * Use these to avoid repeatedly creating the same type nodes.
667
+ * TypeScript keyword types for common primitive types.
552
668
  */
553
669
  const keywordTypeNodes = {
554
- any: factory.createKeywordTypeNode(typescript.SyntaxKind.AnyKeyword),
555
- unknown: factory.createKeywordTypeNode(typescript.SyntaxKind.UnknownKeyword),
556
- void: factory.createKeywordTypeNode(typescript.SyntaxKind.VoidKeyword),
557
- number: factory.createKeywordTypeNode(typescript.SyntaxKind.NumberKeyword),
558
- integer: factory.createKeywordTypeNode(typescript.SyntaxKind.NumberKeyword),
559
- bigint: factory.createKeywordTypeNode(typescript.SyntaxKind.BigIntKeyword),
560
- object: factory.createKeywordTypeNode(typescript.SyntaxKind.ObjectKeyword),
561
- string: factory.createKeywordTypeNode(typescript.SyntaxKind.StringKeyword),
562
- boolean: factory.createKeywordTypeNode(typescript.SyntaxKind.BooleanKeyword),
563
- undefined: factory.createKeywordTypeNode(typescript.SyntaxKind.UndefinedKeyword),
564
- null: factory.createLiteralTypeNode(factory.createToken(typescript.SyntaxKind.NullKeyword)),
565
- never: factory.createKeywordTypeNode(typescript.SyntaxKind.NeverKeyword)
670
+ any: { type: "TSAnyKeyword" },
671
+ unknown: { type: "TSUnknownKeyword" },
672
+ void: { type: "TSVoidKeyword" },
673
+ number: { type: "TSNumberKeyword" },
674
+ integer: { type: "TSNumberKeyword" },
675
+ bigint: { type: "TSBigIntKeyword" },
676
+ object: { type: "TSObjectKeyword" },
677
+ string: { type: "TSStringKeyword" },
678
+ boolean: { type: "TSBooleanKeyword" },
679
+ undefined: { type: "TSUndefinedKeyword" },
680
+ null: { type: "TSNullKeyword" },
681
+ never: { type: "TSNeverKeyword" }
566
682
  };
567
683
  /**
568
- * Converts a path like '/pet/{petId}/uploadImage' to a template literal type
569
- * like `/pet/${string}/uploadImage`
570
- */
571
- /**
572
684
  * Converts an OAS-style path (e.g. `/pets/{petId}`) or an Express-style path
573
685
  * (e.g. `/pets/:petId`) to a TypeScript template literal type
574
686
  * like `` `/pets/${string}` ``.
575
687
  */
576
688
  function createUrlTemplateType(path) {
577
689
  const normalized = path.replace(/:([^/]+)/g, "{$1}");
578
- if (!normalized.includes("{")) return factory.createLiteralTypeNode(factory.createStringLiteral(normalized));
579
- const segments = normalized.split(/(\{[^}]+\})/);
580
- const parts = [];
581
- const parameterIndices = [];
582
- segments.forEach((segment) => {
583
- if (segment.startsWith("{") && segment.endsWith("}")) {
584
- parameterIndices.push(parts.length);
585
- parts.push(segment);
586
- } else if (segment) parts.push(segment);
587
- });
588
- const head = typescript.factory.createTemplateHead(parts[0] || "");
589
- const templateSpans = [];
590
- parameterIndices.forEach((paramIndex, i) => {
591
- const isLast = i === parameterIndices.length - 1;
592
- const nextPart = parts[paramIndex + 1] || "";
593
- const literal = isLast ? typescript.factory.createTemplateTail(nextPart) : typescript.factory.createTemplateMiddle(nextPart);
594
- templateSpans.push(typescript.factory.createTemplateLiteralTypeSpan(keywordTypeNodes.string, literal));
595
- });
596
- return typescript.factory.createTemplateLiteralType(head, templateSpans);
690
+ if (!normalized.includes("{")) return createLiteralType(normalized);
691
+ const segments = normalized.split(/\{[^}]+\}/);
692
+ return {
693
+ type: "TSTemplateLiteralType",
694
+ quasis: segments.map((cooked, i) => ({
695
+ type: "TemplateElement",
696
+ value: { cooked },
697
+ tail: i === segments.length - 1
698
+ })),
699
+ types: segments.slice(1).map(() => keywordTypeNodes.string)
700
+ };
597
701
  }
598
702
  /**
599
- * Creates a TypeScript type literal node (anonymous object type).
600
- */
601
- const createTypeLiteralNode = factory.createTypeLiteralNode;
602
- /**
603
- * Creates a TypeScript type reference node (e.g., `Array<string>`, `Record<K, V>`).
604
- */
605
- const createTypeReferenceNode = factory.createTypeReferenceNode;
606
- /**
607
- * Converts a primitive const value to a TypeScript literal type node.
608
- * Handles negative numbers via a prefix unary expression.
703
+ * Converts a primitive const value to a TypeScript literal type.
609
704
  */
610
705
  function constToTypeNode(value, format) {
611
- if (format === "boolean") return factory.createLiteralTypeNode(value === true ? factory.createTrue() : factory.createFalse());
612
- const literal = format === "number" && typeof value === "number" ? value : String(value);
613
- return factory.createLiteralTypeNode(valueToExpression(literal));
706
+ if (format === "boolean") return createLiteralType(value === true);
707
+ return createLiteralType(format === "number" && typeof value === "number" ? value : String(value));
614
708
  }
615
709
  /**
616
- * Returns a `Date` reference type node when `representation` is `'date'`, otherwise falls back to `string`.
710
+ * Returns a `Date` reference type when `representation` is `'date'`, otherwise falls back to `string`.
617
711
  */
618
712
  function dateOrStringNode(node) {
619
- return node.representation === "date" ? createTypeReferenceNode(factory.createIdentifier("Date")) : keywordTypeNodes.string;
713
+ return node.representation === "date" ? createTypeReferenceNode("Date") : keywordTypeNodes.string;
620
714
  }
621
715
  /**
622
716
  * Maps an array of `SchemaNode`s through the printer, filtering out `null` and `undefined` results.
@@ -625,7 +719,7 @@ function buildMemberNodes(members, print) {
625
719
  return (members ?? []).map(print).filter(isNonNullable$1);
626
720
  }
627
721
  /**
628
- * Builds a TypeScript tuple type node from an array schema's `items`,
722
+ * Builds a TypeScript tuple type from an array schema's `items`,
629
723
  * applying min/max slice and optional/rest element rules.
630
724
  */
631
725
  function buildTupleNode(node, print) {
@@ -636,9 +730,21 @@ function buildTupleNode(node, print) {
636
730
  items = items.slice(0, max);
637
731
  if (items.length < max && restNode) items = [...items, ...Array(max - items.length).fill(restNode)];
638
732
  }
639
- if (min !== void 0) items = items.map((item, i) => i >= min ? factory.createOptionalTypeNode(item) : item);
640
- if (max === void 0 && restNode) items.push(factory.createRestTypeNode(factory.createArrayTypeNode(restNode)));
641
- return factory.createTupleTypeNode(items);
733
+ if (min !== void 0) items = items.map((item, i) => i >= min ? {
734
+ type: "TSOptionalType",
735
+ typeAnnotation: item
736
+ } : item);
737
+ if (max === void 0 && restNode) items.push({
738
+ type: "TSRestType",
739
+ typeAnnotation: {
740
+ type: "TSArrayType",
741
+ elementType: restNode
742
+ }
743
+ });
744
+ return {
745
+ type: "TSTupleType",
746
+ elementTypes: items
747
+ };
642
748
  }
643
749
  /**
644
750
  * Appends `| null` and then `| undefined` to a type when requested.
@@ -655,8 +761,6 @@ function buildPropertyType(schema, baseType, optionalType, optional) {
655
761
  const meta = (0, kubb_kit.syncSchemaRef)(schema);
656
762
  return wrapNullableOptional(baseType, !!meta.nullable, addsUndefined && !!(optional || meta.nullish || meta.optional));
657
763
  }
658
- const indexSignaturePrinter = typescript.createPrinter();
659
- const indexSignatureSource = typescript.createSourceFile("", "", typescript.ScriptTarget.Latest);
660
764
  /**
661
765
  * Creates a TypeScript index signature for `additionalProperties` and `patternProperties` on an
662
766
  * object schema node. TypeScript allows only one string index signature and its value must be
@@ -664,21 +768,35 @@ const indexSignatureSource = typescript.createSourceFile("", "", typescript.Scri
664
768
  * union of all value types (deduplicated), or `unknown` when the object also has fixed properties.
665
769
  * The key regex of `patternProperties` cannot be expressed by an index signature and is dropped.
666
770
  */
667
- function buildIndexSignatures(node, propertyCount, print) {
771
+ function buildIndexSignatures(node, propertyCount, printNode) {
668
772
  const valueTypes = [];
669
- if (node.additionalProperties && node.additionalProperties !== true) valueTypes.push(print(node.additionalProperties) ?? keywordTypeNodes.unknown);
773
+ if (node.additionalProperties && node.additionalProperties !== true) valueTypes.push(printNode(node.additionalProperties) ?? keywordTypeNodes.unknown);
670
774
  else if (node.additionalProperties === true) valueTypes.push(keywordTypeNodes.unknown);
671
775
  for (const schema of Object.values(node.patternProperties ?? {})) {
672
- const patternType = print(schema) ?? keywordTypeNodes.unknown;
776
+ const patternType = printNode(schema) ?? keywordTypeNodes.unknown;
673
777
  valueTypes.push(schema.nullable ? createUnionDeclaration({ nodes: [patternType, keywordTypeNodes.null] }) : patternType);
674
778
  }
675
779
  if (valueTypes.length === 0) return [];
676
- const seen = /* @__PURE__ */ new Set();
677
- const distinct = valueTypes.filter((type) => {
678
- const key = indexSignaturePrinter.printNode(typescript.EmitHint.Unspecified, type, indexSignatureSource);
679
- return seen.has(key) ? false : (seen.add(key), true);
680
- });
681
- return [createIndexSignature(propertyCount > 0 ? keywordTypeNodes.unknown : createUnionDeclaration({ nodes: distinct }))];
780
+ const distinct = [...new Map(valueTypes.map((type) => [print(type), type])).values()];
781
+ const valueType = propertyCount > 0 ? keywordTypeNodes.unknown : createUnionDeclaration({ nodes: distinct });
782
+ return [{
783
+ type: "TSIndexSignature",
784
+ parameters: [{
785
+ type: "Identifier",
786
+ name: "key",
787
+ typeAnnotation: {
788
+ type: "TSTypeAnnotation",
789
+ typeAnnotation: keywordTypeNodes.string
790
+ }
791
+ }],
792
+ typeAnnotation: {
793
+ type: "TSTypeAnnotation",
794
+ typeAnnotation: valueType
795
+ },
796
+ readonly: false,
797
+ static: false,
798
+ accessibility: null
799
+ }];
682
800
  }
683
801
  //#endregion
684
802
  //#region src/components/Enum.tsx
@@ -733,7 +851,7 @@ function Enum({ node, enum: enumOptions, resolver }) {
733
851
  isExportable: true,
734
852
  isIndexable: true,
735
853
  isTypeOnly: false,
736
- children: (0, _kubb_parser_ts.parserTs)().print(nameNode)
854
+ children: nameNode
737
855
  }), /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Source, {
738
856
  name: typeName,
739
857
  isIndexable: !namesMerge,
@@ -743,7 +861,7 @@ function Enum({ node, enum: enumOptions, resolver }) {
743
861
  "literal",
744
862
  void 0
745
863
  ].includes(enumOptions.type),
746
- children: (0, _kubb_parser_ts.parserTs)().print(typeNode)
864
+ children: typeNode
747
865
  })] });
748
866
  }
749
867
  //#endregion
@@ -1197,12 +1315,30 @@ function Type({ name, node, printer, enum: enumOptions, resolver }) {
1197
1315
  //#region src/printers/printerTs.ts
1198
1316
  const { isNonNullable } = factory_exports;
1199
1317
  /**
1318
+ * Adapts user overrides, which work in strings, to the node-based printer: `this.transform` hands them printed
1319
+ * strings and their result is wrapped back into a node. A deprecated compiler node prints through `@kubb/parser-ts`.
1320
+ */
1321
+ function toNodeHandlers(nodes) {
1322
+ return Object.fromEntries(Object.entries(nodes ?? {}).map(([type, handler]) => [type, function(node) {
1323
+ const transform = (child) => {
1324
+ const output = this.transform(child);
1325
+ return output ? print(output) : null;
1326
+ };
1327
+ const result = handler.call({
1328
+ ...this,
1329
+ transform
1330
+ }, node);
1331
+ if (result === null || result === void 0) return result;
1332
+ return createRaw(typeof result === "string" ? result : (0, _kubb_parser_ts.parserTs)().print(result).trimEnd());
1333
+ }]));
1334
+ }
1335
+ /**
1200
1336
  * TypeScript type printer built with `definePrinter`.
1201
1337
  *
1202
- * Converts a `SchemaNode` AST node into a TypeScript AST node:
1203
- * - **`printer.print(node)`** — when `options.typeName` is set, returns a full
1204
- * `type Name = …` or `interface Name { … }` declaration (`ts.Node`).
1205
- * Without `typeName`, returns the raw `ts.TypeNode` for the schema.
1338
+ * Converts a `SchemaNode` AST node into TypeScript source:
1339
+ * - **`printer.print(node)`** — when `options.name` is set, returns a full
1340
+ * `type Name = …` or `interface Name { … }` declaration.
1341
+ * Without `name`, returns the type for the schema, such as `string | null`.
1206
1342
  *
1207
1343
  * Dispatches on `node.type` to the appropriate handler in `nodes`. Options are closed
1208
1344
  * over per printer instance, so each call to `printerTs(options)` produces an independent printer.
@@ -1210,13 +1346,13 @@ const { isNonNullable } = factory_exports;
1210
1346
  * @example Raw type node (no `typeName`)
1211
1347
  * ```ts
1212
1348
  * const printer = printerTs({ optionalType: 'questionToken', arrayType: 'array', enum: { type: 'inlineLiteral' } })
1213
- * const typeNode = printer.print(schemaNode) // ts.TypeNode
1349
+ * const type = printer.print(schemaNode) // 'string | null'
1214
1350
  * ```
1215
1351
  *
1216
1352
  * @example Full declaration (with `typeName`)
1217
1353
  * ```ts
1218
1354
  * const printer = printerTs({ optionalType: 'questionToken', arrayType: 'array', enum: { type: 'inlineLiteral' }, typeName: 'MyType' })
1219
- * const declaration = printer.print(schemaNode) // ts.TypeAliasDeclaration | ts.InterfaceDeclaration
1355
+ * const declaration = printer.print(schemaNode) // 'export type MyType = …'
1220
1356
  * ```
1221
1357
  */
1222
1358
  const printerTs = kubb_kit.ast.createPrinter((options) => {
@@ -1231,7 +1367,7 @@ const printerTs = kubb_kit.ast.createPrinter((options) => {
1231
1367
  never: () => keywordTypeNodes.never,
1232
1368
  boolean: () => keywordTypeNodes.boolean,
1233
1369
  null: () => keywordTypeNodes.null,
1234
- blob: () => createTypeReferenceNode("Blob", []),
1370
+ blob: () => createTypeReferenceNode("Blob"),
1235
1371
  string: () => keywordTypeNodes.string,
1236
1372
  uuid: () => keywordTypeNodes.string,
1237
1373
  email: () => keywordTypeNodes.string,
@@ -1251,27 +1387,22 @@ const printerTs = kubb_kit.ast.createPrinter((options) => {
1251
1387
  if (!node.name) return null;
1252
1388
  const refName = kubb_kit.ast.resolveRefName(node);
1253
1389
  if (!refName) return null;
1254
- const name = node.ref ? enumTypeName({
1390
+ return createTypeReferenceNode(node.ref ? enumTypeName({
1255
1391
  resolver: this.options.resolver,
1256
1392
  name: refName,
1257
1393
  enumOptions: this.options.enum,
1258
1394
  isEnum: !!this.options.enumSchemaNames?.has(refName)
1259
- }) : refName;
1260
- return createTypeReferenceNode(name, void 0);
1395
+ }) : refName);
1261
1396
  },
1262
1397
  enum(node) {
1263
1398
  const values = kubb_kit.ast.getSchemaLiteralValues(node);
1264
- if (this.options.enum.type === "inlineLiteral" || !node.name || isInlineConstEnum(node, this.options.enumSchemaNames)) return createUnionDeclaration({
1265
- withParentheses: true,
1266
- nodes: values.filter((v) => v !== null && v !== void 0).map((value) => constToTypeNode(value, typeof value)).filter(isNonNullable)
1267
- });
1268
- const resolvedName = enumTypeName({
1399
+ if (this.options.enum.type === "inlineLiteral" || !node.name || isInlineConstEnum(node, this.options.enumSchemaNames)) return createUnionDeclaration({ nodes: values.filter((v) => v !== null && v !== void 0).map((value) => constToTypeNode(value, typeof value)).filter(isNonNullable) });
1400
+ return createTypeReferenceNode(enumTypeName({
1269
1401
  resolver: this.options.resolver,
1270
1402
  name: node.name,
1271
1403
  enumOptions: this.options.enum,
1272
1404
  isEnum: true
1273
- });
1274
- return createTypeReferenceNode(resolvedName, void 0);
1405
+ }));
1275
1406
  },
1276
1407
  union(node) {
1277
1408
  const members = node.members ?? [];
@@ -1279,26 +1410,14 @@ const printerTs = kubb_kit.ast.createPrinter((options) => {
1279
1410
  return kubb_kit.ast.narrowSchema(m, kubb_kit.ast.schemaTypes.enum)?.primitive === "string";
1280
1411
  });
1281
1412
  const hasPlainString = members.some((m) => (0, kubb_kit.isStringType)(m));
1282
- if (hasStringLiteral && hasPlainString) return createUnionDeclaration({
1283
- withParentheses: true,
1284
- nodes: members.map((m) => {
1285
- if ((0, kubb_kit.isStringType)(m)) return createIntersectionDeclaration({
1286
- nodes: [keywordTypeNodes.string, createTypeLiteralNode([])],
1287
- withParentheses: true
1288
- });
1289
- return this.transform(m);
1290
- }).filter(isNonNullable)
1291
- });
1292
- return createUnionDeclaration({
1293
- withParentheses: true,
1294
- nodes: buildMemberNodes(members, this.transform)
1295
- });
1413
+ if (hasStringLiteral && hasPlainString) return createUnionDeclaration({ nodes: members.map((m) => {
1414
+ if ((0, kubb_kit.isStringType)(m)) return createIntersectionDeclaration({ nodes: [keywordTypeNodes.string, createTypeLiteralNode([])] });
1415
+ return this.transform(m);
1416
+ }).filter(isNonNullable) });
1417
+ return createUnionDeclaration({ nodes: buildMemberNodes(members, this.transform) });
1296
1418
  },
1297
1419
  intersection(node) {
1298
- return createIntersectionDeclaration({
1299
- withParentheses: true,
1300
- nodes: buildMemberNodes(node.members, this.transform)
1301
- });
1420
+ return createIntersectionDeclaration({ nodes: buildMemberNodes(node.members, this.transform) });
1302
1421
  },
1303
1422
  array(node) {
1304
1423
  return createArrayDeclaration({
@@ -1331,35 +1450,30 @@ const printerTs = kubb_kit.ast.createPrinter((options) => {
1331
1450
  if (!allElements.length) return keywordTypeNodes.object;
1332
1451
  return createTypeLiteralNode(allElements);
1333
1452
  },
1334
- ...options.nodes
1453
+ ...toNodeHandlers(options.nodes)
1335
1454
  },
1336
1455
  print(node) {
1337
1456
  const { name, syntaxType = "type", description, keysToOmit } = this.options;
1338
1457
  const transformed = this.transform(node);
1339
1458
  if (!transformed) return null;
1340
1459
  const meta = (0, kubb_kit.syncSchemaRef)(node);
1341
- if (!name) {
1342
- const result = wrapNullableOptional(transformed, !!meta.nullable, !!(meta.nullish || meta.optional) && addsUndefined);
1343
- return (0, _kubb_parser_ts.parserTs)().print(result);
1344
- }
1345
- const inner = (() => {
1346
- return wrapNullableOptional(keysToOmit?.length ? createOmitDeclaration({
1347
- keys: keysToOmit,
1348
- type: transformed,
1349
- nonNullable: true
1350
- }) : transformed, !!meta.nullable, !!(meta.nullish || meta.optional));
1351
- })();
1352
- const typeNode = createTypeDeclaration({
1460
+ if (!name) return print(wrapNullableOptional(transformed, !!meta.nullable, !!(meta.nullish || meta.optional) && addsUndefined));
1461
+ return createTypeDeclaration({
1353
1462
  name,
1354
1463
  isExportable: true,
1355
- type: inner,
1356
- syntax: syntaxType === "type" || isUnionTypeNode(inner) || !!keysToOmit?.length ? "type" : "interface",
1464
+ type: (() => {
1465
+ return wrapNullableOptional(keysToOmit?.length ? createOmitDeclaration({
1466
+ keys: keysToOmit,
1467
+ type: transformed,
1468
+ nonNullable: true
1469
+ }) : transformed, !!meta.nullable, !!(meta.nullish || meta.optional));
1470
+ })(),
1471
+ syntax: syntaxType === "type" || !!keysToOmit?.length ? "type" : "interface",
1357
1472
  comments: buildPropertyJSDocComments({
1358
1473
  ...meta,
1359
1474
  description
1360
1475
  })
1361
1476
  });
1362
- return (0, _kubb_parser_ts.parserTs)().print(typeNode);
1363
1477
  }
1364
1478
  };
1365
1479
  });
@@ -1642,7 +1756,7 @@ var compatibility = {
1642
1756
  };
1643
1757
  //#endregion
1644
1758
  //#region package.json
1645
- var version = "5.1.0-canary.20261023T200213";
1759
+ var version = "5.2.0-canary.20261024T091509";
1646
1760
  //#endregion
1647
1761
  //#region src/resolvers/resolverTs.ts
1648
1762
  /**