@kubb/parser-ts 5.0.0-beta.5 → 5.0.0-beta.50
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 +111 -0
- package/dist/index.cjs +219 -114
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +60 -55
- package/dist/index.js +221 -111
- package/dist/index.js.map +1 -1
- package/extension.yaml +14 -13
- package/package.json +6 -6
- package/src/constants.ts +15 -5
- package/src/index.ts +1 -1
- package/src/parserTs.ts +35 -468
- package/src/parserTsx.ts +25 -8
- package/src/utils.ts +592 -0
- /package/dist/{chunk--u3MIqq1.js → chunk-C0LytTxp.js} +0 -0
package/LICENSE
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
This repository contains software under two licenses:
|
|
1
|
+
MIT License
|
|
4
2
|
|
|
5
|
-
|
|
6
|
-
MIT License — see licenses/LICENSE-MIT for the full license text.
|
|
3
|
+
Copyright (c) 2026 Stijn Van Hulle
|
|
7
4
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<a href="https://kubb.dev" target="_blank" rel="noopener noreferrer">
|
|
3
|
+
<img src="https://kubb.dev/og.png" alt="Kubb banner">
|
|
4
|
+
</a>
|
|
5
|
+
|
|
6
|
+
[![npm version][npm-version-src]][npm-version-href]
|
|
7
|
+
[![npm downloads][npm-downloads-src]][npm-downloads-href]
|
|
8
|
+
[![Stars][stars-src]][stars-href]
|
|
9
|
+
[![License][license-src]][license-href]
|
|
10
|
+
[![Node][node-src]][node-href]
|
|
11
|
+
|
|
12
|
+
<h4>
|
|
13
|
+
<a href="https://kubb.dev" target="_blank">Documentation</a>
|
|
14
|
+
<span> · </span>
|
|
15
|
+
<a href="https://github.com/kubb-labs/kubb/issues/" target="_blank">Report Bug</a>
|
|
16
|
+
<span> · </span>
|
|
17
|
+
<a href="https://github.com/kubb-labs/kubb/issues/" target="_blank">Request Feature</a>
|
|
18
|
+
</h4>
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
<br />
|
|
22
|
+
|
|
23
|
+
# @kubb/parser-ts
|
|
24
|
+
|
|
25
|
+
### TypeScript source file parser for Kubb
|
|
26
|
+
|
|
27
|
+
Converts AST nodes and raw TypeScript code into formatted source strings using the TypeScript compiler API. Handles both `.ts` and `.tsx` output.
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
bun add @kubb/parser-ts
|
|
33
|
+
# or
|
|
34
|
+
pnpm add @kubb/parser-ts
|
|
35
|
+
# or
|
|
36
|
+
npm install @kubb/parser-ts
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Usage
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
import { defineConfig } from 'kubb'
|
|
43
|
+
import { parserTs, parserTsx } from '@kubb/parser-ts'
|
|
44
|
+
|
|
45
|
+
export default defineConfig({
|
|
46
|
+
input: { path: './petstore.yaml' },
|
|
47
|
+
output: { path: './src/gen' },
|
|
48
|
+
parsers: [parserTs, parserTsx],
|
|
49
|
+
})
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
To render compiler AST nodes to source text from inside a plugin, call `print` on the parser instance:
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
import { parserTs } from '@kubb/parser-ts'
|
|
56
|
+
import ts from 'typescript'
|
|
57
|
+
|
|
58
|
+
const source = parserTs.print(
|
|
59
|
+
ts.factory.createVariableStatement(
|
|
60
|
+
[ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
61
|
+
ts.factory.createVariableDeclarationList(
|
|
62
|
+
[ts.factory.createVariableDeclaration('hello', undefined, undefined, ts.factory.createStringLiteral('world'))],
|
|
63
|
+
ts.NodeFlags.Const,
|
|
64
|
+
),
|
|
65
|
+
),
|
|
66
|
+
)
|
|
67
|
+
// → export const hello = 'world'
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## API
|
|
71
|
+
|
|
72
|
+
### `parserTs`
|
|
73
|
+
|
|
74
|
+
Parser instance for `.ts` and `.js` files. Pass to `defineConfig({ parsers: [...] })` to emit TypeScript source files.
|
|
75
|
+
|
|
76
|
+
- `parserTs.parse(file, options?)` — serialize a `FileNode` to TypeScript source.
|
|
77
|
+
- `parserTs.print(...nodes)` — convert TypeScript compiler `Node` instances to a formatted source string.
|
|
78
|
+
|
|
79
|
+
### `parserTsx`
|
|
80
|
+
|
|
81
|
+
Parser instance for `.tsx` and `.jsx` files. Same API as `parserTs` with JSX support.
|
|
82
|
+
|
|
83
|
+
## Supporting Kubb
|
|
84
|
+
|
|
85
|
+
Kubb is an open source project, and its development is funded entirely by sponsors. If you would like to become a sponsor, please consider:
|
|
86
|
+
|
|
87
|
+
- [Become a Sponsor on GitHub](https://github.com/sponsors/stijnvanhulle)
|
|
88
|
+
- [See sponsorship tiers and our sponsors](https://kubb.dev/sponsors)
|
|
89
|
+
|
|
90
|
+
<p align="center">
|
|
91
|
+
<a href="https://github.com/sponsors/stijnvanhulle">
|
|
92
|
+
<img src="https://raw.githubusercontent.com/stijnvanhulle/sponsors/main/sponsors.svg" alt="My sponsors" />
|
|
93
|
+
</a>
|
|
94
|
+
</p>
|
|
95
|
+
|
|
96
|
+
## License
|
|
97
|
+
|
|
98
|
+
[MIT](https://github.com/kubb-labs/kubb/blob/main/licenses/LICENSE-MIT)
|
|
99
|
+
|
|
100
|
+
<!-- Badges -->
|
|
101
|
+
|
|
102
|
+
[npm-version-src]: https://shieldcn.dev/npm/v/@kubb/parser-ts.svg?variant=secondary&size=xs&theme=zinc&mode=dark
|
|
103
|
+
[npm-version-href]: https://npmx.dev/package/@kubb/parser-ts
|
|
104
|
+
[npm-downloads-src]: https://shieldcn.dev/npm/dm/@kubb/parser-ts.svg?variant=secondary&size=xs&theme=zinc&mode=dark
|
|
105
|
+
[npm-downloads-href]: https://npmx.dev/package/@kubb/parser-ts
|
|
106
|
+
[stars-src]: https://shieldcn.dev/github/stars/kubb-labs/kubb.svg?variant=secondary&size=xs&theme=zinc&mode=dark
|
|
107
|
+
[stars-href]: https://github.com/kubb-labs/kubb
|
|
108
|
+
[license-src]: https://shieldcn.dev/npm/license/@kubb/parser-ts.svg?variant=secondary&size=xs&theme=zinc
|
|
109
|
+
[license-href]: https://github.com/kubb-labs/kubb/blob/main/LICENSE
|
|
110
|
+
[node-src]: https://shieldcn.dev/npm/node/@kubb/parser-ts.svg?variant=secondary&size=xs&theme=zinc&mode=dark
|
|
111
|
+
[node-href]: https://npmx.dev/package/@kubb/parser-ts
|
package/dist/index.cjs
CHANGED
|
@@ -21,11 +21,14 @@ 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
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Indentation unit prepended once per nesting level when pretty-printing.
|
|
30
|
+
*/
|
|
31
|
+
const INDENT = " ".repeat(2);
|
|
29
32
|
/**
|
|
30
33
|
* Matches the trailing `.<ext>` segment of a path (keeps segments like `foo.bar.ts`
|
|
31
34
|
* intact by only trimming the last run of non-`/`/`.` characters).
|
|
@@ -36,26 +39,29 @@ const FILE_EXTENSION_PATTERN = /\.[^/.]+$/;
|
|
|
36
39
|
*/
|
|
37
40
|
const WINDOWS_PATH_SEPARATOR = /\\/g;
|
|
38
41
|
/**
|
|
39
|
-
* Matches `*\/` in free-form text so JSDoc bodies can
|
|
42
|
+
* Matches `*\/` in free-form text so JSDoc bodies can neutralize premature
|
|
40
43
|
* comment terminators (`*\/` → `* /`).
|
|
41
44
|
*/
|
|
42
45
|
const JSDOC_TERMINATOR_PATTERN = /\*\//g;
|
|
43
46
|
/**
|
|
44
|
-
* Matches carriage returns for
|
|
47
|
+
* Matches carriage returns for normalizing CRLF/CR line endings to LF.
|
|
45
48
|
*/
|
|
46
49
|
const CARRIAGE_RETURN_PATTERN = /\r/g;
|
|
47
50
|
/**
|
|
48
|
-
* Matches CRLF sequences used when
|
|
51
|
+
* Matches CRLF sequences used when normalizing TypeScript printer output.
|
|
49
52
|
*/
|
|
50
53
|
const CRLF_PATTERN = /\r\n/g;
|
|
51
54
|
/**
|
|
52
|
-
* Matches an identifier that starts with a digit
|
|
55
|
+
* Matches an identifier that starts with a digit. JavaScript disallows this,
|
|
53
56
|
* so the printer prefixes such names with `_`.
|
|
54
57
|
*/
|
|
55
58
|
const LEADING_DIGIT_PATTERN = /^\d/;
|
|
56
59
|
//#endregion
|
|
57
|
-
//#region src/
|
|
60
|
+
//#region src/utils.ts
|
|
58
61
|
const { factory } = typescript.default;
|
|
62
|
+
/**
|
|
63
|
+
* Normalizes a file-system path to POSIX separators and strips any leading `../` segment.
|
|
64
|
+
*/
|
|
59
65
|
function slash(path) {
|
|
60
66
|
return (0, node_path.normalize)(path).replaceAll(WINDOWS_PATH_SEPARATOR, "/").replace("../", "");
|
|
61
67
|
}
|
|
@@ -85,57 +91,104 @@ function resolveOutputPath(path, options, rootAware) {
|
|
|
85
91
|
return rootAware ? trimExtName(path) : path;
|
|
86
92
|
}
|
|
87
93
|
/**
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
94
|
+
* Serializes a `nodes` array into source text. Each entry is rendered via {@link printCodeNode}
|
|
95
|
+
* and joined with a single newline; a `Break` node (`<br/>`) inserts one blank line between
|
|
96
|
+
* statements. Consecutive breaks, and breaks at the very start or end, are folded into the
|
|
97
|
+
* separator, so a double `<br/>` never emits more than one blank line.
|
|
91
98
|
*/
|
|
92
|
-
function
|
|
99
|
+
function printNodes(nodes) {
|
|
100
|
+
if (!nodes || nodes.length === 0) return "";
|
|
101
|
+
let result = "";
|
|
102
|
+
let hasContent = false;
|
|
103
|
+
let pendingBreak = false;
|
|
93
104
|
for (const node of nodes) {
|
|
94
|
-
if (
|
|
95
|
-
|
|
105
|
+
if (node.kind === "Break") {
|
|
106
|
+
if (hasContent) pendingBreak = true;
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
const text = printCodeNode(node);
|
|
110
|
+
if (!text) continue;
|
|
111
|
+
if (hasContent) result += pendingBreak ? "\n\n" : "\n";
|
|
112
|
+
result += text;
|
|
113
|
+
hasContent = true;
|
|
114
|
+
pendingBreak = false;
|
|
96
115
|
}
|
|
116
|
+
return result;
|
|
97
117
|
}
|
|
98
118
|
/**
|
|
99
|
-
*
|
|
119
|
+
* Indents every non-empty line of `text` by one indent unit. Pass a number to repeat
|
|
120
|
+
* {@link INDENT_CHAR} that many times, or a string to use as the indent verbatim.
|
|
100
121
|
*/
|
|
101
|
-
function
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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");
|
|
122
|
+
function indentLines(text, indent = INDENT) {
|
|
123
|
+
if (!text) return "";
|
|
124
|
+
const pad = typeof indent === "string" ? indent : " ".repeat(indent);
|
|
125
|
+
return text.split("\n").map((line) => line.trim() ? `${pad}${line}` : "").join("\n");
|
|
109
126
|
}
|
|
110
127
|
/**
|
|
111
|
-
*
|
|
128
|
+
* Removes the common leading whitespace shared by every non-blank line and trims
|
|
129
|
+
* surrounding blank lines, normalizing multi-line content authored inside an
|
|
130
|
+
* indented template literal back to a column-zero baseline. Leading whitespace is
|
|
131
|
+
* counted by character, so N tabs and N spaces are treated as the same depth.
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* ```ts
|
|
135
|
+
* dedent('\n foo\n bar\n ')
|
|
136
|
+
* // 'foo\n bar'
|
|
137
|
+
* ```
|
|
112
138
|
*/
|
|
113
|
-
function
|
|
114
|
-
|
|
115
|
-
|
|
139
|
+
function dedent(text) {
|
|
140
|
+
if (!text) return "";
|
|
141
|
+
const lines = text.split("\n");
|
|
142
|
+
const isBlank = (line) => line.trim() === "";
|
|
143
|
+
const start = lines.findIndex((line) => !isBlank(line));
|
|
144
|
+
if (start === -1) return "";
|
|
145
|
+
const end = lines.findLastIndex((line) => !isBlank(line));
|
|
146
|
+
const trimmed = lines.slice(start, end + 1);
|
|
147
|
+
const indents = trimmed.filter((line) => !isBlank(line)).map((line) => line.match(/^\s*/)?.[0].length ?? 0);
|
|
148
|
+
const min = indents.length ? Math.min(...indents) : 0;
|
|
149
|
+
return trimmed.map((line) => isBlank(line) ? "" : line.slice(min)).join("\n");
|
|
116
150
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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);
|
|
151
|
+
/**
|
|
152
|
+
* Renders the generic clause (`<T, U>`) shared by function and arrow-function nodes.
|
|
153
|
+
* Accepts either a raw string (rendered verbatim) or an array of type-parameter names.
|
|
154
|
+
*/
|
|
155
|
+
function formatGenerics(generics) {
|
|
156
|
+
if (!generics) return "";
|
|
157
|
+
return `<${Array.isArray(generics) ? generics.join(", ") : generics}>`;
|
|
131
158
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
return
|
|
159
|
+
/**
|
|
160
|
+
* Renders the return-type suffix (`: T` or `: Promise<T>` when `isAsync` is true).
|
|
161
|
+
* Returns an empty string when no return type is provided.
|
|
162
|
+
*/
|
|
163
|
+
function formatReturnType(returnType, isAsync) {
|
|
164
|
+
if (!returnType) return "";
|
|
165
|
+
return isAsync ? `: Promise<${returnType}>` : `: ${returnType}`;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Module-scoped TypeScript printer instance. `ts.createPrinter()` is stateless across calls
|
|
169
|
+
* (it does not mutate the source file) so a single instance can be safely reused for every
|
|
170
|
+
* `print()` call. Hoisting it out of `print()` avoids re-running the printer initialization
|
|
171
|
+
* for each file's import/export section.
|
|
172
|
+
*/
|
|
173
|
+
const TS_PRINTER = typescript.default.createPrinter({
|
|
174
|
+
omitTrailingSemicolon: true,
|
|
175
|
+
newLine: typescript.default.NewLineKind.LineFeed,
|
|
176
|
+
removeComments: false,
|
|
177
|
+
noEmitHelpers: true
|
|
178
|
+
});
|
|
179
|
+
/**
|
|
180
|
+
* Module-scoped source file used as the print target. `printList` only reads the source
|
|
181
|
+
* file's compiler options / language version. It never mutates it.
|
|
182
|
+
*/
|
|
183
|
+
const PRINT_SOURCE_FILE = typescript.default.createSourceFile("print.tsx", "", typescript.default.ScriptTarget.ES2022, true, typescript.default.ScriptKind.TSX);
|
|
184
|
+
TS_PRINTER.printList(typescript.default.ListFormat.MultiLine, factory.createNodeArray([]), PRINT_SOURCE_FILE);
|
|
185
|
+
/**
|
|
186
|
+
* Converts TypeScript/TSX AST nodes to a string using the TypeScript printer.
|
|
187
|
+
*/
|
|
188
|
+
function print(...elements) {
|
|
189
|
+
const filtered = elements.filter(Boolean);
|
|
190
|
+
if (filtered.length === 0) return "";
|
|
191
|
+
return TS_PRINTER.printList(typescript.default.ListFormat.MultiLine, factory.createNodeArray(filtered), PRINT_SOURCE_FILE).replace(CRLF_PATTERN, "\n");
|
|
139
192
|
}
|
|
140
193
|
/**
|
|
141
194
|
* Converts a {@link JSDocNode} to a JSDoc comment block string.
|
|
@@ -161,41 +214,6 @@ function printJSDoc(jsDoc) {
|
|
|
161
214
|
].join("\n");
|
|
162
215
|
}
|
|
163
216
|
/**
|
|
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
217
|
* Converts a {@link ConstNode} to a TypeScript `const` declaration string.
|
|
200
218
|
*
|
|
201
219
|
* Mirrors the `Const` component from `@kubb/renderer-jsx`.
|
|
@@ -332,15 +350,14 @@ function printArrowFunction(node) {
|
|
|
332
350
|
* ```
|
|
333
351
|
*/
|
|
334
352
|
function printCodeNode(node) {
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
}
|
|
353
|
+
if (node.kind === "Break") return "";
|
|
354
|
+
if (node.kind === "Text") return dedent(node.value);
|
|
355
|
+
if (node.kind === "Jsx") return dedent(node.value);
|
|
356
|
+
if (node.kind === "Const") return printConst(node);
|
|
357
|
+
if (node.kind === "Type") return printType(node);
|
|
358
|
+
if (node.kind === "Function") return printFunction(node);
|
|
359
|
+
if (node.kind === "ArrowFunction") return printArrowFunction(node);
|
|
360
|
+
return "";
|
|
344
361
|
}
|
|
345
362
|
/**
|
|
346
363
|
* Converts a {@link SourceNode} to its TypeScript string representation.
|
|
@@ -348,52 +365,129 @@ function printCodeNode(node) {
|
|
|
348
365
|
* Iterates `nodes` in DOM order, rendering each {@link CodeNode} via
|
|
349
366
|
* {@link printCodeNode}.
|
|
350
367
|
*
|
|
368
|
+
* Top-level declarations are separated by a blank line so the source reads
|
|
369
|
+
* cleanly without an external formatter.
|
|
370
|
+
*
|
|
351
371
|
* @example From nodes
|
|
352
372
|
* ```ts
|
|
353
373
|
* printSource({ kind: 'Source', nodes: [createConst({ name: 'x', nodes: [createText('1')] }), createText('x.toString()')] })
|
|
354
|
-
* // 'const x = 1\nx.toString()'
|
|
374
|
+
* // 'const x = 1\n\nx.toString()'
|
|
355
375
|
* ```
|
|
356
376
|
*/
|
|
357
377
|
function printSource(node) {
|
|
358
|
-
|
|
359
|
-
return "";
|
|
378
|
+
const nodes = node.nodes;
|
|
379
|
+
if (!nodes || nodes.length === 0) return "";
|
|
380
|
+
return nodes.map((child) => printCodeNode(child)).filter(Boolean).join("\n\n");
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* Wraps a module specifier in single quotes, escaping any embedded backslash or quote so the emitted
|
|
384
|
+
* statement stays valid even for unusual paths.
|
|
385
|
+
*/
|
|
386
|
+
function quoteModulePath(path) {
|
|
387
|
+
return `'${path.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
|
|
360
388
|
}
|
|
361
389
|
/**
|
|
362
|
-
*
|
|
363
|
-
*
|
|
390
|
+
* Renders an import declaration string in the repo style (single quotes, no semicolons), mirroring
|
|
391
|
+
* the shapes that {@link createImport} builds: default, namespace (`* as`), and named imports with
|
|
392
|
+
* `{ a as b }` aliases, each optionally `type`-only. `path` is used verbatim, so resolve it first.
|
|
364
393
|
*
|
|
365
|
-
* @
|
|
394
|
+
* @example
|
|
395
|
+
* ```ts
|
|
396
|
+
* printImport({ name: ['z'], path: './zod.ts' })
|
|
397
|
+
* // "import { z } from './zod.ts'"
|
|
398
|
+
* ```
|
|
399
|
+
*/
|
|
400
|
+
function printImport({ name, path, isTypeOnly = false, isNameSpace = false }) {
|
|
401
|
+
const typePrefix = isTypeOnly ? "type " : "";
|
|
402
|
+
const from = quoteModulePath(path);
|
|
403
|
+
if (!Array.isArray(name)) {
|
|
404
|
+
if (isNameSpace) return `import ${typePrefix}* as ${name} from ${from}`;
|
|
405
|
+
return `import ${typePrefix}${name} from ${from}`;
|
|
406
|
+
}
|
|
407
|
+
return `import ${typePrefix}{ ${name.map((item) => {
|
|
408
|
+
if (typeof item === "object") return item.name ? `${item.propertyName} as ${item.name}` : item.propertyName;
|
|
409
|
+
return item;
|
|
410
|
+
}).join(", ")} } from ${from}`;
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Renders an export declaration string in the repo style (single quotes, no semicolons), mirroring
|
|
414
|
+
* the shapes that {@link createExport} builds: named re-exports, namespace alias (`* as name`), and
|
|
415
|
+
* wildcard, each optionally `type`-only. `path` is used verbatim, so resolve it first.
|
|
416
|
+
*
|
|
417
|
+
* @example
|
|
418
|
+
* ```ts
|
|
419
|
+
* printExport({ name: ['Pet', 'Order'], path: './models.ts' })
|
|
420
|
+
* // "export { Pet, Order } from './models.ts'"
|
|
421
|
+
* ```
|
|
422
|
+
*/
|
|
423
|
+
function printExport({ path, name, isTypeOnly = false, asAlias = false }) {
|
|
424
|
+
const typePrefix = isTypeOnly ? "type " : "";
|
|
425
|
+
const from = quoteModulePath(path);
|
|
426
|
+
if (Array.isArray(name)) return `export ${typePrefix}{ ${name.map((item) => typeof item === "string" ? item : item.text).join(", ")} } from ${from}`;
|
|
427
|
+
if (asAlias && name) return `export ${typePrefix}* as ${LEADING_DIGIT_PATTERN.test(name) ? `_${name.slice(1)}` : name} from ${from}`;
|
|
428
|
+
if (name) console.warn(`When using name as string, asAlias should be true: ${name}`);
|
|
429
|
+
return `export ${typePrefix}* from ${from}`;
|
|
430
|
+
}
|
|
431
|
+
//#endregion
|
|
432
|
+
//#region src/parserTs.ts
|
|
433
|
+
/**
|
|
434
|
+
* Default Kubb parser for `.ts` and `.js` files. Takes the universal AST
|
|
435
|
+
* produced by an adapter and prints it as TypeScript source using the official
|
|
436
|
+
* TypeScript compiler. Imports and exports are rewritten based on each file's
|
|
437
|
+
* metadata.
|
|
438
|
+
*
|
|
439
|
+
* Used automatically when no `parsers` option is set on `defineConfig`. Use
|
|
440
|
+
* `parserTsx` instead for React projects that emit JSX.
|
|
441
|
+
*
|
|
442
|
+
* @example
|
|
443
|
+
* ```ts
|
|
444
|
+
* import { defineConfig } from 'kubb'
|
|
445
|
+
* import { adapterOas } from '@kubb/adapter-oas'
|
|
446
|
+
* import { parserTs } from '@kubb/parser-ts'
|
|
447
|
+
*
|
|
448
|
+
* export default defineConfig({
|
|
449
|
+
* input: { path: './petStore.yaml' },
|
|
450
|
+
* output: { path: './src/gen' },
|
|
451
|
+
* adapter: adapterOas(),
|
|
452
|
+
* parsers: [parserTs],
|
|
453
|
+
* plugins: [],
|
|
454
|
+
* })
|
|
455
|
+
* ```
|
|
366
456
|
*/
|
|
367
457
|
const parserTs = (0, _kubb_core.defineParser)({
|
|
368
458
|
name: "typescript",
|
|
369
459
|
extNames: [".ts", ".js"],
|
|
370
|
-
|
|
460
|
+
print(...nodes) {
|
|
461
|
+
return print(...nodes);
|
|
462
|
+
},
|
|
463
|
+
parse(file, options = { extname: ".ts" }) {
|
|
371
464
|
const sourceParts = [];
|
|
372
465
|
for (const item of file.sources) {
|
|
373
466
|
const sourceStr = printSource(item);
|
|
374
467
|
if (sourceStr) sourceParts.push(sourceStr.trimEnd());
|
|
375
468
|
}
|
|
376
469
|
const source = sourceParts.join("\n\n");
|
|
377
|
-
const
|
|
470
|
+
const importLines = [];
|
|
378
471
|
for (const item of file.imports) {
|
|
379
472
|
const importPath = item.root ? getRelativePath(item.root, item.path) : item.path;
|
|
380
|
-
|
|
473
|
+
importLines.push(printImport({
|
|
381
474
|
name: item.name,
|
|
382
475
|
path: resolveOutputPath(importPath, options, Boolean(item.root)),
|
|
383
476
|
isTypeOnly: item.isTypeOnly,
|
|
384
477
|
isNameSpace: item.isNameSpace
|
|
385
478
|
}));
|
|
386
479
|
}
|
|
387
|
-
const
|
|
388
|
-
for (const item of file.exports)
|
|
480
|
+
const exportLines = [];
|
|
481
|
+
for (const item of file.exports) exportLines.push(printExport({
|
|
389
482
|
name: item.name,
|
|
390
483
|
path: resolveOutputPath(item.path, options, true),
|
|
391
484
|
isTypeOnly: item.isTypeOnly,
|
|
392
485
|
asAlias: item.asAlias
|
|
393
486
|
}));
|
|
487
|
+
const importExportBlock = [...importLines, ...exportLines].join("\n");
|
|
394
488
|
return [
|
|
395
489
|
file.banner,
|
|
396
|
-
|
|
490
|
+
importExportBlock,
|
|
397
491
|
source,
|
|
398
492
|
file.footer
|
|
399
493
|
].filter((segment) => Boolean(segment)).map((s) => s.trimEnd()).join("\n\n");
|
|
@@ -402,28 +496,39 @@ const parserTs = (0, _kubb_core.defineParser)({
|
|
|
402
496
|
//#endregion
|
|
403
497
|
//#region src/parserTsx.ts
|
|
404
498
|
/**
|
|
405
|
-
*
|
|
406
|
-
*
|
|
407
|
-
*
|
|
499
|
+
* Kubb parser for `.tsx` and `.jsx` files. Delegates to `parserTs` because the
|
|
500
|
+
* TypeScript compiler handles JSX natively via `ScriptKind.TSX`.
|
|
501
|
+
*
|
|
502
|
+
* Add to the `parsers` array on `defineConfig` when generating components for
|
|
503
|
+
* React (or any framework that emits JSX).
|
|
408
504
|
*
|
|
409
|
-
*
|
|
505
|
+
* @example
|
|
506
|
+
* ```ts
|
|
507
|
+
* import { defineConfig } from 'kubb'
|
|
508
|
+
* import { adapterOas } from '@kubb/adapter-oas'
|
|
509
|
+
* import { parserTsx } from '@kubb/parser-ts'
|
|
410
510
|
*
|
|
411
|
-
*
|
|
511
|
+
* export default defineConfig({
|
|
512
|
+
* input: { path: './petStore.yaml' },
|
|
513
|
+
* output: { path: './src/gen' },
|
|
514
|
+
* adapter: adapterOas(),
|
|
515
|
+
* parsers: [parserTsx],
|
|
516
|
+
* plugins: [],
|
|
517
|
+
* })
|
|
518
|
+
* ```
|
|
412
519
|
*/
|
|
413
520
|
const parserTsx = (0, _kubb_core.defineParser)({
|
|
414
521
|
name: "tsx",
|
|
415
522
|
extNames: [".tsx", ".jsx"],
|
|
416
|
-
|
|
523
|
+
print(...nodes) {
|
|
524
|
+
return print(...nodes);
|
|
525
|
+
},
|
|
526
|
+
parse(file, options = { extname: ".tsx" }) {
|
|
417
527
|
return parserTs.parse(file, options);
|
|
418
528
|
}
|
|
419
529
|
});
|
|
420
530
|
//#endregion
|
|
421
|
-
exports.createExport = createExport;
|
|
422
|
-
exports.createImport = createImport;
|
|
423
531
|
exports.parserTs = parserTs;
|
|
424
532
|
exports.parserTsx = parserTsx;
|
|
425
|
-
exports.print = print;
|
|
426
|
-
exports.safePrint = safePrint;
|
|
427
|
-
exports.validateNodes = validateNodes;
|
|
428
533
|
|
|
429
534
|
//# sourceMappingURL=index.cjs.map
|