@tamagui/static 1.0.1-beta.19 → 1.0.1-beta.191

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 (250) hide show
  1. package/dist/{cjs/constants.js → constants.js} +9 -4
  2. package/dist/constants.js.map +7 -0
  3. package/dist/{cjs/extractor → extractor}/accessSafe.js +14 -4
  4. package/dist/{esm/extractor → extractor}/accessSafe.js.map +2 -2
  5. package/dist/{cjs/extractor → extractor}/babelParse.js +20 -17
  6. package/dist/extractor/babelParse.js.map +7 -0
  7. package/dist/{cjs/extractor → extractor}/buildClassName.js +40 -11
  8. package/dist/extractor/buildClassName.js.map +7 -0
  9. package/dist/{cjs/extractor → extractor}/createEvaluator.js +19 -14
  10. package/dist/extractor/createEvaluator.js.map +7 -0
  11. package/dist/extractor/createExtractor.js +1577 -0
  12. package/dist/extractor/createExtractor.js.map +7 -0
  13. package/dist/{cjs/extractor → extractor}/ensureImportingConcat.js +18 -8
  14. package/dist/extractor/ensureImportingConcat.js.map +7 -0
  15. package/dist/{cjs/extractor → extractor}/evaluateAstNode.js +14 -6
  16. package/dist/{esm/extractor → extractor}/evaluateAstNode.js.map +2 -2
  17. package/dist/{cjs/extractor → extractor}/extractHelpers.js +56 -27
  18. package/dist/extractor/extractHelpers.js.map +7 -0
  19. package/dist/{cjs/extractor → extractor}/extractMediaStyle.js +49 -50
  20. package/dist/extractor/extractMediaStyle.js.map +7 -0
  21. package/dist/{cjs/extractor → extractor}/extractToClassNames.js +160 -109
  22. package/dist/extractor/extractToClassNames.js.map +7 -0
  23. package/dist/{cjs/extractor → extractor}/findTopmostFunction.js +2 -3
  24. package/dist/{esm/extractor → extractor}/findTopmostFunction.js.map +2 -2
  25. package/dist/{cjs/extractor → extractor}/generatedUid.js +9 -4
  26. package/dist/{cjs/extractor → extractor}/generatedUid.js.map +3 -3
  27. package/dist/{cjs/extractor → extractor}/getPrefixLogs.js +1 -2
  28. package/dist/extractor/getPrefixLogs.js.map +7 -0
  29. package/dist/{cjs/extractor → extractor}/getPropValueFromAttributes.js +24 -15
  30. package/dist/extractor/getPropValueFromAttributes.js.map +7 -0
  31. package/dist/{cjs/extractor → extractor}/getSourceModule.js +5 -3
  32. package/dist/{esm/extractor → extractor}/getSourceModule.js.map +2 -2
  33. package/dist/{cjs/extractor → extractor}/getStaticBindingsForScope.js +88 -38
  34. package/dist/extractor/getStaticBindingsForScope.js.map +7 -0
  35. package/dist/{cjs/extractor → extractor}/hoistClassNames.js +5 -4
  36. package/dist/{esm/extractor → extractor}/hoistClassNames.js.map +3 -3
  37. package/dist/{cjs/extractor → extractor}/literalToAst.js +26 -34
  38. package/dist/{cjs/extractor → extractor}/literalToAst.js.map +2 -2
  39. package/dist/extractor/loadFile.js +21 -0
  40. package/dist/extractor/loadFile.js.map +7 -0
  41. package/dist/extractor/loadTamagui.js +327 -0
  42. package/dist/extractor/loadTamagui.js.map +7 -0
  43. package/dist/{cjs/extractor → extractor}/logLines.js +3 -3
  44. package/dist/{cjs/extractor → extractor}/logLines.js.map +2 -2
  45. package/dist/{cjs/extractor → extractor}/normalizeTernaries.js +13 -36
  46. package/dist/extractor/normalizeTernaries.js.map +7 -0
  47. package/dist/{cjs/extractor → extractor}/removeUnusedHooks.js +7 -5
  48. package/dist/{cjs/extractor → extractor}/removeUnusedHooks.js.map +2 -2
  49. package/dist/{cjs/extractor → extractor}/timer.js +11 -4
  50. package/dist/extractor/timer.js.map +7 -0
  51. package/dist/{cjs/extractor → extractor}/validHTMLAttributes.js +52 -0
  52. package/dist/extractor/validHTMLAttributes.js.map +7 -0
  53. package/dist/getPragmaOptions.js +68 -0
  54. package/dist/getPragmaOptions.js.map +7 -0
  55. package/dist/{cjs/index.js → index.js} +11 -7
  56. package/dist/index.js.map +7 -0
  57. package/dist/require.js +95 -0
  58. package/dist/require.js.map +7 -0
  59. package/dist/{cjs/types.js → types.js} +1 -0
  60. package/dist/types.js.map +7 -0
  61. package/dist/webpackPlugin.js +35 -0
  62. package/dist/webpackPlugin.js.map +7 -0
  63. package/package.json +46 -35
  64. package/src/constants.ts +14 -0
  65. package/src/extractor/accessSafe.ts +18 -0
  66. package/src/extractor/babelParse.ts +27 -0
  67. package/src/extractor/buildClassName.ts +77 -0
  68. package/src/extractor/createEvaluator.ts +73 -0
  69. package/src/extractor/createExtractor.ts +2044 -0
  70. package/src/extractor/ensureImportingConcat.ts +32 -0
  71. package/src/extractor/evaluateAstNode.ts +121 -0
  72. package/src/extractor/extractHelpers.ts +154 -0
  73. package/src/extractor/extractMediaStyle.ts +199 -0
  74. package/src/extractor/extractToClassNames.ts +442 -0
  75. package/src/extractor/findTopmostFunction.ts +22 -0
  76. package/src/extractor/generatedUid.ts +43 -0
  77. package/src/extractor/getPrefixLogs.ts +6 -0
  78. package/src/extractor/getPropValueFromAttributes.ts +92 -0
  79. package/src/extractor/getSourceModule.ts +101 -0
  80. package/src/extractor/getStaticBindingsForScope.ts +227 -0
  81. package/src/extractor/hoistClassNames.ts +45 -0
  82. package/src/extractor/literalToAst.ts +84 -0
  83. package/src/extractor/loadFile.ts +17 -0
  84. package/src/extractor/loadTamagui.ts +377 -0
  85. package/src/extractor/logLines.ts +16 -0
  86. package/src/extractor/normalizeTernaries.ts +63 -0
  87. package/src/extractor/removeUnusedHooks.ts +76 -0
  88. package/src/extractor/timer.ts +29 -0
  89. package/src/extractor/validHTMLAttributes.ts +99 -0
  90. package/src/getPragmaOptions.ts +52 -0
  91. package/src/index.ts +12 -0
  92. package/src/require.ts +112 -0
  93. package/src/types.ts +94 -0
  94. package/src/webpackPlugin.ts +9 -0
  95. package/tamagui.tsconfig.json +5 -0
  96. package/types/constants.d.ts +1 -1
  97. package/types/extractor/buildClassName.d.ts +5 -2
  98. package/types/extractor/createEvaluator.d.ts +4 -4
  99. package/types/extractor/createExtractor.d.ts +26 -11
  100. package/types/extractor/extractHelpers.d.ts +6 -4
  101. package/types/extractor/extractMediaStyle.d.ts +3 -3
  102. package/types/extractor/extractToClassNames.d.ts +4 -9
  103. package/types/extractor/findTopmostFunction.d.ts +1 -1
  104. package/types/extractor/getPrefixLogs.d.ts +1 -1
  105. package/types/extractor/getPropValueFromAttributes.d.ts +16 -0
  106. package/types/extractor/getStaticBindingsForScope.d.ts +2 -1
  107. package/types/extractor/loadFile.d.ts +1 -0
  108. package/types/extractor/loadTamagui.d.ts +15 -5
  109. package/types/extractor/normalizeTernaries.d.ts +1 -1
  110. package/types/extractor/validHTMLAttributes.d.ts +49 -0
  111. package/types/getPragmaOptions.d.ts +9 -0
  112. package/types/index.d.ts +10 -7
  113. package/types/require.d.ts +4 -0
  114. package/types/types.d.ts +29 -32
  115. package/types/webpackPlugin.d.ts +4 -0
  116. package/dist/cjs/constants.js.map +0 -7
  117. package/dist/cjs/extractor/accessSafe.js.map +0 -7
  118. package/dist/cjs/extractor/babelParse.js.map +0 -7
  119. package/dist/cjs/extractor/buildClassName.js.map +0 -7
  120. package/dist/cjs/extractor/createEvaluator.js.map +0 -7
  121. package/dist/cjs/extractor/createExtractor.js +0 -1221
  122. package/dist/cjs/extractor/createExtractor.js.map +0 -7
  123. package/dist/cjs/extractor/ensureImportingConcat.js.map +0 -7
  124. package/dist/cjs/extractor/evaluateAstNode.js.map +0 -7
  125. package/dist/cjs/extractor/extractHelpers.js.map +0 -7
  126. package/dist/cjs/extractor/extractMediaStyle.js.map +0 -7
  127. package/dist/cjs/extractor/extractToClassNames.js.map +0 -7
  128. package/dist/cjs/extractor/findTopmostFunction.js.map +0 -7
  129. package/dist/cjs/extractor/getPrefixLogs.js.map +0 -7
  130. package/dist/cjs/extractor/getPropValueFromAttributes.js.map +0 -7
  131. package/dist/cjs/extractor/getSourceModule.js.map +0 -7
  132. package/dist/cjs/extractor/getStaticBindingsForScope.js.map +0 -7
  133. package/dist/cjs/extractor/hoistClassNames.js.map +0 -7
  134. package/dist/cjs/extractor/loadTamagui.js +0 -106
  135. package/dist/cjs/extractor/loadTamagui.js.map +0 -7
  136. package/dist/cjs/extractor/normalizeTernaries.js.map +0 -7
  137. package/dist/cjs/extractor/timer.js.map +0 -7
  138. package/dist/cjs/extractor/validHTMLAttributes.js.map +0 -7
  139. package/dist/cjs/index.js.map +0 -7
  140. package/dist/cjs/patchReactNativeWeb.js +0 -167
  141. package/dist/cjs/patchReactNativeWeb.js.map +0 -7
  142. package/dist/cjs/types.js.map +0 -7
  143. package/dist/esm/constants.js +0 -14
  144. package/dist/esm/constants.js.map +0 -7
  145. package/dist/esm/extractor/accessSafe.js +0 -11
  146. package/dist/esm/extractor/babelParse.js +0 -30
  147. package/dist/esm/extractor/babelParse.js.map +0 -7
  148. package/dist/esm/extractor/buildClassName.js +0 -40
  149. package/dist/esm/extractor/buildClassName.js.map +0 -7
  150. package/dist/esm/extractor/createEvaluator.js +0 -52
  151. package/dist/esm/extractor/createEvaluator.js.map +0 -7
  152. package/dist/esm/extractor/createExtractor.js +0 -1169
  153. package/dist/esm/extractor/createExtractor.js.map +0 -7
  154. package/dist/esm/extractor/ensureImportingConcat.js +0 -24
  155. package/dist/esm/extractor/ensureImportingConcat.js.map +0 -7
  156. package/dist/esm/extractor/evaluateAstNode.js +0 -94
  157. package/dist/esm/extractor/extractHelpers.js +0 -103
  158. package/dist/esm/extractor/extractHelpers.js.map +0 -7
  159. package/dist/esm/extractor/extractMediaStyle.js +0 -152
  160. package/dist/esm/extractor/extractMediaStyle.js.map +0 -7
  161. package/dist/esm/extractor/extractToClassNames.js +0 -293
  162. package/dist/esm/extractor/extractToClassNames.js.map +0 -7
  163. package/dist/esm/extractor/findTopmostFunction.js +0 -23
  164. package/dist/esm/extractor/generatedUid.js +0 -28
  165. package/dist/esm/extractor/generatedUid.js.map +0 -7
  166. package/dist/esm/extractor/getPrefixLogs.js +0 -12
  167. package/dist/esm/extractor/getPrefixLogs.js.map +0 -7
  168. package/dist/esm/extractor/getPropValueFromAttributes.js +0 -49
  169. package/dist/esm/extractor/getPropValueFromAttributes.js.map +0 -7
  170. package/dist/esm/extractor/getSourceModule.js +0 -69
  171. package/dist/esm/extractor/getStaticBindingsForScope.js +0 -137
  172. package/dist/esm/extractor/getStaticBindingsForScope.js.map +0 -7
  173. package/dist/esm/extractor/hoistClassNames.js +0 -44
  174. package/dist/esm/extractor/literalToAst.js +0 -80
  175. package/dist/esm/extractor/literalToAst.js.map +0 -7
  176. package/dist/esm/extractor/loadTamagui.js +0 -84
  177. package/dist/esm/extractor/loadTamagui.js.map +0 -7
  178. package/dist/esm/extractor/logLines.js +0 -22
  179. package/dist/esm/extractor/logLines.js.map +0 -7
  180. package/dist/esm/extractor/normalizeTernaries.js +0 -53
  181. package/dist/esm/extractor/normalizeTernaries.js.map +0 -7
  182. package/dist/esm/extractor/removeUnusedHooks.js +0 -80
  183. package/dist/esm/extractor/removeUnusedHooks.js.map +0 -7
  184. package/dist/esm/extractor/timer.js +0 -24
  185. package/dist/esm/extractor/timer.js.map +0 -7
  186. package/dist/esm/extractor/validHTMLAttributes.js +0 -52
  187. package/dist/esm/extractor/validHTMLAttributes.js.map +0 -7
  188. package/dist/esm/index.js +0 -14
  189. package/dist/esm/index.js.map +0 -7
  190. package/dist/esm/patchReactNativeWeb.js +0 -142
  191. package/dist/esm/patchReactNativeWeb.js.map +0 -7
  192. package/dist/esm/types.js +0 -1
  193. package/dist/esm/types.js.map +0 -7
  194. package/dist/jsx/constants.js +0 -13
  195. package/dist/jsx/extractor/accessSafe.js +0 -10
  196. package/dist/jsx/extractor/babelParse.js +0 -29
  197. package/dist/jsx/extractor/buildClassName.js +0 -39
  198. package/dist/jsx/extractor/createEvaluator.js +0 -51
  199. package/dist/jsx/extractor/createExtractor.js +0 -1168
  200. package/dist/jsx/extractor/ensureImportingConcat.js +0 -23
  201. package/dist/jsx/extractor/evaluateAstNode.js +0 -93
  202. package/dist/jsx/extractor/extractHelpers.js +0 -102
  203. package/dist/jsx/extractor/extractMediaStyle.js +0 -151
  204. package/dist/jsx/extractor/extractToClassNames.js +0 -292
  205. package/dist/jsx/extractor/findTopmostFunction.js +0 -22
  206. package/dist/jsx/extractor/generatedUid.js +0 -27
  207. package/dist/jsx/extractor/getPrefixLogs.js +0 -11
  208. package/dist/jsx/extractor/getPropValueFromAttributes.js +0 -48
  209. package/dist/jsx/extractor/getSourceModule.js +0 -68
  210. package/dist/jsx/extractor/getStaticBindingsForScope.js +0 -136
  211. package/dist/jsx/extractor/hoistClassNames.js +0 -43
  212. package/dist/jsx/extractor/literalToAst.js +0 -79
  213. package/dist/jsx/extractor/loadTamagui.js +0 -83
  214. package/dist/jsx/extractor/logLines.js +0 -21
  215. package/dist/jsx/extractor/normalizeTernaries.js +0 -52
  216. package/dist/jsx/extractor/removeUnusedHooks.js +0 -79
  217. package/dist/jsx/extractor/timer.js +0 -23
  218. package/dist/jsx/extractor/validHTMLAttributes.js +0 -51
  219. package/dist/jsx/index.js +0 -13
  220. package/dist/jsx/patchReactNativeWeb.js +0 -141
  221. package/dist/jsx/types.js +0 -0
  222. package/types/constants.d.ts.map +0 -1
  223. package/types/extractor/accessSafe.d.ts.map +0 -1
  224. package/types/extractor/babelParse.d.ts.map +0 -1
  225. package/types/extractor/buildClassName.d.ts.map +0 -1
  226. package/types/extractor/createEvaluator.d.ts.map +0 -1
  227. package/types/extractor/createExtractor.d.ts.map +0 -1
  228. package/types/extractor/ensureImportingConcat.d.ts.map +0 -1
  229. package/types/extractor/evaluateAstNode.d.ts.map +0 -1
  230. package/types/extractor/extractHelpers.d.ts.map +0 -1
  231. package/types/extractor/extractMediaStyle.d.ts.map +0 -1
  232. package/types/extractor/extractToClassNames.d.ts.map +0 -1
  233. package/types/extractor/findTopmostFunction.d.ts.map +0 -1
  234. package/types/extractor/generatedUid.d.ts.map +0 -1
  235. package/types/extractor/getPrefixLogs.d.ts.map +0 -1
  236. package/types/extractor/getPropValueFromAttributes.d.ts.map +0 -1
  237. package/types/extractor/getSourceModule.d.ts.map +0 -1
  238. package/types/extractor/getStaticBindingsForScope.d.ts.map +0 -1
  239. package/types/extractor/hoistClassNames.d.ts.map +0 -1
  240. package/types/extractor/literalToAst.d.ts.map +0 -1
  241. package/types/extractor/loadTamagui.d.ts.map +0 -1
  242. package/types/extractor/logLines.d.ts.map +0 -1
  243. package/types/extractor/normalizeTernaries.d.ts.map +0 -1
  244. package/types/extractor/removeUnusedHooks.d.ts.map +0 -1
  245. package/types/extractor/timer.d.ts.map +0 -1
  246. package/types/extractor/validHTMLAttributes.d.ts.map +0 -1
  247. package/types/index.d.ts.map +0 -1
  248. package/types/patchReactNativeWeb.d.ts +0 -2
  249. package/types/patchReactNativeWeb.d.ts.map +0 -1
  250. package/types/types.d.ts.map +0 -1
