@kubb/renderer-jsx 5.0.0-beta.6 → 5.0.0-beta.61
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +17 -10
- package/README.md +134 -0
- package/dist/chunk-C0LytTxp.js +8 -0
- package/dist/index.cjs +386 -17922
- package/dist/index.d.ts +232 -147
- package/dist/index.js +370 -17903
- package/dist/jsx-dev-runtime.cjs +3 -10
- package/dist/jsx-dev-runtime.d.ts +4 -8
- package/dist/jsx-dev-runtime.js +1 -9
- package/dist/jsx-runtime-3ncySO6L.cjs +89 -0
- package/dist/jsx-runtime.cjs +5 -14
- package/dist/jsx-runtime.d.ts +60 -10
- package/dist/jsx-runtime.js +24 -7
- package/dist/types-UI1cZVah.d.ts +115 -0
- package/dist/types.d.ts +2 -2
- package/package.json +6 -29
- package/src/SyncRuntime.tsx +298 -0
- package/src/components/Callout.tsx +59 -0
- package/src/components/Const.tsx +4 -4
- package/src/components/File.tsx +7 -5
- package/src/components/Frontmatter.tsx +38 -0
- package/src/components/Function.tsx +8 -8
- package/src/components/Heading.tsx +34 -0
- package/src/components/Jsx.tsx +1 -1
- package/src/components/List.tsx +40 -0
- package/src/components/Paragraph.tsx +28 -0
- package/src/components/Type.tsx +3 -3
- package/src/constants.ts +9 -28
- package/src/createRenderer.tsx +38 -75
- package/src/globals.ts +14 -6
- package/src/index.ts +6 -3
- package/src/jsx-dev-runtime.ts +1 -3
- package/src/jsx-namespace.d.ts +21 -13
- package/src/jsx-runtime.ts +22 -6
- package/src/types.ts +16 -100
- package/dist/chunk-Bb7HlUDG.js +0 -28
- package/dist/jsx-namespace-CNp0arTN.d.ts +0 -39
- package/dist/jsx-runtime-Cvu_ZYgL.js +0 -1448
- package/dist/jsx-runtime-DdmO3p0U.cjs +0 -1503
- package/dist/types-nAFMiWFw.d.ts +0 -168
- package/src/Renderer.ts +0 -184
- package/src/Runtime.tsx +0 -170
- package/src/components/Root.tsx +0 -70
- package/src/dom.ts +0 -105
- package/src/utils.ts +0 -267
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
import type { ArrowFunctionNode, CodeNode, ExportNode, FileNode, ImportNode, JSDocNode, SourceNode } from '@kubb/ast'
|
|
2
|
+
import * as factory from '@kubb/ast/factory'
|
|
3
|
+
import { KUBB_ARROW_FUNCTION, KUBB_CONST, KUBB_EXPORT, KUBB_FILE, KUBB_FUNCTION, KUBB_IMPORT, KUBB_JSX, KUBB_SOURCE, KUBB_TYPE } from './constants.ts'
|
|
4
|
+
import { Fragment } from './jsx-runtime.ts'
|
|
5
|
+
import type { KubbReactElement } from './types.ts'
|
|
6
|
+
|
|
7
|
+
type OnText = (text: string) => void
|
|
8
|
+
type OnHost = (type: string, props: Record<string, unknown>) => void
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Walks `element`, resolving arrays, Fragments, and function components
|
|
12
|
+
* transparently, then calls `onText` for primitive values and `onHost` for
|
|
13
|
+
* every host element encountered. Pure function components are called
|
|
14
|
+
* synchronously. Hooks and class components are not supported.
|
|
15
|
+
*/
|
|
16
|
+
function walkElement(element: unknown, onText: OnText, onHost: OnHost): void {
|
|
17
|
+
if (element == null || typeof element === 'boolean') return
|
|
18
|
+
|
|
19
|
+
if (typeof element === 'string' || typeof element === 'number' || typeof element === 'bigint') {
|
|
20
|
+
onText(String(element))
|
|
21
|
+
return
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (Array.isArray(element)) {
|
|
25
|
+
for (const child of element) walkElement(child, onText, onHost)
|
|
26
|
+
return
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (typeof element === 'object' && '$$typeof' in element) {
|
|
30
|
+
const el = element as unknown as KubbReactElement
|
|
31
|
+
const { type } = el
|
|
32
|
+
const props = el.props as Record<string, unknown>
|
|
33
|
+
|
|
34
|
+
if (type === Fragment) {
|
|
35
|
+
walkElement(props['children'], onText, onHost)
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
if (typeof type === 'function') {
|
|
39
|
+
walkElement((type as (p: unknown) => unknown)(props), onText, onHost)
|
|
40
|
+
return
|
|
41
|
+
}
|
|
42
|
+
if (typeof type === 'string') {
|
|
43
|
+
onHost(type, props)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function toBool(val: unknown): boolean {
|
|
49
|
+
return (val ?? false) as boolean
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function collectCodeNodes(props: Record<string, unknown>): Array<CodeNode> {
|
|
53
|
+
const nodes: Array<CodeNode> = []
|
|
54
|
+
collectCode(props['children'], nodes)
|
|
55
|
+
return nodes
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function collectCode(element: unknown, nodes: Array<CodeNode>): void {
|
|
59
|
+
walkElement(
|
|
60
|
+
element,
|
|
61
|
+
(text) => {
|
|
62
|
+
if (text.trim()) nodes.push(factory.createText(text))
|
|
63
|
+
},
|
|
64
|
+
(type, props) => resolveCodeNode(type, props, nodes),
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function resolveCodeNode(type: string, props: Record<string, unknown>, nodes: Array<CodeNode>): void {
|
|
69
|
+
if (type === 'br') {
|
|
70
|
+
nodes.push(factory.createBreak())
|
|
71
|
+
return
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (type === KUBB_JSX) {
|
|
75
|
+
let value = ''
|
|
76
|
+
walkElement(
|
|
77
|
+
props['children'],
|
|
78
|
+
(t) => {
|
|
79
|
+
value += t
|
|
80
|
+
},
|
|
81
|
+
() => {},
|
|
82
|
+
)
|
|
83
|
+
if (value) nodes.push(factory.createJsx(value))
|
|
84
|
+
return
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (type === KUBB_FUNCTION) {
|
|
88
|
+
nodes.push(
|
|
89
|
+
factory.createFunction({
|
|
90
|
+
name: props['name'] as string,
|
|
91
|
+
params: props['params'] as string | null | undefined,
|
|
92
|
+
export: props['export'] as boolean | null | undefined,
|
|
93
|
+
default: props['default'] as boolean | null | undefined,
|
|
94
|
+
async: props['async'] as boolean | null | undefined,
|
|
95
|
+
generics: props['generics'] as string | Array<string> | null | undefined,
|
|
96
|
+
returnType: props['returnType'] as string | null | undefined,
|
|
97
|
+
JSDoc: props['JSDoc'] as JSDocNode | null | undefined,
|
|
98
|
+
nodes: collectCodeNodes(props),
|
|
99
|
+
}),
|
|
100
|
+
)
|
|
101
|
+
return
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (type === KUBB_ARROW_FUNCTION) {
|
|
105
|
+
nodes.push(
|
|
106
|
+
factory.createArrowFunction({
|
|
107
|
+
name: props['name'] as string,
|
|
108
|
+
params: props['params'] as string | null | undefined,
|
|
109
|
+
export: props['export'] as boolean | null | undefined,
|
|
110
|
+
default: props['default'] as boolean | null | undefined,
|
|
111
|
+
async: props['async'] as boolean | null | undefined,
|
|
112
|
+
generics: props['generics'] as string | Array<string> | null | undefined,
|
|
113
|
+
returnType: props['returnType'] as string | null | undefined,
|
|
114
|
+
singleLine: props['singleLine'] as boolean | null | undefined,
|
|
115
|
+
JSDoc: props['JSDoc'] as JSDocNode | null | undefined,
|
|
116
|
+
nodes: collectCodeNodes(props),
|
|
117
|
+
} as Omit<ArrowFunctionNode, 'kind'>),
|
|
118
|
+
)
|
|
119
|
+
return
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (type === KUBB_CONST) {
|
|
123
|
+
nodes.push(
|
|
124
|
+
factory.createConst({
|
|
125
|
+
name: props['name'] as string,
|
|
126
|
+
type: props['type'] as string | null | undefined,
|
|
127
|
+
export: props['export'] as boolean | null | undefined,
|
|
128
|
+
asConst: props['asConst'] as boolean | null | undefined,
|
|
129
|
+
JSDoc: props['JSDoc'] as JSDocNode | null | undefined,
|
|
130
|
+
nodes: collectCodeNodes(props),
|
|
131
|
+
}),
|
|
132
|
+
)
|
|
133
|
+
return
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (type === KUBB_TYPE) {
|
|
137
|
+
nodes.push(
|
|
138
|
+
factory.createType({
|
|
139
|
+
name: props['name'] as string,
|
|
140
|
+
export: props['export'] as boolean | null | undefined,
|
|
141
|
+
JSDoc: props['JSDoc'] as JSDocNode | null | undefined,
|
|
142
|
+
nodes: collectCodeNodes(props),
|
|
143
|
+
}),
|
|
144
|
+
)
|
|
145
|
+
return
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
type FileChildren = { sources: Array<SourceNode>; exports: Array<ExportNode>; imports: Array<ImportNode> }
|
|
150
|
+
|
|
151
|
+
function collectFileChildren(element: unknown): FileChildren {
|
|
152
|
+
const sources: Array<SourceNode> = []
|
|
153
|
+
const exports: Array<ExportNode> = []
|
|
154
|
+
const imports: Array<ImportNode> = []
|
|
155
|
+
|
|
156
|
+
walkElement(
|
|
157
|
+
element,
|
|
158
|
+
(text) => {
|
|
159
|
+
if (text.trim()) {
|
|
160
|
+
throw new Error(`[react] '${text}' should be part of <File.Source> component when using the <File/> component`)
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
(type, props) => {
|
|
164
|
+
if (type === KUBB_SOURCE) {
|
|
165
|
+
sources.push(
|
|
166
|
+
factory.createSource({
|
|
167
|
+
name: props['name']?.toString(),
|
|
168
|
+
isTypeOnly: toBool(props['isTypeOnly']),
|
|
169
|
+
isExportable: toBool(props['isExportable']),
|
|
170
|
+
isIndexable: toBool(props['isIndexable']),
|
|
171
|
+
nodes: collectCodeNodes(props),
|
|
172
|
+
}),
|
|
173
|
+
)
|
|
174
|
+
return
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (type === KUBB_EXPORT) {
|
|
178
|
+
exports.push(
|
|
179
|
+
factory.createExport({
|
|
180
|
+
name: props['name'] as ExportNode['name'],
|
|
181
|
+
path: props['path'] as string,
|
|
182
|
+
isTypeOnly: toBool(props['isTypeOnly']),
|
|
183
|
+
asAlias: toBool(props['asAlias']),
|
|
184
|
+
}),
|
|
185
|
+
)
|
|
186
|
+
return
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (type === KUBB_IMPORT) {
|
|
190
|
+
imports.push(
|
|
191
|
+
factory.createImport({
|
|
192
|
+
name: props['name'] as ImportNode['name'],
|
|
193
|
+
path: props['path'] as string,
|
|
194
|
+
root: props['root'] as string | null | undefined,
|
|
195
|
+
isTypeOnly: toBool(props['isTypeOnly']),
|
|
196
|
+
isNameSpace: toBool(props['isNameSpace']),
|
|
197
|
+
}),
|
|
198
|
+
)
|
|
199
|
+
return
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const nested = collectFileChildren(props['children'])
|
|
203
|
+
sources.push(...nested.sources)
|
|
204
|
+
exports.push(...nested.exports)
|
|
205
|
+
imports.push(...nested.imports)
|
|
206
|
+
},
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
return { sources, exports, imports }
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function* walkFiles(element: unknown): Generator<FileNode> {
|
|
213
|
+
if (element == null || typeof element === 'boolean') return
|
|
214
|
+
|
|
215
|
+
if (typeof element === 'string' || typeof element === 'number' || typeof element === 'bigint') return
|
|
216
|
+
|
|
217
|
+
if (Array.isArray(element)) {
|
|
218
|
+
for (const child of element) yield* walkFiles(child)
|
|
219
|
+
return
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (typeof element === 'object' && '$$typeof' in element) {
|
|
223
|
+
const el = element as unknown as KubbReactElement
|
|
224
|
+
const { type } = el
|
|
225
|
+
const props = el.props as Record<string, unknown>
|
|
226
|
+
|
|
227
|
+
if (type === Fragment) {
|
|
228
|
+
yield* walkFiles(props['children'])
|
|
229
|
+
return
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (typeof type === 'function') {
|
|
233
|
+
yield* walkFiles((type as (p: unknown) => unknown)(props))
|
|
234
|
+
return
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (typeof type === 'string') {
|
|
238
|
+
if (type === KUBB_FILE && props['baseName'] !== undefined && props['path'] !== undefined) {
|
|
239
|
+
const { sources, exports, imports } = collectFileChildren(props['children'])
|
|
240
|
+
yield {
|
|
241
|
+
baseName: props['baseName'],
|
|
242
|
+
path: props['path'],
|
|
243
|
+
meta: props['meta'] || {},
|
|
244
|
+
footer: props['footer'],
|
|
245
|
+
banner: props['banner'],
|
|
246
|
+
sources,
|
|
247
|
+
exports,
|
|
248
|
+
imports,
|
|
249
|
+
} as FileNode
|
|
250
|
+
} else {
|
|
251
|
+
yield* walkFiles(props['children'])
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Synchronous JSX renderer that walks the element tree in a single pass,
|
|
259
|
+
* producing {@link FileNode} objects directly without an intermediate virtual
|
|
260
|
+
* DOM. No React fiber, scheduler, or work loop is involved.
|
|
261
|
+
*
|
|
262
|
+
* All components must be pure functions. Hooks and class components are not
|
|
263
|
+
* supported. Produces identical output to the React-backed {@link Runtime} at
|
|
264
|
+
* approximately 2, 4× the speed and a fraction of the allocations.
|
|
265
|
+
*/
|
|
266
|
+
export class SyncRuntime {
|
|
267
|
+
/**
|
|
268
|
+
* Accumulated {@link FileNode} results from every {@link render} call.
|
|
269
|
+
*/
|
|
270
|
+
nodes: Array<FileNode> = []
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Walks `element` synchronously, converts every `<kubb-file>` subtree into
|
|
274
|
+
* a {@link FileNode} with no intermediate virtual DOM, and appends the results
|
|
275
|
+
* to {@link nodes}.
|
|
276
|
+
*/
|
|
277
|
+
render(element: KubbReactElement): void {
|
|
278
|
+
for (const file of walkFiles(element)) {
|
|
279
|
+
this.nodes.push(file)
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Walks `element` synchronously and yields each {@link FileNode} as it is
|
|
285
|
+
* produced, without buffering into an intermediate array first. Callers can
|
|
286
|
+
* begin processing each file before the rest of the element tree is traversed.
|
|
287
|
+
*
|
|
288
|
+
* @example
|
|
289
|
+
* ```ts
|
|
290
|
+
* for (const file of runtime.stream(element)) {
|
|
291
|
+
* await writeFile(file)
|
|
292
|
+
* }
|
|
293
|
+
* ```
|
|
294
|
+
*/
|
|
295
|
+
*stream(element: KubbReactElement): Generator<FileNode> {
|
|
296
|
+
yield* walkFiles(element)
|
|
297
|
+
}
|
|
298
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { Key, KubbReactElement } from '../types.ts'
|
|
2
|
+
|
|
3
|
+
const CALLOUT_LABEL = {
|
|
4
|
+
tip: 'TIP',
|
|
5
|
+
note: 'NOTE',
|
|
6
|
+
important: 'IMPORTANT',
|
|
7
|
+
warning: 'WARNING',
|
|
8
|
+
caution: 'CAUTION',
|
|
9
|
+
} as const
|
|
10
|
+
|
|
11
|
+
export type CalloutType = keyof typeof CALLOUT_LABEL
|
|
12
|
+
|
|
13
|
+
type Props = {
|
|
14
|
+
key?: Key
|
|
15
|
+
/**
|
|
16
|
+
* Callout kind. Maps to the uppercase label inside the `> [!TYPE]` marker.
|
|
17
|
+
*/
|
|
18
|
+
type: CalloutType
|
|
19
|
+
/**
|
|
20
|
+
* Optional title rendered on the same line as the marker.
|
|
21
|
+
*/
|
|
22
|
+
title?: string | null
|
|
23
|
+
/**
|
|
24
|
+
* Body text. Each line is quoted with `> ` so multi-line content stays
|
|
25
|
+
* inside the callout block.
|
|
26
|
+
*/
|
|
27
|
+
children: string
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Renders a GitHub-style alert callout, portable across GitHub, GitLab,
|
|
32
|
+
* VitePress, Obsidian, and MDX.
|
|
33
|
+
*
|
|
34
|
+
* Emits a `<File.Source>` block containing `> [!TYPE] Title` followed by the
|
|
35
|
+
* body with every line prefixed by `> `.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```tsx
|
|
39
|
+
* <Callout type="tip">Run `kubb start --watch` to keep the generator hot.</Callout>
|
|
40
|
+
* // > [!TIP]
|
|
41
|
+
* // > Run `kubb start --watch` to keep the generator hot.
|
|
42
|
+
*
|
|
43
|
+
* <Callout type="warning" title="Heads up">Breaking change in v6.</Callout>
|
|
44
|
+
* // > [!WARNING] Heads up
|
|
45
|
+
* // > Breaking change in v6.
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export function Callout({ type, title, children }: Props): KubbReactElement {
|
|
49
|
+
const label = CALLOUT_LABEL[type]
|
|
50
|
+
const header = title ? `> [!${label}] ${title}` : `> [!${label}]`
|
|
51
|
+
const quoted = children
|
|
52
|
+
.trimEnd()
|
|
53
|
+
.split('\n')
|
|
54
|
+
.map((line) => (line.length > 0 ? `> ${line}` : '>'))
|
|
55
|
+
.join('\n')
|
|
56
|
+
return <kubb-source name="callout">{`${header}\n${quoted}`}</kubb-source>
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
Callout.displayName = 'Callout'
|
package/src/components/Const.tsx
CHANGED
|
@@ -15,26 +15,26 @@ type ConstProps = {
|
|
|
15
15
|
* - `false` generates `const name = …`
|
|
16
16
|
* @default false
|
|
17
17
|
*/
|
|
18
|
-
export?: boolean
|
|
18
|
+
export?: boolean | null
|
|
19
19
|
/**
|
|
20
20
|
* TypeScript type annotation for the constant, written verbatim after `const name:`.
|
|
21
21
|
*
|
|
22
22
|
* @example
|
|
23
23
|
* `type: 'Pet'` → `const pet: Pet = …`
|
|
24
24
|
*/
|
|
25
|
-
type?: string
|
|
25
|
+
type?: string | null
|
|
26
26
|
/**
|
|
27
27
|
* JSDoc block to prepend to the constant declaration.
|
|
28
28
|
* Each entry in `comments` becomes one line inside the emitted `/** … *\/` block.
|
|
29
29
|
*/
|
|
30
|
-
JSDoc?: JSDoc
|
|
30
|
+
JSDoc?: JSDoc | null
|
|
31
31
|
/**
|
|
32
32
|
* Append `as const` after the initialiser, enabling TypeScript const assertions.
|
|
33
33
|
* - `true` generates `const name = … as const`
|
|
34
34
|
* - `false` generates `const name = …`
|
|
35
35
|
* @default false
|
|
36
36
|
*/
|
|
37
|
-
asConst?: boolean
|
|
37
|
+
asConst?: boolean | null
|
|
38
38
|
/**
|
|
39
39
|
* Child nodes rendered as the initialiser expression of the constant.
|
|
40
40
|
*/
|
package/src/components/File.tsx
CHANGED
|
@@ -25,9 +25,9 @@ type BasePropsWithoutBaseName = {
|
|
|
25
25
|
baseName?: never
|
|
26
26
|
/**
|
|
27
27
|
* Fully qualified path to the generated file.
|
|
28
|
-
* Optional when `baseName` is omitted
|
|
28
|
+
* Optional when `baseName` is omitted, the component renders its children inline.
|
|
29
29
|
*/
|
|
30
|
-
path?: string
|
|
30
|
+
path?: string | null
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
type BaseProps = BasePropsWithBaseName | BasePropsWithoutBaseName
|
|
@@ -38,15 +38,17 @@ type Props<TMeta> = BaseProps & {
|
|
|
38
38
|
* Arbitrary metadata attached to the file node.
|
|
39
39
|
* Used by plugins for barrel generation and custom post-processing.
|
|
40
40
|
*/
|
|
41
|
-
meta?: TMeta
|
|
41
|
+
meta?: TMeta | null
|
|
42
42
|
/**
|
|
43
43
|
* Text prepended to the generated file content before any source blocks.
|
|
44
|
+
* Accepts `null` so `resolver.resolveBanner()` results can be passed directly.
|
|
44
45
|
*/
|
|
45
|
-
banner?: string
|
|
46
|
+
banner?: string | null
|
|
46
47
|
/**
|
|
47
48
|
* Text appended to the generated file content after all source blocks.
|
|
49
|
+
* Accepts `null` so `resolver.resolveFooter()` results can be passed directly.
|
|
48
50
|
*/
|
|
49
|
-
footer?: string
|
|
51
|
+
footer?: string | null
|
|
50
52
|
/**
|
|
51
53
|
* Child nodes rendered as the content of this file (source blocks, imports, exports).
|
|
52
54
|
*/
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { stringify } from 'yaml'
|
|
2
|
+
import type { Key, KubbReactElement } from '../types.ts'
|
|
3
|
+
|
|
4
|
+
type Props = {
|
|
5
|
+
key?: Key
|
|
6
|
+
/**
|
|
7
|
+
* Plain object serialized as YAML between `---` fences.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* `data: { title: 'Pets', layout: 'doc' }`
|
|
11
|
+
*/
|
|
12
|
+
data: Record<string, unknown>
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Emits a YAML frontmatter envelope at the top of a generated markdown file.
|
|
17
|
+
*
|
|
18
|
+
* Renders a `<File.Source>` block containing `---\n<yaml>\n---`. Place it as
|
|
19
|
+
* the first child of `<File>` so it appears at the top of the output. Pair with
|
|
20
|
+
* `parserMd` to write `.md` files that downstream tooling (VitePress, MDX,
|
|
21
|
+
* static-site generators) treats as frontmatter.
|
|
22
|
+
*
|
|
23
|
+
* @example Page frontmatter at the top of a generated markdown file
|
|
24
|
+
* ```tsx
|
|
25
|
+
* <File baseName="pets.md" path="src/pets.md">
|
|
26
|
+
* <Frontmatter data={{ title: 'Pets', layout: 'doc' }} />
|
|
27
|
+
* <File.Source>
|
|
28
|
+
* {'# Pets\n\nList of pets.'}
|
|
29
|
+
* </File.Source>
|
|
30
|
+
* </File>
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export function Frontmatter({ data }: Props): KubbReactElement {
|
|
34
|
+
const envelope = `---\n${stringify(data).trimEnd()}\n---`
|
|
35
|
+
return <kubb-source name="frontmatter">{envelope}</kubb-source>
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
Frontmatter.displayName = 'Frontmatter'
|
|
@@ -14,28 +14,28 @@ type Props = {
|
|
|
14
14
|
* Requires `export` to also be `true`.
|
|
15
15
|
* @default false
|
|
16
16
|
*/
|
|
17
|
-
default?: boolean
|
|
17
|
+
default?: boolean | null
|
|
18
18
|
/**
|
|
19
19
|
* Parameter list written verbatim between the function's parentheses.
|
|
20
20
|
*
|
|
21
21
|
* @example
|
|
22
22
|
* `params: 'petId: string, options?: RequestOptions'`
|
|
23
23
|
*/
|
|
24
|
-
params?: string
|
|
24
|
+
params?: string | null
|
|
25
25
|
/**
|
|
26
26
|
* Emit the `export` keyword before the function declaration.
|
|
27
27
|
* - `true` generates `export function name(…) { … }`
|
|
28
28
|
* - `false` generates `function name(…) { … }`
|
|
29
29
|
* @default false
|
|
30
30
|
*/
|
|
31
|
-
export?: boolean
|
|
31
|
+
export?: boolean | null
|
|
32
32
|
/**
|
|
33
33
|
* Emit the `async` keyword, making this an async function.
|
|
34
34
|
* The return type is automatically wrapped in `Promise<returnType>` when both
|
|
35
35
|
* `async` and `returnType` are set.
|
|
36
36
|
* @default false
|
|
37
37
|
*/
|
|
38
|
-
async?: boolean
|
|
38
|
+
async?: boolean | null
|
|
39
39
|
/**
|
|
40
40
|
* TypeScript generic type parameters written verbatim between `<` and `>`.
|
|
41
41
|
* Pass an array to emit multiple parameters separated by commas.
|
|
@@ -46,7 +46,7 @@ type Props = {
|
|
|
46
46
|
* @example Multiple generics
|
|
47
47
|
* `generics: ['TData', 'TError = unknown']`
|
|
48
48
|
*/
|
|
49
|
-
generics?: string | string
|
|
49
|
+
generics?: string | Array<string> | null
|
|
50
50
|
/**
|
|
51
51
|
* TypeScript return type annotation written verbatim after `:`.
|
|
52
52
|
* When `async` is `true`, the value is automatically wrapped in `Promise<…>`.
|
|
@@ -54,12 +54,12 @@ type Props = {
|
|
|
54
54
|
* @example
|
|
55
55
|
* `returnType: 'Pet'`
|
|
56
56
|
*/
|
|
57
|
-
returnType?: string
|
|
57
|
+
returnType?: string | null
|
|
58
58
|
/**
|
|
59
59
|
* JSDoc block to prepend to the function declaration.
|
|
60
60
|
* Each entry in `comments` becomes one line inside the emitted `/** … *\/` block.
|
|
61
61
|
*/
|
|
62
|
-
JSDoc?: JSDoc
|
|
62
|
+
JSDoc?: JSDoc | null
|
|
63
63
|
/**
|
|
64
64
|
* Child nodes rendered as the body of the function.
|
|
65
65
|
*/
|
|
@@ -110,7 +110,7 @@ type ArrowFunctionProps = Props & {
|
|
|
110
110
|
* - `false` generates `const name = (…) => { … }`
|
|
111
111
|
* @default false
|
|
112
112
|
*/
|
|
113
|
-
singleLine?: boolean
|
|
113
|
+
singleLine?: boolean | null
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
/**
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Key, KubbReactElement } from '../types.ts'
|
|
2
|
+
|
|
3
|
+
type Level = 1 | 2 | 3 | 4 | 5 | 6
|
|
4
|
+
|
|
5
|
+
type Props = {
|
|
6
|
+
key?: Key
|
|
7
|
+
/**
|
|
8
|
+
* Heading depth, `1` through `6`. Matches the number of `#` characters
|
|
9
|
+
* prefixed to the heading text.
|
|
10
|
+
*/
|
|
11
|
+
level: Level
|
|
12
|
+
/**
|
|
13
|
+
* Heading text. Inline markdown (links, emphasis) is passed through verbatim.
|
|
14
|
+
*/
|
|
15
|
+
children: string
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Renders an ATX-style markdown heading.
|
|
20
|
+
*
|
|
21
|
+
* Emits a `<File.Source>` block containing `${'#'.repeat(level)} ${children}`.
|
|
22
|
+
* Use inside a `<File>` rendered by `parserMd`.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```tsx
|
|
26
|
+
* <Heading level={2}>Installation</Heading>
|
|
27
|
+
* // ## Installation
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export function Heading({ level, children }: Props): KubbReactElement {
|
|
31
|
+
return <kubb-source name="heading">{`${'#'.repeat(level)} ${children}`}</kubb-source>
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
Heading.displayName = 'Heading'
|
package/src/components/Jsx.tsx
CHANGED
|
@@ -17,7 +17,7 @@ type Props = {
|
|
|
17
17
|
*
|
|
18
18
|
* Use this component when you need to include JSX markup (including fragments
|
|
19
19
|
* `<>…</>`) in the body of a generated function or component. The `children`
|
|
20
|
-
* prop must be a plain string
|
|
20
|
+
* prop must be a plain string, expression attributes that reference runtime
|
|
21
21
|
* values should be written as template literals.
|
|
22
22
|
*
|
|
23
23
|
* @example
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { Key, KubbReactElement } from '../types.ts'
|
|
2
|
+
|
|
3
|
+
type Props = {
|
|
4
|
+
key?: Key
|
|
5
|
+
/**
|
|
6
|
+
* When `true`, emits a numbered list (`1. …`). When `false` or omitted,
|
|
7
|
+
* emits a bullet list (`- …`).
|
|
8
|
+
*
|
|
9
|
+
* @default false
|
|
10
|
+
*/
|
|
11
|
+
ordered?: boolean | null
|
|
12
|
+
/**
|
|
13
|
+
* One entry per line. Inline markdown is passed through verbatim.
|
|
14
|
+
*/
|
|
15
|
+
items: ReadonlyArray<string>
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Renders a markdown list.
|
|
20
|
+
*
|
|
21
|
+
* Emits a `<File.Source>` block containing one entry per line, prefixed with
|
|
22
|
+
* `1.` / `2.` … when `ordered`, or `-` otherwise.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```tsx
|
|
26
|
+
* <List items={['Add the parser', 'Render the page']} />
|
|
27
|
+
* // - Add the parser
|
|
28
|
+
* // - Render the page
|
|
29
|
+
*
|
|
30
|
+
* <List ordered items={['First', 'Second']} />
|
|
31
|
+
* // 1. First
|
|
32
|
+
* // 2. Second
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export function List({ ordered, items }: Props): KubbReactElement {
|
|
36
|
+
const body = items.map((item, index) => `${ordered ? `${index + 1}.` : '-'} ${item}`).join('\n')
|
|
37
|
+
return <kubb-source name="list">{body}</kubb-source>
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
List.displayName = 'List'
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Key, KubbReactElement } from '../types.ts'
|
|
2
|
+
|
|
3
|
+
type Props = {
|
|
4
|
+
key?: Key
|
|
5
|
+
/**
|
|
6
|
+
* Paragraph text. Inline markdown (links, emphasis, code spans) is passed
|
|
7
|
+
* through verbatim.
|
|
8
|
+
*/
|
|
9
|
+
children: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Renders a markdown paragraph.
|
|
14
|
+
*
|
|
15
|
+
* Emits a `<File.Source>` block containing the text as-is. Paragraphs are
|
|
16
|
+
* separated from surrounding blocks by blank lines via the parser's source
|
|
17
|
+
* joining.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```tsx
|
|
21
|
+
* <Paragraph>{'A pet object with `id` and `name` fields.'}</Paragraph>
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export function Paragraph({ children }: Props): KubbReactElement {
|
|
25
|
+
return <kubb-source name="paragraph">{children}</kubb-source>
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
Paragraph.displayName = 'Paragraph'
|
package/src/components/Type.tsx
CHANGED
|
@@ -16,12 +16,12 @@ type TypeProps = {
|
|
|
16
16
|
* - `false` generates `type Name = …`
|
|
17
17
|
* @default false
|
|
18
18
|
*/
|
|
19
|
-
export?: boolean
|
|
19
|
+
export?: boolean | null
|
|
20
20
|
/**
|
|
21
21
|
* JSDoc block to prepend to the type alias declaration.
|
|
22
22
|
* Each entry in `comments` becomes one line inside the emitted `/** … *\/` block.
|
|
23
23
|
*/
|
|
24
|
-
JSDoc?: JSDoc
|
|
24
|
+
JSDoc?: JSDoc | null
|
|
25
25
|
/**
|
|
26
26
|
* Child nodes rendered as the type expression on the right-hand side of the alias.
|
|
27
27
|
*/
|
|
@@ -31,7 +31,7 @@ type TypeProps = {
|
|
|
31
31
|
/**
|
|
32
32
|
* Generates a TypeScript type alias declaration.
|
|
33
33
|
*
|
|
34
|
-
* Throws if `name` does not start with an uppercase letter
|
|
34
|
+
* Throws if `name` does not start with an uppercase letter. TypeScript type aliases
|
|
35
35
|
* should follow PascalCase naming conventions.
|
|
36
36
|
*
|
|
37
37
|
* @example Simple exported type alias
|