@kubb/renderer-jsx 5.0.0-beta.4 → 5.0.0-beta.41

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.
Files changed (45) hide show
  1. package/README.md +134 -0
  2. package/dist/index.cjs +621 -193
  3. package/dist/index.d.ts +326 -90
  4. package/dist/index.js +615 -193
  5. package/dist/jsx-dev-runtime.cjs +1 -1
  6. package/dist/jsx-dev-runtime.d.ts +7 -8
  7. package/dist/jsx-dev-runtime.js +2 -2
  8. package/dist/{jsx-namespace-CNp0arTN.d.ts → jsx-namespace-dmStM1a2.d.ts} +3 -3
  9. package/dist/{jsx-runtime-DdmO3p0U.cjs → jsx-runtime-4M1bV6ub.cjs} +9 -9
  10. package/dist/{jsx-runtime-Cvu_ZYgL.js → jsx-runtime-CQ6-_gue.js} +10 -10
  11. package/dist/jsx-runtime.cjs +1 -1
  12. package/dist/jsx-runtime.d.ts +9 -10
  13. package/dist/jsx-runtime.js +2 -2
  14. package/dist/{types-nAFMiWFw.d.ts → types-B5VGpHs0.d.ts} +11 -10
  15. package/dist/types.d.ts +1 -1
  16. package/package.json +8 -12
  17. package/src/Renderer.ts +1 -5
  18. package/src/Runtime.tsx +7 -18
  19. package/src/SyncRuntime.tsx +309 -0
  20. package/src/components/Callout.tsx +59 -0
  21. package/src/components/CodeBlock.tsx +37 -0
  22. package/src/components/Const.tsx +4 -4
  23. package/src/components/File.tsx +7 -5
  24. package/src/components/Frontmatter.tsx +38 -0
  25. package/src/components/Function.tsx +8 -8
  26. package/src/components/Heading.tsx +34 -0
  27. package/src/components/Jsx.tsx +1 -1
  28. package/src/components/List.tsx +40 -0
  29. package/src/components/Paragraph.tsx +28 -0
  30. package/src/components/Type.tsx +3 -3
  31. package/src/constants.ts +19 -9
  32. package/src/createRenderer.tsx +81 -62
  33. package/src/dom.ts +7 -19
  34. package/src/index.ts +7 -1
  35. package/src/types.ts +9 -8
  36. package/src/utils.ts +153 -174
  37. package/dist/index.cjs.map +0 -1
  38. package/dist/index.js.map +0 -1
  39. package/dist/jsx-dev-runtime.cjs.map +0 -1
  40. package/dist/jsx-dev-runtime.js.map +0 -1
  41. package/dist/jsx-runtime-Cvu_ZYgL.js.map +0 -1
  42. package/dist/jsx-runtime-DdmO3p0U.cjs.map +0 -1
  43. package/dist/jsx-runtime.cjs.map +0 -1
  44. package/dist/jsx-runtime.js.map +0 -1
  45. /package/dist/{chunk-Bb7HlUDG.js → chunk-DoukXa0m.js} +0 -0
package/src/utils.ts CHANGED
@@ -11,29 +11,41 @@ import {
11
11
  createText,
12
12
  createType,
13
13
  } from '@kubb/ast'
14
- import { nodeNames, TEXT_NODE_NAME } from './constants.ts'
15
- import type { DOMElement, DOMNode, ElementNames } from './types.ts'
14
+ import {
15
+ KUBB_ARROW_FUNCTION,
16
+ KUBB_CONST,
17
+ KUBB_EXPORT,
18
+ KUBB_FILE,
19
+ KUBB_FUNCTION,
20
+ KUBB_IMPORT,
21
+ KUBB_JSX,
22
+ KUBB_SOURCE,
23
+ KUBB_TYPE,
24
+ TEXT_NODE_NAME,
25
+ nodeNames,
26
+ } from './constants.ts'
27
+ import type { DOMElement, DOMNode } from './types.ts'
28
+
29
+ function toBool(val: unknown): boolean {
30
+ return (val ?? false) as boolean
31
+ }
16
32
 
