@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.
Files changed (207) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1 -0
  3. package/dist/check-dep-versions.cjs +267 -0
  4. package/dist/checkDeps.cjs +200 -0
  5. package/dist/constants.cjs +49 -0
  6. package/dist/exports.cjs +44 -0
  7. package/dist/extractor/accessSafe.cjs +46 -0
  8. package/dist/extractor/babelParse.cjs +54 -0
  9. package/dist/extractor/buildClassName.cjs +62 -0
  10. package/dist/extractor/bundle.cjs +185 -0
  11. package/dist/extractor/bundleConfig.cjs +513 -0
  12. package/dist/extractor/concatClassName.cjs +80 -0
  13. package/dist/extractor/createEvaluator.cjs +75 -0
  14. package/dist/extractor/createExtractor.cjs +1150 -0
  15. package/dist/extractor/createLogger.cjs +45 -0
  16. package/dist/extractor/detectModuleFormat.cjs +49 -0
  17. package/dist/extractor/ensureImportingConcat.cjs +48 -0
  18. package/dist/extractor/errors.cjs +26 -0
  19. package/dist/extractor/esbuildAliasPlugin.cjs +44 -0
  20. package/dist/extractor/esbuildTsconfigPaths.cjs +86 -0
  21. package/dist/extractor/evaluateAstNode.cjs +83 -0
  22. package/dist/extractor/extractHelpers.cjs +119 -0
  23. package/dist/extractor/extractMediaStyle.cjs +128 -0
  24. package/dist/extractor/extractToClassNames.cjs +321 -0
  25. package/dist/extractor/extractToNative.cjs +266 -0
  26. package/dist/extractor/findTopmostFunction.cjs +34 -0
  27. package/dist/extractor/generatedUid.cjs +47 -0
  28. package/dist/extractor/getGuiConfigPathFromOptionsConfig.cjs +35 -0
  29. package/dist/extractor/getPrefixLogs.cjs +29 -0
  30. package/dist/extractor/getPropValueFromAttributes.cjs +67 -0
  31. package/dist/extractor/getSourceModule.cjs +64 -0
  32. package/dist/extractor/getStaticBindingsForScope.cjs +150 -0
  33. package/dist/extractor/hoistClassNames.cjs +62 -0
  34. package/dist/extractor/literalToAst.cjs +84 -0
  35. package/dist/extractor/loadFile.cjs +11 -0
  36. package/dist/extractor/loadGui.cjs +322 -0
  37. package/dist/extractor/logLines.cjs +35 -0
  38. package/dist/extractor/normalizeTernaries.cjs +73 -0
  39. package/dist/extractor/propsToFontFamilyCache.cjs +38 -0
  40. package/dist/extractor/regenerateConfig.cjs +150 -0
  41. package/dist/extractor/removeUnusedHooks.cjs +76 -0
  42. package/dist/extractor/timer.cjs +43 -0
  43. package/dist/extractor/validHTMLAttributes.cjs +77 -0
  44. package/dist/extractor/watchGuiConfig.cjs +58 -0
  45. package/dist/getPragmaOptions.cjs +58 -0
  46. package/dist/helpers/memoize.cjs +37 -0
  47. package/dist/helpers/requireGuiCore.cjs +33 -0
  48. package/dist/index.cjs +40 -0
  49. package/dist/registerRequire.cjs +115 -0
  50. package/dist/server.cjs +75 -0
  51. package/dist/setup.cjs +0 -0
  52. package/dist/types.cjs +16 -0
  53. package/dist/worker.cjs +89 -0
  54. package/package.json +101 -0
  55. package/src/check-dep-versions.ts +738 -0
  56. package/src/checkDeps.ts +371 -0
  57. package/src/constants.ts +14 -0
  58. package/src/exports.ts +15 -0
  59. package/src/extractor/accessSafe.ts +22 -0
  60. package/src/extractor/babelParse.ts +37 -0
  61. package/src/extractor/buildClassName.ts +76 -0
  62. package/src/extractor/bundle.ts +277 -0
  63. package/src/extractor/bundleConfig.ts +958 -0
  64. package/src/extractor/concatClassName.ts +105 -0
  65. package/src/extractor/createEvaluator.ts +82 -0
  66. package/src/extractor/createExtractor.ts +2665 -0
  67. package/src/extractor/createLogger.ts +41 -0
  68. package/src/extractor/detectModuleFormat.ts +42 -0
  69. package/src/extractor/ensureImportingConcat.ts +36 -0
  70. package/src/extractor/errors.ts +1 -0
  71. package/src/extractor/esbuildAliasPlugin.ts +40 -0
  72. package/src/extractor/esbuildTsconfigPaths.ts +103 -0
  73. package/src/extractor/evaluateAstNode.ts +136 -0
  74. package/src/extractor/extractHelpers.ts +211 -0
  75. package/src/extractor/extractMediaStyle.ts +194 -0
  76. package/src/extractor/extractToClassNames.ts +631 -0
  77. package/src/extractor/extractToNative.ts +463 -0
  78. package/src/extractor/findTopmostFunction.ts +24 -0
  79. package/src/extractor/generatedUid.ts +41 -0
  80. package/src/extractor/getGuiConfigPathFromOptionsConfig.ts +24 -0
  81. package/src/extractor/getPrefixLogs.ts +9 -0
  82. package/src/extractor/getPropValueFromAttributes.ts +95 -0
  83. package/src/extractor/getSourceModule.ts +96 -0
  84. package/src/extractor/getStaticBindingsForScope.ts +237 -0
  85. package/src/extractor/hoistClassNames.ts +52 -0
  86. package/src/extractor/literalToAst.ts +85 -0
  87. package/src/extractor/loadFile.ts +17 -0
  88. package/src/extractor/loadGui.ts +487 -0
  89. package/src/extractor/logLines.ts +16 -0
  90. package/src/extractor/normalizeTernaries.ts +75 -0
  91. package/src/extractor/propsToFontFamilyCache.ts +18 -0
  92. package/src/extractor/regenerateConfig.ts +186 -0
  93. package/src/extractor/removeUnusedHooks.ts +83 -0
  94. package/src/extractor/timer.ts +25 -0
  95. package/src/extractor/validHTMLAttributes.ts +52 -0
  96. package/src/extractor/watchGuiConfig.ts +57 -0
  97. package/src/getPragmaOptions.ts +57 -0
  98. package/src/helpers/memoize.ts +24 -0
  99. package/src/helpers/requireGuiCore.ts +28 -0
  100. package/src/index.ts +4 -0
  101. package/src/registerRequire.ts +236 -0
  102. package/src/server.ts +43 -0
  103. package/src/setup.ts +0 -0
  104. package/src/types.ts +109 -0
  105. package/src/worker.ts +142 -0
  106. package/types/check-dep-versions.d.ts +37 -0
  107. package/types/check-dep-versions.d.ts.map +1 -0
  108. package/types/checkDeps.d.ts +19 -0
  109. package/types/checkDeps.d.ts.map +1 -0
  110. package/types/constants.d.ts +6 -0
  111. package/types/constants.d.ts.map +1 -0
  112. package/types/exports.d.ts +16 -0
  113. package/types/exports.d.ts.map +1 -0
  114. package/types/extractor/accessSafe.d.ts +3 -0
  115. package/types/extractor/accessSafe.d.ts.map +1 -0
  116. package/types/extractor/babelParse.d.ts +5 -0
  117. package/types/extractor/babelParse.d.ts.map +1 -0
  118. package/types/extractor/buildClassName.d.ts +7 -0
  119. package/types/extractor/buildClassName.d.ts.map +1 -0
  120. package/types/extractor/bundle.d.ts +121 -0
  121. package/types/extractor/bundle.d.ts.map +1 -0
  122. package/types/extractor/bundleConfig.d.ts +49 -0
  123. package/types/extractor/bundleConfig.d.ts.map +1 -0
  124. package/types/extractor/concatClassName.d.ts +8 -0
  125. package/types/extractor/concatClassName.d.ts.map +1 -0
  126. package/types/extractor/createEvaluator.d.ts +12 -0
  127. package/types/extractor/createEvaluator.d.ts.map +1 -0
  128. package/types/extractor/createExtractor.d.ts +32 -0
  129. package/types/extractor/createExtractor.d.ts.map +1 -0
  130. package/types/extractor/createLogger.d.ts +3 -0
  131. package/types/extractor/createLogger.d.ts.map +1 -0
  132. package/types/extractor/detectModuleFormat.d.ts +5 -0
  133. package/types/extractor/detectModuleFormat.d.ts.map +1 -0
  134. package/types/extractor/ensureImportingConcat.d.ts +4 -0
  135. package/types/extractor/ensureImportingConcat.d.ts.map +1 -0
  136. package/types/extractor/errors.d.ts +3 -0
  137. package/types/extractor/errors.d.ts.map +1 -0
  138. package/types/extractor/esbuildAliasPlugin.d.ts +18 -0
  139. package/types/extractor/esbuildAliasPlugin.d.ts.map +1 -0
  140. package/types/extractor/esbuildTsconfigPaths.d.ts +11 -0
  141. package/types/extractor/esbuildTsconfigPaths.d.ts.map +1 -0
  142. package/types/extractor/evaluateAstNode.d.ts +3 -0
  143. package/types/extractor/evaluateAstNode.d.ts.map +1 -0
  144. package/types/extractor/extractHelpers.d.ts +28 -0
  145. package/types/extractor/extractHelpers.d.ts.map +1 -0
  146. package/types/extractor/extractMediaStyle.d.ts +11 -0
  147. package/types/extractor/extractMediaStyle.d.ts.map +1 -0
  148. package/types/extractor/extractToClassNames.d.ts +25 -0
  149. package/types/extractor/extractToClassNames.d.ts.map +1 -0
  150. package/types/extractor/extractToNative.d.ts +13 -0
  151. package/types/extractor/extractToNative.d.ts.map +1 -0
  152. package/types/extractor/findTopmostFunction.d.ts +4 -0
  153. package/types/extractor/findTopmostFunction.d.ts.map +1 -0
  154. package/types/extractor/generatedUid.d.ts +5 -0
  155. package/types/extractor/generatedUid.d.ts.map +1 -0
  156. package/types/extractor/getGuiConfigPathFromOptionsConfig.d.ts +3 -0
  157. package/types/extractor/getGuiConfigPathFromOptionsConfig.d.ts.map +1 -0
  158. package/types/extractor/getPrefixLogs.d.ts +3 -0
  159. package/types/extractor/getPrefixLogs.d.ts.map +1 -0
  160. package/types/extractor/getPropValueFromAttributes.d.ts +19 -0
  161. package/types/extractor/getPropValueFromAttributes.d.ts.map +1 -0
  162. package/types/extractor/getSourceModule.d.ts +16 -0
  163. package/types/extractor/getSourceModule.d.ts.map +1 -0
  164. package/types/extractor/getStaticBindingsForScope.d.ts +5 -0
  165. package/types/extractor/getStaticBindingsForScope.d.ts.map +1 -0
  166. package/types/extractor/hoistClassNames.d.ts +6 -0
  167. package/types/extractor/hoistClassNames.d.ts.map +1 -0
  168. package/types/extractor/literalToAst.d.ts +4 -0
  169. package/types/extractor/literalToAst.d.ts.map +1 -0
  170. package/types/extractor/loadFile.d.ts +1 -0
  171. package/types/extractor/loadFile.d.ts.map +1 -0
  172. package/types/extractor/loadGui.d.ts +22 -0
  173. package/types/extractor/loadGui.d.ts.map +1 -0
  174. package/types/extractor/logLines.d.ts +2 -0
  175. package/types/extractor/logLines.d.ts.map +1 -0
  176. package/types/extractor/normalizeTernaries.d.ts +3 -0
  177. package/types/extractor/normalizeTernaries.d.ts.map +1 -0
  178. package/types/extractor/propsToFontFamilyCache.d.ts +4 -0
  179. package/types/extractor/propsToFontFamilyCache.d.ts.map +1 -0
  180. package/types/extractor/regenerateConfig.d.ts +9 -0
  181. package/types/extractor/regenerateConfig.d.ts.map +1 -0
  182. package/types/extractor/removeUnusedHooks.d.ts +3 -0
  183. package/types/extractor/removeUnusedHooks.d.ts.map +1 -0
  184. package/types/extractor/timer.d.ts +5 -0
  185. package/types/extractor/timer.d.ts.map +1 -0
  186. package/types/extractor/validHTMLAttributes.d.ts +52 -0
  187. package/types/extractor/validHTMLAttributes.d.ts.map +1 -0
  188. package/types/extractor/watchGuiConfig.d.ts +5 -0
  189. package/types/extractor/watchGuiConfig.d.ts.map +1 -0
  190. package/types/getPragmaOptions.d.ts +8 -0
  191. package/types/getPragmaOptions.d.ts.map +1 -0
  192. package/types/helpers/memoize.d.ts +8 -0
  193. package/types/helpers/memoize.d.ts.map +1 -0
  194. package/types/helpers/requireGuiCore.d.ts +3 -0
  195. package/types/helpers/requireGuiCore.d.ts.map +1 -0
  196. package/types/index.d.ts +4 -0
  197. package/types/index.d.ts.map +1 -0
  198. package/types/registerRequire.d.ts +10 -0
  199. package/types/registerRequire.d.ts.map +1 -0
  200. package/types/server.d.ts +3 -0
  201. package/types/server.d.ts.map +1 -0
  202. package/types/setup.d.ts +1 -0
  203. package/types/setup.d.ts.map +1 -0
  204. package/types/types.d.ts +92 -0
  205. package/types/types.d.ts.map +1 -0
  206. package/types/worker.d.ts +46 -0
  207. package/types/worker.d.ts.map +1 -0
