@kubb/renderer-jsx 5.0.0-beta.17 → 5.0.0-beta.18
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 +423 -176
- package/dist/index.d.ts +38 -10
- package/dist/index.js +423 -177
- package/dist/jsx-dev-runtime.d.ts +2 -2
- package/dist/{jsx-namespace-CNp0arTN.d.ts → jsx-namespace-BLGeMDcR.d.ts} +2 -2
- package/dist/jsx-runtime.d.ts +2 -2
- package/dist/{types-nAFMiWFw.d.ts → types-Dk7A1Y5U.d.ts} +2 -2
- package/dist/types.d.ts +1 -1
- package/package.json +2 -2
- package/src/Renderer.ts +1 -1
- package/src/Runtime.tsx +4 -4
- package/src/SyncRuntime.tsx +285 -0
- package/src/constants.ts +19 -9
- package/src/createRenderer.tsx +46 -5
- package/src/dom.ts +3 -13
- package/src/index.ts +1 -1
- package/src/types.ts +1 -1
- package/src/utils.ts +174 -206
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as __name } from "./chunk-Bb7HlUDG.js";
|
|
2
|
-
import { h as KubbReactNode, m as KubbReactElement } from "./types-
|
|
3
|
-
import { t as JSX } from "./jsx-namespace-
|
|
2
|
+
import { h as KubbReactNode, m as KubbReactElement } from "./types-Dk7A1Y5U.js";
|
|
3
|
+
import { t as JSX } from "./jsx-namespace-BLGeMDcR.js";
|
|
4
4
|
import * as _$react from "react";
|
|
5
5
|
import * as React$1 from "react/jsx-runtime";
|
|
6
6
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as __name } from "./chunk-Bb7HlUDG.js";
|
|
2
|
-
import { _ as KubbTextProps, c as KubbConstProps, d as KubbFunctionProps, f as KubbImportProps, g as KubbSourceProps, h as KubbReactNode, l as KubbExportProps, m as KubbReactElement, p as KubbJsxProps, s as KubbArrowFunctionProps, u as KubbFileProps, v as KubbTypeProps, y as LineBreakProps } from "./types-
|
|
2
|
+
import { _ as KubbTextProps, c as KubbConstProps, d as KubbFunctionProps, f as KubbImportProps, g as KubbSourceProps, h as KubbReactNode, l as KubbExportProps, m as KubbReactElement, p as KubbJsxProps, s as KubbArrowFunctionProps, u as KubbFileProps, v as KubbTypeProps, y as LineBreakProps } from "./types-Dk7A1Y5U.js";
|
|
3
3
|
import React from "react";
|
|
4
4
|
|
|
5
5
|
//#region src/jsx-namespace.d.ts
|
|
@@ -36,4 +36,4 @@ declare namespace JSX$1 {
|
|
|
36
36
|
}
|
|
37
37
|
//#endregion
|
|
38
38
|
export { JSX$1 as t };
|
|
39
|
-
//# sourceMappingURL=jsx-namespace-
|
|
39
|
+
//# sourceMappingURL=jsx-namespace-BLGeMDcR.d.ts.map
|
package/dist/jsx-runtime.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as __name } from "./chunk-Bb7HlUDG.js";
|
|
2
|
-
import { h as KubbReactNode, m as KubbReactElement } from "./types-
|
|
3
|
-
import { t as JSX } from "./jsx-namespace-
|
|
2
|
+
import { h as KubbReactNode, m as KubbReactElement } from "./types-Dk7A1Y5U.js";
|
|
3
|
+
import { t as JSX } from "./jsx-namespace-BLGeMDcR.js";
|
|
4
4
|
import * as _$react from "react";
|
|
5
5
|
import * as React$1 from "react/jsx-runtime";
|
|
6
6
|
|
|
@@ -46,7 +46,7 @@ type DOMElement = {
|
|
|
46
46
|
/**
|
|
47
47
|
* Key/value attributes passed as JSX props to this element.
|
|
48
48
|
*/
|
|
49
|
-
attributes:
|
|
49
|
+
attributes: Record<string, DOMNodeAttribute>;
|
|
50
50
|
/**
|
|
51
51
|
* Ordered list of child nodes attached to this element.
|
|
52
52
|
*/
|
|
@@ -165,4 +165,4 @@ type JSDoc = {
|
|
|
165
165
|
};
|
|
166
166
|
//#endregion
|
|
167
167
|
export { KubbTextProps as _, JSDoc as a, TextNode as b, KubbConstProps as c, KubbFunctionProps as d, KubbImportProps as f, KubbSourceProps as g, KubbReactNode as h, ElementNames as i, KubbExportProps as l, KubbReactElement as m, DOMNode as n, Key as o, KubbJsxProps as p, DOMNodeAttribute as r, KubbArrowFunctionProps as s, DOMElement as t, KubbFileProps as u, KubbTypeProps as v, LineBreakProps as y };
|
|
168
|
-
//# sourceMappingURL=types-
|
|
168
|
+
//# sourceMappingURL=types-Dk7A1Y5U.d.ts.map
|
package/dist/types.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { _ as KubbTextProps, a as JSDoc, b as TextNode, c as KubbConstProps, d as KubbFunctionProps, f as KubbImportProps, g as KubbSourceProps, h as KubbReactNode, i as ElementNames, l as KubbExportProps, m as KubbReactElement, n as DOMNode, o as Key, p as KubbJsxProps, r as DOMNodeAttribute, s as KubbArrowFunctionProps, t as DOMElement, u as KubbFileProps, v as KubbTypeProps, y as LineBreakProps } from "./types-
|
|
1
|
+
import { _ as KubbTextProps, a as JSDoc, b as TextNode, c as KubbConstProps, d as KubbFunctionProps, f as KubbImportProps, g as KubbSourceProps, h as KubbReactNode, i as ElementNames, l as KubbExportProps, m as KubbReactElement, n as DOMNode, o as Key, p as KubbJsxProps, r as DOMNodeAttribute, s as KubbArrowFunctionProps, t as DOMElement, u as KubbFileProps, v as KubbTypeProps, y as LineBreakProps } from "./types-Dk7A1Y5U.js";
|
|
2
2
|
export { DOMElement, DOMNode, DOMNodeAttribute, ElementNames, JSDoc, Key, KubbArrowFunctionProps, KubbConstProps, KubbExportProps, KubbFileProps, KubbFunctionProps, KubbImportProps, KubbJsxProps, KubbReactElement, KubbReactNode, KubbSourceProps, KubbTextProps, KubbTypeProps, LineBreakProps, TextNode };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kubb/renderer-jsx",
|
|
3
|
-
"version": "5.0.0-beta.
|
|
3
|
+
"version": "5.0.0-beta.18",
|
|
4
4
|
"description": "JSX-based renderer for Kubb. Provides a custom React runtime, reconciler, and built-in components (File, Function, Type, Const) for component-based, type-safe code generation.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"codegen",
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
"registry": "https://registry.npmjs.org/"
|
|
76
76
|
},
|
|
77
77
|
"dependencies": {
|
|
78
|
-
"@kubb/ast": "5.0.0-beta.
|
|
78
|
+
"@kubb/ast": "5.0.0-beta.18"
|
|
79
79
|
},
|
|
80
80
|
"devDependencies": {
|
|
81
81
|
"@types/react": "^19.2.14",
|
package/src/Renderer.ts
CHANGED
package/src/Runtime.tsx
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { onProcessExit } from '@internals/utils'
|
|
2
2
|
import type { FileNode } from '@kubb/ast'
|
|
3
|
-
import {
|
|
3
|
+
import { LegacyRoot } from 'react-reconciler/constants.js'
|
|
4
4
|
import { Root } from './components/Root.tsx'
|
|
5
5
|
import { createNode } from './dom.ts'
|
|
6
6
|
import type { FiberRoot } from 'react-reconciler'
|
|
7
7
|
import { Renderer } from './Renderer.ts'
|
|
8
8
|
import type { DOMElement, KubbReactElement } from './types.ts'
|
|
9
|
-
import {
|
|
9
|
+
import { collectFiles } from './utils.ts'
|
|
10
10
|
|
|
11
11
|
type Options = {
|
|
12
12
|
/**
|
|
@@ -51,7 +51,7 @@ export class Runtime {
|
|
|
51
51
|
|
|
52
52
|
const logRecoverableError = typeof reportError === 'function' ? reportError : console.error
|
|
53
53
|
|
|
54
|
-
const rootTag =
|
|
54
|
+
const rootTag = LegacyRoot
|
|
55
55
|
this.#container = Renderer.createContainer(
|
|
56
56
|
this.#rootNode,
|
|
57
57
|
rootTag,
|
|
@@ -86,7 +86,7 @@ export class Runtime {
|
|
|
86
86
|
return
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
const files =
|
|
89
|
+
const files = collectFiles(this.#rootNode)
|
|
90
90
|
|
|
91
91
|
this.nodes.push(...files)
|
|
92
92
|
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import type { ArrowFunctionNode, CodeNode, ExportNode, FileNode, ImportNode, JSDocNode, SourceNode } from '@kubb/ast'
|
|
2
|
+
import {
|
|
3
|
+
createArrowFunction,
|
|
4
|
+
createBreak,
|
|
5
|
+
createConst,
|
|
6
|
+
createExport,
|
|
7
|
+
createFunction,
|
|
8
|
+
createImport,
|
|
9
|
+
createJsx,
|
|
10
|
+
createSource,
|
|
11
|
+
createText,
|
|
12
|
+
createType,
|
|
13
|
+
} from '@kubb/ast'
|
|
14
|
+
import React from 'react'
|
|
15
|
+
import { KUBB_ARROW_FUNCTION, KUBB_CONST, KUBB_EXPORT, KUBB_FILE, KUBB_FUNCTION, KUBB_IMPORT, KUBB_JSX, KUBB_SOURCE, KUBB_TYPE } from './constants.ts'
|
|
16
|
+
import type { KubbReactElement } from './types.ts'
|
|
17
|
+
|
|
18
|
+
type OnText = (text: string) => void
|
|
19
|
+
type OnHost = (type: string, props: Record<string, unknown>) => void
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Walks `element`, resolving arrays, Fragments, and function components
|
|
23
|
+
* transparently, then calls `onText` for primitive values and `onHost` for
|
|
24
|
+
* every host element encountered. Pure function components are called
|
|
25
|
+
* synchronously; hooks and class components are not supported.
|
|
26
|
+
*/
|
|
27
|
+
function walkElement(element: unknown, onText: OnText, onHost: OnHost): void {
|
|
28
|
+
if (element == null || typeof element === 'boolean') return
|
|
29
|
+
|
|
30
|
+
if (typeof element === 'string' || typeof element === 'number' || typeof element === 'bigint') {
|
|
31
|
+
onText(String(element))
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (Array.isArray(element)) {
|
|
36
|
+
for (const child of element) walkElement(child, onText, onHost)
|
|
37
|
+
return
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (typeof element === 'object' && '$$typeof' in element) {
|
|
41
|
+
const el = element as unknown as React.ReactElement
|
|
42
|
+
const { type } = el
|
|
43
|
+
const props = el.props as Record<string, unknown>
|
|
44
|
+
|
|
45
|
+
if (type === React.Fragment) {
|
|
46
|
+
walkElement(props['children'], onText, onHost)
|
|
47
|
+
} else if (typeof type === 'function') {
|
|
48
|
+
walkElement((type as (p: unknown) => unknown)(props), onText, onHost)
|
|
49
|
+
} else if (typeof type === 'string') {
|
|
50
|
+
onHost(type, props)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function toBool(val: unknown): boolean {
|
|
56
|
+
return (val ?? false) as boolean
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function collectCodeNodes(props: Record<string, unknown>): CodeNode[] {
|
|
60
|
+
const nodes: CodeNode[] = []
|
|
61
|
+
collectCode(props['children'], nodes)
|
|
62
|
+
return nodes
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function collectCode(element: unknown, nodes: CodeNode[]): void {
|
|
66
|
+
walkElement(
|
|
67
|
+
element,
|
|
68
|
+
(text) => {
|
|
69
|
+
if (text.trim()) nodes.push(createText(text))
|
|
70
|
+
},
|
|
71
|
+
(type, props) => resolveCodeNode(type, props, nodes),
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function resolveCodeNode(type: string, props: Record<string, unknown>, nodes: CodeNode[]): void {
|
|
76
|
+
if (type === 'br') {
|
|
77
|
+
nodes.push(createBreak())
|
|
78
|
+
return
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (type === KUBB_JSX) {
|
|
82
|
+
let value = ''
|
|
83
|
+
walkElement(
|
|
84
|
+
props['children'],
|
|
85
|
+
(t) => {
|
|
86
|
+
value += t
|
|
87
|
+
},
|
|
88
|
+
() => {},
|
|
89
|
+
)
|
|
90
|
+
if (value) nodes.push(createJsx(value))
|
|
91
|
+
return
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (type === KUBB_FUNCTION) {
|
|
95
|
+
nodes.push(
|
|
96
|
+
createFunction({
|
|
97
|
+
name: props['name'] as string,
|
|
98
|
+
params: props['params'] as string | undefined,
|
|
99
|
+
export: props['export'] as boolean | undefined,
|
|
100
|
+
default: props['default'] as boolean | undefined,
|
|
101
|
+
async: props['async'] as boolean | undefined,
|
|
102
|
+
generics: props['generics'] as string | undefined,
|
|
103
|
+
returnType: props['returnType'] as string | undefined,
|
|
104
|
+
JSDoc: props['JSDoc'] as JSDocNode | undefined,
|
|
105
|
+
nodes: collectCodeNodes(props),
|
|
106
|
+
}),
|
|
107
|
+
)
|
|
108
|
+
return
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (type === KUBB_ARROW_FUNCTION) {
|
|
112
|
+
nodes.push(
|
|
113
|
+
createArrowFunction({
|
|
114
|
+
name: props['name'] as string,
|
|
115
|
+
params: props['params'] as string | undefined,
|
|
116
|
+
export: props['export'] as boolean | undefined,
|
|
117
|
+
default: props['default'] as boolean | undefined,
|
|
118
|
+
async: props['async'] as boolean | undefined,
|
|
119
|
+
generics: props['generics'] as string | undefined,
|
|
120
|
+
returnType: props['returnType'] as string | undefined,
|
|
121
|
+
singleLine: props['singleLine'] as boolean | undefined,
|
|
122
|
+
JSDoc: props['JSDoc'] as JSDocNode | undefined,
|
|
123
|
+
nodes: collectCodeNodes(props),
|
|
124
|
+
} as Omit<ArrowFunctionNode, 'kind'>),
|
|
125
|
+
)
|
|
126
|
+
return
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (type === KUBB_CONST) {
|
|
130
|
+
nodes.push(
|
|
131
|
+
createConst({
|
|
132
|
+
name: props['name'] as string,
|
|
133
|
+
type: props['type'] as string | undefined,
|
|
134
|
+
export: props['export'] as boolean | undefined,
|
|
135
|
+
asConst: props['asConst'] as boolean | undefined,
|
|
136
|
+
JSDoc: props['JSDoc'] as JSDocNode | undefined,
|
|
137
|
+
nodes: collectCodeNodes(props),
|
|
138
|
+
}),
|
|
139
|
+
)
|
|
140
|
+
return
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (type === KUBB_TYPE) {
|
|
144
|
+
nodes.push(
|
|
145
|
+
createType({
|
|
146
|
+
name: props['name'] as string,
|
|
147
|
+
export: props['export'] as boolean | undefined,
|
|
148
|
+
JSDoc: props['JSDoc'] as JSDocNode | undefined,
|
|
149
|
+
nodes: collectCodeNodes(props),
|
|
150
|
+
}),
|
|
151
|
+
)
|
|
152
|
+
return
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
type FileChildren = { sources: SourceNode[]; exports: ExportNode[]; imports: ImportNode[] }
|
|
157
|
+
|
|
158
|
+
function collectFileChildren(element: unknown): FileChildren {
|
|
159
|
+
const sources: SourceNode[] = []
|
|
160
|
+
const exports: ExportNode[] = []
|
|
161
|
+
const imports: ImportNode[] = []
|
|
162
|
+
|
|
163
|
+
walkElement(
|
|
164
|
+
element,
|
|
165
|
+
(text) => {
|
|
166
|
+
if (text.trim()) {
|
|
167
|
+
throw new Error(`[react] '${text}' should be part of <File.Source> component when using the <File/> component`)
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
(type, props) => {
|
|
171
|
+
if (type === KUBB_SOURCE) {
|
|
172
|
+
sources.push(
|
|
173
|
+
createSource({
|
|
174
|
+
name: props['name']?.toString(),
|
|
175
|
+
isTypeOnly: toBool(props['isTypeOnly']),
|
|
176
|
+
isExportable: toBool(props['isExportable']),
|
|
177
|
+
isIndexable: toBool(props['isIndexable']),
|
|
178
|
+
nodes: collectCodeNodes(props),
|
|
179
|
+
}),
|
|
180
|
+
)
|
|
181
|
+
return
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (type === KUBB_EXPORT) {
|
|
185
|
+
exports.push(
|
|
186
|
+
createExport({
|
|
187
|
+
name: props['name'] as ExportNode['name'],
|
|
188
|
+
path: props['path'] as string,
|
|
189
|
+
isTypeOnly: toBool(props['isTypeOnly']),
|
|
190
|
+
asAlias: toBool(props['asAlias']),
|
|
191
|
+
}),
|
|
192
|
+
)
|
|
193
|
+
return
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (type === KUBB_IMPORT) {
|
|
197
|
+
imports.push(
|
|
198
|
+
createImport({
|
|
199
|
+
name: props['name'] as ImportNode['name'],
|
|
200
|
+
path: props['path'] as string,
|
|
201
|
+
root: props['root'] as string | undefined,
|
|
202
|
+
isTypeOnly: toBool(props['isTypeOnly']),
|
|
203
|
+
isNameSpace: toBool(props['isNameSpace']),
|
|
204
|
+
}),
|
|
205
|
+
)
|
|
206
|
+
return
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const nested = collectFileChildren(props['children'])
|
|
210
|
+
sources.push(...nested.sources)
|
|
211
|
+
exports.push(...nested.exports)
|
|
212
|
+
imports.push(...nested.imports)
|
|
213
|
+
},
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
return { sources, exports, imports }
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function* walkFiles(element: unknown): Generator<FileNode> {
|
|
220
|
+
const files: FileNode[] = []
|
|
221
|
+
|
|
222
|
+
function onHost(type: string, props: Record<string, unknown>): void {
|
|
223
|
+
if (type === KUBB_FILE && props['baseName'] !== undefined && props['path'] !== undefined) {
|
|
224
|
+
const { sources, exports, imports } = collectFileChildren(props['children'])
|
|
225
|
+
files.push({
|
|
226
|
+
baseName: props['baseName'],
|
|
227
|
+
path: props['path'],
|
|
228
|
+
meta: props['meta'] || {},
|
|
229
|
+
footer: props['footer'],
|
|
230
|
+
banner: props['banner'],
|
|
231
|
+
sources,
|
|
232
|
+
exports,
|
|
233
|
+
imports,
|
|
234
|
+
} as FileNode)
|
|
235
|
+
} else {
|
|
236
|
+
walkElement(props['children'], () => {}, onHost)
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
walkElement(element, () => {}, onHost)
|
|
241
|
+
yield* files
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Synchronous JSX renderer that walks the element tree in a single pass,
|
|
246
|
+
* producing {@link FileNode} objects directly without an intermediate virtual
|
|
247
|
+
* DOM. No React fiber, scheduler, or work loop is involved.
|
|
248
|
+
*
|
|
249
|
+
* All components must be pure functions; hooks and class components are not
|
|
250
|
+
* supported. Produces identical output to the React-backed {@link Runtime} at
|
|
251
|
+
* approximately 2–4× the speed and a fraction of the allocations.
|
|
252
|
+
*/
|
|
253
|
+
export class SyncRuntime {
|
|
254
|
+
/**
|
|
255
|
+
* Accumulated {@link FileNode} results from every {@link render} call.
|
|
256
|
+
*/
|
|
257
|
+
nodes: FileNode[] = []
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Walks `element` synchronously, converts every `<kubb-file>` subtree into
|
|
261
|
+
* a {@link FileNode} with no intermediate virtual DOM, and appends the results
|
|
262
|
+
* to {@link nodes}.
|
|
263
|
+
*/
|
|
264
|
+
render(element: KubbReactElement): void {
|
|
265
|
+
for (const file of walkFiles(element)) {
|
|
266
|
+
this.nodes.push(file)
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Walks `element` synchronously and yields each {@link FileNode} as it is
|
|
272
|
+
* produced, without buffering into an intermediate array first. Callers can
|
|
273
|
+
* begin processing each file before the rest of the element tree is traversed.
|
|
274
|
+
*
|
|
275
|
+
* @example
|
|
276
|
+
* ```ts
|
|
277
|
+
* for (const file of runtime.stream(element)) {
|
|
278
|
+
* await writeFile(file)
|
|
279
|
+
* }
|
|
280
|
+
* ```
|
|
281
|
+
*/
|
|
282
|
+
*stream(element: KubbReactElement): Generator<FileNode> {
|
|
283
|
+
yield* walkFiles(element)
|
|
284
|
+
}
|
|
285
|
+
}
|
package/src/constants.ts
CHANGED
|
@@ -5,20 +5,30 @@ import type { ElementNames } from './types.ts'
|
|
|
5
5
|
*/
|
|
6
6
|
export const TEXT_NODE_NAME = '#text' as const
|
|
7
7
|
|
|
8
|
+
export const KUBB_FILE = 'kubb-file' as const
|
|
9
|
+
export const KUBB_SOURCE = 'kubb-source' as const
|
|
10
|
+
export const KUBB_EXPORT = 'kubb-export' as const
|
|
11
|
+
export const KUBB_IMPORT = 'kubb-import' as const
|
|
12
|
+
export const KUBB_FUNCTION = 'kubb-function' as const
|
|
13
|
+
export const KUBB_ARROW_FUNCTION = 'kubb-arrow-function' as const
|
|
14
|
+
export const KUBB_CONST = 'kubb-const' as const
|
|
15
|
+
export const KUBB_TYPE = 'kubb-type' as const
|
|
16
|
+
export const KUBB_JSX = 'kubb-jsx' as const
|
|
17
|
+
|
|
8
18
|
/**
|
|
9
19
|
* Set of all element names recognized by the Kubb renderer.
|
|
10
20
|
* Used to distinguish Kubb-owned elements from unrecognized or text nodes during tree traversal.
|
|
11
21
|
*/
|
|
12
22
|
export const nodeNames = new Set<ElementNames>([
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
23
|
+
KUBB_EXPORT,
|
|
24
|
+
KUBB_FILE,
|
|
25
|
+
KUBB_SOURCE,
|
|
26
|
+
KUBB_IMPORT,
|
|
27
|
+
KUBB_FUNCTION,
|
|
28
|
+
KUBB_ARROW_FUNCTION,
|
|
29
|
+
KUBB_CONST,
|
|
30
|
+
KUBB_TYPE,
|
|
31
|
+
KUBB_JSX,
|
|
22
32
|
'kubb-text',
|
|
23
33
|
'kubb-root',
|
|
24
34
|
'kubb-app',
|
package/src/createRenderer.tsx
CHANGED
|
@@ -1,20 +1,19 @@
|
|
|
1
|
+
import type { FileNode } from '@kubb/ast'
|
|
1
2
|
import { Runtime } from './Runtime.tsx'
|
|
3
|
+
import { SyncRuntime } from './SyncRuntime.tsx'
|
|
2
4
|
import type { KubbReactElement } from './types.ts'
|
|
3
5
|
|
|
4
6
|
/**
|
|
5
|
-
*
|
|
7
|
+
* Renderer factory for generators that produce JSX output.
|
|
6
8
|
*
|
|
7
|
-
* Pass
|
|
8
|
-
* core can render the JSX element tree returned by your generator methods
|
|
9
|
+
* Pass as the `renderer` property of `defineGenerator`. Core drives rendering
|
|
9
10
|
* without a hard dependency on `@kubb/renderer-jsx`.
|
|
10
11
|
*
|
|
11
12
|
* @example
|
|
12
13
|
* ```ts
|
|
13
14
|
* import { jsxRenderer } from '@kubb/renderer-jsx'
|
|
14
|
-
* import { defineGenerator } from '@kubb/core'
|
|
15
15
|
*
|
|
16
16
|
* export const myGenerator = defineGenerator<PluginTs>({
|
|
17
|
-
* name: 'my-generator',
|
|
18
17
|
* renderer: jsxRenderer,
|
|
19
18
|
* schema(node, options) {
|
|
20
19
|
* return <File baseName="output.ts" path="src/output.ts">...</File>
|
|
@@ -36,3 +35,45 @@ export const jsxRenderer = () => {
|
|
|
36
35
|
},
|
|
37
36
|
}
|
|
38
37
|
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Lightweight renderer factory with no React fiber, scheduler, or work loop.
|
|
41
|
+
*
|
|
42
|
+
* Walks the JSX element tree in a single recursive pass. All components must be
|
|
43
|
+
* pure functions; hooks and class components are not supported. Drop-in
|
|
44
|
+
* replacement for {@link jsxRenderer} at approximately 2–4× the speed.
|
|
45
|
+
*
|
|
46
|
+
* @example Drop-in replacement
|
|
47
|
+
* ```ts
|
|
48
|
+
* import { jsxRendererSync } from '@kubb/renderer-jsx'
|
|
49
|
+
*
|
|
50
|
+
* export const myGenerator = defineGenerator<PluginTs>({
|
|
51
|
+
* renderer: jsxRendererSync,
|
|
52
|
+
* schema(node, options) {
|
|
53
|
+
* return <File baseName="output.ts" path="src/output.ts">...</File>
|
|
54
|
+
* },
|
|
55
|
+
* })
|
|
56
|
+
* ```
|
|
57
|
+
*
|
|
58
|
+
* @example Stream files as they are produced
|
|
59
|
+
* ```ts
|
|
60
|
+
* for await (const file of jsxRendererSync().stream(element)) {
|
|
61
|
+
* await writeFile(file)
|
|
62
|
+
* }
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export const jsxRendererSync = () => {
|
|
66
|
+
const runtime = new SyncRuntime()
|
|
67
|
+
return {
|
|
68
|
+
async render(element: KubbReactElement): Promise<void> {
|
|
69
|
+
runtime.render(element)
|
|
70
|
+
},
|
|
71
|
+
get files() {
|
|
72
|
+
return runtime.nodes
|
|
73
|
+
},
|
|
74
|
+
async *stream(element: KubbReactElement): AsyncGenerator<FileNode> {
|
|
75
|
+
yield* runtime.stream(element)
|
|
76
|
+
},
|
|
77
|
+
unmount(_error?: Error | number | null) {},
|
|
78
|
+
}
|
|
79
|
+
}
|
package/src/dom.ts
CHANGED
|
@@ -8,7 +8,7 @@ import type { DOMElement, DOMNode, DOMNodeAttribute, TextNode } from './types.ts
|
|
|
8
8
|
export const createNode = (nodeName: string): DOMElement => {
|
|
9
9
|
return {
|
|
10
10
|
nodeName: nodeName as DOMElement['nodeName'],
|
|
11
|
-
attributes:
|
|
11
|
+
attributes: Object.create(null) as Record<string, DOMNodeAttribute>,
|
|
12
12
|
childNodes: [],
|
|
13
13
|
parentNode: undefined,
|
|
14
14
|
}
|
|
@@ -48,7 +48,6 @@ export const insertBeforeNode = (node: DOMElement, newChildNode: DOMNode, before
|
|
|
48
48
|
const index = node.childNodes.indexOf(beforeChildNode)
|
|
49
49
|
if (index >= 0) {
|
|
50
50
|
node.childNodes.splice(index, 0, newChildNode)
|
|
51
|
-
|
|
52
51
|
return
|
|
53
52
|
}
|
|
54
53
|
|
|
@@ -72,32 +71,23 @@ export const removeChildNode = (node: DOMElement, removeNode: DOMNode): void =>
|
|
|
72
71
|
* Set an attribute on `node`, storing it in the node's `attributes` map.
|
|
73
72
|
*/
|
|
74
73
|
export const setAttribute = (node: DOMElement, key: string, value: DOMNodeAttribute): void => {
|
|
75
|
-
node.attributes
|
|
74
|
+
node.attributes[key] = value
|
|
76
75
|
}
|
|
77
76
|
|
|
78
77
|
/**
|
|
79
78
|
* Create a new {@link TextNode} with the given text value.
|
|
80
79
|
*/
|
|
81
80
|
export const createTextNode = (text: string): TextNode => {
|
|
82
|
-
|
|
81
|
+
return {
|
|
83
82
|
nodeName: TEXT_NODE_NAME,
|
|
84
83
|
nodeValue: text,
|
|
85
84
|
parentNode: undefined,
|
|
86
85
|
}
|
|
87
|
-
|
|
88
|
-
setTextNodeValue(node, text)
|
|
89
|
-
|
|
90
|
-
return node
|
|
91
86
|
}
|
|
92
87
|
|
|
93
88
|
/**
|
|
94
89
|
* Update the `nodeValue` of an existing {@link TextNode}.
|
|
95
|
-
* Non-string values are coerced to strings via `String(text)`.
|
|
96
90
|
*/
|
|
97
91
|
export const setTextNodeValue = (node: TextNode, text: string): void => {
|
|
98
|
-
if (typeof text !== 'string') {
|
|
99
|
-
text = String(text)
|
|
100
|
-
}
|
|
101
|
-
|
|
102
92
|
node.nodeValue = text
|
|
103
93
|
}
|
package/src/index.ts
CHANGED
|
@@ -5,4 +5,4 @@ export { Function } from './components/Function.tsx'
|
|
|
5
5
|
export { Jsx } from './components/Jsx.tsx'
|
|
6
6
|
export { Root } from './components/Root.tsx'
|
|
7
7
|
export { Type } from './components/Type.tsx'
|
|
8
|
-
export { jsxRenderer } from './createRenderer.tsx'
|
|
8
|
+
export { jsxRenderer, jsxRendererSync } from './createRenderer.tsx'
|
package/src/types.ts
CHANGED
|
@@ -71,7 +71,7 @@ export type DOMElement = {
|
|
|
71
71
|
/**
|
|
72
72
|
* Key/value attributes passed as JSX props to this element.
|
|
73
73
|
*/
|
|
74
|
-
attributes:
|
|
74
|
+
attributes: Record<string, DOMNodeAttribute>
|
|
75
75
|
/**
|
|
76
76
|
* Ordered list of child nodes attached to this element.
|
|
77
77
|
*/
|