17
33
  /**
18
34
  * Collect the text and nested AST-node children of a single kubb-* element.
19
35
  *
20
- * `#text` children become raw {@link TextNode}s; nested `kubb-function`, `kubb-const`,
36
+ * `#text` children become raw text nodes. Nested `kubb-function`, `kubb-const`,
21
37
  * `kubb-type`, and similar elements are converted into their respective {@link CodeNode}s.
22
- * Any unrecognized DOM elements are silently skipped.
38
+ * Any unrecognized element names are silently skipped.
23
39
  */
24
- function collectChildNodes(element: DOMElement): Array<CodeNode> {
40
+ function collectCodeNodes(element: DOMElement): Array<CodeNode> {
25
41
  const result: Array<CodeNode> = []
26
42
 
27
43
  for (const child of element.childNodes) {
28
- if (!child) {
29
- continue
30
- }
44
+ if (!child) continue
31
45
 
32
46
  if (child.nodeName === TEXT_NODE_NAME) {
33
47
  const text = (child as DOMNode<{ nodeName: '#text' }>).nodeValue
34
- if (text && text.trim().length > 0) {
35
- result.push(createText(text))
36
- }
48
+ if (text && text.trim()) result.push(createText(text))
37
49
  continue
38
50
  }
39
51
 
@@ -42,65 +54,76 @@ function collectChildNodes(element: DOMElement): Array<CodeNode> {
42
54
  continue
43
55
  }
44
56
 
45
- if (child.nodeName === 'kubb-function') {
57
+ if (child.nodeName === KUBB_FUNCTION) {
46
58
  const attrs = child.attributes
47
59
  result.push(
48
60
  createFunction({
49
- name: attrs.get('name') as string,
50
- params: attrs.get('params') as string | undefined,
51
- export: attrs.get('export') as boolean | undefined,
52
- default: attrs.get('default') as boolean | undefined,
53
- async: attrs.get('async') as boolean | undefined,
54
- generics: attrs.get('generics') as string | undefined,
55
- returnType: attrs.get('returnType') as string | undefined,
56
- JSDoc: attrs.get('JSDoc') as JSDocNode | undefined,
57
- nodes: collectChildNodes(child),
61
+ name: attrs['name'] as string,
62
+ params: attrs['params'] as string | null | undefined,
63
+ export: attrs['export'] as boolean | null | undefined,
64
+ default: attrs['default'] as boolean | null | undefined,
65
+ async: attrs['async'] as boolean | null | undefined,
66
+ generics: attrs['generics'] as string | Array<string> | null | undefined,
67
+ returnType: attrs['returnType'] as string | null | undefined,
68
+ JSDoc: attrs['JSDoc'] as JSDocNode | null | undefined,
69
+ nodes: collectCodeNodes(child),
58
70
  }),
59
71
  )
60
- } else if (child.nodeName === 'kubb-arrow-function') {
72
+ continue
73
+ }
74
+
75
+ if (child.nodeName === KUBB_ARROW_FUNCTION) {
61
76
  const attrs = child.attributes
62
77
  result.push(
63
78
  createArrowFunction({
64
- name: attrs.get('name') as string,
65
- params: attrs.get('params') as string | undefined,
66
- export: attrs.get('export') as boolean | undefined,
67
- default: attrs.get('default') as boolean | undefined,
68
- async: attrs.get('async') as boolean | undefined,
69
- generics: attrs.get('generics') as string | undefined,
70
- returnType: attrs.get('returnType') as string | undefined,
71
- singleLine: attrs.get('singleLine') as boolean | undefined,
72
- JSDoc: attrs.get('JSDoc') as JSDocNode | undefined,
73
- nodes: collectChildNodes(child),
79
+ name: attrs['name'] as string,
80
+ params: attrs['params'] as string | null | undefined,
81
+ export: attrs['export'] as boolean | null | undefined,
82
+ default: attrs['default'] as boolean | null | undefined,
83
+ async: attrs['async'] as boolean | null | undefined,
84
+ generics: attrs['generics'] as string | Array<string> | null | undefined,
85
+ returnType: attrs['returnType'] as string | null | undefined,
86
+ singleLine: attrs['singleLine'] as boolean | null | undefined,
87
+ JSDoc: attrs['JSDoc'] as JSDocNode | null | undefined,
88
+ nodes: collectCodeNodes(child),
74
89
  } as Omit<ArrowFunctionNode, 'kind'>),
75
90
  )
76
- } else if (child.nodeName === 'kubb-const') {
91
+ continue
92
+ }
93
+
94
+ if (child.nodeName === KUBB_CONST) {
77
95
  const attrs = child.attributes
78
96
  result.push(
79
97
  createConst({
80
- name: attrs.get('name') as string,
81
- type: attrs.get('type') as string | undefined,
82
- export: attrs.get('export') as boolean | undefined,
83
- asConst: attrs.get('asConst') as boolean | undefined,
84
- JSDoc: attrs.get('JSDoc') as JSDocNode | undefined,
85
- nodes: collectChildNodes(child),
98
+ name: attrs['name'] as string,
99
+ type: attrs['type'] as string | null | undefined,
100
+ export: attrs['export'] as boolean | null | undefined,
101
+ asConst: attrs['asConst'] as boolean | null | undefined,
102
+ JSDoc: attrs['JSDoc'] as JSDocNode | null | undefined,
103
+ nodes: collectCodeNodes(child),
86
104
  }),
87
105
  )
88
- } else if (child.nodeName === 'kubb-type') {
106
+ continue
107
+ }
108
+
109
+ if (child.nodeName === KUBB_TYPE) {
89
110
  const attrs = child.attributes
90
111
  result.push(
91
112
  createType({
92
- name: attrs.get('name') as string,
93
- export: attrs.get('export') as boolean | undefined,
94
- JSDoc: attrs.get('JSDoc') as JSDocNode | undefined,
95
- nodes: collectChildNodes(child),
113
+ name: attrs['name'] as string,
114
+ export: attrs['export'] as boolean | null | undefined,
115
+ JSDoc: attrs['JSDoc'] as JSDocNode | null | undefined,
116
+ nodes: collectCodeNodes(child),
96
117
  }),
97
118
  )
98
- } else if (child.nodeName === 'kubb-jsx') {
119
+ continue
120
+ }
121
+
122
+ if (child.nodeName === KUBB_JSX) {
99
123
  const textChild = child.childNodes[0]
100
124
  const value = textChild?.nodeName === TEXT_NODE_NAME ? (textChild as DOMNode<{ nodeName: '#text' }>).nodeValue : ''
101
- if (value) {
102
- result.push(createJsx(value))
103
- }
125
+ if (value) result.push(createJsx(value))
126
+ continue
104
127
  }
105
128
  }
106
129
 
@@ -108,160 +131,116 @@ function collectChildNodes(element: DOMElement): Array<CodeNode> {
108
131
  }
109
132
 
110
133
  /**
111
- * Traverse `node` and collect all `<kubb-source>` elements into a `Set<SourceNode>`.
134
+ * Yields every {@link SourceNode}, {@link ExportNode}, and {@link ImportNode}
135
+ * within a `<kubb-file>` subtree in a single tree walk.
112
136
  *
113
- * Elements whose `nodeName` is in `ignores` are skipped entirely (including their subtrees).
114
- * This is used to collect source blocks from a file node while excluding import/export subtrees.
115
- *
116
- * @example Collect sources while ignoring export and import elements
117
- * ```ts
118
- * const sources = squashSourceNodes(fileElement, ['kubb-export', 'kubb-import'])
119
- * ```
137
+ * Import and export elements are leaf nodes. Once yielded, the walker does not
138
+ * recurse into them, which also prevents source collection from descending into
139
+ * their subtrees. Dispatch on `.kind` (`'Source'`, `'Export'`, `'Import'`) to
140
+ * separate the results.
120
141
  */
121
- function squashSourceNodes(node: DOMElement, ignores: Array<ElementNames>): Set<SourceNode> {
122
- const ignoreSet = new Set(ignores)
123
- const sources = new Set<SourceNode>()
124
-
125
- const walk = (current: DOMElement): void => {
126
- for (const child of current.childNodes) {
127
- if (!child) {
128
- continue
129
- }
130
-
131
- if (child.nodeName !== TEXT_NODE_NAME && ignoreSet.has(child.nodeName)) {
132
- continue
133
- }
142
+ function* collectFileEntries(node: DOMElement): Generator<SourceNode | ExportNode | ImportNode> {
143
+ for (const child of node.childNodes) {
144
+ if (!child || child.nodeName === TEXT_NODE_NAME) continue
145
+
146
+ if (child.nodeName === KUBB_SOURCE) {
147
+ yield createSource({
148
+ name: child.attributes['name']?.toString(),
149
+ isTypeOnly: toBool(child.attributes['isTypeOnly']),
150
+ isExportable: toBool(child.attributes['isExportable']),
151
+ isIndexable: toBool(child.attributes['isIndexable']),
152
+ nodes: collectCodeNodes(child),
153
+ })
154
+ continue
155
+ }
134
156
 
135
- if (child.nodeName === 'kubb-source') {
136
- const source = createSource({
137
- name: child.attributes.get('name')?.toString(),
138
- isTypeOnly: (child.attributes.get('isTypeOnly') ?? false) as boolean,
139
- isExportable: (child.attributes.get('isExportable') ?? false) as boolean,
140
- isIndexable: (child.attributes.get('isIndexable') ?? false) as boolean,
141
- nodes: collectChildNodes(child),
142
- })
157
+ if (child.nodeName === KUBB_EXPORT) {
158
+ yield createExport({
159
+ name: child.attributes['name'] as ExportNode['name'],
160
+ path: child.attributes['path'] as string,
161
+ isTypeOnly: toBool(child.attributes['isTypeOnly']),
162
+ asAlias: toBool(child.attributes['asAlias']),
163
+ })
164
+ continue
165
+ }
143
166
 
144
- sources.add(source)
145
- continue
146
- }
167
+ if (child.nodeName === KUBB_IMPORT) {
168
+ yield createImport({
169
+ name: child.attributes['name'] as ImportNode['name'],
170
+ path: child.attributes['path'] as string,
171
+ root: child.attributes['root'] as string | null | undefined,
172
+ isTypeOnly: toBool(child.attributes['isTypeOnly']),
173
+ isNameSpace: toBool(child.attributes['isNameSpace']),
174
+ })
175
+ continue
176
+ }
147
177
 
148
- if (child.nodeName !== TEXT_NODE_NAME && nodeNames.has(child.nodeName)) {
149
- walk(child)
150
- }
178
+ if (nodeNames.has(child.nodeName)) {
179
+ yield* collectFileEntries(child)
151
180
  }
152
181
  }
153
-
154
- walk(node)
155
- return sources
156
182
  }
157
183
 
158
184
  /**
159
- * Traverse `node` and collect all `<kubb-export>` elements into a `Set<ExportNode>`.
185
+ * Runs a single {@link collectFileEntries} pass over a `<kubb-file>` DOM element
186
+ * and assembles the result into a {@link FileNode}, bucketing each yielded
187
+ * node by its `.kind`.
160
188
  */
161
- function squashExportNodes(node: DOMElement): Set<ExportNode> {
162
- const exports = new Set<ExportNode>()
163
-
164
- const walk = (current: DOMElement): void => {
165
- for (const child of current.childNodes) {
166
- if (!child) {
167
- continue
168
- }
169
-
170
- if (child.nodeName !== TEXT_NODE_NAME && nodeNames.has(child.nodeName)) {
171
- walk(child)
172
- }
173
-
174
- if (child.nodeName === 'kubb-export') {
175
- exports.add(
176
- createExport({
177
- name: child.attributes.get('name') as ExportNode['name'],
178
- path: child.attributes.get('path') as string,
179
- isTypeOnly: (child.attributes.get('isTypeOnly') ?? false) as boolean,
180
- asAlias: (child.attributes.get('asAlias') ?? false) as boolean,
181
- }),
182
- )
183
- }
189
+ function createFileNode(child: DOMElement): FileNode {
190
+ const sources: Array<SourceNode> = []
191
+ const exports: Array<ExportNode> = []
192
+ const imports: Array<ImportNode> = []
193
+
194
+ for (const node of collectFileEntries(child)) {
195
+ if (node.kind === 'Source') {
196
+ sources.push(node)
197
+ continue
198
+ }
199
+ if (node.kind === 'Export') {
200
+ exports.push(node)
201
+ continue
184
202
  }
203
+ imports.push(node)
185
204
  }
186
205
 
187
- walk(node)
188
- return exports
206
+ return {
207
+ baseName: child.attributes['baseName'],
208
+ path: child.attributes['path'],
209
+ meta: child.attributes['meta'] || {},
210
+ footer: child.attributes['footer'],
211
+ banner: child.attributes['banner'],
212
+ sources,
213
+ exports,
214
+ imports,
215
+ } as FileNode
189
216
  }
190
217
 
191
218
  /**
192
- * Traverse `node` and collect all `<kubb-import>` elements into a `Set<ImportNode>`.
219
+ * Yields each {@link FileNode} as it is encountered during the tree walk,
220
+ * without collecting into an intermediate array. Callers can begin processing
221
+ * each file before the rest of the tree is traversed.
193
222
  */
194
- function squashImportNodes(node: DOMElement): Set<ImportNode> {
195
- const imports = new Set<ImportNode>()
223
+ export function* streamFiles(node: DOMElement): Generator<FileNode> {
224
+ for (const child of node.childNodes) {
225
+ if (!child) continue
196
226
 
197
- const walk = (current: DOMElement): void => {
198
- for (const child of current.childNodes) {
199
- if (!child) {
200
- continue
201
- }
202
-
203
- if (child.nodeName !== TEXT_NODE_NAME && nodeNames.has(child.nodeName)) {
204
- walk(child)
205
- }
227
+ if (child.nodeName !== TEXT_NODE_NAME && child.nodeName !== KUBB_FILE && nodeNames.has(child.nodeName)) {
228
+ yield* streamFiles(child)
229
+ }
206
230
 
207
- if (child.nodeName === 'kubb-import') {
208
- imports.add(
209
- createImport({
210
- name: child.attributes.get('name') as ImportNode['name'],
211
- path: child.attributes.get('path') as string,
212
- root: child.attributes.get('root') as string | undefined,
213
- isTypeOnly: (child.attributes.get('isTypeOnly') ?? false) as boolean,
214
- isNameSpace: (child.attributes.get('isNameSpace') ?? false) as boolean,
215
- }),
216
- )
217
- }
231
+ if (child.nodeName === KUBB_FILE && child.attributes['baseName'] !== undefined && child.attributes['path'] !== undefined) {
232
+ yield createFileNode(child)
218
233
  }
219
234
  }
220
-
221
- walk(node)
222
- return imports
223
235
  }
224
236
 
225
237
  /**
226
238
  * Walk the virtual DOM tree rooted at `node` and convert every `<kubb-file>` element
227
239
  * into a {@link FileNode}, collecting its source blocks, imports, and exports.
228
240
  *
229
- * Returns the list of file nodes in document order. Nested files are supported
241
+ * Returns the list of file nodes in document order. Nested files are supported;
230
242
  * the walker descends into non-file elements and recurses through them.
231
243
  */
232
- export function processFiles(node: DOMElement): Array<FileNode> {
233
- const collected: Array<FileNode> = []
234
-
235
- function walk(current: DOMElement) {
236
- for (const child of current.childNodes) {
237
- if (!child) {
238
- continue
239
- }
240
-
241
- if (child.nodeName !== TEXT_NODE_NAME && child.nodeName !== 'kubb-file' && nodeNames.has(child.nodeName)) {
242
- walk(child)
243
- }
244
-
245
- if (child.nodeName === 'kubb-file') {
246
- if (child.attributes.has('baseName') && child.attributes.has('path')) {
247
- const sources = squashSourceNodes(child, ['kubb-export', 'kubb-import'])
248
-
249
- collected.push({
250
- baseName: child.attributes.get('baseName'),
251
- path: child.attributes.get('path'),
252
- meta: child.attributes.get('meta') || {},
253
- footer: child.attributes.get('footer'),
254
- banner: child.attributes.get('banner'),
255
- sources: [...sources],
256
- exports: [...squashExportNodes(child)],
257
- imports: [...squashImportNodes(child)],
258
- } as FileNode)
259
- }
260
- }
261
- }
262
- }
263
-
264
- walk(node)
265
-
266
- return collected
244
+ export function collectFiles(node: DOMElement): Array<FileNode> {
245
+ return [...streamFiles(node)]
267
246
  }