@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.
Files changed (45) hide show
  1. package/LICENSE +17 -10
  2. package/README.md +134 -0
  3. package/dist/chunk-C0LytTxp.js +8 -0
  4. package/dist/index.cjs +386 -17922
  5. package/dist/index.d.ts +232 -147
  6. package/dist/index.js +370 -17903
  7. package/dist/jsx-dev-runtime.cjs +3 -10
  8. package/dist/jsx-dev-runtime.d.ts +4 -8
  9. package/dist/jsx-dev-runtime.js +1 -9
  10. package/dist/jsx-runtime-3ncySO6L.cjs +89 -0
  11. package/dist/jsx-runtime.cjs +5 -14
  12. package/dist/jsx-runtime.d.ts +60 -10
  13. package/dist/jsx-runtime.js +24 -7
  14. package/dist/types-UI1cZVah.d.ts +115 -0
  15. package/dist/types.d.ts +2 -2
  16. package/package.json +6 -29
  17. package/src/SyncRuntime.tsx +298 -0
  18. package/src/components/Callout.tsx +59 -0
  19. package/src/components/Const.tsx +4 -4
  20. package/src/components/File.tsx +7 -5
  21. package/src/components/Frontmatter.tsx +38 -0
  22. package/src/components/Function.tsx +8 -8
  23. package/src/components/Heading.tsx +34 -0
  24. package/src/components/Jsx.tsx +1 -1
  25. package/src/components/List.tsx +40 -0
  26. package/src/components/Paragraph.tsx +28 -0
  27. package/src/components/Type.tsx +3 -3
  28. package/src/constants.ts +9 -28
  29. package/src/createRenderer.tsx +38 -75
  30. package/src/globals.ts +14 -6
  31. package/src/index.ts +6 -3
  32. package/src/jsx-dev-runtime.ts +1 -3
  33. package/src/jsx-namespace.d.ts +21 -13
  34. package/src/jsx-runtime.ts +22 -6
  35. package/src/types.ts +16 -100
  36. package/dist/chunk-Bb7HlUDG.js +0 -28
  37. package/dist/jsx-namespace-CNp0arTN.d.ts +0 -39
  38. package/dist/jsx-runtime-Cvu_ZYgL.js +0 -1448
  39. package/dist/jsx-runtime-DdmO3p0U.cjs +0 -1503
  40. package/dist/types-nAFMiWFw.d.ts +0 -168
  41. package/src/Renderer.ts +0 -184
  42. package/src/Runtime.tsx +0 -170
  43. package/src/components/Root.tsx +0 -70
  44. package/src/dom.ts +0 -105
  45. 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'
@@ -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
  */
@@ -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 the component renders its children inline.
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'
@@ -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 expression attributes that reference runtime
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'
@@ -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 TypeScript type aliases
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