@kubb/plugin-ts 5.0.0-alpha.4 → 5.0.0-alpha.6

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.
Files changed (35) hide show
  1. package/dist/{components-CRjwjdyE.js → components-CRu8IKY3.js} +12 -8
  2. package/dist/components-CRu8IKY3.js.map +1 -0
  3. package/dist/{components-DI0aTIBg.cjs → components-DeNDKlzf.cjs} +12 -8
  4. package/dist/components-DeNDKlzf.cjs.map +1 -0
  5. package/dist/components.cjs +1 -1
  6. package/dist/components.d.ts +1 -3
  7. package/dist/components.js +1 -1
  8. package/dist/generators.cjs +1 -1
  9. package/dist/generators.d.ts +2 -3
  10. package/dist/generators.js +1 -1
  11. package/dist/index.cjs +1 -1
  12. package/dist/index.d.ts +1 -1
  13. package/dist/index.js +1 -1
  14. package/dist/{plugin-Bgm8TNUt.js → plugin-BcK4SBA0.js} +510 -243
  15. package/dist/plugin-BcK4SBA0.js.map +1 -0
  16. package/dist/{plugin-DvK-Uhvv.cjs → plugin-BrQcApyO.cjs} +510 -244
  17. package/dist/plugin-BrQcApyO.cjs.map +1 -0
  18. package/dist/{types-aotMcdUB.d.ts → types-CsvB6X5Y.d.ts} +11 -14
  19. package/package.json +8 -8
  20. package/src/components/Type.tsx +0 -3
  21. package/src/components/v2/Enum.tsx +67 -0
  22. package/src/components/v2/Type.tsx +22 -117
  23. package/src/constants.ts +29 -0
  24. package/src/factory.ts +12 -16
  25. package/src/generators/typeGenerator.tsx +2 -4
  26. package/src/generators/v2/typeGenerator.tsx +78 -103
  27. package/src/generators/v2/utils.ts +140 -0
  28. package/src/parser.ts +1 -8
  29. package/src/plugin.ts +11 -2
  30. package/src/printer.ts +235 -111
  31. package/src/types.ts +10 -13
  32. package/dist/components-CRjwjdyE.js.map +0 -1
  33. package/dist/components-DI0aTIBg.cjs.map +0 -1
  34. package/dist/plugin-Bgm8TNUt.js.map +0 -1
  35. package/dist/plugin-DvK-Uhvv.cjs.map +0 -1
@@ -1,14 +1,14 @@
1
1
  import "./chunk--u3MIqq1.js";
2
- import { A as keywordTypeNodes, C as createTypeDeclaration, D as createUnionDeclaration, E as createTypeReferenceNode, F as camelCase, I as pascalCase, M as syntaxKind, N as jsStringEscape, O as createUrlTemplateType, P as trimQuotes, S as createTypeAliasDeclaration, T as createTypeOperatorNode, _ as createPropertySignature, a as createArrayTypeNode, b as createTrue, c as createIdentifier, d as createIntersectionDeclaration, f as createLiteralTypeNode, g as createPrefixUnaryExpression, h as createOptionalTypeNode, i as createArrayDeclaration, j as modifiers, k as getUnknownType, l as createIndexSignature, m as createOmitDeclaration, n as SyntaxKind, o as createEnumDeclaration, p as createNumericLiteral, r as appendJSDocToNode, s as createFalse, t as Type$1, u as createIndexedAccessTypeNode, v as createRestTypeNode, w as createTypeLiteralNode, x as createTupleTypeNode, y as createStringLiteral } from "./components-CRjwjdyE.js";
2
+ import { A as keywordTypeNodes, C as createTypeDeclaration, D as createUnionDeclaration, E as createTypeReferenceNode, F as camelCase, I as pascalCase, M as syntaxKind, N as jsStringEscape, O as createUrlTemplateType, P as trimQuotes, S as createTypeAliasDeclaration, T as createTypeOperatorNode, _ as createPropertySignature, a as createArrayTypeNode, b as createTrue, c as createIdentifier, d as createIntersectionDeclaration, f as createLiteralTypeNode, g as createPrefixUnaryExpression, h as createOptionalTypeNode, i as createArrayDeclaration, j as modifiers, k as getUnknownType, l as createIndexSignature, m as createOmitDeclaration, n as SyntaxKind, o as createEnumDeclaration, p as createNumericLiteral, r as appendJSDocToNode, s as createFalse, t as Type$1, u as createIndexedAccessTypeNode, v as createRestTypeNode, w as createTypeLiteralNode, x as createTupleTypeNode, y as createStringLiteral } from "./components-CRu8IKY3.js";
3
3
  import path from "node:path";
4
- import { collect, isPlainStringType, walk } from "@kubb/ast";
4
+ import { applyParamsCasing, collect, createProperty, createSchema, isPlainStringType, walk } from "@kubb/ast";
5
5
  import { defineGenerator, definePlugin, definePrinter, getBarrelFiles, getMode, resolveOptions } from "@kubb/core";
6
6
  import { OperationGenerator, SchemaGenerator, buildOperation, buildSchema, isKeyword, pluginOasName, schemaKeywords } from "@kubb/plugin-oas";
7
7
  import { useKubb, useMode, usePluginManager } from "@kubb/core/hooks";
8
8
  import { safePrint } from "@kubb/fabric-core/parsers/typescript";
9
9
  import { createReactGenerator } from "@kubb/plugin-oas/generators";
10
10
  import { useOas, useOperationManager, useSchemaManager } from "@kubb/plugin-oas/hooks";
11
- import { applyParamsCasing, getBanner, getFooter, getImports, isParameterSchema } from "@kubb/plugin-oas/utils";
11
+ import { applyParamsCasing as applyParamsCasing$1, getBanner, getFooter, getImports, isParameterSchema } from "@kubb/plugin-oas/utils";
12
12
  import { File } from "@kubb/react-fabric";
13
13
  import ts from "typescript";
14
14
  import { Fragment, jsx, jsxs } from "@kubb/react-fabric/jsx-runtime";
