@tamagui/static 1.132.15 → 1.132.16-1754534218765
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.
- package/dist/extractor/createExtractor.js +44 -107
- package/dist/extractor/createExtractor.js.map +1 -1
- package/dist/extractor/createExtractor.native.js +52 -112
- package/dist/extractor/createExtractor.native.js.map +2 -2
- package/dist/extractor/extractMediaStyle.js +1 -1
- package/dist/extractor/extractMediaStyle.js.map +1 -1
- package/dist/extractor/extractMediaStyle.native.js +1 -1
- package/dist/extractor/extractMediaStyle.native.js.map +2 -2
- package/dist/extractor/extractToClassNames.js +184 -168
- package/dist/extractor/extractToClassNames.js.map +2 -2
- package/dist/extractor/extractToClassNames.native.js +185 -186
- package/dist/extractor/extractToClassNames.native.js.map +2 -2
- package/dist/extractor/extractToNative.js +47 -78
- package/dist/extractor/extractToNative.js.map +1 -1
- package/dist/extractor/extractToNative.native.js +23 -39
- package/dist/extractor/extractToNative.native.js.map +2 -2
- package/dist/extractor/normalizeTernaries.js +5 -2
- package/dist/extractor/normalizeTernaries.js.map +1 -1
- package/dist/extractor/normalizeTernaries.native.js +2 -2
- package/dist/extractor/normalizeTernaries.native.js.map +2 -2
- package/dist/registerRequire.js +1 -1
- package/dist/registerRequire.js.map +1 -1
- package/dist/registerRequire.native.js +1 -1
- package/dist/registerRequire.native.js.map +1 -1
- package/dist/types.native.js.map +1 -1
- package/package.json +15 -15
- package/src/extractor/createExtractor.ts +74 -172
- package/src/extractor/extractMediaStyle.ts +1 -1
- package/src/extractor/extractToClassNames.ts +334 -260
- package/src/extractor/extractToNative.ts +68 -111
- package/src/extractor/normalizeTernaries.ts +7 -3
- package/src/registerRequire.ts +1 -1
- package/src/types.ts +9 -13
- package/types/extractor/createExtractor.d.ts.map +1 -1
- package/types/extractor/extractToClassNames.d.ts.map +1 -1
- package/types/extractor/extractToNative.d.ts.map +1 -1
- package/types/extractor/normalizeTernaries.d.ts.map +1 -1
- package/types/types.d.ts +8 -10
- package/types/types.d.ts.map +1 -1
- package/dist/extractor/buildClassName.js +0 -72
- package/dist/extractor/buildClassName.js.map +0 -6
- package/dist/extractor/buildClassName.native.js +0 -67
- package/dist/extractor/buildClassName.native.js.map +0 -6
- package/dist/extractor/ensureImportingConcat.js +0 -50
- package/dist/extractor/ensureImportingConcat.js.map +0 -6
- package/dist/extractor/ensureImportingConcat.native.js +0 -49
- package/dist/extractor/ensureImportingConcat.native.js.map +0 -6
- package/dist/extractor/hoistClassNames.js +0 -63
- package/dist/extractor/hoistClassNames.js.map +0 -6
- package/dist/extractor/hoistClassNames.native.js +0 -66
- package/dist/extractor/hoistClassNames.native.js.map +0 -6
- package/src/extractor/buildClassName.ts +0 -76
- package/src/extractor/ensureImportingConcat.ts +0 -36
- package/src/extractor/hoistClassNames.ts +0 -52
- package/types/extractor/buildClassName.d.ts +0 -7
- package/types/extractor/buildClassName.d.ts.map +0 -1
- package/types/extractor/ensureImportingConcat.d.ts +0 -4
- package/types/extractor/ensureImportingConcat.d.ts.map +0 -1
- package/types/extractor/hoistClassNames.d.ts +0 -6
- package/types/extractor/hoistClassNames.d.ts.map +0 -1
@@ -1,31 +1,19 @@
|
|
1
|
-
import * as path from 'node:path'
|
2
|
-
import * as util from 'node:util'
|
3
|
-
|
4
1
|
import generate from '@babel/generator'
|
2
|
+
import type { NodePath } from '@babel/traverse'
|
5
3
|
import * as t from '@babel/types'
|
6
|
-
import
|
7
|
-
import
|
8
|
-
|
4
|
+
import { StyleObjectIdentifier, StyleObjectRules } from '@tamagui/web'
|
5
|
+
import * as path from 'node:path'
|
6
|
+
import * as util from 'node:util'
|
9
7
|
import { requireTamaguiCore } from '../helpers/requireTamaguiCore'
|
10
|
-
import type {
|
8
|
+
import type { StyleObject, TamaguiOptions, Ternary } from '../types'
|
11
9
|
import { babelParse } from './babelParse'
|
12
|
-
import { buildClassName } from './buildClassName'
|
13
10
|
import type { Extractor } from './createExtractor'
|
14
11
|
import { createLogger } from './createLogger'
|
15
|
-
import { ensureImportingConcat } from './ensureImportingConcat'
|
16
|
-
import { isSimpleSpread } from './extractHelpers'
|
17
12
|
import { extractMediaStyle } from './extractMediaStyle'
|
18
|
-
import {
|
13
|
+
import { normalizeTernaries } from './normalizeTernaries'
|
19
14
|
import { getFontFamilyClassNameFromProps } from './propsToFontFamilyCache'
|
20
15
|
import { timer } from './timer'
|
21
16
|
|
22
|
-
const mergeStyleGroups = {
|
23
|
-
shadowOpacity: true,
|
24
|
-
shadowRadius: true,
|
25
|
-
shadowColor: true,
|
26
|
-
shadowOffset: true,
|
27
|
-
}
|
28
|
-
|
29
17
|
export type ExtractedResponse = {
|
30
18
|
js: string | Buffer
|
31
19
|
styles: string
|
@@ -42,6 +30,12 @@ export type ExtractToClassNamesProps = {
|
|
42
30
|
shouldPrintDebug: boolean | 'verbose'
|
43
31
|
}
|
44
32
|
|
33
|
+
// we only expand into ternaries or plain attr, all style is turned into a always-true ternary
|
34
|
+
// this lets us more easily combine everything easily
|
35
|
+
// all ternaries in this array ONLY have consequent, they are normalized
|
36
|
+
const remove = () => {} // we dont remove after this step
|
37
|
+
const spaceString = t.stringLiteral(' ')
|
38
|
+
|
45
39
|
export async function extractToClassNames({
|
46
40
|
extractor,
|
47
41
|
source,
|
@@ -50,7 +44,7 @@ export async function extractToClassNames({
|
|
50
44
|
shouldPrintDebug,
|
51
45
|
}: ExtractToClassNamesProps): Promise<ExtractedResponse | null> {
|
52
46
|
const tm = timer()
|
53
|
-
const { getCSSStylesAtomic } = requireTamaguiCore('web')
|
47
|
+
const { getCSSStylesAtomic, mergeProps, createMediaStyle } = requireTamaguiCore('web')
|
54
48
|
|
55
49
|
if (sourcePath.includes('node_modules')) {
|
56
50
|
return null
|
@@ -93,9 +87,7 @@ export async function extractToClassNames({
|
|
93
87
|
tm.mark(`babel-parse`, shouldPrintDebug === 'verbose')
|
94
88
|
|
95
89
|
const cssMap = new Map<string, { css: string; commentTexts: string[] }>()
|
96
|
-
const
|
97
|
-
|
98
|
-
let hasFlattened = false
|
90
|
+
const tamaguiConfig = extractor.getTamagui()!
|
99
91
|
|
100
92
|
const res = await extractor.parse(ast, {
|
101
93
|
shouldPrintDebug,
|
@@ -103,7 +95,7 @@ export async function extractToClassNames({
|
|
103
95
|
platform: 'web',
|
104
96
|
sourcePath,
|
105
97
|
extractStyledDefinitions: true,
|
106
|
-
|
98
|
+
onStyledDefinitionRule(identifier, rules) {
|
107
99
|
const css = rules.join(';')
|
108
100
|
if (shouldPrintDebug) {
|
109
101
|
console.info(`adding styled() rule: .${identifier} ${css}`)
|
@@ -111,7 +103,6 @@ export async function extractToClassNames({
|
|
111
103
|
cssMap.set(`.${identifier}`, { css, commentTexts: [] })
|
112
104
|
},
|
113
105
|
getFlattenedNode: ({ tag }) => {
|
114
|
-
hasFlattened = true
|
115
106
|
return tag
|
116
107
|
},
|
117
108
|
onExtractTag: ({
|
@@ -123,8 +114,6 @@ export async function extractToClassNames({
|
|
123
114
|
originalNodeName,
|
124
115
|
filePath,
|
125
116
|
lineNumbers,
|
126
|
-
programPath,
|
127
|
-
isFlattened,
|
128
117
|
staticConfig,
|
129
118
|
}) => {
|
130
119
|
// bail out of views that don't accept className (falls back to runtime + style={})
|
@@ -135,288 +124,330 @@ export async function extractToClassNames({
|
|
135
124
|
return
|
136
125
|
}
|
137
126
|
|
138
|
-
//
|
139
|
-
|
140
|
-
|
127
|
+
// re-worked how we do this
|
128
|
+
// merging ternaries on top of base styles is not simple, because we need to ensure the final
|
129
|
+
// className has no duplicate style props and selector order is preserved
|
130
|
+
// before we tried to be smart and build a big binary expression
|
131
|
+
// instead, what we'll do now is pre-calculate the entire className for every possible path
|
132
|
+
// for super complex components that means we *will* output a lot of bigger classNames
|
133
|
+
// but its so much simpler than trying to implement a multi-stage solver here
|
134
|
+
// and in the end its just strings that gzip very well
|
135
|
+
// its also much easier to intuit/debug for end users and ourselves
|
136
|
+
|
137
|
+
// example:
|
138
|
+
// a ? 'a' : 'b'
|
139
|
+
// b ? 'c' : 'd'
|
140
|
+
// we want:
|
141
|
+
// a && b ? 'a c' : ''
|
142
|
+
// !a && b ? 'b c' : ''
|
143
|
+
// a && !b ? 'a d' : ''
|
144
|
+
// !a && !b ? 'b d' : ''
|
145
|
+
|
146
|
+
// we also simplified the compiler to only handle views that can be fully flattened
|
147
|
+
// this means we don't need to account for strange in-between spreads, so we can merge things
|
148
|
+
// fairly simply. first, we just merge forward all the non-ternary styles into ternaries.
|
149
|
+
|
150
|
+
// save for the end
|
151
|
+
const finalAttrs: t.JSXAttribute[] = []
|
152
|
+
|
153
|
+
let mergeForwardBaseStyle: Object | null = null
|
154
|
+
let attrClassName: t.Expression | null = null
|
155
|
+
let baseFontFamily = ''
|
156
|
+
let mediaStylesSeen = 1
|
141
157
|
|
142
|
-
|
143
|
-
|
144
|
-
|
158
|
+
const comment = util.format(
|
159
|
+
'/* %s:%s (%s) */',
|
160
|
+
filePath,
|
161
|
+
lineNumbers,
|
162
|
+
originalNodeName
|
163
|
+
)
|
145
164
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
165
|
+
function addStyle(style: StyleObject) {
|
166
|
+
const identifier = style[StyleObjectIdentifier]
|
167
|
+
const rules = style[StyleObjectRules]
|
168
|
+
const selector = `.${identifier}`
|
169
|
+
if (cssMap.has(selector)) {
|
170
|
+
const val = cssMap.get(selector)!
|
171
|
+
val.commentTexts.push(comment)
|
172
|
+
} else if (rules.length) {
|
173
|
+
cssMap.set(selector, {
|
174
|
+
css: rules.join('\n'),
|
175
|
+
commentTexts: [comment],
|
176
|
+
})
|
153
177
|
}
|
178
|
+
return identifier
|
154
179
|
}
|
155
180
|
|
156
|
-
|
157
|
-
|
158
|
-
const
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
181
|
+
function addStyles(style: Object) {
|
182
|
+
const cssStyles = getCSSStylesAtomic(style as any)
|
183
|
+
const classNames: string[] = []
|
184
|
+
|
185
|
+
for (const style of cssStyles) {
|
186
|
+
const mediaName = style[0].slice(1)
|
187
|
+
if (tamaguiConfig.media[mediaName]) {
|
188
|
+
const mediaStyle = createMediaStyle(
|
189
|
+
style,
|
190
|
+
mediaName,
|
191
|
+
extractor.getTamagui()!.media,
|
192
|
+
true,
|
193
|
+
false,
|
194
|
+
mediaStylesSeen
|
195
|
+
)
|
196
|
+
const identifier = addStyle(mediaStyle)
|
197
|
+
classNames.push(identifier)
|
198
|
+
continue
|
165
199
|
}
|
166
|
-
}
|
167
|
-
return style
|
168
|
-
}
|
169
200
|
|
170
|
-
|
171
|
-
|
172
|
-
const styleWithPrev = ensureNeededPrevStyle(style)
|
173
|
-
const res = getCSSStylesAtomic(styleWithPrev as any)
|
174
|
-
if (res.length) {
|
175
|
-
finalStyles = [...finalStyles, ...res]
|
201
|
+
const identifier = addStyle(style)
|
202
|
+
classNames.push(identifier)
|
176
203
|
}
|
177
|
-
|
204
|
+
|
205
|
+
return classNames
|
178
206
|
}
|
179
207
|
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
switch (attr.type) {
|
184
|
-
case 'style': {
|
185
|
-
if (!isFlattened) {
|
186
|
-
const styles = getCSSStylesAtomic(attr.value as any)
|
187
|
-
|
188
|
-
finalStyles = [...finalStyles, ...styles]
|
189
|
-
|
190
|
-
for (const style of styles) {
|
191
|
-
// leave them as attributes
|
192
|
-
const prop = style[helpers.StyleObjectPseudo]
|
193
|
-
? `${style[helpers.StyleObjectProperty]}-${
|
194
|
-
style[helpers.StyleObjectPseudo]
|
195
|
-
}`
|
196
|
-
: style[helpers.StyleObjectProperty]
|
197
|
-
finalAttrs.push(
|
198
|
-
t.jsxAttribute(
|
199
|
-
t.jsxIdentifier(prop),
|
200
|
-
t.stringLiteral(style[helpers.StyleObjectIdentifier])
|
201
|
-
)
|
202
|
-
)
|
203
|
-
}
|
204
|
-
} else {
|
205
|
-
const styles = addStyles(attr.value)
|
206
|
-
const newFontFamily = getFontFamilyClassNameFromProps(attr.value) || ''
|
207
|
-
const newClassNames = helpers.concatClassName(
|
208
|
-
styles.map((x) => x[helpers.StyleObjectIdentifier]).join(' ') +
|
209
|
-
newFontFamily
|
210
|
-
)
|
211
|
-
const existing = finalClassNames.find(
|
212
|
-
(x) => x.type == 'StringLiteral'
|
213
|
-
) as t.StringLiteral | null
|
214
|
-
|
215
|
-
if (existing) {
|
216
|
-
let previous = existing.value
|
217
|
-
// replace existing font_ with new one
|
218
|
-
if (newFontFamily) {
|
219
|
-
if (shouldPrintDebug) {
|
220
|
-
console.info(` newFontFamily: ${newFontFamily}`)
|
221
|
-
}
|
222
|
-
previous = previous.replace(/font_[a-z]+/i, '')
|
223
|
-
}
|
224
|
-
existing.value = `${previous} ${newClassNames}`
|
225
|
-
} else {
|
226
|
-
finalClassNames = [...finalClassNames, t.stringLiteral(newClassNames)]
|
227
|
-
}
|
228
|
-
}
|
208
|
+
const onlyTernaries: Ternary[] = attrs.flatMap((attr) => {
|
209
|
+
if (attr.type === 'attr') {
|
210
|
+
const value = attr.value
|
229
211
|
|
230
|
-
|
212
|
+
if (t.isJSXSpreadAttribute(value)) {
|
213
|
+
// we only handle flattened stuff now so skip this
|
214
|
+
console.error(`Should never happen`)
|
215
|
+
return []
|
231
216
|
}
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
t.logicalExpression(
|
238
|
-
'&&',
|
239
|
-
val.argument,
|
240
|
-
t.memberExpression(val.argument, t.identifier('className'))
|
241
|
-
)
|
242
|
-
)
|
243
|
-
}
|
244
|
-
} else if (val.name.name === 'className') {
|
245
|
-
const value = val.value
|
246
|
-
if (value) {
|
247
|
-
try {
|
248
|
-
const evaluatedValue = attemptEval(value)
|
249
|
-
finalClassNames.push(t.stringLiteral(evaluatedValue))
|
250
|
-
} catch (e) {
|
251
|
-
finalClassNames.push(value['expression'])
|
252
|
-
}
|
253
|
-
}
|
254
|
-
continue
|
217
|
+
|
218
|
+
if (value.name.name === 'className') {
|
219
|
+
let inner: any = value.value
|
220
|
+
if (t.isJSXExpressionContainer(inner)) {
|
221
|
+
inner = inner.expression
|
255
222
|
}
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
const mediaExtraction = extractMediaStyle(
|
261
|
-
parserProps,
|
262
|
-
attr.value,
|
263
|
-
jsxPath,
|
264
|
-
extractor.getTamagui()!,
|
265
|
-
sourcePath || '',
|
266
|
-
lastMediaImportance,
|
267
|
-
shouldPrintDebug
|
268
|
-
)
|
269
|
-
if (shouldPrintDebug) {
|
270
|
-
if (mediaExtraction) {
|
271
|
-
console.info(
|
272
|
-
'ternary (mediaStyles)',
|
273
|
-
mediaExtraction.ternaryWithoutMedia?.inlineMediaQuery ?? '',
|
274
|
-
mediaExtraction.mediaStyles
|
275
|
-
.map((x) => x[helpers.StyleObjectIdentifier])
|
276
|
-
.join('.')
|
277
|
-
)
|
223
|
+
try {
|
224
|
+
const evaluatedValue = inner ? attemptEval(inner) : null
|
225
|
+
if (typeof evaluatedValue === 'string') {
|
226
|
+
attrClassName = t.stringLiteral(evaluatedValue)
|
278
227
|
}
|
279
|
-
}
|
280
|
-
|
281
|
-
|
282
|
-
if (mediaExtraction) {
|
283
|
-
console.info('add ternary')
|
284
|
-
}
|
228
|
+
} catch (e) {
|
229
|
+
if (inner) {
|
230
|
+
attrClassName ||= inner
|
285
231
|
}
|
286
|
-
addTernaryStyle(
|
287
|
-
attr.value,
|
288
|
-
addStyles(attr.value.consequent),
|
289
|
-
addStyles(attr.value.alternate)
|
290
|
-
)
|
291
|
-
continue
|
292
232
|
}
|
293
|
-
|
233
|
+
return []
|
234
|
+
}
|
235
|
+
|
236
|
+
finalAttrs.push(value)
|
237
|
+
return []
|
238
|
+
}
|
239
|
+
|
240
|
+
if (attr.type === 'style') {
|
241
|
+
mergeForwardBaseStyle = mergeProps(mergeForwardBaseStyle || {}, attr.value)
|
242
|
+
baseFontFamily = getFontFamilyClassNameFromProps(attr.value) || ''
|
243
|
+
return []
|
244
|
+
}
|
245
|
+
|
246
|
+
let ternary = attr.value
|
247
|
+
|
248
|
+
if (ternary.inlineMediaQuery) {
|
249
|
+
const mediaExtraction = extractMediaStyle(
|
250
|
+
parserProps,
|
251
|
+
attr.value,
|
252
|
+
jsxPath,
|
253
|
+
extractor.getTamagui()!,
|
254
|
+
sourcePath || '',
|
255
|
+
mediaStylesSeen++,
|
256
|
+
shouldPrintDebug
|
257
|
+
)
|
258
|
+
|
259
|
+
if (mediaExtraction) {
|
294
260
|
if (mediaExtraction.mediaStyles) {
|
295
|
-
|
261
|
+
mergeForwardBaseStyle = mergeProps(mergeForwardBaseStyle || {}, {
|
262
|
+
[`$${ternary.inlineMediaQuery}`]: attr.value.consequent!,
|
263
|
+
})
|
296
264
|
}
|
297
265
|
if (mediaExtraction.ternaryWithoutMedia) {
|
298
|
-
|
299
|
-
mediaExtraction.ternaryWithoutMedia,
|
300
|
-
mediaExtraction.mediaStyles,
|
301
|
-
[]
|
302
|
-
)
|
266
|
+
ternary = mediaExtraction.ternaryWithoutMedia
|
303
267
|
} else {
|
304
|
-
|
305
|
-
...finalClassNames,
|
306
|
-
...mediaExtraction.mediaStyles.map((x) =>
|
307
|
-
t.stringLiteral(x[helpers.StyleObjectIdentifier])
|
308
|
-
),
|
309
|
-
]
|
268
|
+
return []
|
310
269
|
}
|
311
|
-
break
|
312
270
|
}
|
313
271
|
}
|
272
|
+
|
273
|
+
// merge the base style forward into both sides
|
274
|
+
return {
|
275
|
+
...ternary,
|
276
|
+
fontFamily: baseFontFamily,
|
277
|
+
alternate: mergeProps(mergeForwardBaseStyle || {}, ternary.alternate || {}),
|
278
|
+
consequent: mergeProps(mergeForwardBaseStyle || {}, ternary.consequent || {}),
|
279
|
+
}
|
280
|
+
})
|
281
|
+
|
282
|
+
const hasTernaries = Boolean(onlyTernaries.length)
|
283
|
+
|
284
|
+
const baseClassNames = mergeForwardBaseStyle
|
285
|
+
? addStyles(mergeForwardBaseStyle)
|
286
|
+
: null
|
287
|
+
|
288
|
+
let baseClassNameStr =
|
289
|
+
hasTernaries || !baseClassNames ? '' : ` ${baseClassNames.join(' ')}`
|
290
|
+
|
291
|
+
if (!hasTernaries && baseFontFamily) {
|
292
|
+
baseClassNameStr = `font_${baseFontFamily} ${baseClassNameStr}`
|
314
293
|
}
|
315
294
|
|
316
|
-
|
317
|
-
|
318
|
-
|
295
|
+
let base = staticConfig.componentName
|
296
|
+
? t.stringLiteral(`is_${staticConfig.componentName}${baseClassNameStr}`)
|
297
|
+
: t.stringLiteral(baseClassNameStr || ' ')
|
319
298
|
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
299
|
+
attrClassName = attrClassName as t.Expression | null // actual typescript bug, flatMap doesn't update from never
|
300
|
+
|
301
|
+
const baseClassNameExpression: t.Expression = (() => {
|
302
|
+
if (attrClassName) {
|
303
|
+
if (t.isStringLiteral(attrClassName)) {
|
304
|
+
return t.stringLiteral(
|
305
|
+
base.value ? `${base.value} ${attrClassName.value}` : attrClassName.value
|
326
306
|
)
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
t.stringLiteral(' ' + aCN)
|
307
|
+
} else {
|
308
|
+
// space after to ensure its a string and its spaced
|
309
|
+
return t.conditionalExpression(
|
310
|
+
attrClassName,
|
311
|
+
t.binaryExpression('+', attrClassName, spaceString),
|
312
|
+
base
|
334
313
|
)
|
335
|
-
|
314
|
+
}
|
336
315
|
}
|
337
|
-
|
316
|
+
return base
|
317
|
+
})()
|
338
318
|
|
339
|
-
|
340
|
-
console.info(' finalClassNames AST\n', JSON.stringify(finalClassNames, null, 2))
|
341
|
-
}
|
319
|
+
const expandedTernaries: Ternary[] = []
|
342
320
|
|
343
|
-
|
321
|
+
if (onlyTernaries.length) {
|
322
|
+
// normalize tests to reduce duplicates
|
323
|
+
const normalizedTernaries = normalizeTernaries(onlyTernaries)
|
344
324
|
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
return value
|
325
|
+
for (const ternary of normalizedTernaries) {
|
326
|
+
if (!expandedTernaries.length) {
|
327
|
+
expandTernary(ternary)
|
328
|
+
continue
|
350
329
|
}
|
351
|
-
|
352
|
-
|
353
|
-
if (process.env.TAMAGUI_DEBUG_OPTIMIZATIONS) {
|
354
|
-
value += `is_tamagui_flattened`
|
330
|
+
for (const prev of [...expandedTernaries]) {
|
331
|
+
expandTernary(ternary, prev)
|
355
332
|
}
|
333
|
+
}
|
334
|
+
}
|
356
335
|
|
357
|
-
|
358
|
-
|
359
|
-
|
336
|
+
function expandTernary(ternary: Ternary, prev?: Ternary) {
|
337
|
+
// need to diverge into two (or four if alternate)
|
338
|
+
if (ternary.consequent && Object.keys(ternary.consequent).length) {
|
339
|
+
expandedTernaries.push({
|
340
|
+
// prevTest && test: merge consequent
|
341
|
+
test: prev
|
342
|
+
? t.logicalExpression('&&', prev.test, ternary.test)
|
343
|
+
: ternary.test,
|
344
|
+
consequent: prev
|
345
|
+
? mergeProps(prev.consequent!, ternary.consequent)
|
346
|
+
: ternary.consequent,
|
347
|
+
remove,
|
348
|
+
alternate: null,
|
349
|
+
})
|
350
|
+
|
351
|
+
if (prev) {
|
352
|
+
expandedTernaries.push({
|
353
|
+
// !prevTest && test: just consequent
|
354
|
+
test: t.logicalExpression(
|
355
|
+
'&&',
|
356
|
+
t.unaryExpression('!', prev.test),
|
357
|
+
ternary.test
|
358
|
+
),
|
359
|
+
consequent: ternary.consequent,
|
360
|
+
alternate: null,
|
361
|
+
remove,
|
362
|
+
})
|
360
363
|
}
|
364
|
+
}
|
361
365
|
|
362
|
-
|
363
|
-
|
366
|
+
if (ternary.alternate && Object.keys(ternary.alternate).length) {
|
367
|
+
const negated = t.unaryExpression('!', ternary.test)
|
368
|
+
expandedTernaries.push({
|
369
|
+
// prevTest && !test: merge alternate
|
370
|
+
test: prev ? t.logicalExpression('&&', prev.test, negated) : negated,
|
371
|
+
consequent: prev
|
372
|
+
? mergeProps(prev.consequent!, ternary.alternate)
|
373
|
+
: ternary.alternate,
|
374
|
+
remove,
|
375
|
+
alternate: null,
|
376
|
+
})
|
364
377
|
|
365
|
-
|
366
|
-
|
378
|
+
if (prev) {
|
379
|
+
expandedTernaries.push({
|
380
|
+
// !prevTest && !test: just alternate
|
381
|
+
test: t.logicalExpression(
|
382
|
+
'&&',
|
383
|
+
t.unaryExpression('!', prev.test),
|
384
|
+
ternary.test
|
385
|
+
),
|
386
|
+
consequent: ternary.alternate,
|
387
|
+
remove,
|
388
|
+
alternate: null,
|
389
|
+
})
|
390
|
+
}
|
391
|
+
}
|
392
|
+
}
|
367
393
|
|
368
|
-
|
369
|
-
let expr = nameExpr
|
394
|
+
let ternaryClassNameExpr: t.Expression | null = null
|
370
395
|
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
396
|
+
// next: create all CSS, build className strings and hoist, and create final node with props
|
397
|
+
if (hasTernaries) {
|
398
|
+
for (const ternary of expandedTernaries) {
|
399
|
+
if (!ternary.consequent) continue
|
400
|
+
const classNames = addStyles(ternary.consequent)
|
401
|
+
if (ternary.fontFamily) {
|
402
|
+
classNames.unshift(`font_${ternary.fontFamily}`)
|
403
|
+
}
|
404
|
+
const baseString = t.isStringLiteral(baseClassNameExpression)
|
405
|
+
? baseClassNameExpression.value
|
406
|
+
: ''
|
407
|
+
const fullClassName =
|
408
|
+
(baseString ? `${baseString} ` : '') + classNames.join(' ')
|
409
|
+
const classNameLiteral = t.stringLiteral(fullClassName)
|
410
|
+
|
411
|
+
if (!ternaryClassNameExpr) {
|
412
|
+
ternaryClassNameExpr = classNameLiteral
|
375
413
|
} else {
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
isSimpleSpread(x.value)
|
382
|
-
)
|
383
|
-
})
|
384
|
-
expr = t.callExpression(t.identifier('concatClassName'), [
|
385
|
-
expr,
|
386
|
-
...simpleSpreads.map((val) => val.value['argument']),
|
387
|
-
])
|
414
|
+
ternaryClassNameExpr = t.conditionalExpression(
|
415
|
+
ternary.test,
|
416
|
+
classNameLiteral,
|
417
|
+
ternaryClassNameExpr
|
418
|
+
)
|
388
419
|
}
|
389
420
|
}
|
421
|
+
}
|
390
422
|
|
391
|
-
|
392
|
-
|
393
|
-
|
423
|
+
let finalExpression: t.Expression | null =
|
424
|
+
!hasTernaries || !t.isStringLiteral(baseClassNameExpression)
|
425
|
+
? baseClassNameExpression
|
426
|
+
: null
|
427
|
+
|
428
|
+
if (ternaryClassNameExpr) {
|
429
|
+
finalExpression =
|
430
|
+
baseClassNameExpression && baseClassNameExpression !== spaceString
|
431
|
+
? t.binaryExpression('+', baseClassNameExpression, ternaryClassNameExpr)
|
432
|
+
: ternaryClassNameExpr
|
394
433
|
}
|
395
434
|
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
lineNumbers,
|
400
|
-
originalNodeName
|
401
|
-
)
|
435
|
+
// console.info('attrs', JSON.stringify(attrs, null, 2))
|
436
|
+
// console.info('expandedTernaries', JSON.stringify(expandedTernaries, null, 2))
|
437
|
+
// console.info('finalExpression', JSON.stringify(finalExpression, null, 2))
|
402
438
|
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
}
|
413
|
-
} else if (rules.length) {
|
414
|
-
cssMap.set(className, {
|
415
|
-
css: rules.join('\n'),
|
416
|
-
commentTexts: [comment],
|
417
|
-
})
|
418
|
-
}
|
439
|
+
if (finalExpression) {
|
440
|
+
// hoist to global variables
|
441
|
+
finalExpression = hoistClassNames(jsxPath, finalExpression)
|
442
|
+
|
443
|
+
const classNameProp = t.jsxAttribute(
|
444
|
+
t.jsxIdentifier('className'),
|
445
|
+
t.jsxExpressionContainer(finalExpression!)
|
446
|
+
)
|
447
|
+
finalAttrs.unshift(classNameProp)
|
419
448
|
}
|
449
|
+
|
450
|
+
node.attributes = finalAttrs
|
420
451
|
},
|
421
452
|
})
|
422
453
|
|
@@ -466,3 +497,46 @@ export async function extractToClassNames({
|
|
466
497
|
map: result.map,
|
467
498
|
}
|
468
499
|
}
|
500
|
+
|
501
|
+
function hoistClassNames(path: NodePath<t.JSXElement>, expr: t.Expression) {
|
502
|
+
if (t.isStringLiteral(expr)) {
|
503
|
+
return hoistClassName(path, expr.value)
|
504
|
+
}
|
505
|
+
|
506
|
+
if (t.isBinaryExpression(expr)) {
|
507
|
+
const left = t.isStringLiteral(expr.left)
|
508
|
+
? hoistClassName(path, expr.left.value)
|
509
|
+
: expr.left
|
510
|
+
const right = t.isStringLiteral(expr.right)
|
511
|
+
? hoistClassName(path, expr.right.value)
|
512
|
+
: hoistClassNames(path, expr.right)
|
513
|
+
return t.binaryExpression(expr.operator, left, right)
|
514
|
+
}
|
515
|
+
|
516
|
+
if (t.isConditionalExpression(expr)) {
|
517
|
+
const cons = t.isStringLiteral(expr.consequent)
|
518
|
+
? hoistClassName(path, expr.consequent.value)
|
519
|
+
: hoistClassNames(path, expr.consequent)
|
520
|
+
|
521
|
+
const alt = t.isStringLiteral(expr.alternate)
|
522
|
+
? hoistClassName(path, expr.alternate.value)
|
523
|
+
: hoistClassNames(path, expr.alternate)
|
524
|
+
|
525
|
+
return t.conditionalExpression(expr.test, cons, alt)
|
526
|
+
}
|
527
|
+
|
528
|
+
return expr
|
529
|
+
}
|
530
|
+
|
531
|
+
function hoistClassName(path: NodePath<t.JSXElement>, str: string) {
|
532
|
+
const uid = path.scope.generateUidIdentifier('cn')
|
533
|
+
const parent = path.findParent((path) => path.isProgram())
|
534
|
+
if (!parent) throw new Error(`no program?`)
|
535
|
+
const variable = t.variableDeclaration('const', [
|
536
|
+
// adding a space for extra safety
|
537
|
+
t.variableDeclarator(uid, t.stringLiteral(str)),
|
538
|
+
])
|
539
|
+
// @ts-ignore
|
540
|
+
parent.unshiftContainer('body', variable)
|
541
|
+
return uid
|
542
|
+
}
|