@tamagui/static 1.0.0-alpha.2 → 1.0.0-alpha.23

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 (204) hide show
  1. package/dist/cjs/constants.js +33 -0
  2. package/dist/cjs/constants.js.map +7 -0
  3. package/dist/cjs/extractor/accessSafe.js +33 -0
  4. package/dist/cjs/extractor/accessSafe.js.map +7 -0
  5. package/dist/cjs/extractor/babelParse.js +52 -0
  6. package/dist/cjs/extractor/babelParse.js.map +7 -0
  7. package/dist/cjs/extractor/buildClassName.js +62 -0
  8. package/dist/cjs/extractor/buildClassName.js.map +7 -0
  9. package/dist/cjs/extractor/createEvaluator.js +73 -0
  10. package/dist/cjs/extractor/createEvaluator.js.map +7 -0
  11. package/dist/cjs/extractor/createExtractor.js +903 -0
  12. package/dist/cjs/extractor/createExtractor.js.map +7 -0
  13. package/dist/cjs/extractor/ensureImportingConcat.js +46 -0
  14. package/dist/cjs/extractor/ensureImportingConcat.js.map +7 -0
  15. package/dist/cjs/extractor/evaluateAstNode.js +116 -0
  16. package/dist/cjs/extractor/evaluateAstNode.js.map +7 -0
  17. package/dist/cjs/extractor/extractHelpers.js +118 -0
  18. package/dist/cjs/extractor/extractHelpers.js.map +7 -0
  19. package/dist/cjs/extractor/extractMediaStyle.js +187 -0
  20. package/dist/cjs/extractor/extractMediaStyle.js.map +7 -0
  21. package/dist/cjs/extractor/extractToClassNames.js +279 -0
  22. package/dist/cjs/extractor/extractToClassNames.js.map +7 -0
  23. package/dist/cjs/extractor/findTopmostFunction.js +29 -0
  24. package/dist/cjs/extractor/findTopmostFunction.js.map +7 -0
  25. package/dist/cjs/extractor/generatedUid.js +50 -0
  26. package/dist/cjs/extractor/generatedUid.js.map +7 -0
  27. package/dist/cjs/extractor/getPropValueFromAttributes.js +71 -0
  28. package/dist/cjs/extractor/getPropValueFromAttributes.js.map +7 -0
  29. package/dist/cjs/extractor/getSourceModule.js +91 -0
  30. package/dist/cjs/extractor/getSourceModule.js.map +7 -0
  31. package/dist/cjs/extractor/getStaticBindingsForScope.js +150 -0
  32. package/dist/cjs/extractor/getStaticBindingsForScope.js.map +7 -0
  33. package/dist/cjs/extractor/hoistClassNames.js +66 -0
  34. package/dist/cjs/extractor/hoistClassNames.js.map +7 -0
  35. package/dist/cjs/extractor/literalToAst.js +56 -0
  36. package/dist/cjs/extractor/literalToAst.js.map +7 -0
  37. package/dist/cjs/extractor/loadTamagui.js +63 -0
  38. package/dist/cjs/extractor/loadTamagui.js.map +7 -0
  39. package/dist/cjs/extractor/logLines.js +23 -0
  40. package/dist/cjs/extractor/logLines.js.map +7 -0
  41. package/dist/cjs/extractor/normalizeTernaries.js +102 -0
  42. package/dist/cjs/extractor/normalizeTernaries.js.map +7 -0
  43. package/dist/cjs/extractor/removeUnusedHooks.js +101 -0
  44. package/dist/cjs/extractor/removeUnusedHooks.js.map +7 -0
  45. package/dist/cjs/index.js +37 -0
  46. package/dist/cjs/index.js.map +7 -0
  47. package/dist/cjs/patchReactNativeWeb.js +129 -0
  48. package/dist/cjs/patchReactNativeWeb.js.map +7 -0
  49. package/dist/cjs/types.js +4 -0
  50. package/dist/cjs/types.js.map +7 -0
  51. package/dist/{constants.js → esm/constants.js} +0 -0
  52. package/dist/{constants.js.map → esm/constants.js.map} +1 -1
  53. package/dist/{extractor → esm/extractor}/accessSafe.js +0 -0
  54. package/dist/{extractor → esm/extractor}/accessSafe.js.map +1 -1
  55. package/dist/{extractor → esm/extractor}/babelParse.js +0 -0
  56. package/dist/{extractor → esm/extractor}/babelParse.js.map +1 -1
  57. package/dist/{extractor → esm/extractor}/buildClassName.js +0 -0
  58. package/dist/{extractor → esm/extractor}/buildClassName.js.map +1 -1
  59. package/dist/{extractor → esm/extractor}/createEvaluator.js +0 -0
  60. package/dist/{extractor → esm/extractor}/createEvaluator.js.map +1 -1
  61. package/dist/{extractor → esm/extractor}/createExtractor.js +92 -54
  62. package/dist/esm/extractor/createExtractor.js.map +7 -0
  63. package/dist/{extractor → esm/extractor}/ensureImportingConcat.js +0 -0
  64. package/dist/{extractor → esm/extractor}/ensureImportingConcat.js.map +1 -1
  65. package/dist/{extractor → esm/extractor}/evaluateAstNode.js +0 -0
  66. package/dist/{extractor → esm/extractor}/evaluateAstNode.js.map +1 -1
  67. package/dist/{extractor → esm/extractor}/extractHelpers.js +3 -1
  68. package/dist/{extractor → esm/extractor}/extractHelpers.js.map +3 -3
  69. package/dist/{extractor → esm/extractor}/extractMediaStyle.js +0 -0
  70. package/dist/{extractor → esm/extractor}/extractMediaStyle.js.map +1 -1
  71. package/dist/{extractor → esm/extractor}/extractToClassNames.js +21 -24
  72. package/dist/esm/extractor/extractToClassNames.js.map +7 -0
  73. package/dist/{extractor → esm/extractor}/findTopmostFunction.js +0 -0
  74. package/dist/{extractor → esm/extractor}/findTopmostFunction.js.map +1 -1
  75. package/dist/{extractor → esm/extractor}/generatedUid.js +0 -0
  76. package/dist/{extractor → esm/extractor}/generatedUid.js.map +1 -1
  77. package/dist/{extractor → esm/extractor}/getPropValueFromAttributes.js +0 -0
  78. package/dist/{extractor → esm/extractor}/getPropValueFromAttributes.js.map +1 -1
  79. package/dist/{extractor → esm/extractor}/getSourceModule.js +0 -0
  80. package/dist/{extractor → esm/extractor}/getSourceModule.js.map +1 -1
  81. package/dist/{extractor → esm/extractor}/getStaticBindingsForScope.js +0 -0
  82. package/dist/{extractor → esm/extractor}/getStaticBindingsForScope.js.map +1 -1
  83. package/dist/{extractor → esm/extractor}/hoistClassNames.js +0 -0
  84. package/dist/{extractor → esm/extractor}/hoistClassNames.js.map +1 -1
  85. package/dist/{extractor → esm/extractor}/literalToAst.js +0 -0
  86. package/dist/{extractor → esm/extractor}/literalToAst.js.map +1 -1
  87. package/dist/{extractor → esm/extractor}/loadTamagui.js +0 -0
  88. package/dist/{extractor → esm/extractor}/loadTamagui.js.map +1 -1
  89. package/dist/esm/extractor/logLines.js +17 -0
  90. package/dist/esm/extractor/logLines.js.map +7 -0
  91. package/dist/{extractor → esm/extractor}/normalizeTernaries.js +0 -0
  92. package/dist/{extractor → esm/extractor}/normalizeTernaries.js.map +1 -1
  93. package/dist/{extractor → esm/extractor}/removeUnusedHooks.js +0 -0
  94. package/dist/{extractor → esm/extractor}/removeUnusedHooks.js.map +1 -1
  95. package/dist/{index.js → esm/index.js} +0 -0
  96. package/dist/{index.js.map → esm/index.js.map} +1 -1
  97. package/dist/{patchReactNativeWeb.js → esm/patchReactNativeWeb.js} +18 -3
  98. package/dist/esm/patchReactNativeWeb.js.map +7 -0
  99. package/dist/{types.js → esm/types.js} +0 -0
  100. package/dist/{types.js.map → esm/types.js.map} +0 -0
  101. package/dist/jsx/constants.js +9 -0
  102. package/dist/jsx/extractor/accessSafe.js +10 -0
  103. package/dist/jsx/extractor/babelParse.js +29 -0
  104. package/dist/jsx/extractor/buildClassName.js +39 -0
  105. package/dist/jsx/extractor/createEvaluator.js +50 -0
  106. package/dist/jsx/extractor/createExtractor.js +839 -0
  107. package/dist/jsx/extractor/ensureImportingConcat.js +23 -0
  108. package/dist/jsx/extractor/evaluateAstNode.js +93 -0
  109. package/dist/jsx/extractor/extractHelpers.js +93 -0
  110. package/dist/jsx/extractor/extractMediaStyle.js +150 -0
  111. package/dist/jsx/extractor/extractToClassNames.js +239 -0
  112. package/dist/jsx/extractor/findTopmostFunction.js +22 -0
  113. package/dist/jsx/extractor/generatedUid.js +27 -0
  114. package/dist/jsx/extractor/getPropValueFromAttributes.js +48 -0
  115. package/dist/jsx/extractor/getSourceModule.js +68 -0
  116. package/dist/jsx/extractor/getStaticBindingsForScope.js +127 -0
  117. package/dist/jsx/extractor/hoistClassNames.js +43 -0
  118. package/dist/jsx/extractor/literalToAst.js +33 -0
  119. package/dist/jsx/extractor/loadTamagui.js +40 -0
  120. package/dist/jsx/extractor/logLines.js +16 -0
  121. package/dist/jsx/extractor/normalizeTernaries.js +51 -0
  122. package/dist/jsx/extractor/removeUnusedHooks.js +77 -0
  123. package/dist/jsx/index.js +13 -0
  124. package/{src/patchReactNativeWeb.ts → dist/jsx/patchReactNativeWeb.js} +44 -45
  125. package/dist/jsx/types.js +0 -0
  126. package/package.json +19 -16
  127. package/types/constants.d.ts +4 -0
  128. package/types/constants.d.ts.map +1 -0
  129. package/types/extractor/accessSafe.d.ts +3 -0
  130. package/types/extractor/accessSafe.d.ts.map +1 -0
  131. package/types/extractor/babelParse.d.ts +5 -0
  132. package/types/extractor/babelParse.d.ts.map +1 -0
  133. package/types/extractor/buildClassName.d.ts +4 -0
  134. package/types/extractor/buildClassName.d.ts.map +1 -0
  135. package/types/extractor/createEvaluator.d.ts +12 -0
  136. package/types/extractor/createEvaluator.d.ts.map +1 -0
  137. package/types/extractor/createExtractor.d.ts +14 -0
  138. package/types/extractor/createExtractor.d.ts.map +1 -0
  139. package/types/extractor/ensureImportingConcat.d.ts +4 -0
  140. package/types/extractor/ensureImportingConcat.d.ts.map +1 -0
  141. package/types/extractor/evaluateAstNode.d.ts +3 -0
  142. package/types/extractor/evaluateAstNode.d.ts.map +1 -0
  143. package/types/extractor/extractHelpers.d.ts +12 -0
  144. package/types/extractor/extractHelpers.d.ts.map +1 -0
  145. package/types/extractor/extractMediaStyle.d.ts +10 -0
  146. package/types/extractor/extractMediaStyle.d.ts.map +1 -0
  147. package/types/extractor/extractToClassNames.d.ts +22 -0
  148. package/types/extractor/extractToClassNames.d.ts.map +1 -0
  149. package/types/extractor/findTopmostFunction.d.ts +4 -0
  150. package/types/extractor/findTopmostFunction.d.ts.map +1 -0
  151. package/types/extractor/generatedUid.d.ts +5 -0
  152. package/types/extractor/generatedUid.d.ts.map +1 -0
  153. package/types/extractor/getPropValueFromAttributes.d.ts +3 -0
  154. package/types/extractor/getPropValueFromAttributes.d.ts.map +1 -0
  155. package/types/extractor/getSourceModule.d.ts +16 -0
  156. package/types/extractor/getSourceModule.d.ts.map +1 -0
  157. package/types/extractor/getStaticBindingsForScope.d.ts +4 -0
  158. package/types/extractor/getStaticBindingsForScope.d.ts.map +1 -0
  159. package/types/extractor/hoistClassNames.d.ts +6 -0
  160. package/types/extractor/hoistClassNames.d.ts.map +1 -0
  161. package/types/extractor/literalToAst.d.ts +3 -0
  162. package/types/extractor/literalToAst.d.ts.map +1 -0
  163. package/types/extractor/loadTamagui.d.ts +9 -0
  164. package/types/extractor/loadTamagui.d.ts.map +1 -0
  165. package/types/extractor/logLines.d.ts +2 -0
  166. package/types/extractor/logLines.d.ts.map +1 -0
  167. package/types/extractor/normalizeTernaries.d.ts +3 -0
  168. package/types/extractor/normalizeTernaries.d.ts.map +1 -0
  169. package/types/extractor/removeUnusedHooks.d.ts +3 -0
  170. package/types/extractor/removeUnusedHooks.d.ts.map +1 -0
  171. package/types/index.d.ts +8 -0
  172. package/types/index.d.ts.map +1 -0
  173. package/types/patchReactNativeWeb.d.ts +2 -0
  174. package/types/patchReactNativeWeb.d.ts.map +1 -0
  175. package/types/types.d.ts +79 -0
  176. package/types/types.d.ts.map +1 -0
  177. package/dist/extractor/createExtractor.js.map +0 -7
  178. package/dist/extractor/extractToClassNames.js.map +0 -7
  179. package/dist/index.cjs +0 -2080
  180. package/dist/index.cjs.map +0 -7
  181. package/dist/patchReactNativeWeb.js.map +0 -7
  182. package/src/constants.ts +0 -10
  183. package/src/extractor/accessSafe.ts +0 -18
  184. package/src/extractor/babelParse.ts +0 -27
  185. package/src/extractor/buildClassName.ts +0 -61
  186. package/src/extractor/createEvaluator.ts +0 -68
  187. package/src/extractor/createExtractor.ts +0 -1115
  188. package/src/extractor/ensureImportingConcat.ts +0 -33
  189. package/src/extractor/evaluateAstNode.ts +0 -121
  190. package/src/extractor/extractHelpers.ts +0 -101
  191. package/src/extractor/extractMediaStyle.ts +0 -191
  192. package/src/extractor/extractToClassNames.ts +0 -337
  193. package/src/extractor/findTopmostFunction.ts +0 -22
  194. package/src/extractor/generatedUid.ts +0 -43
  195. package/src/extractor/getPropValueFromAttributes.ts +0 -92
  196. package/src/extractor/getSourceModule.ts +0 -101
  197. package/src/extractor/getStaticBindingsForScope.ts +0 -173
  198. package/src/extractor/hoistClassNames.ts +0 -45
  199. package/src/extractor/literalToAst.ts +0 -32
  200. package/src/extractor/loadTamagui.ts +0 -61
  201. package/src/extractor/normalizeTernaries.ts +0 -60
  202. package/src/extractor/removeUnusedHooks.ts +0 -76
  203. package/src/index.ts +0 -9
  204. package/src/types.ts +0 -80
