@hanzogui/static 2.0.0
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 +1 -0
- package/dist/check-dep-versions.cjs +267 -0
- package/dist/checkDeps.cjs +200 -0
- package/dist/constants.cjs +49 -0
- package/dist/exports.cjs +44 -0
- package/dist/extractor/accessSafe.cjs +46 -0
- package/dist/extractor/babelParse.cjs +54 -0
- package/dist/extractor/buildClassName.cjs +62 -0
- package/dist/extractor/bundle.cjs +185 -0
- package/dist/extractor/bundleConfig.cjs +513 -0
- package/dist/extractor/concatClassName.cjs +80 -0
- package/dist/extractor/createEvaluator.cjs +75 -0
- package/dist/extractor/createExtractor.cjs +1150 -0
- package/dist/extractor/createLogger.cjs +45 -0
- package/dist/extractor/detectModuleFormat.cjs +49 -0
- package/dist/extractor/ensureImportingConcat.cjs +48 -0
- package/dist/extractor/errors.cjs +26 -0
- package/dist/extractor/esbuildAliasPlugin.cjs +44 -0
- package/dist/extractor/esbuildTsconfigPaths.cjs +86 -0
- package/dist/extractor/evaluateAstNode.cjs +83 -0
- package/dist/extractor/extractHelpers.cjs +119 -0
- package/dist/extractor/extractMediaStyle.cjs +128 -0
- package/dist/extractor/extractToClassNames.cjs +321 -0
- package/dist/extractor/extractToNative.cjs +266 -0
- package/dist/extractor/findTopmostFunction.cjs +34 -0
- package/dist/extractor/generatedUid.cjs +47 -0
- package/dist/extractor/getGuiConfigPathFromOptionsConfig.cjs +35 -0
- package/dist/extractor/getPrefixLogs.cjs +29 -0
- package/dist/extractor/getPropValueFromAttributes.cjs +67 -0
- package/dist/extractor/getSourceModule.cjs +64 -0
- package/dist/extractor/getStaticBindingsForScope.cjs +150 -0
- package/dist/extractor/hoistClassNames.cjs +62 -0
- package/dist/extractor/literalToAst.cjs +84 -0
- package/dist/extractor/loadFile.cjs +11 -0
- package/dist/extractor/loadGui.cjs +322 -0
- package/dist/extractor/logLines.cjs +35 -0
- package/dist/extractor/normalizeTernaries.cjs +73 -0
- package/dist/extractor/propsToFontFamilyCache.cjs +38 -0
- package/dist/extractor/regenerateConfig.cjs +150 -0
- package/dist/extractor/removeUnusedHooks.cjs +76 -0
- package/dist/extractor/timer.cjs +43 -0
- package/dist/extractor/validHTMLAttributes.cjs +77 -0
- package/dist/extractor/watchGuiConfig.cjs +58 -0
- package/dist/getPragmaOptions.cjs +58 -0
- package/dist/helpers/memoize.cjs +37 -0
- package/dist/helpers/requireGuiCore.cjs +33 -0
- package/dist/index.cjs +40 -0
- package/dist/registerRequire.cjs +115 -0
- package/dist/server.cjs +75 -0
- package/dist/setup.cjs +0 -0
- package/dist/types.cjs +16 -0
- package/dist/worker.cjs +89 -0
- package/package.json +101 -0
- package/src/check-dep-versions.ts +738 -0
- package/src/checkDeps.ts +371 -0
- package/src/constants.ts +14 -0
- package/src/exports.ts +15 -0
- package/src/extractor/accessSafe.ts +22 -0
- package/src/extractor/babelParse.ts +37 -0
- package/src/extractor/buildClassName.ts +76 -0
- package/src/extractor/bundle.ts +277 -0
- package/src/extractor/bundleConfig.ts +958 -0
- package/src/extractor/concatClassName.ts +105 -0
- package/src/extractor/createEvaluator.ts +82 -0
- package/src/extractor/createExtractor.ts +2665 -0
- package/src/extractor/createLogger.ts +41 -0
- package/src/extractor/detectModuleFormat.ts +42 -0
- package/src/extractor/ensureImportingConcat.ts +36 -0
- package/src/extractor/errors.ts +1 -0
- package/src/extractor/esbuildAliasPlugin.ts +40 -0
- package/src/extractor/esbuildTsconfigPaths.ts +103 -0
- package/src/extractor/evaluateAstNode.ts +136 -0
- package/src/extractor/extractHelpers.ts +211 -0
- package/src/extractor/extractMediaStyle.ts +194 -0
- package/src/extractor/extractToClassNames.ts +631 -0
- package/src/extractor/extractToNative.ts +463 -0
- package/src/extractor/findTopmostFunction.ts +24 -0
- package/src/extractor/generatedUid.ts +41 -0
- package/src/extractor/getGuiConfigPathFromOptionsConfig.ts +24 -0
- package/src/extractor/getPrefixLogs.ts +9 -0
- package/src/extractor/getPropValueFromAttributes.ts +95 -0
- package/src/extractor/getSourceModule.ts +96 -0
- package/src/extractor/getStaticBindingsForScope.ts +237 -0
- package/src/extractor/hoistClassNames.ts +52 -0
- package/src/extractor/literalToAst.ts +85 -0
- package/src/extractor/loadFile.ts +17 -0
- package/src/extractor/loadGui.ts +487 -0
- package/src/extractor/logLines.ts +16 -0
- package/src/extractor/normalizeTernaries.ts +75 -0
- package/src/extractor/propsToFontFamilyCache.ts +18 -0
- package/src/extractor/regenerateConfig.ts +186 -0
- package/src/extractor/removeUnusedHooks.ts +83 -0
- package/src/extractor/timer.ts +25 -0
- package/src/extractor/validHTMLAttributes.ts +52 -0
- package/src/extractor/watchGuiConfig.ts +57 -0
- package/src/getPragmaOptions.ts +57 -0
- package/src/helpers/memoize.ts +24 -0
- package/src/helpers/requireGuiCore.ts +28 -0
- package/src/index.ts +4 -0
- package/src/registerRequire.ts +236 -0
- package/src/server.ts +43 -0
- package/src/setup.ts +0 -0
- package/src/types.ts +109 -0
- package/src/worker.ts +142 -0
- package/types/check-dep-versions.d.ts +37 -0
- package/types/check-dep-versions.d.ts.map +1 -0
- package/types/checkDeps.d.ts +19 -0
- package/types/checkDeps.d.ts.map +1 -0
- package/types/constants.d.ts +6 -0
- package/types/constants.d.ts.map +1 -0
- package/types/exports.d.ts +16 -0
- package/types/exports.d.ts.map +1 -0
- package/types/extractor/accessSafe.d.ts +3 -0
- package/types/extractor/accessSafe.d.ts.map +1 -0
- package/types/extractor/babelParse.d.ts +5 -0
- package/types/extractor/babelParse.d.ts.map +1 -0
- package/types/extractor/buildClassName.d.ts +7 -0
- package/types/extractor/buildClassName.d.ts.map +1 -0
- package/types/extractor/bundle.d.ts +121 -0
- package/types/extractor/bundle.d.ts.map +1 -0
- package/types/extractor/bundleConfig.d.ts +49 -0
- package/types/extractor/bundleConfig.d.ts.map +1 -0
- package/types/extractor/concatClassName.d.ts +8 -0
- package/types/extractor/concatClassName.d.ts.map +1 -0
- package/types/extractor/createEvaluator.d.ts +12 -0
- package/types/extractor/createEvaluator.d.ts.map +1 -0
- package/types/extractor/createExtractor.d.ts +32 -0
- package/types/extractor/createExtractor.d.ts.map +1 -0
- package/types/extractor/createLogger.d.ts +3 -0
- package/types/extractor/createLogger.d.ts.map +1 -0
- package/types/extractor/detectModuleFormat.d.ts +5 -0
- package/types/extractor/detectModuleFormat.d.ts.map +1 -0
- package/types/extractor/ensureImportingConcat.d.ts +4 -0
- package/types/extractor/ensureImportingConcat.d.ts.map +1 -0
- package/types/extractor/errors.d.ts +3 -0
- package/types/extractor/errors.d.ts.map +1 -0
- package/types/extractor/esbuildAliasPlugin.d.ts +18 -0
- package/types/extractor/esbuildAliasPlugin.d.ts.map +1 -0
- package/types/extractor/esbuildTsconfigPaths.d.ts +11 -0
- package/types/extractor/esbuildTsconfigPaths.d.ts.map +1 -0
- package/types/extractor/evaluateAstNode.d.ts +3 -0
- package/types/extractor/evaluateAstNode.d.ts.map +1 -0
- package/types/extractor/extractHelpers.d.ts +28 -0
- package/types/extractor/extractHelpers.d.ts.map +1 -0
- package/types/extractor/extractMediaStyle.d.ts +11 -0
- package/types/extractor/extractMediaStyle.d.ts.map +1 -0
- package/types/extractor/extractToClassNames.d.ts +25 -0
- package/types/extractor/extractToClassNames.d.ts.map +1 -0
- package/types/extractor/extractToNative.d.ts +13 -0
- package/types/extractor/extractToNative.d.ts.map +1 -0
- package/types/extractor/findTopmostFunction.d.ts +4 -0
- package/types/extractor/findTopmostFunction.d.ts.map +1 -0
- package/types/extractor/generatedUid.d.ts +5 -0
- package/types/extractor/generatedUid.d.ts.map +1 -0
- package/types/extractor/getGuiConfigPathFromOptionsConfig.d.ts +3 -0
- package/types/extractor/getGuiConfigPathFromOptionsConfig.d.ts.map +1 -0
- package/types/extractor/getPrefixLogs.d.ts +3 -0
- package/types/extractor/getPrefixLogs.d.ts.map +1 -0
- package/types/extractor/getPropValueFromAttributes.d.ts +19 -0
- package/types/extractor/getPropValueFromAttributes.d.ts.map +1 -0
- package/types/extractor/getSourceModule.d.ts +16 -0
- package/types/extractor/getSourceModule.d.ts.map +1 -0
- package/types/extractor/getStaticBindingsForScope.d.ts +5 -0
- package/types/extractor/getStaticBindingsForScope.d.ts.map +1 -0
- package/types/extractor/hoistClassNames.d.ts +6 -0
- package/types/extractor/hoistClassNames.d.ts.map +1 -0
- package/types/extractor/literalToAst.d.ts +4 -0
- package/types/extractor/literalToAst.d.ts.map +1 -0
- package/types/extractor/loadFile.d.ts +1 -0
- package/types/extractor/loadFile.d.ts.map +1 -0
- package/types/extractor/loadGui.d.ts +22 -0
- package/types/extractor/loadGui.d.ts.map +1 -0
- package/types/extractor/logLines.d.ts +2 -0
- package/types/extractor/logLines.d.ts.map +1 -0
- package/types/extractor/normalizeTernaries.d.ts +3 -0
- package/types/extractor/normalizeTernaries.d.ts.map +1 -0
- package/types/extractor/propsToFontFamilyCache.d.ts +4 -0
- package/types/extractor/propsToFontFamilyCache.d.ts.map +1 -0
- package/types/extractor/regenerateConfig.d.ts +9 -0
- package/types/extractor/regenerateConfig.d.ts.map +1 -0
- package/types/extractor/removeUnusedHooks.d.ts +3 -0
- package/types/extractor/removeUnusedHooks.d.ts.map +1 -0
- package/types/extractor/timer.d.ts +5 -0
- package/types/extractor/timer.d.ts.map +1 -0
- package/types/extractor/validHTMLAttributes.d.ts +52 -0
- package/types/extractor/validHTMLAttributes.d.ts.map +1 -0
- package/types/extractor/watchGuiConfig.d.ts +5 -0
- package/types/extractor/watchGuiConfig.d.ts.map +1 -0
- package/types/getPragmaOptions.d.ts +8 -0
- package/types/getPragmaOptions.d.ts.map +1 -0
- package/types/helpers/memoize.d.ts +8 -0
- package/types/helpers/memoize.d.ts.map +1 -0
- package/types/helpers/requireGuiCore.d.ts +3 -0
- package/types/helpers/requireGuiCore.d.ts.map +1 -0
- package/types/index.d.ts +4 -0
- package/types/index.d.ts.map +1 -0
- package/types/registerRequire.d.ts +10 -0
- package/types/registerRequire.d.ts.map +1 -0
- package/types/server.d.ts +3 -0
- package/types/server.d.ts.map +1 -0
- package/types/setup.d.ts +1 -0
- package/types/setup.d.ts.map +1 -0
- package/types/types.d.ts +92 -0
- package/types/types.d.ts.map +1 -0
- package/types/worker.d.ts +46 -0
- package/types/worker.d.ts.map +1 -0
|
@@ -0,0 +1,487 @@
|
|
|
1
|
+
import { basename, dirname, extname, join, relative, resolve } from 'node:path'
|
|
2
|
+
// @ts-ignore why
|
|
3
|
+
import { Color, colorLog } from '@hanzogui/cli-color'
|
|
4
|
+
import type { CLIResolvedOptions, CLIUserOptions, GuiOptions } from '@hanzogui/types'
|
|
5
|
+
import type { GuiInternalConfig } from '@hanzogui/web'
|
|
6
|
+
import esbuild from 'esbuild'
|
|
7
|
+
import * as esbuildWasm from 'esbuild-wasm'
|
|
8
|
+
import * as fsExtra from 'fs-extra'
|
|
9
|
+
|
|
10
|
+
import { SHOULD_DEBUG } from '../constants'
|
|
11
|
+
import { requireGuiCore } from '../helpers/requireGuiCore'
|
|
12
|
+
import { getNameToPaths, registerRequire } from '../registerRequire'
|
|
13
|
+
import {
|
|
14
|
+
type GuiProjectInfo,
|
|
15
|
+
getBundledConfig,
|
|
16
|
+
getLoadedConfig,
|
|
17
|
+
hasBundledConfigChanged,
|
|
18
|
+
loadComponentsSync,
|
|
19
|
+
writeGuiCSS,
|
|
20
|
+
} from './bundleConfig'
|
|
21
|
+
import { getGuiConfigPathFromOptionsConfig } from './getGuiConfigPathFromOptionsConfig'
|
|
22
|
+
import {
|
|
23
|
+
generateGuiThemes,
|
|
24
|
+
regenerateConfig,
|
|
25
|
+
regenerateConfigSync,
|
|
26
|
+
} from './regenerateConfig'
|
|
27
|
+
|
|
28
|
+
const getFilledOptions = (propsIn: Partial<GuiOptions>): GuiOptions => ({
|
|
29
|
+
// defaults
|
|
30
|
+
platform: (process.env.HANZO_GUI_TARGET as any) || 'web',
|
|
31
|
+
config: 'gui.config.ts',
|
|
32
|
+
components: ['@hanzo/gui'],
|
|
33
|
+
...(propsIn as Partial<GuiOptions>),
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
let isLoadingPromise: null | Promise<any>
|
|
37
|
+
|
|
38
|
+
export async function loadGui(
|
|
39
|
+
propsIn: Partial<GuiOptions>
|
|
40
|
+
): Promise<GuiProjectInfo | null> {
|
|
41
|
+
if (isLoadingPromise) return await isLoadingPromise
|
|
42
|
+
|
|
43
|
+
let resolvePromise
|
|
44
|
+
let rejectPromise
|
|
45
|
+
isLoadingPromise = new Promise((res, rej) => {
|
|
46
|
+
resolvePromise = res
|
|
47
|
+
rejectPromise = rej
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
const props = getFilledOptions(propsIn)
|
|
52
|
+
|
|
53
|
+
const bundleInfo = await getBundledConfig(props)
|
|
54
|
+
if (!bundleInfo) {
|
|
55
|
+
console.warn(
|
|
56
|
+
`No bundled config generated, maybe an error in bundling. Set DEBUG=hanzo-gui and re-run to get logs.`
|
|
57
|
+
)
|
|
58
|
+
resolvePromise(null)
|
|
59
|
+
return null
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// this affects the bundled config so run it first
|
|
63
|
+
await generateThemesAndLog(props)
|
|
64
|
+
|
|
65
|
+
// if they accidently pass in a config without createGui called,call it
|
|
66
|
+
const maybeGuiConfig = bundleInfo.guiConfig as GuiInternalConfig
|
|
67
|
+
if (maybeGuiConfig && !maybeGuiConfig.parsed) {
|
|
68
|
+
const { createGui } = requireGuiCore(props.platform || 'web')
|
|
69
|
+
bundleInfo.guiConfig = createGui(bundleInfo.guiConfig as any)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (!hasBundledConfigChanged()) {
|
|
73
|
+
resolvePromise(bundleInfo)
|
|
74
|
+
return bundleInfo
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
await regenerateConfig(props, bundleInfo)
|
|
78
|
+
|
|
79
|
+
resolvePromise(bundleInfo)
|
|
80
|
+
return bundleInfo
|
|
81
|
+
} catch (err) {
|
|
82
|
+
rejectPromise()
|
|
83
|
+
throw err
|
|
84
|
+
} finally {
|
|
85
|
+
isLoadingPromise = null
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// debounce a bit
|
|
90
|
+
let waiting = false
|
|
91
|
+
|
|
92
|
+
export const generateThemesAndLog = async (options: GuiOptions, force = false) => {
|
|
93
|
+
if (waiting) return
|
|
94
|
+
if (!options.themeBuilder) return
|
|
95
|
+
try {
|
|
96
|
+
waiting = true
|
|
97
|
+
await new Promise((res) => setTimeout(res, 30))
|
|
98
|
+
const didGenerate = await generateGuiThemes(options, force)
|
|
99
|
+
|
|
100
|
+
// only logs when changed
|
|
101
|
+
if (didGenerate) {
|
|
102
|
+
const whitespaceBefore = ` `
|
|
103
|
+
colorLog(
|
|
104
|
+
Color.FgYellow,
|
|
105
|
+
`${whitespaceBefore}➡ [hanzo-gui] generated themes: ${relative(
|
|
106
|
+
process.cwd(),
|
|
107
|
+
options.themeBuilder.output
|
|
108
|
+
)}`
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
if (options.outputCSS) {
|
|
112
|
+
const loadedConfig = getLoadedConfig()
|
|
113
|
+
if (loadedConfig) {
|
|
114
|
+
await writeGuiCSS(options.outputCSS, loadedConfig)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
} finally {
|
|
119
|
+
waiting = false
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const last: Record<string, GuiProjectInfo | null> = {}
|
|
124
|
+
const lastVersion: Record<string, string> = {}
|
|
125
|
+
|
|
126
|
+
// esbuild-wasm state - initialized once per process
|
|
127
|
+
let esbuildWasmInitialized = false
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Load gui.build.ts config using esbuild-wasm transform
|
|
131
|
+
* Uses WASM to avoid native esbuild service lifecycle issues (EPIPE errors)
|
|
132
|
+
*/
|
|
133
|
+
export async function loadGuiBuildConfigAsync(
|
|
134
|
+
guiOptions: Partial<GuiOptions> | undefined
|
|
135
|
+
): Promise<GuiOptions> {
|
|
136
|
+
const buildFilePath = guiOptions?.buildFile ?? './gui.build.ts'
|
|
137
|
+
const absolutePath =
|
|
138
|
+
buildFilePath[0] === '.' ? join(process.cwd(), buildFilePath) : buildFilePath
|
|
139
|
+
|
|
140
|
+
if (fsExtra.existsSync(absolutePath)) {
|
|
141
|
+
try {
|
|
142
|
+
const source = await fsExtra.readFile(absolutePath, 'utf-8')
|
|
143
|
+
|
|
144
|
+
// initialize esbuild-wasm once
|
|
145
|
+
if (!esbuildWasmInitialized) {
|
|
146
|
+
await esbuildWasm.initialize({})
|
|
147
|
+
esbuildWasmInitialized = true
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// use esbuild-wasm.transform to compile - no native service needed
|
|
151
|
+
const result = await esbuildWasm.transform(source, {
|
|
152
|
+
loader: 'ts',
|
|
153
|
+
format: 'cjs',
|
|
154
|
+
target: 'node18',
|
|
155
|
+
sourcefile: absolutePath,
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
// evaluate the compiled code to get the exports
|
|
159
|
+
// pass process so process.env works in the config
|
|
160
|
+
const module = { exports: {} as any }
|
|
161
|
+
const fn = new Function('module', 'exports', 'require', 'process', result.code)
|
|
162
|
+
fn(module, module.exports, require, process)
|
|
163
|
+
|
|
164
|
+
const out = module.exports.default || module.exports
|
|
165
|
+
if (!out || typeof out !== 'object') {
|
|
166
|
+
throw new Error(`No default export found in ${buildFilePath}: ${out}`)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
guiOptions = {
|
|
170
|
+
...guiOptions,
|
|
171
|
+
...out,
|
|
172
|
+
}
|
|
173
|
+
} catch (err) {
|
|
174
|
+
console.error(`[hanzo-gui] Error loading ${buildFilePath}:`, err)
|
|
175
|
+
throw err
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (!guiOptions) {
|
|
180
|
+
throw new Error(
|
|
181
|
+
`No hanzo-gui build options found either via input props or at gui.build.ts`
|
|
182
|
+
)
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return {
|
|
186
|
+
config: 'gui.config.ts',
|
|
187
|
+
components: ['@hanzo/gui', '@hanzogui/core'],
|
|
188
|
+
...guiOptions,
|
|
189
|
+
} as GuiOptions
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* @deprecated Use loadGuiBuildConfigAsync instead to avoid EPIPE errors
|
|
194
|
+
*/
|
|
195
|
+
export function loadGuiBuildConfigSync(
|
|
196
|
+
guiOptions: Partial<GuiOptions> | undefined
|
|
197
|
+
) {
|
|
198
|
+
const buildFilePath = guiOptions?.buildFile ?? './gui.build.ts'
|
|
199
|
+
if (fsExtra.existsSync(buildFilePath)) {
|
|
200
|
+
const registered = registerRequire('web')
|
|
201
|
+
try {
|
|
202
|
+
const out = require(
|
|
203
|
+
buildFilePath[0] === '.' ? join(process.cwd(), buildFilePath) : buildFilePath
|
|
204
|
+
).default
|
|
205
|
+
if (!out) {
|
|
206
|
+
throw new Error(`No default export found in ${buildFilePath}: ${out}`)
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
guiOptions = {
|
|
210
|
+
...guiOptions,
|
|
211
|
+
...out,
|
|
212
|
+
}
|
|
213
|
+
} finally {
|
|
214
|
+
registered.unregister()
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
if (!guiOptions) {
|
|
218
|
+
throw new Error(
|
|
219
|
+
`No hanzo-gui build options found either via input props or at gui.build.ts`
|
|
220
|
+
)
|
|
221
|
+
}
|
|
222
|
+
return {
|
|
223
|
+
config: 'gui.config.ts',
|
|
224
|
+
components: ['@hanzo/gui', '@hanzogui/core'],
|
|
225
|
+
...guiOptions,
|
|
226
|
+
} as GuiOptions
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// loads in-process using esbuild-register
|
|
230
|
+
export function loadGuiSync({
|
|
231
|
+
forceExports,
|
|
232
|
+
cacheKey,
|
|
233
|
+
...propsIn
|
|
234
|
+
}: Partial<GuiOptions> & {
|
|
235
|
+
forceExports?: boolean
|
|
236
|
+
cacheKey?: string
|
|
237
|
+
}): GuiProjectInfo {
|
|
238
|
+
const key = JSON.stringify(propsIn)
|
|
239
|
+
|
|
240
|
+
if (last[key] && !hasBundledConfigChanged()) {
|
|
241
|
+
if (!lastVersion[key] || lastVersion[key] === cacheKey) {
|
|
242
|
+
return last[key]!
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
lastVersion[key] = cacheKey || ''
|
|
247
|
+
|
|
248
|
+
const props = getFilledOptions(propsIn)
|
|
249
|
+
|
|
250
|
+
// lets shim require and avoid importing react-native + react-native-web
|
|
251
|
+
// we just need to read the config around them
|
|
252
|
+
process.env.IS_STATIC = 'is_static'
|
|
253
|
+
process.env.HANZO_GUI_IS_SERVER = 'true'
|
|
254
|
+
|
|
255
|
+
const { unregister } = registerRequire(props.platform || 'web', {
|
|
256
|
+
proxyWormImports: !!forceExports,
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
try {
|
|
260
|
+
const devValueOG = globalThis['__DEV__' as any]
|
|
261
|
+
globalThis['__DEV__' as any] = process.env.NODE_ENV === 'development'
|
|
262
|
+
|
|
263
|
+
try {
|
|
264
|
+
// config
|
|
265
|
+
let guiConfig: GuiInternalConfig | null = null
|
|
266
|
+
if (propsIn.config) {
|
|
267
|
+
const configPath = getGuiConfigPathFromOptionsConfig(propsIn.config)
|
|
268
|
+
const exp = require(configPath)
|
|
269
|
+
|
|
270
|
+
if (!exp || exp._isProxyWorm) {
|
|
271
|
+
throw new Error(`Got a empty / proxied config!`)
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
guiConfig = (exp['default'] || exp['config'] || exp) as GuiInternalConfig
|
|
275
|
+
|
|
276
|
+
if (!guiConfig || !guiConfig.parsed) {
|
|
277
|
+
const confPath = require.resolve(configPath)
|
|
278
|
+
throw new Error(`Can't find valid config in ${confPath}:
|
|
279
|
+
|
|
280
|
+
Be sure you "export default" or "export const config" the config.`)
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// set up core
|
|
284
|
+
if (guiConfig) {
|
|
285
|
+
const { createGui } = requireGuiCore(props.platform || 'web')
|
|
286
|
+
createGui(guiConfig as any)
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// components
|
|
291
|
+
const components = loadComponentsSync(props, forceExports)
|
|
292
|
+
if (!components) {
|
|
293
|
+
throw new Error(`No components loaded`)
|
|
294
|
+
}
|
|
295
|
+
if (process.env.DEBUG === '@hanzo/gui') {
|
|
296
|
+
console.info(`components`, components)
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// undo shims
|
|
300
|
+
process.env.IS_STATIC = undefined
|
|
301
|
+
globalThis['__DEV__' as any] = devValueOG
|
|
302
|
+
|
|
303
|
+
const info = {
|
|
304
|
+
components,
|
|
305
|
+
guiConfig,
|
|
306
|
+
nameToPaths: getNameToPaths(),
|
|
307
|
+
} satisfies GuiProjectInfo
|
|
308
|
+
|
|
309
|
+
if (guiConfig) {
|
|
310
|
+
const { outputCSS } = props
|
|
311
|
+
if (outputCSS) {
|
|
312
|
+
writeGuiCSS(outputCSS, guiConfig)
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
regenerateConfigSync(props, info)
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
last[key] = {
|
|
319
|
+
...info,
|
|
320
|
+
cached: true,
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
return info as any
|
|
324
|
+
} catch (err) {
|
|
325
|
+
if (err instanceof Error) {
|
|
326
|
+
if (!SHOULD_DEBUG && !forceExports) {
|
|
327
|
+
console.warn(
|
|
328
|
+
`Error loading gui.config.ts (set DEBUG=hanzo-gui to see full stack), running hanzo-gui without custom config`
|
|
329
|
+
)
|
|
330
|
+
console.info(`\n\n ${err.message}\n\n`)
|
|
331
|
+
} else {
|
|
332
|
+
if (SHOULD_DEBUG) {
|
|
333
|
+
console.error(err)
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
} else {
|
|
337
|
+
console.error(`Error loading gui.config.ts`, err)
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
return {
|
|
341
|
+
components: [],
|
|
342
|
+
guiConfig: null,
|
|
343
|
+
nameToPaths: {},
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
} finally {
|
|
347
|
+
unregister()
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
export async function getOptions({
|
|
352
|
+
root = process.cwd(),
|
|
353
|
+
tsconfigPath = 'tsconfig.json',
|
|
354
|
+
guiOptions,
|
|
355
|
+
host,
|
|
356
|
+
debug,
|
|
357
|
+
}: Partial<CLIUserOptions> = {}): Promise<CLIResolvedOptions> {
|
|
358
|
+
const dotDir = join(root, '.gui')
|
|
359
|
+
let pkgJson = {}
|
|
360
|
+
|
|
361
|
+
try {
|
|
362
|
+
pkgJson = await fsExtra.readJSON(join(root, 'package.json'))
|
|
363
|
+
} catch (err) {
|
|
364
|
+
// ok
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
return {
|
|
368
|
+
mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',
|
|
369
|
+
root,
|
|
370
|
+
host: host || '127.0.0.1',
|
|
371
|
+
pkgJson,
|
|
372
|
+
debug,
|
|
373
|
+
tsconfigPath,
|
|
374
|
+
guiOptions: {
|
|
375
|
+
platform: (process.env.HANZO_GUI_TARGET as any) || 'web',
|
|
376
|
+
components: ['@hanzo/gui'],
|
|
377
|
+
...guiOptions,
|
|
378
|
+
config:
|
|
379
|
+
guiOptions?.config ??
|
|
380
|
+
(await getDefaultGuiConfigPath(root, guiOptions?.config)),
|
|
381
|
+
},
|
|
382
|
+
paths: {
|
|
383
|
+
root,
|
|
384
|
+
dotDir,
|
|
385
|
+
conf: join(dotDir, 'gui.config.json'),
|
|
386
|
+
types: join(dotDir, 'types.json'),
|
|
387
|
+
},
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
export function resolveWebOrNativeSpecificEntry(entry: string) {
|
|
392
|
+
const workspaceRoot = resolve()
|
|
393
|
+
const resolved = require.resolve(entry, { paths: [workspaceRoot] })
|
|
394
|
+
const ext = extname(resolved)
|
|
395
|
+
const fileName = basename(resolved).replace(ext, '')
|
|
396
|
+
const specificExt = process.env.HANZO_GUI_TARGET === 'web' ? 'web' : 'native'
|
|
397
|
+
const specificFile = join(dirname(resolved), fileName + '.' + specificExt + ext)
|
|
398
|
+
if (fsExtra.existsSync(specificFile)) {
|
|
399
|
+
return specificFile
|
|
400
|
+
}
|
|
401
|
+
return entry
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
const defaultPaths = ['gui.config.ts', join('src', 'gui.config.ts')]
|
|
405
|
+
let hasWarnedOnce = false
|
|
406
|
+
|
|
407
|
+
async function getDefaultGuiConfigPath(root: string, configPath?: string) {
|
|
408
|
+
const searchPaths = [
|
|
409
|
+
...new Set(
|
|
410
|
+
[configPath, ...defaultPaths].filter(Boolean).map((p) => join(root, p as string))
|
|
411
|
+
),
|
|
412
|
+
]
|
|
413
|
+
|
|
414
|
+
for (const path of searchPaths) {
|
|
415
|
+
if (await fsExtra.pathExists(path)) {
|
|
416
|
+
return path
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
if (!hasWarnedOnce) {
|
|
421
|
+
hasWarnedOnce = true
|
|
422
|
+
console.warn(`Warning: couldn't find gui.config.ts in the following paths given configuration "${configPath}":
|
|
423
|
+
${searchPaths.join(`\n `)}
|
|
424
|
+
`)
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
export type { GuiProjectInfo }
|
|
429
|
+
|
|
430
|
+
export async function esbuildWatchFiles(entry: string, onChanged: () => void) {
|
|
431
|
+
let hasRunOnce = false
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* We're just (ab)using this as a file watcher, so bundle = true to follow paths
|
|
435
|
+
* and then write: false and logLevel silent to avoid all errors
|
|
436
|
+
*/
|
|
437
|
+
|
|
438
|
+
const context = await esbuild.context({
|
|
439
|
+
bundle: true,
|
|
440
|
+
entryPoints: [entry],
|
|
441
|
+
resolveExtensions: ['.ts', '.tsx', '.js', '.mjs'],
|
|
442
|
+
logLevel: 'silent',
|
|
443
|
+
write: false,
|
|
444
|
+
|
|
445
|
+
alias: {
|
|
446
|
+
'@react-native/normalize-color': '@hanzogui/proxy-worm',
|
|
447
|
+
'react-native-web': '@hanzogui/react-native-web-lite',
|
|
448
|
+
'react-native': '@hanzogui/proxy-worm',
|
|
449
|
+
},
|
|
450
|
+
|
|
451
|
+
plugins: [
|
|
452
|
+
// to log what its watching:
|
|
453
|
+
// {
|
|
454
|
+
// name: 'test',
|
|
455
|
+
// setup({ onResolve }) {
|
|
456
|
+
// onResolve({ filter: /.*/ }, (args) => {
|
|
457
|
+
// console.log('wtf', args.path)
|
|
458
|
+
// })
|
|
459
|
+
// },
|
|
460
|
+
// },
|
|
461
|
+
|
|
462
|
+
{
|
|
463
|
+
name: `on-rebuild`,
|
|
464
|
+
setup({ onEnd, onResolve }) {
|
|
465
|
+
// external node modules
|
|
466
|
+
let filter = /^[^./]|^\.[^./]|^\.\.[^/]/ // Must not start with "/" or "./" or "../"
|
|
467
|
+
onResolve({ filter }, (args) => ({ path: args.path, external: true }))
|
|
468
|
+
|
|
469
|
+
onEnd(() => {
|
|
470
|
+
if (!hasRunOnce) {
|
|
471
|
+
hasRunOnce = true
|
|
472
|
+
} else {
|
|
473
|
+
onChanged()
|
|
474
|
+
}
|
|
475
|
+
})
|
|
476
|
+
},
|
|
477
|
+
},
|
|
478
|
+
],
|
|
479
|
+
})
|
|
480
|
+
|
|
481
|
+
// just returns after dispose is called i think
|
|
482
|
+
void context.watch()
|
|
483
|
+
|
|
484
|
+
return () => {
|
|
485
|
+
context.dispose()
|
|
486
|
+
}
|
|
487
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const prefix = ' '
|
|
2
|
+
|
|
3
|
+
export const logLines = (str: string, singleLine = false) => {
|
|
4
|
+
if (singleLine) {
|
|
5
|
+
return prefix + str.split(' ').join(`\n${prefix}`)
|
|
6
|
+
}
|
|
7
|
+
const lines: string[] = ['']
|
|
8
|
+
const items = str.split(' ')
|
|
9
|
+
for (const item of items) {
|
|
10
|
+
if (item.length + lines[lines.length - 1].length > 85) {
|
|
11
|
+
lines.push('')
|
|
12
|
+
}
|
|
13
|
+
lines[lines.length - 1] += item + ' '
|
|
14
|
+
}
|
|
15
|
+
return lines.map((line, i) => prefix + (i == 0 ? '' : ' ') + line.trim()).join('\n')
|
|
16
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import generate from '@babel/generator'
|
|
2
|
+
import * as t from '@babel/types'
|
|
3
|
+
import { mergeProps } from '@hanzogui/web'
|
|
4
|
+
import invariant from 'invariant'
|
|
5
|
+
import type { Ternary } from '../types'
|
|
6
|
+
import { forwardFontFamilyName } from './propsToFontFamilyCache'
|
|
7
|
+
|
|
8
|
+
export function normalizeTernaries(ternaries: Ternary[]) {
|
|
9
|
+
invariant(
|
|
10
|
+
Array.isArray(ternaries),
|
|
11
|
+
'extractStaticTernaries expects param 1 to be an array of ternaries'
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
if (ternaries.length === 0) {
|
|
15
|
+
return []
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const ternariesByKey: { [key: string]: Ternary } = {}
|
|
19
|
+
|
|
20
|
+
for (let idx = -1, len = ternaries.length; ++idx < len; ) {
|
|
21
|
+
const { test, consequent, alternate, remove, ...rest } = ternaries[idx]
|
|
22
|
+
|
|
23
|
+
let ternaryTest = test
|
|
24
|
+
|
|
25
|
+
// strip parens
|
|
26
|
+
if (t.isExpressionStatement(test)) {
|
|
27
|
+
ternaryTest = (test as any).expression
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// convert `!thing` to `thing` with swapped consequent and alternate
|
|
31
|
+
let shouldSwap = false
|
|
32
|
+
if (t.isUnaryExpression(test) && test.operator === '!') {
|
|
33
|
+
ternaryTest = test.argument
|
|
34
|
+
shouldSwap = true
|
|
35
|
+
} else if (t.isBinaryExpression(test)) {
|
|
36
|
+
if (test.operator === '!==' || test.operator === '!=') {
|
|
37
|
+
ternaryTest = t.binaryExpression(
|
|
38
|
+
test.operator.replace('!', '=') as any,
|
|
39
|
+
test.left,
|
|
40
|
+
test.right
|
|
41
|
+
)
|
|
42
|
+
shouldSwap = true
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// @ts-ignore
|
|
47
|
+
const key = generate(ternaryTest as any).code
|
|
48
|
+
|
|
49
|
+
if (!ternariesByKey[key]) {
|
|
50
|
+
ternariesByKey[key] = {
|
|
51
|
+
...rest,
|
|
52
|
+
alternate: {},
|
|
53
|
+
consequent: {},
|
|
54
|
+
test: ternaryTest,
|
|
55
|
+
remove,
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
const altStyle = (shouldSwap ? consequent : alternate) ?? {}
|
|
59
|
+
const consStyle = (shouldSwap ? alternate : consequent) ?? {}
|
|
60
|
+
|
|
61
|
+
const nextAlt = ternariesByKey[key].alternate!
|
|
62
|
+
ternariesByKey[key].alternate = mergeProps(altStyle, nextAlt)
|
|
63
|
+
forwardFontFamilyName(altStyle, ternariesByKey[key].alternate)
|
|
64
|
+
|
|
65
|
+
const nextCons = ternariesByKey[key].consequent!
|
|
66
|
+
ternariesByKey[key].consequent = mergeProps(consStyle, nextCons)
|
|
67
|
+
forwardFontFamilyName(consStyle, ternariesByKey[key].consequent)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const ternaryExpression = Object.keys(ternariesByKey).map((key) => {
|
|
71
|
+
return ternariesByKey[key]
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
return ternaryExpression
|
|
75
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// weird stuff
|
|
2
|
+
|
|
3
|
+
const cache = new WeakMap<any, string>()
|
|
4
|
+
|
|
5
|
+
export function setPropsToFontFamily(props: any, ff: string) {
|
|
6
|
+
cache.set(props, ff.replace('$', '').trim())
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function getFontFamilyNameFromProps(props: any) {
|
|
10
|
+
return cache.get(props)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function forwardFontFamilyName(prev: any, next: any, fallback?: string) {
|
|
14
|
+
const ff = getFontFamilyNameFromProps(prev) || fallback
|
|
15
|
+
if (ff) {
|
|
16
|
+
setPropsToFontFamily(next, ff)
|
|
17
|
+
}
|
|
18
|
+
}
|