@kubb/parser-ts 5.0.0-beta.6 → 5.0.0-beta.61

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