@kubb/plugin-ts 5.0.0-alpha.11 → 5.0.0-alpha.12

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 (43) hide show
  1. package/dist/{components-CRu8IKY3.js → Type-CX1HRooG.js} +377 -365
  2. package/dist/Type-CX1HRooG.js.map +1 -0
  3. package/dist/Type-Cat0_htq.cjs +808 -0
  4. package/dist/Type-Cat0_htq.cjs.map +1 -0
  5. package/dist/components.cjs +3 -2
  6. package/dist/components.d.ts +40 -9
  7. package/dist/components.js +2 -2
  8. package/dist/generators-CLuCmfUz.js +532 -0
  9. package/dist/generators-CLuCmfUz.js.map +1 -0
  10. package/dist/generators-DWBU-MuW.cjs +536 -0
  11. package/dist/generators-DWBU-MuW.cjs.map +1 -0
  12. package/dist/generators.cjs +2 -3
  13. package/dist/generators.d.ts +3 -503
  14. package/dist/generators.js +2 -2
  15. package/dist/index.cjs +308 -4
  16. package/dist/index.cjs.map +1 -0
  17. package/dist/index.d.ts +26 -21
  18. package/dist/index.js +305 -2
  19. package/dist/index.js.map +1 -0
  20. package/dist/{types-mSXmB8WU.d.ts → types-BA1ZCQ5p.d.ts} +73 -57
  21. package/package.json +5 -5
  22. package/src/components/{v2/Enum.tsx → Enum.tsx} +27 -11
  23. package/src/components/Type.tsx +23 -141
  24. package/src/components/index.ts +1 -0
  25. package/src/generators/index.ts +0 -1
  26. package/src/generators/typeGenerator.tsx +189 -413
  27. package/src/generators/utils.ts +298 -0
  28. package/src/index.ts +1 -1
  29. package/src/plugin.ts +80 -126
  30. package/src/printer.ts +15 -4
  31. package/src/resolverTs.ts +109 -1
  32. package/src/types.ts +68 -52
  33. package/dist/components-CRu8IKY3.js.map +0 -1
  34. package/dist/components-DeNDKlzf.cjs +0 -982
  35. package/dist/components-DeNDKlzf.cjs.map +0 -1
  36. package/dist/plugin-CJ29AwE2.cjs +0 -1320
  37. package/dist/plugin-CJ29AwE2.cjs.map +0 -1
  38. package/dist/plugin-D60XNJSD.js +0 -1267
  39. package/dist/plugin-D60XNJSD.js.map +0 -1
  40. package/src/components/v2/Type.tsx +0 -59
  41. package/src/generators/v2/typeGenerator.tsx +0 -167
  42. package/src/generators/v2/utils.ts +0 -140
  43. package/src/parser.ts +0 -389
@@ -1,9 +1,10 @@
1
1
  import "./chunk--u3MIqq1.js";
2
- import { SchemaGenerator, createParser, isKeyword, schemaKeywords } from "@kubb/plugin-oas";
3
- import { safePrint } from "@kubb/fabric-core/parsers/typescript";
2
+ import { collect, isPlainStringType } from "@kubb/ast";
3
+ import { definePrinter } from "@kubb/core";
4
4
  import { File } from "@kubb/react-fabric";
5
- import ts from "typescript";
5
+ import { safePrint } from "@kubb/fabric-core/parsers/typescript";
6
6
  import { isNumber } from "remeda";
7
+ import ts from "typescript";
7
8
  import { Fragment, jsx, jsxs } from "@kubb/react-fabric/jsx-runtime";
8
9
  //#region ../../internals/utils/src/casing.ts
9
10
  /**
@@ -24,9 +25,12 @@ function toCamelOrPascal(text, pascal) {
24
25
  * Splits `text` on `.` and applies `transformPart` to each segment.
25
26
  * The last segment receives `isLast = true`, all earlier segments receive `false`.
26
27
  * Segments are joined with `/` to form a file path.
28
+ *
29
+ * Only splits on dots followed by a letter so that version numbers
30
+ * embedded in operationIds (e.g. `v2025.0`) are kept intact.
27
31
  */
28
32
  function applyToFileParts(text, transformPart) {
29
- const parts = text.split(".");
33
+ const parts = text.split(/\.(?=[a-zA-Z])/);
30
34
  return parts.map((part, i) => transformPart(part, i === parts.length - 1)).join("/");
31
35
  }
32
36
  /**
@@ -120,6 +124,53 @@ function jsStringEscape(input) {
120
124
  });
121
125
  }
122
126
  //#endregion
127
+ //#region ../../internals/utils/src/object.ts
128
+ /**
129
+ * Serializes a primitive value to a JSON string literal, stripping any surrounding quote characters first.
130
+ *
131
+ * @example
132
+ * stringify('hello') // '"hello"'
133
+ * stringify('"hello"') // '"hello"'
134
+ */
135
+ function stringify(value) {
136
+ if (value === void 0 || value === null) return "\"\"";
137
+ return JSON.stringify(trimQuotes(value.toString()));
138
+ }
139
+ //#endregion
140
+ //#region src/constants.ts
141
+ /**
142
+ * `optionalType` values that cause a property's type to include `| undefined`.
143
+ */
144
+ const OPTIONAL_ADDS_UNDEFINED = new Set(["undefined", "questionTokenAndUndefined"]);
145
+ /**
146
+ * `optionalType` values that render the property key with a `?` token.
147
+ */
148
+ const OPTIONAL_ADDS_QUESTION_TOKEN = new Set(["questionToken", "questionTokenAndUndefined"]);
149
+ /**
150
+ * `enumType` values that append a `Key` suffix to the generated enum type alias.
151
+ */
152
+ const ENUM_TYPES_WITH_KEY_SUFFIX = new Set(["asConst", "asPascalConst"]);
153
+ /**
154
+ * `enumType` values that require a runtime value declaration (object, enum, or literal).
155
+ */
156
+ const ENUM_TYPES_WITH_RUNTIME_VALUE = new Set([
157
+ "enum",
158
+ "asConst",
159
+ "asPascalConst",
160
+ "constEnum",
161
+ "literal",
162
+ void 0
163
+ ]);
164
+ /**
165
+ * `enumType` values whose type declaration is type-only (no runtime value emitted for the type alias).
166
+ */
167
+ const ENUM_TYPES_WITH_TYPE_ONLY = new Set([
168
+ "asConst",
169
+ "asPascalConst",
170
+ "literal",
171
+ void 0
172
+ ]);
173
+ //#endregion
123
174
  //#region src/factory.ts
