@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
|
@@ -0,0 +1,478 @@
|
|
|
1
|
+
import {
|
|
2
|
+
childNode,
|
|
3
|
+
childNodes,
|
|
4
|
+
resolvedModuleId,
|
|
5
|
+
walkAst,
|
|
6
|
+
zeroRuleMessage,
|
|
7
|
+
type AstNode,
|
|
8
|
+
type SourceEdit,
|
|
9
|
+
type ZeroViolation,
|
|
10
|
+
} from '@tamagui/compiler-core'
|
|
11
|
+
import { getThemeClassNames, reservedThemeProps } from '@tamagui/helpers'
|
|
12
|
+
import {
|
|
13
|
+
getInlineValuesFromProps,
|
|
14
|
+
getVariablesCSSRules,
|
|
15
|
+
resolveThemeName,
|
|
16
|
+
variableToString,
|
|
17
|
+
type InlineValueIssue,
|
|
18
|
+
type TamaguiInternalConfig,
|
|
19
|
+
} from '@tamagui/web'
|
|
20
|
+
|
|
21
|
+
import type { IslandThemeBridgeLayer } from './islands'
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Static `<Theme>` lowering.
|
|
25
|
+
*
|
|
26
|
+
* A `<Theme>` node is markup plus classes and nothing else once its name and its
|
|
27
|
+
* direct theme-key values are known at build time. This resolves the name the
|
|
28
|
+
* way the runtime resolves it, emits the same span the runtime emits, and turns
|
|
29
|
+
* every value the parser cannot use into a violation rather than the warn-and-
|
|
30
|
+
* drop the render path does.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* One branch of a `<Theme name>`. `test` is the source text of the condition
|
|
35
|
+
* that selects it, or null for the unconditional branch. A literal name is one
|
|
36
|
+
* option with a null test.
|
|
37
|
+
*/
|
|
38
|
+
export interface ThemeNameOption {
|
|
39
|
+
test: string | null
|
|
40
|
+
name: string | undefined
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface StaticThemeNode {
|
|
44
|
+
element: AstNode
|
|
45
|
+
opening: AstNode
|
|
46
|
+
closing: AstNode | null
|
|
47
|
+
options: ThemeNameOption[]
|
|
48
|
+
reset: boolean
|
|
49
|
+
contain: boolean
|
|
50
|
+
/** The compiled inline-value layer, when the node carries theme-key props. */
|
|
51
|
+
layer: IslandThemeBridgeLayer | null
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* The most branches one element's chain may enumerate.
|
|
56
|
+
*
|
|
57
|
+
* Rule 4 says a theme name must be statically enumerable, not that it must be
|
|
58
|
+
* literal. A chain of conditionals is still enumerable, but the emitted
|
|
59
|
+
* expression is one branch per combination, so it has to stop somewhere: past
|
|
60
|
+
* this the authored tree is asking for runtime theme state with extra steps.
|
|
61
|
+
*/
|
|
62
|
+
const MAX_THEME_BRANCHES = 8
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Reserved `<Theme>` props zero mode lowers. Everything else on the table is
|
|
66
|
+
* runtime behavior with no compiled form, including a `children` prop: the
|
|
67
|
+
* lowered span carries the element's body, not an attribute.
|
|
68
|
+
*/
|
|
69
|
+
const LOWERABLE_RESERVED_PROPS = new Set(['name', 'reset', 'contain'])
|
|
70
|
+
|
|
71
|
+
function jsxAttributeName(attribute: AstNode): string | null {
|
|
72
|
+
const name = childNode(attribute, 'name')
|
|
73
|
+
return name && typeof name.name === 'string' ? name.name : null
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function literalOf(node: AstNode | null): string | number | boolean | null | undefined {
|
|
77
|
+
if (!node) return undefined
|
|
78
|
+
if (node.type === 'Literal' && typeof node.value !== 'object') {
|
|
79
|
+
return node.value as string | number | boolean | null
|
|
80
|
+
}
|
|
81
|
+
return undefined
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* True when evaluating this expression twice could do something. The lowered
|
|
86
|
+
* className and style attributes each repeat the condition, so a condition that
|
|
87
|
+
* calls, assigns, or awaits would run more times than the author wrote it.
|
|
88
|
+
*/
|
|
89
|
+
function hasSideEffects(node: AstNode): boolean {
|
|
90
|
+
let found = false
|
|
91
|
+
walkAst(node, (child) => {
|
|
92
|
+
if (
|
|
93
|
+
child.type === 'CallExpression' ||
|
|
94
|
+
child.type === 'OptionalCallExpression' ||
|
|
95
|
+
child.type === 'NewExpression' ||
|
|
96
|
+
child.type === 'AwaitExpression' ||
|
|
97
|
+
child.type === 'YieldExpression' ||
|
|
98
|
+
child.type === 'AssignmentExpression' ||
|
|
99
|
+
child.type === 'UpdateExpression' ||
|
|
100
|
+
child.type === 'TaggedTemplateExpression'
|
|
101
|
+
) {
|
|
102
|
+
found = true
|
|
103
|
+
}
|
|
104
|
+
})
|
|
105
|
+
return found
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Reads a `name` value into its branches. A literal is one branch; a conditional
|
|
110
|
+
* over literal names is one branch per arm, nested conditionals included.
|
|
111
|
+
*/
|
|
112
|
+
function readNameOptions(
|
|
113
|
+
value: AstNode,
|
|
114
|
+
source: string,
|
|
115
|
+
guards: string[]
|
|
116
|
+
): ThemeNameOption[] | null {
|
|
117
|
+
const literal = literalOf(value)
|
|
118
|
+
if (typeof literal === 'string') {
|
|
119
|
+
return [{ test: guards.length ? guards.join(' && ') : null, name: literal }]
|
|
120
|
+
}
|
|
121
|
+
if (value.type === 'ConditionalExpression') {
|
|
122
|
+
const test = childNode(value, 'test')
|
|
123
|
+
const consequent = childNode(value, 'consequent')
|
|
124
|
+
const alternate = childNode(value, 'alternate')
|
|
125
|
+
if (!test || !consequent || !alternate) return null
|
|
126
|
+
if (hasSideEffects(test)) return null
|
|
127
|
+
const testText = source.slice(test.start, test.end).replace(/\s+/g, ' ').trim()
|
|
128
|
+
const left = readNameOptions(consequent, source, [...guards, `(${testText})`])
|
|
129
|
+
const right = readNameOptions(alternate, source, [...guards, `!(${testText})`])
|
|
130
|
+
if (!left || !right) return null
|
|
131
|
+
return [...left, ...right]
|
|
132
|
+
}
|
|
133
|
+
return null
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Folds one value per branch into a single expression. The branches are the
|
|
138
|
+
* product in authored order and the last one is exhaustive, so it is the
|
|
139
|
+
* ternary's else. Branches that agree collapse to a literal, which is what makes
|
|
140
|
+
* an ordinary literal `<Theme name="dark">` emit a plain string.
|
|
141
|
+
*/
|
|
142
|
+
export function foldBranches(branches: { test: string | null; value: string }[]): string {
|
|
143
|
+
const last = branches[branches.length - 1]!
|
|
144
|
+
if (new Set(branches.map((branch) => branch.value)).size === 1) return last.value
|
|
145
|
+
let expression = last.value
|
|
146
|
+
for (let index = branches.length - 2; index >= 0; index--) {
|
|
147
|
+
const branch = branches[index]!
|
|
148
|
+
expression =
|
|
149
|
+
branch.test === null
|
|
150
|
+
? branch.value
|
|
151
|
+
: `${branch.test} ? ${branch.value} : ${expression}`
|
|
152
|
+
}
|
|
153
|
+
return expression
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** One resolved theme name, with the guard that selects it. */
|
|
157
|
+
export interface ThemeBranch {
|
|
158
|
+
test: string | null
|
|
159
|
+
name: string
|
|
160
|
+
isNew: boolean
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Every theme name an element's `<Theme>` ancestry can resolve to.
|
|
165
|
+
*
|
|
166
|
+
* The chain is root-most first and includes the element's own node when it has
|
|
167
|
+
* one. Each node contributes its branches; the result is their product, walked
|
|
168
|
+
* in authored order so a nested `<Theme name="blue">` resolves against whatever
|
|
169
|
+
* its parent resolved to, exactly as `resolveThemeName` does at runtime.
|
|
170
|
+
*/
|
|
171
|
+
export function resolveThemeChain(
|
|
172
|
+
chain: readonly StaticThemeNode[],
|
|
173
|
+
rootThemeName: string,
|
|
174
|
+
config: TamaguiInternalConfig
|
|
175
|
+
): ThemeBranch[] {
|
|
176
|
+
let branches: ThemeBranch[] = [{ test: null, name: rootThemeName, isNew: false }]
|
|
177
|
+
for (const node of chain) {
|
|
178
|
+
const next: typeof branches = []
|
|
179
|
+
for (const parent of branches) {
|
|
180
|
+
for (const option of node.options) {
|
|
181
|
+
const resolved = resolveThemeName(
|
|
182
|
+
parent.name,
|
|
183
|
+
option.name,
|
|
184
|
+
node.reset,
|
|
185
|
+
config.themes as Record<string, any>
|
|
186
|
+
)
|
|
187
|
+
const tests = [parent.test, option.test].filter(Boolean)
|
|
188
|
+
next.push({
|
|
189
|
+
test: tests.length ? tests.join(' && ') : null,
|
|
190
|
+
name: resolved ?? parent.name,
|
|
191
|
+
isNew: resolved !== null,
|
|
192
|
+
})
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
branches = next
|
|
196
|
+
}
|
|
197
|
+
return branches
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export interface StaticThemeReadResult {
|
|
201
|
+
node: StaticThemeNode | null
|
|
202
|
+
violations: ZeroViolation[]
|
|
203
|
+
/** The CSS rules the node's inline values need, keyed by their class name. */
|
|
204
|
+
css: Map<string, string>
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Reads one `<Theme>` element into its static description.
|
|
209
|
+
*
|
|
210
|
+
* Prop classification is `reservedThemeProps`, the same table the runtime reads,
|
|
211
|
+
* so a name that becomes reserved later cannot mean a theme key here and a
|
|
212
|
+
* reserved prop there.
|
|
213
|
+
*/
|
|
214
|
+
export function readStaticTheme(
|
|
215
|
+
element: AstNode,
|
|
216
|
+
id: string,
|
|
217
|
+
source: string,
|
|
218
|
+
config: TamaguiInternalConfig
|
|
219
|
+
): StaticThemeReadResult {
|
|
220
|
+
const moduleId = resolvedModuleId(id)
|
|
221
|
+
const violations: ZeroViolation[] = []
|
|
222
|
+
const css = new Map<string, string>()
|
|
223
|
+
const opening = childNode(element, 'openingElement')!
|
|
224
|
+
const closing = childNode(element, 'closingElement')
|
|
225
|
+
|
|
226
|
+
const span = (node: AstNode) => ({ id: moduleId, start: node.start, end: node.end })
|
|
227
|
+
|
|
228
|
+
let options: ThemeNameOption[] = [{ test: null, name: undefined }]
|
|
229
|
+
let reset = false
|
|
230
|
+
let contain = false
|
|
231
|
+
const themeKeyProps: Record<string, string | number> = {}
|
|
232
|
+
|
|
233
|
+
for (const attribute of childNodes(opening, 'attributes')) {
|
|
234
|
+
if (attribute.type !== 'JSXAttribute') {
|
|
235
|
+
violations.push({
|
|
236
|
+
rule: 1,
|
|
237
|
+
code: 'local/unsafe-style-spread',
|
|
238
|
+
span: span(attribute),
|
|
239
|
+
component: 'Theme',
|
|
240
|
+
message: zeroRuleMessage(1, { component: 'Theme' }),
|
|
241
|
+
})
|
|
242
|
+
continue
|
|
243
|
+
}
|
|
244
|
+
const key = jsxAttributeName(attribute)
|
|
245
|
+
if (!key) continue
|
|
246
|
+
const rawValue = childNode(attribute, 'value')
|
|
247
|
+
const value =
|
|
248
|
+
rawValue && rawValue.type === 'JSXExpressionContainer'
|
|
249
|
+
? childNode(rawValue, 'expression')
|
|
250
|
+
: rawValue
|
|
251
|
+
|
|
252
|
+
if (key === 'name') {
|
|
253
|
+
const read = value ? readNameOptions(value, source, []) : null
|
|
254
|
+
if (!read) {
|
|
255
|
+
violations.push({
|
|
256
|
+
rule: 4,
|
|
257
|
+
code: 'local/unsupported-target',
|
|
258
|
+
span: span(attribute),
|
|
259
|
+
component: 'Theme',
|
|
260
|
+
message: zeroRuleMessage(4, {
|
|
261
|
+
detail: `the <Theme name> value ${source
|
|
262
|
+
.slice(attribute.start, attribute.end)
|
|
263
|
+
.replace(/\s+/g, ' ')
|
|
264
|
+
.trim()}, which is not a literal theme name or a conditional over literal theme names,`,
|
|
265
|
+
}),
|
|
266
|
+
})
|
|
267
|
+
continue
|
|
268
|
+
}
|
|
269
|
+
options = read
|
|
270
|
+
continue
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (reservedThemeProps[key]) {
|
|
274
|
+
if (!LOWERABLE_RESERVED_PROPS.has(key)) {
|
|
275
|
+
violations.push({
|
|
276
|
+
rule: 4,
|
|
277
|
+
code: 'local/unsupported-target',
|
|
278
|
+
span: span(attribute),
|
|
279
|
+
component: 'Theme',
|
|
280
|
+
message: zeroRuleMessage(4, {
|
|
281
|
+
detail: `the <Theme ${key}> prop, which has no compiled form,`,
|
|
282
|
+
}),
|
|
283
|
+
})
|
|
284
|
+
continue
|
|
285
|
+
}
|
|
286
|
+
// presence is the value for a bare boolean attribute
|
|
287
|
+
const literal = value ? literalOf(value) : true
|
|
288
|
+
if (typeof literal !== 'boolean') {
|
|
289
|
+
violations.push({
|
|
290
|
+
rule: 4,
|
|
291
|
+
code: 'local/unsupported-target',
|
|
292
|
+
span: span(attribute),
|
|
293
|
+
component: 'Theme',
|
|
294
|
+
message: zeroRuleMessage(4, {
|
|
295
|
+
detail: `a non-literal <Theme ${key}> value,`,
|
|
296
|
+
}),
|
|
297
|
+
})
|
|
298
|
+
continue
|
|
299
|
+
}
|
|
300
|
+
if (key === 'reset') reset = literal
|
|
301
|
+
if (key === 'contain') contain = literal
|
|
302
|
+
continue
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// everything else is a theme key, and its value has to be build-time data
|
|
306
|
+
const literal = value ? literalOf(value) : undefined
|
|
307
|
+
if (typeof literal !== 'string' && typeof literal !== 'number') {
|
|
308
|
+
violations.push({
|
|
309
|
+
rule: 3,
|
|
310
|
+
code: 'local/dynamic-style-value',
|
|
311
|
+
span: span(attribute),
|
|
312
|
+
component: 'Theme',
|
|
313
|
+
message: zeroRuleMessage(3, {
|
|
314
|
+
prop: key,
|
|
315
|
+
component: 'Theme',
|
|
316
|
+
detail: value
|
|
317
|
+
? 'a theme value must be a string or number literal at build time'
|
|
318
|
+
: 'a theme key needs a value',
|
|
319
|
+
}),
|
|
320
|
+
})
|
|
321
|
+
continue
|
|
322
|
+
}
|
|
323
|
+
themeKeyProps[key] = literal
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// the runtime throws on this pair rather than picking one
|
|
327
|
+
if (reset && options.some((option) => option.name !== undefined)) {
|
|
328
|
+
violations.push({
|
|
329
|
+
rule: 4,
|
|
330
|
+
code: 'local/unsupported-target',
|
|
331
|
+
span: span(opening),
|
|
332
|
+
component: 'Theme',
|
|
333
|
+
message: zeroRuleMessage(4, {
|
|
334
|
+
detail: 'a <Theme> with both name and reset, which cannot mean one theme,',
|
|
335
|
+
}),
|
|
336
|
+
})
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
if (!closing) {
|
|
340
|
+
violations.push({
|
|
341
|
+
rule: 4,
|
|
342
|
+
code: 'local/unsupported-target',
|
|
343
|
+
span: span(element),
|
|
344
|
+
component: 'Theme',
|
|
345
|
+
message: zeroRuleMessage(4, {
|
|
346
|
+
detail: 'a self-closing <Theme>, which has no subtree to theme,',
|
|
347
|
+
}),
|
|
348
|
+
})
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// One parse per unique authored value, and every clause the parser could not
|
|
352
|
+
// use is a violation here instead of the warn-and-drop the render path does.
|
|
353
|
+
const issues: InlineValueIssue[] = []
|
|
354
|
+
const inlineValues = Object.keys(themeKeyProps).length
|
|
355
|
+
? getInlineValuesFromProps(themeKeyProps, config, (issue) => issues.push(issue))
|
|
356
|
+
: null
|
|
357
|
+
for (const issue of issues) {
|
|
358
|
+
violations.push({
|
|
359
|
+
rule: 3,
|
|
360
|
+
code: 'local/dynamic-style-value',
|
|
361
|
+
span: span(opening),
|
|
362
|
+
component: 'Theme',
|
|
363
|
+
message: zeroRuleMessage(3, {
|
|
364
|
+
prop: issue.key,
|
|
365
|
+
component: 'Theme',
|
|
366
|
+
detail: issue.message,
|
|
367
|
+
}),
|
|
368
|
+
})
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
const inlineCSS = inlineValues ? getVariablesCSSRules(inlineValues, config) : null
|
|
372
|
+
if (inlineCSS) css.set(inlineCSS.identifier, inlineCSS.rules.join(''))
|
|
373
|
+
|
|
374
|
+
if (violations.length) return { node: null, violations, css }
|
|
375
|
+
|
|
376
|
+
return {
|
|
377
|
+
node: {
|
|
378
|
+
element,
|
|
379
|
+
opening,
|
|
380
|
+
closing,
|
|
381
|
+
options,
|
|
382
|
+
reset,
|
|
383
|
+
contain,
|
|
384
|
+
layer:
|
|
385
|
+
inlineValues && inlineCSS
|
|
386
|
+
? {
|
|
387
|
+
inlineValues: inlineValues as IslandThemeBridgeLayer['inlineValues'],
|
|
388
|
+
inlineClassName: inlineCSS.identifier,
|
|
389
|
+
}
|
|
390
|
+
: null,
|
|
391
|
+
},
|
|
392
|
+
violations,
|
|
393
|
+
css,
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* The span a static `<Theme>` lowers to.
|
|
399
|
+
*
|
|
400
|
+
* Same classes and same inline style the runtime span carries, because both are
|
|
401
|
+
* read by the same CSS: the theme classes select the named theme's variables,
|
|
402
|
+
* the inline-value class carries the direct props at the anchored specificity
|
|
403
|
+
* that lets it beat them, and `display: contents` keeps the span out of layout.
|
|
404
|
+
*/
|
|
405
|
+
export function lowerStaticTheme(
|
|
406
|
+
node: StaticThemeNode,
|
|
407
|
+
chain: readonly StaticThemeNode[],
|
|
408
|
+
rootThemeName: string,
|
|
409
|
+
config: TamaguiInternalConfig,
|
|
410
|
+
id: string
|
|
411
|
+
): { edits: SourceEdit[]; violations: ZeroViolation[] } {
|
|
412
|
+
const moduleId = resolvedModuleId(id)
|
|
413
|
+
const branches = resolveThemeChain(chain, rootThemeName, config)
|
|
414
|
+
if (branches.length > MAX_THEME_BRANCHES) {
|
|
415
|
+
return {
|
|
416
|
+
edits: [],
|
|
417
|
+
violations: [
|
|
418
|
+
{
|
|
419
|
+
rule: 4,
|
|
420
|
+
code: 'local/unsupported-target',
|
|
421
|
+
span: { id: moduleId, start: node.element.start, end: node.element.end },
|
|
422
|
+
component: 'Theme',
|
|
423
|
+
message: zeroRuleMessage(4, {
|
|
424
|
+
detail: `a <Theme> chain that enumerates ${branches.length} theme names, past the ${MAX_THEME_BRANCHES} this lowers,`,
|
|
425
|
+
}),
|
|
426
|
+
},
|
|
427
|
+
],
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
const inlineClass = node.layer?.inlineClassName ?? ''
|
|
432
|
+
const classBranches = branches.map((branch) => ({
|
|
433
|
+
test: branch.test,
|
|
434
|
+
value: JSON.stringify(
|
|
435
|
+
[branch.isNew ? getThemeClassNames(branch.name) : '', 'is_Theme', inlineClass]
|
|
436
|
+
.filter(Boolean)
|
|
437
|
+
.join(' ')
|
|
438
|
+
.replace(/\s+/g, ' ')
|
|
439
|
+
.trim()
|
|
440
|
+
),
|
|
441
|
+
}))
|
|
442
|
+
|
|
443
|
+
const baseStyle = node.contain
|
|
444
|
+
? `display:"contents",contain:"strict"`
|
|
445
|
+
: `display:"contents"`
|
|
446
|
+
const styleBranches = branches.map((branch) => {
|
|
447
|
+
const theme = (config.themes as Record<string, any>)[branch.name]
|
|
448
|
+
const color = branch.isNew && theme ? variableToString(theme.color) : ''
|
|
449
|
+
return {
|
|
450
|
+
test: branch.test,
|
|
451
|
+
value: color ? `{color:${JSON.stringify(color)},${baseStyle}}` : `{${baseStyle}}`,
|
|
452
|
+
}
|
|
453
|
+
})
|
|
454
|
+
|
|
455
|
+
const className = foldBranches(classBranches)
|
|
456
|
+
const style = foldBranches(styleBranches)
|
|
457
|
+
const classAttribute = className.startsWith('"')
|
|
458
|
+
? `className=${className}`
|
|
459
|
+
: `className={${className}}`
|
|
460
|
+
|
|
461
|
+
const edits: SourceEdit[] = [
|
|
462
|
+
{
|
|
463
|
+
start: node.opening.start,
|
|
464
|
+
end: node.opening.end,
|
|
465
|
+
content: `<span ${classAttribute} style={${style}}>`,
|
|
466
|
+
origin: { id: moduleId, start: node.opening.start, end: node.opening.end },
|
|
467
|
+
},
|
|
468
|
+
]
|
|
469
|
+
if (node.closing) {
|
|
470
|
+
edits.push({
|
|
471
|
+
start: node.closing.start,
|
|
472
|
+
end: node.closing.end,
|
|
473
|
+
content: `</span>`,
|
|
474
|
+
origin: { id: moduleId, start: node.closing.start, end: node.closing.end },
|
|
475
|
+
})
|
|
476
|
+
}
|
|
477
|
+
return { edits, violations: [] }
|
|
478
|
+
}
|