@kubb/parser-ts 5.0.0-beta.7 → 5.0.0-beta.71
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/LICENSE +17 -10
- package/README.md +47 -48
- package/dist/index.cjs +245 -133
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +60 -55
- package/dist/index.js +247 -130
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
- package/extension.yaml +0 -100
- package/src/constants.ts +0 -47
- package/src/index.ts +0 -2
- package/src/parserTs.ts +0 -509
- package/src/parserTsx.ts +0 -20
- /package/dist/{chunk--u3MIqq1.js → rolldown-runtime-C0LytTxp.js} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,11 +1,30 @@
|
|
|
1
|
-
import "./
|
|
2
|
-
import { normalize, relative } from "node:path";
|
|
1
|
+
import "./rolldown-runtime-C0LytTxp.js";
|
|
3
2
|
import { defineParser } from "@kubb/core";
|
|
3
|
+
import { normalize, relative } from "node:path";
|
|
4
4
|
import ts from "typescript";
|
|
5
|
-
//#region src/
|
|
5
|
+
//#region ../../internals/utils/src/fs.ts
|
|
6
|
+
/**
|
|
7
|
+
* Strips the file extension from a path or file name.
|
|
8
|
+
* Only removes the last `.ext` segment when the dot is not part of a directory name.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* trimExtName('petStore.ts') // 'petStore'
|
|
12
|
+
* trimExtName('/src/models/pet.ts') // '/src/models/pet'
|
|
13
|
+
* trimExtName('/project.v2/gen/pet.ts') // '/project.v2/gen/pet'
|
|
14
|
+
* trimExtName('noExtension') // 'noExtension'
|
|
15
|
+
*/
|
|
16
|
+
function trimExtName(text) {
|
|
17
|
+
const dotIndex = text.lastIndexOf(".");
|
|
18
|
+
if (dotIndex > 0 && !text.includes("/", dotIndex)) return text.slice(0, dotIndex);
|
|
19
|
+
return text;
|
|
20
|
+
}
|
|
6
21
|
/**
|
|
7
|
-
*
|
|
8
|
-
|
|
22
|
+
* Indentation unit prepended once per nesting level when pretty-printing.
|
|
23
|
+
*/
|
|
24
|
+
const INDENT = " ".repeat(2);
|
|
25
|
+
/**
|
|
26
|
+
* Matches only the final `.<ext>` of a path, so a name like `foo.bar.ts` keeps
|
|
27
|
+
* `foo.bar` and loses just `.ts`.
|
|
9
28
|
*/
|
|
10
29
|
const FILE_EXTENSION_PATTERN = /\.[^/.]+$/;
|
|
11
30
|
/**
|
|
@@ -13,26 +32,29 @@ const FILE_EXTENSION_PATTERN = /\.[^/.]+$/;
|
|
|
13
32
|
*/
|
|
14
33
|
const WINDOWS_PATH_SEPARATOR = /\\/g;
|
|
15
34
|
/**
|
|
16
|
-
* Matches `*\/` in free-form text so JSDoc bodies can
|
|
35
|
+
* Matches `*\/` in free-form text so JSDoc bodies can neutralize premature
|
|
17
36
|
* comment terminators (`*\/` → `* /`).
|
|
18
37
|
*/
|
|
19
38
|
const JSDOC_TERMINATOR_PATTERN = /\*\//g;
|
|
20
39
|
/**
|
|
21
|
-
* Matches carriage returns for
|
|
40
|
+
* Matches carriage returns for normalizing CRLF/CR line endings to LF.
|
|
22
41
|
*/
|
|
23
42
|
const CARRIAGE_RETURN_PATTERN = /\r/g;
|
|
24
43
|
/**
|
|
25
|
-
* Matches CRLF sequences used when
|
|
44
|
+
* Matches CRLF sequences used when normalizing TypeScript printer output.
|
|
26
45
|
*/
|
|
27
46
|
const CRLF_PATTERN = /\r\n/g;
|
|
28
47
|
/**
|
|
29
|
-
* Matches an identifier that starts with a digit
|
|
30
|
-
* so the printer
|
|
48
|
+
* Matches an identifier that starts with a digit. JavaScript disallows this,
|
|
49
|
+
* so the printer replaces the leading digit with `_`.
|
|
31
50
|
*/
|
|
32
51
|
const LEADING_DIGIT_PATTERN = /^\d/;
|
|
33
52
|
//#endregion
|
|
34
|
-
//#region src/
|
|
53
|
+
//#region src/utils.ts
|
|
35
54
|
const { factory } = ts;
|
|
55
|
+
/**
|
|
56
|
+
* Normalizes a file-system path to POSIX separators and strips any leading `../` segment.
|
|
57
|
+
*/
|
|
36
58
|
function slash(path) {
|
|
37
59
|
return normalize(path).replaceAll(WINDOWS_PATH_SEPARATOR, "/").replace("../", "");
|
|
38
60
|
}
|
|
@@ -45,13 +67,6 @@ function getRelativePath(rootDir, filePath) {
|
|
|
45
67
|
return slashed.startsWith("../") ? slashed : `./${slashed}`;
|
|
46
68
|
}
|
|
47
69
|
/**
|
|
48
|
-
* Strips the trailing file extension (for example `.ts`) from a path.
|
|
49
|
-
* Preserves intermediate dots like `foo.bar.ts` → `foo.bar`.
|
|
50
|
-
*/
|
|
51
|
-
function trimExtName(text) {
|
|
52
|
-
return text.replace(FILE_EXTENSION_PATTERN, "");
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
70
|
* Rewrites an import/export path so its extension matches the caller-supplied
|
|
56
71
|
* `options.extname`. When the source path has no extension the original is kept,
|
|
57
72
|
* so virtual/module-only paths flow through unchanged.
|
|
@@ -62,57 +77,102 @@ function resolveOutputPath(path, options, rootAware) {
|
|
|
62
77
|
return rootAware ? trimExtName(path) : path;
|
|
63
78
|
}
|
|
64
79
|
/**
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
80
|
+
* Serializes a `nodes` array into source text. Each entry is rendered via {@link printCodeNode}
|
|
81
|
+
* and joined with a single newline. A `Break` node (`<br/>`) inserts one blank line between
|
|
82
|
+
* statements. Consecutive breaks, and breaks at the very start or end, are folded into the
|
|
83
|
+
* separator, so a double `<br/>` never emits more than one blank line.
|
|
68
84
|
*/
|
|
69
|
-
function
|
|
85
|
+
function printNodes(nodes) {
|
|
86
|
+
if (!nodes || nodes.length === 0) return "";
|
|
87
|
+
let result = "";
|
|
88
|
+
let hasContent = false;
|
|
89
|
+
let pendingBreak = false;
|
|
70
90
|
for (const node of nodes) {
|
|
71
|
-
if (
|
|
72
|
-
|
|
91
|
+
if (node.kind === "Break") {
|
|
92
|
+
if (hasContent) pendingBreak = true;
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
const text = printCodeNode(node);
|
|
96
|
+
if (!text) continue;
|
|
97
|
+
if (hasContent) result += pendingBreak ? "\n\n" : "\n";
|
|
98
|
+
result += text;
|
|
99
|
+
hasContent = true;
|
|
100
|
+
pendingBreak = false;
|
|
73
101
|
}
|
|
102
|
+
return result;
|
|
74
103
|
}
|
|
75
104
|
/**
|
|
76
|
-
*
|
|
105
|
+
* Indents every non-empty line of `text` by one indent unit. Pass a number to repeat
|
|
106
|
+
* {@link INDENT_CHAR} that many times, or a string to use as the indent verbatim.
|
|
77
107
|
*/
|
|
78
|
-
function
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
newLine: ts.NewLineKind.LineFeed,
|
|
83
|
-
removeComments: false,
|
|
84
|
-
noEmitHelpers: true
|
|
85
|
-
}).printList(ts.ListFormat.MultiLine, factory.createNodeArray(elements.filter(Boolean)), sourceFile).replace(CRLF_PATTERN, "\n");
|
|
108
|
+
function indentLines(text, indent = INDENT) {
|
|
109
|
+
if (!text) return "";
|
|
110
|
+
const pad = typeof indent === "string" ? indent : " ".repeat(indent);
|
|
111
|
+
return text.split("\n").map((line) => line.trim() ? `${pad}${line}` : "").join("\n");
|
|
86
112
|
}
|
|
87
113
|
/**
|
|
88
|
-
*
|
|
114
|
+
* Removes the common leading whitespace shared by every non-blank line and trims
|
|
115
|
+
* surrounding blank lines, so multi-line content authored inside an indented template
|
|
116
|
+
* literal lines up at a column-zero baseline. Leading whitespace is counted by
|
|
117
|
+
* character, so N tabs and N spaces are treated as the same depth.
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* ```ts
|
|
121
|
+
* dedent('\n foo\n bar\n ')
|
|
122
|
+
* // 'foo\n bar'
|
|
123
|
+
* ```
|
|
89
124
|
*/
|
|
90
|
-
function
|
|
91
|
-
|
|
92
|
-
|
|
125
|
+
function dedent(text) {
|
|
126
|
+
if (!text) return "";
|
|
127
|
+
const lines = text.split("\n");
|
|
128
|
+
const isBlank = (line) => line.trim() === "";
|
|
129
|
+
const start = lines.findIndex((line) => !isBlank(line));
|
|
130
|
+
if (start === -1) return "";
|
|
131
|
+
const end = lines.findLastIndex((line) => !isBlank(line));
|
|
132
|
+
const trimmed = lines.slice(start, end + 1);
|
|
133
|
+
const indents = trimmed.filter((line) => !isBlank(line)).map((line) => line.match(/^\s*/)?.[0].length ?? 0);
|
|
134
|
+
const min = indents.length ? Math.min(...indents) : 0;
|
|
135
|
+
return trimmed.map((line) => isBlank(line) ? "" : line.slice(min)).join("\n");
|
|
93
136
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
if (typeof item === "object") {
|
|
102
|
-
const { propertyName, name: alias } = item;
|
|
103
|
-
return factory.createImportSpecifier(false, alias ? factory.createIdentifier(propertyName) : void 0, factory.createIdentifier(alias ?? propertyName));
|
|
104
|
-
}
|
|
105
|
-
return factory.createImportSpecifier(false, void 0, factory.createIdentifier(item));
|
|
106
|
-
});
|
|
107
|
-
return factory.createImportDeclaration(void 0, factory.createImportClause(isTypeOnly, void 0, factory.createNamedImports(specifiers)), factory.createStringLiteral(resolvePath), void 0);
|
|
137
|
+
/**
|
|
138
|
+
* Renders the generic clause (`<T, U>`) shared by function and arrow-function nodes.
|
|
139
|
+
* Accepts either a raw string (rendered verbatim) or an array of type-parameter names.
|
|
140
|
+
*/
|
|
141
|
+
function formatGenerics(generics) {
|
|
142
|
+
if (!generics) return "";
|
|
143
|
+
return `<${Array.isArray(generics) ? generics.join(", ") : generics}>`;
|
|
108
144
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
return
|
|
145
|
+
/**
|
|
146
|
+
* Renders the return-type suffix (`: T` or `: Promise<T>` when `isAsync` is true).
|
|
147
|
+
* Returns an empty string when no return type is provided.
|
|
148
|
+
*/
|
|
149
|
+
function formatReturnType(returnType, isAsync) {
|
|
150
|
+
if (!returnType) return "";
|
|
151
|
+
return isAsync ? `: Promise<${returnType}>` : `: ${returnType}`;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Module-scoped TypeScript printer instance. A printer does not mutate the source file, so one
|
|
155
|
+
* instance is reused across every `print()` call instead of constructing a new printer each time.
|
|
156
|
+
*/
|
|
157
|
+
const TS_PRINTER = ts.createPrinter({
|
|
158
|
+
omitTrailingSemicolon: true,
|
|
159
|
+
newLine: ts.NewLineKind.LineFeed,
|
|
160
|
+
removeComments: false,
|
|
161
|
+
noEmitHelpers: true
|
|
162
|
+
});
|
|
163
|
+
/**
|
|
164
|
+
* Module-scoped source file used as the print target. `printList` only reads the source
|
|
165
|
+
* file's compiler options / language version. It never mutates it.
|
|
166
|
+
*/
|
|
167
|
+
const PRINT_SOURCE_FILE = ts.createSourceFile("print.tsx", "", ts.ScriptTarget.ES2022, true, ts.ScriptKind.TSX);
|
|
168
|
+
TS_PRINTER.printList(ts.ListFormat.MultiLine, factory.createNodeArray([]), PRINT_SOURCE_FILE);
|
|
169
|
+
/**
|
|
170
|
+
* Converts TypeScript/TSX AST nodes to a string using the TypeScript printer.
|
|
171
|
+
*/
|
|
172
|
+
function print(...elements) {
|
|
173
|
+
const filtered = elements.filter(Boolean);
|
|
174
|
+
if (filtered.length === 0) return "";
|
|
175
|
+
return TS_PRINTER.printList(ts.ListFormat.MultiLine, factory.createNodeArray(filtered), PRINT_SOURCE_FILE).replace(CRLF_PATTERN, "\n");
|
|
116
176
|
}
|
|
117
177
|
/**
|
|
118
178
|
* Converts a {@link JSDocNode} to a JSDoc comment block string.
|
|
@@ -138,54 +198,19 @@ function printJSDoc(jsDoc) {
|
|
|
138
198
|
].join("\n");
|
|
139
199
|
}
|
|
140
200
|
/**
|
|
141
|
-
* Serializes the body / value content from a `nodes` array.
|
|
142
|
-
*
|
|
143
|
-
* Each element is either a raw string or a structured {@link CodeNode}
|
|
144
|
-
* (recursively converted via {@link printCodeNode}).
|
|
145
|
-
* Elements are joined with `\n`.
|
|
146
|
-
*/
|
|
147
|
-
function printNodes(nodes) {
|
|
148
|
-
if (!nodes || nodes.length === 0) return "";
|
|
149
|
-
return nodes.map(printCodeNode).join("\n");
|
|
150
|
-
}
|
|
151
|
-
/**
|
|
152
|
-
* Indents every non-empty line of `text` by `spaces` spaces.
|
|
153
|
-
*/
|
|
154
|
-
function indentLines(text, spaces = 2) {
|
|
155
|
-
if (!text) return "";
|
|
156
|
-
const pad = " ".repeat(spaces);
|
|
157
|
-
return text.split("\n").map((line) => line.trim() ? `${pad}${line}` : "").join("\n");
|
|
158
|
-
}
|
|
159
|
-
/**
|
|
160
|
-
* Renders the generic clause (`<T, U>`) shared by function and arrow-function nodes.
|
|
161
|
-
* Accepts either a raw string (rendered verbatim) or an array of type-parameter names.
|
|
162
|
-
*/
|
|
163
|
-
function formatGenerics(generics) {
|
|
164
|
-
if (!generics) return "";
|
|
165
|
-
return `<${Array.isArray(generics) ? generics.join(", ") : generics}>`;
|
|
166
|
-
}
|
|
167
|
-
/**
|
|
168
|
-
* Renders the return-type suffix (`: T` or `: Promise<T>` when `isAsync` is true).
|
|
169
|
-
* Returns an empty string when no return type is provided.
|
|
170
|
-
*/
|
|
171
|
-
function formatReturnType(returnType, isAsync) {
|
|
172
|
-
if (!returnType) return "";
|
|
173
|
-
return isAsync ? `: Promise<${returnType}>` : `: ${returnType}`;
|
|
174
|
-
}
|
|
175
|
-
/**
|
|
176
201
|
* Converts a {@link ConstNode} to a TypeScript `const` declaration string.
|
|
177
202
|
*
|
|
178
203
|
* Mirrors the `Const` component from `@kubb/renderer-jsx`.
|
|
179
204
|
*
|
|
180
205
|
* @example
|
|
181
206
|
* ```ts
|
|
182
|
-
* printConst(createConst({ name: 'pet', export: true, nodes: ['{}'] }))
|
|
207
|
+
* printConst(factory.createConst({ name: 'pet', export: true, nodes: ['{}'] }))
|
|
183
208
|
* // 'export const pet = {}'
|
|
184
209
|
* ```
|
|
185
210
|
*
|
|
186
211
|
* @example With type and `as const`
|
|
187
212
|
* ```ts
|
|
188
|
-
* printConst(createConst({ name: 'pets', export: true, type: 'Pet[]', asConst: true, nodes: ['[]'] }))
|
|
213
|
+
* printConst(factory.createConst({ name: 'pets', export: true, type: 'Pet[]', asConst: true, nodes: ['[]'] }))
|
|
189
214
|
* // 'export const pets: Pet[] = [] as const'
|
|
190
215
|
* ```
|
|
191
216
|
*/
|
|
@@ -210,7 +235,7 @@ function printConst(node) {
|
|
|
210
235
|
*
|
|
211
236
|
* @example
|
|
212
237
|
* ```ts
|
|
213
|
-
* printType(createType({ name: 'Pet', export: true, nodes: ['{ id: number }'] }))
|
|
238
|
+
* printType(factory.createType({ name: 'Pet', export: true, nodes: ['{ id: number }'] }))
|
|
214
239
|
* // 'export type Pet = { id: number }'
|
|
215
240
|
* ```
|
|
216
241
|
*/
|
|
@@ -233,13 +258,13 @@ function printType(node) {
|
|
|
233
258
|
*
|
|
234
259
|
* @example
|
|
235
260
|
* ```ts
|
|
236
|
-
* printFunction(createFunction({ name: 'getPet', export: true, params: 'id: string', returnType: 'Pet', nodes: ['return fetch(id)'] }))
|
|
261
|
+
* printFunction(factory.createFunction({ name: 'getPet', export: true, params: 'id: string', returnType: 'Pet', nodes: ['return fetch(id)'] }))
|
|
237
262
|
* // 'export function getPet(id: string): Pet {\n return fetch(id)\n}'
|
|
238
263
|
* ```
|
|
239
264
|
*
|
|
240
265
|
* @example Async with generics
|
|
241
266
|
* ```ts
|
|
242
|
-
* printFunction(createFunction({ name: 'fetchPet', export: true, async: true, generics: ['T'], params: 'id: string', returnType: 'T' }))
|
|
267
|
+
* printFunction(factory.createFunction({ name: 'fetchPet', export: true, async: true, generics: ['T'], params: 'id: string', returnType: 'T' }))
|
|
243
268
|
* // 'export async function fetchPet<T>(id: string): Promise<T> {\n}'
|
|
244
269
|
* ```
|
|
245
270
|
*/
|
|
@@ -269,13 +294,13 @@ function printFunction(node) {
|
|
|
269
294
|
*
|
|
270
295
|
* @example Multi-line arrow function
|
|
271
296
|
* ```ts
|
|
272
|
-
* printArrowFunction(createArrowFunction({ name: 'getPet', export: true, params: 'id: string', nodes: ['return fetch(id)'] }))
|
|
297
|
+
* printArrowFunction(factory.createArrowFunction({ name: 'getPet', export: true, params: 'id: string', nodes: ['return fetch(id)'] }))
|
|
273
298
|
* // 'export const getPet = (id: string) => {\n return fetch(id)\n}'
|
|
274
299
|
* ```
|
|
275
300
|
*
|
|
276
301
|
* @example Single-line arrow function
|
|
277
302
|
* ```ts
|
|
278
|
-
* printArrowFunction(createArrowFunction({ name: 'double', params: 'n: number', singleLine: true, nodes: ['n * 2'] }))
|
|
303
|
+
* printArrowFunction(factory.createArrowFunction({ name: 'double', params: 'n: number', singleLine: true, nodes: ['n * 2'] }))
|
|
279
304
|
* // 'const double = (n: number) => n * 2'
|
|
280
305
|
* ```
|
|
281
306
|
*/
|
|
@@ -304,20 +329,19 @@ function printArrowFunction(node) {
|
|
|
304
329
|
*
|
|
305
330
|
* @example
|
|
306
331
|
* ```ts
|
|
307
|
-
* printCodeNode(createConst({ name: 'x', nodes: ['1'] }))
|
|
332
|
+
* printCodeNode(factory.createConst({ name: 'x', nodes: ['1'] }))
|
|
308
333
|
* // 'const x = 1'
|
|
309
334
|
* ```
|
|
310
335
|
*/
|
|
311
336
|
function printCodeNode(node) {
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
}
|
|
337
|
+
if (node.kind === "Break") return "";
|
|
338
|
+
if (node.kind === "Text") return dedent(node.value);
|
|
339
|
+
if (node.kind === "Jsx") return dedent(node.value);
|
|
340
|
+
if (node.kind === "Const") return printConst(node);
|
|
341
|
+
if (node.kind === "Type") return printType(node);
|
|
342
|
+
if (node.kind === "Function") return printFunction(node);
|
|
343
|
+
if (node.kind === "ArrowFunction") return printArrowFunction(node);
|
|
344
|
+
return "";
|
|
321
345
|
}
|
|
322
346
|
/**
|
|
323
347
|
* Converts a {@link SourceNode} to its TypeScript string representation.
|
|
@@ -325,52 +349,129 @@ function printCodeNode(node) {
|
|
|
325
349
|
* Iterates `nodes` in DOM order, rendering each {@link CodeNode} via
|
|
326
350
|
* {@link printCodeNode}.
|
|
327
351
|
*
|
|
352
|
+
* Top-level declarations are separated by a blank line so the source reads
|
|
353
|
+
* cleanly without an external formatter.
|
|
354
|
+
*
|
|
328
355
|
* @example From nodes
|
|
329
356
|
* ```ts
|
|
330
|
-
* printSource({ kind: 'Source', nodes: [createConst({ name: 'x', nodes: [createText('1')] }), createText('x.toString()')] })
|
|
331
|
-
* // 'const x = 1\nx.toString()'
|
|
357
|
+
* printSource({ kind: 'Source', nodes: [factory.createConst({ name: 'x', nodes: [factory.createText('1')] }), factory.createText('x.toString()')] })
|
|
358
|
+
* // 'const x = 1\n\nx.toString()'
|
|
332
359
|
* ```
|
|
333
360
|
*/
|
|
334
361
|
function printSource(node) {
|
|
335
|
-
|
|
336
|
-
return "";
|
|
362
|
+
const nodes = node.nodes;
|
|
363
|
+
if (!nodes || nodes.length === 0) return "";
|
|
364
|
+
return nodes.map((child) => printCodeNode(child)).filter(Boolean).join("\n\n");
|
|
337
365
|
}
|
|
338
366
|
/**
|
|
339
|
-
*
|
|
340
|
-
*
|
|
367
|
+
* Wraps a module specifier in single quotes, escaping any embedded backslash or quote so the emitted
|
|
368
|
+
* statement stays valid even for unusual paths.
|
|
369
|
+
*/
|
|
370
|
+
function quoteModulePath(path) {
|
|
371
|
+
return `'${path.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Renders an import declaration string in the repo style (single quotes, no semicolons), covering
|
|
375
|
+
* default, namespace (`* as`), and named imports with `{ a as b }` aliases, each optionally
|
|
376
|
+
* `type`-only. `path` is used verbatim, so resolve it first.
|
|
377
|
+
*
|
|
378
|
+
* @example
|
|
379
|
+
* ```ts
|
|
380
|
+
* printImport({ name: ['z'], path: './zod.ts' })
|
|
381
|
+
* // "import { z } from './zod.ts'"
|
|
382
|
+
* ```
|
|
383
|
+
*/
|
|
384
|
+
function printImport({ name, path, isTypeOnly = false, isNameSpace = false }) {
|
|
385
|
+
const typePrefix = isTypeOnly ? "type " : "";
|
|
386
|
+
const from = quoteModulePath(path);
|
|
387
|
+
if (!Array.isArray(name)) {
|
|
388
|
+
if (isNameSpace) return `import ${typePrefix}* as ${name} from ${from}`;
|
|
389
|
+
return `import ${typePrefix}${name} from ${from}`;
|
|
390
|
+
}
|
|
391
|
+
return `import ${typePrefix}{ ${name.map((item) => {
|
|
392
|
+
if (typeof item === "object") return item.name ? `${item.propertyName} as ${item.name}` : item.propertyName;
|
|
393
|
+
return item;
|
|
394
|
+
}).join(", ")} } from ${from}`;
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Renders an export declaration string in the repo style (single quotes, no semicolons), covering
|
|
398
|
+
* named re-exports, namespace alias (`* as name`), and wildcard, each optionally `type`-only.
|
|
399
|
+
* `path` is used verbatim, so resolve it first.
|
|
400
|
+
*
|
|
401
|
+
* @example
|
|
402
|
+
* ```ts
|
|
403
|
+
* printExport({ name: ['Pet', 'Order'], path: './models.ts' })
|
|
404
|
+
* // "export { Pet, Order } from './models.ts'"
|
|
405
|
+
* ```
|
|
406
|
+
*/
|
|
407
|
+
function printExport({ path, name, isTypeOnly = false, asAlias = false }) {
|
|
408
|
+
const typePrefix = isTypeOnly ? "type " : "";
|
|
409
|
+
const from = quoteModulePath(path);
|
|
410
|
+
if (Array.isArray(name)) return `export ${typePrefix}{ ${name.map((item) => typeof item === "string" ? item : item.text).join(", ")} } from ${from}`;
|
|
411
|
+
if (asAlias && name) return `export ${typePrefix}* as ${LEADING_DIGIT_PATTERN.test(name) ? `_${name.slice(1)}` : name} from ${from}`;
|
|
412
|
+
if (name) console.warn(`When using name as string, asAlias should be true: ${name}`);
|
|
413
|
+
return `export ${typePrefix}* from ${from}`;
|
|
414
|
+
}
|
|
415
|
+
//#endregion
|
|
416
|
+
//#region src/parserTs.ts
|
|
417
|
+
/**
|
|
418
|
+
* Default Kubb parser for `.ts` and `.js` files. Takes the universal AST
|
|
419
|
+
* produced by an adapter and prints it as TypeScript source using the official
|
|
420
|
+
* TypeScript compiler. Imports and exports are rewritten based on each file's
|
|
421
|
+
* metadata.
|
|
341
422
|
*
|
|
342
|
-
*
|
|
423
|
+
* Used automatically when no `parsers` option is set on `defineConfig`. Use
|
|
424
|
+
* `parserTsx` instead for React projects that emit JSX.
|
|
425
|
+
*
|
|
426
|
+
* @example
|
|
427
|
+
* ```ts
|
|
428
|
+
* import { defineConfig } from 'kubb'
|
|
429
|
+
* import { adapterOas } from '@kubb/adapter-oas'
|
|
430
|
+
* import { parserTs } from '@kubb/parser-ts'
|
|
431
|
+
*
|
|
432
|
+
* export default defineConfig({
|
|
433
|
+
* input: { path: './petStore.yaml' },
|
|
434
|
+
* output: { path: './src/gen' },
|
|
435
|
+
* adapter: adapterOas(),
|
|
436
|
+
* parsers: [parserTs],
|
|
437
|
+
* plugins: [],
|
|
438
|
+
* })
|
|
439
|
+
* ```
|
|
343
440
|
*/
|
|
344
441
|
const parserTs = defineParser({
|
|
345
442
|
name: "typescript",
|
|
346
443
|
extNames: [".ts", ".js"],
|
|
347
|
-
|
|
444
|
+
print(...nodes) {
|
|
445
|
+
return print(...nodes);
|
|
446
|
+
},
|
|
447
|
+
parse(file, options = { extname: ".ts" }) {
|
|
348
448
|
const sourceParts = [];
|
|
349
449
|
for (const item of file.sources) {
|
|
350
450
|
const sourceStr = printSource(item);
|
|
351
451
|
if (sourceStr) sourceParts.push(sourceStr.trimEnd());
|
|
352
452
|
}
|
|
353
453
|
const source = sourceParts.join("\n\n");
|
|
354
|
-
const
|
|
454
|
+
const importLines = [];
|
|
355
455
|
for (const item of file.imports) {
|
|
356
456
|
const importPath = item.root ? getRelativePath(item.root, item.path) : item.path;
|
|
357
|
-
|
|
457
|
+
importLines.push(printImport({
|
|
358
458
|
name: item.name,
|
|
359
459
|
path: resolveOutputPath(importPath, options, Boolean(item.root)),
|
|
360
460
|
isTypeOnly: item.isTypeOnly,
|
|
361
461
|
isNameSpace: item.isNameSpace
|
|
362
462
|
}));
|
|
363
463
|
}
|
|
364
|
-
const
|
|
365
|
-
for (const item of file.exports)
|
|
464
|
+
const exportLines = [];
|
|
465
|
+
for (const item of file.exports) exportLines.push(printExport({
|
|
366
466
|
name: item.name,
|
|
367
467
|
path: resolveOutputPath(item.path, options, true),
|
|
368
468
|
isTypeOnly: item.isTypeOnly,
|
|
369
469
|
asAlias: item.asAlias
|
|
370
470
|
}));
|
|
471
|
+
const importExportBlock = [...importLines, ...exportLines].join("\n");
|
|
371
472
|
return [
|
|
372
473
|
file.banner,
|
|
373
|
-
|
|
474
|
+
importExportBlock,
|
|
374
475
|
source,
|
|
375
476
|
file.footer
|
|
376
477
|
].filter((segment) => Boolean(segment)).map((s) => s.trimEnd()).join("\n\n");
|
|
@@ -379,22 +480,38 @@ const parserTs = defineParser({
|
|
|
379
480
|
//#endregion
|
|
380
481
|
//#region src/parserTsx.ts
|
|
381
482
|
/**
|
|
382
|
-
*
|
|
383
|
-
*
|
|
384
|
-
* supports JSX/TSX syntax via `ScriptKind.TSX`.
|
|
483
|
+
* Kubb parser for `.tsx` and `.jsx` files. Delegates to `parserTs` because the
|
|
484
|
+
* TypeScript compiler handles JSX natively via `ScriptKind.TSX`.
|
|
385
485
|
*
|
|
386
|
-
* Add
|
|
486
|
+
* Add to the `parsers` array on `defineConfig` when generating components for
|
|
487
|
+
* React (or any framework that emits JSX).
|
|
387
488
|
*
|
|
388
|
-
* @
|
|
489
|
+
* @example
|
|
490
|
+
* ```ts
|
|
491
|
+
* import { defineConfig } from 'kubb'
|
|
492
|
+
* import { adapterOas } from '@kubb/adapter-oas'
|
|
493
|
+
* import { parserTsx } from '@kubb/parser-ts'
|
|
494
|
+
*
|
|
495
|
+
* export default defineConfig({
|
|
496
|
+
* input: { path: './petStore.yaml' },
|
|
497
|
+
* output: { path: './src/gen' },
|
|
498
|
+
* adapter: adapterOas(),
|
|
499
|
+
* parsers: [parserTsx],
|
|
500
|
+
* plugins: [],
|
|
501
|
+
* })
|
|
502
|
+
* ```
|
|
389
503
|
*/
|
|
390
504
|
const parserTsx = defineParser({
|
|
391
505
|
name: "tsx",
|
|
392
506
|
extNames: [".tsx", ".jsx"],
|
|
393
|
-
|
|
507
|
+
print(...nodes) {
|
|
508
|
+
return print(...nodes);
|
|
509
|
+
},
|
|
510
|
+
parse(file, options = { extname: ".tsx" }) {
|
|
394
511
|
return parserTs.parse(file, options);
|
|
395
512
|
}
|
|
396
513
|
});
|
|
397
514
|
//#endregion
|
|
398
|
-
export {
|
|
515
|
+
export { parserTs, parserTsx };
|
|
399
516
|
|
|
400
517
|
//# sourceMappingURL=index.js.map
|