-
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathindex.ts
More file actions
123 lines (118 loc) · 3.71 KB
/
index.ts
File metadata and controls
123 lines (118 loc) · 3.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import { space } from '../../utils'
import { isDefaultProp } from '../utils/is-default-prop'
import {
paddingLeftMultiline,
wrapReturnStatement,
} from '../utils/padding-left-multiline'
import { propsToString } from '../utils/props-to-str'
const CENTER_SKIP_KEYS = new Set(['alignItems', 'justifyContent'])
const IMAGE_BOX_SKIP_KEYS = new Set([
'alignItems',
'justifyContent',
'flexDir',
'gap',
'outline',
'outlineOffset',
'overflow',
])
export function renderNode(
component: string,
props: Record<string, unknown>,
deps: number = 0,
childrenCodes: string[],
): string {
const propsString = propsToString(filterAndTransformProps(component, props))
const hasChildren = childrenCodes.length > 0
const multiProps = propsString.includes('\n')
let result = `${space(deps)}<${component}${propsString ? (multiProps ? `\n${paddingLeftMultiline(propsString, deps + 1)}` : ` ${propsString}`) : ''}${
(multiProps ? `\n${space(deps)}` : !hasChildren ? ' ' : '') +
(hasChildren ? '>' : '/>')
}`
if (hasChildren) {
let children = ''
for (let i = 0; i < childrenCodes.length; i++) {
if (i > 0) children += '\n'
children += paddingLeftMultiline(childrenCodes[i], deps + 1)
}
result += `\n${children}\n${space(deps)}</${component}>`
}
return result
}
export function renderComponent(
component: string,
code: string,
variants: Record<string, string>,
comments?: Record<string, string>,
) {
// Single pass: collect variant entries, skipping 'effect' (reserved key)
const variantEntries: [string, string][] = []
for (const key in variants) {
if (key.toLowerCase() !== 'effect')
variantEntries.push([key, variants[key]])
}
if (variantEntries.length === 0) {
return `export function ${component}() {
return ${wrapReturnStatement(code, 1)}
}`
}
const interfaceLines: string[] = []
const keys: string[] = []
for (const [key, value] of variantEntries) {
const optional = value === 'boolean' ? '?' : ''
if (comments?.[key]) {
interfaceLines.push(` /** ${comments[key]} */`)
}
interfaceLines.push(` ${key}${optional}: ${value}`)
keys.push(key)
}
return `export interface ${component}Props {
${interfaceLines.join('\n')}
}
export function ${component}({ ${keys.join(', ')} }: ${component}Props) {
return ${wrapReturnStatement(code, 1)}
}`
}
function filterAndTransformProps(
component: string,
props: Record<string, unknown>,
) {
const hasMaskImage = 'maskImage' in props
const newProps: Record<string, unknown> = {}
for (const key in props) {
const value = props[key]
if (value === null || value === undefined) {
continue
}
const newValue = typeof value === 'number' ? String(value) : value
if (isDefaultProp(key, newValue)) {
continue
}
switch (component) {
case 'Flex':
if (key === 'display' && newValue === 'flex') continue
if (key === 'flexDir' && newValue === 'row') continue
break
case 'Grid':
if (key === 'display' && newValue === 'grid') continue
break
case 'Center':
if (CENTER_SKIP_KEYS.has(key)) continue
if (key === 'display' && newValue === 'flex') continue
if (key === 'flexDir' && newValue === 'row') continue
break
case 'VStack':
if (key === 'flexDir' && newValue === 'column') continue
if (key === 'display' && newValue === 'flex') continue
break
case 'Image':
case 'Box':
if (component === 'Box' && !hasMaskImage) break
if (IMAGE_BOX_SKIP_KEYS.has(key)) continue
if (key === 'display' && newValue === 'flex') continue
if (!hasMaskImage && key === 'bg') continue
break
}
newProps[key] = newValue
}
return newProps
}