124
175
  const { SyntaxKind, factory } = ts;
125
176
  const modifiers = {
@@ -133,11 +184,6 @@ const syntaxKind = {
133
184
  literalType: SyntaxKind.LiteralType,
134
185
  stringLiteral: SyntaxKind.StringLiteral
135
186
  };
136
- function getUnknownType(unknownType) {
137
- if (unknownType === "any") return keywordTypeNodes.any;
138
- if (unknownType === "void") return keywordTypeNodes.void;
139
- return keywordTypeNodes.unknown;
140
- }
141
187
  function isValidIdentifier(str) {
142
188
  if (!str.length || str.trim() !== str) return false;
143
189
  const node = ts.parseIsolatedEntityName(str, ts.ScriptTarget.Latest);
@@ -342,388 +388,354 @@ const createTupleTypeNode = factory.createTupleTypeNode;
342
388
  const createRestTypeNode = factory.createRestTypeNode;
343
389
  const createTrue = factory.createTrue;
344
390
  const createFalse = factory.createFalse;
345
- const createIndexedAccessTypeNode = factory.createIndexedAccessTypeNode;
346
- const createTypeOperatorNode = factory.createTypeOperatorNode;
391
+ factory.createIndexedAccessTypeNode;
392
+ factory.createTypeOperatorNode;
347
393
  const createPrefixUnaryExpression = factory.createPrefixUnaryExpression;
348
394
  //#endregion
349
- //#region src/parser.ts
350
- const typeKeywordMapper = {
351
- any: () => keywordTypeNodes.any,
352
- unknown: () => keywordTypeNodes.unknown,
353
- void: () => keywordTypeNodes.void,
354
- number: () => keywordTypeNodes.number,
355
- integer: () => keywordTypeNodes.number,
356
- bigint: () => keywordTypeNodes.bigint,
357
- object: (nodes) => {
358
- if (!nodes || !nodes.length) return keywordTypeNodes.object;
359
- return createTypeLiteralNode(nodes);
360
- },
361
- string: () => keywordTypeNodes.string,
362
- boolean: () => keywordTypeNodes.boolean,
363
- undefined: () => keywordTypeNodes.undefined,
364
- nullable: void 0,
365
- null: () => keywordTypeNodes.null,
366
- nullish: void 0,
367
- array: (nodes, arrayType) => {
368
- if (!nodes) return;
369
- return createArrayDeclaration({
370
- nodes,
371
- arrayType
372
- });
373
- },
374
- tuple: (nodes, rest, min, max) => {
375
- if (!nodes) return;
376
- if (max) {
377
- nodes = nodes.slice(0, max);
378
- if (nodes.length < max && rest) nodes = [...nodes, ...Array(max - nodes.length).fill(rest)];
379
- }
380
- if (min) nodes = nodes.map((node, index) => index >= min ? createOptionalTypeNode(node) : node);
381
- if (typeof max === "undefined" && rest) nodes.push(createRestTypeNode(createArrayTypeNode(rest)));
382
- return createTupleTypeNode(nodes);
383
- },
384
- enum: (name) => {
385
- if (!name) return;
386
- return createTypeReferenceNode(name, void 0);
387
- },
388
- union: (nodes) => {
389
- if (!nodes) return;
390
- return createUnionDeclaration({
391
- withParentheses: true,
392
- nodes
393
- });
394
- },
395
- const: (name, format) => {
396
- if (name === null || name === void 0 || name === "") return;
397
- if (format === "boolean") {
398
- if (name === true) return createLiteralTypeNode(createTrue());
399
- return createLiteralTypeNode(createFalse());
395
+ //#region src/printer.ts
396
+ /**
397
+ * Converts a primitive const value to a TypeScript literal type node.
398
+ * Handles negative numbers via a prefix unary expression.
399
+ */
400
+ function constToTypeNode(value, format) {
401
+ if (format === "boolean") return createLiteralTypeNode(value === true ? createTrue() : createFalse());
402
+ if (format === "number" && typeof value === "number") {
403
+ if (value < 0) return createLiteralTypeNode(createPrefixUnaryExpression(SyntaxKind.MinusToken, createNumericLiteral(Math.abs(value))));
404
+ return createLiteralTypeNode(createNumericLiteral(value));
405
+ }
406
+ return createLiteralTypeNode(createStringLiteral(String(value)));
407
+ }
408
+ /**
409
+ * Returns a `Date` reference type node when `representation` is `'date'`, otherwise falls back to `string`.
410
+ */
411
+ function dateOrStringNode(node) {
412
+ return node.representation === "date" ? createTypeReferenceNode(createIdentifier("Date")) : keywordTypeNodes.string;
413
+ }
414
+ /**
415
+ * Maps an array of `SchemaNode`s through the printer, filtering out `null` and `undefined` results.
416
+ */
417
+ function buildMemberNodes(members, print) {
418
+ return (members ?? []).map(print).filter(Boolean);
419
+ }
420
+ /**
421
+ * Builds a TypeScript tuple type node from an array schema's `items`,
422
+ * applying min/max slice and optional/rest element rules.
423
+ */
424
+ function buildTupleNode(node, print) {
425
+ let items = (node.items ?? []).map(print).filter(Boolean);
426
+ const restNode = node.rest ? print(node.rest) ?? void 0 : void 0;
427
+ const { min, max } = node;
428
+ if (max !== void 0) {
429
+ items = items.slice(0, max);
430
+ if (items.length < max && restNode) items = [...items, ...Array(max - items.length).fill(restNode)];
431
+ }
432
+ if (min !== void 0) items = items.map((item, i) => i >= min ? createOptionalTypeNode(item) : item);
433
+ if (max === void 0 && restNode) items.push(createRestTypeNode(createArrayTypeNode(restNode)));
434
+ return createTupleTypeNode(items);
435
+ }
436
+ /**
437
+ * Applies `nullable` and optional/nullish `| undefined` union modifiers to a property's resolved base type.
438
+ */
439
+ function buildPropertyType(schema, baseType, optionalType) {
440
+ const addsUndefined = OPTIONAL_ADDS_UNDEFINED.has(optionalType);
441
+ let type = baseType;
442
+ if (schema.nullable) type = createUnionDeclaration({ nodes: [type, keywordTypeNodes.null] });
443
+ if ((schema.nullish || schema.optional) && addsUndefined) type = createUnionDeclaration({ nodes: [type, keywordTypeNodes.undefined] });
444
+ return type;
445
+ }
446
+ /**
447
+ * Collects JSDoc annotation strings (description, deprecated, min/max, pattern, default, example, type) for a schema node.
448
+ */
449
+ function buildPropertyJSDocComments(schema) {
450
+ return [
451
+ "description" in schema && schema.description ? `@description ${jsStringEscape(schema.description)}` : void 0,
452
+ "deprecated" in schema && schema.deprecated ? "@deprecated" : void 0,
453
+ "min" in schema && schema.min !== void 0 ? `@minLength ${schema.min}` : void 0,
454
+ "max" in schema && schema.max !== void 0 ? `@maxLength ${schema.max}` : void 0,
455
+ "pattern" in schema && schema.pattern ? `@pattern ${schema.pattern}` : void 0,
456
+ "default" in schema && schema.default !== void 0 ? `@default ${"primitive" in schema && schema.primitive === "string" ? stringify(schema.default) : schema.default}` : void 0,
457
+ "example" in schema && schema.example !== void 0 ? `@example ${schema.example}` : void 0,
458
+ "primitive" in schema && schema.primitive ? [`@type ${schema.primitive || "unknown"}`, "optional" in schema && schema.optional ? " | undefined" : void 0].filter(Boolean).join("") : void 0
459
+ ];
460
+ }
461
+ /**
462
+ * Creates TypeScript index signatures for `additionalProperties` and `patternProperties` on an object schema node.
463
+ */
464
+ function buildIndexSignatures(node, propertyCount, print) {
465
+ const elements = [];
466
+ if (node.additionalProperties && node.additionalProperties !== true) {
467
+ const additionalType = print(node.additionalProperties) ?? keywordTypeNodes.unknown;
468
+ elements.push(createIndexSignature(propertyCount > 0 ? keywordTypeNodes.unknown : additionalType));
469
+ } else if (node.additionalProperties === true) elements.push(createIndexSignature(keywordTypeNodes.unknown));
470
+ if (node.patternProperties) {
471
+ const first = Object.values(node.patternProperties)[0];
472
+ if (first) {
473
+ let patternType = print(first) ?? keywordTypeNodes.unknown;
474
+ if (first.nullable) patternType = createUnionDeclaration({ nodes: [patternType, keywordTypeNodes.null] });
475
+ elements.push(createIndexSignature(patternType));
400
476
  }
401
- if (format === "number" && typeof name === "number") return createLiteralTypeNode(createNumericLiteral(name));
402
- return createLiteralTypeNode(createStringLiteral(name.toString()));
403
- },
404
- datetime: () => keywordTypeNodes.string,
405
- date: (type = "string") => type === "string" ? keywordTypeNodes.string : createTypeReferenceNode(createIdentifier("Date")),
406
- time: (type = "string") => type === "string" ? keywordTypeNodes.string : createTypeReferenceNode(createIdentifier("Date")),
407
- uuid: () => keywordTypeNodes.string,
408
- url: () => keywordTypeNodes.string,
409
- default: void 0,
410
- and: (nodes) => {
411
- if (!nodes) return;
412
- return createIntersectionDeclaration({
413
- withParentheses: true,
414
- nodes
415
- });
416
- },
417
- describe: void 0,
418
- min: void 0,
419
- max: void 0,
420
- optional: void 0,
421
- matches: () => keywordTypeNodes.string,
422
- email: () => keywordTypeNodes.string,
423
- firstName: void 0,
424
- lastName: void 0,
425
- password: void 0,
426
- phone: void 0,
427
- readOnly: void 0,
428
- writeOnly: void 0,
429
- ref: (propertyName) => {
430
- if (!propertyName) return;
431
- return createTypeReferenceNode(propertyName, void 0);
432
- },
433
- blob: () => createTypeReferenceNode("Blob", []),
434
- deprecated: void 0,
435
- example: void 0,
436
- schema: void 0,
437
- catchall: void 0,
438
- name: void 0,
439
- interface: void 0,
440
- exclusiveMaximum: void 0,
441
- exclusiveMinimum: void 0
442
- };
477
+ }
478
+ return elements;
479
+ }
443
480
  /**
444
- * Recursively parses a schema tree node into a corresponding TypeScript AST node.
481
+ * TypeScript type printer built with `definePrinter`.
445
482
  *
446
- * Maps OpenAPI schema keywords to TypeScript AST nodes using the `typeKeywordMapper`, handling complex types such as unions, intersections, arrays, tuples (with optional/rest elements and length constraints), enums, constants, references, and objects with property modifiers and documentation annotations.
483
+ * Converts a `SchemaNode` AST node into a TypeScript AST node:
484
+ * - **`printer.print(node)`** — when `options.typeName` is set, returns a full
485
+ * `type Name = …` or `interface Name { … }` declaration (`ts.Node`).
486
+ * Without `typeName`, returns the raw `ts.TypeNode` for the schema.
447
487
  *
448
- * @param current - The schema node to parse.
449
- * @param siblings - Sibling schema nodes, used for context in certain mappings.
450
- * @param name - The name of the schema or property being parsed.
451
- * @param options - Parsing options controlling output style, property handling.
452
- * @returns The generated TypeScript AST node, or `undefined` if the schema keyword is not mapped.
488
+ * Dispatches on `node.type` to the appropriate handler in `nodes`. Options are closed
489
+ * over per printer instance, so each call to `printerTs(options)` produces an independent printer.
490
+ *
491
+ * @example Raw type node (no `typeName`)
492
+ * ```ts
493
+ * const printer = printerTs({ optionalType: 'questionToken', arrayType: 'array', enumType: 'inlineLiteral' })
494
+ * const typeNode = printer.print(schemaNode) // ts.TypeNode
495
+ * ```
496
+ *
497
+ * @example Full declaration (with `typeName`)
498
+ * ```ts
499
+ * const printer = printerTs({ optionalType: 'questionToken', arrayType: 'array', enumType: 'inlineLiteral', typeName: 'MyType' })
500
+ * const declaration = printer.print(schemaNode) // ts.TypeAliasDeclaration | ts.InterfaceDeclaration
501
+ * ```
453
502
  */
454
- const parse = createParser({
455
- mapper: typeKeywordMapper,
456
- handlers: {
457
- union(tree, options) {
458
- const { current, schema, name } = tree;
459
- return typeKeywordMapper.union(current.args.map((it) => this.parse({
460
- schema,
461
- parent: current,
462
- name,
463
- current: it,
464
- siblings: []
465
- }, options)).filter(Boolean));
466
- },
467
- and(tree, options) {
468
- const { current, schema, name } = tree;
469
- return typeKeywordMapper.and(current.args.map((it) => this.parse({
470
- schema,
471
- parent: current,
472
- name,
473
- current: it,
474
- siblings: []
475
- }, options)).filter(Boolean));
476
- },
477
- array(tree, options) {
478
- const { current, schema, name } = tree;
479
- return typeKeywordMapper.array(current.args.items.map((it) => this.parse({
480
- schema,
481
- parent: current,
482
- name,
483
- current: it,
484
- siblings: []
485
- }, options)).filter(Boolean), options.arrayType);
486
- },
487
- enum(tree, options) {
488
- const { current } = tree;
489
- if (options.enumType === "inlineLiteral") {
490
- const enumValues = current.args.items.map((item) => item.value).filter((value) => value !== void 0 && value !== null).map((value) => {
491
- const format = typeof value === "number" ? "number" : typeof value === "boolean" ? "boolean" : "string";
492
- return typeKeywordMapper.const(value, format);
493
- }).filter(Boolean);
494
- return typeKeywordMapper.union(enumValues);
495
- }
496
- return typeKeywordMapper.enum(["asConst", "asPascalConst"].includes(options.enumType) ? `${current.args.typeName}Key` : current.args.typeName);
497
- },
498
- ref(tree, _options) {
499
- const { current } = tree;
500
- return typeKeywordMapper.ref(current.args.name);
501
- },
502
- blob() {
503
- return typeKeywordMapper.blob();
504
- },
505
- tuple(tree, options) {
506
- const { current, schema, name } = tree;
507
- return typeKeywordMapper.tuple(current.args.items.map((it) => this.parse({
508
- schema,
509
- parent: current,
510
- name,
511
- current: it,
512
- siblings: []
513
- }, options)).filter(Boolean), current.args.rest && (this.parse({
514
- schema,
515
- parent: current,
516
- name,
517
- current: current.args.rest,
518
- siblings: []
519
- }, options) ?? void 0), current.args.min, current.args.max);
520
- },
521
- const(tree, _options) {
522
- const { current } = tree;
523
- return typeKeywordMapper.const(current.args.name, current.args.format);
524
- },
525
- object(tree, options) {
526
- const { current, schema, name } = tree;
527
- const properties = Object.entries(current.args?.properties || {}).filter((item) => {
528
- const schemas = item[1];
529
- return schemas && typeof schemas.map === "function";
530
- }).map(([name, schemas]) => {
531
- const mappedName = schemas.find((schema) => schema.keyword === schemaKeywords.name)?.args || name;
532
- const isNullish = schemas.some((schema) => schema.keyword === schemaKeywords.nullish);
533
- const isNullable = schemas.some((schema) => schema.keyword === schemaKeywords.nullable);
534
- const isOptional = schemas.some((schema) => schema.keyword === schemaKeywords.optional);
535
- const isReadonly = schemas.some((schema) => schema.keyword === schemaKeywords.readOnly);
536
- const describeSchema = schemas.find((schema) => schema.keyword === schemaKeywords.describe);
537
- const deprecatedSchema = schemas.find((schema) => schema.keyword === schemaKeywords.deprecated);
538
- const defaultSchema = schemas.find((schema) => schema.keyword === schemaKeywords.default);
539
- const exampleSchema = schemas.find((schema) => schema.keyword === schemaKeywords.example);
540
- const schemaSchema = schemas.find((schema) => schema.keyword === schemaKeywords.schema);
541
- const minSchema = schemas.find((schema) => schema.keyword === schemaKeywords.min);
542
- const maxSchema = schemas.find((schema) => schema.keyword === schemaKeywords.max);
543
- const matchesSchema = schemas.find((schema) => schema.keyword === schemaKeywords.matches);
544
- let type = schemas.map((it) => this.parse({
545
- schema,
546
- parent: current,
547
- name,
548
- current: it,
549
- siblings: schemas
550
- }, options)).filter(Boolean)[0];
551
- if (isNullable) type = createUnionDeclaration({ nodes: [type, keywordTypeNodes.null] });
552
- if (isNullish && ["undefined", "questionTokenAndUndefined"].includes(options.optionalType)) type = createUnionDeclaration({ nodes: [type, keywordTypeNodes.undefined] });
553
- if (isOptional && ["undefined", "questionTokenAndUndefined"].includes(options.optionalType)) type = createUnionDeclaration({ nodes: [type, keywordTypeNodes.undefined] });
554
- return appendJSDocToNode({
555
- node: createPropertySignature({
556
- questionToken: isOptional || isNullish ? ["questionToken", "questionTokenAndUndefined"].includes(options.optionalType) : false,
557
- name: mappedName,
558
- type,
559
- readOnly: isReadonly
560
- }),
561
- comments: [
562
- describeSchema ? `@description ${jsStringEscape(describeSchema.args)}` : void 0,
563
- deprecatedSchema ? "@deprecated" : void 0,
564
- minSchema ? `@minLength ${minSchema.args}` : void 0,
565
- maxSchema ? `@maxLength ${maxSchema.args}` : void 0,
566
- matchesSchema ? `@pattern ${matchesSchema.args}` : void 0,
567
- defaultSchema ? `@default ${defaultSchema.args}` : void 0,
568
- exampleSchema ? `@example ${exampleSchema.args}` : void 0,
569
- schemaSchema?.args?.type || schemaSchema?.args?.format ? [`@type ${schemaSchema?.args?.type || "unknown"}${!isOptional ? "" : " | undefined"}`, schemaSchema?.args?.format].filter(Boolean).join(", ") : void 0
570
- ].filter(Boolean)
503
+ const printerTs = definePrinter((options) => {
504
+ const addsUndefined = OPTIONAL_ADDS_UNDEFINED.has(options.optionalType);
505
+ return {
506
+ name: "typescript",
507
+ options,
508
+ nodes: {
509
+ any: () => keywordTypeNodes.any,
510
+ unknown: () => keywordTypeNodes.unknown,
511
+ void: () => keywordTypeNodes.void,
512
+ never: () => keywordTypeNodes.never,
513
+ boolean: () => keywordTypeNodes.boolean,
514
+ null: () => keywordTypeNodes.null,
515
+ blob: () => createTypeReferenceNode("Blob", []),
516
+ string: () => keywordTypeNodes.string,
517
+ uuid: () => keywordTypeNodes.string,
518
+ email: () => keywordTypeNodes.string,
519
+ url: (node) => {
520
+ if (node.path) return createUrlTemplateType(node.path);
521
+ return keywordTypeNodes.string;
522
+ },
523
+ datetime: () => keywordTypeNodes.string,
524
+ number: () => keywordTypeNodes.number,
525
+ integer: () => keywordTypeNodes.number,
526
+ bigint: () => keywordTypeNodes.bigint,
527
+ date: dateOrStringNode,
528
+ time: dateOrStringNode,
529
+ ref(node) {
530
+ if (!node.name) return;
531
+ const refName = node.ref ? node.ref.split("/").at(-1) ?? node.name : node.name;
532
+ return createTypeReferenceNode(node.ref ? this.options.resolver.default(refName, "type") : refName, void 0);
533
+ },
534
+ enum(node) {
535
+ const values = node.namedEnumValues?.map((v) => v.value) ?? node.enumValues ?? [];
536
+ if (this.options.enumType === "inlineLiteral" || !node.name) return createUnionDeclaration({
537
+ withParentheses: true,
538
+ nodes: values.filter((v) => v !== null).map((value) => constToTypeNode(value, typeof value)).filter(Boolean)
539
+ }) ?? void 0;
540
+ const resolvedName = this.options.resolver.default(node.name, "type");
541
+ return createTypeReferenceNode(ENUM_TYPES_WITH_KEY_SUFFIX.has(this.options.enumType) ? `${resolvedName}Key` : resolvedName, void 0);
542
+ },
543
+ union(node) {
544
+ const members = node.members ?? [];
545
+ const hasStringLiteral = members.some((m) => m.type === "enum" && (m.enumType === "string" || m.primitive === "string"));
546
+ const hasPlainString = members.some((m) => isPlainStringType(m));
547
+ if (hasStringLiteral && hasPlainString) return createUnionDeclaration({
548
+ withParentheses: true,
549
+ nodes: members.map((m) => {
550
+ if (isPlainStringType(m)) return createIntersectionDeclaration({
551
+ nodes: [keywordTypeNodes.string, createTypeLiteralNode([])],
552
+ withParentheses: true
553
+ });
554
+ return this.print(m);
555
+ }).filter(Boolean)
556
+ }) ?? void 0;
557
+ return createUnionDeclaration({
558
+ withParentheses: true,
559
+ nodes: buildMemberNodes(members, this.print)
560
+ }) ?? void 0;
561
+ },
562
+ intersection(node) {
563
+ return createIntersectionDeclaration({
564
+ withParentheses: true,
565
+ nodes: buildMemberNodes(node.members, this.print)
566
+ }) ?? void 0;
567
+ },
568
+ array(node) {
569
+ return createArrayDeclaration({
570
+ nodes: (node.items ?? []).map((item) => this.print(item)).filter(Boolean),
571
+ arrayType: this.options.arrayType
572
+ }) ?? void 0;
573
+ },
574
+ tuple(node) {
575
+ return buildTupleNode(node, this.print);
576
+ },
577
+ object(node) {
578
+ const { print, options } = this;
579
+ const addsQuestionToken = OPTIONAL_ADDS_QUESTION_TOKEN.has(options.optionalType);
580
+ const propertyNodes = node.properties.map((prop) => {
581
+ const baseType = print(prop.schema) ?? keywordTypeNodes.unknown;
582
+ const type = buildPropertyType(prop.schema, baseType, options.optionalType);
583
+ return appendJSDocToNode({
584
+ node: createPropertySignature({
585
+ questionToken: prop.schema.optional || prop.schema.nullish ? addsQuestionToken : false,
586
+ name: prop.name,
587
+ type,
588
+ readOnly: prop.schema.readOnly
589
+ }),
590
+ comments: buildPropertyJSDocComments(prop.schema)
591
+ });
571
592
  });
572
- });
573
- let additionalProperties;
574
- if (current.args?.additionalProperties?.length) {
575
- let additionalPropertiesType = current.args.additionalProperties.map((it) => this.parse({
576
- schema,
577
- parent: current,
578
- name,
579
- current: it,
580
- siblings: []
581
- }, options)).filter(Boolean).at(0);
582
- if (current.args?.additionalProperties.some((schema) => isKeyword(schema, schemaKeywords.nullable))) additionalPropertiesType = createUnionDeclaration({ nodes: [additionalPropertiesType, keywordTypeNodes.null] });
583
- additionalProperties = createIndexSignature(properties.length > 0 ? keywordTypeNodes.unknown : additionalPropertiesType);
593
+ const allElements = [...propertyNodes, ...buildIndexSignatures(node, propertyNodes.length, print)];
594
+ if (!allElements.length) return keywordTypeNodes.object;
595
+ return createTypeLiteralNode(allElements);
584
596
  }
585
- let patternProperties;
586
- if (current.args?.patternProperties) {
587
- const allPatternSchemas = Object.values(current.args.patternProperties).flat();
588
- if (allPatternSchemas.length > 0) {
589
- patternProperties = allPatternSchemas.map((it) => this.parse({
590
- schema,
591
- parent: current,
592
- name,
593
- current: it,
594
- siblings: []
595
- }, options)).filter(Boolean).at(0);
596
- if (allPatternSchemas.some((schema) => isKeyword(schema, schemaKeywords.nullable))) patternProperties = createUnionDeclaration({ nodes: [patternProperties, keywordTypeNodes.null] });
597
- patternProperties = createIndexSignature(patternProperties);
598
- }
599
- }
600
- return typeKeywordMapper.object([
601
- ...properties,
602
- additionalProperties,
603
- patternProperties
604
- ].filter(Boolean));
605
- },
606
- datetime() {
607
- return typeKeywordMapper.datetime();
608
- },
609
- date(tree) {
610
- const { current } = tree;
611
- return typeKeywordMapper.date(current.args.type);
612
597
  },
613
- time(tree) {
614
- const { current } = tree;
615
- return typeKeywordMapper.time(current.args.type);
598
+ print(node) {
599
+ let type = this.print(node);
600
+ if (!type) return;
601
+ if (node.nullable) type = createUnionDeclaration({ nodes: [type, keywordTypeNodes.null] });
602
+ if ((node.nullish || node.optional) && addsUndefined) type = createUnionDeclaration({ nodes: [type, keywordTypeNodes.undefined] });
603
+ const { typeName, syntaxType = "type", description, keysToOmit } = this.options;
604
+ if (!typeName) return type;
605
+ const useTypeGeneration = syntaxType === "type" || type.kind === syntaxKind.union || !!keysToOmit?.length;
606
+ return createTypeDeclaration({
607
+ name: typeName,
608
+ isExportable: true,
609
+ type: keysToOmit?.length ? createOmitDeclaration({
610
+ keys: keysToOmit,
611
+ type,
612
+ nonNullable: true
613
+ }) : type,
614
+ syntax: useTypeGeneration ? "type" : "interface",
615
+ comments: [
616
+ node?.title ? jsStringEscape(node.title) : void 0,
617
+ description ? `@description ${jsStringEscape(description)}` : void 0,
618
+ node?.deprecated ? "@deprecated" : void 0,
619
+ node && "min" in node && node.min !== void 0 ? `@minLength ${node.min}` : void 0,
620
+ node && "max" in node && node.max !== void 0 ? `@maxLength ${node.max}` : void 0,
621
+ node && "pattern" in node && node.pattern ? `@pattern ${node.pattern}` : void 0,
622
+ node?.default ? `@default ${node.default}` : void 0,
623
+ node?.example ? `@example ${node.example}` : void 0
624
+ ]
625
+ });
616
626
  }
617
- }
627
+ };
618
628
  });
619
629
  //#endregion
630
+ //#region src/components/Enum.tsx
631
+ /**
632
+ * Resolves the runtime identifier name and the TypeScript type name for an enum schema node.
633
+ *
634
+ * The raw `node.name` may be a YAML key such as `"enumNames.Type"` which is not a
635
+ * valid TypeScript identifier. The resolver normalizes it; for inline enum
636
+ * properties the adapter already emits a PascalCase+suffix name so resolution is typically a no-op.
637
+ */
638
+ function getEnumNames({ node, enumType, resolver }) {
639
+ const resolved = resolver.default(node.name, "type");
640
+ return {
641
+ enumName: enumType === "asPascalConst" ? resolved : camelCase(node.name),
642
+ typeName: ENUM_TYPES_WITH_KEY_SUFFIX.has(enumType) ? `${resolved}Key` : resolved,
643
+ refName: resolved
644
+ };
645
+ }
646
+ /**
647
+ * Renders the enum declaration(s) for a single named `EnumSchemaNode`.
648
+ *
649
+ * Depending on `enumType` this may emit:
650
+ * - A runtime object (`asConst` / `asPascalConst`) plus a `typeof` type alias
651
+ * - A `const enum` or plain `enum` declaration (`constEnum` / `enum`)
652
+ * - A union literal type alias (`literal`)
653
+ *
654
+ * The emitted `File.Source` nodes carry the resolved names so that the barrel
655
+ * index picks up the correct export identifiers.
656
+ */
657
+ function Enum({ node, enumType, enumKeyCasing, resolver }) {
658
+ const { enumName, typeName, refName } = getEnumNames({
659
+ node,
660
+ enumType,
661
+ resolver
662
+ });
663
+ const [nameNode, typeNode] = createEnumDeclaration({
664
+ name: enumName,
665
+ typeName,
666
+ 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]) ?? [],
667
+ type: enumType,
668
+ enumKeyCasing
669
+ });
670
+ const needsRefAlias = ENUM_TYPES_WITH_KEY_SUFFIX.has(enumType) && refName !== typeName;
671
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
672
+ nameNode && /* @__PURE__ */ jsx(File.Source, {
673
+ name: enumName,
674
+ isExportable: true,
675
+ isIndexable: true,
676
+ isTypeOnly: false,
677
+ children: safePrint(nameNode)
678
+ }),
679
+ /* @__PURE__ */ jsx(File.Source, {
680
+ name: typeName,
681
+ isIndexable: true,
682
+ isExportable: ENUM_TYPES_WITH_RUNTIME_VALUE.has(enumType),
683
+ isTypeOnly: ENUM_TYPES_WITH_TYPE_ONLY.has(enumType),
684
+ children: safePrint(typeNode)
685
+ }),
686
+ needsRefAlias && /* @__PURE__ */ jsx(File.Source, {
687
+ name: refName,
688
+ isExportable: true,
689
+ isIndexable: true,
690
+ isTypeOnly: true,
691
+ children: `export type ${refName} = ${typeName}`
692
+ })
693
+ ] });
694
+ }
695
+ //#endregion
620
696
  //#region src/components/Type.tsx
621
- function Type({ name, typedName, tree, keysToOmit, schema, optionalType, arrayType, syntaxType, enumType, enumKeyCasing, description }) {
622
- const typeNodes = [];
623
- if (!tree.length) return "";
624
- const schemaFromTree = tree.find((item) => item.keyword === schemaKeywords.schema);
625
- const enumSchemas = SchemaGenerator.deepSearch(tree, schemaKeywords.enum);
626
- let type = tree.map((current, _index, siblings) => parse({
627
- name,
628
- schema,
629
- parent: void 0,
630
- current,
631
- siblings
632
- }, {
697
+ function Type({ name, typedName, node, keysToOmit, optionalType, arrayType, syntaxType, enumType, enumKeyCasing, description, resolver }) {
698
+ const resolvedDescription = description || node?.description;
699
+ const enumSchemaNodes = collect(node, { schema(n) {
700
+ if (n.type === "enum" && n.name) return n;
701
+ } });
702
+ const typeNode = printerTs({
633
703
  optionalType,
634
704
  arrayType,
635
- enumType
636
- })).filter(Boolean).at(0) || typeKeywordMapper.undefined();
637
- if (["asConst", "asPascalConst"].includes(enumType) && enumSchemas.length > 0) {
638
- const isDirectEnum = schema.type === "array" && schema.items !== void 0;
639
- const isEnumOnly = "enum" in schema && schema.enum;
640
- if (isDirectEnum || isEnumOnly) {
641
- type = createTypeReferenceNode(`${enumSchemas[0].args.typeName}Key`);
642
- if (schema.type === "array") if (arrayType === "generic") type = createTypeReferenceNode(createIdentifier("Array"), [type]);
643
- else type = createArrayTypeNode(type);
644
- }
645
- }
646
- if (schemaFromTree && isKeyword(schemaFromTree, schemaKeywords.schema)) {
647
- const isNullish = tree.some((item) => item.keyword === schemaKeywords.nullish);
648
- const isNullable = tree.some((item) => item.keyword === schemaKeywords.nullable);
649
- const isOptional = tree.some((item) => item.keyword === schemaKeywords.optional);
650
- if (isNullable) type = createUnionDeclaration({ nodes: [type, keywordTypeNodes.null] });
651
- if (isNullish && ["undefined", "questionTokenAndUndefined"].includes(optionalType)) type = createUnionDeclaration({ nodes: [type, keywordTypeNodes.undefined] });
652
- if (isOptional && ["undefined", "questionTokenAndUndefined"].includes(optionalType)) type = createUnionDeclaration({ nodes: [type, keywordTypeNodes.undefined] });
653
- }
654
- const useTypeGeneration = syntaxType === "type" || [syntaxKind.union].includes(type.kind) || !!keysToOmit?.length;
655
- typeNodes.push(createTypeDeclaration({
656
- name,
657
- isExportable: true,
658
- type: keysToOmit?.length ? createOmitDeclaration({
659
- keys: keysToOmit,
660
- type,
661
- nonNullable: true
662
- }) : type,
663
- syntax: useTypeGeneration ? "type" : "interface",
664
- comments: [
665
- schema.title ? `${jsStringEscape(schema.title)}` : void 0,
666
- description ? `@description ${jsStringEscape(description)}` : void 0,
667
- schema.deprecated ? "@deprecated" : void 0,
668
- schema.minLength ? `@minLength ${schema.minLength}` : void 0,
669
- schema.maxLength ? `@maxLength ${schema.maxLength}` : void 0,
670
- schema.pattern ? `@pattern ${schema.pattern}` : void 0,
671
- schema.default ? `@default ${schema.default}` : void 0,
672
- schema.example ? `@example ${schema.example}` : void 0
673
- ]
674
- }));
675
- const enums = [...new Set(enumSchemas)].map((enumSchema) => {
676
- const name = enumType === "asPascalConst" ? pascalCase(enumSchema.args.name) : camelCase(enumSchema.args.name);
677
- const typeName = ["asConst", "asPascalConst"].includes(enumType) ? `${enumSchema.args.typeName}Key` : enumSchema.args.typeName;
678
- const [nameNode, typeNode] = createEnumDeclaration({
679
- name,
680
- typeName,
681
- enums: enumSchema.args.items.map((item) => item.value === void 0 ? void 0 : [trimQuotes(item.name?.toString()), item.value]).filter(Boolean),
682
- type: enumType,
683
- enumKeyCasing
684
- });
705
+ enumType,
706
+ typeName: name,
707
+ syntaxType,
708
+ description: resolvedDescription,
709
+ keysToOmit,
710
+ resolver
711
+ }).print(node);
712
+ if (!typeNode) return;
713
+ const enums = [...new Map(enumSchemaNodes.map((n) => [n.name, n])).values()].map((node) => {
685
714
  return {
686
- nameNode,
687
- typeNode,
688
- name,
689
- typeName
715
+ node,
716
+ ...getEnumNames({
717
+ node,
718
+ enumType,
719
+ resolver
720
+ })
690
721
  };
691
722
  });
692
723
  const shouldExportEnums = enumType !== "inlineLiteral";
693
724
  const shouldExportType = enumType === "inlineLiteral" || enums.every((item) => item.typeName !== name);
694
- return /* @__PURE__ */ jsxs(Fragment, { children: [shouldExportEnums && enums.map(({ name, nameNode, typeName, typeNode }) => /* @__PURE__ */ jsxs(Fragment, { children: [nameNode && /* @__PURE__ */ jsx(File.Source, {
695
- name,
696
- isExportable: true,
697
- isIndexable: true,
698
- isTypeOnly: false,
699
- children: safePrint(nameNode)
700
- }), /* @__PURE__ */ jsx(File.Source, {
701
- name: typeName,
702
- isIndexable: true,
703
- isExportable: [
704
- "enum",
705
- "asConst",
706
- "asPascalConst",
707
- "constEnum",
708
- "literal",
709
- void 0
710
- ].includes(enumType),
711
- isTypeOnly: [
712
- "asConst",
713
- "asPascalConst",
714
- "literal",
715
- void 0
716
- ].includes(enumType),
717
- children: safePrint(typeNode)
718
- })] })), shouldExportType && /* @__PURE__ */ jsx(File.Source, {
725
+ return /* @__PURE__ */ jsxs(Fragment, { children: [shouldExportEnums && enums.map(({ node }) => /* @__PURE__ */ jsx(Enum, {
726
+ node,
727
+ enumType,
728
+ enumKeyCasing,
729
+ resolver
730
+ })), shouldExportType && /* @__PURE__ */ jsx(File.Source, {
719
731
  name: typedName,
720
732
  isTypeOnly: true,
721
733
  isExportable: true,
722
734
  isIndexable: true,
723
- children: safePrint(...typeNodes)
735
+ children: safePrint(typeNode)
724
736
  })] });
725
737
  }
726
738
  //#endregion
727
- export { keywordTypeNodes as A, createTypeDeclaration as C, createUnionDeclaration as D, createTypeReferenceNode as E, camelCase as F, pascalCase as I, syntaxKind as M, jsStringEscape as N, createUrlTemplateType as O, trimQuotes as P, createTypeAliasDeclaration as S, createTypeOperatorNode as T, createPropertySignature as _, createArrayTypeNode as a, createTrue as b, createIdentifier as c, createIntersectionDeclaration as d, createLiteralTypeNode as f, createPrefixUnaryExpression as g, createOptionalTypeNode as h, createArrayDeclaration as i, modifiers as j, getUnknownType as k, createIndexSignature as l, createOmitDeclaration as m, SyntaxKind as n, createEnumDeclaration as o, createNumericLiteral as p, appendJSDocToNode as r, createFalse as s, Type as t, createIndexedAccessTypeNode as u, createRestTypeNode as v, createTypeLiteralNode as w, createTupleTypeNode as x, createStringLiteral as y };
739
+ export { pascalCase as a, camelCase as i, Enum as n, ENUM_TYPES_WITH_KEY_SUFFIX as r, Type as t };
728
740
 
729
- //# sourceMappingURL=components-CRu8IKY3.js.map
741
+ //# sourceMappingURL=Type-CX1HRooG.js.map