@tamagui/static 1.88.13 → 1.89.0-1706308641099

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/LICENSE +21 -0
  2. package/dist/esm/constants.mjs +10 -0
  3. package/dist/esm/extractor/accessSafe.mjs +11 -0
  4. package/dist/esm/extractor/babelParse.mjs +18 -0
  5. package/dist/esm/extractor/buildClassName.mjs +26 -0
  6. package/dist/esm/extractor/bundle.mjs +94 -0
  7. package/dist/esm/extractor/bundleConfig.mjs +263 -0
  8. package/dist/esm/extractor/createEvaluator.mjs +34 -0
  9. package/dist/esm/extractor/createExtractor.mjs +952 -0
  10. package/dist/esm/extractor/ensureImportingConcat.mjs +13 -0
  11. package/dist/esm/extractor/esbuildAliasPlugin.mjs +20 -0
  12. package/dist/esm/extractor/evaluateAstNode.mjs +48 -0
  13. package/dist/esm/extractor/extractHelpers.mjs +72 -0
  14. package/dist/esm/extractor/extractMediaStyle.mjs +93 -0
  15. package/dist/esm/extractor/extractToClassNames.mjs +237 -0
  16. package/dist/esm/extractor/findTopmostFunction.mjs +10 -0
  17. package/dist/esm/extractor/generateTamaguiStudioConfig.mjs +108 -0
  18. package/dist/esm/extractor/generatedUid.mjs +12 -0
  19. package/dist/esm/extractor/getPrefixLogs.mjs +4 -0
  20. package/dist/esm/extractor/getPropValueFromAttributes.mjs +31 -0
  21. package/dist/esm/extractor/getSourceModule.mjs +33 -0
  22. package/dist/esm/extractor/getStaticBindingsForScope.mjs +112 -0
  23. package/dist/esm/extractor/getTamaguiConfigPathFromOptionsConfig.mjs +5 -0
  24. package/dist/esm/extractor/hoistClassNames.mjs +24 -0
  25. package/dist/esm/extractor/literalToAst.mjs +48 -0
  26. package/dist/esm/extractor/loadFile.mjs +11 -0
  27. package/dist/esm/extractor/loadTamagui.mjs +233 -0
  28. package/dist/esm/extractor/logLines.mjs +11 -0
  29. package/dist/esm/extractor/normalizeTernaries.mjs +33 -0
  30. package/dist/esm/extractor/propsToFontFamilyCache.mjs +12 -0
  31. package/dist/esm/extractor/removeUnusedHooks.mjs +41 -0
  32. package/dist/esm/extractor/timer.mjs +19 -0
  33. package/dist/esm/extractor/validHTMLAttributes.mjs +49 -0
  34. package/dist/esm/getPragmaOptions.mjs +19 -0
  35. package/dist/esm/helpers/memoize.mjs +13 -0
  36. package/dist/esm/helpers/requireTamaguiCore.mjs +5 -0
  37. package/dist/esm/index.mjs +3 -0
  38. package/dist/esm/minifyCSS.mjs +12 -0
  39. package/dist/esm/registerRequire.mjs +74 -0
  40. package/dist/esm/server.mjs +40 -0
  41. package/dist/esm/setup.mjs +1 -0
  42. package/dist/esm/static.mjs +10 -0
  43. package/dist/esm/types.mjs +0 -0
  44. package/dist/esm/webpackPlugin.mjs +7 -0
  45. package/package.json +15 -15
