@tamagui/static 1.0.0-alpha.7 → 1.0.0-beta.172

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