@kubb/renderer-jsx 5.0.0-beta.2 → 5.0.0-beta.20
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/README.md +124 -0
- package/dist/index.cjs +416 -179
- package/dist/index.d.ts +39 -56
- package/dist/index.js +416 -179
- 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 +3 -9
- package/src/Renderer.ts +1 -5
- package/src/Runtime.tsx +6 -17
- package/src/SyncRuntime.tsx +309 -0
- package/src/constants.ts +19 -9
- package/src/createRenderer.tsx +47 -60
- package/src/dom.ts +4 -16
- package/src/index.ts +1 -1
- package/src/types.ts +1 -1
- package/src/utils.ts +154 -175
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/jsx-dev-runtime.cjs.map +0 -1
- package/dist/jsx-dev-runtime.js.map +0 -1
- package/dist/jsx-runtime-Cvu_ZYgL.js.map +0 -1
- package/dist/jsx-runtime-DdmO3p0U.cjs.map +0 -1
- package/dist/jsx-runtime.cjs.map +0 -1
- package/dist/jsx-runtime.js.map +0 -1
|
@@ -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,19 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kubb/renderer-jsx",
|
|
3
|
-
"version": "5.0.0-beta.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "5.0.0-beta.20",
|
|
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
|
-
"code-generator",
|
|
7
6
|
"codegen",
|
|
8
|
-
"component-generation",
|
|
9
|
-
"file-generation",
|
|
10
7
|
"jsx",
|
|
11
8
|
"jsx-runtime",
|
|
12
9
|
"kubb",
|
|
13
|
-
"plugin-system",
|
|
14
|
-
"plugins",
|
|
15
10
|
"react",
|
|
16
|
-
"react-reconciler",
|
|
17
11
|
"typescript"
|
|
18
12
|
],
|
|
19
13
|
"license": "MIT",
|
|
@@ -81,7 +75,7 @@
|
|
|
81
75
|
"registry": "https://registry.npmjs.org/"
|
|
82
76
|
},
|
|
83
77
|
"dependencies": {
|
|
84
|
-
"@kubb/ast": "5.0.0-beta.
|
|
78
|
+
"@kubb/ast": "5.0.0-beta.20"
|
|
85
79
|
},
|
|
86
80
|
"devDependencies": {
|
|
87
81
|
"@types/react": "^19.2.14",
|
package/src/Renderer.ts
CHANGED
|
@@ -105,7 +105,7 @@ export const Renderer = Reconciler({
|
|
|
105
105
|
return false
|
|
106
106
|
},
|
|
107
107
|
supportsMutation: true,
|
|
108
|
-
isPrimaryRenderer:
|
|
108
|
+
isPrimaryRenderer: false,
|
|
109
109
|
supportsPersistence: false,
|
|
110
110
|
supportsHydration: false,
|
|
111
111
|
scheduleTimeout: setTimeout,
|
|
@@ -155,9 +155,7 @@ export const Renderer = Reconciler({
|
|
|
155
155
|
maySuspendCommit() {
|
|
156
156
|
return false
|
|
157
157
|
},
|
|
158
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
159
158
|
NotPendingTransition: undefined,
|
|
160
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
161
159
|
HostTransitionContext: createContext(null) as unknown as ReactContext<unknown>,
|
|
162
160
|
resetFormInstance() {},
|
|
163
161
|
requestPostPaintCallback() {},
|
|
@@ -180,5 +178,3 @@ export const Renderer = Reconciler({
|
|
|
180
178
|
return null
|
|
181
179
|
},
|
|
182
180
|
})
|
|
183
|
-
|
|
184
|
-
export type { FiberRoot } from 'react-reconciler'
|
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
|
-
import type { FiberRoot } from '
|
|
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
|
/**
|
|
@@ -26,7 +26,7 @@ export class Runtime {
|
|
|
26
26
|
readonly #container: FiberRoot
|
|
27
27
|
readonly #rootNode: DOMElement
|
|
28
28
|
|
|
29
|
-
constructor(options: Options) {
|
|
29
|
+
constructor(options: Options = {}) {
|
|
30
30
|
this.#options = options
|
|
31
31
|
this.#rootNode = createNode('kubb-root')
|
|
32
32
|
this.#rootNode.onRender = this.onRender
|
|
@@ -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
|
|
|
@@ -156,15 +156,4 @@ export class Runtime {
|
|
|
156
156
|
|
|
157
157
|
this.resolveExitPromise()
|
|
158
158
|
}
|
|
159
|
-
|
|
160
|
-
async waitUntilExit(): Promise<void> {
|
|
161
|
-
if (!this.exitPromise) {
|
|
162
|
-
this.exitPromise = new Promise((resolve, reject) => {
|
|
163
|
-
this.resolveExitPromise = resolve
|
|
164
|
-
this.rejectExitPromise = reject
|
|
165
|
-
})
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
return this.exitPromise
|
|
169
|
-
}
|
|
170
159
|
}
|
|
@@ -0,0 +1,309 @@
|
|
|
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
|
+
return
|
|
48
|
+
}
|
|
49
|
+
if (typeof type === 'function') {
|
|
50
|
+
walkElement((type as (p: unknown) => unknown)(props), onText, onHost)
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
if (typeof type === 'string') {
|
|
54
|
+
onHost(type, props)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function toBool(val: unknown): boolean {
|
|
60
|
+
return (val ?? false) as boolean
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function collectCodeNodes(props: Record<string, unknown>): CodeNode[] {
|
|
64
|
+
const nodes: CodeNode[] = []
|
|
65
|
+
collectCode(props['children'], nodes)
|
|
66
|
+
return nodes
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function collectCode(element: unknown, nodes: CodeNode[]): void {
|
|
70
|
+
walkElement(
|
|
71
|
+
element,
|
|
72
|
+
(text) => {
|
|
73
|
+
if (text.trim()) nodes.push(createText(text))
|
|
74
|
+
},
|
|
75
|
+
(type, props) => resolveCodeNode(type, props, nodes),
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function resolveCodeNode(type: string, props: Record<string, unknown>, nodes: CodeNode[]): void {
|
|
80
|
+
if (type === 'br') {
|
|
81
|
+
nodes.push(createBreak())
|
|
82
|
+
return
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (type === KUBB_JSX) {
|
|
86
|
+
let value = ''
|
|
87
|
+
walkElement(
|
|
88
|
+
props['children'],
|
|
89
|
+
(t) => {
|
|
90
|
+
value += t
|
|
91
|
+
},
|
|
92
|
+
() => {},
|
|
93
|
+
)
|
|
94
|
+
if (value) nodes.push(createJsx(value))
|
|
95
|
+
return
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (type === KUBB_FUNCTION) {
|
|
99
|
+
nodes.push(
|
|
100
|
+
createFunction({
|
|
101
|
+
name: props['name'] as string,
|
|
102
|
+
params: props['params'] as string | undefined,
|
|
103
|
+
export: props['export'] as boolean | undefined,
|
|
104
|
+
default: props['default'] as boolean | undefined,
|
|
105
|
+
async: props['async'] as boolean | undefined,
|
|
106
|
+
generics: props['generics'] as string | undefined,
|
|
107
|
+
returnType: props['returnType'] as string | undefined,
|
|
108
|
+
JSDoc: props['JSDoc'] as JSDocNode | undefined,
|
|
109
|
+
nodes: collectCodeNodes(props),
|
|
110
|
+
}),
|
|
111
|
+
)
|
|
112
|
+
return
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (type === KUBB_ARROW_FUNCTION) {
|
|
116
|
+
nodes.push(
|
|
117
|
+
createArrowFunction({
|
|
118
|
+
name: props['name'] as string,
|
|
119
|
+
params: props['params'] as string | undefined,
|
|
120
|
+
export: props['export'] as boolean | undefined,
|
|
121
|
+
default: props['default'] as boolean | undefined,
|
|
122
|
+
async: props['async'] as boolean | undefined,
|
|
123
|
+
generics: props['generics'] as string | undefined,
|
|
124
|
+
returnType: props['returnType'] as string | undefined,
|
|
125
|
+
singleLine: props['singleLine'] as boolean | undefined,
|
|
126
|
+
JSDoc: props['JSDoc'] as JSDocNode | undefined,
|
|
127
|
+
nodes: collectCodeNodes(props),
|
|
128
|
+
} as Omit<ArrowFunctionNode, 'kind'>),
|
|
129
|
+
)
|
|
130
|
+
return
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (type === KUBB_CONST) {
|
|
134
|
+
nodes.push(
|
|
135
|
+
createConst({
|
|
136
|
+
name: props['name'] as string,
|
|
137
|
+
type: props['type'] as string | undefined,
|
|
138
|
+
export: props['export'] as boolean | undefined,
|
|
139
|
+
asConst: props['asConst'] as boolean | undefined,
|
|
140
|
+
JSDoc: props['JSDoc'] as JSDocNode | undefined,
|
|
141
|
+
nodes: collectCodeNodes(props),
|
|
142
|
+
}),
|
|
143
|
+
)
|
|
144
|
+
return
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (type === KUBB_TYPE) {
|
|
148
|
+
nodes.push(
|
|
149
|
+
createType({
|
|
150
|
+
name: props['name'] as string,
|
|
151
|
+
export: props['export'] as boolean | undefined,
|
|
152
|
+
JSDoc: props['JSDoc'] as JSDocNode | undefined,
|
|
153
|
+
nodes: collectCodeNodes(props),
|
|
154
|
+
}),
|
|
155
|
+
)
|
|
156
|
+
return
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
type FileChildren = { sources: SourceNode[]; exports: ExportNode[]; imports: ImportNode[] }
|
|
161
|
+
|
|
162
|
+
function collectFileChildren(element: unknown): FileChildren {
|
|
163
|
+
const sources: SourceNode[] = []
|
|
164
|
+
const exports: ExportNode[] = []
|
|
165
|
+
const imports: ImportNode[] = []
|
|
166
|
+
|
|
167
|
+
walkElement(
|
|
168
|
+
element,
|
|
169
|
+
(text) => {
|
|
170
|
+
if (text.trim()) {
|
|
171
|
+
throw new Error(`[react] '${text}' should be part of <File.Source> component when using the <File/> component`)
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
(type, props) => {
|
|
175
|
+
if (type === KUBB_SOURCE) {
|
|
176
|
+
sources.push(
|
|
177
|
+
createSource({
|
|
178
|
+
name: props['name']?.toString(),
|
|
179
|
+
isTypeOnly: toBool(props['isTypeOnly']),
|
|
180
|
+
isExportable: toBool(props['isExportable']),
|
|
181
|
+
isIndexable: toBool(props['isIndexable']),
|
|
182
|
+
nodes: collectCodeNodes(props),
|
|
183
|
+
}),
|
|
184
|
+
)
|
|
185
|
+
return
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (type === KUBB_EXPORT) {
|
|
189
|
+
exports.push(
|
|
190
|
+
createExport({
|
|
191
|
+
name: props['name'] as ExportNode['name'],
|
|
192
|
+
path: props['path'] as string,
|
|
193
|
+
isTypeOnly: toBool(props['isTypeOnly']),
|
|
194
|
+
asAlias: toBool(props['asAlias']),
|
|
195
|
+
}),
|
|
196
|
+
)
|
|
197
|
+
return
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (type === KUBB_IMPORT) {
|
|
201
|
+
imports.push(
|
|
202
|
+
createImport({
|
|
203
|
+
name: props['name'] as ImportNode['name'],
|
|
204
|
+
path: props['path'] as string,
|
|
205
|
+
root: props['root'] as string | undefined,
|
|
206
|
+
isTypeOnly: toBool(props['isTypeOnly']),
|
|
207
|
+
isNameSpace: toBool(props['isNameSpace']),
|
|
208
|
+
}),
|
|
209
|
+
)
|
|
210
|
+
return
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const nested = collectFileChildren(props['children'])
|
|
214
|
+
sources.push(...nested.sources)
|
|
215
|
+
exports.push(...nested.exports)
|
|
216
|
+
imports.push(...nested.imports)
|
|
217
|
+
},
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
return { sources, exports, imports }
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function* walkFiles(element: unknown): Generator<FileNode> {
|
|
224
|
+
if (element == null || typeof element === 'boolean') return
|
|
225
|
+
|
|
226
|
+
if (typeof element === 'string' || typeof element === 'number' || typeof element === 'bigint') return
|
|
227
|
+
|
|
228
|
+
if (Array.isArray(element)) {
|
|
229
|
+
for (const child of element) yield* walkFiles(child)
|
|
230
|
+
return
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (typeof element === 'object' && '$$typeof' in element) {
|
|
234
|
+
const el = element as unknown as React.ReactElement
|
|
235
|
+
const { type } = el
|
|
236
|
+
const props = el.props as Record<string, unknown>
|
|
237
|
+
|
|
238
|
+
if (type === React.Fragment) {
|
|
239
|
+
yield* walkFiles(props['children'])
|
|
240
|
+
return
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (typeof type === 'function') {
|
|
244
|
+
yield* walkFiles((type as (p: unknown) => unknown)(props))
|
|
245
|
+
return
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (typeof type === 'string') {
|
|
249
|
+
if (type === KUBB_FILE && props['baseName'] !== undefined && props['path'] !== undefined) {
|
|
250
|
+
const { sources, exports, imports } = collectFileChildren(props['children'])
|
|
251
|
+
yield {
|
|
252
|
+
baseName: props['baseName'],
|
|
253
|
+
path: props['path'],
|
|
254
|
+
meta: props['meta'] || {},
|
|
255
|
+
footer: props['footer'],
|
|
256
|
+
banner: props['banner'],
|
|
257
|
+
sources,
|
|
258
|
+
exports,
|
|
259
|
+
imports,
|
|
260
|
+
} as FileNode
|
|
261
|
+
} else {
|
|
262
|
+
yield* walkFiles(props['children'])
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Synchronous JSX renderer that walks the element tree in a single pass,
|
|
270
|
+
* producing {@link FileNode} objects directly without an intermediate virtual
|
|
271
|
+
* DOM. No React fiber, scheduler, or work loop is involved.
|
|
272
|
+
*
|
|
273
|
+
* All components must be pure functions; hooks and class components are not
|
|
274
|
+
* supported. Produces identical output to the React-backed {@link Runtime} at
|
|
275
|
+
* approximately 2–4× the speed and a fraction of the allocations.
|
|
276
|
+
*/
|
|
277
|
+
export class SyncRuntime {
|
|
278
|
+
/**
|
|
279
|
+
* Accumulated {@link FileNode} results from every {@link render} call.
|
|
280
|
+
*/
|
|
281
|
+
nodes: FileNode[] = []
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Walks `element` synchronously, converts every `<kubb-file>` subtree into
|
|
285
|
+
* a {@link FileNode} with no intermediate virtual DOM, and appends the results
|
|
286
|
+
* to {@link nodes}.
|
|
287
|
+
*/
|
|
288
|
+
render(element: KubbReactElement): void {
|
|
289
|
+
for (const file of walkFiles(element)) {
|
|
290
|
+
this.nodes.push(file)
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Walks `element` synchronously and yields each {@link FileNode} as it is
|
|
296
|
+
* produced, without buffering into an intermediate array first. Callers can
|
|
297
|
+
* begin processing each file before the rest of the element tree is traversed.
|
|
298
|
+
*
|
|
299
|
+
* @example
|
|
300
|
+
* ```ts
|
|
301
|
+
* for (const file of runtime.stream(element)) {
|
|
302
|
+
* await writeFile(file)
|
|
303
|
+
* }
|
|
304
|
+
* ```
|
|
305
|
+
*/
|
|
306
|
+
*stream(element: KubbReactElement): Generator<FileNode> {
|
|
307
|
+
yield* walkFiles(element)
|
|
308
|
+
}
|
|
309
|
+
}
|
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,93 +1,80 @@
|
|
|
1
1
|
import type { FileNode } from '@kubb/ast'
|
|
2
2
|
import { Runtime } from './Runtime.tsx'
|
|
3
|
+
import { SyncRuntime } from './SyncRuntime.tsx'
|
|
3
4
|
import type { KubbReactElement } from './types.ts'
|
|
4
5
|
|
|
5
|
-
type Options = {
|
|
6
|
-
/**
|
|
7
|
-
* Print each render result to the console for debugging.
|
|
8
|
-
* Useful when diagnosing output differences between renders.
|
|
9
|
-
* @default false
|
|
10
|
-
*/
|
|
11
|
-
debug?: boolean
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* The renderer instance returned by {@link createRenderer}.
|
|
16
|
-
*/
|
|
17
|
-
type Renderer = {
|
|
18
|
-
/**
|
|
19
|
-
* Render a JSX element tree and collect the resulting {@link FileNode} entries.
|
|
20
|
-
* Resolves once all synchronous render work (including React's flush) is done.
|
|
21
|
-
*/
|
|
22
|
-
render(Element: KubbReactElement): Promise<void>
|
|
23
|
-
/**
|
|
24
|
-
* Tear down the renderer and release all React resources.
|
|
25
|
-
* Pass an `Error` to signal an abnormal shutdown.
|
|
26
|
-
*/
|
|
27
|
-
unmount(error?: Error | number | null): void
|
|
28
|
-
/**
|
|
29
|
-
* The {@link FileNode} entries collected from the most recent `render` call.
|
|
30
|
-
*/
|
|
31
|
-
files: Array<FileNode>
|
|
32
|
-
}
|
|
33
|
-
|
|
34
6
|
/**
|
|
35
|
-
*
|
|
7
|
+
* Renderer factory for generators that produce JSX output.
|
|
36
8
|
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
9
|
+
* Pass as the `renderer` property of `defineGenerator`. Core drives rendering
|
|
10
|
+
* without a hard dependency on `@kubb/renderer-jsx`.
|
|
39
11
|
*
|
|
40
|
-
* @example
|
|
12
|
+
* @example
|
|
41
13
|
* ```ts
|
|
42
|
-
* import {
|
|
14
|
+
* import { jsxRenderer } from '@kubb/renderer-jsx'
|
|
43
15
|
*
|
|
44
|
-
* const
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
* <File.
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* </File>
|
|
51
|
-
* )
|
|
52
|
-
* console.log(renderer.files) // [FileNode]
|
|
53
|
-
* renderer.unmount()
|
|
16
|
+
* export const myGenerator = defineGenerator<PluginTs>({
|
|
17
|
+
* renderer: jsxRenderer,
|
|
18
|
+
* schema(node, options) {
|
|
19
|
+
* return <File baseName="output.ts" path="src/output.ts">...</File>
|
|
20
|
+
* },
|
|
21
|
+
* })
|
|
54
22
|
* ```
|
|
55
23
|
*/
|
|
56
|
-
export
|
|
57
|
-
const runtime = new Runtime(
|
|
58
|
-
|
|
24
|
+
export const jsxRenderer = () => {
|
|
25
|
+
const runtime = new Runtime()
|
|
59
26
|
return {
|
|
60
|
-
async render(
|
|
61
|
-
await runtime.render(
|
|
27
|
+
async render(element: KubbReactElement) {
|
|
28
|
+
await runtime.render(element)
|
|
62
29
|
},
|
|
63
30
|
get files() {
|
|
64
31
|
return runtime.nodes
|
|
65
32
|
},
|
|
66
|
-
unmount(error) {
|
|
33
|
+
unmount(error?: Error | number | null) {
|
|
67
34
|
runtime.unmount(error)
|
|
68
35
|
},
|
|
69
36
|
}
|
|
70
37
|
}
|
|
71
38
|
|
|
72
39
|
/**
|
|
73
|
-
*
|
|
40
|
+
* Lightweight renderer factory with no React fiber, scheduler, or work loop.
|
|
74
41
|
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
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.
|
|
78
45
|
*
|
|
79
|
-
* @example
|
|
46
|
+
* @example Drop-in replacement
|
|
80
47
|
* ```ts
|
|
81
|
-
* import {
|
|
82
|
-
* import { defineGenerator } from '@kubb/core'
|
|
48
|
+
* import { jsxRendererSync } from '@kubb/renderer-jsx'
|
|
83
49
|
*
|
|
84
50
|
* export const myGenerator = defineGenerator<PluginTs>({
|
|
85
|
-
*
|
|
86
|
-
* renderer: jsxRenderer,
|
|
51
|
+
* renderer: jsxRendererSync,
|
|
87
52
|
* schema(node, options) {
|
|
88
53
|
* return <File baseName="output.ts" path="src/output.ts">...</File>
|
|
89
54
|
* },
|
|
90
55
|
* })
|
|
91
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
|
+
* ```
|
|
92
64
|
*/
|
|
93
|
-
export const
|
|
65
|
+
export const jsxRendererSync = () => {
|
|
66
|
+
const runtime = new SyncRuntime()
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
async render(element: KubbReactElement): Promise<void> {
|
|
70
|
+
runtime.render(element)
|
|
71
|
+
},
|
|
72
|
+
get files() {
|
|
73
|
+
return runtime.nodes
|
|
74
|
+
},
|
|
75
|
+
stream(element: KubbReactElement): Generator<FileNode> {
|
|
76
|
+
return runtime.stream(element)
|
|
77
|
+
},
|
|
78
|
+
unmount(_error?: Error | number | null) {},
|
|
79
|
+
}
|
|
80
|
+
}
|