@tamagui/static 1.88.12 → 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.
- package/LICENSE +21 -0
- package/dist/esm/constants.mjs +10 -0
- package/dist/esm/extractor/accessSafe.mjs +11 -0
- package/dist/esm/extractor/babelParse.mjs +18 -0
- package/dist/esm/extractor/buildClassName.mjs +26 -0
- package/dist/esm/extractor/bundle.mjs +94 -0
- package/dist/esm/extractor/bundleConfig.mjs +263 -0
- package/dist/esm/extractor/createEvaluator.mjs +34 -0
- package/dist/esm/extractor/createExtractor.mjs +952 -0
- package/dist/esm/extractor/ensureImportingConcat.mjs +13 -0
- package/dist/esm/extractor/esbuildAliasPlugin.mjs +20 -0
- package/dist/esm/extractor/evaluateAstNode.mjs +48 -0
- package/dist/esm/extractor/extractHelpers.mjs +72 -0
- package/dist/esm/extractor/extractMediaStyle.mjs +93 -0
- package/dist/esm/extractor/extractToClassNames.mjs +237 -0
- package/dist/esm/extractor/findTopmostFunction.mjs +10 -0
- package/dist/esm/extractor/generateTamaguiStudioConfig.mjs +108 -0
- package/dist/esm/extractor/generatedUid.mjs +12 -0
- package/dist/esm/extractor/getPrefixLogs.mjs +4 -0
- package/dist/esm/extractor/getPropValueFromAttributes.mjs +31 -0
- package/dist/esm/extractor/getSourceModule.mjs +33 -0
- package/dist/esm/extractor/getStaticBindingsForScope.mjs +112 -0
- package/dist/esm/extractor/getTamaguiConfigPathFromOptionsConfig.mjs +5 -0
- package/dist/esm/extractor/hoistClassNames.mjs +24 -0
- package/dist/esm/extractor/literalToAst.mjs +48 -0
- package/dist/esm/extractor/loadFile.mjs +11 -0
- package/dist/esm/extractor/loadTamagui.mjs +233 -0
- package/dist/esm/extractor/logLines.mjs +11 -0
- package/dist/esm/extractor/normalizeTernaries.mjs +33 -0
- package/dist/esm/extractor/propsToFontFamilyCache.mjs +12 -0
- package/dist/esm/extractor/removeUnusedHooks.mjs +41 -0
- package/dist/esm/extractor/timer.mjs +19 -0
- package/dist/esm/extractor/validHTMLAttributes.mjs +49 -0
- package/dist/esm/getPragmaOptions.mjs +19 -0
- package/dist/esm/helpers/memoize.mjs +13 -0
- package/dist/esm/helpers/requireTamaguiCore.mjs +5 -0
- package/dist/esm/index.mjs +3 -0
- package/dist/esm/minifyCSS.mjs +12 -0
- package/dist/esm/registerRequire.mjs +74 -0
- package/dist/esm/server.mjs +40 -0
- package/dist/esm/setup.mjs +1 -0
- package/dist/esm/static.mjs +10 -0
- package/dist/esm/types.mjs +0 -0
- package/dist/esm/webpackPlugin.mjs +7 -0
- 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,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 };
|