@tamagui/static 1.88.13 → 1.89.0-1706308641099
Sign up to get free protection for your applications and to get access to all the features.
- 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 };
|