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