@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,40 @@
|
|
|
1
|
+
import type { JSDoc, Key, KubbNode } from '../types.ts'
|
|
2
|
+
import { createJSDoc } from '../utils/createJSDoc.ts'
|
|
3
|
+
|
|
4
|
+
type Props = {
|
|
5
|
+
key?: Key
|
|
6
|
+
/**
|
|
7
|
+
* Name of the type, this needs to start with a capital letter.
|
|
8
|
+
*/
|
|
9
|
+
name: string
|
|
10
|
+
/**
|
|
11
|
+
* Does this type need to be exported.
|
|
12
|
+
*/
|
|
13
|
+
export?: boolean
|
|
14
|
+
/**
|
|
15
|
+
* Options for JSdocs.
|
|
16
|
+
*/
|
|
17
|
+
JSDoc?: JSDoc
|
|
18
|
+
children?: KubbNode
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function Type({ name, export: canExport, JSDoc, children }: Props) {
|
|
22
|
+
if (name.charAt(0).toUpperCase() !== name.charAt(0)) {
|
|
23
|
+
throw new Error('Name should start with a capital letter(see TypeScript types)')
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<>
|
|
28
|
+
{JSDoc?.comments && (
|
|
29
|
+
<>
|
|
30
|
+
{createJSDoc({ comments: JSDoc?.comments })}
|
|
31
|
+
<br />
|
|
32
|
+
</>
|
|
33
|
+
)}
|
|
34
|
+
{canExport && <>export </>}
|
|
35
|
+
type {name} = {children}
|
|
36
|
+
</>
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
Type.displayName = 'KubbType'
|
package/src/createApp.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import process from 'node:process'
|
|
2
|
+
import { defineApp } from '@kubb/fabric-core'
|
|
3
|
+
import { type ElementType, createElement } from 'react'
|
|
4
|
+
import { ReactTemplate } from './ReactTemplate.tsx'
|
|
5
|
+
|
|
6
|
+
export const createApp = defineApp<ElementType>((app, context) => {
|
|
7
|
+
const template =
|
|
8
|
+
process.env.NODE_ENV === 'test'
|
|
9
|
+
? new ReactTemplate({ context })
|
|
10
|
+
: new ReactTemplate({ context, stdout: process.stdout, stderr: process.stderr, stdin: process.stdin })
|
|
11
|
+
|
|
12
|
+
return {
|
|
13
|
+
render() {
|
|
14
|
+
template.render(createElement(app))
|
|
15
|
+
},
|
|
16
|
+
async renderToString() {
|
|
17
|
+
return template.renderToString(createElement(app))
|
|
18
|
+
},
|
|
19
|
+
waitUntilExit() {
|
|
20
|
+
return template.waitUntilExit()
|
|
21
|
+
},
|
|
22
|
+
}
|
|
23
|
+
})
|
package/src/devtools.ts
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// @ts-expect-error cannot find package
|
|
2
|
+
import { connectToDevTools } from 'react-devtools-inline/backend'
|
|
3
|
+
// import { onExit } from 'signal-exit'
|
|
4
|
+
import { WebSocketServer } from 'ws'
|
|
5
|
+
|
|
6
|
+
// declare global {
|
|
7
|
+
// var WebSocket: typeof WebSocket
|
|
8
|
+
// var self: any
|
|
9
|
+
// var window: any
|
|
10
|
+
// var isDevtoolsEnabled: any
|
|
11
|
+
// }
|
|
12
|
+
|
|
13
|
+
// Filter out Kubbs's internal components from devtools for a cleaner view.
|
|
14
|
+
// See https://github.com/facebook/react/blob/edf6eac8a181860fd8a2d076a43806f1237495a1/packages/react-devtools-shared/src/types.js#L24
|
|
15
|
+
|
|
16
|
+
// const customGlobal: any = globalThis
|
|
17
|
+
// customGlobal.WebSocket ||= ws
|
|
18
|
+
// customGlobal.window ||= customGlobal
|
|
19
|
+
// customGlobal.self ||= customGlobal
|
|
20
|
+
// customGlobal.isDevtoolsEnabled = true
|
|
21
|
+
// customGlobal.window.__REACT_DEVTOOLS_COMPONENT_FILTERS__ = [
|
|
22
|
+
// {
|
|
23
|
+
// // ComponentFilterDisplayName
|
|
24
|
+
// type: 2,
|
|
25
|
+
// value: 'Context.Provider',
|
|
26
|
+
// isEnabled: true,
|
|
27
|
+
// isValid: true,
|
|
28
|
+
// },
|
|
29
|
+
// {
|
|
30
|
+
// // ComponentFilterDisplayName
|
|
31
|
+
// type: 2,
|
|
32
|
+
// value: 'KubbRoot',
|
|
33
|
+
// isEnabled: true,
|
|
34
|
+
// isValid: true,
|
|
35
|
+
// },
|
|
36
|
+
// {
|
|
37
|
+
// // ComponentFilterDisplayName
|
|
38
|
+
// type: 2,
|
|
39
|
+
// value: 'KubbErrorBoundary',
|
|
40
|
+
// isEnabled: true,
|
|
41
|
+
// isValid: true,
|
|
42
|
+
// },
|
|
43
|
+
// {
|
|
44
|
+
// // ComponentFilterDisplayName
|
|
45
|
+
// type: 2,
|
|
46
|
+
// value: 'kubb-file',
|
|
47
|
+
// isEnabled: true,
|
|
48
|
+
// isValid: true,
|
|
49
|
+
// },
|
|
50
|
+
// {
|
|
51
|
+
// // ComponentFilterDisplayName
|
|
52
|
+
// type: 2,
|
|
53
|
+
// value: 'kubb-text',
|
|
54
|
+
// isEnabled: true,
|
|
55
|
+
// isValid: true,
|
|
56
|
+
// },
|
|
57
|
+
// {
|
|
58
|
+
// // ComponentFilterDisplayName
|
|
59
|
+
// type: 2,
|
|
60
|
+
// value: 'kubb-import',
|
|
61
|
+
// isEnabled: true,
|
|
62
|
+
// isValid: true,
|
|
63
|
+
// },
|
|
64
|
+
// {
|
|
65
|
+
// // ComponentFilterDisplayName
|
|
66
|
+
// type: 2,
|
|
67
|
+
// value: 'kubb-export',
|
|
68
|
+
// isEnabled: true,
|
|
69
|
+
// isValid: true,
|
|
70
|
+
// },
|
|
71
|
+
// {
|
|
72
|
+
// // ComponentFilterDisplayName
|
|
73
|
+
// type: 2,
|
|
74
|
+
// value: 'kubb-source',
|
|
75
|
+
// isEnabled: true,
|
|
76
|
+
// isValid: true,
|
|
77
|
+
// },
|
|
78
|
+
// ]
|
|
79
|
+
|
|
80
|
+
function openDevtools() {
|
|
81
|
+
// let subprocess: { kill: () => void }
|
|
82
|
+
|
|
83
|
+
const wss = new WebSocketServer({ port: 8097 })
|
|
84
|
+
|
|
85
|
+
connectToDevTools({
|
|
86
|
+
websocket: wss,
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
// import('execa')
|
|
90
|
+
// .then(async (execa) => {
|
|
91
|
+
// console.log('Opening devtools')
|
|
92
|
+
//
|
|
93
|
+
// subprocess = execa.execa({ preferLocal: true })`npx react-devtools`
|
|
94
|
+
// })
|
|
95
|
+
// .then(() => {
|
|
96
|
+
// // @ts-expect-error
|
|
97
|
+
// return import('react-devtools-inline/backend')
|
|
98
|
+
// })
|
|
99
|
+
// .then((devtools) => {
|
|
100
|
+
// console.log('Connecting devtools')
|
|
101
|
+
// console.log(window.__REACT_DEVTOOLS_GLOBAL_HOOK__, customGlobal.window.__REACT_DEVTOOLS_GLOBAL_HOOK__)
|
|
102
|
+
// devtools.initialize()
|
|
103
|
+
// devtools.connectToDevTools()
|
|
104
|
+
// })
|
|
105
|
+
// .catch((err) => {
|
|
106
|
+
// console.log('Error connecting devtools\n', err)
|
|
107
|
+
// })
|
|
108
|
+
//
|
|
109
|
+
// onExit(
|
|
110
|
+
// () => {
|
|
111
|
+
// console.log('Disconnecting devtools')
|
|
112
|
+
// subprocess?.kill()
|
|
113
|
+
// },
|
|
114
|
+
// { alwaysLast: false },
|
|
115
|
+
// )
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
openDevtools()
|
package/src/dom.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { DOMElement, DOMNode, DOMNodeAttribute, ElementNames, TextNode } from './types.ts'
|
|
2
|
+
|
|
3
|
+
export const createNode = (nodeName: string): DOMElement => {
|
|
4
|
+
const node: DOMElement = {
|
|
5
|
+
nodeName: nodeName as DOMElement['nodeName'],
|
|
6
|
+
attributes: {},
|
|
7
|
+
childNodes: [],
|
|
8
|
+
parentNode: undefined,
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return node
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const appendChildNode = (node: DOMNode, childNode: DOMElement | DOMNode): void => {
|
|
15
|
+
if (childNode.parentNode) {
|
|
16
|
+
removeChildNode(childNode.parentNode, childNode)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (node.nodeName !== '#text') {
|
|
20
|
+
childNode.parentNode = node
|
|
21
|
+
node.childNodes.push(childNode)
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const insertBeforeNode = (node: DOMElement, newChildNode: DOMNode, beforeChildNode: DOMNode): void => {
|
|
26
|
+
if (newChildNode.parentNode) {
|
|
27
|
+
removeChildNode(newChildNode.parentNode, newChildNode)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
newChildNode.parentNode = node
|
|
31
|
+
|
|
32
|
+
const index = node.childNodes.indexOf(beforeChildNode)
|
|
33
|
+
if (index >= 0) {
|
|
34
|
+
node.childNodes.splice(index, 0, newChildNode)
|
|
35
|
+
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
node.childNodes.push(newChildNode)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export const removeChildNode = (node: DOMElement, removeNode: DOMNode): void => {
|
|
43
|
+
removeNode.parentNode = undefined
|
|
44
|
+
|
|
45
|
+
const index = node.childNodes.indexOf(removeNode)
|
|
46
|
+
if (index >= 0) {
|
|
47
|
+
node.childNodes.splice(index, 1)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export const setAttribute = (node: DOMElement, key: string, value: DOMNodeAttribute): void => {
|
|
52
|
+
node.attributes[key] = value
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export const createTextNode = (text: string): TextNode => {
|
|
56
|
+
const node: TextNode = {
|
|
57
|
+
nodeName: '#text',
|
|
58
|
+
nodeValue: text,
|
|
59
|
+
parentNode: undefined,
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
setTextNodeValue(node, text)
|
|
63
|
+
|
|
64
|
+
return node
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export const setTextNodeValue = (node: TextNode, text: string): void => {
|
|
68
|
+
if (typeof text !== 'string') {
|
|
69
|
+
text = String(text)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
node.nodeValue = text
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export const nodeNames: Array<ElementNames> = ['kubb-export', 'kubb-file', 'kubb-source', 'kubb-import', 'kubb-text']
|
package/src/globals.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { KubbFile } from '@kubb/fabric-core'
|
|
2
|
+
import type React from 'react'
|
|
3
|
+
import type { KubbNode } from './types.ts'
|
|
4
|
+
|
|
5
|
+
declare module 'react' {
|
|
6
|
+
namespace JSX {
|
|
7
|
+
interface IntrinsicElements {
|
|
8
|
+
'kubb-text': {
|
|
9
|
+
children?: KubbNode
|
|
10
|
+
}
|
|
11
|
+
'kubb-file': {
|
|
12
|
+
id?: string
|
|
13
|
+
children?: KubbNode
|
|
14
|
+
baseName: string
|
|
15
|
+
path: string
|
|
16
|
+
override?: boolean
|
|
17
|
+
meta?: KubbFile.File['meta']
|
|
18
|
+
}
|
|
19
|
+
'kubb-source': KubbFile.Source & {
|
|
20
|
+
children?: KubbNode
|
|
21
|
+
}
|
|
22
|
+
'kubb-import': KubbFile.Import
|
|
23
|
+
'kubb-export': KubbFile.Export
|
|
24
|
+
br: React.DetailedHTMLProps<React.HTMLAttributes<HTMLBRElement>, HTMLBRElement>
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// biome-ignore lint/suspicious/noTsIgnore: not needed
|
|
29
|
+
// @ts-ignore
|
|
30
|
+
declare module '@kubb/react-fabric/jsx-runtime' {
|
|
31
|
+
namespace JSX {
|
|
32
|
+
interface IntrinsicElements {
|
|
33
|
+
'kubb-text': {
|
|
34
|
+
children?: KubbNode
|
|
35
|
+
}
|
|
36
|
+
'kubb-file': {
|
|
37
|
+
id?: string
|
|
38
|
+
children?: KubbNode
|
|
39
|
+
baseName: string
|
|
40
|
+
path: string
|
|
41
|
+
override?: boolean
|
|
42
|
+
meta?: KubbFile.File['meta']
|
|
43
|
+
}
|
|
44
|
+
'kubb-source': KubbFile.Source & {
|
|
45
|
+
children?: KubbNode
|
|
46
|
+
}
|
|
47
|
+
'kubb-import': KubbFile.Import
|
|
48
|
+
'kubb-export': KubbFile.Export
|
|
49
|
+
br: React.DetailedHTMLProps<React.HTMLAttributes<HTMLBRElement>, HTMLBRElement>
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { useContext } from 'react'
|
|
2
|
+
import { App, type AppContextProps } from '../components/App.tsx'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* `useApp` will return the current App with plugin, pluginManager, fileManager and mode.
|
|
6
|
+
*/
|
|
7
|
+
export function useApp<TMeta = unknown>(): AppContextProps<TMeta> {
|
|
8
|
+
const app = useContext(App.Context)
|
|
9
|
+
|
|
10
|
+
if (!app) {
|
|
11
|
+
throw new Error('<App /> should be set')
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return app as AppContextProps<TMeta>
|
|
15
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { useContext } from 'react'
|
|
2
|
+
|
|
3
|
+
import { File } from '../components/File.tsx'
|
|
4
|
+
|
|
5
|
+
import type { FileContextProps } from '../components/File.tsx'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* `useFile` will return the current file when <File/> is used.
|
|
9
|
+
*/
|
|
10
|
+
export function useFile(): FileContextProps {
|
|
11
|
+
const file = useContext(File.Context)
|
|
12
|
+
|
|
13
|
+
return file as FileContextProps
|
|
14
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { useContext } from 'react'
|
|
2
|
+
|
|
3
|
+
import { Root } from '../components/Root.tsx'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* `useLifecycle` will return some helpers to exit/restart the generation.
|
|
7
|
+
*/
|
|
8
|
+
export function useLifecycle() {
|
|
9
|
+
const { exit } = useContext(Root.Context)
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
exit: () => {
|
|
13
|
+
setTimeout(() => {
|
|
14
|
+
exit()
|
|
15
|
+
}, 0)
|
|
16
|
+
},
|
|
17
|
+
}
|
|
18
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import './globals.ts'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
|
|
5
|
+
export { App } from './components/App.tsx'
|
|
6
|
+
export { Const } from './components/Const.tsx'
|
|
7
|
+
export { File } from './components/File.tsx'
|
|
8
|
+
export { Function } from './components/Function.tsx'
|
|
9
|
+
export { Indent } from './components/Indent.tsx'
|
|
10
|
+
export { Type } from './components/Type.tsx'
|
|
11
|
+
export { createApp } from './createApp.ts'
|
|
12
|
+
export { useApp } from './hooks/useApp.ts'
|
|
13
|
+
export { useFile } from './hooks/useFile.ts'
|
|
14
|
+
export { useLifecycle } from './hooks/useLifecycle.tsx'
|
|
15
|
+
export { createFunctionParams, FunctionParams } from './utils/getFunctionParams.ts'
|
|
16
|
+
|
|
17
|
+
export const createContext = React.createContext
|
|
18
|
+
export const createElement = React.createElement
|
|
19
|
+
export const useContext = React.useContext
|
|
20
|
+
export const useEffect = React.useEffect
|
|
21
|
+
export const useState = React.useState
|
|
22
|
+
export const useRef = React.useRef
|
|
23
|
+
export const use = React.use
|
|
24
|
+
export const useReducer = React.useReducer
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import Reconciler from 'react-reconciler'
|
|
2
|
+
import { DefaultEventPriority, NoEventPriority } from 'react-reconciler/constants'
|
|
3
|
+
|
|
4
|
+
import { appendChildNode, createNode, createTextNode, insertBeforeNode, removeChildNode, setAttribute, setTextNodeValue } from './dom.ts'
|
|
5
|
+
import type { KubbNode } 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: KubbNode, 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 KubbRenderer = 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
|
+
setAttribute(node, key, value as DOMNodeAttribute)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return node
|
|
82
|
+
},
|
|
83
|
+
createTextInstance(text: string, _root: DOMElement, hostContext: HostContext) {
|
|
84
|
+
if (hostContext.isFile && !hostContext.isSource) {
|
|
85
|
+
throw new Error(`[react] '${text}' should be part of <File.Source> component when using the <File/> component`)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return createTextNode(text)
|
|
89
|
+
},
|
|
90
|
+
resetTextContent() {},
|
|
91
|
+
hideTextInstance(node: TextNode) {
|
|
92
|
+
setTextNodeValue(node, '')
|
|
93
|
+
},
|
|
94
|
+
unhideTextInstance(node: TextNode, text: string) {
|
|
95
|
+
setTextNodeValue(node, text)
|
|
96
|
+
},
|
|
97
|
+
getPublicInstance: (instance) => instance,
|
|
98
|
+
appendInitialChild: appendChildNode,
|
|
99
|
+
appendChild: appendChildNode,
|
|
100
|
+
insertBefore: insertBeforeNode,
|
|
101
|
+
finalizeInitialChildren(_node, _type, _props, _rootNode) {
|
|
102
|
+
return false
|
|
103
|
+
},
|
|
104
|
+
supportsMutation: true,
|
|
105
|
+
isPrimaryRenderer: true,
|
|
106
|
+
supportsPersistence: false,
|
|
107
|
+
supportsHydration: false,
|
|
108
|
+
scheduleTimeout: setTimeout,
|
|
109
|
+
cancelTimeout: clearTimeout,
|
|
110
|
+
noTimeout: -1,
|
|
111
|
+
beforeActiveInstanceBlur() {},
|
|
112
|
+
afterActiveInstanceBlur() {},
|
|
113
|
+
detachDeletedInstance() {},
|
|
114
|
+
getInstanceFromNode: () => null,
|
|
115
|
+
prepareScopeUpdate() {},
|
|
116
|
+
getInstanceFromScope: () => null,
|
|
117
|
+
appendChildToContainer: appendChildNode,
|
|
118
|
+
insertInContainerBefore: insertBeforeNode,
|
|
119
|
+
removeChildFromContainer(node: DOMElement, removeNode: TextNode) {
|
|
120
|
+
removeChildNode(node, removeNode)
|
|
121
|
+
},
|
|
122
|
+
resetFormInstance() {},
|
|
123
|
+
commitMount() {},
|
|
124
|
+
commitUpdate(node: DOMElement, _payload, _type, _oldProps: Props, newProps: Props) {
|
|
125
|
+
const { props } = newProps
|
|
126
|
+
|
|
127
|
+
if (props) {
|
|
128
|
+
for (const [key, value] of Object.entries(props)) {
|
|
129
|
+
setAttribute(node, key, value as DOMNodeAttribute)
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
commitTextUpdate(node: TextNode, _oldText, newText) {
|
|
134
|
+
setTextNodeValue(node, newText)
|
|
135
|
+
},
|
|
136
|
+
removeChild(node: DOMElement, removeNode: TextNode) {
|
|
137
|
+
removeChildNode(node, removeNode)
|
|
138
|
+
},
|
|
139
|
+
setCurrentUpdatePriority: (newPriority: number) => {
|
|
140
|
+
currentUpdatePriority = newPriority
|
|
141
|
+
},
|
|
142
|
+
getCurrentUpdatePriority: () => currentUpdatePriority,
|
|
143
|
+
resolveUpdatePriority: () => currentUpdatePriority || DefaultEventPriority,
|
|
144
|
+
maySuspendCommit() {
|
|
145
|
+
return false
|
|
146
|
+
},
|
|
147
|
+
startSuspendingCommit() {},
|
|
148
|
+
waitForCommitToBeReady() {
|
|
149
|
+
return null
|
|
150
|
+
},
|
|
151
|
+
preloadInstance() {
|
|
152
|
+
// Return true to indicate it's already loaded
|
|
153
|
+
return true
|
|
154
|
+
},
|
|
155
|
+
suspendInstance() {},
|
|
156
|
+
shouldAttemptEagerTransition() {
|
|
157
|
+
return false
|
|
158
|
+
},
|
|
159
|
+
NotPendingTransition: undefined,
|
|
160
|
+
requestPostPaintCallback: function (_callback: (time: number) => void): void {
|
|
161
|
+
throw new Error('Function not implemented.')
|
|
162
|
+
},
|
|
163
|
+
trackSchedulerEvent: function (): void {
|
|
164
|
+
throw new Error('Function not implemented.')
|
|
165
|
+
},
|
|
166
|
+
resolveEventType: function (): null | string {
|
|
167
|
+
throw new Error('Function not implemented.')
|
|
168
|
+
},
|
|
169
|
+
resolveEventTimeStamp: function (): number {
|
|
170
|
+
throw new Error('Function not implemented.')
|
|
171
|
+
},
|
|
172
|
+
HostTransitionContext: undefined as any,
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
export type { FiberRoot } from 'react-reconciler'
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { ReactNode } from 'react'
|
|
2
|
+
type ReactElementNames = 'br' | 'div'
|
|
3
|
+
|
|
4
|
+
export type ElementNames = ReactElementNames | 'kubb-text' | 'kubb-file' | 'kubb-source' | 'kubb-import' | 'kubb-export' | 'kubb-root' | 'kubb-app'
|
|
5
|
+
|
|
6
|
+
type Node = {
|
|
7
|
+
parentNode: DOMElement | undefined
|
|
8
|
+
internal_static?: boolean
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export type DOMNodeAttribute = boolean | string | number
|
|
12
|
+
|
|
13
|
+
type TextName = '#text'
|
|
14
|
+
export type TextNode = {
|
|
15
|
+
nodeName: TextName
|
|
16
|
+
nodeValue: string
|
|
17
|
+
} & Node
|
|
18
|
+
|
|
19
|
+
export type DOMNode<T = { nodeName: NodeNames }> = T extends {
|
|
20
|
+
nodeName: infer U
|
|
21
|
+
}
|
|
22
|
+
? U extends '#text'
|
|
23
|
+
? TextNode
|
|
24
|
+
: DOMElement
|
|
25
|
+
: never
|
|
26
|
+
|
|
27
|
+
type OutputTransformer = (s: string, index: number) => string
|
|
28
|
+
|
|
29
|
+
export type DOMElement = {
|
|
30
|
+
nodeName: ElementNames
|
|
31
|
+
attributes: Record<string, DOMNodeAttribute>
|
|
32
|
+
childNodes: DOMNode[]
|
|
33
|
+
internal_transform?: OutputTransformer
|
|
34
|
+
|
|
35
|
+
// Internal properties
|
|
36
|
+
isStaticDirty?: boolean
|
|
37
|
+
staticNode?: DOMElement
|
|
38
|
+
onComputeLayout?: () => void
|
|
39
|
+
onRender?: () => void
|
|
40
|
+
onImmediateRender?: () => void
|
|
41
|
+
} & Node
|
|
42
|
+
|
|
43
|
+
type NodeNames = ElementNames | TextName
|
|
44
|
+
|
|
45
|
+
export type KubbNode = ReactNode
|
|
46
|
+
|
|
47
|
+
export type { Key } from 'react'
|
|
48
|
+
|
|
49
|
+
export type JSDoc = {
|
|
50
|
+
comments: string[]
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export type { Params, Param } from './utils/getFunctionParams.ts'
|