@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,96 @@
1
+ import * as t from '@babel/types'
2
+
3
+ export interface SourceModule {
4
+ sourceModule?: string
5
+ imported?: string
6
+ local?: string
7
+ destructured?: boolean
8
+ usesImportSyntax: boolean
9
+ }
10
+
11
+ export function getSourceModule(
12
+ itemName: string,
13
+ itemBinding: {
14
+ constant?: boolean
15
+ path: { node: t.Node; parent: any }
16
+ }
17
+ ): SourceModule | null {
18
+ // TODO: deal with reassignment
19
+ if (!itemBinding.constant) {
20
+ return null
21
+ }
22
+
23
+ let sourceModule: string | undefined
24
+ let imported: string | undefined
25
+ let local: string | undefined
26
+ let destructured: boolean | undefined
27
+ let usesImportSyntax = false
28
+
29
+ const itemNode = itemBinding.path.node
30
+
31
+ if (t.isImportDefaultSpecifier(itemNode) || t.isImportSpecifier(itemNode)) {
32
+ if (t.isImportDeclaration(itemBinding.path.parent)) {
33
+ sourceModule = itemBinding.path.parent.source.value
34
+ local = itemNode.local.name
35
+ usesImportSyntax = true
36
+ if (t.isImportSpecifier(itemNode)) {
37
+ imported = itemNode.imported['name']
38
+ destructured = true
39
+ } else {
40
+ imported = itemNode.local.name
41
+ destructured = false
42
+ }
43
+ }
44
+ } else if (
45
+ t.isVariableDeclarator(itemNode) &&
46
+ itemNode.init != null &&
47
+ t.isCallExpression(itemNode.init) &&
48
+ t.isIdentifier(itemNode.init.callee) &&
49
+ itemNode.init.callee.name === 'require' &&
50
+ itemNode.init.arguments.length === 1
51
+ ) {
52
+ const firstArg = itemNode.init.arguments[0]
53
+ if (!t.isStringLiteral(firstArg)) {
54
+ return null
55
+ }
56
+ sourceModule = firstArg.value
57
+
58
+ if (t.isIdentifier(itemNode.id)) {
59
+ local = itemNode.id.name
60
+ imported = itemNode.id.name
61
+ destructured = false
62
+ } else if (t.isObjectPattern(itemNode.id)) {
63
+ for (const objProp of itemNode.id.properties) {
64
+ if (
65
+ t.isObjectProperty(objProp) &&
66
+ t.isIdentifier(objProp.value) &&
67
+ objProp.value.name === itemName
68
+ ) {
69
+ local = objProp.value.name
70
+ // @ts-ignore TODO remove this is only an issue on CI
71
+ imported = objProp.key.name
72
+ destructured = true
73
+ break
74
+ }
75
+ }
76
+
77
+ if (!local || !imported) {
78
+ console.error('could not find prop with value `%s`', itemName)
79
+ return null
80
+ }
81
+ } else {
82
+ console.error('Unhandled id type: %s', itemNode.id.type)
83
+ return null
84
+ }
85
+ } else {
86
+ return null
87
+ }
88
+
89
+ return {
90
+ destructured,
91
+ imported,
92
+ local,
93
+ sourceModule,
94
+ usesImportSyntax,
95
+ }
96
+ }
@@ -0,0 +1,237 @@
1
+ import type { ChildProcess } from 'node:child_process'
2
+ import { fork } from 'node:child_process'
3
+ import { dirname, extname, join, resolve } from 'node:path'
4
+
5
+ import type { Binding, NodePath } from '@babel/traverse'
6
+ import * as t from '@babel/types'
7
+
8
+ import { evaluateAstNode } from './evaluateAstNode'
9
+ import { getSourceModule } from './getSourceModule'
10
+
11
+ // import { fileURLToPath } from 'node:url'
12
+ // // @ts-ignore
13
+ // const __dirname = dirname(fileURLToPath(import.meta.url))
14
+
15
+ const isLocalImport = (path: string) => path.startsWith('.') || path.startsWith('/')
16
+
17
+ function resolveImportPath(sourcePath: string, path: string) {
18
+ const sourceDir = dirname(sourcePath)
19
+ if (isLocalImport(path)) {
20
+ if (extname(path) === '') {
21
+ path += ''
22
+ }
23
+ return resolve(sourceDir, path)
24
+ }
25
+ return path
26
+ }
27
+
28
+ const cache = new Map()
29
+ const pending = new Map<string, Promise<any>>()
30
+
31
+ const loadCmd = `${join(__dirname, 'loadFile.js')}`
32
+
33
+ let exited = false
34
+
35
+ let child: ChildProcess | null = null
36
+
37
+ function forkChild() {
38
+ child = fork(loadCmd, [], {
39
+ execArgv: ['-r', 'esbuild-register'],
40
+ detached: false,
41
+ stdio: 'ignore',
42
+ })
43
+ }
44
+
45
+ export function cleanupBeforeExit() {
46
+ if (exited) return
47
+ if (!child) return
48
+ child.removeAllListeners()
49
+ child.unref()
50
+ child.disconnect()
51
+ child.kill()
52
+ exited = true
53
+ }
54
+
55
+ process.once('SIGTERM', cleanupBeforeExit)
56
+ process.once('SIGINT', cleanupBeforeExit)
57
+ process.once('beforeExit', cleanupBeforeExit)
58
+
59
+ function importModule(path: string) {
60
+ if (!child) {
61
+ forkChild()
62
+ }
63
+ if (pending.has(path)) {
64
+ return pending.get(path)
65
+ }
66
+ const promise = new Promise((res, rej) => {
67
+ if (!child) return
68
+ if (cache.size > 2000) {
69
+ cache.clear()
70
+ }
71
+ if (cache.has(path)) {
72
+ return cache.get(path)
73
+ }
74
+ const listener = (msg: any) => {
75
+ if (!child) return
76
+ if (!msg) return
77
+ if (typeof msg !== 'string') return
78
+ if (msg[0] === '-') {
79
+ rej(new Error(msg.slice(1)))
80
+ return
81
+ }
82
+ child.removeListener('message', listener)
83
+ const val = JSON.parse(msg)
84
+ cache.set(path, val)
85
+ res(val)
86
+ }
87
+ child.once('message', listener)
88
+ child.send(`${path.replace('.js', '')}`)
89
+ }).finally(() => {
90
+ // clean up pending map to prevent memory leak
91
+ pending.delete(path)
92
+ })
93
+ pending.set(path, promise)
94
+ return promise
95
+ }
96
+
97
+ export async function getStaticBindingsForScope(
98
+ scope: NodePath<t.JSXElement>['scope'],
99
+ whitelist: string[] = [],
100
+ sourcePath: string,
101
+ bindingCache: Record<string, string | null>,
102
+ shouldPrintDebug: boolean | 'verbose'
103
+ ): Promise<Record<string, any>> {
104
+ const bindings: Record<string, Binding> = scope.getAllBindings() as any
105
+ const ret: Record<string, any> = {}
106
+
107
+ if (shouldPrintDebug) {
108
+ // prettier-ignore
109
+ // console.info(' ', Object.keys(bindings).length, 'variables in scope')
110
+ // .map(x => bindings[x].identifier?.name).join(', ')
111
+ }
112
+
113
+ // on react native at least it doesnt find some bindings? not sure why
114
+ // lets add in whitelisted imports if they exist
115
+ const program = scope.getProgramParent().block as t.Program
116
+ for (const node of program.body) {
117
+ if (t.isImportDeclaration(node)) {
118
+ const importPath = node.source.value
119
+ if (!node.specifiers.length) continue
120
+ if (!isLocalImport(importPath)) {
121
+ continue
122
+ }
123
+ const moduleName = resolveImportPath(sourcePath, importPath)
124
+ const isOnWhitelist = whitelist.some((test) => moduleName.endsWith(test))
125
+ if (!isOnWhitelist) continue
126
+ try {
127
+ const src = await importModule(moduleName)
128
+ if (!src) continue
129
+ for (const specifier of node.specifiers) {
130
+ if (t.isImportSpecifier(specifier) && t.isIdentifier(specifier.imported)) {
131
+ if (typeof src[specifier.imported.name] !== 'undefined') {
132
+ const val = src[specifier.local.name]
133
+ ret[specifier.local.name] = val
134
+ }
135
+ }
136
+ }
137
+ } catch (err: any) {
138
+ if (shouldPrintDebug) {
139
+ console.warn(
140
+ ` | Skipping partial evaluation of constant file: ${moduleName} (DEBUG=hanzo-gui for more)`
141
+ )
142
+ } else if (process.env.DEBUG?.startsWith('@hanzo/gui')) {
143
+ console.info(`Error in partial evaluation`, err.message, err.stack)
144
+ }
145
+ }
146
+ }
147
+ }
148
+
149
+ if (!bindingCache) {
150
+ throw new Error('BindingCache is a required param')
151
+ }
152
+
153
+ for (const k in bindings) {
154
+ const binding = bindings[k]
155
+
156
+ // check to see if the item is a module
157
+ const sourceModule = getSourceModule(k, binding)
158
+ if (sourceModule) {
159
+ if (!sourceModule.sourceModule) {
160
+ continue
161
+ }
162
+
163
+ const moduleName = resolveImportPath(sourcePath, sourceModule.sourceModule)
164
+ const isOnWhitelist = whitelist.some((test) => moduleName.endsWith(test))
165
+
166
+ // TODO we could cache this at the file level.. and check if its been touched since
167
+
168
+ if (isOnWhitelist) {
169
+ const src = importModule(moduleName)
170
+ if (!src) {
171
+ console.info(
172
+ ` | ⚠️ Missing file ${moduleName} via ${sourcePath} import ${sourceModule.sourceModule}?`
173
+ )
174
+ return {}
175
+ }
176
+ if (sourceModule.destructured) {
177
+ if (sourceModule.imported) {
178
+ ret[k] = src[sourceModule.imported]
179
+ }
180
+ } else {
181
+ ret[k] = src
182
+ }
183
+ }
184
+ continue
185
+ }
186
+
187
+ const { parent } = binding.path
188
+
189
+ if (!t.isVariableDeclaration(parent) || parent.kind !== 'const') {
190
+ continue
191
+ }
192
+
193
+ // pick out the right variable declarator
194
+ const dec = parent.declarations.find((d) => t.isIdentifier(d.id) && d.id.name === k)
195
+
196
+ // if init is not set, there's nothing to evaluate
197
+ // TODO: handle spread syntax
198
+ if (!dec || !dec.init) {
199
+ continue
200
+ }
201
+
202
+ // missing start/end will break caching
203
+ if (typeof dec.id.start !== 'number' || typeof dec.id.end !== 'number') {
204
+ console.error('dec.id.start/end is not a number')
205
+ continue
206
+ }
207
+
208
+ if (!t.isIdentifier(dec.id)) {
209
+ console.error('dec is not an identifier')
210
+ continue
211
+ }
212
+
213
+ const cacheKey = `${dec.id.name}_${dec.id.start}-${dec.id.end}`
214
+
215
+ // retrieve value from cache
216
+ if (Object.hasOwnProperty.call(bindingCache, cacheKey)) {
217
+ ret[k] = bindingCache[cacheKey]
218
+ continue
219
+ }
220
+ // retrieve value from cache
221
+ if (Object.hasOwnProperty.call(bindingCache, cacheKey)) {
222
+ ret[k] = bindingCache[cacheKey]
223
+ continue
224
+ }
225
+
226
+ // evaluate
227
+ try {
228
+ ret[k] = evaluateAstNode(dec.init, undefined, shouldPrintDebug)
229
+ bindingCache[cacheKey] = ret[k]
230
+ continue
231
+ } catch {
232
+ // skip
233
+ }
234
+ }
235
+
236
+ return ret
237
+ }
@@ -0,0 +1,52 @@
1
+ import type { NodePath } from '@babel/traverse'
2
+ import * as t from '@babel/types'
3
+
4
+ export function hoistClassNames(
5
+ path: NodePath<t.JSXElement>,
6
+ existing: { [key: string]: t.Identifier },
7
+ expr: t.Expression
8
+ ) {
9
+ const hoist = hoistClassNames.bind(null, path, existing)
10
+ if (t.isStringLiteral(expr)) {
11
+ if (expr.value.trim() === '') {
12
+ return expr
13
+ }
14
+ if (existing[expr.value]) {
15
+ return existing[expr.value]
16
+ }
17
+ const identifier = replaceStringWithVariable(expr)
18
+ existing[expr.value] = identifier
19
+ return identifier
20
+ }
21
+ if (t.isBinaryExpression(expr)) {
22
+ if (t.isPrivateName(expr.left)) {
23
+ throw new Error(`no private name`)
24
+ }
25
+ return t.binaryExpression(expr.operator, hoist(expr.left), hoist(expr.right))
26
+ }
27
+ if (t.isLogicalExpression(expr)) {
28
+ return t.logicalExpression(expr.operator, hoist(expr.left), hoist(expr.right))
29
+ }
30
+ if (t.isConditionalExpression(expr)) {
31
+ return t.conditionalExpression(
32
+ expr.test,
33
+ hoist(expr.consequent),
34
+ hoist(expr.alternate)
35
+ )
36
+ }
37
+ return expr
38
+
39
+ function replaceStringWithVariable(str: t.StringLiteral): t.Identifier {
40
+ // hoist outside fn!
41
+ const uid = path.scope.generateUidIdentifier('cn')
42
+ const parent = path.findParent((path) => path.isProgram())
43
+ if (!parent) throw new Error(`no program?`)
44
+ const variable = t.variableDeclaration('const', [
45
+ // adding a space for extra safety
46
+ t.variableDeclarator(uid, t.stringLiteral(` ${str.value}`)),
47
+ ])
48
+ // @ts-ignore
49
+ parent.unshiftContainer('body', variable)
50
+ return uid
51
+ }
52
+ }
@@ -0,0 +1,85 @@
1
+ import * as t from '@babel/types'
2
+
3
+ export function literalToAst(literal: any): t.Expression {
4
+ if (literal === null) {
5
+ return t.nullLiteral()
6
+ }
7
+ switch (typeof literal) {
8
+ case 'function':
9
+ throw new Error('Unsupported')
10
+ case 'number':
11
+ return t.numericLiteral(literal)
12
+ case 'string':
13
+ return t.stringLiteral(literal)
14
+ case 'boolean':
15
+ return t.booleanLiteral(literal)
16
+ case 'undefined':
17
+ return t.unaryExpression('void', t.numericLiteral(0), true)
18
+ default:
19
+ if (Array.isArray(literal)) {
20
+ return t.arrayExpression(literal.map(literalToAst))
21
+ }
22
+ return t.objectExpression(
23
+ Object.keys(literal)
24
+ .filter((k) => {
25
+ return typeof literal[k] !== 'undefined'
26
+ })
27
+ .map((k) => {
28
+ return t.objectProperty(t.stringLiteral(k), literalToAst(literal[k]))
29
+ })
30
+ )
31
+ }
32
+ }
33
+
34
+ const easyPeasies = ['BooleanLiteral', 'StringLiteral', 'NumericLiteral']
35
+
36
+ export function astToLiteral(node: any) {
37
+ if (!node) {
38
+ return
39
+ }
40
+ if (easyPeasies.includes(node.type)) {
41
+ return node.value
42
+ }
43
+ if (node.name === 'undefined' && !node.value) {
44
+ return undefined
45
+ }
46
+ if (t.isNullLiteral(node)) {
47
+ return null
48
+ }
49
+ if (t.isObjectExpression(node)) {
50
+ return computeProps(node.properties)
51
+ }
52
+ if (t.isArrayExpression(node)) {
53
+ return node.elements.reduce(
54
+ // @ts-ignore
55
+ (acc, element) => [
56
+ ...acc,
57
+ ...(element?.type === 'SpreadElement'
58
+ ? astToLiteral(element.argument)
59
+ : [astToLiteral(element)]),
60
+ ],
61
+ []
62
+ )
63
+ }
64
+ }
65
+
66
+ function computeProps(props) {
67
+ return props.reduce((acc, prop) => {
68
+ if (prop.type === 'SpreadElement') {
69
+ return {
70
+ ...acc,
71
+ ...astToLiteral(prop.argument),
72
+ }
73
+ }
74
+ if (prop.type !== 'ObjectMethod') {
75
+ const val = astToLiteral(prop.value)
76
+ if (val !== undefined) {
77
+ return {
78
+ ...acc,
79
+ [prop.key.name]: val,
80
+ }
81
+ }
82
+ }
83
+ return acc
84
+ }, {})
85
+ }
@@ -0,0 +1,17 @@
1
+ process.on('message', (path) => {
2
+ if (typeof path !== 'string') {
3
+ throw new Error(`Not a string: ${path}`)
4
+ }
5
+ try {
6
+ const out = require(path)
7
+ process.send?.(JSON.stringify(out))
8
+ } catch (err) {
9
+ if (err instanceof Error) {
10
+ process.send?.(`-${err.message}\n${err.stack}`)
11
+ } else {
12
+ process.send?.(`-${err}`)
13
+ }
14
+ }
15
+ })
16
+
17
+ setInterval(() => {}, 1000)