@@ -0,0 +1,32 @@
1
+ import { NodePath } from '@babel/traverse'
2
+ import * as t from '@babel/types'
3
+
4
+ const importConcatPkg = '@tamagui/helpers'
5
+
6
+ export function ensureImportingConcat(path: NodePath<t.Program>) {
7
+ const bodyPath = path.get('body')
8
+ const imported: NodePath<t.ImportDeclaration> | undefined = bodyPath.find(
9
+ (x) => x.isImportDeclaration() && x.node.source.value === importConcatPkg
10
+ ) as any
11
+ const importSpecifier = t.importSpecifier(
12
+ t.identifier('concatClassName'),
13
+ t.identifier('concatClassName')
14
+ )
15
+
16
+ if (!imported) {
17
+ path.node.body.push(t.importDeclaration([importSpecifier], t.stringLiteral(importConcatPkg)))
18
+ return
19
+ }
20
+
21
+ const specifiers = imported.node.specifiers
22
+ const alreadyImported = specifiers.some(
23
+ (x) =>
24
+ t.isImportSpecifier(x) && t.isIdentifier(x.imported) && x.imported.name === 'concatClassName'
25
+ )
26
+
27
+ if (!alreadyImported) {
28
+ specifiers.push(
29
+ t.importSpecifier(t.identifier('concatClassName'), t.identifier('concatClassName'))
30
+ )
31
+ }
32
+ }
@@ -0,0 +1,121 @@
1
+ import * as t from '@babel/types'
2
+
3
+ export function evaluateAstNode(
4
+ exprNode: t.Node | undefined | null,
5
+ evalFn?: (node: t.Node) => any,
6
+ shouldPrintDebug?: boolean | 'verbose'
7
+ ): any {
8
+ if (exprNode === undefined) {
9
+ return undefined
10
+ }
11
+
12
+ // null === boolean true (at least in our use cases for jsx eval)
13
+ if (exprNode === null) {
14
+ return true
15
+ }
16
+
17
+ if (t.isJSXExpressionContainer(exprNode)) {
18
+ return evaluateAstNode(exprNode.expression)
19
+ }
20
+
21
+ // loop through ObjectExpression keys
22
+ if (t.isObjectExpression(exprNode)) {
23
+ const ret: Record<string, any> = {}
24
+ for (let idx = -1, len = exprNode.properties.length; ++idx < len; ) {
25
+ const value = exprNode.properties[idx]
26
+
27
+ if (!t.isObjectProperty(value)) {
28
+ throw new Error('evaluateAstNode can only evaluate object properties')
29
+ }
30
+
31
+ let key: string | number | null | undefined | boolean
32
+ if (value.computed) {
33
+ if (typeof evalFn !== 'function') {
34
+ throw new Error(
35
+ 'evaluateAstNode does not support computed keys unless an eval function is provided'
36
+ )
37
+ }
38
+ key = evaluateAstNode(value.key, evalFn)
39
+ } else if (t.isIdentifier(value.key)) {
40
+ key = value.key.name
41
+ } else if (t.isStringLiteral(value.key) || t.isNumericLiteral(value.key)) {
42
+ key = value.key.value
43
+ } else {
44
+ throw new Error('Unsupported key type: ' + value.key.type)
45
+ }
46
+
47
+ if (typeof key !== 'string' && typeof key !== 'number') {
48
+ throw new Error('key must be either a string or a number')
49
+ }
50
+
51
+ ret[key] = evaluateAstNode(value.value, evalFn)
52
+ }
53
+ return ret
54
+ }
55
+
56
+ if (t.isArrayExpression(exprNode)) {
57
+ return exprNode.elements.map((x) => {
58
+ return evaluateAstNode(x as any, evalFn)
59
+ })
60
+ }
61
+
62
+ if (t.isUnaryExpression(exprNode) && exprNode.operator === '-') {
63
+ const ret = evaluateAstNode(exprNode.argument, evalFn)
64
+ if (ret == null) {
65
+ return null
66
+ }
67
+ return -ret
68
+ }
69
+
70
+ if (t.isTemplateLiteral(exprNode)) {
71
+ if (typeof evalFn !== 'function') {
72
+ throw new Error(
73
+ 'evaluateAstNode does not support template literals unless an eval function is provided'
74
+ )
75
+ }
76
+
77
+ let ret: string = ''
78
+ for (let idx = -1, len = exprNode.quasis.length; ++idx < len; ) {
79
+ const quasi = exprNode.quasis[idx]
80
+ const expr = exprNode.expressions[idx]
81
+ ret += quasi.value.raw
82
+ if (expr) {
83
+ ret += evaluateAstNode(expr, evalFn)
84
+ }
85
+ }
86
+ return ret
87
+ }
88
+
89
+ // In the interest of representing the "evaluated" prop
90
+ // as the user intended, we support negative null. Why not.
91
+ if (t.isNullLiteral(exprNode)) {
92
+ return null
93
+ }
94
+
95
+ if (t.isNumericLiteral(exprNode) || t.isStringLiteral(exprNode) || t.isBooleanLiteral(exprNode)) {
96
+ // In the interest of representing the "evaluated" prop
97
+ // as the user intended, we support negative null. Why not.
98
+ return exprNode.value
99
+ }
100
+
101
+ if (t.isBinaryExpression(exprNode)) {
102
+ if (exprNode.operator === '+') {
103
+ return evaluateAstNode(exprNode.left, evalFn) + evaluateAstNode(exprNode.right, evalFn)
104
+ } else if (exprNode.operator === '-') {
105
+ return evaluateAstNode(exprNode.left, evalFn) - evaluateAstNode(exprNode.right, evalFn)
106
+ } else if (exprNode.operator === '*') {
107
+ return evaluateAstNode(exprNode.left, evalFn) * evaluateAstNode(exprNode.right, evalFn)
108
+ } else if (exprNode.operator === '/') {
109
+ return evaluateAstNode(exprNode.left, evalFn) / evaluateAstNode(exprNode.right, evalFn)
110
+ }
111
+ }
112
+
113
+ // if we've made it this far, the value has to be evaluated
114
+ if (typeof evalFn !== 'function') {
115
+ throw new Error(
116
+ 'evaluateAstNode does not support non-literal values unless an eval function is provided'
117
+ )
118
+ }
119
+
120
+ return evalFn(exprNode)
121
+ }
@@ -0,0 +1,154 @@
1
+ import { basename, relative } from 'path'
2
+
3
+ import generate from '@babel/generator'
4
+ import type { NodePath } from '@babel/traverse'
5
+ import * as t from '@babel/types'
6
+ import findRoot from 'find-root'
7
+ import { memoize } from 'lodash'
8
+
9
+ import type { ExtractedAttr, TamaguiOptionsWithFileInfo, Ternary } from '../types.js'
10
+
11
+ // import { astToLiteral } from './literalToAst'
12
+
13
+ export function isPresent<T extends Object>(input: null | void | undefined | T): input is T {
14
+ return input != null
15
+ }
16
+
17
+ export function isSimpleSpread(node: t.JSXSpreadAttribute) {
18
+ return t.isIdentifier(node.argument) || t.isMemberExpression(node.argument)
19
+ }
20
+
21
+ export const attrStr = (attr?: ExtractedAttr) => {
22
+ return !attr
23
+ ? ''
24
+ : attr.type === 'attr'
25
+ ? getNameAttr(attr.value)
26
+ : attr.type === 'ternary'
27
+ ? `...${ternaryStr(attr.value)}`
28
+ : `${attr.type}(${objToStr(attr.value)})`
29
+ }
30
+
31
+ export const objToStr = (obj: any, spacer = ', ') => {
32
+ if (!obj) {
33
+ return `${obj}`
34
+ }
35
+ return `{${Object.entries(obj)
36
+ .map(
37
+ ([k, v]) =>
38
+ `${k}:${
39
+ Array.isArray(v)
40
+ ? `[...]`
41
+ : v && typeof v === 'object'
42
+ ? `${objToStr(v, ',')}`
43
+ : JSON.stringify(v)
44
+ }`
45
+ )
46
+ .join(spacer)}}`
47
+ }
48
+
49
+ const getNameAttr = (attr: t.JSXAttribute | t.JSXSpreadAttribute) => {
50
+ if (t.isJSXSpreadAttribute(attr)) {
51
+ return `...${attr.argument['name']}`
52
+ }
53
+ return 'name' in attr ? attr.name.name : `unknown-${attr['type']}`
54
+ }
55
+
56
+ export const ternaryStr = (x: Ternary) => {
57
+ const conditional = t.isIdentifier(x.test)
58
+ ? x.test.name
59
+ : t.isMemberExpression(x.test)
60
+ ? [x.test.object['name'], x.test.property['name']]
61
+ : generate(x.test).code
62
+ return [
63
+ 'ternary(',
64
+ conditional,
65
+ isFilledObj(x.consequent) ? ` ? ${objToStr(x.consequent)}` : ' ? 🚫',
66
+ isFilledObj(x.alternate) ? ` : ${objToStr(x.alternate)}` : ' : 🚫',
67
+ ')',
68
+ ]
69
+ .flat()
70
+ .join('')
71
+ }
72
+
73
+ const isFilledObj = (obj: any) => obj && Object.keys(obj).length
74
+
75
+ export function findComponentName(scope) {
76
+ const componentName = ''
77
+ let cur = scope.path
78
+ while (cur.parentPath && !t.isProgram(cur.parentPath.parent)) {
79
+ cur = cur.parentPath
80
+ }
81
+ let node = cur.parent
82
+ if (t.isExportNamedDeclaration(node)) {
83
+ node = node.declaration
84
+ }
85
+ if (t.isVariableDeclaration(node)) {
86
+ const [dec] = node.declarations
87
+ if (t.isVariableDeclarator(dec) && t.isIdentifier(dec.id)) {
88
+ return dec.id.name
89
+ }
90
+ }
91
+ if (t.isFunctionDeclaration(node)) {
92
+ return node.id?.name
93
+ }
94
+ return componentName
95
+ }
96
+
97
+ export function isValidThemeHook(
98
+ props: TamaguiOptionsWithFileInfo,
99
+ jsxPath: NodePath<t.JSXElement>,
100
+ n: t.MemberExpression,
101
+ sourcePath: string
102
+ ) {
103
+ if (!t.isIdentifier(n.object) || !t.isIdentifier(n.property)) return false
104
+ const bindings = jsxPath.scope.getAllBindings()
105
+ const binding = bindings[n.object.name]
106
+ if (!binding?.path) return false
107
+ if (!binding.path.isVariableDeclarator()) return false
108
+ const init = binding.path.node.init
109
+ if (!t.isCallExpression(init)) return false
110
+ if (!t.isIdentifier(init.callee)) return false
111
+ // TODO could support renaming useTheme by looking up import first
112
+ if (init.callee.name !== 'useTheme') return false
113
+ const importNode = binding.scope.getBinding('useTheme')?.path.parent
114
+ if (!t.isImportDeclaration(importNode)) return false
115
+ if (!isValidImport(props, sourcePath)) {
116
+ return false
117
+ }
118
+ return true
119
+ }
120
+
121
+ export const isInsideComponentPackage = (props: TamaguiOptionsWithFileInfo, srcName: string) => {
122
+ return getValidComponentsPaths(props).some((path) => {
123
+ return srcName.startsWith(path)
124
+ })
125
+ }
126
+
127
+ export const isComponentPackage = (props: TamaguiOptionsWithFileInfo, srcName: string) => {
128
+ return getValidComponentsPaths(props).some((path) => {
129
+ return srcName.startsWith(path)
130
+ })
131
+ }
132
+
133
+ export const isValidImport = (props: TamaguiOptionsWithFileInfo, srcName: string) => {
134
+ if (typeof srcName !== 'string') {
135
+ // eslint-disable-next-line no-console
136
+ console.trace(`Invalid file name: ${srcName}`)
137
+ return false
138
+ }
139
+ return srcName.startsWith('.')
140
+ ? isInsideComponentPackage(props, srcName)
141
+ : isComponentPackage(props, srcName)
142
+ }
143
+
144
+ const getValidComponentPackages = memoize((props: TamaguiOptionsWithFileInfo) => {
145
+ // just always look for `tamagui` and `@tamagui/core`
146
+ return [...new Set(['@tamagui/core', 'tamagui', ...props.components])]
147
+ })
148
+
149
+ const getValidComponentsPaths = memoize((props: TamaguiOptionsWithFileInfo) => {
150
+ return getValidComponentPackages(props).map((pkg) => {
151
+ const root = findRoot(pkg)
152
+ return basename(root)
153
+ })
154
+ })
@@ -0,0 +1,199 @@
1
+ import { NodePath } from '@babel/traverse'
2
+ import * as t from '@babel/types'
3
+ import { TamaguiInternalConfig, getStylesAtomic, mediaObjectToString } from '@tamagui/core-node'
4
+ import type { ViewStyle } from 'react-native'
5
+
6
+ import { MEDIA_SEP } from '../constants.js'
7
+ import type { StyleObject, TamaguiOptionsWithFileInfo, Ternary } from '../types.js'
8
+ import { isPresent, isValidImport } from './extractHelpers.js'
9
+
10
+ export function extractMediaStyle(
11
+ props: TamaguiOptionsWithFileInfo,
12
+ ternary: Ternary,
13
+ jsxPath: NodePath<t.JSXElement>,
14
+ tamaguiConfig: TamaguiInternalConfig,
15
+ sourcePath: string,
16
+ importance = 0,
17
+ shouldPrintDebug: boolean | 'verbose' = false
18
+ ) {
19
+ const mt = getMediaQueryTernary(props, ternary, jsxPath, sourcePath)
20
+ if (!mt) {
21
+ return null
22
+ }
23
+ const { key } = mt
24
+ const mq = tamaguiConfig.media[key]
25
+ if (!mq) {
26
+ // eslint-disable-next-line no-console
27
+ console.error(`Media query "${key}" not found: ${Object.keys(tamaguiConfig.media)}`)
28
+ return null
29
+ }
30
+ const getStyleObj = (styleObj: ViewStyle | null, negate = false) => {
31
+ return styleObj ? { styleObj, negate } : null
32
+ }
33
+ const styleOpts = [
34
+ getStyleObj(ternary.consequent, false),
35
+ getStyleObj(ternary.alternate, true),
36
+ ].filter(isPresent)
37
+ if (shouldPrintDebug && !styleOpts.length) {
38
+ // eslint-disable-next-line no-console
39
+ console.log(' media query, no styles?')
40
+ return null
41
+ }
42
+ // for now order first strongest
43
+ const mediaKeys = Object.keys(tamaguiConfig.media)
44
+ const mediaKeyPrecendence = mediaKeys.reduce((acc, cur, i) => {
45
+ acc[cur] = new Array(importance + 1).fill(':root').join('')
46
+ return acc
47
+ }, {})
48
+ let mediaStyles: StyleObject[] = []
49
+ for (const { styleObj, negate } of styleOpts) {
50
+ const styles = getStylesAtomic(styleObj)
51
+ const singleMediaStyles = styles.map((style) => {
52
+ const negKey = negate ? '0' : ''
53
+ const ogPrefix = style.identifier.slice(0, style.identifier.indexOf('-') + 1)
54
+ // adds an extra separator before and after to detect later in concatClassName
55
+ // so it goes from: "_f-[hash]"
56
+ // to: "_f-_sm0_[hash]" or "_f-_sm_[hash]"
57
+ const identifier = `${style.identifier.replace(
58
+ ogPrefix,
59
+ `${ogPrefix}${MEDIA_SEP}${key}${negKey}${MEDIA_SEP}`
60
+ )}`
61
+ const className = `.${identifier}`
62
+ const mediaSelector = mediaObjectToString(tamaguiConfig.media[key])
63
+ const screenStr = negate ? 'not all' : 'screen'
64
+ const mediaQuery = `${screenStr} and ${mediaSelector}`
65
+ const precendencePrefix = mediaKeyPrecendence[key]
66
+ const styleInner = style.rules
67
+ .map((rule) => rule.replace(style.identifier, identifier))
68
+ .join(';')
69
+ // combines media queries if they already exist
70
+ let styleRule = ''
71
+ if (styleInner.includes('@media')) {
72
+ // combine
73
+ styleRule = styleInner.replace('{', ` and ${mediaQuery} {`)
74
+ } else {
75
+ styleRule = `@media ${mediaQuery} { ${precendencePrefix} ${styleInner} }`
76
+ }
77
+ return {
78
+ ...style,
79
+ identifier,
80
+ className,
81
+ rules: [styleRule],
82
+ }
83
+ })
84
+ if (shouldPrintDebug === 'verbose') {
85
+ // prettier-ignore
86
+ // eslint-disable-next-line no-console
87
+ console.log(' media styles:', importance, styleObj, singleMediaStyles.map(x => x.identifier).join(', '))
88
+ }
89
+ // add to output
90
+ mediaStyles = [...mediaStyles, ...singleMediaStyles]
91
+ }
92
+ // filter out
93
+ ternary.remove()
94
+ return { mediaStyles, ternaryWithoutMedia: mt.ternaryWithoutMedia }
95
+ }
96
+
97
+ function getMediaQueryTernary(
98
+ props: TamaguiOptionsWithFileInfo,
99
+ ternary: Ternary,
100
+ jsxPath: NodePath<t.JSXElement>,
101
+ sourcePath: string
102
+ ): null | {
103
+ key: string
104
+ bindingName: string
105
+ ternaryWithoutMedia: Ternary | null
106
+ } {
107
+ // this handles unwrapping logical && media query ternarys
108
+ // first, unwrap if it has media logicalExpression
109
+ if (t.isLogicalExpression(ternary.test) && ternary.test.operator === '&&') {
110
+ // *should* be normalized to always be on left side
111
+ const mediaLeft = getMediaInfoFromExpression(
112
+ props,
113
+ ternary.test.left,
114
+ jsxPath,
115
+ sourcePath,
116
+ ternary.inlineMediaQuery
117
+ )
118
+ if (mediaLeft) {
119
+ return {
120
+ ...mediaLeft,
121
+ ternaryWithoutMedia: {
122
+ ...ternary,
123
+ test: ternary.test.right,
124
+ },
125
+ }
126
+ }
127
+ }
128
+ // const media = useMedia()
129
+ // ... media.sm
130
+ const result = getMediaInfoFromExpression(
131
+ props,
132
+ ternary.test,
133
+ jsxPath,
134
+ sourcePath,
135
+ ternary.inlineMediaQuery
136
+ )
137
+ if (result) {
138
+ return {
139
+ ...result,
140
+ ternaryWithoutMedia: null,
141
+ }
142
+ }
143
+ return null
144
+ }
145
+
146
+ function getMediaInfoFromExpression(
147
+ props: TamaguiOptionsWithFileInfo,
148
+ test: t.Expression,
149
+ jsxPath: NodePath<t.JSXElement>,
150
+ sourcePath: string,
151
+ inlineMediaQuery?: string
152
+ ) {
153
+ if (inlineMediaQuery) {
154
+ return {
155
+ key: inlineMediaQuery,
156
+ bindingName: inlineMediaQuery,
157
+ }
158
+ }
159
+ if (t.isMemberExpression(test) && t.isIdentifier(test.object) && t.isIdentifier(test.property)) {
160
+ const name = test.object['name']
161
+ const key = test.property['name']
162
+ const bindings = jsxPath.scope.getAllBindings()
163
+ const binding = bindings[name]
164
+ if (!binding) return false
165
+ const bindingNode = binding.path?.node
166
+ if (!t.isVariableDeclarator(bindingNode) || !bindingNode.init) return false
167
+ if (!isValidMediaCall(props, jsxPath, bindingNode.init, sourcePath)) return false
168
+ return { key, bindingName: name }
169
+ }
170
+ if (t.isIdentifier(test)) {
171
+ const key = test.name
172
+ const node = jsxPath.scope.getBinding(test.name)?.path?.node
173
+ if (!t.isVariableDeclarator(node)) return false
174
+ if (!node.init || !isValidMediaCall(props, jsxPath, node.init, sourcePath)) return false
175
+ return { key, bindingName: key }
176
+ }
177
+ return null
178
+ }
179
+
180
+ export function isValidMediaCall(
181
+ props: TamaguiOptionsWithFileInfo,
182
+ jsxPath: NodePath<t.JSXElement>,
183
+ init: t.Expression,
184
+ sourcePath: string
185
+ ) {
186
+ if (!t.isCallExpression(init)) return false
187
+ if (!t.isIdentifier(init.callee)) return false
188
+ // TODO could support renaming useMedia by looking up import first
189
+ if (init.callee.name !== 'useMedia') return false
190
+ const bindings = jsxPath.scope.getAllBindings()
191
+ const mediaBinding = bindings['useMedia']
192
+ if (!mediaBinding) return false
193
+ const useMediaImport = mediaBinding.path.parent
194
+ if (!t.isImportDeclaration(useMediaImport)) return false
195
+ if (!isValidImport(props, sourcePath)) {
196
+ return false
197
+ }
198
+ return true
199
+ }