@kubb/renderer-jsx 5.0.0-alpha.33
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 +14 -0
- package/dist/chunk-CErwXX-a.js +28 -0
- package/dist/index.cjs +18090 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +330 -0
- package/dist/index.js +18075 -0
- package/dist/index.js.map +1 -0
- package/dist/jsx-dev-runtime.cjs +11 -0
- package/dist/jsx-dev-runtime.cjs.map +1 -0
- package/dist/jsx-dev-runtime.d.ts +14 -0
- package/dist/jsx-dev-runtime.js +10 -0
- package/dist/jsx-dev-runtime.js.map +1 -0
- package/dist/jsx-namespace-Cx1KMEbe.d.ts +39 -0
- package/dist/jsx-runtime-CeMde2cR.cjs +1503 -0
- package/dist/jsx-runtime-CeMde2cR.cjs.map +1 -0
- package/dist/jsx-runtime-Dmf9wTKR.js +1448 -0
- package/dist/jsx-runtime-Dmf9wTKR.js.map +1 -0
- package/dist/jsx-runtime.cjs +15 -0
- package/dist/jsx-runtime.cjs.map +1 -0
- package/dist/jsx-runtime.d.ts +16 -0
- package/dist/jsx-runtime.js +12 -0
- package/dist/jsx-runtime.js.map +1 -0
- package/dist/types-C7FD9BLg.d.ts +119 -0
- package/dist/types.cjs +0 -0
- package/dist/types.d.ts +2 -0
- package/dist/types.js +1 -0
- package/package.json +121 -0
- package/src/Renderer.ts +184 -0
- package/src/Runtime.tsx +171 -0
- package/src/components/Const.tsx +44 -0
- package/src/components/File.tsx +106 -0
- package/src/components/Function.tsx +107 -0
- package/src/components/Jsx.tsx +34 -0
- package/src/components/Root.tsx +64 -0
- package/src/components/Type.tsx +40 -0
- package/src/context/KubbContext.ts +15 -0
- package/src/context/OasContext.ts +9 -0
- package/src/createRenderer.tsx +32 -0
- package/src/dom.ts +91 -0
- package/src/globals.ts +34 -0
- package/src/index.ts +10 -0
- package/src/jsx-dev-runtime.ts +10 -0
- package/src/jsx-namespace.d.ts +53 -0
- package/src/jsx-runtime.ts +12 -0
- package/src/types.ts +113 -0
- package/src/utils.ts +301 -0
package/src/Renderer.ts
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
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
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
159
|
+
NotPendingTransition: undefined,
|
|
160
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
161
|
+
HostTransitionContext: createContext(null) as unknown as ReactContext<unknown>,
|
|
162
|
+
resetFormInstance() {},
|
|
163
|
+
requestPostPaintCallback() {},
|
|
164
|
+
shouldAttemptEagerTransition() {
|
|
165
|
+
return false
|
|
166
|
+
},
|
|
167
|
+
trackSchedulerEvent() {},
|
|
168
|
+
resolveEventType() {
|
|
169
|
+
return null
|
|
170
|
+
},
|
|
171
|
+
resolveEventTimeStamp() {
|
|
172
|
+
return -1.1
|
|
173
|
+
},
|
|
174
|
+
preloadInstance() {
|
|
175
|
+
return true
|
|
176
|
+
},
|
|
177
|
+
startSuspendingCommit() {},
|
|
178
|
+
suspendInstance() {},
|
|
179
|
+
waitForCommitToBeReady() {
|
|
180
|
+
return null
|
|
181
|
+
},
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
export type { FiberRoot } from 'react-reconciler'
|
package/src/Runtime.tsx
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { onProcessExit } from '@internals/utils'
|
|
2
|
+
import type { FileNode } from '@kubb/ast/types'
|
|
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
|
+
// Unmount when process exits
|
|
70
|
+
this.unsubscribeExit = onProcessExit((code) => {
|
|
71
|
+
this.unmount(code)
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
#renderPromise: Promise<void> = Promise.resolve()
|
|
76
|
+
resolveExitPromise: () => void = () => {}
|
|
77
|
+
rejectExitPromise: (reason?: Error) => void = () => {}
|
|
78
|
+
unsubscribeExit: () => void = () => {}
|
|
79
|
+
|
|
80
|
+
onRender: () => Promise<void> = () => {
|
|
81
|
+
const previous = this.#renderPromise
|
|
82
|
+
|
|
83
|
+
const task = previous
|
|
84
|
+
.catch(() => {})
|
|
85
|
+
.then(async () => {
|
|
86
|
+
if (this.#isUnmounted) {
|
|
87
|
+
return
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const files = await processFiles(this.#rootNode)
|
|
91
|
+
|
|
92
|
+
this.nodes.push(...files)
|
|
93
|
+
|
|
94
|
+
if (!this.#options?.debug) {
|
|
95
|
+
return
|
|
96
|
+
}
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
this.#renderPromise = task.catch((error) => {
|
|
100
|
+
this.onError(error as Error)
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
return this.#renderPromise
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
onError(error: Error): void {
|
|
107
|
+
// Store the error to be thrown after render completes
|
|
108
|
+
this.#renderError = error
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
onExit(error?: Error): void {
|
|
112
|
+
setTimeout(() => {
|
|
113
|
+
this.unmount(error)
|
|
114
|
+
}, 0)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async render(node: KubbReactElement): Promise<void> {
|
|
118
|
+
const props = {
|
|
119
|
+
onExit: this.onExit.bind(this),
|
|
120
|
+
onError: this.onError.bind(this),
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const element = <Root {...props}>{node}</Root>
|
|
124
|
+
|
|
125
|
+
Renderer.updateContainerSync(element, this.#container, null, null)
|
|
126
|
+
Renderer.flushSyncWork()
|
|
127
|
+
await this.#renderPromise
|
|
128
|
+
|
|
129
|
+
// Throw any errors that occurred during rendering
|
|
130
|
+
if (this.#renderError) {
|
|
131
|
+
const error = this.#renderError
|
|
132
|
+
this.#renderError = undefined
|
|
133
|
+
throw error
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
unmount(error?: Error | number | null): void {
|
|
138
|
+
if (this.#isUnmounted) {
|
|
139
|
+
return
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (this.#options?.debug) {
|
|
143
|
+
console.log('Unmount', error)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
this.onRender()
|
|
147
|
+
this.unsubscribeExit()
|
|
148
|
+
|
|
149
|
+
this.#isUnmounted = true
|
|
150
|
+
|
|
151
|
+
Renderer.updateContainerSync(null, this.#container, null, null)
|
|
152
|
+
|
|
153
|
+
if (error instanceof Error) {
|
|
154
|
+
this.rejectExitPromise(error)
|
|
155
|
+
return
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
this.resolveExitPromise()
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async waitUntilExit(): Promise<void> {
|
|
162
|
+
if (!this.exitPromise) {
|
|
163
|
+
this.exitPromise = new Promise((resolve, reject) => {
|
|
164
|
+
this.resolveExitPromise = resolve
|
|
165
|
+
this.rejectExitPromise = reject
|
|
166
|
+
})
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return this.exitPromise
|
|
170
|
+
}
|
|
171
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { JSDoc, Key, KubbReactElement, KubbReactNode } from '../types.ts'
|
|
2
|
+
|
|
3
|
+
export type ConstProps = {
|
|
4
|
+
key?: Key
|
|
5
|
+
/**
|
|
6
|
+
* Name of the const
|
|
7
|
+
*/
|
|
8
|
+
name: string
|
|
9
|
+
/**
|
|
10
|
+
* Does this type need to be exported.
|
|
11
|
+
*/
|
|
12
|
+
export?: boolean
|
|
13
|
+
/**
|
|
14
|
+
* Type to make the const being typed
|
|
15
|
+
*/
|
|
16
|
+
type?: string
|
|
17
|
+
/**
|
|
18
|
+
* Options for JSdocs.
|
|
19
|
+
*/
|
|
20
|
+
JSDoc?: JSDoc
|
|
21
|
+
/**
|
|
22
|
+
* Use of `const` assertions
|
|
23
|
+
*/
|
|
24
|
+
asConst?: boolean
|
|
25
|
+
/**
|
|
26
|
+
* Children nodes.
|
|
27
|
+
*/
|
|
28
|
+
children?: KubbReactNode
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Generates a TypeScript constant declaration.
|
|
33
|
+
*/
|
|
34
|
+
export function Const({ children, ...props }: ConstProps): KubbReactElement {
|
|
35
|
+
const { name, export: canExport, type, JSDoc, asConst } = props
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<kubb-const name={name} type={type} export={canExport} asConst={asConst} JSDoc={JSDoc}>
|
|
39
|
+
{children}
|
|
40
|
+
</kubb-const>
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
Const.displayName = 'Const'
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { ExportNode, ImportNode, SourceNode } from '@kubb/ast/types'
|
|
2
|
+
import type { Key, KubbReactElement, KubbReactNode } from '../types.ts'
|
|
3
|
+
|
|
4
|
+
type BasePropsWithBaseName = {
|
|
5
|
+
/**
|
|
6
|
+
* Name to be used to dynamically create the baseName(based on input.path).
|
|
7
|
+
* Based on UNIX basename
|
|
8
|
+
* @link https://nodejs.org/api/path.html#pathbasenamepath-suffix
|
|
9
|
+
*/
|
|
10
|
+
baseName: `${string}.${string}`
|
|
11
|
+
/**
|
|
12
|
+
* Path will be full qualified path to a specified file.
|
|
13
|
+
*/
|
|
14
|
+
path: string
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
type BasePropsWithoutBaseName = {
|
|
18
|
+
baseName?: never
|
|
19
|
+
/**
|
|
20
|
+
* Path will be full qualified path to a specified file.
|
|
21
|
+
*/
|
|
22
|
+
path?: string
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
type BaseProps = BasePropsWithBaseName | BasePropsWithoutBaseName
|
|
26
|
+
|
|
27
|
+
type Props<TMeta> = BaseProps & {
|
|
28
|
+
key?: Key
|
|
29
|
+
meta?: TMeta
|
|
30
|
+
banner?: string
|
|
31
|
+
footer?: string
|
|
32
|
+
children?: KubbReactNode
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Adds files to the FileManager
|
|
37
|
+
*/
|
|
38
|
+
export function File<TMeta extends object = object>({ children, ...props }: Props<TMeta>): KubbReactElement {
|
|
39
|
+
const { baseName, path } = props
|
|
40
|
+
|
|
41
|
+
if (!baseName || !path) {
|
|
42
|
+
return <>{children}</>
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return <kubb-file {...props}>{children}</kubb-file>
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
File.displayName = 'File'
|
|
49
|
+
|
|
50
|
+
type FileSourceProps = Omit<SourceNode, 'kind' | 'value'> & {
|
|
51
|
+
key?: Key
|
|
52
|
+
children?: KubbReactNode
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* File.Source
|
|
57
|
+
*
|
|
58
|
+
* Marks a block of source text to be associated with the current file when
|
|
59
|
+
* rendering with the FileCollector. Children are treated as the source string.
|
|
60
|
+
*/
|
|
61
|
+
function FileSource({ children, ...props }: FileSourceProps): KubbReactElement {
|
|
62
|
+
const { name, isExportable, isIndexable, isTypeOnly } = props
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<kubb-source name={name} isTypeOnly={isTypeOnly} isExportable={isExportable} isIndexable={isIndexable}>
|
|
66
|
+
{children}
|
|
67
|
+
</kubb-source>
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
FileSource.displayName = 'FileSource'
|
|
72
|
+
|
|
73
|
+
export type FileExportProps = Omit<ExportNode, 'kind'> & { key?: Key }
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* File.Export
|
|
77
|
+
*
|
|
78
|
+
* Declares an export entry for the current file. This will be collected by
|
|
79
|
+
* the FileCollector for later emission.
|
|
80
|
+
*/
|
|
81
|
+
function FileExport(props: FileExportProps): KubbReactElement {
|
|
82
|
+
const { name, path, isTypeOnly, asAlias } = props
|
|
83
|
+
|
|
84
|
+
return <kubb-export name={name} path={path} isTypeOnly={isTypeOnly} asAlias={asAlias} />
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
FileExport.displayName = 'FileExport'
|
|
88
|
+
|
|
89
|
+
export type FileImportProps = Omit<ImportNode, 'kind'> & { key?: Key }
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* File.Import
|
|
93
|
+
*
|
|
94
|
+
* Declares an import entry for the current file.
|
|
95
|
+
*/
|
|
96
|
+
function FileImport(props: FileImportProps): KubbReactElement {
|
|
97
|
+
const { name, root, path, isTypeOnly, isNameSpace } = props
|
|
98
|
+
|
|
99
|
+
return <kubb-import name={name} root={root} path={path} isNameSpace={isNameSpace} isTypeOnly={isTypeOnly} />
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
FileImport.displayName = 'FileImport'
|
|
103
|
+
|
|
104
|
+
File.Export = FileExport
|
|
105
|
+
File.Import = FileImport
|
|
106
|
+
File.Source = FileSource
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import type { JSDoc, Key, KubbReactElement, KubbReactNode } from '../types.ts'
|
|
2
|
+
|
|
3
|
+
type Props = {
|
|
4
|
+
key?: Key
|
|
5
|
+
/**
|
|
6
|
+
* Name of the function.
|
|
7
|
+
*/
|
|
8
|
+
name: string
|
|
9
|
+
/**
|
|
10
|
+
* Add default when export is being used
|
|
11
|
+
*/
|
|
12
|
+
default?: boolean
|
|
13
|
+
/**
|
|
14
|
+
* Parameters/options/props that need to be used.
|
|
15
|
+
*/
|
|
16
|
+
params?: string
|
|
17
|
+
/**
|
|
18
|
+
* Does this function need to be exported.
|
|
19
|
+
*/
|
|
20
|
+
export?: boolean
|
|
21
|
+
/**
|
|
22
|
+
* Does the function has async/promise behavior.
|
|
23
|
+
* This will also add `Promise<returnType>` as the returnType.
|
|
24
|
+
*/
|
|
25
|
+
async?: boolean
|
|
26
|
+
/**
|
|
27
|
+
* Generics that needs to be added for TypeScript.
|
|
28
|
+
*/
|
|
29
|
+
generics?: string | string[]
|
|
30
|
+
/**
|
|
31
|
+
* ReturnType(see async for adding Promise type).
|
|
32
|
+
*/
|
|
33
|
+
returnType?: string
|
|
34
|
+
/**
|
|
35
|
+
* Options for JSdocs.
|
|
36
|
+
*/
|
|
37
|
+
JSDoc?: JSDoc
|
|
38
|
+
/**
|
|
39
|
+
* Children nodes.
|
|
40
|
+
*/
|
|
41
|
+
children?: KubbReactNode
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Generates a TypeScript function declaration.
|
|
46
|
+
*/
|
|
47
|
+
export function Function({ children, ...props }: Props): KubbReactElement {
|
|
48
|
+
const { name, default: isDefault, export: canExport, async: isAsync, generics, params, returnType, JSDoc } = props
|
|
49
|
+
|
|
50
|
+
// Normalize generics array to comma-separated string for DOM attribute storage
|
|
51
|
+
const genericsString = Array.isArray(generics) ? generics.join(', ').trim() : generics
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<kubb-function
|
|
55
|
+
name={name}
|
|
56
|
+
params={params}
|
|
57
|
+
export={canExport}
|
|
58
|
+
default={isDefault}
|
|
59
|
+
async={isAsync}
|
|
60
|
+
generics={genericsString}
|
|
61
|
+
returnType={returnType}
|
|
62
|
+
JSDoc={JSDoc}
|
|
63
|
+
>
|
|
64
|
+
{children}
|
|
65
|
+
</kubb-function>
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
Function.displayName = 'Function'
|
|
70
|
+
|
|
71
|
+
type ArrowFunctionProps = Props & {
|
|
72
|
+
/**
|
|
73
|
+
* Create Arrow function in one line
|
|
74
|
+
*/
|
|
75
|
+
singleLine?: boolean
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* ArrowFunction
|
|
80
|
+
*
|
|
81
|
+
* Renders an arrow function definition. Supports the same flags as `Function`.
|
|
82
|
+
* Use `singleLine` to render the body as a single-line expression.
|
|
83
|
+
*/
|
|
84
|
+
function ArrowFunction({ children, ...props }: ArrowFunctionProps) {
|
|
85
|
+
const { name, default: isDefault, export: canExport, async, generics, params, returnType, JSDoc, singleLine } = props
|
|
86
|
+
|
|
87
|
+
const genericsString = Array.isArray(generics) ? generics.join(', ').trim() : generics
|
|
88
|
+
|
|
89
|
+
return (
|
|
90
|
+
<kubb-arrow-function
|
|
91
|
+
name={name}
|
|
92
|
+
params={params}
|
|
93
|
+
export={canExport}
|
|
94
|
+
default={isDefault}
|
|
95
|
+
async={async}
|
|
96
|
+
generics={genericsString}
|
|
97
|
+
returnType={returnType}
|
|
98
|
+
singleLine={singleLine}
|
|
99
|
+
JSDoc={JSDoc}
|
|
100
|
+
>
|
|
101
|
+
{children}
|
|
102
|
+
</kubb-arrow-function>
|
|
103
|
+
)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
ArrowFunction.displayName = 'ArrowFunction'
|
|
107
|
+
Function.Arrow = ArrowFunction
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { KubbReactElement } from '../types.ts'
|
|
2
|
+
|
|
3
|
+
type Props = {
|
|
4
|
+
/**
|
|
5
|
+
* Raw JSX string to embed verbatim in the generated code.
|
|
6
|
+
* Supports JSX fragments (`<>…</>`), elements, and any valid JSX syntax.
|
|
7
|
+
* @example
|
|
8
|
+
* ```tsx
|
|
9
|
+
* <Jsx>{'<>\n <a href={href}>Open</a>\n</>'}</Jsx>
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
children?: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Embeds a raw JSX string verbatim in the generated source code.
|
|
17
|
+
*
|
|
18
|
+
* Use this component when you need to include JSX markup (including fragments
|
|
19
|
+
* `<>…</>`) in the body of a generated function or component. The `children`
|
|
20
|
+
* prop must be a plain string — expression attributes that reference runtime
|
|
21
|
+
* values should be written as template literals.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```tsx
|
|
25
|
+
* <Function name="MyComponent" export>
|
|
26
|
+
* <Jsx>{'return (\n <>\n <div>Hello</div>\n </>\n)'}</Jsx>
|
|
27
|
+
* </Function>
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export function Jsx({ children }: Props): KubbReactElement {
|
|
31
|
+
return <kubb-jsx>{children}</kubb-jsx>
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
Jsx.displayName = 'Jsx'
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Component } from 'react'
|
|
2
|
+
import type { KubbReactElement, KubbReactNode } from '../types.ts'
|
|
3
|
+
|
|
4
|
+
type ErrorBoundaryProps = {
|
|
5
|
+
onError: (error: Error) => void
|
|
6
|
+
children?: KubbReactNode
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
class ErrorBoundary extends Component<{
|
|
10
|
+
onError: ErrorBoundaryProps['onError']
|
|
11
|
+
children?: KubbReactNode
|
|
12
|
+
}> {
|
|
13
|
+
state = { hasError: false }
|
|
14
|
+
|
|
15
|
+
static displayName = 'ErrorBoundary'
|
|
16
|
+
static getDerivedStateFromError(_error: Error) {
|
|
17
|
+
return { hasError: true }
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
componentDidCatch(error: Error) {
|
|
21
|
+
if (error) {
|
|
22
|
+
this.props.onError(error)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
render() {
|
|
27
|
+
if (this.state.hasError) {
|
|
28
|
+
return null
|
|
29
|
+
}
|
|
30
|
+
return this.props.children
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export type RootProps = {
|
|
35
|
+
/**
|
|
36
|
+
* Exit (unmount) the whole app.
|
|
37
|
+
*/
|
|
38
|
+
onExit: (error?: Error) => void
|
|
39
|
+
/**
|
|
40
|
+
* Error hook receiving runtime exceptions.
|
|
41
|
+
*/
|
|
42
|
+
onError: (error: Error) => void
|
|
43
|
+
/**
|
|
44
|
+
* Children nodes.
|
|
45
|
+
*/
|
|
46
|
+
children?: KubbReactNode
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* This component provides the root behavior for the Kubb runtime.
|
|
51
|
+
*/
|
|
52
|
+
export function Root({ onError, children }: RootProps): KubbReactElement {
|
|
53
|
+
return (
|
|
54
|
+
<ErrorBoundary
|
|
55
|
+
onError={(error) => {
|
|
56
|
+
onError(error)
|
|
57
|
+
}}
|
|
58
|
+
>
|
|
59
|
+
{children}
|
|
60
|
+
</ErrorBoundary>
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
Root.displayName = 'Root'
|