@@ -0,0 +1,371 @@
1
+ import { existsSync, readFileSync, readdirSync, realpathSync } from 'node:fs'
2
+ import { join, relative } from 'node:path'
3
+ import { CDVC } from './check-dep-versions'
4
+
5
+ export enum DEPENDENCY_TYPE {
6
+ dependencies = 'dependencies',
7
+ devDependencies = 'devDependencies',
8
+ optionalDependencies = 'optionalDependencies',
9
+ peerDependencies = 'peerDependencies',
10
+ resolutions = 'resolutions',
11
+ }
12
+
13
+ export type Options = {
14
+ depType?: readonly `${DEPENDENCY_TYPE}`[] // Allow strings so the enum type doesn't always have to be used.
15
+ fix?: boolean
16
+ ignoreDep?: readonly string[]
17
+ ignoreDepPattern?: readonly string[]
18
+ ignorePackage?: readonly string[]
19
+ ignorePackagePattern?: readonly string[]
20
+ ignorePath?: readonly string[]
21
+ ignorePathPattern?: readonly string[]
22
+ }
23
+
24
+ // critical packages that must not be duplicated at runtime
25
+ const CRITICAL_PACKAGES = ['@hanzogui/web', '@hanzogui/core', '@hanzo/gui']
26
+
27
+ /**
28
+ * Walks node_modules to find duplicate physical copies of critical hanzo-gui packages.
29
+ * Detects nested node_modules that would cause multiple runtime instances.
30
+ */
31
+ function checkDuplicateInstalls(root: string): string {
32
+ const nodeModules = join(root, 'node_modules')
33
+ if (!existsSync(nodeModules)) return ''
34
+
35
+ const duplicates = new Map<string, string[]>()
36
+
37
+ for (const pkg of CRITICAL_PACKAGES) {
38
+ const locations = findAllInstances(nodeModules, pkg)
39
+ if (locations.length > 1) {
40
+ // resolve symlinks to find truly distinct copies
41
+ const realPaths = new Set<string>()
42
+ const distinctLocations: string[] = []
43
+ for (const loc of locations) {
44
+ try {
45
+ const real = realpathSync(loc)
46
+ if (!realPaths.has(real)) {
47
+ realPaths.add(real)
48
+ distinctLocations.push(relative(root, loc))
49
+ }
50
+ } catch {
51
+ distinctLocations.push(relative(root, loc))
52
+ }
53
+ }
54
+ if (distinctLocations.length > 1) {
55
+ duplicates.set(pkg, distinctLocations)
56
+ }
57
+ }
58
+ }
59
+
60
+ if (duplicates.size === 0) return ''
61
+
62
+ const lines: string[] = [
63
+ 'Found duplicate gui installations in node_modules:',
64
+ '',
65
+ 'This causes multiple runtime instances, which breaks theme/config detection.',
66
+ '',
67
+ ]
68
+
69
+ for (const [pkg, locations] of duplicates) {
70
+ // read versions from each location
71
+ lines.push(` ${pkg}:`)
72
+ for (const loc of locations) {
73
+ const pkgJsonPath = join(root, loc, 'package.json')
74
+ let version = '?'
75
+ try {
76
+ version = JSON.parse(readFileSync(pkgJsonPath, 'utf8')).version
77
+ } catch {}
78
+ lines.push(` ${version} at ${loc}`)
79
+ }
80
+ lines.push('')
81
+ }
82
+
83
+ lines.push("Fix: run your package manager's dedupe command:")
84
+ lines.push(' bun install (bun auto-dedupes)')
85
+ lines.push(' npx yarn-deduplicate && yarn install')
86
+ lines.push(' npm dedupe')
87
+ lines.push('')
88
+ lines.push("If that doesn't help, delete node_modules and lockfile, then reinstall.")
89
+
90
+ return lines.join('\n')
91
+ }
92
+
93
+ /**
94
+ * Recursively find all instances of a package in node_modules.
95
+ * Handles both scoped (@hanzogui/web) and unscoped (gui) packages.
96
+ */
97
+ function findAllInstances(
98
+ nodeModulesDir: string,
99
+ packageName: string,
100
+ found: string[] = [],
101
+ depth = 0
102
+ ): string[] {
103
+ // don't go too deep, typical hoisting issues show up within a few levels
104
+ if (depth > 4 || !existsSync(nodeModulesDir)) return found
105
+
106
+ const pkgDir = join(nodeModulesDir, ...packageName.split('/'))
107
+ if (existsSync(join(pkgDir, 'package.json'))) {
108
+ found.push(pkgDir)
109
+ }
110
+
111
+ // scan nested node_modules inside direct children
112
+ try {
113
+ const entries = readdirSync(nodeModulesDir)
114
+ for (const entry of entries) {
115
+ if (entry.startsWith('.')) continue
116
+
117
+ if (entry.startsWith('@')) {
118
+ // scoped packages have another level
119
+ const scopeDir = join(nodeModulesDir, entry)
120
+ try {
121
+ const scopeEntries = readdirSync(scopeDir)
122
+ for (const scopeEntry of scopeEntries) {
123
+ const nested = join(scopeDir, scopeEntry, 'node_modules')
124
+ if (existsSync(nested)) {
125
+ findAllInstances(nested, packageName, found, depth + 1)
126
+ }
127
+ }
128
+ } catch {}
129
+ } else {
130
+ const nested = join(nodeModulesDir, entry, 'node_modules')
131
+ if (existsSync(nested)) {
132
+ findAllInstances(nested, packageName, found, depth + 1)
133
+ }
134
+ }
135
+ }
136
+ } catch {}
137
+
138
+ return found
139
+ }
140
+
141
+ /**
142
+ * Checks lockfile for multiple resolved versions of hanzo-gui packages.
143
+ * Supports bun.lock, yarn.lock, and package-lock.json.
144
+ */
145
+ function checkLockfileDuplicates(root: string): string {
146
+ const bunLock = join(root, 'bun.lock')
147
+ const yarnLock = join(root, 'yarn.lock')
148
+ const npmLock = join(root, 'package-lock.json')
149
+
150
+ if (existsSync(bunLock)) return checkBunLockDuplicates(bunLock)
151
+ if (existsSync(yarnLock)) return checkYarnLockDuplicates(yarnLock)
152
+ if (existsSync(npmLock)) return checkNpmLockDuplicates(npmLock)
153
+
154
+ return ''
155
+ }
156
+
157
+ function checkBunLockDuplicates(lockPath: string): string {
158
+ try {
159
+ const content = readFileSync(lockPath, 'utf8')
160
+ const duplicates = new Map<string, Set<string>>()
161
+ const criticalSet = new Set(CRITICAL_PACKAGES)
162
+
163
+ // match patterns like "@hanzogui/web@version" or "gui@version" in resolved entries
164
+ // bun.lock format: "package@version": ["resolved-url", ...]
165
+ const packagePattern = /["'](@gui\/[\w-]+|gui)@([^"'\s,]+)["']/g
166
+ let match: RegExpExecArray | null
167
+ while ((match = packagePattern.exec(content)) !== null) {
168
+ const name = match[1]
169
+ const version = match[2]
170
+ if (version.startsWith('workspace:')) continue
171
+ // only flag critical packages — leaf packages can safely differ
172
+ if (!criticalSet.has(name)) continue
173
+ if (!duplicates.has(name)) duplicates.set(name, new Set())
174
+ duplicates.get(name)!.add(version)
175
+ }
176
+
177
+ return formatLockfileDuplicates(duplicates, 'bun.lock')
178
+ } catch {
179
+ return ''
180
+ }
181
+ }
182
+
183
+ function checkYarnLockDuplicates(lockPath: string): string {
184
+ try {
185
+ const content = readFileSync(lockPath, 'utf8')
186
+ const duplicates = new Map<string, Set<string>>()
187
+ const criticalSet = new Set(CRITICAL_PACKAGES)
188
+
189
+ // yarn.lock format:
190
+ // "@hanzogui/web@^1.0.0":
191
+ // version "1.0.1"
192
+ const entryPattern = /^"?(@gui\/[\w-]+|gui)@[^":\n]+[":]?\s*$/gm
193
+ const versionPattern = /^\s+version\s+"([^"]+)"/gm
194
+
195
+ let entryMatch: RegExpExecArray | null
196
+ while ((entryMatch = entryPattern.exec(content)) !== null) {
197
+ const name = entryMatch[1]
198
+ if (!criticalSet.has(name)) continue
199
+ versionPattern.lastIndex = entryMatch.index
200
+ const verMatch = versionPattern.exec(content)
201
+ if (verMatch) {
202
+ if (!duplicates.has(name)) duplicates.set(name, new Set())
203
+ duplicates.get(name)!.add(verMatch[1])
204
+ }
205
+ }
206
+
207
+ return formatLockfileDuplicates(duplicates, 'yarn.lock')
208
+ } catch {
209
+ return ''
210
+ }
211
+ }
212
+
213
+ function checkNpmLockDuplicates(lockPath: string): string {
214
+ try {
215
+ const lock = JSON.parse(readFileSync(lockPath, 'utf8'))
216
+ const duplicates = new Map<string, Set<string>>()
217
+ const criticalSet = new Set(CRITICAL_PACKAGES)
218
+
219
+ // package-lock.json v2/v3 uses "packages" map with path keys
220
+ const packages = lock.packages || {}
221
+ for (const [path, info] of Object.entries(packages) as [string, any][]) {
222
+ if (!path) continue // skip root
223
+ const name = info.name || path.split('node_modules/').pop()
224
+ if (!name) continue
225
+ if (!criticalSet.has(name)) continue
226
+ const version = info.version
227
+ if (version) {
228
+ if (!duplicates.has(name)) duplicates.set(name, new Set())
229
+ duplicates.get(name)!.add(version)
230
+ }
231
+ }
232
+
233
+ return formatLockfileDuplicates(duplicates, 'package-lock.json')
234
+ } catch {
235
+ return ''
236
+ }
237
+ }
238
+
239
+ function formatLockfileDuplicates(
240
+ duplicates: Map<string, Set<string>>,
241
+ lockfileName: string
242
+ ): string {
243
+ // filter to only packages with multiple versions
244
+ const multiVersion = new Map<string, string[]>()
245
+ for (const [name, versions] of duplicates) {
246
+ if (versions.size > 1) {
247
+ multiVersion.set(name, [...versions].sort())
248
+ }
249
+ }
250
+
251
+ if (multiVersion.size === 0) return ''
252
+
253
+ const lines: string[] = [`Found multiple resolved versions in ${lockfileName}:`, '']
254
+
255
+ for (const [name, versions] of multiVersion) {
256
+ lines.push(` ${name}: ${versions.join(', ')}`)
257
+ }
258
+
259
+ lines.push('')
260
+ lines.push(
261
+ 'Multiple versions cause duplicate runtime instances, breaking config/theme detection.'
262
+ )
263
+ lines.push('Fix: ensure all hanzo-gui packages use the same version range, then dedupe.')
264
+
265
+ return lines.join('\n')
266
+ }
267
+
268
+ /**
269
+ * Checks that a gui config file exists in common locations.
270
+ */
271
+ function checkConfigExists(root: string): string {
272
+ const configNames = [
273
+ 'gui.config.ts',
274
+ 'gui.config.tsx',
275
+ 'gui.config.js',
276
+ 'gui.config.mjs',
277
+ 'gui.config.cjs',
278
+ ]
279
+
280
+ const searchDirs = [root, join(root, 'src'), join(root, 'app'), join(root, 'config')]
281
+
282
+ for (const dir of searchDirs) {
283
+ for (const name of configNames) {
284
+ if (existsSync(join(dir, name))) {
285
+ return ''
286
+ }
287
+ }
288
+ }
289
+
290
+ // check if gui.build.ts references a config path
291
+ const buildConfigNames = [
292
+ 'gui.build.ts',
293
+ 'gui.build.js',
294
+ 'gui.build.mjs',
295
+ 'gui.build.cjs',
296
+ ]
297
+ for (const name of buildConfigNames) {
298
+ const buildPath = join(root, name)
299
+ if (existsSync(buildPath)) {
300
+ try {
301
+ const content = readFileSync(buildPath, 'utf8')
302
+ const match = content.match(/config\s*:\s*['"`]([^'"`]+)['"`]/)
303
+ if (match) {
304
+ const configPath = join(root, match[1])
305
+ if (existsSync(configPath)) return ''
306
+ }
307
+ } catch {}
308
+ }
309
+ }
310
+
311
+ // also check if there's a gui config referenced in package.json
312
+ const pkgJsonPath = join(root, 'package.json')
313
+ if (existsSync(pkgJsonPath)) {
314
+ try {
315
+ const pkg = JSON.parse(readFileSync(pkgJsonPath, 'utf8'))
316
+ if (pkg.gui?.config) {
317
+ const configPath = join(root, pkg.gui.config)
318
+ if (existsSync(configPath)) return ''
319
+ }
320
+ } catch {}
321
+ }
322
+
323
+ // check if this is a monorepo root (has workspaces) - skip config check for root
324
+ if (existsSync(pkgJsonPath)) {
325
+ try {
326
+ const pkg = JSON.parse(readFileSync(pkgJsonPath, 'utf8'))
327
+ if (pkg.workspaces) return ''
328
+ } catch {}
329
+ }
330
+
331
+ return [
332
+ 'No gui.config file found.',
333
+ '',
334
+ 'Gui requires a config file (e.g. gui.config.ts) that calls createGui().',
335
+ 'Without it, components will throw "Can\'t find Hanzo GUI configuration" at runtime.',
336
+ '',
337
+ 'See: https://gui.hanzo.ai/docs/core/configuration',
338
+ ].join('\n')
339
+ }
340
+
341
+ export async function checkDeps(root: string) {
342
+ const issues: string[] = []
343
+
344
+ // 1. check for dependency version mismatches across workspace packages
345
+ const workspaceMismatchSummary = new CDVC(root).toMismatchSummary()
346
+ if (workspaceMismatchSummary) issues.push(workspaceMismatchSummary)
347
+
348
+ // 2. check lockfile for duplicate resolved versions of critical packages
349
+ const lockfileSummary = checkLockfileDuplicates(root)
350
+ if (lockfileSummary) issues.push(lockfileSummary)
351
+
352
+ // 3. check for duplicate physical installations in node_modules
353
+ const duplicatesSummary = checkDuplicateInstalls(root)
354
+ if (duplicatesSummary) issues.push(duplicatesSummary)
355
+
356
+ // 4. check that a config file exists
357
+ const configSummary = checkConfigExists(root)
358
+ if (configSummary) issues.push(configSummary)
359
+
360
+ if (issues.length === 0) {
361
+ console.info(`Gui dependencies look good ✅`)
362
+ process.exit(0)
363
+ }
364
+
365
+ for (let i = 0; i < issues.length; i++) {
366
+ if (i > 0) console.error('')
367
+ console.error(issues[i])
368
+ }
369
+
370
+ process.exit(1)
371
+ }
@@ -0,0 +1,14 @@
1
+ import findCacheDir from 'find-cache-dir'
2
+
3
+ export const CSS_FILE_NAME = '__snack.css'
4
+
5
+ // ENSURE THIS ISNT THE SAME AS THE SEPARATOR USED FOR STYLE KEYS
6
+ export const MEDIA_SEP = '_'
7
+
8
+ // ensure cache dir
9
+ export const cacheDir = findCacheDir({ name: 'hanzo-gui', create: true })
10
+
11
+ export const FAILED_EVAL = Symbol('failed_style_eval')
12
+
13
+ export const SHOULD_DEBUG =
14
+ process.env.DEBUG === '*' || process.env.DEBUG?.startsWith('@hanzo/gui')
package/src/exports.ts ADDED
@@ -0,0 +1,15 @@
1
+ export * from './checkDeps'
2
+ export * from './types'
3
+ export { createExtractor } from './extractor/createExtractor'
4
+ export { literalToAst } from './extractor/literalToAst'
5
+ export * from './constants'
6
+ export * from './extractor/extractToClassNames'
7
+ export * from './extractor/concatClassName'
8
+ export * from './extractor/extractToNative'
9
+ export * from './extractor/extractHelpers'
10
+ export * from './extractor/loadGui'
11
+ export * from './extractor/watchGuiConfig'
12
+ export * from './extractor/createLogger'
13
+ export * from './registerRequire'
14
+ export { detectModuleFormat, clearFormatCache } from './extractor/detectModuleFormat'
15
+ export * from './getPragmaOptions'
@@ -0,0 +1,22 @@
1
+ import * as t from '@babel/types'
2
+
3
+ // accessSafe wraps memberExpressions in object/null checks
4
+ // TODO: inject this as a function? this gets pretty repetitive
5
+ export function accessSafe(obj: t.Expression, member: string): t.LogicalExpression {
6
+ return t.logicalExpression(
7
+ '&&',
8
+ t.logicalExpression(
9
+ '&&',
10
+ // typeof obj === 'object
11
+ t.binaryExpression(
12
+ '===',
13
+ t.unaryExpression('typeof', obj),
14
+ t.stringLiteral('object')
15
+ ),
16
+ // obj !== null
17
+ t.binaryExpression('!==', obj, t.nullLiteral())
18
+ ),
19
+ // obj.member
20
+ t.memberExpression(obj, t.identifier(member), false)
21
+ )
22
+ }
@@ -0,0 +1,37 @@
1
+ import * as babelParser from '@babel/parser'
2
+ import type * as t from '@babel/types'
3
+
4
+ const plugins: babelParser.ParserPlugin[] = [
5
+ 'asyncGenerators',
6
+ 'classProperties',
7
+ 'dynamicImport',
8
+ 'functionBind',
9
+ 'jsx',
10
+ 'numericSeparator',
11
+ 'objectRestSpread',
12
+ 'optionalCatchBinding',
13
+ 'decorators-legacy',
14
+ 'typescript',
15
+ 'optionalChaining',
16
+ 'nullishCoalescingOperator',
17
+ ]
18
+
19
+ export const parserOptions: babelParser.ParserOptions = Object.freeze({
20
+ plugins,
21
+ sourceType: 'module',
22
+ })
23
+
24
+ const parser = babelParser.parse.bind(babelParser)
25
+
26
+ export function babelParse(code: string | Buffer, fileName?: string): t.File {
27
+ const codeString = code.toString()
28
+ try {
29
+ return parser(codeString, parserOptions) as any
30
+ } catch (err) {
31
+ throw new Error(
32
+ `Error parsing babel: ${err} in ${fileName}, code:\n${codeString}\n ${
33
+ (err as any).stack
34
+ }`
35
+ )
36
+ }
37
+ }
@@ -0,0 +1,76 @@
1
+ import * as t from '@babel/types'
2
+
3
+ import type { ClassNameObject } from '../types'
4
+
5
+ type Builder = (
6
+ objects: ClassNameObject[],
7
+ extras?: string
8
+ ) => t.Expression | t.StringLiteral | null
9
+
10
+ export const buildClassName: Builder = (objectsIn, extras = '') => {
11
+ let objects = buildClassNameLogic(objectsIn)
12
+ if (!objects) return null
13
+ if (t.isStringLiteral(objects)) {
14
+ // objects.value = objects.value
15
+ objects.value = `${extras} ${objects.value}`
16
+ } else {
17
+ objects = t.binaryExpression('+', t.stringLiteral(extras), objects)
18
+ }
19
+ return objects
20
+ }
21
+
22
+ export const buildClassNameLogic: Builder = (objects) => {
23
+ return objects.reduce<t.Expression | null>((acc, val) => {
24
+ if (acc == null) {
25
+ if (
26
+ // pass conditional expressions through
27
+ t.isConditionalExpression(val) ||
28
+ // pass non-null literals through
29
+ t.isStringLiteral(val) ||
30
+ t.isNumericLiteral(val)
31
+ ) {
32
+ return val
33
+ }
34
+ return t.logicalExpression('||', val, t.stringLiteral(''))
35
+ }
36
+
37
+ let inner: t.Expression
38
+ if (t.isStringLiteral(val)) {
39
+ if (t.isStringLiteral(acc)) {
40
+ // join adjacent string literals
41
+ return t.stringLiteral(`${acc.value} ${val.value}`)
42
+ }
43
+ inner = t.stringLiteral(` ${val.value}`)
44
+ } else if (t.isLiteral(val)) {
45
+ inner = t.binaryExpression('+', t.stringLiteral(' '), val)
46
+ } else if (t.isConditionalExpression(val) || t.isBinaryExpression(val)) {
47
+ if (t.isStringLiteral(acc)) {
48
+ return t.binaryExpression('+', t.stringLiteral(`${acc.value} `), val)
49
+ }
50
+ inner = t.binaryExpression('+', t.stringLiteral(' '), val)
51
+ } else if (t.isIdentifier(val) || t.isMemberExpression(val)) {
52
+ // identifiers and member expressions make for reasonable ternaries
53
+ inner = t.conditionalExpression(
54
+ val,
55
+ t.binaryExpression('+', t.stringLiteral(' '), val),
56
+ t.stringLiteral('')
57
+ )
58
+ } else {
59
+ if (t.isStringLiteral(acc)) {
60
+ return t.binaryExpression(
61
+ '+',
62
+ t.stringLiteral(`${acc.value} `),
63
+ t.logicalExpression('||', val, t.stringLiteral(''))
64
+ )
65
+ }
66
+ // use a logical expression for more complex prop values
67
+ inner = t.binaryExpression(
68
+ '+',
69
+ t.stringLiteral(' '),
70
+ t.logicalExpression('||', val, t.stringLiteral(''))
71
+ )
72
+ }
73
+
74
+ return t.binaryExpression('+', acc, inner)
75
+ }, null)
76
+ }