@@ -202,7 +202,7 @@ function printResponseSchema({ baseName, schemas, pluginManager, unknownType })
202
202
  const typeGenerator$1 = createReactGenerator({
203
203
  name: "typescript",
204
204
  Operation({ operation, generator, plugin }) {
205
- const { options, options: { mapper, enumType, enumKeyCasing, syntaxType, optionalType, arrayType, unknownType, paramsCasing } } = plugin;
205
+ const { options, options: { enumType, enumKeyCasing, syntaxType, optionalType, arrayType, unknownType, paramsCasing } } = plugin;
206
206
  const mode = useMode();
207
207
  const pluginManager = usePluginManager();
208
208
  const oas = useOas();
@@ -232,7 +232,7 @@ const typeGenerator$1 = createReactGenerator({
232
232
  schemas.response
233
233
  ].flat().filter(Boolean);
234
234
  const mapOperationSchema = ({ name, schema, description, keysToOmit, ...options }) => {
235
- const transformedSchema = paramsCasing && isParameterSchema(name) ? applyParamsCasing(schema, paramsCasing) : schema;
235
+ const transformedSchema = paramsCasing && isParameterSchema(name) ? applyParamsCasing$1(schema, paramsCasing) : schema;
236
236
  const tree = schemaGenerator.parse({
237
237
  schema: transformedSchema,
238
238
  name,
@@ -261,7 +261,6 @@ const typeGenerator$1 = createReactGenerator({
261
261
  description,
262
262
  tree,
263
263
  schema: transformedSchema,
264
- mapper,
265
264
  enumType,
266
265
  enumKeyCasing,
267
266
  optionalType,
@@ -321,7 +320,7 @@ const typeGenerator$1 = createReactGenerator({
321
320
  });
322
321
  },
323
322
  Schema({ schema, plugin }) {
324
- const { options: { mapper, enumType, enumKeyCasing, syntaxType, optionalType, arrayType, output } } = plugin;
323
+ const { options: { enumType, enumKeyCasing, syntaxType, optionalType, arrayType, output } } = plugin;
325
324
  const mode = useMode();
326
325
  const oas = useOas();
327
326
  const pluginManager = usePluginManager();
@@ -363,7 +362,6 @@ const typeGenerator$1 = createReactGenerator({
363
362
  description: schema.value.description,
364
363
  tree: schema.tree,
365
364
  schema: schema.value,
366
- mapper,
367
365
  enumType,
368
366
  enumKeyCasing,
369
367
  optionalType,
@@ -374,7 +372,45 @@ const typeGenerator$1 = createReactGenerator({
374
372
  }
375
373
  });
376
374
  //#endregion
375
+ //#region src/constants.ts
376
+ /**
377
+ * `optionalType` values that cause a property's type to include `| undefined`.
378
+ */
379
+ const OPTIONAL_ADDS_UNDEFINED = new Set(["undefined", "questionTokenAndUndefined"]);
380
+ /**
381
+ * `optionalType` values that render the property key with a `?` token.
382
+ */
383
+ const OPTIONAL_ADDS_QUESTION_TOKEN = new Set(["questionToken", "questionTokenAndUndefined"]);
384
+ /**
385
+ * `enumType` values that append a `Key` suffix to the generated enum type alias.
386
+ */
387
+ const ENUM_TYPES_WITH_KEY_SUFFIX = new Set(["asConst", "asPascalConst"]);
388
+ /**
389
+ * `enumType` values that require a runtime value declaration (object, enum, or literal).
390
+ */
391
+ const ENUM_TYPES_WITH_RUNTIME_VALUE = new Set([
392
+ "enum",
393
+ "asConst",
394
+ "asPascalConst",
395
+ "constEnum",
396
+ "literal",
397
+ void 0
398
+ ]);
399
+ /**
400
+ * `enumType` values whose type declaration is type-only (no runtime value emitted for the type alias).
401
+ */
402
+ const ENUM_TYPES_WITH_TYPE_ONLY = new Set([
403
+ "asConst",
404
+ "asPascalConst",
405
+ "literal",
406
+ void 0
407
+ ]);
408
+ //#endregion
377
409
  //#region src/printer.ts
410
+ /**
411
+ * Converts a primitive const value to a TypeScript literal type node.
412
+ * Handles negative numbers via a prefix unary expression.
413
+ */
378
414
  function constToTypeNode(value, format) {
379
415
  if (format === "boolean") return createLiteralTypeNode(value === true ? createTrue() : createFalse());
380
416
  if (format === "number" && typeof value === "number") {
@@ -383,12 +419,22 @@ function constToTypeNode(value, format) {
383
419
  }
384
420
  return createLiteralTypeNode(createStringLiteral(String(value)));
385
421
  }
422
+ /**
423
+ * Returns a `Date` reference type node when `representation` is `'date'`, otherwise falls back to `string`.
424
+ */
386
425
  function dateOrStringNode(node) {
387
426
  return node.representation === "date" ? createTypeReferenceNode(createIdentifier("Date")) : keywordTypeNodes.string;
388
427
  }
428
+ /**
429
+ * Maps an array of `SchemaNode`s through the printer, filtering out `null` and `undefined` results.
430
+ */
389
431
  function buildMemberNodes(members, print) {
390
432
  return (members ?? []).map(print).filter(Boolean);
391
433
  }
434
+ /**
435
+ * Builds a TypeScript tuple type node from an array schema's `items`,
436
+ * applying min/max slice and optional/rest element rules.
437
+ */
392
438
  function buildTupleNode(node, print) {
393
439
  let items = (node.items ?? []).map(print).filter(Boolean);
394
440
  const restNode = node.rest ? print(node.rest) ?? void 0 : void 0;
@@ -401,13 +447,19 @@ function buildTupleNode(node, print) {
401
447
  if (max === void 0 && restNode) items.push(createRestTypeNode(createArrayTypeNode(restNode)));
402
448
  return createTupleTypeNode(items);
403
449
  }
450
+ /**
451
+ * Applies `nullable` and optional/nullish `| undefined` union modifiers to a property's resolved base type.
452
+ */
404
453
  function buildPropertyType(schema, baseType, optionalType) {
405
- const addsUndefined = ["undefined", "questionTokenAndUndefined"].includes(optionalType);
454
+ const addsUndefined = OPTIONAL_ADDS_UNDEFINED.has(optionalType);
406
455
  let type = baseType;
407
456
  if (schema.nullable) type = createUnionDeclaration({ nodes: [type, keywordTypeNodes.null] });
408
457
  if ((schema.nullish || schema.optional) && addsUndefined) type = createUnionDeclaration({ nodes: [type, keywordTypeNodes.undefined] });
409
458
  return type;
410
459
  }
460
+ /**
461
+ * Collects JSDoc annotation strings (description, deprecated, min/max, pattern, default, example, type) for a schema node.
462
+ */
411
463
  function buildPropertyJSDocComments(schema) {
412
464
  return [
413
465
  "description" in schema && schema.description ? `@description ${jsStringEscape(schema.description)}` : void 0,
@@ -420,6 +472,9 @@ function buildPropertyJSDocComments(schema) {
420
472
  "primitive" in schema && schema.primitive ? [`@type ${schema.primitive || "unknown"}`, "optional" in schema && schema.optional ? " | undefined" : void 0].filter(Boolean).join("") : void 0
421
473
  ];
422
474
  }
475
+ /**
476
+ * Creates TypeScript index signatures for `additionalProperties` and `patternProperties` on an object schema node.
477
+ */
423
478
  function buildIndexSignatures(node, propertyCount, print) {
424
479
  const elements = [];
425
480
  if (node.additionalProperties && node.additionalProperties !== true) {
@@ -437,224 +492,405 @@ function buildIndexSignatures(node, propertyCount, print) {
437
492
  return elements;
438
493
  }
439
494
  /**
440
- * Converts a `SchemaNode` AST node into a TypeScript `ts.TypeNode`.
495
+ * TypeScript type printer built with `definePrinter`.
496
+ *
497
+ * Converts a `SchemaNode` AST node into a TypeScript AST node:
498
+ * - **`printer.print(node)`** — when `options.typeName` is set, returns a full
499
+ * `type Name = …` or `interface Name { … }` declaration (`ts.Node`).
500
+ * Without `typeName`, returns the raw `ts.TypeNode` for the schema.
441
501
  *
442
- * Built on `definePrinter` dispatches on `node.type`, with options closed over
443
- * per printer instance. Produces the same `ts.TypeNode` output as the keyword-based
444
- * `parse` in `parser.ts`.
502
+ * Dispatches on `node.type` to the appropriate handler in `nodes`. Options are closed
503
+ * over per printer instance, so each call to `printerTs(options)` produces an independent printer.
504
+ *
505
+ * @example Raw type node (no `typeName`)
506
+ * ```ts
507
+ * const printer = printerTs({ optionalType: 'questionToken', arrayType: 'array', enumType: 'inlineLiteral' })
508
+ * const typeNode = printer.print(schemaNode) // ts.TypeNode
509
+ * ```
510
+ *
511
+ * @example Full declaration (with `typeName`)
512
+ * ```ts
513
+ * const printer = printerTs({ optionalType: 'questionToken', arrayType: 'array', enumType: 'inlineLiteral', typeName: 'MyType' })
514
+ * const declaration = printer.print(schemaNode) // ts.TypeAliasDeclaration | ts.InterfaceDeclaration
515
+ * ```
445
516
  */
446
- const printerTs = definePrinter((options) => ({
447
- name: "typescript",
448
- options,
449
- nodes: {
450
- any: () => keywordTypeNodes.any,
451
- unknown: () => keywordTypeNodes.unknown,
452
- void: () => keywordTypeNodes.void,
453
- boolean: () => keywordTypeNodes.boolean,
454
- null: () => keywordTypeNodes.null,
455
- blob: () => createTypeReferenceNode("Blob", []),
456
- string: () => keywordTypeNodes.string,
457
- uuid: () => keywordTypeNodes.string,
458
- email: () => keywordTypeNodes.string,
459
- url: () => keywordTypeNodes.string,
460
- datetime: () => keywordTypeNodes.string,
461
- number: () => keywordTypeNodes.number,
462
- integer: () => keywordTypeNodes.number,
463
- bigint: () => keywordTypeNodes.bigint,
464
- date: (node) => dateOrStringNode(node),
465
- time: (node) => dateOrStringNode(node),
466
- ref(node) {
467
- if (!node.name) return;
468
- return createTypeReferenceNode(node.name, void 0);
469
- },
470
- enum(node) {
471
- const values = node.namedEnumValues?.map((v) => v.value) ?? node.enumValues ?? [];
472
- if (this.options.enumType === "inlineLiteral" || !node.name) return createUnionDeclaration({
473
- withParentheses: true,
474
- nodes: values.filter((v) => v !== null).map((value) => constToTypeNode(value, typeof value === "number" ? "number" : typeof value === "boolean" ? "boolean" : "string")).filter(Boolean)
475
- }) ?? void 0;
476
- return createTypeReferenceNode(["asConst", "asPascalConst"].includes(this.options.enumType) ? `${node.name}Key` : node.name, void 0);
477
- },
478
- union(node) {
479
- const members = node.members ?? [];
480
- const hasStringLiteral = members.some((m) => m.type === "enum" && m.enumType === "string");
481
- const hasPlainString = members.some((m) => isPlainStringType(m));
482
- if (hasStringLiteral && hasPlainString) return createUnionDeclaration({
483
- withParentheses: true,
484
- nodes: members.map((m) => {
485
- if (isPlainStringType(m)) return createIntersectionDeclaration({
486
- nodes: [keywordTypeNodes.string, createTypeLiteralNode([])],
487
- withParentheses: true
517
+ const printerTs = definePrinter((options) => {
518
+ const addsUndefined = OPTIONAL_ADDS_UNDEFINED.has(options.optionalType);
519
+ return {
520
+ name: "typescript",
521
+ options,
522
+ nodes: {
523
+ any: () => keywordTypeNodes.any,
524
+ unknown: () => keywordTypeNodes.unknown,
525
+ void: () => keywordTypeNodes.void,
526
+ never: () => keywordTypeNodes.never,
527
+ boolean: () => keywordTypeNodes.boolean,
528
+ null: () => keywordTypeNodes.null,
529
+ blob: () => createTypeReferenceNode("Blob", []),
530
+ string: () => keywordTypeNodes.string,
531
+ uuid: () => keywordTypeNodes.string,
532
+ email: () => keywordTypeNodes.string,
533
+ url: (node) => {
534
+ if (node.path) return createUrlTemplateType(node.path);
535
+ return keywordTypeNodes.string;
536
+ },
537
+ datetime: () => keywordTypeNodes.string,
538
+ number: () => keywordTypeNodes.number,
539
+ integer: () => keywordTypeNodes.number,
540
+ bigint: () => keywordTypeNodes.bigint,
541
+ date: dateOrStringNode,
542
+ time: dateOrStringNode,
543
+ ref(node) {
544
+ if (!node.name) return;
545
+ return createTypeReferenceNode(node.name, void 0);
546
+ },
547
+ enum(node) {
548
+ const values = node.namedEnumValues?.map((v) => v.value) ?? node.enumValues ?? [];
549
+ if (this.options.enumType === "inlineLiteral" || !node.name) return createUnionDeclaration({
550
+ withParentheses: true,
551
+ nodes: values.filter((v) => v !== null).map((value) => constToTypeNode(value, typeof value)).filter(Boolean)
552
+ }) ?? void 0;
553
+ const resolvedName = pascalCase(node.name);
554
+ return createTypeReferenceNode(ENUM_TYPES_WITH_KEY_SUFFIX.has(this.options.enumType) ? `${resolvedName}Key` : resolvedName, void 0);
555
+ },
556
+ union(node) {
557
+ const members = node.members ?? [];
558
+ const hasStringLiteral = members.some((m) => m.type === "enum" && m.enumType === "string");
559
+ const hasPlainString = members.some((m) => isPlainStringType(m));
560
+ if (hasStringLiteral && hasPlainString) return createUnionDeclaration({
561
+ withParentheses: true,
562
+ nodes: members.map((m) => {
563
+ if (isPlainStringType(m)) return createIntersectionDeclaration({
564
+ nodes: [keywordTypeNodes.string, createTypeLiteralNode([])],
565
+ withParentheses: true
566
+ });
567
+ return this.print(m);
568
+ }).filter(Boolean)
569
+ }) ?? void 0;
570
+ return createUnionDeclaration({
571
+ withParentheses: true,
572
+ nodes: buildMemberNodes(members, this.print)
573
+ }) ?? void 0;
574
+ },
575
+ intersection(node) {
576
+ return createIntersectionDeclaration({
577
+ withParentheses: true,
578
+ nodes: buildMemberNodes(node.members, this.print)
579
+ }) ?? void 0;
580
+ },
581
+ array(node) {
582
+ return createArrayDeclaration({
583
+ nodes: (node.items ?? []).map((item) => this.print(item)).filter(Boolean),
584
+ arrayType: this.options.arrayType
585
+ }) ?? void 0;
586
+ },
587
+ tuple(node) {
588
+ return buildTupleNode(node, this.print);
589
+ },
590
+ object(node) {
591
+ const { print, options } = this;
592
+ const addsQuestionToken = OPTIONAL_ADDS_QUESTION_TOKEN.has(options.optionalType);
593
+ const propertyNodes = node.properties.map((prop) => {
594
+ const baseType = print(prop.schema) ?? keywordTypeNodes.unknown;
595
+ const type = buildPropertyType(prop.schema, baseType, options.optionalType);
596
+ return appendJSDocToNode({
597
+ node: createPropertySignature({
598
+ questionToken: prop.schema.optional || prop.schema.nullish ? addsQuestionToken : false,
599
+ name: prop.name,
600
+ type,
601
+ readOnly: prop.schema.readOnly
602
+ }),
603
+ comments: buildPropertyJSDocComments(prop.schema)
488
604
  });
489
- return this.print(m);
490
- }).filter(Boolean)
491
- }) ?? void 0;
492
- return createUnionDeclaration({
493
- withParentheses: true,
494
- nodes: buildMemberNodes(members, this.print)
495
- }) ?? void 0;
496
- },
497
- intersection(node) {
498
- return createIntersectionDeclaration({
499
- withParentheses: true,
500
- nodes: buildMemberNodes(node.members, this.print)
501
- }) ?? void 0;
502
- },
503
- array(node) {
504
- return createArrayDeclaration({
505
- nodes: (node.items ?? []).map((item) => this.print(item)).filter(Boolean),
506
- arrayType: this.options.arrayType
507
- }) ?? void 0;
508
- },
509
- tuple(node) {
510
- return buildTupleNode(node, this.print);
511
- },
512
- object(node) {
513
- const addsQuestionToken = ["questionToken", "questionTokenAndUndefined"].includes(this.options.optionalType);
514
- const { print } = this;
515
- const propertyNodes = node.properties.map((prop) => {
516
- const baseType = print(prop.schema) ?? keywordTypeNodes.unknown;
517
- const type = buildPropertyType(prop.schema, baseType, this.options.optionalType);
518
- return appendJSDocToNode({
519
- node: createPropertySignature({
520
- questionToken: prop.schema.optional || prop.schema.nullish ? addsQuestionToken : false,
521
- name: prop.name,
522
- type,
523
- readOnly: prop.schema.readOnly
524
- }),
525
- comments: buildPropertyJSDocComments(prop.schema)
526
605
  });
606
+ const allElements = [...propertyNodes, ...buildIndexSignatures(node, propertyNodes.length, print)];
607
+ if (!allElements.length) return keywordTypeNodes.object;
608
+ return createTypeLiteralNode(allElements);
609
+ }
610
+ },
611
+ print(node) {
612
+ let type = this.print(node);
613
+ if (!type) return;
614
+ if (node.nullable) type = createUnionDeclaration({ nodes: [type, keywordTypeNodes.null] });
615
+ if ((node.nullish || node.optional) && addsUndefined) type = createUnionDeclaration({ nodes: [type, keywordTypeNodes.undefined] });
616
+ const { typeName, syntaxType = "type", description, keysToOmit } = this.options;
617
+ if (!typeName) return type;
618
+ const useTypeGeneration = syntaxType === "type" || type.kind === syntaxKind.union || !!keysToOmit?.length;
619
+ return createTypeDeclaration({
620
+ name: typeName,
621
+ isExportable: true,
622
+ type: keysToOmit?.length ? createOmitDeclaration({
623
+ keys: keysToOmit,
624
+ type,
625
+ nonNullable: true
626
+ }) : type,
627
+ syntax: useTypeGeneration ? "type" : "interface",
628
+ comments: [
629
+ node?.title ? jsStringEscape(node.title) : void 0,
630
+ description ? `@description ${jsStringEscape(description)}` : void 0,
631
+ node?.deprecated ? "@deprecated" : void 0,
632
+ node && "min" in node && node.min !== void 0 ? `@minLength ${node.min}` : void 0,
633
+ node && "max" in node && node.max !== void 0 ? `@maxLength ${node.max}` : void 0,
634
+ node && "pattern" in node && node.pattern ? `@pattern ${node.pattern}` : void 0,
635
+ node?.default ? `@default ${node.default}` : void 0,
636
+ node?.example ? `@example ${node.example}` : void 0
637
+ ]
527
638
  });
528
- const allElements = [...propertyNodes, ...buildIndexSignatures(node, propertyNodes.length, print)];
529
- if (!allElements.length) return keywordTypeNodes.object;
530
- return createTypeLiteralNode(allElements);
531
639
  }
532
- }
533
- }));
640
+ };
641
+ });
642
+ //#endregion
643
+ //#region src/components/v2/Enum.tsx
644
+ /**
645
+ * Resolves the runtime identifier name and the TypeScript type name for an enum schema node.
646
+ *
647
+ * The raw `node.name` may be a YAML key such as `"enumNames.Type"` which is not a
648
+ * valid TypeScript identifier. `pascalCase` normalizes it unconditionally; for inline enum
649
+ * properties the adapter already emits a PascalCase+suffix name so `pascalCase` is a no-op.
650
+ */
651
+ function getEnumNames(node, enumType) {
652
+ const resolved = pascalCase(node.name);
653
+ return {
654
+ enumName: enumType === "asPascalConst" ? resolved : camelCase(node.name),
655
+ typeName: ENUM_TYPES_WITH_KEY_SUFFIX.has(enumType) ? `${resolved}Key` : resolved
656
+ };
657
+ }
658
+ /**
659
+ * Renders the enum declaration(s) for a single named `EnumSchemaNode`.
660
+ *
661
+ * Depending on `enumType` this may emit:
662
+ * - A runtime object (`asConst` / `asPascalConst`) plus a `typeof` type alias
663
+ * - A `const enum` or plain `enum` declaration (`constEnum` / `enum`)
664
+ * - A union literal type alias (`literal`)
665
+ *
666
+ * The emitted `File.Source` nodes carry the resolved names so that the barrel
667
+ * index picks up the correct export identifiers.
668
+ */
669
+ function Enum({ node, enumType, enumKeyCasing }) {
670
+ const { enumName, typeName } = getEnumNames(node, enumType);
671
+ const [nameNode, typeNode] = createEnumDeclaration({
672
+ name: enumName,
673
+ typeName,
674
+ enums: node.namedEnumValues?.map((v) => [trimQuotes(v.name.toString()), v.value]) ?? node.enumValues?.filter((v) => v !== null && v !== void 0).map((v) => [trimQuotes(v.toString()), v]) ?? [],
675
+ type: enumType,
676
+ enumKeyCasing
677
+ });
678
+ return /* @__PURE__ */ jsxs(Fragment, { children: [nameNode && /* @__PURE__ */ jsx(File.Source, {
679
+ name: enumName,
680
+ isExportable: true,
681
+ isIndexable: true,
682
+ isTypeOnly: false,
683
+ children: safePrint(nameNode)
684
+ }), /* @__PURE__ */ jsx(File.Source, {
685
+ name: typeName,
686
+ isIndexable: true,
687
+ isExportable: ENUM_TYPES_WITH_RUNTIME_VALUE.has(enumType),
688
+ isTypeOnly: ENUM_TYPES_WITH_TYPE_ONLY.has(enumType),
689
+ children: safePrint(typeNode)
690
+ })] });
691
+ }
534
692
  //#endregion
535
693
  //#region src/components/v2/Type.tsx
536
- function Type({ name, typedName, node, keysToOmit, optionalType, arrayType, syntaxType, enumType, enumKeyCasing, ...rest }) {
537
- const typeNodes = [];
538
- const description = rest.description || node?.description;
694
+ function Type({ name, typedName, node, keysToOmit, optionalType, arrayType, syntaxType, enumType, enumKeyCasing, description }) {
695
+ const resolvedDescription = description || node?.description;
539
696
  const enumSchemaNodes = collect(node, { schema(n) {
540
697
  if (n.type === "enum" && n.name) return n;
541
698
  } });
542
- let type = printerTs({
699
+ const typeNode = printerTs({
543
700
  optionalType,
544
701
  arrayType,
545
- enumType
702
+ enumType,
703
+ typeName: name,
704
+ syntaxType,
705
+ description: resolvedDescription,
706
+ keysToOmit
546
707
  }).print(node);
547
- if (!type) return;
548
- if (["asConst", "asPascalConst"].includes(enumType) && enumSchemaNodes.length > 0) {
549
- const isDirectEnum = node.type === "array" && node.items !== void 0;
550
- const isEnumOnly = "enum" in node && node.enum;
551
- if (isDirectEnum || isEnumOnly) {
552
- type = createTypeReferenceNode(`${enumSchemaNodes[0].name}Key`);
553
- if (isDirectEnum) if (arrayType === "generic") type = createTypeReferenceNode(createIdentifier("Array"), [type]);
554
- else type = createArrayTypeNode(type);
555
- }
556
- }
557
- if (node) {
558
- if (node.nullable) type = createUnionDeclaration({ nodes: [type, keywordTypeNodes.null] });
559
- if (node.nullish && ["undefined", "questionTokenAndUndefined"].includes(optionalType)) type = createUnionDeclaration({ nodes: [type, keywordTypeNodes.undefined] });
560
- if (node.optional && ["undefined", "questionTokenAndUndefined"].includes(optionalType)) type = createUnionDeclaration({ nodes: [type, keywordTypeNodes.undefined] });
561
- }
562
- const useTypeGeneration = syntaxType === "type" || [syntaxKind.union].includes(type.kind) || !!keysToOmit?.length;
563
- typeNodes.push(createTypeDeclaration({
564
- name,
565
- isExportable: true,
566
- type: keysToOmit?.length ? createOmitDeclaration({
567
- keys: keysToOmit,
568
- type,
569
- nonNullable: true
570
- }) : type,
571
- syntax: useTypeGeneration ? "type" : "interface",
572
- comments: [
573
- node?.title ? `${jsStringEscape(node.title)}` : void 0,
574
- description ? `@description ${jsStringEscape(description)}` : void 0,
575
- node?.deprecated ? "@deprecated" : void 0,
576
- node && "min" in node && node.min !== void 0 ? `@minLength ${node.min}` : void 0,
577
- node && "max" in node && node.max !== void 0 ? `@maxLength ${node.max}` : void 0,
578
- node && "pattern" in node && node.pattern ? `@pattern ${node.pattern}` : void 0,
579
- node?.default ? `@default ${node.default}` : void 0,
580
- node?.example ? `@example ${node.example}` : void 0
581
- ]
582
- }));
583
- const enums = [...new Map(enumSchemaNodes.map((n) => [n.name, n])).values()].map((enumSchemaNode) => {
584
- const enumName = enumType === "asPascalConst" ? pascalCase(enumSchemaNode.name) : camelCase(enumSchemaNode.name);
585
- const typeName = ["asConst", "asPascalConst"].includes(enumType) ? `${enumSchemaNode.name}Key` : enumSchemaNode.name;
586
- const [nameNode, typeNode] = createEnumDeclaration({
587
- name: enumName,
588
- typeName,
589
- enums: enumSchemaNode.namedEnumValues?.map((v) => [trimQuotes(v.name.toString()), v.value]) ?? enumSchemaNode.enumValues?.filter((v) => v !== null && v !== void 0).map((v) => [trimQuotes(v.toString()), v]) ?? [],
590
- type: enumType,
591
- enumKeyCasing
592
- });
708
+ if (!typeNode) return;
709
+ const enums = [...new Map(enumSchemaNodes.map((n) => [n.name, n])).values()].map((node) => {
593
710
  return {
594
- nameNode,
595
- typeNode,
596
- name: enumName,
597
- typeName
711
+ node,
712
+ ...getEnumNames(node, enumType)
598
713
  };
599
714
  });
600
715
  const shouldExportEnums = enumType !== "inlineLiteral";
601
716
  const shouldExportType = enumType === "inlineLiteral" || enums.every((item) => item.typeName !== name);
602
- return /* @__PURE__ */ jsxs(Fragment, { children: [shouldExportEnums && enums.map(({ name: enumName, nameNode, typeName, typeNode }) => /* @__PURE__ */ jsxs(Fragment, { children: [nameNode && /* @__PURE__ */ jsx(File.Source, {
603
- name: enumName,
604
- isExportable: true,
605
- isIndexable: true,
606
- isTypeOnly: false,
607
- children: safePrint(nameNode)
608
- }), /* @__PURE__ */ jsx(File.Source, {
609
- name: typeName,
610
- isIndexable: true,
611
- isExportable: [
612
- "enum",
613
- "asConst",
614
- "asPascalConst",
615
- "constEnum",
616
- "literal",
617
- void 0
618
- ].includes(enumType),
619
- isTypeOnly: [
620
- "asConst",
621
- "asPascalConst",
622
- "literal",
623
- void 0
624
- ].includes(enumType),
625
- children: safePrint(typeNode)
626
- })] })), shouldExportType && /* @__PURE__ */ jsx(File.Source, {
717
+ return /* @__PURE__ */ jsxs(Fragment, { children: [shouldExportEnums && enums.map(({ node }) => /* @__PURE__ */ jsx(Enum, {
718
+ node,
719
+ enumType,
720
+ enumKeyCasing
721
+ })), shouldExportType && /* @__PURE__ */ jsx(File.Source, {
627
722
  name: typedName,
628
723
  isTypeOnly: true,
629
724
  isExportable: true,
630
725
  isIndexable: true,
631
- children: safePrint(...typeNodes)
726
+ children: safePrint(typeNode)
632
727
  })] });
633
728
  }
634
729
  //#endregion
730
+ //#region src/generators/v2/utils.ts
731
+ /**
732
+ * Builds an `ObjectSchemaNode` for a group of parameters (path/query/header).
733
+ * Each property is a `ref` schema pointing to the individually-resolved parameter type.
734
+ * The ref name includes the parameter location so generated type names follow
735
+ * the `<OperationId><Location><ParamName>` convention.
736
+ */
737
+ function buildParamsSchema({ params, operationId, resolveName }) {
738
+ return createSchema({
739
+ type: "object",
740
+ properties: params.map((param) => createProperty({
741
+ name: param.name,
742
+ schema: createSchema({
743
+ type: "ref",
744
+ name: resolveName({
745
+ name: `${operationId} ${pascalCase(param.in)} ${param.name}`,
746
+ type: "function"
747
+ }),
748
+ optional: !param.required
749
+ })
750
+ }))
751
+ });
752
+ }
753
+ /**
754
+ * Builds an `ObjectSchemaNode` representing the `<OperationId>RequestConfig` type:
755
+ * - `data` → request body ref (optional) or `never`
756
+ * - `pathParams` → inline object of path param refs, or `never`
757
+ * - `queryParams` → inline object of query param refs (optional), or `never`
758
+ * - `headerParams` → inline object of header param refs (optional), or `never`
759
+ * - `url` → Express-style template literal (plugin-ts extension, handled by printer)
760
+ */
761
+ function buildDataSchemaNode({ node, resolveName }) {
762
+ const pathParams = node.parameters.filter((p) => p.in === "path");
763
+ const queryParams = node.parameters.filter((p) => p.in === "query");
764
+ const headerParams = node.parameters.filter((p) => p.in === "header");
765
+ return createSchema({
766
+ type: "object",
767
+ properties: [
768
+ createProperty({
769
+ name: "data",
770
+ schema: node.requestBody ? createSchema({
771
+ type: "ref",
772
+ name: resolveName({
773
+ name: `${node.operationId} Data`,
774
+ type: "function"
775
+ }),
776
+ optional: true
777
+ }) : createSchema({
778
+ type: "never",
779
+ optional: true
780
+ })
781
+ }),
782
+ createProperty({
783
+ name: "pathParams",
784
+ schema: pathParams.length > 0 ? buildParamsSchema({
785
+ params: pathParams,
786
+ operationId: node.operationId,
787
+ resolveName
788
+ }) : createSchema({
789
+ type: "never",
790
+ optional: true
791
+ })
792
+ }),
793
+ createProperty({
794
+ name: "queryParams",
795
+ schema: queryParams.length > 0 ? createSchema({
796
+ ...buildParamsSchema({
797
+ params: queryParams,
798
+ operationId: node.operationId,
799
+ resolveName
800
+ }),
801
+ optional: true
802
+ }) : createSchema({
803
+ type: "never",
804
+ optional: true
805
+ })
806
+ }),
807
+ createProperty({
808
+ name: "headerParams",
809
+ schema: headerParams.length > 0 ? createSchema({
810
+ ...buildParamsSchema({
811
+ params: headerParams,
812
+ operationId: node.operationId,
813
+ resolveName
814
+ }),
815
+ optional: true
816
+ }) : createSchema({
817
+ type: "never",
818
+ optional: true
819
+ })
820
+ }),
821
+ createProperty({
822
+ name: "url",
823
+ schema: createSchema({
824
+ type: "url",
825
+ path: node.path
826
+ })
827
+ })
828
+ ]
829
+ });
830
+ }
831
+ /**
832
+ * Builds an `ObjectSchemaNode` representing `<OperationId>Responses` — keyed by HTTP status code.
833
+ * Numeric status codes produce unquoted numeric keys (e.g. `200:`).
834
+ */
835
+ function buildResponsesSchemaNode({ node, resolveName }) {
836
+ const responsesWithSchema = node.responses.filter((res) => res.schema);
837
+ if (responsesWithSchema.length === 0) return null;
838
+ return createSchema({
839
+ type: "object",
840
+ properties: responsesWithSchema.map((res) => createProperty({
841
+ name: String(res.statusCode),
842
+ schema: createSchema({
843
+ type: "ref",
844
+ name: resolveName({
845
+ name: `${node.operationId} Status ${res.statusCode}`,
846
+ type: "function"
847
+ })
848
+ })
849
+ }))
850
+ });
851
+ }
852
+ /**
853
+ * Builds a `UnionSchemaNode` representing `<OperationId>Response` — all response types in union format.
854
+ * Returns `null` when the operation has no responses with schemas.
855
+ */
856
+ function buildResponseUnionSchemaNode({ node, resolveName }) {
857
+ const responsesWithSchema = node.responses.filter((res) => res.schema);
858
+ if (responsesWithSchema.length === 0) return null;
859
+ return createSchema({
860
+ type: "union",
861
+ members: responsesWithSchema.map((res) => createSchema({
862
+ type: "ref",
863
+ name: resolveName({
864
+ name: `${node.operationId} Status ${res.statusCode}`,
865
+ type: "function"
866
+ })
867
+ }))
868
+ });
869
+ }
870
+ //#endregion
635
871
  //#region src/generators/v2/typeGenerator.tsx
636
872
  const typeGenerator = defineGenerator({
637
873
  name: "typescript",
638
874
  type: "react",
639
875
  Operation({ node, adapter, options }) {
640
- const { enumType, enumKeyCasing, optionalType, arrayType, syntaxType } = options;
641
- const { plugin, mode, getFile, resolveName } = useKubb();
876
+ const { enumType, enumKeyCasing, optionalType, arrayType, syntaxType, paramsCasing, group } = options;
877
+ const { mode, getFile, resolveName } = useKubb();
642
878
  const file = getFile({
643
879
  name: node.operationId,
644
- pluginName: plugin.name,
645
880
  extname: ".ts",
646
- mode
881
+ mode,
882
+ options: { group: group ? group.type === "tag" ? { tag: node.tags[0] } : { path: node.path } : void 0 }
647
883
  });
884
+ const params = applyParamsCasing(node.parameters, paramsCasing);
648
885
  function renderSchemaType({ node: schemaNode, name, typedName, description }) {
886
+ if (!schemaNode) return null;
649
887
  const imports = adapter.getImports(schemaNode, (schemaName) => ({
650
888
  name: resolveName({
651
889
  name: schemaName,
652
- pluginName: plugin.name,
653
890
  type: "type"
654
891
  }),
655
892
  path: getFile({
656
893
  name: schemaName,
657
- pluginName: plugin.name,
658
894
  extname: ".ts",
659
895
  mode
660
896
  }).path
@@ -680,60 +916,87 @@ const typeGenerator = defineGenerator({
680
916
  syntaxType
681
917
  })] });
682
918
  }
683
- const paramTypes = node.parameters.map((param) => {
684
- const name = resolveName({
685
- name: `${node.operationId} ${param.name}`,
686
- pluginName: plugin.name,
919
+ const paramTypes = params.map((param) => renderSchemaType({
920
+ node: param.schema,
921
+ name: resolveName({
922
+ name: `${node.operationId} ${pascalCase(param.in)} ${param.name}`,
687
923
  type: "function"
688
- });
689
- const typedName = resolveName({
690
- name: `${node.operationId} ${param.name}`,
691
- pluginName: plugin.name,
924
+ }),
925
+ typedName: resolveName({
926
+ name: `${node.operationId} ${pascalCase(param.in)} ${param.name}`,
692
927
  type: "type"
693
- });
694
- return renderSchemaType({
695
- node: param.schema,
696
- name,
697
- typedName
698
- });
928
+ })
929
+ }));
930
+ const responseTypes = node.responses.filter((res) => res.schema).map((res) => renderSchemaType({
931
+ node: res.schema,
932
+ name: resolveName({
933
+ name: `${node.operationId} Status ${res.statusCode}`,
934
+ type: "function"
935
+ }),
936
+ typedName: resolveName({
937
+ name: `${node.operationId} Status ${res.statusCode}`,
938
+ type: "type"
939
+ }),
940
+ description: res.description
941
+ }));
942
+ const requestType = node.requestBody ? renderSchemaType({
943
+ node: node.requestBody,
944
+ name: resolveName({
945
+ name: `${node.operationId} Data`,
946
+ type: "function"
947
+ }),
948
+ typedName: resolveName({
949
+ name: `${node.operationId} Data`,
950
+ type: "type"
951
+ }),
952
+ description: node.requestBody.description
953
+ }) : null;
954
+ const dataType = renderSchemaType({
955
+ node: buildDataSchemaNode({
956
+ node: {
957
+ ...node,
958
+ parameters: params
959
+ },
960
+ resolveName
961
+ }),
962
+ name: resolveName({
963
+ name: `${node.operationId} RequestConfig`,
964
+ type: "function"
965
+ }),
966
+ typedName: resolveName({
967
+ name: `${node.operationId} RequestConfig`,
968
+ type: "type"
969
+ })
699
970
  });
700
- const responseTypes = node.responses.filter((res) => res.schema).map((res) => {
701
- const schemaNode = res.schema;
702
- const responseName = `${node.operationId} ${res.statusCode}`;
703
- return renderSchemaType({
704
- node: schemaNode,
705
- name: resolveName({
706
- name: responseName,
707
- pluginName: plugin.name,
708
- type: "function"
709
- }),
710
- typedName: resolveName({
711
- name: responseName,
712
- pluginName: plugin.name,
713
- type: "type"
714
- }),
715
- description: res.description
716
- });
971
+ const responsesType = renderSchemaType({
972
+ node: buildResponsesSchemaNode({
973
+ node,
974
+ resolveName
975
+ }),
976
+ name: resolveName({
977
+ name: `${node.operationId} Responses`,
978
+ type: "function"
979
+ }),
980
+ typedName: resolveName({
981
+ name: `${node.operationId} Responses`,
982
+ type: "type"
983
+ })
717
984
  });
718
- const requestType = node.requestBody ? (() => {
719
- const requestName = `${node.operationId} MutationRequest`;
720
- const resolvedName = resolveName({
721
- name: requestName,
722
- pluginName: plugin.name,
985
+ const responseType = renderSchemaType({
986
+ node: buildResponseUnionSchemaNode({
987
+ node,
988
+ resolveName
989
+ }),
990
+ name: resolveName({
991
+ name: `${node.operationId} Response`,
723
992
  type: "function"
724
- });
725
- const typedName = resolveName({
726
- name: requestName,
727
- pluginName: plugin.name,
993
+ }),
994
+ typedName: resolveName({
995
+ name: `${node.operationId} Response`,
728
996
  type: "type"
729
- });
730
- return renderSchemaType({
731
- node: node.requestBody,
732
- name: resolvedName,
733
- typedName,
734
- description: node.requestBody.description
735
- });
736
- })() : null;
997
+ }),
998
+ description: "Union of all possible responses"
999
+ });
737
1000
  return /* @__PURE__ */ jsxs(File, {
738
1001
  baseName: file.baseName,
739
1002
  path: file.path,
@@ -741,23 +1004,24 @@ const typeGenerator = defineGenerator({
741
1004
  children: [
742
1005
  paramTypes,
743
1006
  responseTypes,
744
- requestType
1007
+ requestType,
1008
+ dataType,
1009
+ responsesType,
1010
+ responseType
745
1011
  ]
746
1012
  });
747
1013
  },
748
1014
  Schema({ node, adapter, options }) {
749
1015
  const { enumType, enumKeyCasing, syntaxType, optionalType, arrayType } = options;
750
- const { plugin, mode, resolveName, getFile } = useKubb();
1016
+ const { mode, resolveName, getFile } = useKubb();
751
1017
  if (!node.name) return;
752
1018
  const imports = adapter.getImports(node, (schemaName) => ({
753
1019
  name: resolveName({
754
1020
  name: schemaName,
755
- pluginName: plugin.name,
756
1021
  type: "type"
757
1022
  }),
758
1023
  path: getFile({
759
1024
  name: schemaName,
760
- pluginName: plugin.name,
761
1025
  extname: ".ts",
762
1026
  mode
763
1027
  }).path
@@ -765,20 +1029,17 @@ const typeGenerator = defineGenerator({
765
1029
  const isEnumSchema = node.type === "enum";
766
1030
  let typedName = resolveName({
767
1031
  name: node.name,
768
- pluginName: plugin.name,
769
1032
  type: "type"
770
1033
  });
771
- if (["asConst", "asPascalConst"].includes(enumType) && isEnumSchema) typedName = typedName += "Key";
1034
+ if (ENUM_TYPES_WITH_KEY_SUFFIX.has(enumType) && isEnumSchema) typedName += "Key";
772
1035
  const type = {
773
1036
  name: resolveName({
774
1037
  name: node.name,
775
- pluginName: plugin.name,
776
1038
  type: "function"
777
1039
  }),
778
1040
  typedName,
779
1041
  file: getFile({
780
1042
  name: node.name,
781
- pluginName: plugin.name,
782
1043
  extname: ".ts",
783
1044
  mode
784
1045
  })
@@ -816,7 +1077,7 @@ const pluginTs = definePlugin((options) => {
816
1077
  const { output = {
817
1078
  path: "types",
818
1079
  barrelType: "named"
819
- }, group, exclude = [], include, override = [], enumType = "asConst", enumKeyCasing = "none", enumSuffix = "enum", dateType = "string", integerType = "number", unknownType = "any", optionalType = "questionToken", arrayType = "array", emptySchemaType = unknownType, syntaxType = "type", transformers = {}, mapper = {}, paramsCasing, generators = [typeGenerator$1, typeGenerator].filter(Boolean), contentType, UNSTABLE_NAMING } = options;
1080
+ }, group, exclude = [], include, override = [], enumType = "asConst", enumKeyCasing = "none", enumSuffix = "enum", dateType = "string", integerType = "number", unknownType = "any", optionalType = "questionToken", arrayType = "array", emptySchemaType = unknownType, syntaxType = "type", transformers = {}, paramsCasing, generators = [typeGenerator$1, typeGenerator].filter(Boolean), contentType, UNSTABLE_NAMING } = options;
820
1081
  return {
821
1082
  name: pluginTsName,
822
1083
  options: {
@@ -834,7 +1095,6 @@ const pluginTs = definePlugin((options) => {
834
1095
  syntaxType,
835
1096
  group,
836
1097
  override,
837
- mapper,
838
1098
  paramsCasing,
839
1099
  usedEnumNames: {}
840
1100
  },
@@ -919,6 +1179,13 @@ const pluginTs = definePlugin((options) => {
919
1179
  await Promise.all(writeTasks);
920
1180
  }
921
1181
  }, { depth: "shallow" });
1182
+ const barrelFiles = await getBarrelFiles(this.fabric.files, {
1183
+ type: output.barrelType ?? "named",
1184
+ root,
1185
+ output,
1186
+ meta: { pluginName: this.plugin.name }
1187
+ });
1188
+ await this.upsertFile(...barrelFiles);
922
1189
  return;
923
1190
  }
924
1191
  const oas = await this.getOas();
@@ -962,4 +1229,4 @@ const pluginTs = definePlugin((options) => {
962
1229
  //#endregion
963
1230
  export { typeGenerator$1 as i, pluginTsName as n, typeGenerator as r, pluginTs as t };
964
1231
 
965
- //# sourceMappingURL=plugin-Bgm8TNUt.js.map
1232
+ //# sourceMappingURL=plugin-BcK4SBA0.js.map