@kubb/plugin-ts 5.0.0-beta.75 → 5.0.0-beta.77

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
@@ -589,7 +589,7 @@ function applyEnumKeyCasing(key, casing = "none") {
589
589
  * type: 'enum',
590
590
  * name: 'petType',
591
591
  * typeName: 'PetType',
592
- * enums: [['cat', 'cat'], ['dog', 'dog']],
592
+ * enums: [['cat', 'cat', 'A cat'], ['dog', 'dog']],
593
593
  * })
594
594
  * ```
595
595
  */
@@ -602,30 +602,39 @@ function createEnumDeclaration({ type = "enum", name, typeName, enums, enumKeyCa
602
602
  if (typeof value === "boolean") return factory.createLiteralTypeNode(value ? factory.createTrue() : factory.createFalse());
603
603
  if (value !== null && value !== void 0) return factory.createLiteralTypeNode(factory.createStringLiteral(value.toString()));
604
604
  }).filter((node) => node !== void 0)))];
605
- if (type === "enum" || type === "constEnum") return [void 0, factory.createEnumDeclaration([factory.createToken(typescript.default.SyntaxKind.ExportKeyword), type === "constEnum" ? factory.createToken(typescript.default.SyntaxKind.ConstKeyword) : void 0].filter((modifier) => modifier !== void 0), factory.createIdentifier(typeName), enums.map(([key, value]) => {
605
+ if (type === "enum" || type === "constEnum") return [void 0, factory.createEnumDeclaration([factory.createToken(typescript.default.SyntaxKind.ExportKeyword), type === "constEnum" ? factory.createToken(typescript.default.SyntaxKind.ConstKeyword) : void 0].filter((modifier) => modifier !== void 0), factory.createIdentifier(typeName), enums.map(([key, value, description]) => {
606
606
  let initializer = factory.createStringLiteral(value?.toString());
607
607
  if (Number.parseInt(value.toString(), 10) === value && isNumber(Number.parseInt(value.toString(), 10))) if (value < 0) initializer = factory.createPrefixUnaryExpression(typescript.default.SyntaxKind.MinusToken, factory.createNumericLiteral(Math.abs(value)));
608
608
  else initializer = factory.createNumericLiteral(value);
609
609
  if (typeof value === "boolean") initializer = value ? factory.createTrue() : factory.createFalse();
610
610
  if (isNumber(Number.parseInt(key.toString(), 10))) {
611
611
  const casingKey = applyEnumKeyCasing(`${typeName}_${key}`, enumKeyCasing);
612
- return factory.createEnumMember(propertyName(casingKey), initializer);
612
+ return appendJSDocToNode({
613
+ node: factory.createEnumMember(propertyName(casingKey), initializer),
614
+ comments: [description]
615
+ });
613
616
  }
614
617
  if (key !== null && key !== void 0) {
615
618
  const casingKey = applyEnumKeyCasing(key.toString(), enumKeyCasing);
616
- return factory.createEnumMember(propertyName(casingKey), initializer);
619
+ return appendJSDocToNode({
620
+ node: factory.createEnumMember(propertyName(casingKey), initializer),
621
+ comments: [description]
622
+ });
617
623
  }
618
624
  }).filter((member) => member !== void 0))];
619
625
  const identifierName = name;
620
626
  if (enums.length === 0) return [void 0, factory.createTypeAliasDeclaration([factory.createToken(typescript.default.SyntaxKind.ExportKeyword)], factory.createIdentifier(typeName), void 0, factory.createKeywordTypeNode(typescript.default.SyntaxKind.NeverKeyword))];
621
- return [factory.createVariableStatement([factory.createToken(typescript.default.SyntaxKind.ExportKeyword)], factory.createVariableDeclarationList([factory.createVariableDeclaration(factory.createIdentifier(identifierName), void 0, void 0, factory.createAsExpression(factory.createObjectLiteralExpression(enums.map(([key, value]) => {
627
+ return [factory.createVariableStatement([factory.createToken(typescript.default.SyntaxKind.ExportKeyword)], factory.createVariableDeclarationList([factory.createVariableDeclaration(factory.createIdentifier(identifierName), void 0, void 0, factory.createAsExpression(factory.createObjectLiteralExpression(enums.map(([key, value, description]) => {
622
628
  let initializer = factory.createStringLiteral(value?.toString());
623
629
  if (isNumber(value)) if (value < 0) initializer = factory.createPrefixUnaryExpression(typescript.default.SyntaxKind.MinusToken, factory.createNumericLiteral(Math.abs(value)));
624
630
  else initializer = factory.createNumericLiteral(value);
625
631
  if (typeof value === "boolean") initializer = value ? factory.createTrue() : factory.createFalse();
626
632
  if (key !== null && key !== void 0) {
627
633
  const casingKey = applyEnumKeyCasing(key.toString(), enumKeyCasing);
628
- return factory.createPropertyAssignment(propertyName(casingKey), initializer);
634
+ return appendJSDocToNode({
635
+ node: factory.createPropertyAssignment(propertyName(casingKey), initializer),
636
+ comments: [description]
637
+ });
629
638
  }
630
639
  }).filter((property) => property !== void 0), true), factory.createTypeReferenceNode(factory.createIdentifier("const"), void 0)))], typescript.default.NodeFlags.Const)), factory.createTypeAliasDeclaration([factory.createToken(typescript.default.SyntaxKind.ExportKeyword)], factory.createIdentifier(typeName), void 0, factory.createIndexedAccessTypeNode(factory.createParenthesizedType(factory.createTypeQueryNode(factory.createIdentifier(identifierName), void 0)), factory.createTypeOperatorNode(typescript.default.SyntaxKind.KeyOfKeyword, factory.createTypeQueryNode(factory.createIdentifier(identifierName), void 0))))];
631
640
  }
@@ -792,24 +801,30 @@ function buildPropertyType(schema, baseType, optionalType, optional) {
792
801
  if ((optional || meta.nullish || meta.optional) && addsUndefined) type = createUnionDeclaration({ nodes: [type, keywordTypeNodes.undefined] });
793
802
  return type;
794
803
  }
804
+ const indexSignaturePrinter = typescript.default.createPrinter();
805
+ const indexSignatureSource = typescript.default.createSourceFile("", "", typescript.default.ScriptTarget.Latest);
795
806
  /**
796
- * Creates TypeScript index signatures for `additionalProperties` and `patternProperties` on an object schema node.
807
+ * Creates a TypeScript index signature for `additionalProperties` and `patternProperties` on an
808
+ * object schema node. TypeScript allows only one string index signature and its value must be
809
+ * assignable from every named property, so both keywords collapse into a single signature: the
810
+ * union of all value types (deduplicated), or `unknown` when the object also has fixed properties.
811
+ * The key regex of `patternProperties` cannot be expressed by an index signature and is dropped.
797
812
  */
798
813
  function buildIndexSignatures(node, propertyCount, print) {
799
- const elements = [];
800
- if (node.additionalProperties && node.additionalProperties !== true) {
801
- const additionalType = print(node.additionalProperties) ?? keywordTypeNodes.unknown;
802
- elements.push(createIndexSignature(propertyCount > 0 ? keywordTypeNodes.unknown : additionalType));
803
- } else if (node.additionalProperties === true) elements.push(createIndexSignature(keywordTypeNodes.unknown));
804
- if (node.patternProperties) {
805
- const first = Object.values(node.patternProperties)[0];
806
- if (first) {
807
- let patternType = print(first) ?? keywordTypeNodes.unknown;
808
- if (first.nullable) patternType = createUnionDeclaration({ nodes: [patternType, keywordTypeNodes.null] });
809
- elements.push(createIndexSignature(patternType));
810
- }
814
+ const valueTypes = [];
815
+ if (node.additionalProperties && node.additionalProperties !== true) valueTypes.push(print(node.additionalProperties) ?? keywordTypeNodes.unknown);
816
+ else if (node.additionalProperties === true) valueTypes.push(keywordTypeNodes.unknown);
817
+ for (const schema of Object.values(node.patternProperties ?? {})) {
818
+ const patternType = print(schema) ?? keywordTypeNodes.unknown;
819
+ valueTypes.push(schema.nullable ? createUnionDeclaration({ nodes: [patternType, keywordTypeNodes.null] }) : patternType);
811
820
  }
812
- return elements;
821
+ if (valueTypes.length === 0) return [];
822
+ const seen = /* @__PURE__ */ new Set();
823
+ const distinct = valueTypes.filter((type) => {
824
+ const key = indexSignaturePrinter.printNode(typescript.default.EmitHint.Unspecified, type, indexSignatureSource);
825
+ return seen.has(key) ? false : (seen.add(key), true);
826
+ });
827
+ return [createIndexSignature(propertyCount > 0 ? keywordTypeNodes.unknown : createUnionDeclaration({ nodes: distinct }))];
813
828
  }
814
829
  //#endregion
815
830
  //#region src/components/Enum.tsx
@@ -850,7 +865,11 @@ function Enum({ node, enum: enumOptions, resolver }) {
850
865
  const [nameNode, typeNode] = createEnumDeclaration({
851
866
  name: enumName,
852
867
  typeName,
853
- enums: node.namedEnumValues?.map((v) => [(0, _kubb_ast_utils.trimQuotes)(v.name.toString()), v.value]) ?? node.enumValues?.filter((v) => v !== null && v !== void 0).map((v) => [(0, _kubb_ast_utils.trimQuotes)(v.toString()), v]) ?? [],
868
+ enums: node.namedEnumValues?.map((v) => [
869
+ (0, _kubb_ast_utils.trimQuotes)(v.name.toString()),
870
+ v.value,
871
+ v.description
872
+ ]) ?? node.enumValues?.filter((v) => v !== null && v !== void 0).map((v) => [(0, _kubb_ast_utils.trimQuotes)(v.toString()), v]) ?? [],
854
873
  type: enumOptions.type,
855
874
  enumKeyCasing: enumOptions.keyCasing
856
875
  });
@@ -870,39 +889,6 @@ function Enum({ node, enum: enumOptions, resolver }) {
870
889
  })] });
871
890
  }
872
891
  //#endregion
873
- //#region src/components/Type.tsx
874
- function Type({ name, node, printer, enum: enumOptions, resolver }) {
875
- const enumSchemaNodes = _kubb_core.ast.collect(node, { schema(n) {
876
- const enumNode = _kubb_core.ast.narrowSchema(n, _kubb_core.ast.schemaTypes.enum);
877
- if (enumNode?.name) return enumNode;
878
- } });
879
- const output = printer.print(node);
880
- if (!output) return;
881
- const enums = [...new Map(enumSchemaNodes.map((n) => [n.name, n])).values()].map((node) => {
882
- return {
883
- node,
884
- ...getEnumNames({
885
- node,
886
- enum: enumOptions,
887
- resolver
888
- })
889
- };
890
- });
891
- const shouldExportEnums = enumOptions.type !== "inlineLiteral";
892
- const shouldExportType = enumOptions.type === "inlineLiteral" || enums.every((item) => item.typeName !== name);
893
- return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [shouldExportEnums && enums.map(({ node }) => /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(Enum, {
894
- node,
895
- enum: enumOptions,
896
- resolver
897
- }, node.name)), shouldExportType && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
898
- name,
899
- isTypeOnly: true,
900
- isExportable: true,
901
- isIndexable: true,
902
- children: output
903
- })] });
904
- }
905
- //#endregion
906
892
  //#region ../../internals/shared/src/params.ts
907
893
  const caseParamsCache = /* @__PURE__ */ new WeakMap();
908
894
  /**
@@ -1016,6 +1002,18 @@ function createGroupConfig(group) {
1016
1002
  //#endregion
1017
1003
  //#region src/utils.ts
1018
1004
  /**
1005
+ * Tells whether a `const` (single-value enum) should render as a bare literal type (`'active'`)
1006
+ * rather than a named enum reference or a runtime enum declaration.
1007
+ *
1008
+ * The parser folds `const` into a single-value enum node. The adapter decides which schemas are
1009
+ * named enums and lists them in `enumSchemaNames`, and references to those names get suffixed (for
1010
+ * example `StatusKey`). A const renders as a literal only when the adapter has not registered it as
1011
+ * a named enum, which keeps the declaration and its references in sync across adapter versions.
1012
+ */
1013
+ function isInlineConstEnum(node, enumSchemaNames) {
1014
+ return (node.namedEnumValues ?? node.enumValues ?? []).length === 1 && !(node.name && enumSchemaNames?.has(node.name));
1015
+ }
1016
+ /**
1019
1017
  * Collects JSDoc annotation strings for a schema node.
1020
1018
  *
1021
1019
  * Only uses official JSDoc tags from https://jsdoc.app/: `@description`, `@deprecated`, `@default`, `@example`, `@type`.
@@ -1153,6 +1151,39 @@ function buildResponseUnion(node, { resolver }) {
1153
1151
  });
1154
1152
  }
1155
1153
  //#endregion
1154
+ //#region src/components/Type.tsx
1155
+ function Type({ name, node, printer, enum: enumOptions, resolver }) {
1156
+ const enumSchemaNodes = _kubb_core.ast.collect(node, { schema(n) {
1157
+ const enumNode = _kubb_core.ast.narrowSchema(n, _kubb_core.ast.schemaTypes.enum);
1158
+ if (enumNode?.name && !isInlineConstEnum(enumNode, printer.options.enumSchemaNames)) return enumNode;
1159
+ } });
1160
+ const output = printer.print(node);
1161
+ if (!output) return;
1162
+ const enums = [...new Map(enumSchemaNodes.map((n) => [n.name, n])).values()].map((node) => {
1163
+ return {
1164
+ node,
1165
+ ...getEnumNames({
1166
+ node,
1167
+ enum: enumOptions,
1168
+ resolver
1169
+ })
1170
+ };
1171
+ });
1172
+ const shouldExportEnums = enumOptions.type !== "inlineLiteral";
1173
+ const shouldExportType = enumOptions.type === "inlineLiteral" || enums.every((item) => item.typeName !== name);
1174
+ return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [shouldExportEnums && enums.map(({ node }) => /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(Enum, {
1175
+ node,
1176
+ enum: enumOptions,
1177
+ resolver
1178
+ }, node.name)), shouldExportType && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
1179
+ name,
1180
+ isTypeOnly: true,
1181
+ isExportable: true,
1182
+ isIndexable: true,
1183
+ children: output
1184
+ })] });
1185
+ }
1186
+ //#endregion
1156
1187
  //#region src/printers/printerTs.ts
1157
1188
  const { isNonNullable } = factory_exports;
1158
1189
  /**
@@ -1213,7 +1244,7 @@ const printerTs = _kubb_core.ast.createPrinter((options) => {
1213
1244
  },
1214
1245
  enum(node) {
1215
1246
  const values = node.namedEnumValues?.map((v) => v.value) ?? node.enumValues ?? [];
1216
- if (this.options.enum.type === "inlineLiteral" || !node.name) return createUnionDeclaration({
1247
+ if (this.options.enum.type === "inlineLiteral" || !node.name || isInlineConstEnum(node, this.options.enumSchemaNames)) return createUnionDeclaration({
1217
1248
  withParentheses: true,
1218
1249
  nodes: values.filter((v) => v !== null && v !== void 0).map((value) => constToTypeNode(value, typeof value)).filter(isNonNullable)
1219
1250
  }) ?? void 0;
@@ -1343,7 +1374,8 @@ const typeGenerator = (0, _kubb_core.defineGenerator)({
1343
1374
  group: group ?? void 0
1344
1375
  }).path
1345
1376
  }));
1346
- const isEnumSchema = !!_kubb_core.ast.narrowSchema(node, _kubb_core.ast.schemaTypes.enum);
1377
+ const enumNode = _kubb_core.ast.narrowSchema(node, _kubb_core.ast.schemaTypes.enum);
1378
+ const isEnumSchema = !!enumNode && !isInlineConstEnum(enumNode, enumSchemaNames);
1347
1379
  const meta = {
1348
1380
  name: ENUM_TYPES_WITH_KEY_SUFFIX.has(enumOptions.type) && isEnumSchema ? resolver.resolveEnumKeyName(node, enumOptions.typeSuffix) : resolver.resolveTypeName(node.name),
1349
1381
  file: resolver.resolveFile({