@tamagui/static 1.0.0-alpha.9 → 1.0.0-beta.0

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