@kubb/renderer-jsx 5.0.0-beta.7 → 5.0.0-beta.70

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.
@@ -1,168 +0,0 @@
1
- import { n as __name } from "./chunk-Bb7HlUDG.js";
2
- import { ArrowFunctionNode, ConstNode, ExportNode, FileNode, FunctionNode, ImportNode, SourceNode, TypeNode } from "@kubb/ast";
3
- import React, { JSX, ReactNode } from "react";
4
-
5
- //#region src/types.d.ts
6
- /**
7
- * Unique identifier for a React element in lists or conditional renders.
8
- */
9
- type Key = string | number | bigint;
10
- /**
11
- * Custom element names recognized by the Kubb JSX renderer.
12
- * Each name maps to a corresponding AST node type in the generated code.
13
- */
14
- type ElementNames = 'br' | 'div' | 'indent' | 'dedent' | 'kubb-jsx' | 'kubb-text' | 'kubb-file' | 'kubb-source' | 'kubb-import' | 'kubb-export' | 'kubb-function' | 'kubb-arrow-function' | 'kubb-const' | 'kubb-type' | 'kubb-root' | 'kubb-app';
15
- type Node = {
16
- parentNode: DOMElement | undefined;
17
- internal_static?: boolean;
18
- };
19
- /**
20
- * Allowed attribute value types for DOM elements.
21
- */
22
- type DOMNodeAttribute = boolean | string | number | Record<string, unknown> | Array<unknown>;
23
- type TextName = '#text';
24
- /**
25
- * Leaf DOM node containing raw text.
26
- */
27
- type TextNode = {
28
- nodeName: TextName;
29
- nodeValue: string;
30
- } & Node;
31
- /**
32
- * Virtual DOM node — either a text node or a named element.
33
- */
34
- type DOMNode<T = {
35
- nodeName: NodeNames;
36
- }> = T extends {
37
- nodeName: infer U;
38
- } ? U extends '#text' ? TextNode : DOMElement : never;
39
- type OutputTransformer = (s: string, index: number) => string;
40
- /**
41
- * Named element in the Kubb virtual DOM tree.
42
- * Stores attributes, child nodes, and lifecycle callbacks for rendering.
43
- */
44
- type DOMElement = {
45
- nodeName: ElementNames;
46
- /**
47
- * Key/value attributes passed as JSX props to this element.
48
- */
49
- attributes: Map<string, DOMNodeAttribute>;
50
- /**
51
- * Ordered list of child nodes attached to this element.
52
- */
53
- childNodes: DOMNode[];
54
- internal_transform?: OutputTransformer;
55
- isStaticDirty?: boolean;
56
- staticNode?: DOMElement;
57
- onComputeLayout?: () => void;
58
- onRender?: () => void;
59
- onImmediateRender?: () => void;
60
- } & Node;
61
- type NodeNames = ElementNames | TextName;
62
- /**
63
- * React node type for Kubb JSX components.
64
- */
65
- type KubbReactNode = ReactNode;
66
- /**
67
- * React element type returned by Kubb JSX components.
68
- */
69
- type KubbReactElement = JSX.Element;
70
- /**
71
- * Props for the `<kubb-jsx>` element.
72
- * Embeds a raw JSX string verbatim in generated output.
73
- */
74
- type KubbJsxProps = {
75
- children?: string;
76
- };
77
- /**
78
- * Props for the `<kubb-text>` element.
79
- * Wraps React children as plain text in the output.
80
- */
81
- type KubbTextProps = {
82
- children?: KubbReactNode;
83
- };
84
- /**
85
- * Props for the `<kubb-file>` element.
86
- * Represents a generated file.
87
- */
88
- type KubbFileProps = {
89
- id?: string;
90
- children?: KubbReactNode;
91
- baseName: string;
92
- path: string;
93
- override?: boolean;
94
- meta?: FileNode['meta'];
95
- };
96
- /**
97
- * Props for the `<kubb-source>` element.
98
- * Marks a block of source text associated with a file.
99
- */
100
- type KubbSourceProps = Omit<SourceNode, 'kind'> & {
101
- children?: KubbReactNode;
102
- };
103
- /**
104
- * Props for the `<kubb-import>` element.
105
- * Declares an import statement in the generated file.
106
- */
107
- type KubbImportProps = Omit<ImportNode, 'kind'> & {};
108
- /**
109
- * Props for the `<kubb-export>` element.
110
- * Declares an export statement in the generated file.
111
- */
112
- type KubbExportProps = Omit<ExportNode, 'kind'> & {};
113
- /**
114
- * Props for the `<kubb-function>` element.
115
- * Generates a function declaration.
116
- */
117
- type KubbFunctionProps = Omit<FunctionNode, 'kind'> & {
118
- children?: KubbReactNode;
119
- };
120
- /**
121
- * Props for the `<kubb-arrow-function>` element.
122
- * Generates an arrow function declaration.
123
- */
124
- type KubbArrowFunctionProps = Omit<ArrowFunctionNode, 'kind'> & {
125
- children?: KubbReactNode;
126
- };
127
- /**
128
- * Props for the `<kubb-const>` element.
129
- * Generates a constant declaration.
130
- */
131
- type KubbConstProps = Omit<ConstNode, 'kind'> & {
132
- children?: KubbReactNode;
133
- };
134
- /**
135
- * Props for the `<kubb-type>` element.
136
- * Generates a TypeScript type alias declaration.
137
- */
138
- type KubbTypeProps = Omit<TypeNode, 'kind'> & {
139
- children?: KubbReactNode;
140
- };
141
- /**
142
- * Props for the HTML `<br>` element.
143
- */
144
- type LineBreakProps = React.DetailedHTMLProps<React.HTMLAttributes<HTMLBRElement>, HTMLBRElement>;
145
- /**
146
- * JSDoc comment block to attach to a generated declaration.
147
- * Each string in `comments` becomes one line inside the `/** … *\/` block.
148
- *
149
- * @example
150
- * ```ts
151
- * { comments: ['@description A pet object.', '@deprecated Use PetV2 instead.'] }
152
- * // Emits:
153
- * // /**
154
- * // * @description A pet object.
155
- * // * @deprecated Use PetV2 instead.
156
- * // *\/
157
- * ```
158
- */
159
- type JSDoc = {
160
- /**
161
- * Lines to emit inside the JSDoc block, in source order.
162
- * Use standard JSDoc tags such as `@description`, `@deprecated`, `@see`, etc.
163
- */
164
- comments: Array<string>;
165
- };
166
- //#endregion
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-nAFMiWFw.d.ts.map
package/src/Renderer.ts DELETED
@@ -1,182 +0,0 @@
1
- import { createContext } from 'react'
2
- import Reconciler, { type ReactContext } from 'react-reconciler'
3
- import { DefaultEventPriority, NoEventPriority } from 'react-reconciler/constants.js'
4
- import { appendChildNode, createNode, createTextNode, insertBeforeNode, removeChildNode, setAttribute, setTextNodeValue } from './dom.ts'
5
- import type { KubbReactNode } from './types'
6
- import type { DOMElement, DOMNodeAttribute, ElementNames, TextNode } from './types.ts'
7
-
8
- declare module 'react-reconciler' {
9
- // @ts-expect-error custom override
10
- interface Reconciler {
11
- updateContainerSync(element: KubbReactNode, container: unknown, parentComponent: any, callback?: null | (() => void)): void
12
- flushSyncWork(): void
13
- createContainer(
14
- containerInfo: unknown,
15
- tag: Reconciler.RootTag,
16
- hydrationCallbacks: null | Reconciler.SuspenseHydrationCallbacks<any>,
17
- isStrictMode: boolean,
18
- concurrentUpdatesByDefaultOverride: null | boolean,
19
- identifierPrefix: string,
20
- onUncaughtError: (error: Error) => void,
21
- onCaughtError: (error: Error) => void,
22
- onRecoverableError: (error: Error) => void,
23
- transitionCallbacks: null | Reconciler.TransitionTracingCallbacks,
24
- ): Reconciler.OpaqueRoot
25
- }
26
- }
27
-
28
- type Props = Record<string, unknown>
29
-
30
- type HostContext = {
31
- type: ElementNames
32
- isFile: boolean
33
- isSource: boolean
34
- }
35
-
36
- let currentUpdatePriority = NoEventPriority
37
-
38
- /**
39
- * @link https://www.npmjs.com/package/react-devtools-inline
40
- * @link https://github.com/nitin42/Making-a-custom-React-renderer/blob/master/part-one.md
41
- * @link https://github.com/facebook/react/tree/main/packages/react-reconciler#practical-examples
42
- * @link https://github.com/vadimdemedes/ink
43
- * @link https://github.com/pixijs/pixi-react/tree/main/packages
44
- * @link https://github.com/diegomura/react-pdf/blob/master/packages/reconciler/src/reconciler-31.ts
45
- */
46
- export const Renderer = Reconciler({
47
- getRootHostContext: () => ({
48
- type: 'kubb-root',
49
- isFile: false,
50
- isSource: false,
51
- }),
52
- prepareForCommit: () => {
53
- return null
54
- },
55
- preparePortalMount: () => null,
56
- clearContainer: () => false,
57
- resetAfterCommit(rootNode: DOMElement) {
58
- if (typeof rootNode.onRender === 'function') {
59
- rootNode.onRender()
60
- }
61
- },
62
- getChildHostContext(parentHostContext: HostContext, type: ElementNames) {
63
- const isInsideText = type === 'kubb-text'
64
- const isFile = type === 'kubb-file' || parentHostContext.isFile
65
- const isSource = type === 'kubb-source' || parentHostContext.isSource
66
-
67
- return { isInsideText, isFile, isSource, type }
68
- },
69
- shouldSetTextContent: () => false,
70
- createInstance(originalType: ElementNames, newProps: Props, _root: DOMElement) {
71
- const node = createNode(originalType)
72
-
73
- for (const [key, value] of Object.entries(newProps)) {
74
- if (key === 'children') {
75
- continue
76
- }
77
-
78
- // Skip undefined values to match React's behavior
79
- if (value !== undefined) {
80
- setAttribute(node, key, value as DOMNodeAttribute)
81
- }
82
- }
83
-
84
- return node
85
- },
86
- createTextInstance(text: string, _root: DOMElement, hostContext: HostContext) {
87
- if (hostContext.isFile && !hostContext.isSource) {
88
- throw new Error(`[react] '${text}' should be part of <File.Source> component when using the <File/> component`)
89
- }
90
-
91
- return createTextNode(text)
92
- },
93
- resetTextContent() {},
94
- hideTextInstance(node: TextNode) {
95
- setTextNodeValue(node, '')
96
- },
97
- unhideTextInstance(node: TextNode, text: string) {
98
- setTextNodeValue(node, text)
99
- },
100
- getPublicInstance: (instance) => instance,
101
- appendInitialChild: appendChildNode,
102
- appendChild: appendChildNode,
103
- insertBefore: insertBeforeNode,
104
- finalizeInitialChildren(_node, _type, _props, _rootNode) {
105
- return false
106
- },
107
- supportsMutation: true,
108
- isPrimaryRenderer: true,
109
- supportsPersistence: false,
110
- supportsHydration: false,
111
- scheduleTimeout: setTimeout,
112
- cancelTimeout: clearTimeout,
113
- noTimeout: -1,
114
- beforeActiveInstanceBlur() {},
115
- afterActiveInstanceBlur() {},
116
- detachDeletedInstance() {},
117
- getInstanceFromNode: () => null,
118
- prepareScopeUpdate() {},
119
- getInstanceFromScope: () => null,
120
- appendChildToContainer: appendChildNode,
121
- insertInContainerBefore: insertBeforeNode,
122
- removeChildFromContainer(node: DOMElement, removeNode: TextNode) {
123
- removeChildNode(node, removeNode)
124
- },
125
- commitMount() {},
126
- commitUpdate(node: DOMElement, _payload, _type, _oldProps: Props, newProps: Props) {
127
- const { props } = newProps
128
-
129
- if (props) {
130
- for (const [key, value] of Object.entries(props)) {
131
- // Skip undefined values to match React's behavior
132
- if (value !== undefined) {
133
- setAttribute(node, key, value as DOMNodeAttribute)
134
- }
135
- }
136
- }
137
- },
138
- commitTextUpdate(node: TextNode, _oldText, newText) {
139
- setTextNodeValue(node, newText)
140
- },
141
- removeChild(node: DOMElement, removeNode: TextNode) {
142
- removeChildNode(node, removeNode)
143
- },
144
- setCurrentUpdatePriority: (newPriority: number) => {
145
- currentUpdatePriority = newPriority
146
- },
147
- getCurrentUpdatePriority: () => currentUpdatePriority,
148
- resolveUpdatePriority() {
149
- if (currentUpdatePriority !== NoEventPriority) {
150
- return currentUpdatePriority
151
- }
152
-
153
- return DefaultEventPriority
154
- },
155
- maySuspendCommit() {
156
- return false
157
- },
158
- NotPendingTransition: undefined,
159
- HostTransitionContext: createContext(null) as unknown as ReactContext<unknown>,
160
- resetFormInstance() {},
161
- requestPostPaintCallback() {},
162
- shouldAttemptEagerTransition() {
163
- return false
164
- },
165
- trackSchedulerEvent() {},
166
- resolveEventType() {
167
- return null
168
- },
169
- resolveEventTimeStamp() {
170
- return -1.1
171
- },
172
- preloadInstance() {
173
- return true
174
- },
175
- startSuspendingCommit() {},
176
- suspendInstance() {},
177
- waitForCommitToBeReady() {
178
- return null
179
- },
180
- })
181
-
182
- export type { FiberRoot } from 'react-reconciler'
package/src/Runtime.tsx DELETED
@@ -1,159 +0,0 @@
1
- import { onProcessExit } from '@internals/utils'
2
- import type { FileNode } from '@kubb/ast'
3
- import { ConcurrentRoot } from 'react-reconciler/constants.js'
4
- import { Root } from './components/Root.tsx'
5
- import { createNode } from './dom.ts'
6
- import type { FiberRoot } from './Renderer.ts'
7
- import { Renderer } from './Renderer.ts'
8
- import type { DOMElement, KubbReactElement } from './types.ts'
9
- import { processFiles } from './utils.ts'
10
-
11
- type Options = {
12
- /**
13
- * Set this to true to always see the result of the render in the console(line per render)
14
- */
15
- debug?: boolean
16
- }
17
-
18
- export class Runtime {
19
- readonly #options: Options
20
- #isUnmounted: boolean
21
- #renderError?: Error
22
-
23
- exitPromise?: Promise<void>
24
-
25
- nodes: FileNode[] = []
26
- readonly #container: FiberRoot
27
- readonly #rootNode: DOMElement
28
-
29
- constructor(options: Options) {
30
- this.#options = options
31
- this.#rootNode = createNode('kubb-root')
32
- this.#rootNode.onRender = this.onRender
33
- this.#rootNode.onImmediateRender = this.onRender
34
- this.#isUnmounted = false
35
- this.unmount.bind(this)
36
-
37
- // Intercept noisy React errors
38
- console.error = (data: string | Error) => {
39
- const message = typeof data === 'string' ? data : data?.message
40
- if (
41
- message?.match(/Encountered two children with the same key/gi) ||
42
- message?.match(/React will try to recreat/gi) ||
43
- message?.match(/Each child in a list should have a unique/gi) ||
44
- message?.match(/The above error occurred in the <KubbErrorBoundary/gi) ||
45
- message?.match(/A React Element from an older version of React was render/gi)
46
- ) {
47
- return
48
- }
49
- console.log(data)
50
- }
51
-
52
- const logRecoverableError = typeof reportError === 'function' ? reportError : console.error
53
-
54
- const rootTag = ConcurrentRoot
55
- this.#container = Renderer.createContainer(
56
- this.#rootNode,
57
- rootTag,
58
- null,
59
- false,
60
- false,
61
- 'id',
62
- logRecoverableError,
63
- logRecoverableError,
64
- logRecoverableError,
65
- null,
66
- )
67
-
68
- // Unmount when process exits
69
- this.unsubscribeExit = onProcessExit((code) => {
70
- this.unmount(code)
71
- })
72
- }
73
-
74
- #renderPromise: Promise<void> = Promise.resolve()
75
- resolveExitPromise: () => void = () => {}
76
- rejectExitPromise: (reason?: Error) => void = () => {}
77
- unsubscribeExit: () => void = () => {}
78
-
79
- onRender: () => Promise<void> = () => {
80
- const previous = this.#renderPromise
81
-
82
- const task = previous
83
- .catch(() => {})
84
- .then(() => {
85
- if (this.#isUnmounted) {
86
- return
87
- }
88
-
89
- const files = processFiles(this.#rootNode)
90
-
91
- this.nodes.push(...files)
92
-
93
- if (!this.#options?.debug) {
94
- return
95
- }
96
- })
97
-
98
- this.#renderPromise = task.catch((error) => {
99
- this.onError(error as Error)
100
- })
101
-
102
- return this.#renderPromise
103
- }
104
-
105
- onError(error: Error): void {
106
- // Store the error to be thrown after render completes
107
- this.#renderError = error
108
- }
109
-
110
- onExit(error?: Error): void {
111
- setTimeout(() => {
112
- this.unmount(error)
113
- }, 0)
114
- }
115
-
116
- async render(node: KubbReactElement): Promise<void> {
117
- const props = {
118
- onExit: this.onExit.bind(this),
119
- onError: this.onError.bind(this),
120
- }
121
-
122
- const element = <Root {...props}>{node}</Root>
123
-
124
- Renderer.updateContainerSync(element, this.#container, null, null)
125
- Renderer.flushSyncWork()
126
- await this.#renderPromise
127
-
128
- // Throw any errors that occurred during rendering
129
- if (this.#renderError) {
130
- const error = this.#renderError
131
- this.#renderError = undefined
132
- throw error
133
- }
134
- }
135
-
136
- unmount(error?: Error | number | null): void {
137
- if (this.#isUnmounted) {
138
- return
139
- }
140
-
141
- if (this.#options?.debug) {
142
- console.log('Unmount', error)
143
- }
144
-
145
- this.onRender()
146
- this.unsubscribeExit()
147
-
148
- this.#isUnmounted = true
149
-
150
- Renderer.updateContainerSync(null, this.#container, null, null)
151
-
152
- if (error instanceof Error) {
153
- this.rejectExitPromise(error)
154
- return
155
- }
156
-
157
- this.resolveExitPromise()
158
- }
159
- }
@@ -1,72 +0,0 @@
1
- import type { JSDoc, Key, KubbReactElement, KubbReactNode } from '../types.ts'
2
-
3
- type ConstProps = {
4
- key?: Key
5
- /**
6
- * Identifier of the generated constant declaration.
7
- *
8
- * @example
9
- * `name: 'petSchema'`
10
- */
11
- name: string
12
- /**
13
- * Emit the `export` keyword before the `const` declaration.
14
- * - `true` generates `export const name = …`
15
- * - `false` generates `const name = …`
16
- * @default false
17
- */
18
- export?: boolean
19
- /**
20
- * TypeScript type annotation for the constant, written verbatim after `const name:`.
21
- *
22
- * @example
23
- * `type: 'Pet'` → `const pet: Pet = …`
24
- */
25
- type?: string
26
- /**
27
- * JSDoc block to prepend to the constant declaration.
28
- * Each entry in `comments` becomes one line inside the emitted `/** … *\/` block.
29
- */
30
- JSDoc?: JSDoc
31
- /**
32
- * Append `as const` after the initialiser, enabling TypeScript const assertions.
33
- * - `true` generates `const name = … as const`
34
- * - `false` generates `const name = …`
35
- * @default false
36
- */
37
- asConst?: boolean
38
- /**
39
- * Child nodes rendered as the initialiser expression of the constant.
40
- */
41
- children?: KubbReactNode
42
- }
43
-
44
- /**
45
- * Generates a TypeScript constant declaration.
46
- *
47
- * @example Named export with type annotation
48
- * ```tsx
49
- * <Const export name="petSchema" type="z.ZodType<Pet>">
50
- * {`z.object({ id: z.number() })`}
51
- * </Const>
52
- * // export const petSchema: z.ZodType<Pet> = z.object({ id: z.number() })
53
- * ```
54
- *
55
- * @example With JSDoc and const assertion
56
- * ```tsx
57
- * <Const name="HTTP_METHODS" asConst JSDoc={{ comments: ['@description Supported HTTP methods.'] }}>
58
- * {`['GET', 'POST', 'PUT', 'DELETE']`}
59
- * </Const>
60
- * ```
61
- */
62
- export function Const({ children, ...props }: ConstProps): KubbReactElement {
63
- const { name, export: canExport, type, JSDoc, asConst } = props
64
-
65
- return (
66
- <kubb-const name={name} type={type} export={canExport} asConst={asConst} JSDoc={JSDoc}>
67
- {children}
68
- </kubb-const>
69
- )
70
- }
71
-
72
- Const.displayName = 'Const'