@@ -0,0 +1,13 @@
1
+ import * as t from "@babel/types";
2
+ const importConcatPkg = "@tamagui/helpers";
3
+ function ensureImportingConcat(path) {
4
+ const imported = path.get("body").find(x => x.isImportDeclaration() && x.node.source.value === importConcatPkg),
5
+ importSpecifier = t.importSpecifier(t.identifier("concatClassName"), t.identifier("concatClassName"));
6
+ if (!imported) {
7
+ path.node.body.push(t.importDeclaration([importSpecifier], t.stringLiteral(importConcatPkg)));
8
+ return;
9
+ }
10
+ const specifiers = imported.node.specifiers;
11
+ specifiers.some(x => t.isImportSpecifier(x) && t.isIdentifier(x.imported) && x.imported.name === "concatClassName") || specifiers.push(t.importSpecifier(t.identifier("concatClassName"), t.identifier("concatClassName")));
12
+ }
13
+ export { ensureImportingConcat };
@@ -0,0 +1,20 @@
1
+ const esbuildAliasPlugin = config => {
2
+ const alias = config && Object.keys(config);
3
+ return {
4
+ name: "path-alias",
5
+ setup(build) {
6
+ if (!alias || !alias.length) return;
7
+ const main = (k, args) => ({
8
+ path: config[k].replace(/\/$/, "")
9
+ });
10
+ alias.forEach(k => {
11
+ build.onResolve({
12
+ filter: new RegExp(`^.*${k}$`)
13
+ }, args => main(k, args)), build.onResolve({
14
+ filter: new RegExp(`^.*\\/${k}\\/.*$`)
15
+ }, args => main(k, args));
16
+ });
17
+ }
18
+ };
19
+ };
20
+ export { esbuildAliasPlugin };
@@ -0,0 +1,48 @@
1
+ import * as t from "@babel/types";
2
+ function evaluateAstNode(exprNode, evalFn, shouldPrintDebug) {
3
+ if (exprNode !== void 0) {
4
+ if (exprNode === null) return !0;
5
+ if (t.isJSXExpressionContainer(exprNode)) return evaluateAstNode(exprNode.expression);
6
+ if (t.isObjectExpression(exprNode)) {
7
+ const ret = {};
8
+ for (let idx = -1, len = exprNode.properties.length; ++idx < len;) {
9
+ const value = exprNode.properties[idx];
10
+ if (!t.isObjectProperty(value)) throw new Error("evaluateAstNode can only evaluate object properties");
11
+ let key;
12
+ if (value.computed) {
13
+ if (typeof evalFn != "function") throw new Error("evaluateAstNode does not support computed keys unless an eval function is provided");
14
+ key = evaluateAstNode(value.key, evalFn);
15
+ } else if (t.isIdentifier(value.key)) key = value.key.name;else if (t.isStringLiteral(value.key) || t.isNumericLiteral(value.key)) key = value.key.value;else throw new Error("Unsupported key type: " + value.key.type);
16
+ if (typeof key != "string" && typeof key != "number") throw new Error("key must be either a string or a number");
17
+ ret[key] = evaluateAstNode(value.value, evalFn);
18
+ }
19
+ return ret;
20
+ }
21
+ if (t.isArrayExpression(exprNode)) return exprNode.elements.map(x => evaluateAstNode(x, evalFn));
22
+ if (t.isUnaryExpression(exprNode) && exprNode.operator === "-") {
23
+ const ret = evaluateAstNode(exprNode.argument, evalFn);
24
+ return ret == null ? null : -ret;
25
+ }
26
+ if (t.isTemplateLiteral(exprNode)) {
27
+ if (typeof evalFn != "function") throw new Error("evaluateAstNode does not support template literals unless an eval function is provided");
28
+ let ret = "";
29
+ for (let idx = -1, len = exprNode.quasis.length; ++idx < len;) {
30
+ const quasi = exprNode.quasis[idx],
31
+ expr = exprNode.expressions[idx];
32
+ ret += quasi.value.raw, expr && (ret += evaluateAstNode(expr, evalFn));
33
+ }
34
+ return ret;
35
+ }
36
+ if (t.isNullLiteral(exprNode)) return null;
37
+ if (t.isNumericLiteral(exprNode) || t.isStringLiteral(exprNode) || t.isBooleanLiteral(exprNode)) return exprNode.value;
38
+ if (t.isBinaryExpression(exprNode)) {
39
+ if (exprNode.operator === "+") return evaluateAstNode(exprNode.left, evalFn) + evaluateAstNode(exprNode.right, evalFn);
40
+ if (exprNode.operator === "-") return evaluateAstNode(exprNode.left, evalFn) - evaluateAstNode(exprNode.right, evalFn);
41
+ if (exprNode.operator === "*") return evaluateAstNode(exprNode.left, evalFn) * evaluateAstNode(exprNode.right, evalFn);
42
+ if (exprNode.operator === "/") return evaluateAstNode(exprNode.left, evalFn) / evaluateAstNode(exprNode.right, evalFn);
43
+ }
44
+ if (typeof evalFn != "function") throw new Error("evaluateAstNode does not support non-literal values unless an eval function is provided");
45
+ return evalFn(exprNode);
46
+ }
47
+ }
48
+ export { evaluateAstNode };
@@ -0,0 +1,72 @@
1
+ import { basename } from "path";
2
+ import generate from "@babel/generator";
3
+ import * as t from "@babel/types";
4
+ import findRoot from "find-root";
5
+ import { memoize } from "../helpers/memoize.mjs";
6
+ function isPresent(input) {
7
+ return input != null;
8
+ }
9
+ function isSimpleSpread(node) {
10
+ return t.isIdentifier(node.argument) || t.isMemberExpression(node.argument);
11
+ }
12
+ const attrStr = attr => attr ? attr.type === "attr" ? getNameAttr(attr.value) : attr.type === "ternary" ? `...${ternaryStr(attr.value)}` : `${attr.type}(${objToStr(attr.value)})` : "",
13
+ objToStr = (obj, spacer = ", ") => obj ? `{${Object.entries(obj).map(([k, v]) => `${k}:${Array.isArray(v) ? "[...]" : v && typeof v == "object" ? `${objToStr(v, ",")}` : JSON.stringify(v)}`).join(spacer)}}` : `${obj}`,
14
+ getNameAttr = attr => t.isJSXSpreadAttribute(attr) ? `...${attr.argument.name}` : "name" in attr ? attr.name.name : `unknown-${attr.type}`,
15
+ ternaryStr = x => ["ternary(", t.isIdentifier(x.test) ? x.test.name : t.isMemberExpression(x.test) ? [x.test.object.name, x.test.property.name] :
16
+ // @ts-ignore
17
+ generate(x.test).code, isFilledObj(x.consequent) ? ` ? ${objToStr(x.consequent)}` : " ? \u{1F6AB}", isFilledObj(x.alternate) ? ` : ${objToStr(x.alternate)}` : " : \u{1F6AB}", ")"].flat().join(""),
18
+ isFilledObj = obj => obj && Object.keys(obj).length;
19
+ function findComponentName(scope) {
20
+ const componentName = "";
21
+ let cur = scope.path;
22
+ for (; cur.parentPath && !t.isProgram(cur.parentPath.parent);) cur = cur.parentPath;
23
+ let node = cur.parent;
24
+ if (t.isExportNamedDeclaration(node) && (node = node.declaration), t.isVariableDeclaration(node)) {
25
+ const [dec] = node.declarations;
26
+ if (t.isVariableDeclarator(dec) && t.isIdentifier(dec.id)) return dec.id.name;
27
+ }
28
+ return t.isFunctionDeclaration(node) ? node.id?.name : componentName;
29
+ }
30
+ function isValidThemeHook(props, jsxPath, n, sourcePath) {
31
+ if (!t.isIdentifier(n.object) || !t.isIdentifier(n.property)) return !1;
32
+ const binding = jsxPath.scope.getAllBindings()[n.object.name];
33
+ if (!binding?.path || !binding.path.isVariableDeclarator()) return !1;
34
+ const init = binding.path.node.init;
35
+ if (!init || !t.isCallExpression(init) || !t.isIdentifier(init.callee) || init.callee.name !== "useTheme") return !1;
36
+ const importNode = binding.scope.getBinding("useTheme")?.path.parent;
37
+ return !(!t.isImportDeclaration(importNode) || sourcePath && !isValidImport(props, sourcePath));
38
+ }
39
+ const isInsideComponentPackage = (props, moduleName) => getValidComponentsPaths(props).some(path => moduleName.startsWith(path)),
40
+ isComponentPackage = (props, srcName) => getValidComponentsPaths(props).some(path => srcName.startsWith(path));
41
+ function getValidComponent(props, moduleName, componentName) {
42
+ if (componentName[0].toUpperCase() !== componentName[0]) return !1;
43
+ for (const loaded of props.allLoadedComponents) {
44
+ if (!loaded) continue;
45
+ const isInModule = moduleName === "*" || moduleName.startsWith(loaded.moduleName),
46
+ foundComponent = loaded.nameToInfo[componentName];
47
+ if (isInModule && foundComponent) return foundComponent;
48
+ }
49
+ return null;
50
+ }
51
+ const isValidModule = (props, moduleName) => {
52
+ if (typeof moduleName != "string") throw new Error("No module name");
53
+ const isLocal = moduleName.startsWith(".");
54
+ return {
55
+ isLocal,
56
+ isValid: isLocal ? isInsideComponentPackage(props, moduleName) : isComponentPackage(props, moduleName)
57
+ };
58
+ },
59
+ getValidImport = (props, moduleName, componentName) => {
60
+ const {
61
+ isValid,
62
+ isLocal
63
+ } = isValidModule(props, moduleName);
64
+ return !isValid || !componentName ? null : getValidComponent(props, isLocal ? "*" : moduleName, componentName) || null;
65
+ },
66
+ isValidImport = (props, moduleName, componentName) => componentName ? !!getValidImport(props, moduleName, componentName) : isValidModule(props, moduleName).isValid,
67
+ getValidComponentPackages = memoize(props => [... /* @__PURE__ */new Set(["@tamagui/core", "tamagui", ...props.components])]),
68
+ getValidComponentsPaths = memoize(props => getValidComponentPackages(props).flatMap(pkg => {
69
+ const root = findRoot(pkg);
70
+ return [basename(root), pkg].filter(Boolean);
71
+ }));
72
+ export { attrStr, findComponentName, getValidComponent, getValidComponentsPaths, getValidImport, isComponentPackage, isInsideComponentPackage, isPresent, isSimpleSpread, isValidImport, isValidModule, isValidThemeHook, objToStr, ternaryStr };
@@ -0,0 +1,93 @@
1
+ import * as t from "@babel/types";
2
+ import { createMediaStyle } from "@tamagui/core";
3
+ import { requireTamaguiCore } from "../helpers/requireTamaguiCore.mjs";
4
+ import { isPresent, isValidImport } from "./extractHelpers.mjs";
5
+ function extractMediaStyle(props, ternary, jsxPath, tamaguiConfig, sourcePath, importance = 0, shouldPrintDebug = !1) {
6
+ const {
7
+ getStylesAtomic,
8
+ mediaObjectToString
9
+ } = requireTamaguiCore("web"),
10
+ mt = getMediaQueryTernary(props, ternary, jsxPath, sourcePath);
11
+ if (!mt) return null;
12
+ const {
13
+ key
14
+ } = mt;
15
+ if (!tamaguiConfig.media[key]) return console.error(`Media query "${key}" not found: ${Object.keys(tamaguiConfig.media)}`), null;
16
+ const getStyleObj = (styleObj, negate = !1) => styleObj ? {
17
+ styleObj,
18
+ negate
19
+ } : null,
20
+ styleOpts = [getStyleObj(ternary.consequent, !1), getStyleObj(ternary.alternate, !0)].filter(isPresent);
21
+ if (shouldPrintDebug && !styleOpts.length) return console.info(" media query, no styles?"), null;
22
+ const mediaKeyPrecendence = Object.keys(tamaguiConfig.media).reduce((acc, cur, i) => (acc[cur] = new Array(importance + 1).fill(":root").join(""), acc), {});
23
+ let mediaStyles = [];
24
+ for (const {
25
+ styleObj,
26
+ negate
27
+ } of styleOpts) {
28
+ const singleMediaStyles = getStylesAtomic(styleObj).map(style => {
29
+ const mediaStyle = createMediaStyle(style, key, tamaguiConfig.media, !0, negate),
30
+ className = `.${mediaStyle.identifier}`;
31
+ return {
32
+ ...mediaStyle,
33
+ className
34
+ };
35
+ });
36
+ shouldPrintDebug === "verbose" && console.info(" media styles:", importance, styleObj, singleMediaStyles.map(x => x.identifier).join(", ")), mediaStyles = [...mediaStyles, ...singleMediaStyles];
37
+ }
38
+ return ternary.remove(), {
39
+ mediaStyles,
40
+ ternaryWithoutMedia: mt.ternaryWithoutMedia
41
+ };
42
+ }
43
+ function getMediaQueryTernary(props, ternary, jsxPath, sourcePath) {
44
+ if (t.isLogicalExpression(ternary.test) && ternary.test.operator === "&&") {
45
+ const mediaLeft = getMediaInfoFromExpression(props, ternary.test.left, jsxPath, sourcePath, ternary.inlineMediaQuery);
46
+ if (mediaLeft) return {
47
+ ...mediaLeft,
48
+ ternaryWithoutMedia: {
49
+ ...ternary,
50
+ test: ternary.test.right
51
+ }
52
+ };
53
+ }
54
+ const result = getMediaInfoFromExpression(props, ternary.test, jsxPath, sourcePath, ternary.inlineMediaQuery);
55
+ return result ? {
56
+ ...result,
57
+ ternaryWithoutMedia: null
58
+ } : null;
59
+ }
60
+ function getMediaInfoFromExpression(props, test, jsxPath, sourcePath, inlineMediaQuery) {
61
+ if (inlineMediaQuery) return {
62
+ key: inlineMediaQuery,
63
+ bindingName: inlineMediaQuery
64
+ };
65
+ if (t.isMemberExpression(test) && t.isIdentifier(test.object) && t.isIdentifier(test.property)) {
66
+ const name = test.object.name,
67
+ key = test.property.name,
68
+ binding = jsxPath.scope.getAllBindings()[name];
69
+ if (!binding) return !1;
70
+ const bindingNode = binding.path?.node;
71
+ return !t.isVariableDeclarator(bindingNode) || !bindingNode.init || !isValidMediaCall(props, jsxPath, bindingNode.init, sourcePath) ? !1 : {
72
+ key,
73
+ bindingName: name
74
+ };
75
+ }
76
+ if (t.isIdentifier(test)) {
77
+ const key = test.name,
78
+ node = jsxPath.scope.getBinding(test.name)?.path?.node;
79
+ return !t.isVariableDeclarator(node) || !node.init || !isValidMediaCall(props, jsxPath, node.init, sourcePath) ? !1 : {
80
+ key,
81
+ bindingName: key
82
+ };
83
+ }
84
+ return null;
85
+ }
86
+ function isValidMediaCall(props, jsxPath, init, sourcePath) {
87
+ if (!init || !t.isCallExpression(init) || !t.isIdentifier(init.callee) || init.callee.name !== "useMedia") return !1;
88
+ const mediaBinding = jsxPath.scope.getAllBindings().useMedia;
89
+ if (!mediaBinding) return !1;
90
+ const useMediaImport = mediaBinding.path.parent;
91
+ return !(!t.isImportDeclaration(useMediaImport) || !isValidImport(props, sourcePath));
92
+ }
93
+ export { extractMediaStyle, isValidMediaCall };
@@ -0,0 +1,237 @@
1
+ import * as path from "path";
2
+ import { basename } from "path";
3
+ import * as util from "util";
4
+ import generate from "@babel/generator";
5
+ import * as t from "@babel/types";
6
+ import { concatClassName } from "@tamagui/helpers";
7
+ import { requireTamaguiCore } from "../helpers/requireTamaguiCore.mjs";
8
+ import { babelParse } from "./babelParse.mjs";
9
+ import { buildClassName } from "./buildClassName.mjs";
10
+ import { ensureImportingConcat } from "./ensureImportingConcat.mjs";
11
+ import { isSimpleSpread } from "./extractHelpers.mjs";
12
+ import { extractMediaStyle } from "./extractMediaStyle.mjs";
13
+ import { getPrefixLogs } from "./getPrefixLogs.mjs";
14
+ import { hoistClassNames } from "./hoistClassNames.mjs";
15
+ import { logLines } from "./logLines.mjs";
16
+ import { getFontFamilyClassNameFromProps } from "./propsToFontFamilyCache.mjs";
17
+ import { timer } from "./timer.mjs";
18
+ const mergeStyleGroups = {
19
+ shadowOpacity: !0,
20
+ shadowRadius: !0,
21
+ shadowColor: !0,
22
+ shadowOffset: !0
23
+ };
24
+ async function extractToClassNames({
25
+ extractor,
26
+ source,
27
+ sourcePath,
28
+ options,
29
+ shouldPrintDebug
30
+ }) {
31
+ const tm = timer(),
32
+ {
33
+ getStylesAtomic
34
+ } = requireTamaguiCore("web");
35
+ if (sourcePath?.includes("node_modules")) return null;
36
+ if (shouldPrintDebug && console.warn(`--- ${sourcePath} ---
37
+
38
+ `), typeof source != "string") throw new Error("`source` must be a string of javascript");
39
+ if (sourcePath && !path.isAbsolute(sourcePath)) throw new Error("`sourcePath` must be an absolute path to a .js file, got: " + sourcePath);
40
+ /.[tj]sx?$/i.test(sourcePath || "") || console.warn(`${sourcePath?.slice(0, 100)} - bad filename.`), !options.disableExtraction && !options._disableLoadTamagui && (await extractor.loadTamagui(options));
41
+ const shouldLogTiming = options.logTimings ?? !0,
42
+ start = Date.now(),
43
+ mem = process.env.TAMAGUI_SHOW_MEMORY_USAGE && shouldLogTiming ? process.memoryUsage() : null;
44
+ let ast;
45
+ try {
46
+ ast = babelParse(source, sourcePath);
47
+ } catch (err) {
48
+ throw console.error("babel parse error:", sourcePath?.slice(0, 100)), err;
49
+ }
50
+ tm.mark("babel-parse", shouldPrintDebug === "verbose");
51
+ const cssMap = /* @__PURE__ */new Map(),
52
+ existingHoists = {};
53
+ let hasFlattened = !1;
54
+ const res = await extractor.parse(ast, {
55
+ shouldPrintDebug,
56
+ ...options,
57
+ sourcePath,
58
+ extractStyledDefinitions: !0,
59
+ onStyleRule(identifier, rules) {
60
+ const css = rules.join(";");
61
+ shouldPrintDebug && console.info(`adding styled() rule: .${identifier} ${css}`), cssMap.set(`.${identifier}`, {
62
+ css,
63
+ commentTexts: []
64
+ });
65
+ },
66
+ getFlattenedNode: ({
67
+ tag
68
+ }) => (hasFlattened = !0, tag),
69
+ onExtractTag: ({
70
+ parserProps,
71
+ attrs,
72
+ node,
73
+ attemptEval,
74
+ jsxPath,
75
+ originalNodeName,
76
+ filePath,
77
+ lineNumbers,
78
+ programPath,
79
+ isFlattened,
80
+ config,
81
+ completeProps,
82
+ staticConfig
83
+ }) => {
84
+ if (staticConfig.acceptsClassName === !1) {
85
+ shouldPrintDebug && console.info("bail, acceptsClassName is false");
86
+ return;
87
+ }
88
+ const didFlattenThisTag = hasFlattened;
89
+ hasFlattened = !1;
90
+ let finalClassNames = [];
91
+ const finalAttrs = [];
92
+ let finalStyles = [],
93
+ viewStyles = {};
94
+ for (const attr of attrs) attr.type === "style" && (viewStyles = {
95
+ ...viewStyles,
96
+ ...attr.value
97
+ });
98
+ const ensureNeededPrevStyle = style => {
99
+ if (!Object.keys(style).some(key => mergeStyleGroups[key])) return style;
100
+ for (const k in mergeStyleGroups) k in viewStyles && (style[k] = style[k] ?? viewStyles[k]);
101
+ return style;
102
+ },
103
+ addStyles = style => {
104
+ if (!style) return [];
105
+ const styleWithPrev = ensureNeededPrevStyle(style),
106
+ res2 = getStylesAtomic(styleWithPrev);
107
+ return res2.length && (finalStyles = [...finalStyles, ...res2]), res2;
108
+ };
109
+ let lastMediaImportance = 1;
110
+ for (const attr of attrs) switch (attr.type) {
111
+ case "style":
112
+ {
113
+ if (isFlattened) {
114
+ const styles2 = addStyles(attr.value),
115
+ newFontFamily = getFontFamilyClassNameFromProps(attr.value) || "",
116
+ newClassNames = concatClassName(styles2.map(x => x.identifier).join(" ") + newFontFamily),
117
+ existing = finalClassNames.find(x => x.type == "StringLiteral");
118
+ if (existing) {
119
+ let previous = existing.value;
120
+ newFontFamily && (shouldPrintDebug && console.info(` newFontFamily: ${newFontFamily}`), previous = previous.replace(/font_[a-z]+/i, "")), existing.value = `${previous} ${newClassNames}`;
121
+ } else finalClassNames = [...finalClassNames, t.stringLiteral(newClassNames)];
122
+ } else {
123
+ const styles2 = getStylesAtomic(attr.value);
124
+ finalStyles = [...finalStyles, ...styles2];
125
+ for (const style of styles2) {
126
+ const prop = style.pseudo ? `${style.property}-${style.pseudo}` : style.property;
127
+ finalAttrs.push(t.jsxAttribute(t.jsxIdentifier(prop), t.stringLiteral(style.identifier)));
128
+ }
129
+ }
130
+ break;
131
+ }
132
+ case "attr":
133
+ {
134
+ const val = attr.value;
135
+ if (t.isJSXSpreadAttribute(val)) isSimpleSpread(val) && finalClassNames.push(t.logicalExpression("&&", val.argument, t.memberExpression(val.argument, t.identifier("className"))));else if (val.name.name === "className") {
136
+ const value = val.value;
137
+ if (value) try {
138
+ const evaluatedValue = attemptEval(value);
139
+ finalClassNames.push(t.stringLiteral(evaluatedValue));
140
+ } catch {
141
+ finalClassNames.push(value.expression);
142
+ }
143
+ continue;
144
+ }
145
+ finalAttrs.push(val);
146
+ break;
147
+ }
148
+ case "ternary":
149
+ {
150
+ const mediaExtraction = extractMediaStyle(parserProps, attr.value, jsxPath, extractor.getTamagui(), sourcePath || "", lastMediaImportance, shouldPrintDebug);
151
+ if (shouldPrintDebug && mediaExtraction && console.info("ternary (mediaStyles)", mediaExtraction.ternaryWithoutMedia?.inlineMediaQuery ?? "", mediaExtraction.mediaStyles.map(x => x.identifier).join(".")), !mediaExtraction) {
152
+ addTernaryStyle(attr.value, addStyles(attr.value.consequent), addStyles(attr.value.alternate));
153
+ continue;
154
+ }
155
+ lastMediaImportance++, mediaExtraction.mediaStyles && (finalStyles = [...finalStyles, ...mediaExtraction.mediaStyles]), mediaExtraction.ternaryWithoutMedia ? addTernaryStyle(mediaExtraction.ternaryWithoutMedia, mediaExtraction.mediaStyles, []) : finalClassNames = [...finalClassNames, ...mediaExtraction.mediaStyles.map(x => t.stringLiteral(x.identifier))];
156
+ break;
157
+ }
158
+ }
159
+ function addTernaryStyle(ternary, a, b) {
160
+ const cCN = a.map(x => x.identifier).join(" "),
161
+ aCN = b.map(x => x.identifier).join(" ");
162
+ a.length && b.length ? finalClassNames.push(t.conditionalExpression(ternary.test, t.stringLiteral(cCN), t.stringLiteral(aCN))) : finalClassNames.push(t.conditionalExpression(ternary.test, t.stringLiteral(" " + cCN), t.stringLiteral(" " + aCN)));
163
+ }
164
+ if (shouldPrintDebug && console.info(` finalClassNames
165
+ `, logLines(finalClassNames.map(x => x.value).join(" "))), node.attributes = finalAttrs, finalClassNames.length) {
166
+ const extraClassNames = (() => {
167
+ let value = "";
168
+ return isFlattened && (process.env.TAMAGUI_DEBUG_OPTIMIZATIONS && (value += "is_tamagui_flattened"), staticConfig.componentName && (value += ` is_${staticConfig.componentName}`)), value;
169
+ })(),
170
+ names = buildClassName(finalClassNames, extraClassNames),
171
+ nameExpr = names ? hoistClassNames(jsxPath, existingHoists, names) : null;
172
+ let expr = nameExpr;
173
+ if (nameExpr && !t.isIdentifier(nameExpr) && didFlattenThisTag) {
174
+ ensureImportingConcat(programPath);
175
+ const simpleSpreads = attrs.filter(x => x.type === "attr" && t.isJSXSpreadAttribute(x.value) && isSimpleSpread(x.value));
176
+ expr = t.callExpression(t.identifier("concatClassName"), [expr, ...simpleSpreads.map(val => val.value.argument)]);
177
+ }
178
+ node.attributes.push(t.jsxAttribute(t.jsxIdentifier("className"), t.jsxExpressionContainer(expr)));
179
+ }
180
+ const comment = util.format("/* %s:%s (%s) */", filePath, lineNumbers, originalNodeName);
181
+ for (const {
182
+ identifier,
183
+ rules
184
+ } of finalStyles) {
185
+ const className = `.${identifier}`;
186
+ if (cssMap.has(className)) {
187
+ if (comment) {
188
+ const val = cssMap.get(className);
189
+ val.commentTexts.push(comment), cssMap.set(className, val);
190
+ }
191
+ } else rules.length && cssMap.set(className, {
192
+ css: rules.join(`
193
+ `),
194
+ commentTexts: [comment]
195
+ });
196
+ }
197
+ }
198
+ });
199
+ if (!res || !res.modified && !res.optimized && !res.flattened && !res.styled) return shouldPrintDebug && console.info("no res or none modified", res), null;
200
+ const styles = Array.from(cssMap.values()).map(x => x.css).join(`
201
+ `).trim(),
202
+ result = generate(ast, {
203
+ concise: !1,
204
+ filename: sourcePath,
205
+ // this makes the debug output terrible, and i think sourcemap works already
206
+ retainLines: !1,
207
+ sourceFileName: sourcePath,
208
+ sourceMaps: !0
209
+ }, source);
210
+ if (shouldPrintDebug && (console.info(`
211
+ -------- output code -------
212
+
213
+ `, result.code.split(`
214
+ `).filter(x => !x.startsWith("//")).join(`
215
+ `)), console.info(`
216
+ -------- output style --------
217
+
218
+ `, styles)), shouldLogTiming) {
219
+ const memUsed = mem ? Math.round((process.memoryUsage().heapUsed - mem.heapUsed) / 1024 / 1204 * 10) / 10 : 0,
220
+ path2 = basename(sourcePath || "").replace(/\.[jt]sx?$/, "").slice(0, 22).trim().padStart(24),
221
+ numOptimized = `${res.optimized + res.styled}`.padStart(3),
222
+ numFound = `${res.found + res.styled}`.padStart(3),
223
+ numFlattened = `${res.flattened}`.padStart(3),
224
+ memory = memUsed ? ` ${memUsed}MB` : "",
225
+ timingStr = `${Date.now() - start}ms`.padStart(6),
226
+ pre = getPrefixLogs(options),
227
+ memStr = memory ? `(${memory})` : "";
228
+ console.info(`${pre} ${path2} \xB7 ${numFound} found \xB7 ${numOptimized} opt \xB7 ${numFlattened} flat ${timingStr} ${memStr}`);
229
+ }
230
+ return {
231
+ ast,
232
+ styles,
233
+ js: result.code,
234
+ map: result.map
235
+ };
236
+ }
237
+ export { extractToClassNames };
@@ -0,0 +1,10 @@
1
+ function findTopmostFunction(jsxPath) {
2
+ const isFunction = path => path.isArrowFunctionExpression() || path.isFunctionDeclaration() || path.isFunctionExpression();
3
+ let compFn = jsxPath.findParent(isFunction);
4
+ for (; compFn;) {
5
+ const parent = compFn.findParent(isFunction);
6
+ if (parent) compFn = parent;else break;
7
+ }
8
+ return compFn || null;
9
+ }
10
+ export { findTopmostFunction };
@@ -0,0 +1,108 @@
1
+ import { dirname, join } from "path";
2
+ import { generateThemes, writeGeneratedThemes } from "@tamagui/generate-themes";
3
+ import fs, { readFile } from "fs-extra";
4
+ import { requireTamaguiCore } from "../helpers/requireTamaguiCore.mjs";
5
+ import { getBundledConfig } from "./bundleConfig.mjs";
6
+ const tamaguiDir = join(process.cwd(), ".tamagui"),
7
+ confFile = join(tamaguiDir, "tamagui.config.json");
8
+ async function generateTamaguiStudioConfig(tamaguiOptions, configIn, rebuild = !1) {
9
+ try {
10
+ const config = configIn ?? (await getBundledConfig(tamaguiOptions, rebuild));
11
+ if (!config) return;
12
+ const out = transformConfig(config, tamaguiOptions.platform);
13
+ await fs.ensureDir(dirname(confFile)), await fs.writeJSON(confFile, out, {
14
+ spaces: 2
15
+ });
16
+ } catch (err) {
17
+ (process.env.DEBUG?.includes("tamagui") || process.env.IS_TAMAGUI_DEV) && console.warn("generateTamaguiStudioConfig error", err);
18
+ }
19
+ }
20
+ function generateTamaguiStudioConfigSync(_tamaguiOptions, config) {
21
+ try {
22
+ fs.ensureDirSync(dirname(confFile)), fs.writeJSONSync(confFile, transformConfig(config, _tamaguiOptions.platform), {
23
+ spaces: 2
24
+ });
25
+ } catch (err) {
26
+ (process.env.DEBUG?.includes("tamagui") || process.env.IS_TAMAGUI_DEV) && console.warn("generateTamaguiStudioConfig error", err);
27
+ }
28
+ }
29
+ async function generateTamaguiThemes(tamaguiOptions, force = !1) {
30
+ if (!tamaguiOptions.themeBuilder) return;
31
+ const {
32
+ input,
33
+ output
34
+ } = tamaguiOptions.themeBuilder,
35
+ inPath = resolveRelativePath(input),
36
+ outPath = resolveRelativePath(output),
37
+ generatedOutput = await generateThemes(inPath),
38
+ hasChanged = force || (await (async () => {
39
+ try {
40
+ if (!(await fs.pathExists(join(tamaguiDir, "theme-builder.json")))) return !0;
41
+ if (!generatedOutput) return !1;
42
+ const next = generatedOutput.generated,
43
+ current = await readFile(outPath, "utf-8");
44
+ return next !== current;
45
+ } catch {}
46
+ return !0;
47
+ })());
48
+ return hasChanged && (await writeGeneratedThemes(tamaguiDir, outPath, generatedOutput)), hasChanged;
49
+ }
50
+ const resolveRelativePath = inputPath => inputPath.startsWith(".") ? join(process.cwd(), inputPath) : require.resolve(inputPath);
51
+ function cloneDeepSafe(x, excludeKeys = {}) {
52
+ return x && (Array.isArray(x) ? x.map(_ => cloneDeepSafe(_)) : typeof x == "function" ? "Function" : typeof x != "object" ? x : "$$typeof" in x ? "Component" : Object.fromEntries(Object.entries(x).flatMap(([k, v]) => excludeKeys[k] ? [] : [[k, cloneDeepSafe(v)]])));
53
+ }
54
+ function transformConfig(config, platform) {
55
+ if (!config) return null;
56
+ const {
57
+ getVariableValue
58
+ } = requireTamaguiCore(platform),
59
+ next = cloneDeepSafe(config, {
60
+ validStyles: !0
61
+ }),
62
+ {
63
+ components,
64
+ nameToPaths,
65
+ tamaguiConfig
66
+ } = next,
67
+ {
68
+ themes,
69
+ tokens
70
+ } = tamaguiConfig;
71
+ for (const key in themes) {
72
+ const theme = themes[key];
73
+ theme.id = key;
74
+ for (const tkey in theme) theme[tkey] = getVariableValue(theme[tkey]);
75
+ }
76
+ for (const key in tokens) {
77
+ const token = {
78
+ ...tokens[key]
79
+ };
80
+ for (const tkey in token) token[tkey] = getVariableValue(token[tkey]);
81
+ }
82
+ for (const component of components) for (const _ in component.nameToInfo) {
83
+ const compDefinition = {
84
+ ...component.nameToInfo[_]
85
+ };
86
+ component.nameToInfo[_] = compDefinition;
87
+ const {
88
+ parentStaticConfig,
89
+ ...rest
90
+ } = compDefinition.staticConfig;
91
+ compDefinition.staticConfig = rest;
92
+ }
93
+ next.nameToPaths = {};
94
+ for (const key in nameToPaths) next.nameToPaths[key] = [...nameToPaths[key]];
95
+ const {
96
+ fontsParsed,
97
+ getCSS,
98
+ tokensParsed,
99
+ themeConfig,
100
+ ...cleanedConfig
101
+ } = next.tamaguiConfig;
102
+ return {
103
+ components,
104
+ nameToPaths,
105
+ tamaguiConfig: cleanedConfig
106
+ };
107
+ }
108
+ export { generateTamaguiStudioConfig, generateTamaguiStudioConfigSync, generateTamaguiThemes };
@@ -0,0 +1,12 @@
1
+ import * as t from "@babel/types";
2
+ function generateUid(scope, name) {
3
+ if (typeof scope != "object") throw "generateUid expects a scope object as its first parameter";
4
+ if (!(typeof name == "string" && name !== "")) throw "generateUid expects a valid name as its second parameter";
5
+ name = t.toIdentifier(name).replace(/^_+/, "").replace(/[0-9]+$/g, "");
6
+ let uid,
7
+ i = 0;
8
+ do i > 1 ? uid = name + i : uid = name, i++; while (scope.hasLabel(uid) || scope.hasBinding(uid) || scope.hasGlobal(uid) || scope.hasReference(uid));
9
+ const program = scope.getProgramParent();
10
+ return program.references[uid] = !0, program.uids[uid] = !0, uid;
11
+ }
12
+ export { generateUid };
@@ -0,0 +1,4 @@
1
+ function getPrefixLogs(options) {
2
+ return options?.prefixLogs ?? ` ${options?.platform || "web"} | `;
3
+ }
4
+ export { getPrefixLogs };
@@ -0,0 +1,31 @@
1
+ import generate from "@babel/generator";
2
+ import * as t from "@babel/types";
3
+ import { accessSafe } from "./accessSafe.mjs";
4
+ function getPropValueFromAttributes(propName, attrs) {
5
+ let propIndex = -1,
6
+ jsxAttr = null;
7
+ for (let idx = -1, len = attrs.length; ++idx < len;) {
8
+ const attr = attrs[idx];
9
+ if (t.isJSXAttribute(attr) && attr.name && attr.name.name === propName) {
10
+ propIndex = idx, jsxAttr = attr;
11
+ break;
12
+ }
13
+ }
14
+ if (!jsxAttr || jsxAttr.value == null) return null;
15
+ let propValue = jsxAttr.value;
16
+ if (t.isJSXExpressionContainer(propValue) && (propValue = propValue.expression), t.isJSXEmptyExpression(propValue)) return console.error("encountered JSXEmptyExpression"), null;
17
+ const applicableSpreads = attrs.filter(
18
+ // 1. idx is greater than propValue prop index
19
+ // 2. attr is a spread operator
20
+ (attr, idx) => {
21
+ if (t.isJSXSpreadAttribute(attr)) {
22
+ if (t.isIdentifier(attr.argument) || t.isMemberExpression(attr.argument)) return idx > propIndex;
23
+ if (t.isLogicalExpression(attr.argument)) return !1;
24
+ throw new Error(`unsupported spread of type "${attr.argument.type}": ${// @ts-ignore
25
+ generate(attr).code}`);
26
+ }
27
+ return !1;
28
+ }).map(attr => attr.argument);
29
+ return applicableSpreads.length > 0 && (propValue = applicableSpreads.reduce((acc, val) => t.logicalExpression("||", accessSafe(val, propName), acc), propValue)), propValue;
30
+ }
31
+ export { getPropValueFromAttributes };