@@ -1,1115 +0,0 @@
1
- import traverse, { NodePath, Visitor } from '@babel/traverse'
2
- import * as t from '@babel/types'
3
- import type { StaticConfigParsed, TamaguiInternalConfig } from '@tamagui/core'
4
- import * as CoreNode from '@tamagui/core-node'
5
- import { stylePropsTransform } from '@tamagui/helpers'
6
- import { difference, pick } from 'lodash'
7
-
8
- import { ExtractedAttr, ExtractedAttrAttr, ExtractorParseProps, Ternary } from '../types'
9
- import { createEvaluator, createSafeEvaluator } from './createEvaluator'
10
- import { evaluateAstNode } from './evaluateAstNode'
11
- import { attrStr, findComponentName, isInsideTamagui, isPresent, objToStr } from './extractHelpers'
12
- import { findTopmostFunction } from './findTopmostFunction'
13
- import { getStaticBindingsForScope } from './getStaticBindingsForScope'
14
- import { literalToAst } from './literalToAst'
15
- import { loadTamagui } from './loadTamagui'
16
- import { normalizeTernaries } from './normalizeTernaries'
17
- import { removeUnusedHooks } from './removeUnusedHooks'
18
-
19
- const { mediaQueryConfig, postProcessStyles, pseudos } = CoreNode
20
-
21
- export const FAILED_EVAL = Symbol('failed_style_eval')
22
- const UNTOUCHED_PROPS = {
23
- key: true,
24
- style: true,
25
- className: true,
26
- }
27
-
28
- const isAttr = (x: ExtractedAttr): x is ExtractedAttrAttr => x.type === 'attr'
29
-
30
- const validHooks = {
31
- useMedia: true,
32
- useTheme: true,
33
- }
34
-
35
- export type Extractor = ReturnType<typeof createExtractor>
36
-
37
- const createTernary = (x: Ternary) => x
38
-
39
- export function createExtractor() {
40
- const shouldAddDebugProp =
41
- // really basic disable this for next.js because it messes with ssr
42
- !process.env.npm_package_dependencies_next &&
43
- process.env.TAMAGUI_TARGET !== 'native' &&
44
- process.env.IDENTIFY_TAGS !== 'false' &&
45
- (process.env.NODE_ENV === 'development' || process.env.DEBUG || process.env.IDENTIFY_TAGS)
46
-
47
- // ts imports
48
- require('esbuild-register/dist/node').register({
49
- target: 'es2019',
50
- format: 'cjs',
51
- })
52
-
53
- let loadedTamaguiConfig: TamaguiInternalConfig
54
-
55
- return {
56
- getTamaguiConfig() {
57
- return loadedTamaguiConfig
58
- },
59
- parse: (
60
- fileOrPath: NodePath<t.Program> | t.File,
61
- {
62
- config = 'tamagui.config.ts',
63
- importsWhitelist = ['constants.js'],
64
- evaluateVars = true,
65
- shouldPrintDebug = false,
66
- sourcePath = '',
67
- onExtractTag,
68
- getFlattenedNode,
69
- onDidFlatten,
70
- ...props
71
- }: ExtractorParseProps
72
- ) => {
73
- if (sourcePath === '') {
74
- throw new Error(`Must provide a source file name`)
75
- }
76
- if (!Array.isArray(props.components)) {
77
- throw new Error(`Must provide components array with list of Tamagui component modules`)
78
- }
79
-
80
- // we require it after parse because we need to set some global/env stuff before importing
81
- // otherwise we'd import `rnw` and cause it to evaluate react-native-web which causes errors
82
- const { components, tamaguiConfig } = loadTamagui({
83
- config,
84
- components: props.components || ['tamagui'],
85
- })
86
-
87
- loadedTamaguiConfig = tamaguiConfig
88
-
89
- const defaultTheme = tamaguiConfig.themes[Object.keys(tamaguiConfig.themes)[0]]
90
-
91
- // TODO this can be passed in / set based on if source changed
92
- // const shouldReCheckTheme = false //Date.now() - hasParsedFileLast > 600
93
- // hasParsedFileLast = Date.now()
94
-
95
- let doesUseValidImport = false
96
- const body = fileOrPath.type === 'Program' ? fileOrPath.get('body') : fileOrPath.program.body
97
-
98
- /**
99
- * Step 1: Determine if importing any statically extractable components
100
- */
101
- const isInternalImport = (importStr: string) =>
102
- isInsideTamagui(sourcePath) && importStr[0] === '.'
103
-
104
- const validComponents: { [key: string]: any } = Object.keys(components)
105
- .filter((key) => !!components[key]?.staticConfig)
106
- .reduce((obj, name) => {
107
- obj[name] = components[name]
108
- return obj
109
- }, {})
110
-
111
- for (const bodyPath of body) {
112
- if (bodyPath.type !== 'ImportDeclaration') continue
113
- const node = ('node' in bodyPath ? bodyPath.node : bodyPath) as any
114
- const from = node.source.value
115
- if (props.components.includes(from) || isInternalImport(from)) {
116
- if (
117
- node.specifiers.some((specifier) => {
118
- const name = specifier.local.name
119
- return validComponents[name] || validHooks[name]
120
- })
121
- ) {
122
- console.log('WHAT')
123
- doesUseValidImport = true
124
- break
125
- }
126
- }
127
- }
128
-
129
- if (shouldPrintDebug) {
130
- console.log(sourcePath, { doesUseValidImport })
131
- }
132
-
133
- if (!doesUseValidImport) {
134
- return null
135
- }
136
-
137
- let couldntParse = false
138
- const modifiedComponents = new Set<NodePath<any>>()
139
-
140
- // only keeping a cache around per-file, reset it if it changes
141
- const bindingCache: Record<string, string | null> = {}
142
-
143
- const callTraverse = (a: Visitor<{}>) => {
144
- return fileOrPath.type === 'File' ? traverse(fileOrPath, a) : fileOrPath.traverse(a)
145
- }
146
-
147
- /**
148
- * Step 2: Statically extract from JSX < /> nodes
149
- */
150
- let programPath: NodePath<t.Program>
151
-
152
- callTraverse({
153
- Program: {
154
- enter(path) {
155
- programPath = path
156
- },
157
- },
158
- JSXElement(traversePath) {
159
- const node = traversePath.node.openingElement
160
- const ogAttributes = node.attributes
161
- const componentName = findComponentName(traversePath.scope)
162
- const closingElement = traversePath.node.closingElement
163
-
164
- // skip non-identifier opening elements (member expressions, etc.)
165
- if (t.isJSXMemberExpression(closingElement?.name) || !t.isJSXIdentifier(node.name)) {
166
- return
167
- }
168
-
169
- // validate its a proper import from tamagui (or internally inside tamagui)
170
- const binding = traversePath.scope.getBinding(node.name.name)
171
-
172
- if (binding) {
173
- if (!t.isImportDeclaration(binding.path.parent)) {
174
- return
175
- }
176
- const source = binding.path.parent.source
177
- if (!props.components.includes(source.value) && !isInternalImport(source.value)) {
178
- return
179
- }
180
- if (!validComponents[binding.identifier.name]) {
181
- return
182
- }
183
- }
184
-
185
- const component = validComponents[node.name.name] as { staticConfig?: StaticConfigParsed }
186
- if (!component || !component.staticConfig) {
187
- return
188
- }
189
-
190
- const { staticConfig } = component
191
- const originalNodeName = node.name.name
192
- const isTextView = staticConfig.isText || false
193
- const validStyles = staticConfig?.validStyles ?? {}
194
-
195
- // find tag="a" tag="main" etc dom indicators
196
- let tagName = staticConfig.defaultProps?.tag ?? (isTextView ? 'span' : 'div')
197
- traversePath
198
- .get('openingElement')
199
- .get('attributes')
200
- .forEach((path) => {
201
- const attr = path.node
202
- if (t.isJSXSpreadAttribute(attr)) return
203
- if (attr.name.name !== 'tag') return
204
- const val = attr.value
205
- if (!t.isStringLiteral(val)) return
206
- tagName = val.value
207
- })
208
-
209
- const flatNode = getFlattenedNode({ isTextView, tag: tagName })
210
-
211
- const deoptProps = new Set([
212
- ...(props.deoptProps ?? []),
213
- ...(staticConfig.deoptProps ?? []),
214
- ])
215
- const excludeProps = new Set(props.excludeProps ?? [])
216
- const isExcludedProp = (name: string) => {
217
- const res = excludeProps.has(name)
218
- if (res && shouldPrintDebug) console.log(` excluding ${name}`)
219
- return res
220
- }
221
-
222
- const isDeoptedProp = (name: string) => {
223
- const res = deoptProps.has(name)
224
- if (res && shouldPrintDebug) console.log(` deopting ${name}`)
225
- return res
226
- }
227
-
228
- if (shouldPrintDebug) {
229
- console.log(`\n<${originalNodeName} />`)
230
- }
231
-
232
- // Generate scope object at this level
233
- const staticNamespace = getStaticBindingsForScope(
234
- traversePath.scope,
235
- importsWhitelist,
236
- sourcePath,
237
- bindingCache,
238
- shouldPrintDebug
239
- )
240
-
241
- const attemptEval = !evaluateVars
242
- ? evaluateAstNode
243
- : createEvaluator({
244
- tamaguiConfig,
245
- staticNamespace,
246
- sourcePath,
247
- traversePath,
248
- shouldPrintDebug,
249
- })
250
- const attemptEvalSafe = createSafeEvaluator(attemptEval)
251
-
252
- if (shouldPrintDebug) {
253
- console.log(' staticNamespace', Object.keys(staticNamespace).join(', '))
254
- }
255
-
256
- //
257
- // SPREADS SETUP
258
- //
259
-
260
- // TODO restore
261
- const hasDeopt = (obj: Object) => {
262
- return Object.keys(obj).some(isDeoptedProp)
263
- }
264
-
265
- // flatten any easily evaluatable spreads
266
- const flattenedAttrs: (t.JSXAttribute | t.JSXSpreadAttribute)[] = []
267
- traversePath
268
- .get('openingElement')
269
- .get('attributes')
270
- .forEach((path) => {
271
- const attr = path.node
272
- if (!t.isJSXSpreadAttribute(attr)) {
273
- flattenedAttrs.push(attr)
274
- return
275
- }
276
- let arg: any
277
- try {
278
- arg = attemptEval(attr.argument)
279
- } catch (e: any) {
280
- if (shouldPrintDebug) {
281
- console.log(' couldnt parse spread', e.message)
282
- }
283
- flattenedAttrs.push(attr)
284
- return
285
- }
286
- if (typeof arg !== 'undefined') {
287
- try {
288
- if (typeof arg !== 'object' || arg == null) {
289
- if (shouldPrintDebug) {
290
- console.log(' non object or null arg', arg)
291
- }
292
- flattenedAttrs.push(attr)
293
- } else {
294
- for (const k in arg) {
295
- const value = arg[k]
296
- // this is a null prop:
297
- if (!value && typeof value === 'object') {
298
- console.log('shouldnt we handle this?', k, value, arg)
299
- continue
300
- }
301
- flattenedAttrs.push(
302
- t.jsxAttribute(
303
- t.jsxIdentifier(k),
304
- t.jsxExpressionContainer(literalToAst(value))
305
- )
306
- )
307
- }
308
- }
309
- } catch (err) {
310
- console.warn('cant parse spread, caught err', err)
311
- couldntParse = true
312
- }
313
- }
314
- })
315
-
316
- if (couldntParse) {
317
- return
318
- }
319
-
320
- // set flattened
321
- node.attributes = flattenedAttrs
322
-
323
- // add in default props
324
- if (staticConfig.defaultProps) {
325
- for (const key in staticConfig.defaultProps) {
326
- const serialize = require('babel-literal-to-ast')
327
- const val = staticConfig.defaultProps[key]
328
- node.attributes.unshift(
329
- t.jsxAttribute(
330
- t.jsxIdentifier(key),
331
- typeof val === 'string'
332
- ? t.stringLiteral(val)
333
- : t.jsxExpressionContainer(serialize(val))
334
- )
335
- )
336
- }
337
- }
338
-
339
- let attrs: ExtractedAttr[] = []
340
- let shouldDeopt = false
341
- let inlinePropCount = 0
342
- let isFlattened = false
343
-
344
- // RUN first pass
345
-
346
- // normalize all conditionals so we can evaluate away easier later
347
- // at the same time lets normalize shorthand media queries into spreads:
348
- // that way we can parse them with the same logic later on
349
- //
350
- // {...media.sm && { color: x ? 'red' : 'blue' }}
351
- // => {...media.sm && x && { color: 'red' }}
352
- // => {...media.sm && !x && { color: 'blue' }}
353
- //
354
- // $sm={{ color: 'red' }}
355
- // => {...media.sm && { color: 'red' }}
356
- //
357
- // $sm={{ color: x ? 'red' : 'blue' }}
358
- // => {...media.sm && x && { color: 'red' }}
359
- // => {...media.sm && !x && { color: 'blue' }}
360
-
361
- attrs = traversePath
362
- .get('openingElement')
363
- .get('attributes')
364
- .flatMap((path) => {
365
- try {
366
- const res = evaluateAttribute(path)
367
- if (!res) {
368
- path.remove()
369
- }
370
- return res
371
- } catch (err: any) {
372
- console.log('Error extracting attribute', err.message, err.stack)
373
- console.log('node', path.node)
374
- return {
375
- type: 'attr',
376
- value: path.node,
377
- } as const
378
- }
379
- })
380
- .flat(4)
381
- .filter(isPresent)
382
-
383
- function isStaticAttributeName(name: string) {
384
- return !!(
385
- !!validStyles[name] ||
386
- staticConfig.validPropsExtra?.[name] ||
387
- !!pseudos[name] ||
388
- staticConfig.variants?.[name] ||
389
- tamaguiConfig.shorthands[name] ||
390
- (name[0] === '$' ? !!mediaQueryConfig[name.slice(1)] : false)
391
- )
392
- }
393
-
394
- function isExtractable(obj: t.Node): obj is t.ObjectExpression {
395
- return (
396
- t.isObjectExpression(obj) &&
397
- obj.properties.every((prop) => {
398
- if (!t.isObjectProperty(prop)) {
399
- console.log('not object prop', prop)
400
- return false
401
- }
402
- const propName = prop.key['name']
403
- if (!isStaticAttributeName(propName) && propName !== 'tag') {
404
- // if (shouldPrintDebug) {
405
- console.log(' not a valid style prop!', propName)
406
- // }
407
- return false
408
- }
409
- return true
410
- })
411
- )
412
- }
413
-
414
- // side <= { color: 'red', background: x ? 'red' : 'green' }
415
- // | => Ternary<test, { color: 'red' }, null>
416
- // | => Ternary<test && x, { background: 'red' }, null>
417
- // | => Ternary<test && !x, { background: 'green' }, null>
418
- function createTernariesFromObjectProperties(
419
- test: t.Expression,
420
- side: t.Expression | null,
421
- ternaryPartial: Partial<Ternary> = {}
422
- ): null | Ternary[] {
423
- if (!side) {
424
- return null
425
- }
426
- if (!isExtractable(side)) {
427
- throw new Error('not extractable')
428
- }
429
- return side.properties.flatMap((property) => {
430
- if (!t.isObjectProperty(property)) {
431
- throw new Error('expected object property')
432
- }
433
- // this could be a recurse here if we want to get fancy
434
- if (t.isConditionalExpression(property.value)) {
435
- // merge up into the parent conditional, split into two
436
- const [truthy, falsy] = [
437
- t.objectExpression([t.objectProperty(property.key, property.value.consequent)]),
438
- t.objectExpression([t.objectProperty(property.key, property.value.alternate)]),
439
- ].map((x) => attemptEval(x))
440
- return [
441
- createTernary({
442
- remove() {},
443
- ...ternaryPartial,
444
- test: t.logicalExpression('&&', test, property.value.test),
445
- consequent: truthy,
446
- alternate: null,
447
- }),
448
- createTernary({
449
- ...ternaryPartial,
450
- test: t.logicalExpression(
451
- '&&',
452
- test,
453
- t.unaryExpression('!', property.value.test)
454
- ),
455
- consequent: falsy,
456
- alternate: null,
457
- remove() {},
458
- }),
459
- ]
460
- }
461
- const obj = t.objectExpression([t.objectProperty(property.key, property.value)])
462
- const consequent = attemptEval(obj)
463
- return createTernary({
464
- remove() {},
465
- ...ternaryPartial,
466
- test,
467
- consequent,
468
- alternate: null,
469
- })
470
- })
471
- }
472
-
473
- // START function evaluateAttribute
474
- function evaluateAttribute(
475
- path: NodePath<t.JSXAttribute | t.JSXSpreadAttribute>
476
- ): ExtractedAttr | ExtractedAttr[] | null {
477
- const attribute = path.node
478
- const attr: ExtractedAttr = { type: 'attr', value: attribute }
479
- // ...spreads
480
- if (t.isJSXSpreadAttribute(attribute)) {
481
- const arg = attribute.argument
482
- const conditional = t.isConditionalExpression(arg)
483
- ? // <YStack {...isSmall ? { color: 'red } : { color: 'blue }}
484
- ([arg.test, arg.consequent, arg.alternate] as const)
485
- : t.isLogicalExpression(arg) && arg.operator === '&&'
486
- ? // <YStack {...isSmall && { color: 'red }}
487
- ([arg.left, arg.right, null] as const)
488
- : null
489
-
490
- if (conditional) {
491
- const [test, alt, cons] = conditional
492
- if (!test) throw new Error(`no test`)
493
- if ([alt, cons].some((side) => side && !isExtractable(side))) {
494
- console.log('not extractable', alt, cons)
495
- return attr
496
- }
497
- // split into individual ternaries per object property
498
- return [
499
- ...(createTernariesFromObjectProperties(test, alt) || []),
500
- ...((cons &&
501
- createTernariesFromObjectProperties(t.unaryExpression('!', test), cons)) ||
502
- []),
503
- ].map((ternary) => ({
504
- type: 'ternary',
505
- value: ternary,
506
- }))
507
- }
508
- }
509
- // END ...spreads
510
-
511
- // directly keep these
512
- // couldn't evaluate spread, undefined name, or name is not string
513
- if (
514
- t.isJSXSpreadAttribute(attribute) ||
515
- !attribute.name ||
516
- typeof attribute.name.name !== 'string'
517
- ) {
518
- inlinePropCount++
519
- return attr
520
- }
521
-
522
- const name = attribute.name.name
523
-
524
- if (isExcludedProp(name)) {
525
- return null
526
- }
527
-
528
- // can still optimize the object... see hoverStyle on native
529
- if (isDeoptedProp(name)) {
530
- if (shouldPrintDebug) {
531
- console.log(' ! inlining, deopt prop', name)
532
- }
533
- inlinePropCount++
534
- return attr
535
- }
536
-
537
- // pass className, key, and style props through untouched
538
- if (UNTOUCHED_PROPS[name]) {
539
- return attr
540
- }
541
-
542
- // shorthand media queries
543
- if (name[0] === '$' && t.isJSXExpressionContainer(attribute?.value)) {
544
- const shortname = name.slice(1)
545
- if (mediaQueryConfig[shortname]) {
546
- const expression = attribute.value.expression
547
- if (!t.isJSXEmptyExpression(expression)) {
548
- const ternaries = createTernariesFromObjectProperties(
549
- t.stringLiteral(shortname),
550
- expression,
551
- {
552
- inlineMediaQuery: shortname,
553
- }
554
- )
555
- if (ternaries) {
556
- return ternaries.map((value) => ({
557
- type: 'ternary',
558
- value,
559
- }))
560
- }
561
- }
562
- }
563
- }
564
-
565
- const [value, valuePath] = (() => {
566
- if (t.isJSXExpressionContainer(attribute?.value)) {
567
- return [attribute.value.expression!, path.get('value')!] as const
568
- } else {
569
- return [attribute.value!, path.get('value')!] as const
570
- }
571
- })()
572
-
573
- const remove = () => {
574
- Array.isArray(valuePath) ? valuePath.map((p) => p.remove()) : valuePath.remove()
575
- }
576
-
577
- if (name === 'ref') {
578
- if (shouldPrintDebug) {
579
- console.log(' ! inlining, ref', name)
580
- }
581
- inlinePropCount++
582
- return attr
583
- }
584
-
585
- if (name === 'tag') {
586
- return {
587
- type: 'attr',
588
- value: path.node,
589
- }
590
- }
591
-
592
- // if value can be evaluated, extract it and filter it out
593
- const styleValue = attemptEvalSafe(value)
594
-
595
- // we never flatten if a prop isn't a valid static attribute
596
- // but we need to make sure its post-prop mapping
597
- if (!isStaticAttributeName(name)) {
598
- let keys = [name]
599
- if (staticConfig.propMapper) {
600
- // for now passing empty props {}, a bit odd, need to at least document
601
- // for now we don't expose custom components so just noting behavior
602
- const out = staticConfig.propMapper(
603
- name,
604
- styleValue,
605
- defaultTheme,
606
- staticConfig.defaultProps
607
- )
608
- if (out) {
609
- keys = Object.keys(out)
610
- }
611
- }
612
- if (keys.some((k) => !isStaticAttributeName(k) && k !== 'tag')) {
613
- if (shouldPrintDebug) {
614
- console.log(' ! inlining, not static attribute name', name)
615
- }
616
- inlinePropCount++
617
- return attr
618
- }
619
- }
620
-
621
- // FAILED = dynamic or ternary, keep going
622
- if (styleValue !== FAILED_EVAL) {
623
- return {
624
- type: 'style',
625
- value: { [name]: styleValue },
626
- }
627
- }
628
-
629
- // ternaries!
630
-
631
- // binary ternary, we can eventually make this smarter but step 1
632
- // basically for the common use case of:
633
- // opacity={(conditional ? 0 : 1) * scale}
634
- if (t.isBinaryExpression(value)) {
635
- const { operator, left, right } = value
636
- // if one side is a ternary, and the other side is evaluatable, we can maybe extract
637
- const lVal = attemptEvalSafe(left)
638
- const rVal = attemptEvalSafe(right)
639
- if (shouldPrintDebug) {
640
- console.log(` evalBinaryExpression lVal ${String(lVal)}, rVal ${String(rVal)}`)
641
- }
642
- if (lVal !== FAILED_EVAL && t.isConditionalExpression(right)) {
643
- const ternary = addBinaryConditional(operator, left, right)
644
- if (ternary) return ternary
645
- }
646
- if (rVal !== FAILED_EVAL && t.isConditionalExpression(left)) {
647
- const ternary = addBinaryConditional(operator, right, left)
648
- if (ternary) return ternary
649
- }
650
- if (shouldPrintDebug) {
651
- console.log(` evalBinaryExpression cant extract`)
652
- }
653
- inlinePropCount++
654
- return attr
655
- }
656
-
657
- const staticConditional = getStaticConditional(value)
658
- if (staticConditional) {
659
- return { type: 'ternary', value: staticConditional }
660
- }
661
-
662
- const staticLogical = getStaticLogical(value)
663
- if (staticLogical) {
664
- return { type: 'ternary', value: staticLogical }
665
- }
666
-
667
- if (shouldPrintDebug) {
668
- console.log(' ! inline prop via no match', name, value.type)
669
- }
670
- // if we've made it this far, the prop stays inline
671
- inlinePropCount++
672
-
673
- //
674
- // RETURN ATTR
675
- //
676
- return attr
677
-
678
- // attr helpers:
679
- function addBinaryConditional(
680
- operator: any,
681
- staticExpr: any,
682
- cond: t.ConditionalExpression
683
- ): ExtractedAttr | null {
684
- if (getStaticConditional(cond)) {
685
- const alt = attemptEval(t.binaryExpression(operator, staticExpr, cond.alternate))
686
- const cons = attemptEval(t.binaryExpression(operator, staticExpr, cond.consequent))
687
- if (shouldPrintDebug) {
688
- console.log(' binaryConditional', cond.test, cons, alt)
689
- }
690
- return {
691
- type: 'ternary',
692
- value: {
693
- test: cond.test,
694
- remove,
695
- alternate: { [name]: alt },
696
- consequent: { [name]: cons },
697
- },
698
- }
699
- }
700
- return null
701
- }
702
-
703
- function getStaticConditional(value: t.Node): Ternary | null {
704
- if (t.isConditionalExpression(value)) {
705
- try {
706
- if (shouldPrintDebug) {
707
- console.log('attempt', value.alternate, value.consequent)
708
- }
709
- const aVal = attemptEval(value.alternate)
710
- const cVal = attemptEval(value.consequent)
711
- if (shouldPrintDebug) {
712
- const type = value.test.type
713
- console.log(' static ternary', type, cVal, aVal)
714
- }
715
- return {
716
- test: value.test,
717
- remove,
718
- consequent: { [name]: cVal },
719
- alternate: { [name]: aVal },
720
- }
721
- } catch (err: any) {
722
- if (shouldPrintDebug) {
723
- console.log(' cant eval ternary', err.message)
724
- }
725
- }
726
- }
727
- return null
728
- }
729
-
730
- function getStaticLogical(value: t.Node): Ternary | null {
731
- if (t.isLogicalExpression(value)) {
732
- if (value.operator === '&&') {
733
- try {
734
- const val = attemptEval(value.right)
735
- if (shouldPrintDebug) {
736
- console.log(' staticLogical', value.left, name, val)
737
- }
738
- return {
739
- test: value.left,
740
- remove,
741
- consequent: { [name]: val },
742
- alternate: null,
743
- }
744
- } catch (err) {
745
- if (shouldPrintDebug) {
746
- console.log(' cant static eval logical', err)
747
- }
748
- }
749
- }
750
- }
751
- return null
752
- }
753
- } // END function evaluateAttribute
754
-
755
- // see if we can filter them
756
- if (shouldPrintDebug) {
757
- console.log(' - attrs (before): ', attrs.map(attrStr).join(', '))
758
- }
759
-
760
- // now update to new values
761
- node.attributes = attrs.filter(isAttr).map((x) => x.value)
762
-
763
- if (couldntParse) {
764
- if (shouldPrintDebug) {
765
- console.log(` cancel:`, { couldntParse, shouldDeopt })
766
- }
767
- node.attributes = ogAttributes
768
- return
769
- }
770
-
771
- // before deopt, can still optimize
772
- const parentFn = findTopmostFunction(traversePath)
773
- if (parentFn) {
774
- modifiedComponents.add(parentFn)
775
- }
776
-
777
- const filePath = sourcePath.replace(process.cwd(), '.')
778
- const lineNumbers = node.loc
779
- ? node.loc.start.line +
780
- (node.loc.start.line !== node.loc.end.line ? `-${node.loc.end.line}` : '')
781
- : ''
782
-
783
- // combine ternaries
784
- let ternaries: Ternary[] = []
785
- attrs = attrs
786
- .reduce<(ExtractedAttr | ExtractedAttr[])[]>((out, cur) => {
787
- const next = attrs[attrs.indexOf(cur) + 1]
788
- if (cur.type === 'ternary') {
789
- ternaries.push(cur.value)
790
- }
791
- if ((!next || next.type !== 'ternary') && ternaries.length) {
792
- // finish, process
793
- const normalized = normalizeTernaries(ternaries).map(
794
- ({ alternate, consequent, ...rest }) => {
795
- return {
796
- type: 'ternary' as const,
797
- value: {
798
- ...rest,
799
- alternate: alternate || null,
800
- consequent: consequent || null,
801
- },
802
- }
803
- }
804
- )
805
- try {
806
- return [...out, ...normalized]
807
- } finally {
808
- if (shouldPrintDebug) {
809
- console.log(
810
- ` normalizeTernaries (${ternaries.length} => ${normalized.length})`
811
- )
812
- }
813
- ternaries = []
814
- }
815
- }
816
- if (cur.type === 'ternary') {
817
- return out
818
- }
819
- out.push(cur)
820
- return out
821
- }, [])
822
- .flat()
823
-
824
- // evaluates all static attributes into a simple object
825
- const completeStaticProps = {
826
- ...Object.keys(attrs).reduce((acc, index) => {
827
- const cur = attrs[index] as ExtractedAttr
828
- if (cur.type === 'style') {
829
- Object.assign(acc, cur.value)
830
- }
831
- if (cur.type === 'attr') {
832
- if (t.isJSXSpreadAttribute(cur.value)) {
833
- return acc
834
- }
835
- if (!t.isJSXIdentifier(cur.value.name)) {
836
- return acc
837
- }
838
- const key = cur.value.name.name
839
- // undefined = boolean true
840
- const value = attemptEvalSafe(cur.value.value || t.booleanLiteral(true))
841
- if (value === FAILED_EVAL) {
842
- return acc
843
- }
844
- acc[key] = value
845
- }
846
- return acc
847
- }, {}),
848
- }
849
-
850
- // flatten logic!
851
- // fairly simple check to see if all children are text
852
- const hasSpread = node.attributes.some((x) => t.isJSXSpreadAttribute(x))
853
- const hasOnlyStringChildren =
854
- !hasSpread &&
855
- (node.selfClosing ||
856
- (traversePath.node.children &&
857
- traversePath.node.children.every((x) => x.type === 'JSXText')))
858
- const shouldFlatten =
859
- !shouldDeopt &&
860
- inlinePropCount === 0 &&
861
- !hasSpread &&
862
- staticConfig.neverFlatten !== true &&
863
- (staticConfig.neverFlatten === 'jsx' ? hasOnlyStringChildren : true)
864
-
865
- // insert overrides - this inserts null props for things that are set in classNames
866
- // only when not flattening, so the downstream component can skip applying those styles
867
- if (!shouldFlatten) {
868
- attrs = attrs.reduce<ExtractedAttr[]>((acc, cur) => {
869
- if (cur.type === 'style') {
870
- // TODO need to loop over initial props not just style props
871
- for (const key in cur.value) {
872
- const shouldInsertNull =
873
- !!(
874
- staticConfig.ensureOverriddenProp?.[key] // || staticConfig.defaultProps?.[key]
875
- )
876
- const isSetInAttrsAlready = attrs.some(
877
- (x) =>
878
- x.type === 'attr' &&
879
- x.value.type === 'JSXAttribute' &&
880
- x.value.name.name === key
881
- )
882
- const shouldInsertNullOverride = shouldInsertNull && !isSetInAttrsAlready
883
- // if (shouldPrintDebug) {
884
- // // prettier-ignore
885
- // console.log('what is', key, { shouldInsertNullOverride, shouldInsertNull, isSetInAttrsAlready })
886
- // }
887
- if (shouldInsertNullOverride) {
888
- acc.push({
889
- type: 'attr',
890
- value: t.jsxAttribute(
891
- t.jsxIdentifier(key),
892
- t.jsxExpressionContainer(t.nullLiteral())
893
- ),
894
- })
895
- }
896
- }
897
- }
898
- acc.push(cur)
899
- return acc
900
- }, [])
901
- }
902
-
903
- if (shouldPrintDebug) {
904
- console.log(' - attrs (flattened): ', attrs.map(attrStr).join(', '))
905
- }
906
-
907
- // evaluate away purely style props
908
- attrs = attrs.reduce<ExtractedAttr[]>((acc, cur) => {
909
- if (
910
- cur.type !== 'attr' ||
911
- !t.isJSXAttribute(cur.value) ||
912
- typeof cur.value.name.name !== 'string'
913
- ) {
914
- if (cur.type === 'style') {
915
- const key = Object.keys(cur.value)[0]
916
- if (!validStyles[key] && !pseudos[key]) {
917
- if (shouldPrintDebug) {
918
- console.log(' ❌ excluding', key)
919
- }
920
- // we've already expanded shorthands, now we can remove them
921
- return acc
922
- }
923
- }
924
- }
925
- acc.push(cur)
926
- return acc
927
- }, [])
928
-
929
- if (shouldPrintDebug) {
930
- console.log(' - attrs (evaluated styles): ', attrs.map(attrStr).join(', '))
931
- }
932
-
933
- // combine styles, leave undefined values
934
- let prev: ExtractedAttr | null = null
935
- attrs = attrs.reduce<ExtractedAttr[]>((acc, cur) => {
936
- if (cur.type === 'style') {
937
- if (prev?.type === 'style') {
938
- Object.assign(prev.value, cur.value)
939
- return acc
940
- }
941
- }
942
- acc.push(cur)
943
- prev = cur
944
- return acc
945
- }, [])
946
-
947
- if (shouldPrintDebug) {
948
- console.log(' - attrs (combined 🔀): ', attrs.map(attrStr).join(', '))
949
- }
950
-
951
- // post process
952
- const getStyles = (props: Object | null) => {
953
- if (!props) return
954
- if (!!excludeProps.size) {
955
- for (const key in props) {
956
- if (isExcludedProp(key)) delete props[key]
957
- }
958
- }
959
-
960
- const out = postProcessStyles(props, staticConfig, defaultTheme)
961
- const next = out?.style ?? props
962
- if (shouldPrintDebug) {
963
- console.log(' >> getStyles: ', objToStr(props), '==>>', objToStr(next))
964
- console.log(' >> style: ', objToStr(out.style))
965
- console.log(' >> viewp: ', objToStr(out.viewProps))
966
- }
967
- if (staticConfig.validStyles) {
968
- for (const key in next) {
969
- if (!staticConfig.validStyles[key] && !pseudos[key]) {
970
- delete next[key]
971
- }
972
- }
973
- }
974
- return next
975
- }
976
-
977
- if (shouldPrintDebug) {
978
- console.log(' staticConfig.defaultProps', staticConfig.defaultProps)
979
- }
980
-
981
- // used to ensure we pass the entire prop bundle to getStyles
982
- const completeStylesProcessed = getStyles({
983
- ...staticConfig.defaultProps,
984
- ...completeStaticProps,
985
- })
986
-
987
- // any extra styles added in postprocess should be added to first group as they wont be overriden
988
- const stylesToAddToInitialGroup = difference(
989
- Object.keys(completeStylesProcessed),
990
- Object.keys(completeStaticProps)
991
- )
992
-
993
- if (stylesToAddToInitialGroup.length) {
994
- const toAdd = pick(completeStylesProcessed, ...stylesToAddToInitialGroup)
995
- const firstGroup = attrs.find((x) => x.type === 'style')
996
- if (shouldPrintDebug) {
997
- console.log(' stylesToAddToInitialGroup', stylesToAddToInitialGroup.join(', '))
998
- console.log(' toAdd', objToStr(toAdd))
999
- }
1000
- if (!firstGroup) {
1001
- attrs.unshift({ type: 'style', value: toAdd })
1002
- } else {
1003
- Object.assign(firstGroup.value, toAdd)
1004
- }
1005
- }
1006
-
1007
- if (shouldPrintDebug) {
1008
- // prettier-ignore
1009
- console.log(' completeStaticProps', objToStr(completeStaticProps))
1010
- // prettier-ignore
1011
- console.log(' completeStylesProcessed', objToStr(completeStylesProcessed))
1012
- }
1013
-
1014
- for (const attr of attrs) {
1015
- try {
1016
- switch (attr.type) {
1017
- case 'ternary':
1018
- const a = getStyles(attr.value.alternate)
1019
- const c = getStyles(attr.value.consequent)
1020
- attr.value.alternate = a
1021
- attr.value.consequent = c
1022
- if (shouldPrintDebug) {
1023
- console.log(' => tern ', attrStr(attr))
1024
- }
1025
- break
1026
- case 'style':
1027
- const next = {}
1028
- for (const key in attr.value) {
1029
- if (key in stylePropsTransform) {
1030
- // TODO this logic needs to be a bit more right, because could have spread in between transforms...
1031
- next['transform'] = completeStylesProcessed['transform']
1032
- } else {
1033
- next[key] = completeStylesProcessed[key] ?? attr.value[key]
1034
- }
1035
- }
1036
- attr.value = next
1037
- break
1038
- }
1039
- } catch (err) {
1040
- // any error de-opt
1041
- if (shouldPrintDebug) {
1042
- console.log(' postprocessing error, deopt', err)
1043
- node.attributes = ogAttributes
1044
- return node
1045
- }
1046
- }
1047
- }
1048
-
1049
- if (shouldPrintDebug) {
1050
- console.log(' - attrs (after): ', attrs.map(attrStr).join(', '))
1051
- }
1052
-
1053
- // add data-is
1054
- if (shouldAddDebugProp) {
1055
- const preName = componentName ? `${componentName}:` : ''
1056
- // unshift so spreads/nesting overwrite
1057
- attrs.unshift({
1058
- type: 'attr',
1059
- value: t.jsxAttribute(
1060
- t.jsxIdentifier('data-is'),
1061
- t.stringLiteral(
1062
- ` ${preName}${node.name.name} ${filePath.replace('./', '')}:${lineNumbers} `
1063
- )
1064
- ),
1065
- })
1066
- }
1067
-
1068
- if (shouldFlatten) {
1069
- // DO FLATTEN
1070
- if (shouldPrintDebug) {
1071
- console.log(' [✅] flattening', originalNodeName, flatNode)
1072
- }
1073
- isFlattened = true
1074
- node.name.name = flatNode
1075
- onDidFlatten?.()
1076
- if (closingElement) {
1077
- closingElement.name.name = flatNode
1078
- }
1079
- }
1080
-
1081
- if (shouldPrintDebug) {
1082
- // prettier-ignore
1083
- console.log(' [❊] inline props ', inlinePropCount, shouldDeopt ? ' deopted' : '', hasSpread ? ' spread' : '', '!flatten', staticConfig.neverFlatten)
1084
- console.log(' - attrs (end): ', attrs.map(attrStr).join(', '))
1085
- }
1086
-
1087
- onExtractTag({
1088
- attrs,
1089
- node,
1090
- lineNumbers,
1091
- filePath,
1092
- attemptEval,
1093
- jsxPath: traversePath,
1094
- originalNodeName,
1095
- isFlattened,
1096
- programPath,
1097
- })
1098
- },
1099
- })
1100
-
1101
- /**
1102
- * Step 3: Remove dead code from removed media query / theme hooks
1103
- */
1104
- if (modifiedComponents.size) {
1105
- const all = Array.from(modifiedComponents)
1106
- if (shouldPrintDebug) {
1107
- console.log(' [🪝] hook check', all.length)
1108
- }
1109
- for (const comp of all) {
1110
- removeUnusedHooks(comp, shouldPrintDebug)
1111
- }
1112
- }
1113
- },
1114
- }
1115
- }