@kubb/react-fabric 0.0.0-canary-20251020201500
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 +21 -0
- package/README.md +52 -0
- package/dist/devtools.cjs +10817 -0
- package/dist/devtools.cjs.map +1 -0
- package/dist/devtools.d.cts +1 -0
- package/dist/devtools.d.ts +1 -0
- package/dist/devtools.js +10817 -0
- package/dist/devtools.js.map +1 -0
- package/dist/globals-8sJ940pg.cjs +0 -0
- package/dist/globals-C6rGETh5.d.ts +166 -0
- package/dist/globals-CnATk-Sl.d.cts +166 -0
- package/dist/globals-Df5klKjG.js +1 -0
- package/dist/globals.cjs +1 -0
- package/dist/globals.d.cts +2 -0
- package/dist/globals.d.ts +2 -0
- package/dist/globals.js +3 -0
- package/dist/index.cjs +15924 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +331 -0
- package/dist/index.d.ts +331 -0
- package/dist/index.js +15899 -0
- package/dist/index.js.map +1 -0
- package/dist/jsx-dev-runtime.cjs +9 -0
- package/dist/jsx-dev-runtime.d.cts +13 -0
- package/dist/jsx-dev-runtime.d.ts +13 -0
- package/dist/jsx-dev-runtime.js +6 -0
- package/dist/jsx-runtime-B3MMb3PL.cjs +233 -0
- package/dist/jsx-runtime-B3MMb3PL.cjs.map +1 -0
- package/dist/jsx-runtime-BPQkRAg2.js +228 -0
- package/dist/jsx-runtime-BPQkRAg2.js.map +1 -0
- package/dist/jsx-runtime-DmD5u6a-.js +13 -0
- package/dist/jsx-runtime-DmD5u6a-.js.map +1 -0
- package/dist/jsx-runtime-zKfRQHQD.cjs +36 -0
- package/dist/jsx-runtime-zKfRQHQD.cjs.map +1 -0
- package/dist/jsx-runtime.cjs +9 -0
- package/dist/jsx-runtime.js +6 -0
- package/dist/react-BBkwFtZV.js +1138 -0
- package/dist/react-BBkwFtZV.js.map +1 -0
- package/dist/react-Bq0UOw6S.cjs +1156 -0
- package/dist/react-Bq0UOw6S.cjs.map +1 -0
- package/dist/types-C3p0Ljxf.d.cts +85 -0
- package/dist/types-DEroxUW0.d.ts +85 -0
- package/dist/types.cjs +0 -0
- package/dist/types.d.cts +2 -0
- package/dist/types.d.ts +2 -0
- package/dist/types.js +1 -0
- package/package.json +115 -0
- package/src/ReactTemplate.tsx +229 -0
- package/src/components/App.tsx +27 -0
- package/src/components/Const.tsx +53 -0
- package/src/components/File.tsx +100 -0
- package/src/components/Function.tsx +139 -0
- package/src/components/Indent.tsx +53 -0
- package/src/components/Root.tsx +75 -0
- package/src/components/Type.tsx +40 -0
- package/src/createApp.ts +23 -0
- package/src/devtools.ts +118 -0
- package/src/dom.ts +75 -0
- package/src/globals.ts +52 -0
- package/src/hooks/useApp.ts +15 -0
- package/src/hooks/useFile.ts +14 -0
- package/src/hooks/useLifecycle.tsx +18 -0
- package/src/index.ts +24 -0
- package/src/jsx-runtime.ts +8 -0
- package/src/kubbRenderer.ts +175 -0
- package/src/types.ts +53 -0
- package/src/utils/createJSDoc.ts +9 -0
- package/src/utils/getFunctionParams.ts +236 -0
- package/src/utils/processFiles.ts +44 -0
- package/src/utils/squashExportNodes.ts +23 -0
- package/src/utils/squashImportNodes.ts +23 -0
- package/src/utils/squashSourceNodes.ts +40 -0
- package/src/utils/squashTextNodes.ts +82 -0
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import process from 'node:process'
|
|
2
|
+
import type { AppContext } from '@kubb/fabric-core'
|
|
3
|
+
import type { ReactNode } from 'react'
|
|
4
|
+
import { ConcurrentRoot } from 'react-reconciler/constants'
|
|
5
|
+
import { onExit } from 'signal-exit'
|
|
6
|
+
import { Root } from './components/Root.tsx'
|
|
7
|
+
import { createNode } from './dom.ts'
|
|
8
|
+
import type { FiberRoot } from './kubbRenderer.ts'
|
|
9
|
+
import { KubbRenderer } from './kubbRenderer.ts'
|
|
10
|
+
import type { DOMElement } from './types.ts'
|
|
11
|
+
import { squashTextNodes } from './utils/squashTextNodes.ts'
|
|
12
|
+
import { processFiles } from './utils/processFiles.ts'
|
|
13
|
+
|
|
14
|
+
export type ReactTemplateOptions = {
|
|
15
|
+
context: AppContext
|
|
16
|
+
stdout?: NodeJS.WriteStream
|
|
17
|
+
stdin?: NodeJS.ReadStream
|
|
18
|
+
stderr?: NodeJS.WriteStream
|
|
19
|
+
/**
|
|
20
|
+
* Set this to true to always see the result of the render in the console(line per render)
|
|
21
|
+
*/
|
|
22
|
+
debug?: boolean
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export class ReactTemplate {
|
|
26
|
+
readonly #options: ReactTemplateOptions
|
|
27
|
+
// Ignore last render after unmounting a tree to prevent empty output before exit
|
|
28
|
+
#isUnmounted: boolean
|
|
29
|
+
|
|
30
|
+
exitPromise?: Promise<void>
|
|
31
|
+
readonly #container: FiberRoot
|
|
32
|
+
readonly #rootNode: DOMElement
|
|
33
|
+
|
|
34
|
+
constructor(options: ReactTemplateOptions) {
|
|
35
|
+
this.#options = { ...options }
|
|
36
|
+
|
|
37
|
+
this.#rootNode = createNode('kubb-root')
|
|
38
|
+
this.#rootNode.onRender = this.onRender
|
|
39
|
+
this.#rootNode.onImmediateRender = this.onRender
|
|
40
|
+
|
|
41
|
+
// Ignore last render after unmounting a tree to prevent empty output before exit
|
|
42
|
+
this.#isUnmounted = false
|
|
43
|
+
this.unmount.bind(this)
|
|
44
|
+
|
|
45
|
+
const originalError = console.error
|
|
46
|
+
console.error = (data: string | Error) => {
|
|
47
|
+
const message = typeof data === 'string' ? data : data?.message
|
|
48
|
+
|
|
49
|
+
if (message.match(/Encountered two children with the same key/gi)) {
|
|
50
|
+
return
|
|
51
|
+
}
|
|
52
|
+
if (message.match(/React will try to recreat/gi)) {
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
if (message.match(/Each child in a list should have a unique/gi)) {
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
if (message.match(/The above error occurred in the <KubbErrorBoundary/gi)) {
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (message.match(/A React Element from an older version of React was render/gi)) {
|
|
63
|
+
return
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
originalError(data)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Report when an error was detected in a previous render
|
|
70
|
+
// https://github.com/pmndrs/react-three-fiber/pull/2261
|
|
71
|
+
const logRecoverableError =
|
|
72
|
+
typeof reportError === 'function'
|
|
73
|
+
? // In modern browsers, reportError will dispatch an error event,
|
|
74
|
+
// emulating an uncaught JavaScript error.
|
|
75
|
+
reportError
|
|
76
|
+
: // In older browsers and test environments, fallback to console.error.
|
|
77
|
+
console.error
|
|
78
|
+
|
|
79
|
+
const rootTag = ConcurrentRoot
|
|
80
|
+
const hydrationCallbacks = null
|
|
81
|
+
const isStrictMode = false
|
|
82
|
+
const concurrentUpdatesByDefaultOverride = false
|
|
83
|
+
const identifierPrefix = 'id'
|
|
84
|
+
const onUncaughtError = logRecoverableError
|
|
85
|
+
const onCaughtError = logRecoverableError
|
|
86
|
+
const onRecoverableError = logRecoverableError
|
|
87
|
+
const transitionCallbacks = null
|
|
88
|
+
|
|
89
|
+
this.#container = KubbRenderer.createContainer(
|
|
90
|
+
this.#rootNode,
|
|
91
|
+
rootTag,
|
|
92
|
+
hydrationCallbacks,
|
|
93
|
+
isStrictMode,
|
|
94
|
+
concurrentUpdatesByDefaultOverride,
|
|
95
|
+
identifierPrefix,
|
|
96
|
+
onUncaughtError,
|
|
97
|
+
onCaughtError,
|
|
98
|
+
onRecoverableError,
|
|
99
|
+
transitionCallbacks,
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
// Unmount when process exits
|
|
103
|
+
this.unsubscribeExit = onExit(
|
|
104
|
+
(code) => {
|
|
105
|
+
this.unmount(code)
|
|
106
|
+
},
|
|
107
|
+
{ alwaysLast: false },
|
|
108
|
+
).bind(this)
|
|
109
|
+
|
|
110
|
+
KubbRenderer.injectIntoDevTools({
|
|
111
|
+
bundleType: 0, // 0 for PROD, 1 for DEV
|
|
112
|
+
version: '19.1.1', // should be React version and not Kubb's custom version
|
|
113
|
+
rendererPackageName: 'kubb', // package name
|
|
114
|
+
})
|
|
115
|
+
}
|
|
116
|
+
resolveExitPromise: () => void = () => {}
|
|
117
|
+
rejectExitPromise: (reason?: Error) => void = () => {}
|
|
118
|
+
unsubscribeExit: () => void = () => {}
|
|
119
|
+
onRender: () => void = async () => {
|
|
120
|
+
if (this.#isUnmounted) {
|
|
121
|
+
return
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
this.#options.context.clear()
|
|
125
|
+
|
|
126
|
+
processFiles(this.#rootNode, this.#options.context)
|
|
127
|
+
|
|
128
|
+
if (!this.#options.debug && !this.#options.stdout) {
|
|
129
|
+
return
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const output = await this.#getOutput(this.#rootNode, this.#options.context)
|
|
133
|
+
|
|
134
|
+
if (this.#options.debug) {
|
|
135
|
+
console.log('Rendering: \n')
|
|
136
|
+
console.log(output)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (this.#options.stdout) {
|
|
140
|
+
this.#options.stdout.clearLine(0)
|
|
141
|
+
this.#options.stdout.cursorTo(0)
|
|
142
|
+
this.#options.stdout.write(output)
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
onError(error: Error): void {
|
|
146
|
+
if (process.env.NODE_ENV === 'test') {
|
|
147
|
+
console.warn(error)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
throw error
|
|
151
|
+
}
|
|
152
|
+
onExit(error?: Error): void {
|
|
153
|
+
this.unmount(error)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async #getOutput(node: DOMElement, context: AppContext): Promise<string> {
|
|
157
|
+
const text = squashTextNodes(node)
|
|
158
|
+
const files = context.files
|
|
159
|
+
|
|
160
|
+
return files.length
|
|
161
|
+
? [...files]
|
|
162
|
+
.flatMap((file) => [...file.sources].map((item) => item.value))
|
|
163
|
+
.filter(Boolean)
|
|
164
|
+
.join('\n\n')
|
|
165
|
+
: text
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
render(node: ReactNode): void {
|
|
169
|
+
const element = (
|
|
170
|
+
<Root onExit={this.onExit.bind(this)} onError={this.onError.bind(this)}>
|
|
171
|
+
{node}
|
|
172
|
+
</Root>
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
KubbRenderer.updateContainerSync(element, this.#container, null, null)
|
|
176
|
+
KubbRenderer.flushSyncWork()
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
async renderToString(node: ReactNode): Promise<string> {
|
|
180
|
+
const element = (
|
|
181
|
+
<Root onExit={this.onExit.bind(this)} onError={this.onError.bind(this)}>
|
|
182
|
+
{node}
|
|
183
|
+
</Root>
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
KubbRenderer.updateContainerSync(element, this.#container, null, null)
|
|
187
|
+
KubbRenderer.flushSyncWork()
|
|
188
|
+
|
|
189
|
+
this.#options.context.clear()
|
|
190
|
+
|
|
191
|
+
return this.#getOutput(this.#rootNode, this.#options.context)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
unmount(error?: Error | number | null): void {
|
|
195
|
+
if (this.#isUnmounted) {
|
|
196
|
+
return
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (this.#options.debug) {
|
|
200
|
+
console.log('Unmount', error)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
this.onRender()
|
|
204
|
+
this.unsubscribeExit()
|
|
205
|
+
|
|
206
|
+
this.#isUnmounted = true
|
|
207
|
+
|
|
208
|
+
KubbRenderer.updateContainerSync(null, this.#container, null, null)
|
|
209
|
+
|
|
210
|
+
if (error instanceof Error) {
|
|
211
|
+
this.rejectExitPromise(error)
|
|
212
|
+
|
|
213
|
+
return
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
this.resolveExitPromise()
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
async waitUntilExit(): Promise<void> {
|
|
220
|
+
if (!this.exitPromise) {
|
|
221
|
+
this.exitPromise = new Promise((resolve, reject) => {
|
|
222
|
+
this.resolveExitPromise = resolve
|
|
223
|
+
this.rejectExitPromise = reject
|
|
224
|
+
})
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return this.exitPromise
|
|
228
|
+
}
|
|
229
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { createContext, useContext } from 'react'
|
|
2
|
+
import type { KubbNode } from '../types.ts'
|
|
3
|
+
import { RootContext } from './Root.tsx'
|
|
4
|
+
|
|
5
|
+
export type AppContextProps<TMeta = unknown> = {
|
|
6
|
+
/**
|
|
7
|
+
* Exit (unmount)
|
|
8
|
+
*/
|
|
9
|
+
readonly exit: (error?: Error) => void
|
|
10
|
+
readonly meta: TMeta
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const AppContext = createContext<AppContextProps | undefined>(undefined)
|
|
14
|
+
|
|
15
|
+
type Props<TMeta = unknown> = {
|
|
16
|
+
readonly children?: KubbNode
|
|
17
|
+
readonly meta: TMeta
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function App<TMeta = unknown>({ meta, children }: Props<TMeta>) {
|
|
21
|
+
const { exit } = useContext(RootContext)
|
|
22
|
+
|
|
23
|
+
return <AppContext.Provider value={{ exit, meta }}>{children}</AppContext.Provider>
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
App.Context = AppContext
|
|
27
|
+
App.displayName = 'KubbApp'
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { JSDoc, Key, KubbNode } from '../types.ts'
|
|
2
|
+
|
|
3
|
+
import { createJSDoc } from '../utils/createJSDoc.ts'
|
|
4
|
+
|
|
5
|
+
type Props = {
|
|
6
|
+
key?: Key
|
|
7
|
+
/**
|
|
8
|
+
* Name of the const
|
|
9
|
+
*/
|
|
10
|
+
name: string
|
|
11
|
+
/**
|
|
12
|
+
* Does this type need to be exported.
|
|
13
|
+
*/
|
|
14
|
+
export?: boolean
|
|
15
|
+
/**
|
|
16
|
+
* Type to make the const being typed
|
|
17
|
+
*/
|
|
18
|
+
type?: string
|
|
19
|
+
/**
|
|
20
|
+
* Options for JSdocs.
|
|
21
|
+
*/
|
|
22
|
+
JSDoc?: JSDoc
|
|
23
|
+
/**
|
|
24
|
+
* Use of `const` assertions
|
|
25
|
+
*/
|
|
26
|
+
asConst?: boolean
|
|
27
|
+
children?: KubbNode
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function Const({ name, export: canExport, type, JSDoc, asConst, children }: Props) {
|
|
31
|
+
return (
|
|
32
|
+
<>
|
|
33
|
+
{JSDoc?.comments && (
|
|
34
|
+
<>
|
|
35
|
+
{createJSDoc({ comments: JSDoc?.comments })}
|
|
36
|
+
<br />
|
|
37
|
+
</>
|
|
38
|
+
)}
|
|
39
|
+
{canExport && <>export </>}
|
|
40
|
+
const {name}{' '}
|
|
41
|
+
{type && (
|
|
42
|
+
<>
|
|
43
|
+
{':'}
|
|
44
|
+
{type}{' '}
|
|
45
|
+
</>
|
|
46
|
+
)}
|
|
47
|
+
= {children}
|
|
48
|
+
{asConst && <> as const</>}
|
|
49
|
+
</>
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
Const.displayName = 'KubbConst'
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { createContext } from 'react'
|
|
2
|
+
|
|
3
|
+
import type { KubbFile } from '@kubb/fabric-core'
|
|
4
|
+
import type { Key, KubbNode } from '../types.ts'
|
|
5
|
+
|
|
6
|
+
export type FileContextProps<TMeta extends object = object> = {
|
|
7
|
+
/**
|
|
8
|
+
* Name to be used to dynamicly create the baseName(based on input.path).
|
|
9
|
+
* Based on UNIX basename
|
|
10
|
+
* @link https://nodejs.org/api/path.html#pathbasenamepath-suffix
|
|
11
|
+
*/
|
|
12
|
+
baseName: KubbFile.BaseName
|
|
13
|
+
/**
|
|
14
|
+
* Path will be full qualified path to a specified file.
|
|
15
|
+
*/
|
|
16
|
+
path: KubbFile.Path
|
|
17
|
+
meta?: TMeta
|
|
18
|
+
}
|
|
19
|
+
const FileContext = createContext<FileContextProps>({} as FileContextProps)
|
|
20
|
+
|
|
21
|
+
type BasePropsWithBaseName = {
|
|
22
|
+
/**
|
|
23
|
+
* Name to be used to dynamicly create the baseName(based on input.path).
|
|
24
|
+
* Based on UNIX basename
|
|
25
|
+
* @link https://nodejs.org/api/path.html#pathbasenamepath-suffix
|
|
26
|
+
*/
|
|
27
|
+
baseName: KubbFile.BaseName
|
|
28
|
+
/**
|
|
29
|
+
* Path will be full qualified path to a specified file.
|
|
30
|
+
*/
|
|
31
|
+
path: KubbFile.Path
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
type BasePropsWithoutBaseName = {
|
|
35
|
+
baseName?: never
|
|
36
|
+
/**
|
|
37
|
+
* Path will be full qualified path to a specified file.
|
|
38
|
+
*/
|
|
39
|
+
path?: KubbFile.Path
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
type BaseProps = BasePropsWithBaseName | BasePropsWithoutBaseName
|
|
43
|
+
|
|
44
|
+
type Props<TMeta> = BaseProps & {
|
|
45
|
+
key?: Key
|
|
46
|
+
meta?: TMeta
|
|
47
|
+
banner?: string
|
|
48
|
+
footer?: string
|
|
49
|
+
children?: KubbNode
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function File<TMeta extends object = object>({ children, ...rest }: Props<TMeta>) {
|
|
53
|
+
if (!rest.baseName || !rest.path) {
|
|
54
|
+
return <>{children}</>
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<kubb-file {...rest}>
|
|
59
|
+
<FileContext.Provider value={{ baseName: rest.baseName, path: rest.path, meta: rest.meta }}>{children}</FileContext.Provider>
|
|
60
|
+
</kubb-file>
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
File.displayName = 'KubbFile'
|
|
65
|
+
|
|
66
|
+
type FileSourceProps = Omit<KubbFile.Source, 'value'> & {
|
|
67
|
+
key?: Key
|
|
68
|
+
children?: KubbNode
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function FileSource({ isTypeOnly, name, isExportable, isIndexable, children }: FileSourceProps) {
|
|
72
|
+
return (
|
|
73
|
+
<kubb-source name={name} isTypeOnly={isTypeOnly} isExportable={isExportable} isIndexable={isIndexable}>
|
|
74
|
+
{children}
|
|
75
|
+
</kubb-source>
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
FileSource.displayName = 'KubbFileSource'
|
|
80
|
+
|
|
81
|
+
type FileExportProps = KubbFile.Export & { key?: Key }
|
|
82
|
+
|
|
83
|
+
function FileExport({ name, path, isTypeOnly, asAlias }: FileExportProps) {
|
|
84
|
+
return <kubb-export name={name} path={path} isTypeOnly={isTypeOnly || false} asAlias={asAlias} />
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
FileExport.displayName = 'KubbFileExport'
|
|
88
|
+
|
|
89
|
+
type FileImportProps = KubbFile.Import & { key?: Key }
|
|
90
|
+
|
|
91
|
+
function FileImport({ name, root, path, isTypeOnly, isNameSpace }: FileImportProps) {
|
|
92
|
+
return <kubb-import name={name} root={root} path={path} isNameSpace={isNameSpace} isTypeOnly={isTypeOnly || false} />
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
FileImport.displayName = 'KubbFileImport'
|
|
96
|
+
|
|
97
|
+
File.Export = FileExport
|
|
98
|
+
File.Import = FileImport
|
|
99
|
+
File.Source = FileSource
|
|
100
|
+
File.Context = FileContext
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import type { JSDoc, Key, KubbNode } from '../types.ts'
|
|
2
|
+
import { Indent } from './Indent.tsx'
|
|
3
|
+
import { createJSDoc } from '../utils/createJSDoc.ts'
|
|
4
|
+
|
|
5
|
+
type Props = {
|
|
6
|
+
key?: Key
|
|
7
|
+
/**
|
|
8
|
+
* Name of the function.
|
|
9
|
+
*/
|
|
10
|
+
name: string
|
|
11
|
+
/**
|
|
12
|
+
* Add default when export is being used
|
|
13
|
+
*/
|
|
14
|
+
default?: boolean
|
|
15
|
+
/**
|
|
16
|
+
* Parameters/options/props that need to be used.
|
|
17
|
+
*/
|
|
18
|
+
params?: string
|
|
19
|
+
/**
|
|
20
|
+
* Does this function need to be exported.
|
|
21
|
+
*/
|
|
22
|
+
export?: boolean
|
|
23
|
+
/**
|
|
24
|
+
* Does the function has async/promise behaviour.
|
|
25
|
+
* This will also add `Promise<returnType>` as the returnType.
|
|
26
|
+
*/
|
|
27
|
+
async?: boolean
|
|
28
|
+
/**
|
|
29
|
+
* Generics that needs to be added for TypeScript.
|
|
30
|
+
*/
|
|
31
|
+
generics?: string | string[]
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* ReturnType(see async for adding Promise type).
|
|
35
|
+
*/
|
|
36
|
+
returnType?: string
|
|
37
|
+
/**
|
|
38
|
+
* Options for JSdocs.
|
|
39
|
+
*/
|
|
40
|
+
JSDoc?: JSDoc
|
|
41
|
+
children?: KubbNode
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function Function({ name, default: isDefault, export: canExport, async, generics, params, returnType, JSDoc, children }: Props) {
|
|
45
|
+
return (
|
|
46
|
+
<>
|
|
47
|
+
{JSDoc?.comments && (
|
|
48
|
+
<>
|
|
49
|
+
{createJSDoc({ comments: JSDoc?.comments })}
|
|
50
|
+
<br />
|
|
51
|
+
</>
|
|
52
|
+
)}
|
|
53
|
+
{canExport && <>export </>}
|
|
54
|
+
{isDefault && <>default </>}
|
|
55
|
+
{async && <>async </>}
|
|
56
|
+
function {name}
|
|
57
|
+
{generics && (
|
|
58
|
+
<>
|
|
59
|
+
{'<'}
|
|
60
|
+
{Array.isArray(generics) ? generics.join(', ').trim() : generics}
|
|
61
|
+
{'>'}
|
|
62
|
+
</>
|
|
63
|
+
)}
|
|
64
|
+
({params}){returnType && !async && <>: {returnType}</>}
|
|
65
|
+
{returnType && async && (
|
|
66
|
+
<>
|
|
67
|
+
: Promise{'<'}
|
|
68
|
+
{returnType}
|
|
69
|
+
{'>'}
|
|
70
|
+
</>
|
|
71
|
+
)}
|
|
72
|
+
{' {'}
|
|
73
|
+
<br />
|
|
74
|
+
<Indent size={2}>{children}</Indent>
|
|
75
|
+
<br />
|
|
76
|
+
{'}'}
|
|
77
|
+
</>
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
Function.displayName = 'KubbFunction'
|
|
82
|
+
|
|
83
|
+
type ArrowFunctionProps = Props & {
|
|
84
|
+
/**
|
|
85
|
+
* Create Arrow function in one line
|
|
86
|
+
*/
|
|
87
|
+
singleLine?: boolean
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function ArrowFunction({ name, default: isDefault, export: canExport, async, generics, params, returnType, JSDoc, singleLine, children }: ArrowFunctionProps) {
|
|
91
|
+
return (
|
|
92
|
+
<>
|
|
93
|
+
{JSDoc?.comments && (
|
|
94
|
+
<>
|
|
95
|
+
{createJSDoc({ comments: JSDoc?.comments })}
|
|
96
|
+
<br />
|
|
97
|
+
</>
|
|
98
|
+
)}
|
|
99
|
+
{canExport && <>export </>}
|
|
100
|
+
{isDefault && <>default </>}
|
|
101
|
+
const {name} = {async && <>async </>}
|
|
102
|
+
{generics && (
|
|
103
|
+
<>
|
|
104
|
+
{'<'}
|
|
105
|
+
{Array.isArray(generics) ? generics.join(', ').trim() : generics}
|
|
106
|
+
{'>'}
|
|
107
|
+
</>
|
|
108
|
+
)}
|
|
109
|
+
({params}){returnType && !async && <>: {returnType}</>}
|
|
110
|
+
{returnType && async && (
|
|
111
|
+
<>
|
|
112
|
+
: Promise{'<'}
|
|
113
|
+
{returnType}
|
|
114
|
+
{'>'}
|
|
115
|
+
</>
|
|
116
|
+
)}
|
|
117
|
+
{singleLine && (
|
|
118
|
+
<>
|
|
119
|
+
{' => '}
|
|
120
|
+
{children}
|
|
121
|
+
<br />
|
|
122
|
+
</>
|
|
123
|
+
)}
|
|
124
|
+
{!singleLine && (
|
|
125
|
+
<>
|
|
126
|
+
{' => {'}
|
|
127
|
+
<br />
|
|
128
|
+
<Indent size={2}>{children}</Indent>
|
|
129
|
+
<br />
|
|
130
|
+
{'}'}
|
|
131
|
+
<br />
|
|
132
|
+
</>
|
|
133
|
+
)}
|
|
134
|
+
</>
|
|
135
|
+
)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
ArrowFunction.displayName = 'KubbArrowFunction'
|
|
139
|
+
Function.Arrow = ArrowFunction
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import dedent from 'dedent'
|
|
2
|
+
import indentString from 'indent-string'
|
|
3
|
+
import React from 'react'
|
|
4
|
+
|
|
5
|
+
type IndentProps = {
|
|
6
|
+
size?: number
|
|
7
|
+
children?: React.ReactNode
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Indents all children by `size` spaces.
|
|
12
|
+
* Collapses consecutive <br /> tags to at most 2.
|
|
13
|
+
*/
|
|
14
|
+
export function Indent({ size = 2, children }: IndentProps) {
|
|
15
|
+
if (!children) return null
|
|
16
|
+
|
|
17
|
+
const filtered = React.Children.toArray(children).filter(Boolean)
|
|
18
|
+
const result: React.ReactNode[] = []
|
|
19
|
+
|
|
20
|
+
let prevWasBr = false
|
|
21
|
+
let brCount = 0
|
|
22
|
+
|
|
23
|
+
filtered.forEach((child) => {
|
|
24
|
+
if (React.isValidElement(child) && child.type === 'br') {
|
|
25
|
+
if (!prevWasBr || brCount < 2) {
|
|
26
|
+
result.push(child)
|
|
27
|
+
brCount++
|
|
28
|
+
}
|
|
29
|
+
prevWasBr = true
|
|
30
|
+
} else {
|
|
31
|
+
prevWasBr = false
|
|
32
|
+
brCount = 0
|
|
33
|
+
result.push(child)
|
|
34
|
+
}
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<>
|
|
39
|
+
{result.map((child) => {
|
|
40
|
+
if (typeof child === 'string') {
|
|
41
|
+
const cleaned = dedent(child)
|
|
42
|
+
return <>{indentString(cleaned, size)}</>
|
|
43
|
+
}
|
|
44
|
+
return (
|
|
45
|
+
<>
|
|
46
|
+
{' '.repeat(size)}
|
|
47
|
+
{child}
|
|
48
|
+
</>
|
|
49
|
+
)
|
|
50
|
+
})}
|
|
51
|
+
</>
|
|
52
|
+
)
|
|
53
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { Component, createContext } from 'react'
|
|
2
|
+
|
|
3
|
+
import type { KubbNode } from '../types.ts'
|
|
4
|
+
|
|
5
|
+
type ErrorBoundaryProps = {
|
|
6
|
+
onError: (error: Error) => void
|
|
7
|
+
children?: KubbNode
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
class ErrorBoundary extends Component<{
|
|
11
|
+
onError: ErrorBoundaryProps['onError']
|
|
12
|
+
children?: KubbNode
|
|
13
|
+
}> {
|
|
14
|
+
state = { hasError: false }
|
|
15
|
+
|
|
16
|
+
static displayName = 'KubbErrorBoundary'
|
|
17
|
+
static getDerivedStateFromError(_error: Error) {
|
|
18
|
+
return { hasError: true }
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
componentDidCatch(error: Error) {
|
|
22
|
+
if (error) {
|
|
23
|
+
this.props.onError(error)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
render() {
|
|
28
|
+
if (this.state.hasError) {
|
|
29
|
+
return null
|
|
30
|
+
}
|
|
31
|
+
return this.props.children
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export type RootContextProps = {
|
|
36
|
+
/**
|
|
37
|
+
* Exit (unmount) the whole Ink app.
|
|
38
|
+
*/
|
|
39
|
+
readonly exit: (error?: Error) => void
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export const RootContext = createContext<RootContextProps>({
|
|
43
|
+
exit: () => {},
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
type RootProps = {
|
|
47
|
+
/**
|
|
48
|
+
* Exit (unmount) hook
|
|
49
|
+
*/
|
|
50
|
+
readonly onExit: (error?: Error) => void
|
|
51
|
+
/**
|
|
52
|
+
* Error hook
|
|
53
|
+
*/
|
|
54
|
+
readonly onError: (error: Error) => void
|
|
55
|
+
readonly children?: KubbNode
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function Root({ onError, onExit, children }: RootProps) {
|
|
59
|
+
try {
|
|
60
|
+
return (
|
|
61
|
+
<ErrorBoundary
|
|
62
|
+
onError={(error) => {
|
|
63
|
+
onError(error)
|
|
64
|
+
}}
|
|
65
|
+
>
|
|
66
|
+
<RootContext.Provider value={{ exit: onExit }}>{children}</RootContext.Provider>
|
|
67
|
+
</ErrorBoundary>
|
|
68
|
+
)
|
|
69
|
+
} catch (_e) {
|
|
70
|
+
return null
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
Root.Context = RootContext
|
|
75
|
+
Root.displayName = 'KubbRoot'
|