@tamagui/static 1.0.0-alpha.5 → 1.0.0-alpha.50

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