@tamagui/static 2.7.7 → 3.0.0-beta.643.1
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/cjs/check-dep-versions.cjs +355 -0
- package/dist/cjs/checkDeps.cjs +302 -0
- package/dist/cjs/compiler.cjs +286 -0
- package/dist/cjs/compilerHost.cjs +1695 -0
- package/dist/cjs/constants.cjs +33 -0
- package/dist/cjs/domStructuralPass.cjs +112 -0
- package/dist/cjs/exports.cjs +42 -0
- package/dist/cjs/extractor/addLocalExports.cjs +64 -0
- package/dist/cjs/extractor/bundle.cjs +203 -0
- package/dist/cjs/extractor/bundleConfig.cjs +747 -0
- package/dist/cjs/extractor/concatClassName.cjs +117 -0
- package/dist/cjs/extractor/detectModuleFormat.cjs +54 -0
- package/dist/cjs/extractor/esbuildAliasPlugin.cjs +47 -0
- package/dist/cjs/extractor/esbuildTsconfigPaths.cjs +92 -0
- package/dist/cjs/extractor/getTamaguiConfigPathFromOptionsConfig.cjs +38 -0
- package/dist/cjs/extractor/loadTamagui.cjs +344 -0
- package/dist/cjs/extractor/regenerateConfig.cjs +161 -0
- package/dist/cjs/extractor/watchTamaguiConfig.cjs +64 -0
- package/dist/cjs/getPragmaOptions.cjs +67 -0
- package/dist/cjs/helpers/memoize.cjs +42 -0
- package/dist/cjs/helpers/requireTamaguiCore.cjs +40 -0
- package/dist/cjs/index.cjs +34 -0
- package/dist/cjs/registerRequire.cjs +220 -0
- package/dist/cjs/server.cjs +66 -0
- package/dist/cjs/staticEvaluationIgnoredModules.cjs +86 -0
- package/dist/cjs/types.cjs +17 -0
- package/dist/cjs/zero/artifact.cjs +145 -0
- package/dist/cjs/zero/graph.cjs +209 -0
- package/dist/cjs/zero/identity.cjs +61 -0
- package/dist/cjs/zero/index.cjs +26 -0
- package/dist/cjs/zero/islands.cjs +232 -0
- package/dist/cjs/zero/options.cjs +163 -0
- package/dist/cjs/zero/ownership.cjs +79 -0
- package/dist/cjs/zero/theme.cjs +328 -0
- package/dist/cjs/zero/transform.cjs +203 -0
- package/dist/esm/check-dep-versions.mjs +329 -0
- package/dist/esm/check-dep-versions.mjs.map +1 -0
- package/dist/esm/checkDeps.mjs +279 -0
- package/dist/esm/checkDeps.mjs.map +1 -0
- package/dist/esm/compiler.mjs +255 -0
- package/dist/esm/compiler.mjs.map +1 -0
- package/dist/esm/compilerHost.mjs +1675 -0
- package/dist/esm/compilerHost.mjs.map +1 -0
- package/dist/esm/constants.mjs +7 -0
- package/dist/esm/constants.mjs.map +1 -0
- package/dist/esm/domStructuralPass.mjs +92 -0
- package/dist/esm/domStructuralPass.mjs.map +1 -0
- package/dist/esm/exports.mjs +26 -0
- package/dist/esm/extractor/addLocalExports.mjs +44 -0
- package/dist/esm/extractor/addLocalExports.mjs.map +1 -0
- package/dist/esm/extractor/bundle.mjs +173 -0
- package/dist/esm/extractor/bundle.mjs.map +1 -0
- package/dist/esm/extractor/bundleConfig.mjs +706 -0
- package/dist/esm/extractor/bundleConfig.mjs.map +1 -0
- package/dist/esm/extractor/concatClassName.mjs +96 -0
- package/dist/esm/extractor/concatClassName.mjs.map +1 -0
- package/dist/esm/extractor/detectModuleFormat.mjs +31 -0
- package/dist/esm/extractor/detectModuleFormat.mjs.map +1 -0
- package/dist/esm/extractor/esbuildAliasPlugin.mjs +26 -0
- package/dist/esm/extractor/esbuildAliasPlugin.mjs.map +1 -0
- package/dist/esm/extractor/esbuildTsconfigPaths.mjs +63 -0
- package/dist/esm/extractor/esbuildTsconfigPaths.mjs.map +1 -0
- package/dist/esm/extractor/getTamaguiConfigPathFromOptionsConfig.mjs +18 -0
- package/dist/esm/extractor/getTamaguiConfigPathFromOptionsConfig.mjs.map +1 -0
- package/dist/esm/extractor/loadTamagui.mjs +306 -0
- package/dist/esm/extractor/loadTamagui.mjs.map +1 -0
- package/dist/esm/extractor/regenerateConfig.mjs +131 -0
- package/dist/esm/extractor/regenerateConfig.mjs.map +1 -0
- package/dist/esm/extractor/watchTamaguiConfig.mjs +43 -0
- package/dist/esm/extractor/watchTamaguiConfig.mjs.map +1 -0
- package/dist/esm/getPragmaOptions.mjs +46 -0
- package/dist/esm/getPragmaOptions.mjs.map +1 -0
- package/dist/esm/helpers/memoize.mjs +21 -0
- package/dist/esm/helpers/memoize.mjs.map +1 -0
- package/dist/esm/helpers/requireTamaguiCore.mjs +19 -0
- package/dist/esm/helpers/requireTamaguiCore.mjs.map +1 -0
- package/dist/esm/index.mjs +8 -0
- package/dist/esm/index.mjs.map +1 -0
- package/dist/esm/registerRequire.mjs +195 -0
- package/dist/esm/registerRequire.mjs.map +1 -0
- package/dist/esm/server.mjs +40 -0
- package/dist/esm/server.mjs.map +1 -0
- package/dist/esm/setup.mjs +0 -0
- package/dist/esm/staticEvaluationIgnoredModules.mjs +61 -0
- package/dist/esm/staticEvaluationIgnoredModules.mjs.map +1 -0
- package/dist/esm/types.mjs +0 -0
- package/dist/esm/zero/artifact.mjs +119 -0
- package/dist/esm/zero/artifact.mjs.map +1 -0
- package/dist/esm/zero/graph.mjs +170 -0
- package/dist/esm/zero/graph.mjs.map +1 -0
- package/dist/esm/zero/identity.mjs +36 -0
- package/dist/esm/zero/identity.mjs.map +1 -0
- package/dist/esm/zero/index.mjs +15 -0
- package/dist/esm/zero/islands.mjs +197 -0
- package/dist/esm/zero/islands.mjs.map +1 -0
- package/dist/esm/zero/options.mjs +129 -0
- package/dist/esm/zero/options.mjs.map +1 -0
- package/dist/esm/zero/ownership.mjs +48 -0
- package/dist/esm/zero/ownership.mjs.map +1 -0
- package/dist/esm/zero/theme.mjs +303 -0
- package/dist/esm/zero/theme.mjs.map +1 -0
- package/dist/esm/zero/transform.mjs +177 -0
- package/dist/esm/zero/transform.mjs.map +1 -0
- package/package.json +33 -43
- package/src/check-dep-versions.ts +2 -2
- package/src/checkDeps.ts +3 -2
- package/src/compiler.ts +425 -0
- package/src/compilerHost.ts +3125 -0
- package/src/constants.ts +0 -5
- package/src/domStructuralPass.ts +170 -0
- package/src/exports.ts +3 -6
- package/src/extractor/addLocalExports.ts +49 -0
- package/src/extractor/bundle.ts +20 -35
- package/src/extractor/bundleConfig.ts +334 -187
- package/src/extractor/concatClassName.ts +13 -20
- package/src/extractor/getTamaguiConfigPathFromOptionsConfig.ts +5 -4
- package/src/extractor/loadTamagui.ts +196 -143
- package/src/extractor/regenerateConfig.ts +65 -13
- package/src/extractor/watchTamaguiConfig.ts +6 -1
- package/src/helpers/requireTamaguiCore.ts +6 -1
- package/src/registerRequire.ts +94 -132
- package/src/staticEvaluationIgnoredModules.ts +74 -0
- package/src/types.ts +2 -107
- package/src/zero/artifact.ts +142 -0
- package/src/zero/graph.ts +359 -0
- package/src/zero/identity.ts +73 -0
- package/src/zero/index.ts +8 -0
- package/src/zero/islands.ts +262 -0
- package/src/zero/options.ts +239 -0
- package/src/zero/ownership.ts +113 -0
- package/src/zero/theme.ts +478 -0
- package/src/zero/transform.ts +320 -0
- package/types/check-dep-versions.d.ts.map +1 -1
- package/types/checkDeps.d.ts.map +1 -1
- package/types/compiler.d.ts +117 -0
- package/types/compiler.d.ts.map +1 -0
- package/types/compilerHost.d.ts +25 -0
- package/types/compilerHost.d.ts.map +1 -0
- package/types/constants.d.ts +0 -1
- package/types/constants.d.ts.map +1 -1
- package/types/domStructuralPass.d.ts +3 -0
- package/types/domStructuralPass.d.ts.map +1 -0
- package/types/exports.d.ts +3 -6
- package/types/exports.d.ts.map +1 -1
- package/types/extractor/addLocalExports.d.ts +3 -0
- package/types/extractor/addLocalExports.d.ts.map +1 -0
- package/types/extractor/bundle.d.ts +66 -65
- package/types/extractor/bundle.d.ts.map +1 -1
- package/types/extractor/bundleConfig.d.ts +19 -4
- package/types/extractor/bundleConfig.d.ts.map +1 -1
- package/types/extractor/esbuildAliasPlugin.d.ts.map +1 -1
- package/types/extractor/getTamaguiConfigPathFromOptionsConfig.d.ts +1 -1
- package/types/extractor/getTamaguiConfigPathFromOptionsConfig.d.ts.map +1 -1
- package/types/extractor/loadTamagui.d.ts +26 -3
- package/types/extractor/loadTamagui.d.ts.map +1 -1
- package/types/extractor/regenerateConfig.d.ts +1 -1
- package/types/extractor/regenerateConfig.d.ts.map +1 -1
- package/types/extractor/watchTamaguiConfig.d.ts.map +1 -1
- package/types/getPragmaOptions.d.ts +1 -1
- package/types/helpers/memoize.d.ts +1 -1
- package/types/helpers/memoize.d.ts.map +1 -1
- package/types/helpers/requireTamaguiCore.d.ts.map +1 -1
- package/types/index.d.ts.map +1 -1
- package/types/registerRequire.d.ts +2 -2
- package/types/registerRequire.d.ts.map +1 -1
- package/types/staticEvaluationIgnoredModules.d.ts +9 -0
- package/types/staticEvaluationIgnoredModules.d.ts.map +1 -0
- package/types/types.d.ts +2 -90
- package/types/types.d.ts.map +1 -1
- package/types/zero/artifact.d.ts +44 -0
- package/types/zero/artifact.d.ts.map +1 -0
- package/types/zero/graph.d.ts +139 -0
- package/types/zero/graph.d.ts.map +1 -0
- package/types/zero/identity.d.ts +33 -0
- package/types/zero/identity.d.ts.map +1 -0
- package/types/zero/index.d.ts +9 -0
- package/types/zero/index.d.ts.map +1 -0
- package/types/zero/islands.d.ts +56 -0
- package/types/zero/islands.d.ts.map +1 -0
- package/types/zero/options.d.ts +58 -0
- package/types/zero/options.d.ts.map +1 -0
- package/types/zero/ownership.d.ts +51 -0
- package/types/zero/ownership.d.ts.map +1 -0
- package/types/zero/theme.d.ts +83 -0
- package/types/zero/theme.d.ts.map +1 -0
- package/types/zero/transform.d.ts +53 -0
- package/types/zero/transform.d.ts.map +1 -0
- package/dist/check-dep-versions.cjs +0 -372
- package/dist/checkDeps.cjs +0 -271
- package/dist/constants.cjs +0 -51
- package/dist/exports.cjs +0 -48
- package/dist/extractor/accessSafe.cjs +0 -48
- package/dist/extractor/babelParse.cjs +0 -56
- package/dist/extractor/buildClassName.cjs +0 -86
- package/dist/extractor/bundle.cjs +0 -234
- package/dist/extractor/bundleConfig.cjs +0 -729
- package/dist/extractor/concatClassName.cjs +0 -129
- package/dist/extractor/createEvaluator.cjs +0 -88
- package/dist/extractor/createExtractor.cjs +0 -1968
- package/dist/extractor/createLogger.cjs +0 -50
- package/dist/extractor/detectModuleFormat.cjs +0 -55
- package/dist/extractor/ensureImportingConcat.cjs +0 -54
- package/dist/extractor/errors.cjs +0 -28
- package/dist/extractor/esbuildAliasPlugin.cjs +0 -56
- package/dist/extractor/esbuildTsconfigPaths.cjs +0 -108
- package/dist/extractor/evaluateAstNode.cjs +0 -128
- package/dist/extractor/extractHelpers.cjs +0 -182
- package/dist/extractor/extractMediaStyle.cjs +0 -169
- package/dist/extractor/extractToClassNames.cjs +0 -475
- package/dist/extractor/extractToNative.cjs +0 -369
- package/dist/extractor/findTopmostFunction.cjs +0 -43
- package/dist/extractor/generatedUid.cjs +0 -58
- package/dist/extractor/getPrefixLogs.cjs +0 -31
- package/dist/extractor/getPropValueFromAttributes.cjs +0 -85
- package/dist/extractor/getSourceModule.cjs +0 -100
- package/dist/extractor/getStaticBindingsForScope.cjs +0 -213
- package/dist/extractor/getTamaguiConfigPathFromOptionsConfig.cjs +0 -41
- package/dist/extractor/hasTopLevelAwait.cjs +0 -62
- package/dist/extractor/hoistClassNames.cjs +0 -76
- package/dist/extractor/literalToAst.cjs +0 -109
- package/dist/extractor/loadFile.cjs +0 -17
- package/dist/extractor/loadTamagui.cjs +0 -373
- package/dist/extractor/logLines.cjs +0 -43
- package/dist/extractor/normalizeTernaries.cjs +0 -100
- package/dist/extractor/propsToFontFamilyCache.cjs +0 -42
- package/dist/extractor/regenerateConfig.cjs +0 -178
- package/dist/extractor/removeUnusedHooks.cjs +0 -108
- package/dist/extractor/timer.cjs +0 -52
- package/dist/extractor/validHTMLAttributes.cjs +0 -79
- package/dist/extractor/watchTamaguiConfig.cjs +0 -70
- package/dist/getPragmaOptions.cjs +0 -73
- package/dist/helpers/memoize.cjs +0 -45
- package/dist/helpers/requireTamaguiCore.cjs +0 -40
- package/dist/index.cjs +0 -42
- package/dist/registerRequire.cjs +0 -209
- package/dist/server.cjs +0 -82
- package/dist/types.cjs +0 -18
- package/dist/worker.cjs +0 -111
- package/src/extractor/accessSafe.ts +0 -22
- package/src/extractor/babelParse.ts +0 -38
- package/src/extractor/buildClassName.ts +0 -76
- package/src/extractor/createEvaluator.ts +0 -82
- package/src/extractor/createExtractor.ts +0 -2970
- package/src/extractor/createLogger.ts +0 -41
- package/src/extractor/ensureImportingConcat.ts +0 -36
- package/src/extractor/errors.ts +0 -1
- package/src/extractor/evaluateAstNode.ts +0 -136
- package/src/extractor/extractHelpers.ts +0 -211
- package/src/extractor/extractMediaStyle.ts +0 -194
- package/src/extractor/extractToClassNames.ts +0 -733
- package/src/extractor/extractToNative.ts +0 -506
- package/src/extractor/findTopmostFunction.ts +0 -24
- package/src/extractor/generatedUid.ts +0 -41
- package/src/extractor/getPrefixLogs.ts +0 -9
- package/src/extractor/getPropValueFromAttributes.ts +0 -95
- package/src/extractor/getSourceModule.ts +0 -96
- package/src/extractor/getStaticBindingsForScope.ts +0 -237
- package/src/extractor/hasTopLevelAwait.ts +0 -28
- package/src/extractor/hoistClassNames.ts +0 -52
- package/src/extractor/literalToAst.ts +0 -85
- package/src/extractor/loadFile.ts +0 -17
- package/src/extractor/logLines.ts +0 -16
- package/src/extractor/normalizeTernaries.ts +0 -89
- package/src/extractor/propsToFontFamilyCache.ts +0 -18
- package/src/extractor/removeUnusedHooks.ts +0 -83
- package/src/extractor/timer.ts +0 -25
- package/src/extractor/validHTMLAttributes.ts +0 -52
- package/src/worker.ts +0 -142
- package/types/extractor/accessSafe.d.ts +0 -3
- package/types/extractor/accessSafe.d.ts.map +0 -1
- package/types/extractor/babelParse.d.ts +0 -5
- package/types/extractor/babelParse.d.ts.map +0 -1
- package/types/extractor/buildClassName.d.ts +0 -7
- package/types/extractor/buildClassName.d.ts.map +0 -1
- package/types/extractor/createEvaluator.d.ts +0 -12
- package/types/extractor/createEvaluator.d.ts.map +0 -1
- package/types/extractor/createExtractor.d.ts +0 -32
- package/types/extractor/createExtractor.d.ts.map +0 -1
- package/types/extractor/createLogger.d.ts +0 -3
- package/types/extractor/createLogger.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/errors.d.ts +0 -3
- package/types/extractor/errors.d.ts.map +0 -1
- package/types/extractor/evaluateAstNode.d.ts +0 -3
- package/types/extractor/evaluateAstNode.d.ts.map +0 -1
- package/types/extractor/extractHelpers.d.ts +0 -28
- package/types/extractor/extractHelpers.d.ts.map +0 -1
- package/types/extractor/extractMediaStyle.d.ts +0 -11
- package/types/extractor/extractMediaStyle.d.ts.map +0 -1
- package/types/extractor/extractToClassNames.d.ts +0 -25
- package/types/extractor/extractToClassNames.d.ts.map +0 -1
- package/types/extractor/extractToNative.d.ts +0 -13
- package/types/extractor/extractToNative.d.ts.map +0 -1
- package/types/extractor/findTopmostFunction.d.ts +0 -4
- package/types/extractor/findTopmostFunction.d.ts.map +0 -1
- package/types/extractor/generatedUid.d.ts +0 -5
- package/types/extractor/generatedUid.d.ts.map +0 -1
- package/types/extractor/getPrefixLogs.d.ts +0 -3
- package/types/extractor/getPrefixLogs.d.ts.map +0 -1
- package/types/extractor/getPropValueFromAttributes.d.ts +0 -19
- package/types/extractor/getPropValueFromAttributes.d.ts.map +0 -1
- package/types/extractor/getSourceModule.d.ts +0 -16
- package/types/extractor/getSourceModule.d.ts.map +0 -1
- package/types/extractor/getStaticBindingsForScope.d.ts +0 -5
- package/types/extractor/getStaticBindingsForScope.d.ts.map +0 -1
- package/types/extractor/hasTopLevelAwait.d.ts +0 -2
- package/types/extractor/hasTopLevelAwait.d.ts.map +0 -1
- package/types/extractor/hoistClassNames.d.ts +0 -6
- package/types/extractor/hoistClassNames.d.ts.map +0 -1
- package/types/extractor/literalToAst.d.ts +0 -4
- package/types/extractor/literalToAst.d.ts.map +0 -1
- package/types/extractor/loadFile.d.ts +0 -1
- package/types/extractor/loadFile.d.ts.map +0 -1
- package/types/extractor/logLines.d.ts +0 -2
- package/types/extractor/logLines.d.ts.map +0 -1
- package/types/extractor/normalizeTernaries.d.ts +0 -5
- package/types/extractor/normalizeTernaries.d.ts.map +0 -1
- package/types/extractor/propsToFontFamilyCache.d.ts +0 -4
- package/types/extractor/propsToFontFamilyCache.d.ts.map +0 -1
- package/types/extractor/removeUnusedHooks.d.ts +0 -3
- package/types/extractor/removeUnusedHooks.d.ts.map +0 -1
- package/types/extractor/timer.d.ts +0 -5
- package/types/extractor/timer.d.ts.map +0 -1
- package/types/extractor/validHTMLAttributes.d.ts +0 -52
- package/types/extractor/validHTMLAttributes.d.ts.map +0 -1
- package/types/worker.d.ts +0 -46
- package/types/worker.d.ts.map +0 -1
- /package/dist/{setup.cjs → cjs/setup.cjs} +0 -0
|
@@ -1,2970 +0,0 @@
|
|
|
1
|
-
import type { NodePath, TraverseOptions } from '@babel/traverse'
|
|
2
|
-
import traverse from '@babel/traverse'
|
|
3
|
-
import * as t from '@babel/types'
|
|
4
|
-
import { Color, colorLog } from '@tamagui/cli-color'
|
|
5
|
-
import * as reactNativeWebInternals from '@tamagui/react-native-web-internals'
|
|
6
|
-
import {
|
|
7
|
-
StyleObjectIdentifier,
|
|
8
|
-
StyleObjectRules,
|
|
9
|
-
type GetStyleState,
|
|
10
|
-
type PseudoStyles,
|
|
11
|
-
type SplitStyleProps,
|
|
12
|
-
type StaticConfig,
|
|
13
|
-
type TamaguiComponentState,
|
|
14
|
-
} from '@tamagui/web'
|
|
15
|
-
import { existsSync, readFileSync } from 'node:fs'
|
|
16
|
-
import { basename, dirname, resolve, relative } from 'node:path'
|
|
17
|
-
import { nodeModuleNameResolver, sys } from 'typescript'
|
|
18
|
-
import type { ViewStyle } from 'react-native'
|
|
19
|
-
|
|
20
|
-
import { FAILED_EVAL } from '../constants'
|
|
21
|
-
import { requireTamaguiCore } from '../helpers/requireTamaguiCore'
|
|
22
|
-
import type {
|
|
23
|
-
ExtractedAttr,
|
|
24
|
-
ExtractedAttrStyle,
|
|
25
|
-
ExtractorOptions,
|
|
26
|
-
ExtractorParseProps,
|
|
27
|
-
TamaguiOptions,
|
|
28
|
-
TamaguiOptionsWithFileInfo,
|
|
29
|
-
Ternary,
|
|
30
|
-
} from '../types'
|
|
31
|
-
import type { LoadedComponents, TamaguiProjectInfo } from './bundleConfig'
|
|
32
|
-
import { createEvaluator, createSafeEvaluator } from './createEvaluator'
|
|
33
|
-
import { evaluateAstNode } from './evaluateAstNode'
|
|
34
|
-
import {
|
|
35
|
-
attrStr,
|
|
36
|
-
findComponentName,
|
|
37
|
-
getValidComponent,
|
|
38
|
-
getValidComponentsPaths,
|
|
39
|
-
getValidImport,
|
|
40
|
-
isPresent,
|
|
41
|
-
isValidImport,
|
|
42
|
-
objToStr,
|
|
43
|
-
} from './extractHelpers'
|
|
44
|
-
import { findTopmostFunction } from './findTopmostFunction'
|
|
45
|
-
import { cleanupBeforeExit, getStaticBindingsForScope } from './getStaticBindingsForScope'
|
|
46
|
-
import { literalToAst } from './literalToAst'
|
|
47
|
-
import { loadTamagui, loadTamaguiSync } from './loadTamagui'
|
|
48
|
-
import { logLines } from './logLines'
|
|
49
|
-
import { getTernaryKey, normalizeTernaries } from './normalizeTernaries'
|
|
50
|
-
import { setPropsToFontFamily } from './propsToFontFamilyCache'
|
|
51
|
-
import { timer } from './timer'
|
|
52
|
-
import { validHTMLAttributes } from './validHTMLAttributes'
|
|
53
|
-
import { BailOptimizationError } from './errors'
|
|
54
|
-
import { loadCompilerOptionsFromTsconfig } from './esbuildTsconfigPaths'
|
|
55
|
-
|
|
56
|
-
const UNTOUCHED_PROPS = {
|
|
57
|
-
key: true,
|
|
58
|
-
style: true,
|
|
59
|
-
className: true,
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Platform variants that can't be resolved at compile time on native builds.
|
|
63
|
-
// Defined at module level (not inside the loop) to avoid repeated Set allocations during compilation.
|
|
64
|
-
// (requires runtime Platform.OS + Platform.isTV checks via react-native-tvos)
|
|
65
|
-
const nativeOnlyPlatforms = new Set(['android', 'ios', 'tv', 'androidtv', 'tvos'])
|
|
66
|
-
|
|
67
|
-
const createTernary = (x: Ternary) => x
|
|
68
|
-
|
|
69
|
-
export type Extractor = ReturnType<typeof createExtractor>
|
|
70
|
-
|
|
71
|
-
type FileOrPath = NodePath<t.Program> | t.File
|
|
72
|
-
|
|
73
|
-
let hasLoggedBaseInfo = false
|
|
74
|
-
|
|
75
|
-
function isFullyDisabled(props: TamaguiOptions) {
|
|
76
|
-
return props.disableExtraction && props.disableDebugAttr
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// Walk up JSX ancestors looking for one that declares `group="<groupName>"` together
|
|
80
|
-
// with the `untilMeasured` prop. Used to deopt children whose styles depend on a
|
|
81
|
-
// parent that the runtime measures before emitting child styles (can't be modeled
|
|
82
|
-
// in static CSS).
|
|
83
|
-
function hasUntilMeasuredAncestor(path: NodePath<any>, groupName: string): boolean {
|
|
84
|
-
let current: NodePath<any> | null = path.parentPath
|
|
85
|
-
while (current) {
|
|
86
|
-
if (current.isJSXElement()) {
|
|
87
|
-
const opening = current.node.openingElement
|
|
88
|
-
let foundGroup = false
|
|
89
|
-
let foundUntilMeasured = false
|
|
90
|
-
for (const attr of opening.attributes) {
|
|
91
|
-
if (!t.isJSXAttribute(attr)) continue
|
|
92
|
-
if (!t.isJSXIdentifier(attr.name)) continue
|
|
93
|
-
const aName = attr.name.name
|
|
94
|
-
if (aName === 'group') {
|
|
95
|
-
// only literal string equality counts — dynamic group= is left to runtime
|
|
96
|
-
if (t.isStringLiteral(attr.value) && attr.value.value === groupName) {
|
|
97
|
-
foundGroup = true
|
|
98
|
-
} else if (
|
|
99
|
-
t.isJSXExpressionContainer(attr.value) &&
|
|
100
|
-
t.isStringLiteral(attr.value.expression) &&
|
|
101
|
-
attr.value.expression.value === groupName
|
|
102
|
-
) {
|
|
103
|
-
foundGroup = true
|
|
104
|
-
}
|
|
105
|
-
} else if (aName === 'untilMeasured') {
|
|
106
|
-
foundUntilMeasured = true
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
if (foundGroup && foundUntilMeasured) return true
|
|
110
|
-
}
|
|
111
|
-
current = current.parentPath
|
|
112
|
-
}
|
|
113
|
-
return false
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
export function createExtractor(
|
|
117
|
-
{ logger = console, platform = 'web' }: ExtractorOptions = { logger: console }
|
|
118
|
-
) {
|
|
119
|
-
const INLINE_EXTRACTABLE = {
|
|
120
|
-
ref: 'ref',
|
|
121
|
-
key: 'key',
|
|
122
|
-
...(platform === 'web' && {
|
|
123
|
-
onPress: 'onClick',
|
|
124
|
-
onHoverIn: 'onMouseEnter',
|
|
125
|
-
onHoverOut: 'onMouseLeave',
|
|
126
|
-
onPressIn: 'onMouseDown',
|
|
127
|
-
onPressOut: 'onMouseUp',
|
|
128
|
-
}),
|
|
129
|
-
...(platform === 'native' && {
|
|
130
|
-
// native view props that should pass through without preventing flattening
|
|
131
|
-
testID: 'testID',
|
|
132
|
-
nativeID: 'nativeID',
|
|
133
|
-
accessibilityLabel: 'accessibilityLabel',
|
|
134
|
-
accessibilityHint: 'accessibilityHint',
|
|
135
|
-
accessibilityRole: 'accessibilityRole',
|
|
136
|
-
accessibilityState: 'accessibilityState',
|
|
137
|
-
accessibilityValue: 'accessibilityValue',
|
|
138
|
-
accessibilityActions: 'accessibilityActions',
|
|
139
|
-
accessibilityLabelledBy: 'accessibilityLabelledBy',
|
|
140
|
-
accessibilityLiveRegion: 'accessibilityLiveRegion',
|
|
141
|
-
accessibilityElementsHidden: 'accessibilityElementsHidden',
|
|
142
|
-
accessibilityViewIsModal: 'accessibilityViewIsModal',
|
|
143
|
-
importantForAccessibility: 'importantForAccessibility',
|
|
144
|
-
collapsable: 'collapsable',
|
|
145
|
-
needsOffscreenAlphaCompositing: 'needsOffscreenAlphaCompositing',
|
|
146
|
-
removeClippedSubviews: 'removeClippedSubviews',
|
|
147
|
-
renderToHardwareTextureAndroid: 'renderToHardwareTextureAndroid',
|
|
148
|
-
shouldRasterizeIOS: 'shouldRasterizeIOS',
|
|
149
|
-
hitSlop: 'hitSlop',
|
|
150
|
-
pointerEvents: 'pointerEvents',
|
|
151
|
-
}),
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
const componentState: TamaguiComponentState = {
|
|
155
|
-
focus: false,
|
|
156
|
-
focusVisible: false,
|
|
157
|
-
focusWithin: false,
|
|
158
|
-
hover: false,
|
|
159
|
-
unmounted: true,
|
|
160
|
-
press: false,
|
|
161
|
-
pressIn: false,
|
|
162
|
-
disabled: false,
|
|
163
|
-
} as const
|
|
164
|
-
|
|
165
|
-
const styleProps: SplitStyleProps = {
|
|
166
|
-
resolveValues: platform === 'native' ? 'value' : 'variable',
|
|
167
|
-
noClass: false,
|
|
168
|
-
isAnimated: false,
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
const shouldAddDebugProp =
|
|
172
|
-
// really basic disable this for next.js because it messes with ssr
|
|
173
|
-
!process.env.npm_package_dependencies_next &&
|
|
174
|
-
platform !== 'native' &&
|
|
175
|
-
process.env.IDENTIFY_TAGS !== 'false' &&
|
|
176
|
-
(process.env.NODE_ENV === 'development' || process.env.IDENTIFY_TAGS)
|
|
177
|
-
|
|
178
|
-
let projectInfo: TamaguiProjectInfo | null = null
|
|
179
|
-
|
|
180
|
-
// cache of dynamically discovered styled components, keyed by absolute file path
|
|
181
|
-
// persists across files within the same worker/extractor instance
|
|
182
|
-
const dynamicComponentCache = new Map<string, LoadedComponents>()
|
|
183
|
-
const dynamicLoadingInProgress = new Set<string>()
|
|
184
|
-
|
|
185
|
-
// lazily loaded tsconfig compiler options for path alias resolution
|
|
186
|
-
let _compilerOptions: any = null
|
|
187
|
-
function getCompilerOptions() {
|
|
188
|
-
if (!_compilerOptions) {
|
|
189
|
-
try {
|
|
190
|
-
_compilerOptions = loadCompilerOptionsFromTsconfig()
|
|
191
|
-
} catch {
|
|
192
|
-
_compilerOptions = {}
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
return _compilerOptions
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
function resolveImportPath(fromFile: string, importPath: string): string | null {
|
|
199
|
-
if (importPath.startsWith('.')) {
|
|
200
|
-
// relative path resolution
|
|
201
|
-
const dir = dirname(fromFile)
|
|
202
|
-
const base = resolve(dir, importPath)
|
|
203
|
-
const extensions = ['.tsx', '.ts', '.jsx', '.js']
|
|
204
|
-
for (const ext of extensions) {
|
|
205
|
-
const full = base + ext
|
|
206
|
-
if (existsSync(full)) return full
|
|
207
|
-
}
|
|
208
|
-
// try index files
|
|
209
|
-
for (const ext of extensions) {
|
|
210
|
-
const full = resolve(base, `index${ext}`)
|
|
211
|
-
if (existsSync(full)) return full
|
|
212
|
-
}
|
|
213
|
-
return null
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
// tsconfig path alias resolution (e.g. ~/foo, @/bar)
|
|
217
|
-
const compilerOptions = getCompilerOptions()
|
|
218
|
-
if (compilerOptions.paths) {
|
|
219
|
-
try {
|
|
220
|
-
const { resolvedModule } = nodeModuleNameResolver(
|
|
221
|
-
importPath,
|
|
222
|
-
fromFile,
|
|
223
|
-
compilerOptions,
|
|
224
|
-
sys
|
|
225
|
-
)
|
|
226
|
-
if (
|
|
227
|
-
resolvedModule &&
|
|
228
|
-
!resolvedModule.resolvedFileName.endsWith('.d.ts') &&
|
|
229
|
-
!resolvedModule.isExternalLibraryImport
|
|
230
|
-
) {
|
|
231
|
-
return resolvedModule.resolvedFileName
|
|
232
|
-
}
|
|
233
|
-
} catch {
|
|
234
|
-
// fallback - tsconfig resolution failed
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
return null
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
const styledCheckCache = new Map<string, boolean>()
|
|
242
|
-
|
|
243
|
-
function mightHaveStyledComponents(filePath: string): boolean {
|
|
244
|
-
const cached = styledCheckCache.get(filePath)
|
|
245
|
-
if (cached !== undefined) return cached
|
|
246
|
-
try {
|
|
247
|
-
const content = readFileSync(filePath, 'utf-8')
|
|
248
|
-
const result = content.includes('styled(')
|
|
249
|
-
styledCheckCache.set(filePath, result)
|
|
250
|
-
return result
|
|
251
|
-
} catch {
|
|
252
|
-
styledCheckCache.set(filePath, false)
|
|
253
|
-
return false
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
// we load tamagui delayed because we need to set some global/env stuff before importing
|
|
258
|
-
// otherwise we'd import `rnw` and cause it to evaluate react-native-web which causes errors
|
|
259
|
-
|
|
260
|
-
function loadSync(props: TamaguiOptions) {
|
|
261
|
-
if (isFullyDisabled(props)) {
|
|
262
|
-
return null
|
|
263
|
-
}
|
|
264
|
-
return (projectInfo ||= loadTamaguiSync(props))
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
async function load(props: TamaguiOptions) {
|
|
268
|
-
if (isFullyDisabled(props)) {
|
|
269
|
-
return null
|
|
270
|
-
}
|
|
271
|
-
return (projectInfo ||= await loadTamagui(props))
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
return {
|
|
275
|
-
options: {
|
|
276
|
-
logger,
|
|
277
|
-
},
|
|
278
|
-
cleanupBeforeExit,
|
|
279
|
-
loadTamagui: load,
|
|
280
|
-
loadTamaguiSync: loadSync,
|
|
281
|
-
getTamagui() {
|
|
282
|
-
return projectInfo?.tamaguiConfig
|
|
283
|
-
},
|
|
284
|
-
parseSync: (f: FileOrPath, props: ExtractorParseProps) => {
|
|
285
|
-
globalThis.expo ||= {} // expo-modules-core checks this and avoids loading "native" modules if exists
|
|
286
|
-
const projectInfo = loadSync(props)
|
|
287
|
-
return parseWithConfig(projectInfo || {}, f, props)
|
|
288
|
-
},
|
|
289
|
-
parse: async (f: FileOrPath, props: ExtractorParseProps) => {
|
|
290
|
-
globalThis.expo ||= {} // expo-modules-core checks this and avoids loading "native" modules if exists
|
|
291
|
-
const projectInfo = await load(props)
|
|
292
|
-
return parseWithConfig(projectInfo || {}, f, props)
|
|
293
|
-
},
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
function parseWithConfig(
|
|
297
|
-
{ components, tamaguiConfig }: TamaguiProjectInfo,
|
|
298
|
-
fileOrPath: FileOrPath,
|
|
299
|
-
options: ExtractorParseProps
|
|
300
|
-
) {
|
|
301
|
-
const {
|
|
302
|
-
config = 'tamagui.config.ts',
|
|
303
|
-
importsWhitelist = ['constants.js'],
|
|
304
|
-
evaluateVars = true,
|
|
305
|
-
sourcePath = '',
|
|
306
|
-
onExtractTag,
|
|
307
|
-
onStyledDefinitionRule,
|
|
308
|
-
getFlattenedNode,
|
|
309
|
-
disable,
|
|
310
|
-
disableExtraction,
|
|
311
|
-
disableExtractVariables,
|
|
312
|
-
disableDebugAttr,
|
|
313
|
-
enableDynamicEvaluation = false,
|
|
314
|
-
includeExtensions = ['.ts', '.tsx', '.jsx'],
|
|
315
|
-
extractStyledDefinitions = false,
|
|
316
|
-
prefixLogs,
|
|
317
|
-
excludeProps,
|
|
318
|
-
platform,
|
|
319
|
-
...restProps
|
|
320
|
-
} = options
|
|
321
|
-
|
|
322
|
-
// invalidate dynamic cache for this file on re-parse (HMR)
|
|
323
|
-
if (sourcePath && dynamicComponentCache.has(sourcePath)) {
|
|
324
|
-
dynamicComponentCache.delete(sourcePath)
|
|
325
|
-
styledCheckCache.delete(sourcePath)
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
if (sourcePath.includes('.tamagui-dynamic-eval')) {
|
|
329
|
-
return null
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
const {
|
|
333
|
-
normalizeStyle,
|
|
334
|
-
getSplitStyles,
|
|
335
|
-
mediaQueryConfig,
|
|
336
|
-
propMapper,
|
|
337
|
-
proxyThemeVariables,
|
|
338
|
-
getDefaultProps,
|
|
339
|
-
pseudoDescriptors,
|
|
340
|
-
} = requireTamaguiCore(platform)
|
|
341
|
-
|
|
342
|
-
let shouldPrintDebug = options.shouldPrintDebug || false
|
|
343
|
-
|
|
344
|
-
if (disable === true || (Array.isArray(disable) && disable.includes(sourcePath))) {
|
|
345
|
-
return null
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
if (!isFullyDisabled(options)) {
|
|
349
|
-
if (!components) {
|
|
350
|
-
throw new Error(`Must provide components`)
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
if (
|
|
355
|
-
sourcePath &&
|
|
356
|
-
includeExtensions &&
|
|
357
|
-
!includeExtensions.some((ext) => sourcePath.endsWith(ext))
|
|
358
|
-
) {
|
|
359
|
-
if (shouldPrintDebug) {
|
|
360
|
-
logger.info(
|
|
361
|
-
`Ignoring file due to includeExtensions: ${sourcePath}, includeExtensions: ${includeExtensions.join(
|
|
362
|
-
', '
|
|
363
|
-
)}`
|
|
364
|
-
)
|
|
365
|
-
}
|
|
366
|
-
return null
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
function isValidStyleKey(name: string, staticConfig: StaticConfig) {
|
|
370
|
-
if (!projectInfo) {
|
|
371
|
-
throw new Error(`Tamagui extractor not loaded yet`)
|
|
372
|
-
}
|
|
373
|
-
if (platform === 'native' && name[0] === '$' && mediaQueryConfig[name.slice(1)]) {
|
|
374
|
-
return false
|
|
375
|
-
}
|
|
376
|
-
// Check for $theme-, $platform-, $group- prefixed keys
|
|
377
|
-
if (name[0] === '$') {
|
|
378
|
-
const mediaName = name.slice(1)
|
|
379
|
-
if (
|
|
380
|
-
mediaName.startsWith('theme-') ||
|
|
381
|
-
mediaName.startsWith('platform-') ||
|
|
382
|
-
mediaName.startsWith('group-')
|
|
383
|
-
) {
|
|
384
|
-
return true
|
|
385
|
-
}
|
|
386
|
-
if (mediaQueryConfig[mediaName]) {
|
|
387
|
-
return true
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
return !!(
|
|
391
|
-
staticConfig.validStyles?.[name] ||
|
|
392
|
-
pseudoDescriptors[name] ||
|
|
393
|
-
// don't disable variants or else you lose many things flattening
|
|
394
|
-
staticConfig.variants?.[name] ||
|
|
395
|
-
projectInfo?.tamaguiConfig?.shorthands[name]
|
|
396
|
-
)
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
function getGroupPseudo(name: string) {
|
|
400
|
-
const [_, groupName, a, b, c] = name.split('-')
|
|
401
|
-
if (!groupName) return
|
|
402
|
-
const m2 = a && b ? `${a}-${b}` : ''
|
|
403
|
-
const media = (m2 && mediaQueryConfig[m2] && m2) || (a && mediaQueryConfig[a] && a)
|
|
404
|
-
return media
|
|
405
|
-
? media === m2
|
|
406
|
-
? c
|
|
407
|
-
: b
|
|
408
|
-
? `${b}${c ? `-${c}` : ''}`
|
|
409
|
-
: undefined
|
|
410
|
-
: a
|
|
411
|
-
? `${a}${b ? `-${b}` : ''}${c ? `-${c}` : ''}`
|
|
412
|
-
: undefined
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
/**
|
|
416
|
-
* Step 1: Determine if importing any statically extractable components
|
|
417
|
-
*/
|
|
418
|
-
|
|
419
|
-
const isTargetingHTML = platform === 'web'
|
|
420
|
-
const ogDebug = shouldPrintDebug
|
|
421
|
-
const tm = timer()
|
|
422
|
-
const propsWithFileInfo: TamaguiOptionsWithFileInfo = {
|
|
423
|
-
...options,
|
|
424
|
-
sourcePath,
|
|
425
|
-
allLoadedComponents: components ? [...components] : [],
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
if (!hasLoggedBaseInfo) {
|
|
429
|
-
hasLoggedBaseInfo = true
|
|
430
|
-
if (shouldPrintDebug) {
|
|
431
|
-
logger.info(
|
|
432
|
-
[
|
|
433
|
-
'loaded components:',
|
|
434
|
-
propsWithFileInfo.allLoadedComponents
|
|
435
|
-
.map((comp) => Object.keys(comp.nameToInfo).join(', '))
|
|
436
|
-
.join(', '),
|
|
437
|
-
].join(' ')
|
|
438
|
-
)
|
|
439
|
-
}
|
|
440
|
-
if (process.env.DEBUG?.startsWith('tamagui')) {
|
|
441
|
-
logger.info(
|
|
442
|
-
[
|
|
443
|
-
'loaded:',
|
|
444
|
-
propsWithFileInfo.allLoadedComponents.map((x) => x.moduleName),
|
|
445
|
-
].join('\n')
|
|
446
|
-
)
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
tm.mark('load-tamagui', !!shouldPrintDebug)
|
|
451
|
-
|
|
452
|
-
if (!isFullyDisabled(options)) {
|
|
453
|
-
if (!tamaguiConfig?.themes) {
|
|
454
|
-
console.error(
|
|
455
|
-
`⛔️ Error: Missing "themes" in your tamagui.config file:
|
|
456
|
-
|
|
457
|
-
You may not need the compiler! Remember you can run Tamagui with no configuration at all.
|
|
458
|
-
|
|
459
|
-
You may have not "export default" your config (you can also "export const config").
|
|
460
|
-
|
|
461
|
-
Or this may be due to duplicated dependency versions:
|
|
462
|
-
- try out https://github.com/bmish/check-dependency-version-consistency to see if there are mis-matches.
|
|
463
|
-
- or search your lockfile for mis-matches.
|
|
464
|
-
`
|
|
465
|
-
)
|
|
466
|
-
console.info(` Got config:`, tamaguiConfig)
|
|
467
|
-
process.exit(0)
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
const firstThemeName = Object.keys(tamaguiConfig?.themes || {})[0]
|
|
472
|
-
const firstTheme = tamaguiConfig?.themes[firstThemeName] || {}
|
|
473
|
-
|
|
474
|
-
if (!firstTheme || typeof firstTheme !== 'object') {
|
|
475
|
-
const err = `Missing theme ${firstThemeName}, an error occurred when importing your config`
|
|
476
|
-
console.info(err, `Got config:`, tamaguiConfig)
|
|
477
|
-
console.info(`Looking for theme:`, firstThemeName)
|
|
478
|
-
throw new Error(err)
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
const proxiedTheme = proxyThemeVariables(firstTheme)
|
|
482
|
-
type AccessListener = (key: string) => void
|
|
483
|
-
const themeAccessListeners = new Set<AccessListener>()
|
|
484
|
-
const defaultTheme = new Proxy(proxiedTheme, {
|
|
485
|
-
get(target, key) {
|
|
486
|
-
if (Reflect.has(target, key)) {
|
|
487
|
-
themeAccessListeners.forEach((cb) => cb(String(key)))
|
|
488
|
-
}
|
|
489
|
-
return Reflect.get(target, key)
|
|
490
|
-
},
|
|
491
|
-
})
|
|
492
|
-
|
|
493
|
-
const body: t.Statement[] | NodePath<t.Statement>[] =
|
|
494
|
-
fileOrPath.type === 'Program' ? fileOrPath.get('body') : fileOrPath.program.body
|
|
495
|
-
|
|
496
|
-
if (!isFullyDisabled(options)) {
|
|
497
|
-
if (Object.keys(components || []).length === 0) {
|
|
498
|
-
console.warn(
|
|
499
|
-
`Warning: Tamagui didn't find any valid components (DEBUG=tamagui for more)`
|
|
500
|
-
)
|
|
501
|
-
if (process.env.DEBUG === 'tamagui') {
|
|
502
|
-
console.info(`components`, Object.keys(components || []), components)
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
if (shouldPrintDebug === 'verbose') {
|
|
508
|
-
logger.info(
|
|
509
|
-
`allLoadedComponent modules ${propsWithFileInfo.allLoadedComponents
|
|
510
|
-
.map((k) => k.moduleName)
|
|
511
|
-
.join(', ')}`
|
|
512
|
-
)
|
|
513
|
-
logger.info(
|
|
514
|
-
`valid import paths: ${JSON.stringify(
|
|
515
|
-
getValidComponentsPaths(propsWithFileInfo)
|
|
516
|
-
)}`
|
|
517
|
-
)
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
let doesUseValidImport = false
|
|
521
|
-
let hasImportedTheme = false
|
|
522
|
-
|
|
523
|
-
const importDeclarations: t.ImportDeclaration[] = []
|
|
524
|
-
|
|
525
|
-
for (const bodyPath of body) {
|
|
526
|
-
if (bodyPath.type !== 'ImportDeclaration') continue
|
|
527
|
-
const node = ('node' in bodyPath ? bodyPath.node : bodyPath) as t.ImportDeclaration
|
|
528
|
-
const moduleName = node.source.value
|
|
529
|
-
|
|
530
|
-
// if importing valid module
|
|
531
|
-
const valid = isValidImport(propsWithFileInfo, moduleName)
|
|
532
|
-
|
|
533
|
-
if (valid) {
|
|
534
|
-
importDeclarations.push(node)
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
if (shouldPrintDebug === 'verbose') {
|
|
538
|
-
logger.info(` - import via ${moduleName} ${valid}`)
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
if (extractStyledDefinitions && enableDynamicEvaluation) {
|
|
542
|
-
// check all imports for `styled`, not just valid packages
|
|
543
|
-
// styled( is basically guaranteed to be tamagui regardless of source
|
|
544
|
-
if (node.specifiers.some((specifier) => specifier.local.name === 'styled')) {
|
|
545
|
-
doesUseValidImport = true
|
|
546
|
-
// don't break - need to collect all import declarations for the styled() handler
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
if (valid) {
|
|
551
|
-
const names = node.specifiers.map((specifier) => specifier.local.name)
|
|
552
|
-
const isValidComponent = names.some((name) =>
|
|
553
|
-
Boolean(isValidImport(propsWithFileInfo, moduleName, name))
|
|
554
|
-
)
|
|
555
|
-
if (shouldPrintDebug === 'verbose') {
|
|
556
|
-
logger.info(
|
|
557
|
-
` - import ${isValidComponent ? '✅' : '⇣'} - ${names.join(
|
|
558
|
-
', '
|
|
559
|
-
)} via package '${moduleName}' - (valid: ${JSON.stringify(
|
|
560
|
-
getValidComponentsPaths(propsWithFileInfo)
|
|
561
|
-
)})`
|
|
562
|
-
)
|
|
563
|
-
}
|
|
564
|
-
if (isValidComponent) {
|
|
565
|
-
doesUseValidImport = true
|
|
566
|
-
if (!(extractStyledDefinitions && enableDynamicEvaluation)) break
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
if (shouldPrintDebug) {
|
|
572
|
-
logger.info(
|
|
573
|
-
`${JSON.stringify({ doesUseValidImport, hasImportedTheme }, null, 2)}\n`
|
|
574
|
-
)
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
if (
|
|
578
|
-
!doesUseValidImport &&
|
|
579
|
-
extractStyledDefinitions &&
|
|
580
|
-
enableDynamicEvaluation &&
|
|
581
|
-
sourcePath
|
|
582
|
-
) {
|
|
583
|
-
// check if any local import is in the dynamic cache or has styled components
|
|
584
|
-
for (const bodyPath of body) {
|
|
585
|
-
if (bodyPath.type !== 'ImportDeclaration') continue
|
|
586
|
-
const node = (
|
|
587
|
-
'node' in bodyPath ? bodyPath.node : bodyPath
|
|
588
|
-
) as t.ImportDeclaration
|
|
589
|
-
const moduleName = node.source.value
|
|
590
|
-
|
|
591
|
-
const resolved = resolveImportPath(sourcePath, moduleName)
|
|
592
|
-
if (!resolved) continue
|
|
593
|
-
|
|
594
|
-
if (dynamicComponentCache.has(resolved)) {
|
|
595
|
-
doesUseValidImport = true
|
|
596
|
-
break
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
if (mightHaveStyledComponents(resolved)) {
|
|
600
|
-
doesUseValidImport = true
|
|
601
|
-
break
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
if (!doesUseValidImport) {
|
|
607
|
-
return null
|
|
608
|
-
}
|
|
609
|
-
|
|
610
|
-
function getValidImportedComponent(componentName: string) {
|
|
611
|
-
const importDeclaration = importDeclarations.find((dec) =>
|
|
612
|
-
dec.specifiers.some((spec) => spec.local.name === componentName)
|
|
613
|
-
)
|
|
614
|
-
if (!importDeclaration) {
|
|
615
|
-
return null
|
|
616
|
-
}
|
|
617
|
-
return getValidImport(
|
|
618
|
-
propsWithFileInfo,
|
|
619
|
-
importDeclaration.source.value,
|
|
620
|
-
componentName
|
|
621
|
-
)
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
tm.mark('import-check', !!shouldPrintDebug)
|
|
625
|
-
|
|
626
|
-
let couldntParse = false
|
|
627
|
-
// evaluating the file resolves every styled() in it at once, so once is enough
|
|
628
|
-
let didDynamicLoad = false
|
|
629
|
-
const modifiedComponents = new Set<NodePath<any>>()
|
|
630
|
-
|
|
631
|
-
// only keeping a cache around per-file, reset it if it changes
|
|
632
|
-
const bindingCache: Record<string, string | null> = {}
|
|
633
|
-
|
|
634
|
-
const callTraverse = (a: TraverseOptions<any>) => {
|
|
635
|
-
// @ts-ignore
|
|
636
|
-
return fileOrPath.type === 'File' ? traverse(fileOrPath, a) : fileOrPath.traverse(a)
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
const shouldDisableExtraction =
|
|
640
|
-
disableExtraction === true ||
|
|
641
|
-
(Array.isArray(disableExtraction) && disableExtraction.includes(sourcePath))
|
|
642
|
-
|
|
643
|
-
/**
|
|
644
|
-
* Step 2: Statically extract from JSX < /> nodes
|
|
645
|
-
*/
|
|
646
|
-
let programPath: NodePath<t.Program> | null = null
|
|
647
|
-
|
|
648
|
-
const res = {
|
|
649
|
-
styled: 0,
|
|
650
|
-
flattened: 0,
|
|
651
|
-
optimized: 0,
|
|
652
|
-
modified: 0,
|
|
653
|
-
found: 0,
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
const version = `${Math.random()}`
|
|
657
|
-
|
|
658
|
-
callTraverse({
|
|
659
|
-
// @ts-ignore
|
|
660
|
-
Program: {
|
|
661
|
-
enter(path) {
|
|
662
|
-
programPath = path
|
|
663
|
-
},
|
|
664
|
-
},
|
|
665
|
-
|
|
666
|
-
// styled() calls
|
|
667
|
-
CallExpression(path) {
|
|
668
|
-
if (disable || shouldDisableExtraction || extractStyledDefinitions === false) {
|
|
669
|
-
return
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
if (!t.isIdentifier(path.node.callee) || path.node.callee.name !== 'styled') {
|
|
673
|
-
return
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
const variableName =
|
|
677
|
-
t.isVariableDeclarator(path.parent) && t.isIdentifier(path.parent.id)
|
|
678
|
-
? path.parent.id.name
|
|
679
|
-
: 'unknown'
|
|
680
|
-
|
|
681
|
-
if (shouldPrintDebug) {
|
|
682
|
-
logger.info(` [styled] Found styled(${variableName})`)
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
const parentNode = path.node.arguments[0]
|
|
686
|
-
|
|
687
|
-
if (!t.isIdentifier(parentNode)) {
|
|
688
|
-
return
|
|
689
|
-
}
|
|
690
|
-
const parentName = parentNode.name
|
|
691
|
-
const definition = path.node.arguments[1]
|
|
692
|
-
|
|
693
|
-
if (!parentName || !definition || !t.isObjectExpression(definition)) {
|
|
694
|
-
return
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
// look up by parent first (e.g. View in `styled(View, {...})`), then by self
|
|
698
|
-
let Component =
|
|
699
|
-
getValidImportedComponent(parentName) || getValidImportedComponent(variableName)
|
|
700
|
-
|
|
701
|
-
// the parent's staticConfig knows nothing about the variants this call
|
|
702
|
-
// declares, so a JSX site passing one reads as an unknown prop and
|
|
703
|
-
// de-opts the whole element. evaluating the file gives us the real
|
|
704
|
-
// staticConfig, variants included.
|
|
705
|
-
const declaresVariants =
|
|
706
|
-
!didDynamicLoad &&
|
|
707
|
-
definition.properties.some(
|
|
708
|
-
(prop) =>
|
|
709
|
-
t.isObjectProperty(prop) &&
|
|
710
|
-
t.isIdentifier(prop.key) &&
|
|
711
|
-
prop.key.name === 'variants'
|
|
712
|
-
)
|
|
713
|
-
|
|
714
|
-
if ((!Component || declaresVariants) && enableDynamicEvaluation) {
|
|
715
|
-
didDynamicLoad = true
|
|
716
|
-
try {
|
|
717
|
-
if (shouldPrintDebug) {
|
|
718
|
-
logger.info(
|
|
719
|
-
`Unknown component: ${variableName} = styled(${parentName}) attempting dynamic load: ${sourcePath}`
|
|
720
|
-
)
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
const out = loadTamaguiSync({
|
|
724
|
-
forceExports: true,
|
|
725
|
-
components: [sourcePath],
|
|
726
|
-
cacheKey: version,
|
|
727
|
-
})
|
|
728
|
-
|
|
729
|
-
if (out?.components) {
|
|
730
|
-
propsWithFileInfo.allLoadedComponents = [
|
|
731
|
-
...propsWithFileInfo.allLoadedComponents,
|
|
732
|
-
...out.components,
|
|
733
|
-
]
|
|
734
|
-
|
|
735
|
-
Component =
|
|
736
|
-
out.components.flatMap((x) => x.nameToInfo[variableName] ?? [])[0] ||
|
|
737
|
-
Component
|
|
738
|
-
|
|
739
|
-
if (!out.cached) {
|
|
740
|
-
const foundNames = out.components
|
|
741
|
-
?.map((x) => Object.keys(x.nameToInfo).join(', '))
|
|
742
|
-
.join(', ')
|
|
743
|
-
.trim()
|
|
744
|
-
|
|
745
|
-
if (foundNames) {
|
|
746
|
-
colorLog(
|
|
747
|
-
Color.FgYellow,
|
|
748
|
-
` | Tamagui found dynamic components: ${foundNames}`
|
|
749
|
-
)
|
|
750
|
-
}
|
|
751
|
-
}
|
|
752
|
-
} else if (shouldPrintDebug) {
|
|
753
|
-
logger.info(`Couldn't load, got ${out}`)
|
|
754
|
-
}
|
|
755
|
-
} catch (err: any) {
|
|
756
|
-
if (shouldPrintDebug) {
|
|
757
|
-
logger.info(
|
|
758
|
-
`skip optimize styled(${variableName}), unable to pre-process (DEBUG=tamagui for more)`
|
|
759
|
-
)
|
|
760
|
-
}
|
|
761
|
-
}
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
if (!Component) {
|
|
765
|
-
if (shouldPrintDebug) {
|
|
766
|
-
logger.info(` No component found`)
|
|
767
|
-
}
|
|
768
|
-
|
|
769
|
-
/**
|
|
770
|
-
* We could/should still extract CSS just limited to validStyleProps
|
|
771
|
-
*/
|
|
772
|
-
return
|
|
773
|
-
}
|
|
774
|
-
|
|
775
|
-
const componentSkipProps = new Set([
|
|
776
|
-
...(Component.staticConfig.inlineWhenUnflattened || []),
|
|
777
|
-
...(Component.staticConfig.inlineProps || []),
|
|
778
|
-
// for now skip variants, will return to them
|
|
779
|
-
'variants',
|
|
780
|
-
'defaultVariants',
|
|
781
|
-
// skip fontFamily its basically a "variant", important for theme use to be value always
|
|
782
|
-
'fontFamily',
|
|
783
|
-
'name',
|
|
784
|
-
'focusStyle',
|
|
785
|
-
'focusVisibleStyle',
|
|
786
|
-
'focusWithinStyle',
|
|
787
|
-
'disabledStyle',
|
|
788
|
-
'hoverStyle',
|
|
789
|
-
'pressStyle',
|
|
790
|
-
])
|
|
791
|
-
|
|
792
|
-
// for now dont parse variants, spreads, etc
|
|
793
|
-
const skipped = new Set<t.ObjectProperty | t.SpreadElement | t.ObjectMethod>()
|
|
794
|
-
const styles = {}
|
|
795
|
-
const staticDefaultProps = {}
|
|
796
|
-
|
|
797
|
-
// Generate scope object at this level
|
|
798
|
-
const staticNamespace = getStaticBindingsForScope(
|
|
799
|
-
path.scope,
|
|
800
|
-
importsWhitelist,
|
|
801
|
-
sourcePath,
|
|
802
|
-
bindingCache,
|
|
803
|
-
shouldPrintDebug
|
|
804
|
-
)
|
|
805
|
-
|
|
806
|
-
const attemptEval = !evaluateVars
|
|
807
|
-
? evaluateAstNode
|
|
808
|
-
: createEvaluator({
|
|
809
|
-
props: propsWithFileInfo,
|
|
810
|
-
staticNamespace,
|
|
811
|
-
sourcePath,
|
|
812
|
-
shouldPrintDebug,
|
|
813
|
-
})
|
|
814
|
-
const attemptEvalSafe = createSafeEvaluator(attemptEval)
|
|
815
|
-
|
|
816
|
-
for (const property of definition.properties) {
|
|
817
|
-
if (
|
|
818
|
-
t.isObjectProperty(property) &&
|
|
819
|
-
(t.isIdentifier(property.key) || t.isStringLiteral(property.key))
|
|
820
|
-
) {
|
|
821
|
-
const key = t.isIdentifier(property.key)
|
|
822
|
-
? property.key.name
|
|
823
|
-
: property.key.value
|
|
824
|
-
const defaultPropValue = attemptEvalSafe(property.value)
|
|
825
|
-
if (defaultPropValue !== FAILED_EVAL) {
|
|
826
|
-
staticDefaultProps[key] = defaultPropValue
|
|
827
|
-
}
|
|
828
|
-
}
|
|
829
|
-
|
|
830
|
-
if (
|
|
831
|
-
!t.isObjectProperty(property) ||
|
|
832
|
-
!t.isIdentifier(property.key) ||
|
|
833
|
-
!isValidStyleKey(property.key.name, Component.staticConfig) ||
|
|
834
|
-
// TODO make pseudos and variants work
|
|
835
|
-
// skip pseudos
|
|
836
|
-
pseudoDescriptors[property.key.name] ||
|
|
837
|
-
// skip variants
|
|
838
|
-
Component.staticConfig.variants?.[property.key.name] ||
|
|
839
|
-
componentSkipProps.has(property.key.name)
|
|
840
|
-
) {
|
|
841
|
-
skipped.add(property)
|
|
842
|
-
continue
|
|
843
|
-
}
|
|
844
|
-
// attempt eval
|
|
845
|
-
const out = attemptEvalSafe(property.value)
|
|
846
|
-
if (out === FAILED_EVAL) {
|
|
847
|
-
skipped.add(property)
|
|
848
|
-
} else {
|
|
849
|
-
styles[property.key.name] = out
|
|
850
|
-
}
|
|
851
|
-
}
|
|
852
|
-
|
|
853
|
-
const out = getSplitStyles(
|
|
854
|
-
styles,
|
|
855
|
-
Component.staticConfig,
|
|
856
|
-
defaultTheme,
|
|
857
|
-
'',
|
|
858
|
-
componentState,
|
|
859
|
-
styleProps,
|
|
860
|
-
undefined,
|
|
861
|
-
undefined,
|
|
862
|
-
undefined,
|
|
863
|
-
undefined,
|
|
864
|
-
false,
|
|
865
|
-
shouldPrintDebug
|
|
866
|
-
)!
|
|
867
|
-
|
|
868
|
-
const classNames = {
|
|
869
|
-
...out.classNames,
|
|
870
|
-
}
|
|
871
|
-
|
|
872
|
-
// // add in the style object as classnames
|
|
873
|
-
// const atomics = getPropsAtomic(out.style)
|
|
874
|
-
// for (const atomic of atomics) {
|
|
875
|
-
// out.rulesToInsert = out.rulesToInsert || []
|
|
876
|
-
// out.rulesToInsert.push(atomic)
|
|
877
|
-
// classNames[atomic.property] = atomic.identifier
|
|
878
|
-
// }
|
|
879
|
-
|
|
880
|
-
if (shouldPrintDebug) {
|
|
881
|
-
logger.info(
|
|
882
|
-
[
|
|
883
|
-
`Extracted styled(${variableName})\n`,
|
|
884
|
-
JSON.stringify(styles, null, 2),
|
|
885
|
-
'\n classNames:',
|
|
886
|
-
JSON.stringify(classNames, null, 2),
|
|
887
|
-
'\n rulesToInsert:',
|
|
888
|
-
out.rulesToInsert,
|
|
889
|
-
].join(' ')
|
|
890
|
-
)
|
|
891
|
-
}
|
|
892
|
-
|
|
893
|
-
// don't replace definition values with class name strings -
|
|
894
|
-
// the runtime needs real values for animations, context, and group styles.
|
|
895
|
-
// we only emit the CSS rules so they're available if the runtime uses classNames.
|
|
896
|
-
|
|
897
|
-
if (out.rulesToInsert) {
|
|
898
|
-
for (const key in out.rulesToInsert) {
|
|
899
|
-
const styleObject = out.rulesToInsert[key]
|
|
900
|
-
onStyledDefinitionRule?.(
|
|
901
|
-
styleObject[StyleObjectIdentifier],
|
|
902
|
-
styleObject[StyleObjectRules]
|
|
903
|
-
)
|
|
904
|
-
}
|
|
905
|
-
}
|
|
906
|
-
|
|
907
|
-
res.styled++
|
|
908
|
-
|
|
909
|
-
// register so JSX handler can find this component (same-file and cross-file)
|
|
910
|
-
if (extractStyledDefinitions && enableDynamicEvaluation && Component) {
|
|
911
|
-
const dynamicStaticConfig = {
|
|
912
|
-
...Component.staticConfig,
|
|
913
|
-
defaultProps: {
|
|
914
|
-
...Component.staticConfig.defaultProps,
|
|
915
|
-
...staticDefaultProps,
|
|
916
|
-
},
|
|
917
|
-
}
|
|
918
|
-
|
|
919
|
-
// add to allLoadedComponents with '' so getValidComponent matches when moduleName is ''
|
|
920
|
-
// (same-file styled components have '' as moduleName in JSX handler)
|
|
921
|
-
propsWithFileInfo.allLoadedComponents.push({
|
|
922
|
-
moduleName: '',
|
|
923
|
-
nameToInfo: { [variableName]: { staticConfig: dynamicStaticConfig } },
|
|
924
|
-
})
|
|
925
|
-
|
|
926
|
-
// also cache by file path so other files importing from this path can find it
|
|
927
|
-
if (sourcePath) {
|
|
928
|
-
let existing = dynamicComponentCache.get(sourcePath)
|
|
929
|
-
if (!existing) {
|
|
930
|
-
existing = { moduleName: sourcePath, nameToInfo: {} }
|
|
931
|
-
dynamicComponentCache.set(sourcePath, existing)
|
|
932
|
-
}
|
|
933
|
-
existing.nameToInfo[variableName] = { staticConfig: dynamicStaticConfig }
|
|
934
|
-
}
|
|
935
|
-
}
|
|
936
|
-
|
|
937
|
-
if (shouldPrintDebug) {
|
|
938
|
-
logger.info(`Extracted styled(${variableName})`)
|
|
939
|
-
}
|
|
940
|
-
},
|
|
941
|
-
|
|
942
|
-
JSXElement(traversePath) {
|
|
943
|
-
tm.mark('jsx-element', !!shouldPrintDebug)
|
|
944
|
-
|
|
945
|
-
const node = traversePath.node.openingElement
|
|
946
|
-
const ogAttributes = node.attributes.map((attr) => ({ ...attr }))
|
|
947
|
-
const componentName = findComponentName(traversePath.scope)
|
|
948
|
-
const closingElement = traversePath.node.closingElement
|
|
949
|
-
|
|
950
|
-
// skip non-identifier opening elements (member expressions, etc.)
|
|
951
|
-
if (
|
|
952
|
-
(closingElement && t.isJSXMemberExpression(closingElement?.name)) ||
|
|
953
|
-
!t.isJSXIdentifier(node.name)
|
|
954
|
-
) {
|
|
955
|
-
if (shouldPrintDebug) {
|
|
956
|
-
logger.info(` skip non-identifier element`)
|
|
957
|
-
}
|
|
958
|
-
|
|
959
|
-
return
|
|
960
|
-
}
|
|
961
|
-
|
|
962
|
-
// validate its a proper import from tamagui (or internally inside tamagui)
|
|
963
|
-
const binding = traversePath.scope.getBinding(node.name.name)
|
|
964
|
-
let moduleName = ''
|
|
965
|
-
let dynamicComponent: { staticConfig: any } | null = null
|
|
966
|
-
|
|
967
|
-
if (binding) {
|
|
968
|
-
if (t.isImportDeclaration(binding.path.parent)) {
|
|
969
|
-
moduleName = binding.path.parent.source.value
|
|
970
|
-
if (!isValidImport(propsWithFileInfo, moduleName, binding.identifier.name)) {
|
|
971
|
-
// fallback: try dynamic component cache for local imports (relative or tsconfig alias)
|
|
972
|
-
if (enableDynamicEvaluation && sourcePath) {
|
|
973
|
-
const resolved = resolveImportPath(sourcePath, moduleName)
|
|
974
|
-
if (resolved) {
|
|
975
|
-
// check cache first
|
|
976
|
-
const cached = dynamicComponentCache.get(resolved)
|
|
977
|
-
if (cached?.nameToInfo[binding.identifier.name]) {
|
|
978
|
-
dynamicComponent = cached.nameToInfo[binding.identifier.name]
|
|
979
|
-
} else if (
|
|
980
|
-
!dynamicLoadingInProgress.has(resolved) &&
|
|
981
|
-
mightHaveStyledComponents(resolved)
|
|
982
|
-
) {
|
|
983
|
-
// proactively load the file
|
|
984
|
-
dynamicLoadingInProgress.add(resolved)
|
|
985
|
-
try {
|
|
986
|
-
const out = loadTamaguiSync({
|
|
987
|
-
forceExports: true,
|
|
988
|
-
components: [resolved],
|
|
989
|
-
})
|
|
990
|
-
if (out?.components) {
|
|
991
|
-
for (const comp of out.components) {
|
|
992
|
-
// merge into cache
|
|
993
|
-
let existing = dynamicComponentCache.get(resolved)
|
|
994
|
-
if (!existing) {
|
|
995
|
-
existing = { moduleName: resolved, nameToInfo: {} }
|
|
996
|
-
dynamicComponentCache.set(resolved, existing)
|
|
997
|
-
}
|
|
998
|
-
Object.assign(existing.nameToInfo, comp.nameToInfo)
|
|
999
|
-
// also add to allLoadedComponents so getValidComponent works
|
|
1000
|
-
propsWithFileInfo.allLoadedComponents.push({
|
|
1001
|
-
moduleName: resolved,
|
|
1002
|
-
nameToInfo: comp.nameToInfo,
|
|
1003
|
-
})
|
|
1004
|
-
}
|
|
1005
|
-
const cachedNow = dynamicComponentCache.get(resolved)
|
|
1006
|
-
if (cachedNow?.nameToInfo[binding.identifier.name]) {
|
|
1007
|
-
dynamicComponent = cachedNow.nameToInfo[binding.identifier.name]
|
|
1008
|
-
}
|
|
1009
|
-
}
|
|
1010
|
-
} catch (err) {
|
|
1011
|
-
if (shouldPrintDebug) {
|
|
1012
|
-
logger.info(` - Failed to dynamically load ${resolved}: ${err}`)
|
|
1013
|
-
}
|
|
1014
|
-
} finally {
|
|
1015
|
-
dynamicLoadingInProgress.delete(resolved)
|
|
1016
|
-
}
|
|
1017
|
-
}
|
|
1018
|
-
}
|
|
1019
|
-
}
|
|
1020
|
-
|
|
1021
|
-
if (!dynamicComponent) {
|
|
1022
|
-
if (shouldPrintDebug) {
|
|
1023
|
-
logger.info(
|
|
1024
|
-
` - Binding in component ${componentName} not valid import: "${binding.identifier.name}" isn't in ${moduleName}\n`
|
|
1025
|
-
)
|
|
1026
|
-
}
|
|
1027
|
-
return
|
|
1028
|
-
}
|
|
1029
|
-
}
|
|
1030
|
-
}
|
|
1031
|
-
}
|
|
1032
|
-
|
|
1033
|
-
const component =
|
|
1034
|
-
dynamicComponent ||
|
|
1035
|
-
getValidComponent(propsWithFileInfo, moduleName, node.name.name)
|
|
1036
|
-
if (!component || !component.staticConfig) {
|
|
1037
|
-
if (shouldPrintDebug) {
|
|
1038
|
-
logger.info(`\n - No Tamagui conf for: ${node.name.name}\n`)
|
|
1039
|
-
}
|
|
1040
|
-
return
|
|
1041
|
-
}
|
|
1042
|
-
|
|
1043
|
-
const originalNodeName = node.name.name
|
|
1044
|
-
|
|
1045
|
-
// found a valid tag
|
|
1046
|
-
res.found++
|
|
1047
|
-
|
|
1048
|
-
const filePath = `./${relative(process.cwd(), sourcePath)}`
|
|
1049
|
-
const lineNumbers = node.loc
|
|
1050
|
-
? node.loc.start.line +
|
|
1051
|
-
(node.loc.start.line !== node.loc.end.line ? `-${node.loc.end.line}` : '')
|
|
1052
|
-
: ''
|
|
1053
|
-
|
|
1054
|
-
const codePosition = `${filePath}:${lineNumbers}`
|
|
1055
|
-
|
|
1056
|
-
// debug just one
|
|
1057
|
-
const debugPropValue = node.attributes
|
|
1058
|
-
.filter(
|
|
1059
|
-
(n) =>
|
|
1060
|
-
t.isJSXAttribute(n) && t.isJSXIdentifier(n.name) && n.name.name === 'debug'
|
|
1061
|
-
)
|
|
1062
|
-
// @ts-ignore
|
|
1063
|
-
.map((n: t.JSXAttribute) => {
|
|
1064
|
-
if (n.value === null) return true
|
|
1065
|
-
if (t.isStringLiteral(n.value)) return n.value.value as 'verbose'
|
|
1066
|
-
return false
|
|
1067
|
-
})[0] as boolean | 'verbose' | undefined
|
|
1068
|
-
|
|
1069
|
-
if (debugPropValue) {
|
|
1070
|
-
shouldPrintDebug = debugPropValue
|
|
1071
|
-
}
|
|
1072
|
-
|
|
1073
|
-
if (shouldPrintDebug) {
|
|
1074
|
-
logger.info(
|
|
1075
|
-
`\x1b[33m\x1b[0m ` + `${componentName} | ${codePosition} -------------------`
|
|
1076
|
-
)
|
|
1077
|
-
// prettier-ignore
|
|
1078
|
-
logger.info(
|
|
1079
|
-
[
|
|
1080
|
-
'\x1b[1m',
|
|
1081
|
-
'\x1b[32m',
|
|
1082
|
-
`<${originalNodeName} />`,
|
|
1083
|
-
disableDebugAttr ? '' : '🐛',
|
|
1084
|
-
].join(' ')
|
|
1085
|
-
)
|
|
1086
|
-
}
|
|
1087
|
-
|
|
1088
|
-
// add data-* debug attributes
|
|
1089
|
-
if (platform !== 'native') {
|
|
1090
|
-
if (shouldAddDebugProp && !disableDebugAttr) {
|
|
1091
|
-
res.modified++
|
|
1092
|
-
node.attributes.unshift(
|
|
1093
|
-
t.jsxAttribute(t.jsxIdentifier('data-is'), t.stringLiteral(node.name.name))
|
|
1094
|
-
)
|
|
1095
|
-
if (componentName) {
|
|
1096
|
-
node.attributes.unshift(
|
|
1097
|
-
t.jsxAttribute(t.jsxIdentifier('data-in'), t.stringLiteral(componentName))
|
|
1098
|
-
)
|
|
1099
|
-
}
|
|
1100
|
-
|
|
1101
|
-
node.attributes.unshift(
|
|
1102
|
-
t.jsxAttribute(
|
|
1103
|
-
t.jsxIdentifier('data-at'),
|
|
1104
|
-
t.stringLiteral(`${basename(filePath)}:${lineNumbers}`)
|
|
1105
|
-
)
|
|
1106
|
-
)
|
|
1107
|
-
}
|
|
1108
|
-
}
|
|
1109
|
-
|
|
1110
|
-
if (shouldDisableExtraction) {
|
|
1111
|
-
if (shouldPrintDebug === 'verbose') {
|
|
1112
|
-
logger.info(` ❌ Extraction disabled: ${JSON.stringify(disableExtraction)}\n`)
|
|
1113
|
-
}
|
|
1114
|
-
return
|
|
1115
|
-
}
|
|
1116
|
-
|
|
1117
|
-
try {
|
|
1118
|
-
const { staticConfig } = component
|
|
1119
|
-
|
|
1120
|
-
const defaultProps = {
|
|
1121
|
-
...getDefaultProps(staticConfig),
|
|
1122
|
-
}
|
|
1123
|
-
const variants = staticConfig.variants || {}
|
|
1124
|
-
const isTextView = staticConfig.isText || false
|
|
1125
|
-
const validStyles = staticConfig?.validStyles ?? {}
|
|
1126
|
-
|
|
1127
|
-
// find render="a" render="main" etc dom indicators
|
|
1128
|
-
let tagName = defaultProps.render ?? (isTextView ? 'span' : 'div')
|
|
1129
|
-
traversePath
|
|
1130
|
-
.get('openingElement')
|
|
1131
|
-
.get('attributes')
|
|
1132
|
-
.forEach((path) => {
|
|
1133
|
-
const attr = path.node
|
|
1134
|
-
if (t.isJSXSpreadAttribute(attr)) return
|
|
1135
|
-
if (attr.name.name !== 'render') return
|
|
1136
|
-
const val = attr.value
|
|
1137
|
-
if (!t.isStringLiteral(val)) return
|
|
1138
|
-
tagName = val.value
|
|
1139
|
-
})
|
|
1140
|
-
|
|
1141
|
-
if (shouldPrintDebug === 'verbose') {
|
|
1142
|
-
console.info(` Start tag ${tagName}`)
|
|
1143
|
-
}
|
|
1144
|
-
|
|
1145
|
-
const flatNodeName = getFlattenedNode?.({ isTextView, tag: tagName })
|
|
1146
|
-
|
|
1147
|
-
const inlineProps = new Set([
|
|
1148
|
-
// adding some always inline props
|
|
1149
|
-
...(restProps.inlineProps || []),
|
|
1150
|
-
...(staticConfig.inlineProps || []),
|
|
1151
|
-
])
|
|
1152
|
-
|
|
1153
|
-
const canFlattenTransition =
|
|
1154
|
-
isTargetingHTML &&
|
|
1155
|
-
tamaguiConfig?.animations.outputStyle === 'css' &&
|
|
1156
|
-
!tamaguiConfig.animationDrivers
|
|
1157
|
-
|
|
1158
|
-
const deoptProps = new Set([
|
|
1159
|
-
// css-only transitions lower to ordinary css; every runtime driver
|
|
1160
|
-
// needs the component preserved so it can respond to prop changes.
|
|
1161
|
-
'animation',
|
|
1162
|
-
...(canFlattenTransition ? [] : ['transition']),
|
|
1163
|
-
'animateOnly',
|
|
1164
|
-
'animatePresence',
|
|
1165
|
-
'disableOptimization',
|
|
1166
|
-
|
|
1167
|
-
...(!isTargetingHTML
|
|
1168
|
-
? [
|
|
1169
|
-
// native has no css pseudo selectors; these are runtime-only on
|
|
1170
|
-
// rn (event listeners + style merge in createComponent), and if
|
|
1171
|
-
// we let them flatten into the stylesheet they get written
|
|
1172
|
-
// under a literal key that rn treats as an unknown style prop.
|
|
1173
|
-
// hover is intentionally excluded: it is no-op on native and
|
|
1174
|
-
// should be dropped rather than preserved as runtime work.
|
|
1175
|
-
'pressStyle',
|
|
1176
|
-
'focusStyle',
|
|
1177
|
-
'focusVisibleStyle',
|
|
1178
|
-
'focusWithinStyle',
|
|
1179
|
-
'disabledStyle',
|
|
1180
|
-
]
|
|
1181
|
-
: []),
|
|
1182
|
-
|
|
1183
|
-
// when using a non-CSS driver, de-opt on enterStyle/exitStyle
|
|
1184
|
-
...(tamaguiConfig?.animations.isReactNative
|
|
1185
|
-
? ['enterStyle', 'exitStyle']
|
|
1186
|
-
: []),
|
|
1187
|
-
])
|
|
1188
|
-
|
|
1189
|
-
const inlineWhenUnflattened = new Set(staticConfig.inlineWhenUnflattened || [])
|
|
1190
|
-
|
|
1191
|
-
// Generate scope object at this level
|
|
1192
|
-
const staticNamespace = getStaticBindingsForScope(
|
|
1193
|
-
traversePath.scope,
|
|
1194
|
-
importsWhitelist,
|
|
1195
|
-
sourcePath,
|
|
1196
|
-
bindingCache,
|
|
1197
|
-
shouldPrintDebug
|
|
1198
|
-
)
|
|
1199
|
-
|
|
1200
|
-
const attemptEval = !evaluateVars
|
|
1201
|
-
? evaluateAstNode
|
|
1202
|
-
: createEvaluator({
|
|
1203
|
-
props: propsWithFileInfo,
|
|
1204
|
-
staticNamespace,
|
|
1205
|
-
sourcePath,
|
|
1206
|
-
traversePath,
|
|
1207
|
-
shouldPrintDebug,
|
|
1208
|
-
})
|
|
1209
|
-
const attemptEvalSafe = createSafeEvaluator(attemptEval)
|
|
1210
|
-
|
|
1211
|
-
if (shouldPrintDebug) {
|
|
1212
|
-
logger.info(` staticNamespace ${Object.keys(staticNamespace).join(', ')}`)
|
|
1213
|
-
}
|
|
1214
|
-
|
|
1215
|
-
//
|
|
1216
|
-
// SPREADS SETUP
|
|
1217
|
-
//
|
|
1218
|
-
|
|
1219
|
-
if (couldntParse) {
|
|
1220
|
-
return
|
|
1221
|
-
}
|
|
1222
|
-
|
|
1223
|
-
tm.mark('jsx-element-flattened', !!shouldPrintDebug)
|
|
1224
|
-
|
|
1225
|
-
let attrs: ExtractedAttr[] = []
|
|
1226
|
-
let shouldDeopt = false
|
|
1227
|
-
const inlined = new Map<string, any>()
|
|
1228
|
-
const variantValues = new Map<string, any>()
|
|
1229
|
-
let hasSetOptimized = false
|
|
1230
|
-
const inlineWhenUnflattenedOGVals = {}
|
|
1231
|
-
|
|
1232
|
-
// RUN first pass
|
|
1233
|
-
|
|
1234
|
-
// normalize all conditionals so we can evaluate away easier later
|
|
1235
|
-
// at the same time lets normalize shorthand media queries into spreads:
|
|
1236
|
-
// that way we can parse them with the same logic later on
|
|
1237
|
-
//
|
|
1238
|
-
// {...media.sm && { color: x ? 'red' : 'blue' }}
|
|
1239
|
-
// => {...media.sm && x && { color: 'red' }}
|
|
1240
|
-
// => {...media.sm && !x && { color: 'blue' }}
|
|
1241
|
-
//
|
|
1242
|
-
// $sm={{ color: 'red' }}
|
|
1243
|
-
// => {...media.sm && { color: 'red' }}
|
|
1244
|
-
//
|
|
1245
|
-
// $sm={{ color: x ? 'red' : 'blue' }}
|
|
1246
|
-
// => {...media.sm && x && { color: 'red' }}
|
|
1247
|
-
// => {...media.sm && !x && { color: 'blue' }}
|
|
1248
|
-
|
|
1249
|
-
const propMapperStyleState: GetStyleState = {
|
|
1250
|
-
staticConfig,
|
|
1251
|
-
usedKeys: {},
|
|
1252
|
-
classNames: {},
|
|
1253
|
-
style: {},
|
|
1254
|
-
theme: defaultTheme,
|
|
1255
|
-
viewProps: defaultProps,
|
|
1256
|
-
conf: tamaguiConfig!,
|
|
1257
|
-
props: defaultProps,
|
|
1258
|
-
componentState,
|
|
1259
|
-
styleProps: {
|
|
1260
|
-
...styleProps,
|
|
1261
|
-
resolveValues: 'auto',
|
|
1262
|
-
},
|
|
1263
|
-
debug: shouldPrintDebug,
|
|
1264
|
-
}
|
|
1265
|
-
|
|
1266
|
-
attrs = traversePath
|
|
1267
|
-
.get('openingElement')
|
|
1268
|
-
.get('attributes')
|
|
1269
|
-
.flatMap((path) => {
|
|
1270
|
-
// avoid work
|
|
1271
|
-
if (shouldDeopt) {
|
|
1272
|
-
return
|
|
1273
|
-
}
|
|
1274
|
-
|
|
1275
|
-
try {
|
|
1276
|
-
const res = evaluateAttribute(path)
|
|
1277
|
-
if (!res) {
|
|
1278
|
-
path.remove()
|
|
1279
|
-
}
|
|
1280
|
-
|
|
1281
|
-
return res
|
|
1282
|
-
} catch (err: any) {
|
|
1283
|
-
if (shouldPrintDebug) {
|
|
1284
|
-
logger.info(
|
|
1285
|
-
[
|
|
1286
|
-
'Recoverable error extracting attribute',
|
|
1287
|
-
err.message,
|
|
1288
|
-
shouldPrintDebug === 'verbose' ? err.stack : '',
|
|
1289
|
-
].join(' ')
|
|
1290
|
-
)
|
|
1291
|
-
if (shouldPrintDebug === 'verbose') {
|
|
1292
|
-
logger.info(`node ${path.node?.type}`)
|
|
1293
|
-
}
|
|
1294
|
-
}
|
|
1295
|
-
// dont flatten if we run into error
|
|
1296
|
-
inlined.set(`${Math.random()}`, 'spread')
|
|
1297
|
-
return {
|
|
1298
|
-
type: 'attr',
|
|
1299
|
-
value: path.node,
|
|
1300
|
-
} as const
|
|
1301
|
-
}
|
|
1302
|
-
})
|
|
1303
|
-
.flat(4)
|
|
1304
|
-
.filter(isPresent)
|
|
1305
|
-
|
|
1306
|
-
if (shouldPrintDebug) {
|
|
1307
|
-
logger.info(
|
|
1308
|
-
[' - attrs (before):\n', logLines(attrs.map(attrStr).join(', '))].join(' ')
|
|
1309
|
-
)
|
|
1310
|
-
}
|
|
1311
|
-
|
|
1312
|
-
// START function evaluateAttribute
|
|
1313
|
-
function evaluateAttribute(
|
|
1314
|
-
path: NodePath<t.JSXAttribute | t.JSXSpreadAttribute>
|
|
1315
|
-
): ExtractedAttr | ExtractedAttr[] | null {
|
|
1316
|
-
const attribute = path.node
|
|
1317
|
-
const attr: ExtractedAttr = { type: 'attr', value: attribute }
|
|
1318
|
-
// ...spreads
|
|
1319
|
-
if (t.isJSXSpreadAttribute(attribute)) {
|
|
1320
|
-
const arg = attribute.argument
|
|
1321
|
-
const conditional = t.isConditionalExpression(arg)
|
|
1322
|
-
? // <YStack {...isSmall ? { color: 'red } : { color: 'blue }}
|
|
1323
|
-
([arg.test, arg.consequent, arg.alternate] as const)
|
|
1324
|
-
: t.isLogicalExpression(arg) && arg.operator === '&&'
|
|
1325
|
-
? // <YStack {...isSmall && { color: 'red }}
|
|
1326
|
-
([arg.left, arg.right, null] as const)
|
|
1327
|
-
: null
|
|
1328
|
-
|
|
1329
|
-
if (conditional) {
|
|
1330
|
-
const [test, alt, cons] = conditional
|
|
1331
|
-
if (!test) throw new Error(`no test`)
|
|
1332
|
-
if ([alt, cons].some((side) => side && !isStaticObject(side))) {
|
|
1333
|
-
if (shouldPrintDebug) {
|
|
1334
|
-
logger.info(`not extractable ${alt} ${cons}`)
|
|
1335
|
-
}
|
|
1336
|
-
return attr
|
|
1337
|
-
}
|
|
1338
|
-
// split into individual ternaries per object property
|
|
1339
|
-
return [
|
|
1340
|
-
...(flattenNestedTernaries(test, alt) || []),
|
|
1341
|
-
...((cons &&
|
|
1342
|
-
flattenNestedTernaries(t.unaryExpression('!', test), cons)) ||
|
|
1343
|
-
[]),
|
|
1344
|
-
].map((ternary) => ({
|
|
1345
|
-
type: 'ternary',
|
|
1346
|
-
value: ternary,
|
|
1347
|
-
}))
|
|
1348
|
-
}
|
|
1349
|
-
}
|
|
1350
|
-
// END ...spreads
|
|
1351
|
-
|
|
1352
|
-
// directly keep these
|
|
1353
|
-
// couldn't evaluate spread, undefined name, or name is not string
|
|
1354
|
-
if (
|
|
1355
|
-
t.isJSXSpreadAttribute(attribute) ||
|
|
1356
|
-
!attribute.name ||
|
|
1357
|
-
typeof attribute.name.name !== 'string'
|
|
1358
|
-
) {
|
|
1359
|
-
if (shouldPrintDebug) {
|
|
1360
|
-
logger.info(' ! inlining, spread attr')
|
|
1361
|
-
}
|
|
1362
|
-
inlined.set(`${Math.random()}`, 'spread')
|
|
1363
|
-
return attr
|
|
1364
|
-
}
|
|
1365
|
-
|
|
1366
|
-
const name = attribute.name.name
|
|
1367
|
-
|
|
1368
|
-
// in tamagui style is handled at the end of the style loop so its not as simple as just
|
|
1369
|
-
// adding this as a "style" property
|
|
1370
|
-
// its not used often when using tamagui so not optimizing it for now
|
|
1371
|
-
if (name === 'style') {
|
|
1372
|
-
shouldDeopt = true
|
|
1373
|
-
return null
|
|
1374
|
-
}
|
|
1375
|
-
|
|
1376
|
-
if (excludeProps?.has(name)) {
|
|
1377
|
-
if (shouldPrintDebug) {
|
|
1378
|
-
logger.info([' excluding prop', name].join(' '))
|
|
1379
|
-
}
|
|
1380
|
-
return null
|
|
1381
|
-
}
|
|
1382
|
-
|
|
1383
|
-
if (inlineProps.has(name)) {
|
|
1384
|
-
inlined.set(name, name)
|
|
1385
|
-
if (shouldPrintDebug) {
|
|
1386
|
-
logger.info([' ! inlining, inline prop', name].join(' '))
|
|
1387
|
-
}
|
|
1388
|
-
return attr
|
|
1389
|
-
}
|
|
1390
|
-
|
|
1391
|
-
// pass className, key, and style props through untouched
|
|
1392
|
-
if (UNTOUCHED_PROPS[name]) {
|
|
1393
|
-
return attr
|
|
1394
|
-
}
|
|
1395
|
-
|
|
1396
|
-
if (INLINE_EXTRACTABLE[name]) {
|
|
1397
|
-
inlined.set(name, INLINE_EXTRACTABLE[name])
|
|
1398
|
-
return attr
|
|
1399
|
-
}
|
|
1400
|
-
|
|
1401
|
-
if (
|
|
1402
|
-
name.startsWith('data-') ||
|
|
1403
|
-
name.startsWith('aria-') ||
|
|
1404
|
-
validHTMLAttributes[name]
|
|
1405
|
-
) {
|
|
1406
|
-
return attr
|
|
1407
|
-
}
|
|
1408
|
-
|
|
1409
|
-
// de-opt on enterStyle={expression}
|
|
1410
|
-
if (
|
|
1411
|
-
(name === 'enterStyle' || name === 'exitStyle') &&
|
|
1412
|
-
t.isJSXExpressionContainer(attribute?.value)
|
|
1413
|
-
) {
|
|
1414
|
-
shouldDeopt = true
|
|
1415
|
-
return attr
|
|
1416
|
-
}
|
|
1417
|
-
|
|
1418
|
-
// shorthand media queries
|
|
1419
|
-
if (name[0] === '$' && t.isJSXExpressionContainer(attribute?.value)) {
|
|
1420
|
-
const shortname = name.slice(1)
|
|
1421
|
-
if (mediaQueryConfig[shortname]) {
|
|
1422
|
-
const expression = attribute.value.expression
|
|
1423
|
-
if (!t.isJSXEmptyExpression(expression)) {
|
|
1424
|
-
const ternaries = flattenNestedTernaries(
|
|
1425
|
-
t.stringLiteral(shortname),
|
|
1426
|
-
expression,
|
|
1427
|
-
{
|
|
1428
|
-
inlineMediaQuery: shortname,
|
|
1429
|
-
}
|
|
1430
|
-
)
|
|
1431
|
-
if (ternaries) {
|
|
1432
|
-
return ternaries.map((value) => ({
|
|
1433
|
-
type: 'ternary',
|
|
1434
|
-
value,
|
|
1435
|
-
}))
|
|
1436
|
-
}
|
|
1437
|
-
}
|
|
1438
|
-
}
|
|
1439
|
-
}
|
|
1440
|
-
|
|
1441
|
-
const [value, valuePath] = (() => {
|
|
1442
|
-
if (t.isJSXExpressionContainer(attribute?.value)) {
|
|
1443
|
-
return [attribute.value.expression!, path.get('value')!] as const
|
|
1444
|
-
}
|
|
1445
|
-
return [attribute.value!, path.get('value')!] as const
|
|
1446
|
-
})()
|
|
1447
|
-
|
|
1448
|
-
// these props have runtime-only meaning on native. decide from the
|
|
1449
|
-
// original jsx attr, before getSplitStyles has a chance to drop
|
|
1450
|
-
// native-dead work like hoverStyle from its static output.
|
|
1451
|
-
if (
|
|
1452
|
-
deoptProps.has(name) ||
|
|
1453
|
-
(platform === 'native' &&
|
|
1454
|
-
name[0] === '$' &&
|
|
1455
|
-
(name.startsWith('$theme-') ||
|
|
1456
|
-
(name.startsWith('$group-') && getGroupPseudo(name) !== 'hover')))
|
|
1457
|
-
) {
|
|
1458
|
-
inlined.set(name, true)
|
|
1459
|
-
return attr
|
|
1460
|
-
}
|
|
1461
|
-
|
|
1462
|
-
const remove = () => {
|
|
1463
|
-
Array.isArray(valuePath)
|
|
1464
|
-
? valuePath.map((p) => p.remove())
|
|
1465
|
-
: valuePath.remove()
|
|
1466
|
-
}
|
|
1467
|
-
|
|
1468
|
-
if (name === 'ref') {
|
|
1469
|
-
if (shouldPrintDebug) {
|
|
1470
|
-
logger.info([' ! inlining, ref', name].join(' '))
|
|
1471
|
-
}
|
|
1472
|
-
inlined.set('ref', 'ref')
|
|
1473
|
-
return attr
|
|
1474
|
-
}
|
|
1475
|
-
|
|
1476
|
-
if (name === 'render') {
|
|
1477
|
-
// Only optimize string literal render props
|
|
1478
|
-
// JSX elements and functions should deopt
|
|
1479
|
-
if (!value || value.type !== 'StringLiteral') {
|
|
1480
|
-
if (shouldPrintDebug) {
|
|
1481
|
-
logger.info(` ! deopt on render prop (not a string literal)`)
|
|
1482
|
-
}
|
|
1483
|
-
shouldDeopt = true
|
|
1484
|
-
}
|
|
1485
|
-
return {
|
|
1486
|
-
type: 'attr',
|
|
1487
|
-
value: path.node,
|
|
1488
|
-
}
|
|
1489
|
-
}
|
|
1490
|
-
|
|
1491
|
-
// native shouldn't extract variables
|
|
1492
|
-
if (disableExtractVariables === true) {
|
|
1493
|
-
if (value) {
|
|
1494
|
-
if (value.type === 'StringLiteral' && value.value[0] === '$') {
|
|
1495
|
-
if (shouldPrintDebug) {
|
|
1496
|
-
logger.info(
|
|
1497
|
-
[
|
|
1498
|
-
` ! inlining, native disable extract: ${name} =`,
|
|
1499
|
-
value.value,
|
|
1500
|
-
].join(' ')
|
|
1501
|
-
)
|
|
1502
|
-
}
|
|
1503
|
-
inlined.set(name, true)
|
|
1504
|
-
return attr
|
|
1505
|
-
}
|
|
1506
|
-
}
|
|
1507
|
-
}
|
|
1508
|
-
|
|
1509
|
-
if (name === 'theme') {
|
|
1510
|
-
inlined.set('theme', attr.value)
|
|
1511
|
-
return attr
|
|
1512
|
-
}
|
|
1513
|
-
|
|
1514
|
-
// static `group="<literal>"` is handled at compile-time in
|
|
1515
|
-
// extractToClassNames (emits container CSS + adds `t_group_<name>`
|
|
1516
|
-
// className), so we drop the JSX attribute here without bailing
|
|
1517
|
-
// flattening. dynamic `group={expr}` falls through to runtime.
|
|
1518
|
-
if (isTargetingHTML && name === 'group' && t.isStringLiteral(value)) {
|
|
1519
|
-
return []
|
|
1520
|
-
}
|
|
1521
|
-
|
|
1522
|
-
// if value can be evaluated, extract it and filter it out
|
|
1523
|
-
const styleValue = attemptEvalSafe(value)
|
|
1524
|
-
|
|
1525
|
-
// media-like blocks with nested $-keys (eg $theme-dark={{ $sm: {…} }})
|
|
1526
|
-
// can't resolve to static CSS in one pass — keep them on the runtime path
|
|
1527
|
-
if (
|
|
1528
|
-
name[0] === '$' &&
|
|
1529
|
-
(name.startsWith('$theme-') || name.startsWith('$group-')) &&
|
|
1530
|
-
styleValue &&
|
|
1531
|
-
typeof styleValue === 'object' &&
|
|
1532
|
-
Object.keys(styleValue).some((k) => k[0] === '$')
|
|
1533
|
-
) {
|
|
1534
|
-
if (shouldPrintDebug) {
|
|
1535
|
-
logger.info(` ! nested media-like key inside ${name}, deopt to runtime`)
|
|
1536
|
-
}
|
|
1537
|
-
inlined.set(name, true)
|
|
1538
|
-
return attr
|
|
1539
|
-
}
|
|
1540
|
-
|
|
1541
|
-
// never flatten if a prop isn't a valid static attribute
|
|
1542
|
-
// only post prop-mapping
|
|
1543
|
-
if (!variants[name] && !isValidStyleKey(name, staticConfig)) {
|
|
1544
|
-
let out: any = null
|
|
1545
|
-
|
|
1546
|
-
// for now passing empty props {}, a bit odd, need to at least document
|
|
1547
|
-
// for now we don't expose custom components so just noting behavior
|
|
1548
|
-
propMapper(name, styleValue, propMapperStyleState, false, (key, val) => {
|
|
1549
|
-
out ||= {}
|
|
1550
|
-
out[key] = val
|
|
1551
|
-
})
|
|
1552
|
-
|
|
1553
|
-
if (out) {
|
|
1554
|
-
if (isTargetingHTML) {
|
|
1555
|
-
// translate to DOM-compat
|
|
1556
|
-
out = reactNativeWebInternals.createDOMProps(
|
|
1557
|
-
isTextView ? 'span' : 'div',
|
|
1558
|
-
out
|
|
1559
|
-
)
|
|
1560
|
-
// remove className - we dont use rnw styling
|
|
1561
|
-
delete out.className
|
|
1562
|
-
// remove style - rnw createDOMProps unconditionally emits a
|
|
1563
|
-
// (possibly empty) style key, but we passed it a single
|
|
1564
|
-
// non-style prop. Leaving it in causes Object.keys(out) to
|
|
1565
|
-
// iterate twice and emit the original JSXAttribute twice
|
|
1566
|
-
// (e.g. duplicate testID), breaking the DOM output.
|
|
1567
|
-
delete out.style
|
|
1568
|
-
}
|
|
1569
|
-
}
|
|
1570
|
-
|
|
1571
|
-
let didInline = false
|
|
1572
|
-
const attributes = Object.keys(out).map((key) => {
|
|
1573
|
-
const val = out[key]
|
|
1574
|
-
const isStyle = isValidStyleKey(key, staticConfig)
|
|
1575
|
-
if (isStyle) {
|
|
1576
|
-
return {
|
|
1577
|
-
type: 'style',
|
|
1578
|
-
value: { [key]: styleValue },
|
|
1579
|
-
name: key,
|
|
1580
|
-
attr: path.node,
|
|
1581
|
-
} as const
|
|
1582
|
-
}
|
|
1583
|
-
if (
|
|
1584
|
-
validHTMLAttributes[key] ||
|
|
1585
|
-
key.startsWith('aria-') ||
|
|
1586
|
-
key.startsWith('data-') ||
|
|
1587
|
-
// this is debug stuff added by vite / new jsx transform
|
|
1588
|
-
key === '__source' ||
|
|
1589
|
-
key === '__self'
|
|
1590
|
-
) {
|
|
1591
|
-
if (
|
|
1592
|
-
styleValue === FAILED_EVAL &&
|
|
1593
|
-
key !== name &&
|
|
1594
|
-
t.isJSXAttribute(attr.value)
|
|
1595
|
-
) {
|
|
1596
|
-
// createDOMProps renamed the prop (e.g. testID -> data-testid).
|
|
1597
|
-
// preserve the original expression value but use the new
|
|
1598
|
-
// attribute name. restricted to FAILED_EVAL because the
|
|
1599
|
-
// later `case 'attr'` rename pass only runs on
|
|
1600
|
-
// statically-evaluable values; for static values that pass
|
|
1601
|
-
// intentionally preserves some prop names (e.g. focusable
|
|
1602
|
-
// in v2) instead of doing the createDOMProps rename.
|
|
1603
|
-
return {
|
|
1604
|
-
type: 'attr',
|
|
1605
|
-
value: t.jsxAttribute(t.jsxIdentifier(key), attr.value.value),
|
|
1606
|
-
} as const
|
|
1607
|
-
}
|
|
1608
|
-
return attr
|
|
1609
|
-
}
|
|
1610
|
-
if (shouldPrintDebug) {
|
|
1611
|
-
logger.info(' ! inlining, non-static ' + key)
|
|
1612
|
-
}
|
|
1613
|
-
didInline = true
|
|
1614
|
-
inlined.set(key, val)
|
|
1615
|
-
return val
|
|
1616
|
-
})
|
|
1617
|
-
|
|
1618
|
-
// weird logic whats going on here
|
|
1619
|
-
if (didInline) {
|
|
1620
|
-
if (shouldPrintDebug) {
|
|
1621
|
-
logger.info(
|
|
1622
|
-
` bailing flattening due to attributes ${attributes.map((x) =>
|
|
1623
|
-
x.toString()
|
|
1624
|
-
)}`
|
|
1625
|
-
)
|
|
1626
|
-
}
|
|
1627
|
-
// bail
|
|
1628
|
-
return attr
|
|
1629
|
-
}
|
|
1630
|
-
|
|
1631
|
-
// return evaluated attributes
|
|
1632
|
-
return attributes
|
|
1633
|
-
}
|
|
1634
|
-
|
|
1635
|
-
// FAILED = dynamic or ternary, keep going
|
|
1636
|
-
if (styleValue !== FAILED_EVAL) {
|
|
1637
|
-
if (inlineWhenUnflattened.has(name)) {
|
|
1638
|
-
// preserve original value for restoration
|
|
1639
|
-
inlineWhenUnflattenedOGVals[name] = { styleValue, attr }
|
|
1640
|
-
}
|
|
1641
|
-
|
|
1642
|
-
if (isValidStyleKey(name, staticConfig)) {
|
|
1643
|
-
// $theme- / $group- styles extract through the atomic-CSS pipeline
|
|
1644
|
-
// (extractToClassNames → createMediaStyle), so they fall through to
|
|
1645
|
-
// the normal style return below. The one case we still bail is
|
|
1646
|
-
// $group-<name>-* when an ancestor element declares `group="<name>"`
|
|
1647
|
-
// together with `untilMeasured` — the runtime measures the parent
|
|
1648
|
-
// and only then emits child styles, which can't be modeled in CSS.
|
|
1649
|
-
// $platform- can be flattened if the platform matches.
|
|
1650
|
-
if (name[0] === '$') {
|
|
1651
|
-
if (name.startsWith('$group-')) {
|
|
1652
|
-
const groupName = name.slice('$group-'.length).split('-')[0]
|
|
1653
|
-
if (groupName && hasUntilMeasuredAncestor(path, groupName)) {
|
|
1654
|
-
if (shouldPrintDebug) {
|
|
1655
|
-
logger.info(
|
|
1656
|
-
` ! group="${groupName}" ancestor has untilMeasured, not flattening: ${name}`
|
|
1657
|
-
)
|
|
1658
|
-
}
|
|
1659
|
-
inlined.set(name, true)
|
|
1660
|
-
return attr
|
|
1661
|
-
}
|
|
1662
|
-
}
|
|
1663
|
-
|
|
1664
|
-
// $platform-web, $platform-native, $platform-ios, $platform-android, $platform-tv, $platform-androidtv, $platform-tvos
|
|
1665
|
-
if (name.startsWith('$platform-')) {
|
|
1666
|
-
const platformName = name.slice(10) // remove '$platform-'
|
|
1667
|
-
const isMatchingPlatform =
|
|
1668
|
-
platformName === platform ||
|
|
1669
|
-
(platformName === 'native' && platform === 'native') ||
|
|
1670
|
-
(platformName === 'web' && platform === 'web')
|
|
1671
|
-
|
|
1672
|
-
if (isMatchingPlatform && typeof styleValue === 'object') {
|
|
1673
|
-
// Flatten the inner styles directly
|
|
1674
|
-
if (shouldPrintDebug) {
|
|
1675
|
-
logger.info(
|
|
1676
|
-
` flattening $platform-${platformName}: ${JSON.stringify(styleValue)}`
|
|
1677
|
-
)
|
|
1678
|
-
}
|
|
1679
|
-
return Object.entries(styleValue).map(([key, val]) => ({
|
|
1680
|
-
type: 'style' as const,
|
|
1681
|
-
value: { [key]: val },
|
|
1682
|
-
name: key,
|
|
1683
|
-
attr: path.node,
|
|
1684
|
-
}))
|
|
1685
|
-
} else {
|
|
1686
|
-
// On native builds, sub-platform variants (android, ios, tv, androidtv, tvos)
|
|
1687
|
-
// can't be resolved at compile time - leave for runtime evaluation
|
|
1688
|
-
if (
|
|
1689
|
-
platform === 'native' &&
|
|
1690
|
-
nativeOnlyPlatforms.has(platformName)
|
|
1691
|
-
) {
|
|
1692
|
-
if (shouldPrintDebug) {
|
|
1693
|
-
logger.info(
|
|
1694
|
-
` ! keeping platform-specific style for runtime evaluation: ${name}`
|
|
1695
|
-
)
|
|
1696
|
-
}
|
|
1697
|
-
inlined.set(name, true)
|
|
1698
|
-
return attr
|
|
1699
|
-
}
|
|
1700
|
-
// Platform doesn't match, skip these styles entirely
|
|
1701
|
-
if (shouldPrintDebug) {
|
|
1702
|
-
logger.info(` ! skipping non-matching platform style: ${name}`)
|
|
1703
|
-
}
|
|
1704
|
-
return []
|
|
1705
|
-
}
|
|
1706
|
-
}
|
|
1707
|
-
}
|
|
1708
|
-
if (shouldPrintDebug) {
|
|
1709
|
-
logger.info(` style: ${name} = ${JSON.stringify(styleValue)}`)
|
|
1710
|
-
}
|
|
1711
|
-
if (!(name in defaultProps)) {
|
|
1712
|
-
if (!hasSetOptimized) {
|
|
1713
|
-
res.optimized++
|
|
1714
|
-
hasSetOptimized = true
|
|
1715
|
-
}
|
|
1716
|
-
}
|
|
1717
|
-
return {
|
|
1718
|
-
type: 'style',
|
|
1719
|
-
value: { [name]: styleValue },
|
|
1720
|
-
name,
|
|
1721
|
-
attr: path.node,
|
|
1722
|
-
}
|
|
1723
|
-
}
|
|
1724
|
-
if (variants[name]) {
|
|
1725
|
-
variantValues.set(name, styleValue)
|
|
1726
|
-
}
|
|
1727
|
-
inlined.set(name, true)
|
|
1728
|
-
return attr
|
|
1729
|
-
}
|
|
1730
|
-
|
|
1731
|
-
// ternaries!
|
|
1732
|
-
|
|
1733
|
-
// binary ternary, we can eventually make this smarter but step 1
|
|
1734
|
-
// basically for the common use case of:
|
|
1735
|
-
// opacity={(conditional ? 0 : 1) * scale}
|
|
1736
|
-
if (t.isBinaryExpression(value)) {
|
|
1737
|
-
if (shouldPrintDebug) {
|
|
1738
|
-
logger.info(` binary expression ${name} = ${value}`)
|
|
1739
|
-
}
|
|
1740
|
-
const { operator, left, right } = value
|
|
1741
|
-
// if one side is a ternary, and the other side is evaluatable, we can maybe extract
|
|
1742
|
-
const lVal = attemptEvalSafe(left)
|
|
1743
|
-
const rVal = attemptEvalSafe(right)
|
|
1744
|
-
if (shouldPrintDebug) {
|
|
1745
|
-
logger.info(
|
|
1746
|
-
` evalBinaryExpression lVal ${String(lVal)}, rVal ${String(rVal)}`
|
|
1747
|
-
)
|
|
1748
|
-
}
|
|
1749
|
-
if (lVal !== FAILED_EVAL && t.isConditionalExpression(right)) {
|
|
1750
|
-
const ternary = addBinaryConditional(operator, left, right)
|
|
1751
|
-
if (ternary) return ternary
|
|
1752
|
-
}
|
|
1753
|
-
if (rVal !== FAILED_EVAL && t.isConditionalExpression(left)) {
|
|
1754
|
-
const ternary = addBinaryConditional(operator, right, left)
|
|
1755
|
-
if (ternary) return ternary
|
|
1756
|
-
}
|
|
1757
|
-
if (shouldPrintDebug) {
|
|
1758
|
-
logger.info(` evalBinaryExpression cant extract`)
|
|
1759
|
-
}
|
|
1760
|
-
inlined.set(name, true)
|
|
1761
|
-
return attr
|
|
1762
|
-
}
|
|
1763
|
-
|
|
1764
|
-
const staticConditional = getStaticConditional(value)
|
|
1765
|
-
if (staticConditional) {
|
|
1766
|
-
if (shouldPrintDebug === 'verbose') {
|
|
1767
|
-
logger.info(` static conditional ${name} ${value}`)
|
|
1768
|
-
}
|
|
1769
|
-
return { type: 'ternary', value: staticConditional }
|
|
1770
|
-
}
|
|
1771
|
-
|
|
1772
|
-
const staticLogical = getStaticLogical(value)
|
|
1773
|
-
if (staticLogical) {
|
|
1774
|
-
if (shouldPrintDebug === 'verbose') {
|
|
1775
|
-
logger.info(` static ternary ${name} = ${value}`)
|
|
1776
|
-
}
|
|
1777
|
-
return { type: 'ternary', value: staticLogical }
|
|
1778
|
-
}
|
|
1779
|
-
|
|
1780
|
-
// if we've made it this far, the prop stays inline
|
|
1781
|
-
inlined.set(name, true)
|
|
1782
|
-
if (shouldPrintDebug) {
|
|
1783
|
-
logger.info(` ! inline no match ${name} ${value}`)
|
|
1784
|
-
}
|
|
1785
|
-
|
|
1786
|
-
//
|
|
1787
|
-
// RETURN ATTR
|
|
1788
|
-
//
|
|
1789
|
-
return attr
|
|
1790
|
-
|
|
1791
|
-
// attr helpers:
|
|
1792
|
-
function addBinaryConditional(
|
|
1793
|
-
operator: any,
|
|
1794
|
-
staticExpr: any,
|
|
1795
|
-
cond: t.ConditionalExpression
|
|
1796
|
-
): ExtractedAttr | null {
|
|
1797
|
-
if (getStaticConditional(cond)) {
|
|
1798
|
-
const alt = attemptEval(
|
|
1799
|
-
t.binaryExpression(operator, staticExpr, cond.alternate)
|
|
1800
|
-
)
|
|
1801
|
-
const cons = attemptEval(
|
|
1802
|
-
t.binaryExpression(operator, staticExpr, cond.consequent)
|
|
1803
|
-
)
|
|
1804
|
-
if (shouldPrintDebug) {
|
|
1805
|
-
logger.info([' binaryConditional', cond.test, cons, alt].join(' '))
|
|
1806
|
-
}
|
|
1807
|
-
return {
|
|
1808
|
-
type: 'ternary',
|
|
1809
|
-
value: {
|
|
1810
|
-
test: cond.test,
|
|
1811
|
-
remove,
|
|
1812
|
-
alternate: { [name]: alt },
|
|
1813
|
-
consequent: { [name]: cons },
|
|
1814
|
-
},
|
|
1815
|
-
}
|
|
1816
|
-
}
|
|
1817
|
-
return null
|
|
1818
|
-
}
|
|
1819
|
-
|
|
1820
|
-
function getStaticConditional(value: t.Node): Ternary | null {
|
|
1821
|
-
if (t.isConditionalExpression(value)) {
|
|
1822
|
-
try {
|
|
1823
|
-
const aVal = attemptEval(value.alternate)
|
|
1824
|
-
const cVal = attemptEval(value.consequent)
|
|
1825
|
-
if (shouldPrintDebug) {
|
|
1826
|
-
const type = value.test.type
|
|
1827
|
-
logger.info([' static ternary', type, cVal, aVal].join(' '))
|
|
1828
|
-
}
|
|
1829
|
-
return {
|
|
1830
|
-
test: value.test,
|
|
1831
|
-
remove,
|
|
1832
|
-
consequent: { [name]: cVal },
|
|
1833
|
-
alternate: { [name]: aVal },
|
|
1834
|
-
}
|
|
1835
|
-
} catch (err: any) {
|
|
1836
|
-
if (shouldPrintDebug) {
|
|
1837
|
-
logger.info([' cant eval ternary', err.message].join(' '))
|
|
1838
|
-
}
|
|
1839
|
-
}
|
|
1840
|
-
}
|
|
1841
|
-
return null
|
|
1842
|
-
}
|
|
1843
|
-
|
|
1844
|
-
function getStaticLogical(value: t.Node): Ternary | null {
|
|
1845
|
-
if (t.isLogicalExpression(value)) {
|
|
1846
|
-
if (value.operator === '&&') {
|
|
1847
|
-
try {
|
|
1848
|
-
const val = attemptEval(value.right)
|
|
1849
|
-
if (shouldPrintDebug) {
|
|
1850
|
-
logger.info([' staticLogical', value.left, name, val].join(' '))
|
|
1851
|
-
}
|
|
1852
|
-
return {
|
|
1853
|
-
test: value.left,
|
|
1854
|
-
remove,
|
|
1855
|
-
consequent: { [name]: val },
|
|
1856
|
-
alternate: null,
|
|
1857
|
-
}
|
|
1858
|
-
} catch (err) {
|
|
1859
|
-
if (shouldPrintDebug) {
|
|
1860
|
-
logger.info([' cant static eval logical', err].join(' '))
|
|
1861
|
-
}
|
|
1862
|
-
}
|
|
1863
|
-
}
|
|
1864
|
-
}
|
|
1865
|
-
return null
|
|
1866
|
-
}
|
|
1867
|
-
} // END function evaluateAttribute
|
|
1868
|
-
|
|
1869
|
-
function isStaticObject(obj: t.Node): obj is t.ObjectExpression {
|
|
1870
|
-
return (
|
|
1871
|
-
t.isObjectExpression(obj) &&
|
|
1872
|
-
obj.properties.every((prop) => {
|
|
1873
|
-
if (!t.isObjectProperty(prop)) {
|
|
1874
|
-
// console.warn('not an object prop?', prop)
|
|
1875
|
-
return false
|
|
1876
|
-
}
|
|
1877
|
-
const propName = prop.key['name']
|
|
1878
|
-
if (!isValidStyleKey(propName, staticConfig) && propName !== 'render') {
|
|
1879
|
-
if (shouldPrintDebug) {
|
|
1880
|
-
logger.info([' not a valid style prop!', propName].join(' '))
|
|
1881
|
-
}
|
|
1882
|
-
return false
|
|
1883
|
-
}
|
|
1884
|
-
return true
|
|
1885
|
-
})
|
|
1886
|
-
)
|
|
1887
|
-
}
|
|
1888
|
-
|
|
1889
|
-
// side = {
|
|
1890
|
-
// color: 'red',
|
|
1891
|
-
// background: x ? 'red' : 'green',
|
|
1892
|
-
// $gtSm: { color: 'green' }
|
|
1893
|
-
// }
|
|
1894
|
-
// => Ternary<test, { color: 'red' }, null>
|
|
1895
|
-
// => Ternary<test && x, { background: 'red' }, null>
|
|
1896
|
-
// => Ternary<test && !x, { background: 'green' }, null>
|
|
1897
|
-
// => Ternary<test && '$gtSm', { color: 'green' }, null>
|
|
1898
|
-
function flattenNestedTernaries(
|
|
1899
|
-
test: t.Expression,
|
|
1900
|
-
side: t.Expression | null,
|
|
1901
|
-
ternaryPartial: Partial<Ternary> = {}
|
|
1902
|
-
): null | Ternary[] {
|
|
1903
|
-
if (!side) {
|
|
1904
|
-
return null
|
|
1905
|
-
}
|
|
1906
|
-
if (!isStaticObject(side)) {
|
|
1907
|
-
throw new Error('not extractable')
|
|
1908
|
-
}
|
|
1909
|
-
return side.properties.flatMap((property) => {
|
|
1910
|
-
if (!t.isObjectProperty(property)) {
|
|
1911
|
-
throw new Error('expected object property')
|
|
1912
|
-
}
|
|
1913
|
-
// this could be a recurse here if we want to get fancy
|
|
1914
|
-
if (t.isConditionalExpression(property.value)) {
|
|
1915
|
-
// merge up into the parent conditional, split into two
|
|
1916
|
-
const [truthy, falsy] = [
|
|
1917
|
-
t.objectExpression([
|
|
1918
|
-
t.objectProperty(property.key, property.value.consequent),
|
|
1919
|
-
]),
|
|
1920
|
-
t.objectExpression([
|
|
1921
|
-
t.objectProperty(property.key, property.value.alternate),
|
|
1922
|
-
]),
|
|
1923
|
-
].map((x) => attemptEval(x))
|
|
1924
|
-
return [
|
|
1925
|
-
createTernary({
|
|
1926
|
-
remove() {},
|
|
1927
|
-
...ternaryPartial,
|
|
1928
|
-
test: t.logicalExpression('&&', test, property.value.test),
|
|
1929
|
-
consequent: truthy,
|
|
1930
|
-
alternate: null,
|
|
1931
|
-
}),
|
|
1932
|
-
createTernary({
|
|
1933
|
-
...ternaryPartial,
|
|
1934
|
-
test: t.logicalExpression(
|
|
1935
|
-
'&&',
|
|
1936
|
-
test,
|
|
1937
|
-
t.unaryExpression('!', property.value.test)
|
|
1938
|
-
),
|
|
1939
|
-
consequent: falsy,
|
|
1940
|
-
alternate: null,
|
|
1941
|
-
remove() {},
|
|
1942
|
-
}),
|
|
1943
|
-
]
|
|
1944
|
-
}
|
|
1945
|
-
const obj = t.objectExpression([
|
|
1946
|
-
t.objectProperty(property.key, property.value),
|
|
1947
|
-
])
|
|
1948
|
-
const consequent = attemptEval(obj)
|
|
1949
|
-
return createTernary({
|
|
1950
|
-
remove() {},
|
|
1951
|
-
...ternaryPartial,
|
|
1952
|
-
test,
|
|
1953
|
-
consequent,
|
|
1954
|
-
alternate: null,
|
|
1955
|
-
})
|
|
1956
|
-
})
|
|
1957
|
-
}
|
|
1958
|
-
|
|
1959
|
-
if (couldntParse || shouldDeopt) {
|
|
1960
|
-
if (shouldPrintDebug) {
|
|
1961
|
-
logger.info(
|
|
1962
|
-
[` avoid optimizing:`, { couldntParse, shouldDeopt }].join(' ')
|
|
1963
|
-
)
|
|
1964
|
-
}
|
|
1965
|
-
node.attributes = ogAttributes
|
|
1966
|
-
return
|
|
1967
|
-
}
|
|
1968
|
-
|
|
1969
|
-
// before deopt, can still optimize
|
|
1970
|
-
const parentFn = findTopmostFunction(traversePath)
|
|
1971
|
-
if (parentFn) {
|
|
1972
|
-
modifiedComponents.add(parentFn)
|
|
1973
|
-
}
|
|
1974
|
-
|
|
1975
|
-
// flatten logic!
|
|
1976
|
-
// fairly simple check to see if all children are text
|
|
1977
|
-
const hasSpread = attrs.some(
|
|
1978
|
-
(x) => x.type === 'attr' && t.isJSXSpreadAttribute(x.value)
|
|
1979
|
-
)
|
|
1980
|
-
|
|
1981
|
-
const hasOnlyStringChildren =
|
|
1982
|
-
!hasSpread &&
|
|
1983
|
-
(node.selfClosing ||
|
|
1984
|
-
(traversePath.node.children &&
|
|
1985
|
-
traversePath.node.children.every((x) => x.type === 'JSXText')))
|
|
1986
|
-
|
|
1987
|
-
let themeVal = inlined.get('theme')
|
|
1988
|
-
|
|
1989
|
-
// on native we can't flatten when theme prop is set
|
|
1990
|
-
if (platform !== 'native') {
|
|
1991
|
-
inlined.delete('theme')
|
|
1992
|
-
}
|
|
1993
|
-
|
|
1994
|
-
for (const [key] of inlined) {
|
|
1995
|
-
const isStaticObjectVariant =
|
|
1996
|
-
staticConfig.variants?.[key] && variantValues.has(key)
|
|
1997
|
-
if (INLINE_EXTRACTABLE[key] || isStaticObjectVariant) {
|
|
1998
|
-
inlined.delete(key)
|
|
1999
|
-
}
|
|
2000
|
-
}
|
|
2001
|
-
|
|
2002
|
-
const canFlattenProps = inlined.size === 0
|
|
2003
|
-
|
|
2004
|
-
let shouldFlatten = Boolean(
|
|
2005
|
-
flatNodeName &&
|
|
2006
|
-
!shouldDeopt &&
|
|
2007
|
-
canFlattenProps &&
|
|
2008
|
-
!hasSpread &&
|
|
2009
|
-
!staticConfig.isStyledHOC &&
|
|
2010
|
-
!staticConfig.isHOC &&
|
|
2011
|
-
!staticConfig.isReactNative &&
|
|
2012
|
-
staticConfig.neverFlatten !== true &&
|
|
2013
|
-
(staticConfig.neverFlatten === 'jsx' ? hasOnlyStringChildren : true)
|
|
2014
|
-
)
|
|
2015
|
-
|
|
2016
|
-
const usedThemeKeys = new Set<string>()
|
|
2017
|
-
// if it accesses any theme values during evaluation
|
|
2018
|
-
themeAccessListeners.add((key) => {
|
|
2019
|
-
if (disableExtractVariables) {
|
|
2020
|
-
usedThemeKeys.add(key)
|
|
2021
|
-
shouldFlatten = false
|
|
2022
|
-
if (shouldPrintDebug === 'verbose') {
|
|
2023
|
-
logger.info([' ! accessing theme key, avoid flatten', key].join(' '))
|
|
2024
|
-
}
|
|
2025
|
-
}
|
|
2026
|
-
})
|
|
2027
|
-
|
|
2028
|
-
if (!shouldFlatten) {
|
|
2029
|
-
if (shouldPrintDebug) {
|
|
2030
|
-
logger.info(
|
|
2031
|
-
`Deopting ${JSON.stringify({
|
|
2032
|
-
shouldFlatten,
|
|
2033
|
-
shouldDeopt,
|
|
2034
|
-
canFlattenProps,
|
|
2035
|
-
hasSpread,
|
|
2036
|
-
neverFlatten: staticConfig.neverFlatten,
|
|
2037
|
-
})}`
|
|
2038
|
-
)
|
|
2039
|
-
}
|
|
2040
|
-
node.attributes = ogAttributes
|
|
2041
|
-
return
|
|
2042
|
-
}
|
|
2043
|
-
|
|
2044
|
-
// ensure the default styles are there
|
|
2045
|
-
let skipMap = false
|
|
2046
|
-
const defaultStyleAttrs = Object.keys(defaultProps).flatMap((key) => {
|
|
2047
|
-
if (skipMap) return []
|
|
2048
|
-
const value = defaultProps[key]
|
|
2049
|
-
if (key === 'theme' && !themeVal) {
|
|
2050
|
-
if (platform === 'native') {
|
|
2051
|
-
shouldFlatten = false
|
|
2052
|
-
skipMap = true
|
|
2053
|
-
inlined.set('theme', { value: t.stringLiteral(value) })
|
|
2054
|
-
}
|
|
2055
|
-
themeVal = { value: t.stringLiteral(value) }
|
|
2056
|
-
return []
|
|
2057
|
-
}
|
|
2058
|
-
if (!isValidStyleKey(key, staticConfig)) {
|
|
2059
|
-
return []
|
|
2060
|
-
}
|
|
2061
|
-
const name = tamaguiConfig?.shorthands[key] || key
|
|
2062
|
-
if (value === undefined) {
|
|
2063
|
-
logger.warn(
|
|
2064
|
-
`⚠️ Error evaluating default style for component, prop ${key} ${value}`
|
|
2065
|
-
)
|
|
2066
|
-
shouldDeopt = true
|
|
2067
|
-
return
|
|
2068
|
-
}
|
|
2069
|
-
if (name[0] === '$' && mediaQueryConfig[name.slice(1)]) {
|
|
2070
|
-
defaultProps[key] = undefined
|
|
2071
|
-
return evaluateAttribute({
|
|
2072
|
-
node: t.jsxAttribute(
|
|
2073
|
-
t.jsxIdentifier(name),
|
|
2074
|
-
t.jsxExpressionContainer(
|
|
2075
|
-
t.objectExpression(
|
|
2076
|
-
Object.keys(value)
|
|
2077
|
-
.filter((k) => {
|
|
2078
|
-
return typeof value[k] !== 'undefined'
|
|
2079
|
-
})
|
|
2080
|
-
.map((k) => {
|
|
2081
|
-
return t.objectProperty(t.identifier(k), literalToAst(value[k]))
|
|
2082
|
-
})
|
|
2083
|
-
)
|
|
2084
|
-
)
|
|
2085
|
-
),
|
|
2086
|
-
} as any)
|
|
2087
|
-
}
|
|
2088
|
-
const attr: ExtractedAttrStyle = {
|
|
2089
|
-
type: 'style',
|
|
2090
|
-
name,
|
|
2091
|
-
value: { [name]: value },
|
|
2092
|
-
}
|
|
2093
|
-
return attr
|
|
2094
|
-
}) as ExtractedAttr[]
|
|
2095
|
-
|
|
2096
|
-
if (!skipMap) {
|
|
2097
|
-
if (defaultStyleAttrs.length) {
|
|
2098
|
-
attrs = [...defaultStyleAttrs, ...attrs]
|
|
2099
|
-
}
|
|
2100
|
-
}
|
|
2101
|
-
|
|
2102
|
-
// combine ternaries
|
|
2103
|
-
let ternaries: Ternary[] = []
|
|
2104
|
-
attrs = attrs
|
|
2105
|
-
.reduce<(ExtractedAttr | ExtractedAttr[])[]>((out, cur) => {
|
|
2106
|
-
const next = attrs[attrs.indexOf(cur) + 1]
|
|
2107
|
-
if (cur.type === 'ternary') {
|
|
2108
|
-
ternaries.push(cur.value)
|
|
2109
|
-
}
|
|
2110
|
-
if ((!next || next.type !== 'ternary') && ternaries.length) {
|
|
2111
|
-
// finish, process
|
|
2112
|
-
const normalized = normalizeTernaries(ternaries).map(
|
|
2113
|
-
({ alternate, consequent, ...rest }) => {
|
|
2114
|
-
return {
|
|
2115
|
-
type: 'ternary' as const,
|
|
2116
|
-
value: {
|
|
2117
|
-
...rest,
|
|
2118
|
-
alternate: alternate || null,
|
|
2119
|
-
consequent: consequent || null,
|
|
2120
|
-
},
|
|
2121
|
-
}
|
|
2122
|
-
}
|
|
2123
|
-
)
|
|
2124
|
-
try {
|
|
2125
|
-
return [...out, ...normalized]
|
|
2126
|
-
} finally {
|
|
2127
|
-
if (shouldPrintDebug) {
|
|
2128
|
-
logger.info(
|
|
2129
|
-
` normalizeTernaries (${ternaries.length} => ${normalized.length})`
|
|
2130
|
-
)
|
|
2131
|
-
}
|
|
2132
|
-
ternaries = []
|
|
2133
|
-
}
|
|
2134
|
-
}
|
|
2135
|
-
if (cur.type === 'ternary') {
|
|
2136
|
-
return out
|
|
2137
|
-
}
|
|
2138
|
-
out.push(cur)
|
|
2139
|
-
return out
|
|
2140
|
-
}, [])
|
|
2141
|
-
.flat()
|
|
2142
|
-
|
|
2143
|
-
const ternaryBranchProps = new Map<string, Ternary>()
|
|
2144
|
-
const allTernaries = attrs.flatMap((attr) =>
|
|
2145
|
-
attr.type === 'ternary' ? attr.value : []
|
|
2146
|
-
)
|
|
2147
|
-
if (allTernaries.length > 1) {
|
|
2148
|
-
for (const ternary of normalizeTernaries(allTernaries)) {
|
|
2149
|
-
ternaryBranchProps.set(getTernaryKey(ternary.test), ternary)
|
|
2150
|
-
}
|
|
2151
|
-
}
|
|
2152
|
-
|
|
2153
|
-
// wrap theme around children on flatten
|
|
2154
|
-
// account for shouldFlatten could change w the above block "if (disableExtractVariables)"
|
|
2155
|
-
if (themeVal) {
|
|
2156
|
-
if (!programPath) {
|
|
2157
|
-
console.warn(
|
|
2158
|
-
`No program path found, avoiding importing flattening / importing theme in ${sourcePath}`
|
|
2159
|
-
)
|
|
2160
|
-
} else {
|
|
2161
|
-
if (shouldPrintDebug) {
|
|
2162
|
-
logger.info([' - wrapping theme', themeVal].join(' '))
|
|
2163
|
-
}
|
|
2164
|
-
|
|
2165
|
-
// remove theme attribute from flattened node
|
|
2166
|
-
attrs = attrs.filter(
|
|
2167
|
-
(x) =>
|
|
2168
|
-
!(
|
|
2169
|
-
x.type === 'attr' &&
|
|
2170
|
-
t.isJSXAttribute(x.value) &&
|
|
2171
|
-
x.value.name.name === 'theme'
|
|
2172
|
-
)
|
|
2173
|
-
)
|
|
2174
|
-
|
|
2175
|
-
// add import
|
|
2176
|
-
if (!hasImportedTheme) {
|
|
2177
|
-
hasImportedTheme = true
|
|
2178
|
-
programPath.node.body.push(
|
|
2179
|
-
t.importDeclaration(
|
|
2180
|
-
[
|
|
2181
|
-
t.importSpecifier(
|
|
2182
|
-
t.identifier('_TamaguiTheme'),
|
|
2183
|
-
t.identifier('Theme')
|
|
2184
|
-
),
|
|
2185
|
-
],
|
|
2186
|
-
t.stringLiteral('@tamagui/web')
|
|
2187
|
-
)
|
|
2188
|
-
)
|
|
2189
|
-
}
|
|
2190
|
-
|
|
2191
|
-
traversePath.replaceWith(
|
|
2192
|
-
t.jsxElement(
|
|
2193
|
-
t.jsxOpeningElement(t.jsxIdentifier('_TamaguiTheme'), [
|
|
2194
|
-
t.jsxAttribute(t.jsxIdentifier('name'), themeVal.value),
|
|
2195
|
-
]),
|
|
2196
|
-
t.jsxClosingElement(t.jsxIdentifier('_TamaguiTheme')),
|
|
2197
|
-
[traversePath.node]
|
|
2198
|
-
)
|
|
2199
|
-
)
|
|
2200
|
-
}
|
|
2201
|
-
}
|
|
2202
|
-
|
|
2203
|
-
if (shouldPrintDebug) {
|
|
2204
|
-
logger.info(
|
|
2205
|
-
[' - attrs (flattened): \n', logLines(attrs.map(attrStr).join(', '))].join(
|
|
2206
|
-
' '
|
|
2207
|
-
)
|
|
2208
|
-
)
|
|
2209
|
-
}
|
|
2210
|
-
|
|
2211
|
-
function mergeToEnd(obj: object, key: string, val: any) {
|
|
2212
|
-
if (key in obj) {
|
|
2213
|
-
delete obj[key]
|
|
2214
|
-
}
|
|
2215
|
-
obj[key] = val
|
|
2216
|
-
}
|
|
2217
|
-
|
|
2218
|
-
// preserves order
|
|
2219
|
-
function normalizeStyleWithoutVariants(style: any) {
|
|
2220
|
-
let res = {}
|
|
2221
|
-
for (const key in style) {
|
|
2222
|
-
if (staticConfig.variants && key in staticConfig.variants) {
|
|
2223
|
-
mergeToEnd(res, key, style[key])
|
|
2224
|
-
} else {
|
|
2225
|
-
const expanded = normalizeStyle({ [key]: style[key] }, true)
|
|
2226
|
-
for (const key in expanded) {
|
|
2227
|
-
mergeToEnd(res, key, expanded[key])
|
|
2228
|
-
}
|
|
2229
|
-
}
|
|
2230
|
-
}
|
|
2231
|
-
return res
|
|
2232
|
-
}
|
|
2233
|
-
|
|
2234
|
-
// evaluates all static attributes into a simple object
|
|
2235
|
-
let foundStaticProps = {}
|
|
2236
|
-
|
|
2237
|
-
for (const key in attrs) {
|
|
2238
|
-
const cur = attrs[key]
|
|
2239
|
-
if (cur.type === 'style') {
|
|
2240
|
-
// remove variants because they are processed later, and can lead to invalid values here
|
|
2241
|
-
// see <Spacer flex /> where flex looks like a valid style, but is a variant
|
|
2242
|
-
const expanded = normalizeStyleWithoutVariants(cur.value)
|
|
2243
|
-
// preserve order
|
|
2244
|
-
for (const key in expanded) {
|
|
2245
|
-
mergeToEnd(foundStaticProps, key, expanded[key])
|
|
2246
|
-
}
|
|
2247
|
-
continue
|
|
2248
|
-
}
|
|
2249
|
-
if (cur.type === 'attr') {
|
|
2250
|
-
if (t.isJSXSpreadAttribute(cur.value)) {
|
|
2251
|
-
continue
|
|
2252
|
-
}
|
|
2253
|
-
if (!t.isJSXIdentifier(cur.value.name)) {
|
|
2254
|
-
continue
|
|
2255
|
-
}
|
|
2256
|
-
const key = cur.value.name.name
|
|
2257
|
-
// undefined = boolean true
|
|
2258
|
-
const value = attemptEvalSafe(cur.value.value || t.booleanLiteral(true))
|
|
2259
|
-
if (value !== FAILED_EVAL) {
|
|
2260
|
-
mergeToEnd(foundStaticProps, key, value)
|
|
2261
|
-
}
|
|
2262
|
-
}
|
|
2263
|
-
}
|
|
2264
|
-
|
|
2265
|
-
// must preserve exact order
|
|
2266
|
-
const completeProps = {}
|
|
2267
|
-
for (const key in defaultProps) {
|
|
2268
|
-
if (!(key in foundStaticProps)) {
|
|
2269
|
-
completeProps[key] = defaultProps[key]
|
|
2270
|
-
}
|
|
2271
|
-
}
|
|
2272
|
-
for (const key in foundStaticProps) {
|
|
2273
|
-
completeProps[key] = foundStaticProps[key]
|
|
2274
|
-
}
|
|
2275
|
-
|
|
2276
|
-
// expand shorthands, de-opt variables
|
|
2277
|
-
attrs = attrs.reduce<ExtractedAttr[]>((acc, cur) => {
|
|
2278
|
-
if (!cur) return acc
|
|
2279
|
-
if (cur.type === 'attr' && !t.isJSXSpreadAttribute(cur.value)) {
|
|
2280
|
-
if (shouldFlatten) {
|
|
2281
|
-
const name = cur.value.name.name
|
|
2282
|
-
if (typeof name === 'string') {
|
|
2283
|
-
if (name === 'render') {
|
|
2284
|
-
// remove render=""
|
|
2285
|
-
return acc
|
|
2286
|
-
}
|
|
2287
|
-
|
|
2288
|
-
// if flattening, expand variants
|
|
2289
|
-
if (variants[name] && variantValues.has(name)) {
|
|
2290
|
-
const styleState = {
|
|
2291
|
-
...propMapperStyleState,
|
|
2292
|
-
props: completeProps,
|
|
2293
|
-
}
|
|
2294
|
-
|
|
2295
|
-
let out: Record<string, any> = {}
|
|
2296
|
-
propMapper(
|
|
2297
|
-
name,
|
|
2298
|
-
variantValues.get(name),
|
|
2299
|
-
styleState,
|
|
2300
|
-
false,
|
|
2301
|
-
(key, val) => {
|
|
2302
|
-
out[key] = val
|
|
2303
|
-
}
|
|
2304
|
-
)
|
|
2305
|
-
|
|
2306
|
-
if (out && isTargetingHTML) {
|
|
2307
|
-
const cn = out.className
|
|
2308
|
-
// translate to DOM-compat
|
|
2309
|
-
out = reactNativeWebInternals.createDOMProps(
|
|
2310
|
-
isTextView ? 'span' : 'div',
|
|
2311
|
-
out
|
|
2312
|
-
)
|
|
2313
|
-
// remove rnw className use ours
|
|
2314
|
-
out.className = cn
|
|
2315
|
-
// see note in single-prop branch above; createDOMProps
|
|
2316
|
-
// also emits a stray style key here that would duplicate
|
|
2317
|
-
// emitted JSXAttributes downstream.
|
|
2318
|
-
delete out.style
|
|
2319
|
-
}
|
|
2320
|
-
if (shouldPrintDebug) {
|
|
2321
|
-
logger.info([' - expanded variant', name, out].join(' '))
|
|
2322
|
-
}
|
|
2323
|
-
for (const key in out) {
|
|
2324
|
-
const value = out[key]
|
|
2325
|
-
if (isValidStyleKey(key, staticConfig)) {
|
|
2326
|
-
acc.push({
|
|
2327
|
-
type: 'style',
|
|
2328
|
-
value: { [key]: value },
|
|
2329
|
-
name: key,
|
|
2330
|
-
attr: cur.value,
|
|
2331
|
-
} as const)
|
|
2332
|
-
} else {
|
|
2333
|
-
acc.push({
|
|
2334
|
-
type: 'attr',
|
|
2335
|
-
value: t.jsxAttribute(
|
|
2336
|
-
t.jsxIdentifier(key),
|
|
2337
|
-
t.jsxExpressionContainer(
|
|
2338
|
-
typeof value === 'string'
|
|
2339
|
-
? t.stringLiteral(value)
|
|
2340
|
-
: literalToAst(value)
|
|
2341
|
-
)
|
|
2342
|
-
),
|
|
2343
|
-
})
|
|
2344
|
-
}
|
|
2345
|
-
}
|
|
2346
|
-
}
|
|
2347
|
-
}
|
|
2348
|
-
}
|
|
2349
|
-
}
|
|
2350
|
-
|
|
2351
|
-
if (cur.type !== 'style') {
|
|
2352
|
-
acc.push(cur)
|
|
2353
|
-
return acc
|
|
2354
|
-
}
|
|
2355
|
-
|
|
2356
|
-
let key = Object.keys(cur.value)[0]
|
|
2357
|
-
const value = cur.value[key]
|
|
2358
|
-
const fullKey = tamaguiConfig?.shorthands[key]
|
|
2359
|
-
// expand shorthands
|
|
2360
|
-
if (fullKey) {
|
|
2361
|
-
cur.value = { [fullKey]: value }
|
|
2362
|
-
key = fullKey
|
|
2363
|
-
}
|
|
2364
|
-
|
|
2365
|
-
// finally we have all styles + expansions, lets see if we need to skip
|
|
2366
|
-
// any and keep them as attrs
|
|
2367
|
-
if (disableExtractVariables) {
|
|
2368
|
-
if (
|
|
2369
|
-
value[0] === '$' &&
|
|
2370
|
-
(usedThemeKeys.has(key) || usedThemeKeys.has(fullKey))
|
|
2371
|
-
) {
|
|
2372
|
-
if (shouldPrintDebug) {
|
|
2373
|
-
logger.info([` keeping variable inline: ${key} =`, value].join(' '))
|
|
2374
|
-
}
|
|
2375
|
-
acc.push({
|
|
2376
|
-
type: 'attr',
|
|
2377
|
-
value: t.jsxAttribute(
|
|
2378
|
-
t.jsxIdentifier(key),
|
|
2379
|
-
t.jsxExpressionContainer(t.stringLiteral(value))
|
|
2380
|
-
),
|
|
2381
|
-
})
|
|
2382
|
-
return acc
|
|
2383
|
-
}
|
|
2384
|
-
}
|
|
2385
|
-
|
|
2386
|
-
acc.push(cur)
|
|
2387
|
-
return acc
|
|
2388
|
-
}, [])
|
|
2389
|
-
|
|
2390
|
-
tm.mark('jsx-element-expanded', !!shouldPrintDebug)
|
|
2391
|
-
if (shouldPrintDebug) {
|
|
2392
|
-
logger.info(
|
|
2393
|
-
[' - attrs (expanded): \n', logLines(attrs.map(attrStr).join(', '))].join(
|
|
2394
|
-
' '
|
|
2395
|
-
)
|
|
2396
|
-
)
|
|
2397
|
-
}
|
|
2398
|
-
|
|
2399
|
-
// merge styles, leave undefined values
|
|
2400
|
-
let prev: ExtractedAttr | null = null
|
|
2401
|
-
|
|
2402
|
-
function mergeStyles(
|
|
2403
|
-
prev: ViewStyle & PseudoStyles,
|
|
2404
|
-
next: ViewStyle & PseudoStyles
|
|
2405
|
-
) {
|
|
2406
|
-
for (const key in next) {
|
|
2407
|
-
// merge pseudos
|
|
2408
|
-
if (pseudoDescriptors[key]) {
|
|
2409
|
-
prev[key] = prev[key] || {}
|
|
2410
|
-
Object.assign(prev[key], next[key])
|
|
2411
|
-
} else {
|
|
2412
|
-
mergeToEnd(prev, key, next[key])
|
|
2413
|
-
}
|
|
2414
|
-
}
|
|
2415
|
-
}
|
|
2416
|
-
|
|
2417
|
-
// post process
|
|
2418
|
-
const getProps = (
|
|
2419
|
-
props: object | null,
|
|
2420
|
-
includeProps = false,
|
|
2421
|
-
debugName = '',
|
|
2422
|
-
branchProps?: object | null
|
|
2423
|
-
) => {
|
|
2424
|
-
if (!props) {
|
|
2425
|
-
if (shouldPrintDebug) logger.info([' getProps() no props'].join(' '))
|
|
2426
|
-
return {}
|
|
2427
|
-
}
|
|
2428
|
-
if (excludeProps?.size) {
|
|
2429
|
-
for (const key in props) {
|
|
2430
|
-
if (excludeProps.has(key)) {
|
|
2431
|
-
if (shouldPrintDebug) logger.info([' delete excluded', key].join(' '))
|
|
2432
|
-
delete props[key]
|
|
2433
|
-
}
|
|
2434
|
-
}
|
|
2435
|
-
}
|
|
2436
|
-
|
|
2437
|
-
const before = process.env.IS_STATIC
|
|
2438
|
-
process.env.IS_STATIC = 'is_static'
|
|
2439
|
-
try {
|
|
2440
|
-
const fallbackProps = branchProps
|
|
2441
|
-
? { ...completeProps, ...branchProps }
|
|
2442
|
-
: completeProps
|
|
2443
|
-
|
|
2444
|
-
// $group-* / $theme-* keys carry block-form style objects that
|
|
2445
|
-
// getSplitStyles drops in static mode (no parent group context,
|
|
2446
|
-
// no theme value to read). Pluck them out so the atomic-CSS
|
|
2447
|
-
// pipeline in extractToClassNames can emit @container / theme
|
|
2448
|
-
// rules for them directly.
|
|
2449
|
-
let extractedMediaLikeProps: Record<string, any> | null = null
|
|
2450
|
-
let propsForSplit: any = props
|
|
2451
|
-
for (const k in props) {
|
|
2452
|
-
if (
|
|
2453
|
-
k[0] === '$' &&
|
|
2454
|
-
(k.startsWith('$group-') || k.startsWith('$theme-'))
|
|
2455
|
-
) {
|
|
2456
|
-
if (propsForSplit === props) {
|
|
2457
|
-
propsForSplit = { ...props }
|
|
2458
|
-
}
|
|
2459
|
-
if (
|
|
2460
|
-
platform === 'native' &&
|
|
2461
|
-
k.startsWith('$group-') &&
|
|
2462
|
-
getGroupPseudo(k) === 'hover'
|
|
2463
|
-
) {
|
|
2464
|
-
delete propsForSplit[k]
|
|
2465
|
-
continue
|
|
2466
|
-
}
|
|
2467
|
-
extractedMediaLikeProps ||= {}
|
|
2468
|
-
extractedMediaLikeProps[k] = propsForSplit[k]
|
|
2469
|
-
delete propsForSplit[k]
|
|
2470
|
-
}
|
|
2471
|
-
}
|
|
2472
|
-
|
|
2473
|
-
const out = getSplitStyles(
|
|
2474
|
-
propsForSplit,
|
|
2475
|
-
staticConfig,
|
|
2476
|
-
defaultTheme,
|
|
2477
|
-
'',
|
|
2478
|
-
componentState,
|
|
2479
|
-
{
|
|
2480
|
-
...styleProps,
|
|
2481
|
-
noClass: true,
|
|
2482
|
-
fallbackProps,
|
|
2483
|
-
...(platform === 'native' && {
|
|
2484
|
-
resolveValues: 'except-theme',
|
|
2485
|
-
}),
|
|
2486
|
-
},
|
|
2487
|
-
undefined,
|
|
2488
|
-
undefined,
|
|
2489
|
-
undefined,
|
|
2490
|
-
undefined,
|
|
2491
|
-
false,
|
|
2492
|
-
debugPropValue || shouldPrintDebug
|
|
2493
|
-
)!
|
|
2494
|
-
|
|
2495
|
-
// resolve tokens inside the plucked blocks: they skipped the main
|
|
2496
|
-
// split, so values like "$color5" would flow raw into the emitted
|
|
2497
|
-
// CSS where browsers reject the declaration. run each block through
|
|
2498
|
-
// its own static split so tokens become var(--x) references.
|
|
2499
|
-
// (native never extracts these — it deopts below — so web only.)
|
|
2500
|
-
if (extractedMediaLikeProps && platform !== 'native') {
|
|
2501
|
-
for (const k in extractedMediaLikeProps) {
|
|
2502
|
-
const block = extractedMediaLikeProps[k]
|
|
2503
|
-
if (!block || typeof block !== 'object') continue
|
|
2504
|
-
const blockOut = getSplitStyles(
|
|
2505
|
-
block,
|
|
2506
|
-
staticConfig,
|
|
2507
|
-
defaultTheme,
|
|
2508
|
-
'',
|
|
2509
|
-
componentState,
|
|
2510
|
-
{
|
|
2511
|
-
...styleProps,
|
|
2512
|
-
noClass: true,
|
|
2513
|
-
fallbackProps,
|
|
2514
|
-
},
|
|
2515
|
-
undefined,
|
|
2516
|
-
undefined,
|
|
2517
|
-
undefined,
|
|
2518
|
-
undefined,
|
|
2519
|
-
false,
|
|
2520
|
-
debugPropValue || shouldPrintDebug
|
|
2521
|
-
)
|
|
2522
|
-
if (blockOut) {
|
|
2523
|
-
extractedMediaLikeProps[k] = {
|
|
2524
|
-
...blockOut.style,
|
|
2525
|
-
...blockOut.pseudos,
|
|
2526
|
-
}
|
|
2527
|
-
}
|
|
2528
|
-
}
|
|
2529
|
-
}
|
|
2530
|
-
|
|
2531
|
-
let outProps = {
|
|
2532
|
-
...(includeProps ? out.viewProps : {}),
|
|
2533
|
-
...out.style,
|
|
2534
|
-
...out.pseudos,
|
|
2535
|
-
...extractedMediaLikeProps,
|
|
2536
|
-
}
|
|
2537
|
-
|
|
2538
|
-
// check de-opt props again
|
|
2539
|
-
for (const key in outProps) {
|
|
2540
|
-
if (deoptProps.has(key)) {
|
|
2541
|
-
shouldFlatten = false
|
|
2542
|
-
}
|
|
2543
|
-
// native has no atomic-CSS sink for theme- / group- pseudo
|
|
2544
|
-
// blocks; if they flatten they get serialized under the literal
|
|
2545
|
-
// `$theme-…` / `$group-…` key into the RN StyleSheet, where the
|
|
2546
|
-
// runtime's @container / theme-name matching never runs. de-opt
|
|
2547
|
-
// → preserve as inline prop so getSplitStyles handles them at
|
|
2548
|
-
// render time.
|
|
2549
|
-
if (
|
|
2550
|
-
platform === 'native' &&
|
|
2551
|
-
key[0] === '$' &&
|
|
2552
|
-
(key.startsWith('$theme-') ||
|
|
2553
|
-
(key.startsWith('$group-') && getGroupPseudo(key) !== 'hover') ||
|
|
2554
|
-
// same story for a breakpoint a variant brought with it:
|
|
2555
|
-
// native matches media at render time, so there is nothing
|
|
2556
|
-
// to write it to here
|
|
2557
|
-
mediaQueryConfig[key.slice(1)])
|
|
2558
|
-
) {
|
|
2559
|
-
shouldFlatten = false
|
|
2560
|
-
}
|
|
2561
|
-
}
|
|
2562
|
-
|
|
2563
|
-
if (shouldPrintDebug) {
|
|
2564
|
-
logger.info(`(${debugName})`)
|
|
2565
|
-
// prettier-ignore
|
|
2566
|
-
logger.info(`\n getProps (props in): ${logLines(objToStr(props))}`)
|
|
2567
|
-
// prettier-ignore
|
|
2568
|
-
logger.info(
|
|
2569
|
-
`\n getProps (outProps): ${logLines(objToStr(outProps))}`
|
|
2570
|
-
)
|
|
2571
|
-
}
|
|
2572
|
-
|
|
2573
|
-
if (out.fontFamily) {
|
|
2574
|
-
setPropsToFontFamily(outProps, out.fontFamily)
|
|
2575
|
-
if (shouldPrintDebug) {
|
|
2576
|
-
logger.info(`\n 💬 new font fam: ${out.fontFamily}`)
|
|
2577
|
-
}
|
|
2578
|
-
}
|
|
2579
|
-
|
|
2580
|
-
return outProps
|
|
2581
|
-
} catch (err: any) {
|
|
2582
|
-
logger.info(['error', err.message, err.stack].join(' '))
|
|
2583
|
-
return {}
|
|
2584
|
-
} finally {
|
|
2585
|
-
process.env.IS_STATIC = before
|
|
2586
|
-
}
|
|
2587
|
-
}
|
|
2588
|
-
|
|
2589
|
-
// add default props
|
|
2590
|
-
attrs.unshift({
|
|
2591
|
-
type: 'style',
|
|
2592
|
-
value: defaultProps,
|
|
2593
|
-
})
|
|
2594
|
-
|
|
2595
|
-
attrs = attrs.reduce<ExtractedAttr[]>((acc, cur) => {
|
|
2596
|
-
if (cur.type === 'style') {
|
|
2597
|
-
const keys = Object.keys(cur.value || {})
|
|
2598
|
-
if (!keys.length) {
|
|
2599
|
-
return acc
|
|
2600
|
-
}
|
|
2601
|
-
const key = keys[0]
|
|
2602
|
-
const value = cur.value[key]
|
|
2603
|
-
|
|
2604
|
-
// Check if this is a media-like key ($theme-, $platform-, $group-, or $mediaQuery)
|
|
2605
|
-
const isMediaLikeKey =
|
|
2606
|
-
key[0] === '$' &&
|
|
2607
|
-
(key.startsWith('$theme-') ||
|
|
2608
|
-
key.startsWith('$platform-') ||
|
|
2609
|
-
key.startsWith('$group-') ||
|
|
2610
|
-
mediaQueryConfig[key.slice(1)])
|
|
2611
|
-
|
|
2612
|
-
const shouldKeepOriginalAttr =
|
|
2613
|
-
// !isStyleAndAttr[key] &&
|
|
2614
|
-
!shouldFlatten &&
|
|
2615
|
-
// de-opt if non-style
|
|
2616
|
-
!validStyles[key] &&
|
|
2617
|
-
!pseudoDescriptors[key] &&
|
|
2618
|
-
!isMediaLikeKey &&
|
|
2619
|
-
!(key.startsWith('data-') || key.startsWith('aria-'))
|
|
2620
|
-
|
|
2621
|
-
if (shouldKeepOriginalAttr) {
|
|
2622
|
-
if (shouldPrintDebug) {
|
|
2623
|
-
logger.info([' - keeping as non-style', key].join(' '))
|
|
2624
|
-
}
|
|
2625
|
-
prev = cur
|
|
2626
|
-
acc.push({
|
|
2627
|
-
type: 'attr',
|
|
2628
|
-
value: t.jsxAttribute(
|
|
2629
|
-
t.jsxIdentifier(key),
|
|
2630
|
-
t.jsxExpressionContainer(
|
|
2631
|
-
typeof value === 'string'
|
|
2632
|
-
? t.stringLiteral(value)
|
|
2633
|
-
: literalToAst(value)
|
|
2634
|
-
)
|
|
2635
|
-
),
|
|
2636
|
-
})
|
|
2637
|
-
acc.push(cur)
|
|
2638
|
-
return acc
|
|
2639
|
-
}
|
|
2640
|
-
|
|
2641
|
-
if (prev?.type === 'style') {
|
|
2642
|
-
mergeStyles(prev.value, cur.value)
|
|
2643
|
-
return acc
|
|
2644
|
-
}
|
|
2645
|
-
}
|
|
2646
|
-
|
|
2647
|
-
if (cur.type === 'style') {
|
|
2648
|
-
prev = cur
|
|
2649
|
-
}
|
|
2650
|
-
acc.push(cur)
|
|
2651
|
-
return acc
|
|
2652
|
-
}, [])
|
|
2653
|
-
|
|
2654
|
-
if (shouldPrintDebug) {
|
|
2655
|
-
logger.info(
|
|
2656
|
-
[
|
|
2657
|
-
' - attrs (combined 🔀): \n',
|
|
2658
|
-
logLines(attrs.map(attrStr).join(', ')),
|
|
2659
|
-
].join(' ')
|
|
2660
|
-
)
|
|
2661
|
-
}
|
|
2662
|
-
|
|
2663
|
-
let getStyleError: any = null
|
|
2664
|
-
|
|
2665
|
-
// a variant can carry its own media blocks ($md/$lg inside a variant
|
|
2666
|
-
// value). getSplitStyles leaves those nested rather than folding them
|
|
2667
|
-
// into the flat style, so hand them to the same media path a $md/$lg
|
|
2668
|
-
// prop takes. they go on the end because a variant is a prop, and so
|
|
2669
|
-
// outranks the media the styled() frame declared in its defaults.
|
|
2670
|
-
const mediaFromVariants: ExtractedAttr[] = []
|
|
2671
|
-
|
|
2672
|
-
// fix up ternaries, combine final style values
|
|
2673
|
-
for (const attr of attrs) {
|
|
2674
|
-
try {
|
|
2675
|
-
if (shouldPrintDebug) {
|
|
2676
|
-
console.info(` Processing ${attr.type}:`)
|
|
2677
|
-
}
|
|
2678
|
-
|
|
2679
|
-
switch (attr.type) {
|
|
2680
|
-
case 'ternary': {
|
|
2681
|
-
const branchProps = ternaryBranchProps.get(
|
|
2682
|
-
getTernaryKey(attr.value.test)
|
|
2683
|
-
)
|
|
2684
|
-
const a = getProps(
|
|
2685
|
-
attr.value.alternate,
|
|
2686
|
-
false,
|
|
2687
|
-
'ternary.alternate',
|
|
2688
|
-
branchProps?.alternate
|
|
2689
|
-
)
|
|
2690
|
-
const c = getProps(
|
|
2691
|
-
attr.value.consequent,
|
|
2692
|
-
false,
|
|
2693
|
-
'ternary.consequent',
|
|
2694
|
-
branchProps?.consequent
|
|
2695
|
-
)
|
|
2696
|
-
if (a) attr.value.alternate = a
|
|
2697
|
-
if (c) attr.value.consequent = c
|
|
2698
|
-
if (shouldPrintDebug)
|
|
2699
|
-
logger.info([' => tern ', attrStr(attr)].join(' '))
|
|
2700
|
-
continue
|
|
2701
|
-
}
|
|
2702
|
-
case 'style': {
|
|
2703
|
-
// expand variants and such
|
|
2704
|
-
const styles = getProps(attr.value, false, 'style')
|
|
2705
|
-
if (styles) {
|
|
2706
|
-
for (const key in styles) {
|
|
2707
|
-
if (key[0] !== '$') continue
|
|
2708
|
-
const mediaKey = key.slice(1)
|
|
2709
|
-
if (!mediaQueryConfig[mediaKey]) continue
|
|
2710
|
-
mediaFromVariants.push({
|
|
2711
|
-
type: 'ternary',
|
|
2712
|
-
value: {
|
|
2713
|
-
inlineMediaQuery: mediaKey,
|
|
2714
|
-
test: t.stringLiteral(mediaKey),
|
|
2715
|
-
consequent: styles[key],
|
|
2716
|
-
alternate: null,
|
|
2717
|
-
remove() {},
|
|
2718
|
-
},
|
|
2719
|
-
})
|
|
2720
|
-
delete styles[key]
|
|
2721
|
-
}
|
|
2722
|
-
// @ts-ignore
|
|
2723
|
-
attr.value = styles
|
|
2724
|
-
}
|
|
2725
|
-
// prettier-ignore
|
|
2726
|
-
if (shouldPrintDebug)
|
|
2727
|
-
logger.info(
|
|
2728
|
-
[' * styles (in)', logLines(objToStr(attr.value))].join(' ')
|
|
2729
|
-
)
|
|
2730
|
-
// prettier-ignore
|
|
2731
|
-
if (shouldPrintDebug)
|
|
2732
|
-
logger.info(
|
|
2733
|
-
[' * styles (out)', logLines(objToStr(styles))].join(' ')
|
|
2734
|
-
)
|
|
2735
|
-
continue
|
|
2736
|
-
}
|
|
2737
|
-
case 'attr': {
|
|
2738
|
-
if (shouldFlatten && t.isJSXAttribute(attr.value)) {
|
|
2739
|
-
// we know all attributes are static
|
|
2740
|
-
// this only does one at a time but it should really do the whole group together...
|
|
2741
|
-
// also awkward to be doing it using jsxAttributes...
|
|
2742
|
-
const key = attr.value.name.name as string
|
|
2743
|
-
|
|
2744
|
-
// dont process style/className can just stay attrs
|
|
2745
|
-
if (key === 'style' || key === 'className' || key === 'render') {
|
|
2746
|
-
continue
|
|
2747
|
-
}
|
|
2748
|
-
|
|
2749
|
-
// undefined = boolean true
|
|
2750
|
-
const value = attemptEvalSafe(
|
|
2751
|
-
attr.value.value || t.booleanLiteral(true)
|
|
2752
|
-
)
|
|
2753
|
-
if (value !== FAILED_EVAL) {
|
|
2754
|
-
const outProps = getProps({ [key]: value }, true, `attr.${key}`)
|
|
2755
|
-
const outKey = Object.keys(outProps)[0]
|
|
2756
|
-
if (outKey) {
|
|
2757
|
-
const outVal = outProps[outKey]
|
|
2758
|
-
attr.value = t.jsxAttribute(
|
|
2759
|
-
t.jsxIdentifier(outKey),
|
|
2760
|
-
t.jsxExpressionContainer(
|
|
2761
|
-
typeof outVal === 'string'
|
|
2762
|
-
? t.stringLiteral(outVal)
|
|
2763
|
-
: literalToAst(outVal)
|
|
2764
|
-
)
|
|
2765
|
-
)
|
|
2766
|
-
}
|
|
2767
|
-
}
|
|
2768
|
-
}
|
|
2769
|
-
}
|
|
2770
|
-
}
|
|
2771
|
-
} catch (err) {
|
|
2772
|
-
// any error de-opt
|
|
2773
|
-
getStyleError = err
|
|
2774
|
-
}
|
|
2775
|
-
}
|
|
2776
|
-
|
|
2777
|
-
if (mediaFromVariants.length) {
|
|
2778
|
-
attrs.push(...mediaFromVariants)
|
|
2779
|
-
}
|
|
2780
|
-
|
|
2781
|
-
if (shouldPrintDebug) {
|
|
2782
|
-
// prettier-ignore
|
|
2783
|
-
logger.info(
|
|
2784
|
-
[
|
|
2785
|
-
' - attrs (ternaries/combined):\n',
|
|
2786
|
-
logLines(attrs.map(attrStr).join(', ')),
|
|
2787
|
-
].join(' ')
|
|
2788
|
-
)
|
|
2789
|
-
}
|
|
2790
|
-
|
|
2791
|
-
tm.mark('jsx-element-styles', !!shouldPrintDebug)
|
|
2792
|
-
|
|
2793
|
-
if (getStyleError) {
|
|
2794
|
-
logger.info([' ⚠️ postprocessing error, deopt', getStyleError].join(' '))
|
|
2795
|
-
node.attributes = ogAttributes
|
|
2796
|
-
return null
|
|
2797
|
-
}
|
|
2798
|
-
|
|
2799
|
-
// final lazy extra loop:
|
|
2800
|
-
const existingStyleKeys = new Set()
|
|
2801
|
-
for (let i = attrs.length - 1; i >= 0; i--) {
|
|
2802
|
-
const attr = attrs[i]
|
|
2803
|
-
|
|
2804
|
-
// if flattening map inline props to proper flattened names
|
|
2805
|
-
if (shouldFlatten) {
|
|
2806
|
-
if (attr.type === 'attr') {
|
|
2807
|
-
if (t.isJSXAttribute(attr.value)) {
|
|
2808
|
-
if (t.isJSXIdentifier(attr.value.name)) {
|
|
2809
|
-
const name = attr.value.name.name
|
|
2810
|
-
if (INLINE_EXTRACTABLE[name]) {
|
|
2811
|
-
// map to HTML only name
|
|
2812
|
-
attr.value.name.name = INLINE_EXTRACTABLE[name]
|
|
2813
|
-
}
|
|
2814
|
-
}
|
|
2815
|
-
}
|
|
2816
|
-
}
|
|
2817
|
-
}
|
|
2818
|
-
|
|
2819
|
-
// remove duplicate styles
|
|
2820
|
-
// so if you have:
|
|
2821
|
-
// style({ color: 'red' }), ...someProps, style({ color: 'green' })
|
|
2822
|
-
// this will mutate:
|
|
2823
|
-
// style({}), ...someProps, style({ color: 'green' })
|
|
2824
|
-
if (attr.type === 'style') {
|
|
2825
|
-
for (const key in attr.value) {
|
|
2826
|
-
if (existingStyleKeys.has(key)) {
|
|
2827
|
-
if (shouldPrintDebug) {
|
|
2828
|
-
logger.info([` >> delete existing ${key}`].join(' '))
|
|
2829
|
-
}
|
|
2830
|
-
delete attr.value[key]
|
|
2831
|
-
} else {
|
|
2832
|
-
existingStyleKeys.add(key)
|
|
2833
|
-
}
|
|
2834
|
-
}
|
|
2835
|
-
}
|
|
2836
|
-
}
|
|
2837
|
-
|
|
2838
|
-
attrs = attrs.filter(Boolean)
|
|
2839
|
-
|
|
2840
|
-
// inlineWhenUnflattened
|
|
2841
|
-
if (!shouldFlatten) {
|
|
2842
|
-
if (inlineWhenUnflattened.size) {
|
|
2843
|
-
for (const [index, attr] of attrs.entries()) {
|
|
2844
|
-
if (attr.type === 'style') {
|
|
2845
|
-
for (const key in attr.value) {
|
|
2846
|
-
if (!inlineWhenUnflattened.has(key)) continue
|
|
2847
|
-
const val = inlineWhenUnflattenedOGVals[key]
|
|
2848
|
-
if (val) {
|
|
2849
|
-
// delete the style
|
|
2850
|
-
delete attr.value[key]
|
|
2851
|
-
|
|
2852
|
-
// and insert it before
|
|
2853
|
-
attrs.splice(index - 1, 0, val.attr)
|
|
2854
|
-
} else {
|
|
2855
|
-
// just delete it, it was added during expansion but should be left inline
|
|
2856
|
-
delete attr.value[key]
|
|
2857
|
-
}
|
|
2858
|
-
}
|
|
2859
|
-
}
|
|
2860
|
-
}
|
|
2861
|
-
}
|
|
2862
|
-
}
|
|
2863
|
-
|
|
2864
|
-
// delete empty styles:
|
|
2865
|
-
attrs = attrs.filter((x) => {
|
|
2866
|
-
if (x.type === 'style' && Object.keys(x.value).length === 0) {
|
|
2867
|
-
return false
|
|
2868
|
-
}
|
|
2869
|
-
return true
|
|
2870
|
-
})
|
|
2871
|
-
|
|
2872
|
-
const isNativeNotFlat = !shouldFlatten && platform === 'native'
|
|
2873
|
-
if (isNativeNotFlat) {
|
|
2874
|
-
if (shouldPrintDebug) {
|
|
2875
|
-
logger.info(
|
|
2876
|
-
`Disabled flattening except for simple cases on native for now: ${JSON.stringify(
|
|
2877
|
-
{
|
|
2878
|
-
flatNode: flatNodeName,
|
|
2879
|
-
shouldDeopt,
|
|
2880
|
-
canFlattenProps,
|
|
2881
|
-
hasSpread,
|
|
2882
|
-
'staticConfig.isStyledHOC': staticConfig.isStyledHOC,
|
|
2883
|
-
'!staticConfig.isHOC': !staticConfig.isHOC,
|
|
2884
|
-
'staticConfig.isReactNative': staticConfig.isReactNative,
|
|
2885
|
-
'staticConfig.neverFlatten': staticConfig.neverFlatten,
|
|
2886
|
-
},
|
|
2887
|
-
null,
|
|
2888
|
-
2
|
|
2889
|
-
)}`
|
|
2890
|
-
)
|
|
2891
|
-
}
|
|
2892
|
-
node.attributes = ogAttributes
|
|
2893
|
-
return null
|
|
2894
|
-
}
|
|
2895
|
-
|
|
2896
|
-
if (shouldPrintDebug) {
|
|
2897
|
-
// prettier-ignore
|
|
2898
|
-
logger.info(
|
|
2899
|
-
[
|
|
2900
|
-
` - inlined props (${inlined.size}):`,
|
|
2901
|
-
shouldDeopt ? ' deopted' : '',
|
|
2902
|
-
hasSpread ? ' has spread' : '',
|
|
2903
|
-
staticConfig.neverFlatten ? 'neverFlatten' : '',
|
|
2904
|
-
].join(' ')
|
|
2905
|
-
)
|
|
2906
|
-
logger.info(` - attrs (end):\n ${logLines(attrs.map(attrStr).join(', '))}`)
|
|
2907
|
-
}
|
|
2908
|
-
|
|
2909
|
-
onExtractTag({
|
|
2910
|
-
parserProps: propsWithFileInfo,
|
|
2911
|
-
attrs,
|
|
2912
|
-
node,
|
|
2913
|
-
lineNumbers,
|
|
2914
|
-
filePath,
|
|
2915
|
-
config: tamaguiConfig!,
|
|
2916
|
-
flatNodeName,
|
|
2917
|
-
attemptEval,
|
|
2918
|
-
jsxPath: traversePath,
|
|
2919
|
-
originalNodeName,
|
|
2920
|
-
programPath: programPath!,
|
|
2921
|
-
completeProps,
|
|
2922
|
-
staticConfig,
|
|
2923
|
-
})
|
|
2924
|
-
|
|
2925
|
-
if (shouldFlatten) {
|
|
2926
|
-
if (shouldPrintDebug) {
|
|
2927
|
-
logger.info([' [✅] flattened', originalNodeName, flatNodeName].join(' '))
|
|
2928
|
-
}
|
|
2929
|
-
// Only rename if onExtractTag hasn't already renamed to a custom wrapper
|
|
2930
|
-
// @ts-ignore - check if already renamed by callback (e.g., to a styled wrapper)
|
|
2931
|
-
const currentName = node.name?.name
|
|
2932
|
-
if (
|
|
2933
|
-
!currentName ||
|
|
2934
|
-
currentName === originalNodeName ||
|
|
2935
|
-
currentName.startsWith('__ReactNative')
|
|
2936
|
-
) {
|
|
2937
|
-
// @ts-ignore
|
|
2938
|
-
node.name.name = flatNodeName
|
|
2939
|
-
if (closingElement) {
|
|
2940
|
-
// @ts-ignore
|
|
2941
|
-
closingElement.name.name = flatNodeName
|
|
2942
|
-
}
|
|
2943
|
-
}
|
|
2944
|
-
res.flattened++
|
|
2945
|
-
}
|
|
2946
|
-
} catch (err: any) {
|
|
2947
|
-
node.attributes = ogAttributes
|
|
2948
|
-
|
|
2949
|
-
if (!(err instanceof BailOptimizationError)) {
|
|
2950
|
-
console.error(
|
|
2951
|
-
`@tamagui/static error, reverting optimization. In ${filePath} ${lineNumbers} on ${originalNodeName}: ${err.message}. For stack trace set environment TAMAGUI_DEBUG=1`
|
|
2952
|
-
)
|
|
2953
|
-
if (process.env.TAMAGUI_DEBUG === '1') {
|
|
2954
|
-
console.error(err.stack)
|
|
2955
|
-
}
|
|
2956
|
-
}
|
|
2957
|
-
} finally {
|
|
2958
|
-
if (debugPropValue) {
|
|
2959
|
-
shouldPrintDebug = ogDebug
|
|
2960
|
-
}
|
|
2961
|
-
}
|
|
2962
|
-
},
|
|
2963
|
-
})
|
|
2964
|
-
|
|
2965
|
-
tm.mark('jsx-done', !!shouldPrintDebug)
|
|
2966
|
-
tm.done(shouldPrintDebug === 'verbose')
|
|
2967
|
-
|
|
2968
|
-
return res
|
|
2969
|
-
}
|
|
2970
|
-
}
|