@kubb/plugin-ts 5.0.0-beta.42 → 5.0.0-beta.56
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 +106 -165
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +94 -92
- package/dist/index.js +104 -163
- package/dist/index.js.map +1 -1
- package/package.json +8 -15
- package/src/components/Enum.tsx +30 -26
- package/src/components/Type.tsx +6 -11
- package/src/constants.ts +7 -7
- package/src/factory.ts +5 -38
- package/src/generators/typeGenerator.tsx +22 -42
- package/src/plugin.ts +12 -9
- package/src/printers/printerTs.ts +13 -24
- package/src/resolvers/resolverTs.ts +6 -6
- package/src/types.ts +77 -57
- package/src/utils.ts +1 -1
- package/extension.yaml +0 -1080
package/dist/index.cjs
CHANGED
|
@@ -28,6 +28,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
28
28
|
enumerable: true
|
|
29
29
|
}) : target, mod));
|
|
30
30
|
//#endregion
|
|
31
|
+
let _kubb_ast_utils = require("@kubb/ast/utils");
|
|
31
32
|
let _kubb_parser_ts = require("@kubb/parser-ts");
|
|
32
33
|
let _kubb_renderer_jsx = require("@kubb/renderer-jsx");
|
|
33
34
|
let _kubb_core = require("@kubb/core");
|
|
@@ -45,58 +46,41 @@ let _kubb_renderer_jsx_jsx_runtime = require("@kubb/renderer-jsx/jsx-runtime");
|
|
|
45
46
|
function toCamelOrPascal(text, pascal) {
|
|
46
47
|
return text.trim().replace(/([a-z\d])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/(\d)([a-z])/g, "$1 $2").split(/[\s\-_./\\:]+/).filter(Boolean).map((word, i) => {
|
|
47
48
|
if (word.length > 1 && word === word.toUpperCase()) return word;
|
|
48
|
-
|
|
49
|
-
return word.charAt(0).toUpperCase() + word.slice(1);
|
|
49
|
+
return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
|
|
50
50
|
}).join("").replace(/[^a-zA-Z0-9]/g, "");
|
|
51
51
|
}
|
|
52
52
|
/**
|
|
53
|
-
* Splits `text` on `.` and applies `transformPart` to each segment.
|
|
54
|
-
* The last segment receives `isLast = true`, all earlier segments receive `false`.
|
|
55
|
-
* Segments are joined with `/` to form a file path.
|
|
56
|
-
*
|
|
57
|
-
* Only splits on dots followed by a letter so that version numbers
|
|
58
|
-
* embedded in operationIds (e.g. `v2025.0`) are kept intact.
|
|
59
|
-
*/
|
|
60
|
-
function applyToFileParts(text, transformPart) {
|
|
61
|
-
const parts = text.split(/\.(?=[a-zA-Z])/);
|
|
62
|
-
return parts.map((part, i) => transformPart(part, i === parts.length - 1)).join("/");
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
53
|
* Converts `text` to camelCase.
|
|
66
|
-
* When `isFile` is `true`, dot-separated segments are each cased independently and joined with `/`.
|
|
67
54
|
*
|
|
68
|
-
* @example
|
|
69
|
-
* camelCase('hello-world')
|
|
70
|
-
*
|
|
55
|
+
* @example Word boundaries
|
|
56
|
+
* `camelCase('hello-world') // 'helloWorld'`
|
|
57
|
+
*
|
|
58
|
+
* @example With a prefix
|
|
59
|
+
* `camelCase('tag', { prefix: 'create' }) // 'createTag'`
|
|
71
60
|
*/
|
|
72
|
-
function camelCase(text, {
|
|
73
|
-
if (isFile) return applyToFileParts(text, (part, isLast) => camelCase(part, isLast ? {
|
|
74
|
-
prefix,
|
|
75
|
-
suffix
|
|
76
|
-
} : {}));
|
|
61
|
+
function camelCase(text, { prefix = "", suffix = "" } = {}) {
|
|
77
62
|
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
|
|
78
63
|
}
|
|
79
64
|
/**
|
|
80
65
|
* Converts `text` to PascalCase.
|
|
81
|
-
* When `isFile` is `true`, the last dot-separated segment is PascalCased and earlier segments are camelCased.
|
|
82
66
|
*
|
|
83
|
-
* @example
|
|
84
|
-
* pascalCase('hello-world')
|
|
85
|
-
*
|
|
67
|
+
* @example Word boundaries
|
|
68
|
+
* `pascalCase('hello-world') // 'HelloWorld'`
|
|
69
|
+
*
|
|
70
|
+
* @example With a suffix
|
|
71
|
+
* `pascalCase('tag', { suffix: 'schema' }) // 'TagSchema'`
|
|
86
72
|
*/
|
|
87
|
-
function pascalCase(text, {
|
|
88
|
-
if (isFile) return applyToFileParts(text, (part, isLast) => isLast ? pascalCase(part, {
|
|
89
|
-
prefix,
|
|
90
|
-
suffix
|
|
91
|
-
}) : camelCase(part));
|
|
73
|
+
function pascalCase(text, { prefix = "", suffix = "" } = {}) {
|
|
92
74
|
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true);
|
|
93
75
|
}
|
|
94
76
|
/**
|
|
95
77
|
* Converts `text` to snake_case.
|
|
96
78
|
*
|
|
97
|
-
* @example
|
|
98
|
-
* snakeCase('helloWorld')
|
|
99
|
-
*
|
|
79
|
+
* @example From camelCase
|
|
80
|
+
* `snakeCase('helloWorld') // 'hello_world'`
|
|
81
|
+
*
|
|
82
|
+
* @example From mixed separators
|
|
83
|
+
* `snakeCase('Hello-World') // 'hello_world'`
|
|
100
84
|
*/
|
|
101
85
|
function snakeCase(text, { prefix = "", suffix = "" } = {}) {
|
|
102
86
|
return `${prefix} ${text} ${suffix}`.trim().replace(/([a-z])([A-Z])/g, "$1_$2").replace(/[\s\-.]+/g, "_").replace(/[^a-zA-Z0-9_]/g, "").toLowerCase().split("_").filter(Boolean).join("_");
|
|
@@ -104,8 +88,8 @@ function snakeCase(text, { prefix = "", suffix = "" } = {}) {
|
|
|
104
88
|
/**
|
|
105
89
|
* Converts `text` to SCREAMING_SNAKE_CASE.
|
|
106
90
|
*
|
|
107
|
-
* @example
|
|
108
|
-
* screamingSnakeCase('helloWorld') // 'HELLO_WORLD'
|
|
91
|
+
* @example From camelCase
|
|
92
|
+
* `screamingSnakeCase('helloWorld') // 'HELLO_WORLD'`
|
|
109
93
|
*/
|
|
110
94
|
function screamingSnakeCase(text, { prefix = "", suffix = "" } = {}) {
|
|
111
95
|
return snakeCase(text, {
|
|
@@ -114,60 +98,29 @@ function screamingSnakeCase(text, { prefix = "", suffix = "" } = {}) {
|
|
|
114
98
|
}).toUpperCase();
|
|
115
99
|
}
|
|
116
100
|
//#endregion
|
|
117
|
-
//#region ../../internals/utils/src/
|
|
101
|
+
//#region ../../internals/utils/src/fs.ts
|
|
118
102
|
/**
|
|
119
|
-
*
|
|
120
|
-
*
|
|
103
|
+
* Builds a nested file path from a dotted name. Splits on dots that precede a letter
|
|
104
|
+
* (so version numbers embedded in operationIds like `v2025.0` stay intact), camelCases
|
|
105
|
+
* every earlier segment, applies `caseLast` to the final segment, and joins with `/`.
|
|
121
106
|
*
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
|
|
126
|
-
function trimQuotes(text) {
|
|
127
|
-
if (text.length >= 2) {
|
|
128
|
-
const first = text[0];
|
|
129
|
-
const last = text[text.length - 1];
|
|
130
|
-
if (first === "\"" && last === "\"" || first === "'" && last === "'" || first === "`" && last === "`") return text.slice(1, -1);
|
|
131
|
-
}
|
|
132
|
-
return text;
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* Escapes characters that are not allowed inside JS string literals.
|
|
136
|
-
* Handles quotes, backslashes, and Unicode line terminators (U+2028 / U+2029).
|
|
107
|
+
* Empty segments are dropped before joining. They arise when the name starts with a dot
|
|
108
|
+
* followed by a letter (e.g. `..Schema` splits into `['..', 'Schema']` and `'..'` cases to
|
|
109
|
+
* an empty string). Without this a leading `/` would form, which `path.resolve` reads as an
|
|
110
|
+
* absolute path, letting generated files escape the configured output directory.
|
|
137
111
|
*
|
|
138
|
-
* @
|
|
112
|
+
* @example Nested path from a dotted name
|
|
113
|
+
* `toFilePath('pet.petId') // 'pet/petId'`
|
|
139
114
|
*
|
|
140
|
-
* @example
|
|
141
|
-
*
|
|
142
|
-
* jsStringEscape('say "hi"\nbye') // 'say \\"hi\\"\\nbye'
|
|
143
|
-
* ```
|
|
144
|
-
*/
|
|
145
|
-
function jsStringEscape(input) {
|
|
146
|
-
return `${input}`.replace(/["'\\\n\r\u2028\u2029]/g, (character) => {
|
|
147
|
-
switch (character) {
|
|
148
|
-
case "\"":
|
|
149
|
-
case "'":
|
|
150
|
-
case "\\": return `\\${character}`;
|
|
151
|
-
case "\n": return "\\n";
|
|
152
|
-
case "\r": return "\\r";
|
|
153
|
-
case "\u2028": return "\\u2028";
|
|
154
|
-
case "\u2029": return "\\u2029";
|
|
155
|
-
default: return "";
|
|
156
|
-
}
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
//#endregion
|
|
160
|
-
//#region ../../internals/utils/src/object.ts
|
|
161
|
-
/**
|
|
162
|
-
* Serializes a primitive value to a JSON string literal, stripping any surrounding quote characters first.
|
|
115
|
+
* @example PascalCase the final segment
|
|
116
|
+
* `toFilePath('pet.Pet', pascalCase) // 'pet/Pet'`
|
|
163
117
|
*
|
|
164
|
-
* @example
|
|
165
|
-
*
|
|
166
|
-
* stringify('"hello"') // '"hello"'
|
|
118
|
+
* @example Suffix applied to the final segment only
|
|
119
|
+
* `toFilePath('tag.tag', (part) => camelCase(part, { suffix: 'schema' })) // 'tag/tagSchema'`
|
|
167
120
|
*/
|
|
168
|
-
function
|
|
169
|
-
|
|
170
|
-
return
|
|
121
|
+
function toFilePath(name, caseLast = camelCase) {
|
|
122
|
+
const parts = name.split(/\.(?=[a-zA-Z])/);
|
|
123
|
+
return parts.map((part, i) => i === parts.length - 1 ? caseLast(part) : camelCase(part)).filter(Boolean).join("/");
|
|
171
124
|
}
|
|
172
125
|
//#endregion
|
|
173
126
|
//#region ../../internals/utils/src/reserved.ts
|
|
@@ -303,26 +256,24 @@ const OPTIONAL_ADDS_UNDEFINED = new Set(["undefined", "questionTokenAndUndefined
|
|
|
303
256
|
*/
|
|
304
257
|
const OPTIONAL_ADDS_QUESTION_TOKEN = new Set(["questionToken", "questionTokenAndUndefined"]);
|
|
305
258
|
/**
|
|
306
|
-
* `
|
|
259
|
+
* `enum.type` values that append a `typeSuffix` to the generated enum type alias.
|
|
307
260
|
*/
|
|
308
|
-
const ENUM_TYPES_WITH_KEY_SUFFIX = new Set(["asConst"
|
|
261
|
+
const ENUM_TYPES_WITH_KEY_SUFFIX = new Set(["asConst"]);
|
|
309
262
|
/**
|
|
310
|
-
* `
|
|
263
|
+
* `enum.type` values that require a runtime value declaration (object, enum, or literal).
|
|
311
264
|
*/
|
|
312
265
|
const ENUM_TYPES_WITH_RUNTIME_VALUE = new Set([
|
|
313
266
|
"enum",
|
|
314
267
|
"asConst",
|
|
315
|
-
"asPascalConst",
|
|
316
268
|
"constEnum",
|
|
317
269
|
"literal",
|
|
318
270
|
void 0
|
|
319
271
|
]);
|
|
320
272
|
/**
|
|
321
|
-
* `
|
|
273
|
+
* `enum.type` values whose type declaration is type-only (no runtime value emitted for the type alias).
|
|
322
274
|
*/
|
|
323
275
|
const ENUM_TYPES_WITH_TYPE_ONLY = new Set([
|
|
324
276
|
"asConst",
|
|
325
|
-
"asPascalConst",
|
|
326
277
|
"literal",
|
|
327
278
|
void 0
|
|
328
279
|
]);
|
|
@@ -642,12 +593,10 @@ const createStringLiteral = factory.createStringLiteral;
|
|
|
642
593
|
* Creates an array type node (e.g., `T[]`).
|
|
643
594
|
*/
|
|
644
595
|
const createArrayTypeNode = factory.createArrayTypeNode;
|
|
645
|
-
factory.createParenthesizedType;
|
|
646
596
|
/**
|
|
647
597
|
* Creates a literal type node (e.g., `'hello'`, `42`, `true`).
|
|
648
598
|
*/
|
|
649
599
|
const createLiteralTypeNode = factory.createLiteralTypeNode;
|
|
650
|
-
factory.createNull;
|
|
651
600
|
/**
|
|
652
601
|
* Creates an identifier node.
|
|
653
602
|
*/
|
|
@@ -672,8 +621,6 @@ const createTrue = factory.createTrue;
|
|
|
672
621
|
* Creates a boolean false literal type node.
|
|
673
622
|
*/
|
|
674
623
|
const createFalse = factory.createFalse;
|
|
675
|
-
factory.createIndexedAccessTypeNode;
|
|
676
|
-
factory.createTypeOperatorNode;
|
|
677
624
|
/**
|
|
678
625
|
* Creates a prefix unary expression (e.g., negative numbers, logical not).
|
|
679
626
|
*/
|
|
@@ -754,41 +701,44 @@ function buildIndexSignatures(node, propertyCount, print) {
|
|
|
754
701
|
* Resolves the runtime identifier name and the TypeScript type name for an enum schema node.
|
|
755
702
|
*
|
|
756
703
|
* The raw `node.name` may be a YAML key such as `"enumNames.Type"` which is not a
|
|
757
|
-
* valid TypeScript identifier. The resolver normalizes it
|
|
758
|
-
*
|
|
704
|
+
* valid TypeScript identifier. The resolver normalizes it. For inline enum properties the adapter
|
|
705
|
+
* already emits a PascalCase+suffix name, so resolution is typically a no-op.
|
|
706
|
+
*
|
|
707
|
+
* When `constCasing` is `'pascalCase'` and `typeSuffix` is empty, the const and the type
|
|
708
|
+
* resolve to the same name, which TypeScript merges into a single value+type declaration.
|
|
759
709
|
*/
|
|
760
|
-
function getEnumNames({ node,
|
|
710
|
+
function getEnumNames({ node, enum: enumOptions, resolver }) {
|
|
761
711
|
const resolved = resolver.default(node.name, "type");
|
|
762
712
|
return {
|
|
763
|
-
enumName:
|
|
764
|
-
typeName: ENUM_TYPES_WITH_KEY_SUFFIX.has(
|
|
713
|
+
enumName: enumOptions.constCasing === "pascalCase" ? resolved : camelCase(node.name),
|
|
714
|
+
typeName: ENUM_TYPES_WITH_KEY_SUFFIX.has(enumOptions.type) ? resolver.resolveEnumKeyName(node, enumOptions.typeSuffix) : resolved
|
|
765
715
|
};
|
|
766
716
|
}
|
|
767
717
|
/**
|
|
768
718
|
* Renders the enum declaration(s) for a single named `EnumSchemaNode`.
|
|
769
719
|
*
|
|
770
|
-
* Depending on `
|
|
771
|
-
* - A runtime object (`asConst`
|
|
720
|
+
* Depending on `enum.type` this may emit:
|
|
721
|
+
* - A runtime object (`asConst`) plus a `typeof` type alias
|
|
772
722
|
* - A `const enum` or plain `enum` declaration (`constEnum` / `enum`)
|
|
773
723
|
* - A union literal type alias (`literal`)
|
|
774
724
|
*
|
|
775
725
|
* The emitted `File.Source` nodes carry the resolved names so that the barrel
|
|
776
726
|
* index picks up the correct export identifiers.
|
|
777
727
|
*/
|
|
778
|
-
function Enum({ node,
|
|
728
|
+
function Enum({ node, enum: enumOptions, resolver }) {
|
|
779
729
|
const { enumName, typeName } = getEnumNames({
|
|
780
730
|
node,
|
|
781
|
-
|
|
782
|
-
enumTypeSuffix,
|
|
731
|
+
enum: enumOptions,
|
|
783
732
|
resolver
|
|
784
733
|
});
|
|
785
734
|
const [nameNode, typeNode] = createEnumDeclaration({
|
|
786
735
|
name: enumName,
|
|
787
736
|
typeName,
|
|
788
|
-
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]) ?? [],
|
|
789
|
-
type:
|
|
790
|
-
enumKeyCasing
|
|
737
|
+
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]) ?? [],
|
|
738
|
+
type: enumOptions.type,
|
|
739
|
+
enumKeyCasing: enumOptions.keyCasing
|
|
791
740
|
});
|
|
741
|
+
const namesMerge = !!nameNode && enumName === typeName;
|
|
792
742
|
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [nameNode && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
|
|
793
743
|
name: enumName,
|
|
794
744
|
isExportable: true,
|
|
@@ -797,15 +747,15 @@ function Enum({ node, enumType, enumTypeSuffix, enumKeyCasing, resolver }) {
|
|
|
797
747
|
children: _kubb_parser_ts.parserTs.print(nameNode)
|
|
798
748
|
}), /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
|
|
799
749
|
name: typeName,
|
|
800
|
-
isIndexable:
|
|
801
|
-
isExportable: ENUM_TYPES_WITH_RUNTIME_VALUE.has(
|
|
802
|
-
isTypeOnly: ENUM_TYPES_WITH_TYPE_ONLY.has(
|
|
750
|
+
isIndexable: !namesMerge,
|
|
751
|
+
isExportable: !namesMerge && ENUM_TYPES_WITH_RUNTIME_VALUE.has(enumOptions.type),
|
|
752
|
+
isTypeOnly: ENUM_TYPES_WITH_TYPE_ONLY.has(enumOptions.type),
|
|
803
753
|
children: _kubb_parser_ts.parserTs.print(typeNode)
|
|
804
754
|
})] });
|
|
805
755
|
}
|
|
806
756
|
//#endregion
|
|
807
757
|
//#region src/components/Type.tsx
|
|
808
|
-
function Type({ name, node, printer,
|
|
758
|
+
function Type({ name, node, printer, enum: enumOptions, resolver }) {
|
|
809
759
|
const enumSchemaNodes = _kubb_core.ast.collect(node, { schema(n) {
|
|
810
760
|
const enumNode = _kubb_core.ast.narrowSchema(n, _kubb_core.ast.schemaTypes.enum);
|
|
811
761
|
if (enumNode?.name) return enumNode;
|
|
@@ -817,19 +767,16 @@ function Type({ name, node, printer, enumType, enumTypeSuffix, enumKeyCasing, re
|
|
|
817
767
|
node,
|
|
818
768
|
...getEnumNames({
|
|
819
769
|
node,
|
|
820
|
-
|
|
821
|
-
enumTypeSuffix,
|
|
770
|
+
enum: enumOptions,
|
|
822
771
|
resolver
|
|
823
772
|
})
|
|
824
773
|
};
|
|
825
774
|
});
|
|
826
|
-
const shouldExportEnums =
|
|
827
|
-
const shouldExportType =
|
|
775
|
+
const shouldExportEnums = enumOptions.type !== "inlineLiteral";
|
|
776
|
+
const shouldExportType = enumOptions.type === "inlineLiteral" || enums.every((item) => item.typeName !== name);
|
|
828
777
|
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, {
|
|
829
778
|
node,
|
|
830
|
-
|
|
831
|
-
enumTypeSuffix,
|
|
832
|
-
enumKeyCasing,
|
|
779
|
+
enum: enumOptions,
|
|
833
780
|
resolver
|
|
834
781
|
}, node.name)), shouldExportType && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
|
|
835
782
|
name,
|
|
@@ -905,26 +852,24 @@ function getOperationParameters(node, options = {}) {
|
|
|
905
852
|
* shared default naming so every plugin groups output consistently:
|
|
906
853
|
*
|
|
907
854
|
* - `path` groups use the second path segment (`/pet/findByStatus` → `pet`).
|
|
908
|
-
* - other groups use
|
|
855
|
+
* - other groups use the camelCased group (`pet store` → `petStore`).
|
|
909
856
|
*
|
|
910
857
|
* A user-provided `group.name` always wins over the default namer, so callers stay in
|
|
911
858
|
* control of their output folders. Returns `null` when grouping is disabled, matching the
|
|
912
859
|
* per-plugin convention.
|
|
913
860
|
*
|
|
914
861
|
* @param group - The user-supplied group option, or `undefined` to disable grouping.
|
|
915
|
-
* @param options.suffix - Appended to non-`path` group names, e.g. `'Controller'` or `'Requests'`.
|
|
916
862
|
*
|
|
917
863
|
* @example
|
|
918
864
|
* ```ts
|
|
919
|
-
* createGroupConfig(group
|
|
920
|
-
* createGroupConfig(group, { suffix: 'Requests' }) // plugin-cypress, plugin-mcp
|
|
865
|
+
* createGroupConfig(group) // shared across every plugin
|
|
921
866
|
* ```
|
|
922
867
|
*/
|
|
923
|
-
function createGroupConfig(group
|
|
868
|
+
function createGroupConfig(group) {
|
|
924
869
|
if (!group) return null;
|
|
925
870
|
const defaultName = (ctx) => {
|
|
926
871
|
if (group.type === "path") return `${ctx.group.split("/")[1]}`;
|
|
927
|
-
return
|
|
872
|
+
return camelCase(ctx.group);
|
|
928
873
|
};
|
|
929
874
|
return {
|
|
930
875
|
...group,
|
|
@@ -946,13 +891,13 @@ function buildPropertyJSDocComments(schema) {
|
|
|
946
891
|
const hasDescription = meta && "description" in meta && meta.description;
|
|
947
892
|
const formatComment = meta && "format" in meta && meta.format ? hasDescription ? [" ", `Format: \`${meta.format}\``] : ["@description", `Format: \`${meta.format}\``] : [];
|
|
948
893
|
return [
|
|
949
|
-
hasDescription ? `@description ${jsStringEscape(meta.description)}` : null,
|
|
894
|
+
hasDescription ? `@description ${(0, _kubb_ast_utils.jsStringEscape)(meta.description)}` : null,
|
|
950
895
|
...formatComment,
|
|
951
896
|
meta && "deprecated" in meta && meta.deprecated ? "@deprecated" : null,
|
|
952
897
|
!isArray && meta && "min" in meta && meta.min !== void 0 ? `@minLength ${meta.min}` : null,
|
|
953
898
|
!isArray && meta && "max" in meta && meta.max !== void 0 ? `@maxLength ${meta.max}` : null,
|
|
954
899
|
meta && "pattern" in meta && meta.pattern ? `@pattern ${meta.pattern}` : null,
|
|
955
|
-
meta && "default" in meta && meta.default !== void 0 ? `@default ${"primitive" in meta && meta.primitive === "string" ? stringify(meta.default) : meta.default}` : null,
|
|
900
|
+
meta && "default" in meta && meta.default !== void 0 ? `@default ${"primitive" in meta && meta.primitive === "string" ? (0, _kubb_ast_utils.stringify)(meta.default) : meta.default}` : null,
|
|
956
901
|
meta && "example" in meta && meta.example !== void 0 ? `@example ${meta.example}` : null,
|
|
957
902
|
meta && "primitive" in meta && meta.primitive ? [`@type ${meta.primitive}`, "optional" in schema && schema.optional ? " | undefined" : null].filter(Boolean).join("") : null
|
|
958
903
|
].filter(Boolean);
|
|
@@ -1081,13 +1026,13 @@ function isNonNullable(value) {
|
|
|
1081
1026
|
*
|
|
1082
1027
|
* @example Raw type node (no `typeName`)
|
|
1083
1028
|
* ```ts
|
|
1084
|
-
* const printer = printerTs({ optionalType: 'questionToken', arrayType: 'array',
|
|
1029
|
+
* const printer = printerTs({ optionalType: 'questionToken', arrayType: 'array', enum: { type: 'inlineLiteral' } })
|
|
1085
1030
|
* const typeNode = printer.print(schemaNode) // ts.TypeNode
|
|
1086
1031
|
* ```
|
|
1087
1032
|
*
|
|
1088
1033
|
* @example Full declaration (with `typeName`)
|
|
1089
1034
|
* ```ts
|
|
1090
|
-
* const printer = printerTs({ optionalType: 'questionToken', arrayType: 'array',
|
|
1035
|
+
* const printer = printerTs({ optionalType: 'questionToken', arrayType: 'array', enum: { type: 'inlineLiteral' }, typeName: 'MyType' })
|
|
1091
1036
|
* const declaration = printer.print(schemaNode) // ts.TypeAliasDeclaration | ts.InterfaceDeclaration
|
|
1092
1037
|
* ```
|
|
1093
1038
|
*/
|
|
@@ -1121,16 +1066,16 @@ const printerTs = _kubb_core.ast.definePrinter((options) => {
|
|
|
1121
1066
|
time: dateOrStringNode,
|
|
1122
1067
|
ref(node) {
|
|
1123
1068
|
if (!node.name) return null;
|
|
1124
|
-
const refName = node.ref ?
|
|
1125
|
-
return createTypeReferenceNode(node.ref && ENUM_TYPES_WITH_KEY_SUFFIX.has(this.options.
|
|
1069
|
+
const refName = node.ref ? (0, _kubb_ast_utils.extractRefName)(node.ref) ?? node.name : node.name;
|
|
1070
|
+
return createTypeReferenceNode(node.ref && ENUM_TYPES_WITH_KEY_SUFFIX.has(this.options.enum.type) && this.options.enum.typeSuffix && this.options.enumSchemaNames?.has(refName) ? this.options.resolver.resolveEnumKeyName({ name: refName }, this.options.enum.typeSuffix) : node.ref ? this.options.resolver.default(refName, "type") : refName, void 0);
|
|
1126
1071
|
},
|
|
1127
1072
|
enum(node) {
|
|
1128
1073
|
const values = node.namedEnumValues?.map((v) => v.value) ?? node.enumValues ?? [];
|
|
1129
|
-
if (this.options.
|
|
1074
|
+
if (this.options.enum.type === "inlineLiteral" || !node.name) return createUnionDeclaration({
|
|
1130
1075
|
withParentheses: true,
|
|
1131
1076
|
nodes: values.filter((v) => v !== null && v !== void 0).map((value) => constToTypeNode(value, typeof value)).filter(isNonNullable)
|
|
1132
1077
|
}) ?? void 0;
|
|
1133
|
-
return createTypeReferenceNode(ENUM_TYPES_WITH_KEY_SUFFIX.has(this.options.
|
|
1078
|
+
return createTypeReferenceNode(ENUM_TYPES_WITH_KEY_SUFFIX.has(this.options.enum.type) && this.options.enum.typeSuffix ? this.options.resolver.resolveEnumKeyName(node, this.options.enum.typeSuffix) : this.options.resolver.default(node.name, "type"), void 0);
|
|
1134
1079
|
},
|
|
1135
1080
|
union(node) {
|
|
1136
1081
|
const members = node.members ?? [];
|
|
@@ -1234,15 +1179,14 @@ const printerTs = _kubb_core.ast.definePrinter((options) => {
|
|
|
1234
1179
|
*/
|
|
1235
1180
|
const typeGenerator = (0, _kubb_core.defineGenerator)({
|
|
1236
1181
|
name: "typescript",
|
|
1237
|
-
renderer: _kubb_renderer_jsx.
|
|
1182
|
+
renderer: _kubb_renderer_jsx.jsxRenderer,
|
|
1238
1183
|
schema(node, ctx) {
|
|
1239
|
-
const {
|
|
1184
|
+
const { enum: enumOptions, syntaxType, optionalType, arrayType, output, group, printer } = ctx.options;
|
|
1240
1185
|
const { adapter, config, resolver, root } = ctx;
|
|
1241
1186
|
if (!node.name) return;
|
|
1242
|
-
const mode = ctx.getMode(output);
|
|
1243
1187
|
const enumSchemaNames = new Set(ctx.meta.enumNames);
|
|
1244
1188
|
function resolveImportName(schemaName) {
|
|
1245
|
-
if (ENUM_TYPES_WITH_KEY_SUFFIX.has(
|
|
1189
|
+
if (ENUM_TYPES_WITH_KEY_SUFFIX.has(enumOptions.type) && enumOptions.typeSuffix && enumSchemaNames.has(schemaName)) return resolver.resolveEnumKeyName({ name: schemaName }, enumOptions.typeSuffix);
|
|
1246
1190
|
return resolver.resolveTypeName(schemaName);
|
|
1247
1191
|
}
|
|
1248
1192
|
const imports = adapter.getImports(node, (schemaName) => ({
|
|
@@ -1258,7 +1202,7 @@ const typeGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1258
1202
|
}));
|
|
1259
1203
|
const isEnumSchema = !!_kubb_core.ast.narrowSchema(node, _kubb_core.ast.schemaTypes.enum);
|
|
1260
1204
|
const meta = {
|
|
1261
|
-
name: ENUM_TYPES_WITH_KEY_SUFFIX.has(
|
|
1205
|
+
name: ENUM_TYPES_WITH_KEY_SUFFIX.has(enumOptions.type) && isEnumSchema ? resolver.resolveEnumKeyName(node, enumOptions.typeSuffix) : resolver.resolveTypeName(node.name),
|
|
1262
1206
|
file: resolver.resolveFile({
|
|
1263
1207
|
name: node.name,
|
|
1264
1208
|
extname: ".ts"
|
|
@@ -1271,8 +1215,7 @@ const typeGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1271
1215
|
const schemaPrinter = printerTs({
|
|
1272
1216
|
optionalType,
|
|
1273
1217
|
arrayType,
|
|
1274
|
-
|
|
1275
|
-
enumTypeSuffix,
|
|
1218
|
+
enum: enumOptions,
|
|
1276
1219
|
name: meta.name,
|
|
1277
1220
|
syntaxType,
|
|
1278
1221
|
description: node.description,
|
|
@@ -1300,7 +1243,7 @@ const typeGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1300
1243
|
baseName: meta.file.baseName
|
|
1301
1244
|
}
|
|
1302
1245
|
}),
|
|
1303
|
-
children: [
|
|
1246
|
+
children: [imports.map((imp) => /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1304
1247
|
root: meta.file.path,
|
|
1305
1248
|
path: imp.path,
|
|
1306
1249
|
name: imp.name,
|
|
@@ -1312,18 +1255,15 @@ const typeGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1312
1255
|
].join("-"))), /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(Type, {
|
|
1313
1256
|
name: meta.name,
|
|
1314
1257
|
node,
|
|
1315
|
-
|
|
1316
|
-
enumTypeSuffix,
|
|
1317
|
-
enumKeyCasing,
|
|
1258
|
+
enum: enumOptions,
|
|
1318
1259
|
resolver,
|
|
1319
1260
|
printer: schemaPrinter
|
|
1320
1261
|
})]
|
|
1321
1262
|
});
|
|
1322
1263
|
},
|
|
1323
1264
|
operation(node, ctx) {
|
|
1324
|
-
const {
|
|
1265
|
+
const { enum: enumOptions, optionalType, arrayType, syntaxType, paramsCasing, group, output, printer } = ctx.options;
|
|
1325
1266
|
const { adapter, config, resolver, root } = ctx;
|
|
1326
|
-
const mode = ctx.getMode(output);
|
|
1327
1267
|
const params = _kubb_core.ast.caseParams(node.parameters, paramsCasing);
|
|
1328
1268
|
const meta = { file: resolver.resolveFile({
|
|
1329
1269
|
name: node.operationId,
|
|
@@ -1337,7 +1277,7 @@ const typeGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1337
1277
|
}) };
|
|
1338
1278
|
const enumSchemaNames = new Set(ctx.meta.enumNames);
|
|
1339
1279
|
function resolveImportName(schemaName) {
|
|
1340
|
-
if (ENUM_TYPES_WITH_KEY_SUFFIX.has(
|
|
1280
|
+
if (ENUM_TYPES_WITH_KEY_SUFFIX.has(enumOptions.type) && enumOptions.typeSuffix && enumSchemaNames.has(schemaName)) return resolver.resolveEnumKeyName({ name: schemaName }, enumOptions.typeSuffix);
|
|
1341
1281
|
return resolver.resolveTypeName(schemaName);
|
|
1342
1282
|
}
|
|
1343
1283
|
function renderSchemaType({ schema, name, keysToOmit }) {
|
|
@@ -1356,8 +1296,7 @@ const typeGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1356
1296
|
const schemaPrinter = printerTs({
|
|
1357
1297
|
optionalType,
|
|
1358
1298
|
arrayType,
|
|
1359
|
-
|
|
1360
|
-
enumTypeSuffix,
|
|
1299
|
+
enum: enumOptions,
|
|
1361
1300
|
name,
|
|
1362
1301
|
syntaxType,
|
|
1363
1302
|
description: schema.description,
|
|
@@ -1366,7 +1305,7 @@ const typeGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1366
1305
|
enumSchemaNames,
|
|
1367
1306
|
nodes: printer?.nodes
|
|
1368
1307
|
});
|
|
1369
|
-
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [
|
|
1308
|
+
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [imports.map((imp) => /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1370
1309
|
root: meta.file.path,
|
|
1371
1310
|
path: imp.path,
|
|
1372
1311
|
name: imp.name,
|
|
@@ -1378,9 +1317,7 @@ const typeGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1378
1317
|
].join("-"))), /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(Type, {
|
|
1379
1318
|
name,
|
|
1380
1319
|
node: schema,
|
|
1381
|
-
|
|
1382
|
-
enumTypeSuffix,
|
|
1383
|
-
enumKeyCasing,
|
|
1320
|
+
enum: enumOptions,
|
|
1384
1321
|
resolver,
|
|
1385
1322
|
printer: schemaPrinter
|
|
1386
1323
|
})] });
|
|
@@ -1511,7 +1448,7 @@ const typeGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1511
1448
|
* casing/file-layout rules.
|
|
1512
1449
|
*
|
|
1513
1450
|
* The `default` method is supplied by `defineResolver`. It uses PascalCase for
|
|
1514
|
-
* type names and PascalCase
|
|
1451
|
+
* type names and PascalCase file paths (dotted names become `/`-joined) for files.
|
|
1515
1452
|
*
|
|
1516
1453
|
* @example Resolve a type and file name
|
|
1517
1454
|
* ```ts
|
|
@@ -1527,15 +1464,15 @@ const resolverTs = (0, _kubb_core.defineResolver)(() => {
|
|
|
1527
1464
|
name: "default",
|
|
1528
1465
|
pluginName: "plugin-ts",
|
|
1529
1466
|
default(name, type) {
|
|
1530
|
-
|
|
1531
|
-
return
|
|
1467
|
+
if (type === "file") return toFilePath(name, pascalCase);
|
|
1468
|
+
return ensureValidVarName(pascalCase(name));
|
|
1532
1469
|
},
|
|
1533
1470
|
resolveTypeName(name) {
|
|
1534
1471
|
return ensureValidVarName(pascalCase(name));
|
|
1535
1472
|
},
|
|
1536
1473
|
resolvePathName(name, type) {
|
|
1537
|
-
|
|
1538
|
-
return
|
|
1474
|
+
if (type === "file") return toFilePath(name, pascalCase);
|
|
1475
|
+
return ensureValidVarName(pascalCase(name));
|
|
1539
1476
|
},
|
|
1540
1477
|
resolveParamName(node, param) {
|
|
1541
1478
|
return this.resolveTypeName(`${node.operationId} ${param.in} ${param.name}`);
|
|
@@ -1593,7 +1530,7 @@ const pluginTsName = "plugin-ts";
|
|
|
1593
1530
|
* plugins: [
|
|
1594
1531
|
* pluginTs({
|
|
1595
1532
|
* output: { path: './types' },
|
|
1596
|
-
*
|
|
1533
|
+
* enum: { type: 'asConst' },
|
|
1597
1534
|
* optionalType: 'questionTokenAndUndefined',
|
|
1598
1535
|
* }),
|
|
1599
1536
|
* ],
|
|
@@ -1603,9 +1540,15 @@ const pluginTsName = "plugin-ts";
|
|
|
1603
1540
|
const pluginTs = (0, _kubb_core.definePlugin)((options) => {
|
|
1604
1541
|
const { output = {
|
|
1605
1542
|
path: "types",
|
|
1606
|
-
|
|
1607
|
-
}, group, exclude = [], include, override = [],
|
|
1608
|
-
const groupConfig = createGroupConfig(group
|
|
1543
|
+
barrel: { type: "named" }
|
|
1544
|
+
}, group, exclude = [], include, override = [], enum: enumOptions = {}, optionalType = "questionToken", arrayType = "array", syntaxType = "type", paramsCasing, printer, resolver: userResolver, transformer: userTransformer, generators: userGenerators = [] } = options;
|
|
1545
|
+
const groupConfig = createGroupConfig(group);
|
|
1546
|
+
const resolvedEnum = {
|
|
1547
|
+
type: enumOptions.type ?? "asConst",
|
|
1548
|
+
constCasing: enumOptions.constCasing ?? "camelCase",
|
|
1549
|
+
typeSuffix: enumOptions.typeSuffix ?? "Key",
|
|
1550
|
+
keyCasing: enumOptions.keyCasing ?? "none"
|
|
1551
|
+
};
|
|
1609
1552
|
return {
|
|
1610
1553
|
name: pluginTsName,
|
|
1611
1554
|
options,
|
|
@@ -1618,9 +1561,7 @@ const pluginTs = (0, _kubb_core.definePlugin)((options) => {
|
|
|
1618
1561
|
optionalType,
|
|
1619
1562
|
group: groupConfig,
|
|
1620
1563
|
arrayType,
|
|
1621
|
-
|
|
1622
|
-
enumTypeSuffix,
|
|
1623
|
-
enumKeyCasing,
|
|
1564
|
+
enum: resolvedEnum,
|
|
1624
1565
|
syntaxType,
|
|
1625
1566
|
paramsCasing,
|
|
1626
1567
|
printer
|