@plumeria/unplugin 18.1.5 → 18.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core.js +219 -107
- package/dist/core.mjs +219 -107
- package/package.json +2 -2
package/dist/core.js
CHANGED
|
@@ -41,6 +41,70 @@ const zss_engine_1 = require("zss-engine");
|
|
|
41
41
|
const utils_1 = require("@plumeria/utils");
|
|
42
42
|
exports.TARGET_EXTENSIONS = ['ts', 'tsx', 'js', 'jsx'];
|
|
43
43
|
exports.EXTENSION_PATTERN = /\.(ts|tsx|js|jsx)$/;
|
|
44
|
+
const isStaticArgValue = (node) => node.type === 'StringLiteral' ||
|
|
45
|
+
node.type === 'NumericLiteral' ||
|
|
46
|
+
node.type === 'BooleanLiteral' ||
|
|
47
|
+
(node.type === 'TemplateLiteral' && node.expressions.length === 0) ||
|
|
48
|
+
utils_1.t.isIdentifier(node) ||
|
|
49
|
+
utils_1.t.isMemberExpression(node);
|
|
50
|
+
const namedParamsOf = (params) => {
|
|
51
|
+
if (params.length !== 1)
|
|
52
|
+
return undefined;
|
|
53
|
+
const first = params[0];
|
|
54
|
+
const pattern = (first?.pat ?? first);
|
|
55
|
+
if (pattern?.type !== 'ObjectPattern')
|
|
56
|
+
return undefined;
|
|
57
|
+
const named = [];
|
|
58
|
+
for (const prop of pattern.properties ?? []) {
|
|
59
|
+
if (prop.type === 'AssignmentPatternProperty' &&
|
|
60
|
+
utils_1.t.isIdentifier(prop.key) &&
|
|
61
|
+
!prop.value) {
|
|
62
|
+
named.push({ key: prop.key.value, local: prop.key.value });
|
|
63
|
+
}
|
|
64
|
+
else if (prop.type === 'KeyValuePatternProperty' &&
|
|
65
|
+
utils_1.t.isIdentifier(prop.key) &&
|
|
66
|
+
utils_1.t.isIdentifier(prop.value)) {
|
|
67
|
+
named.push({ key: prop.key.value, local: prop.value.value });
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return named.length > 0 ? named : undefined;
|
|
74
|
+
};
|
|
75
|
+
const foldDynamicVars = (vars) => {
|
|
76
|
+
const grouped = new Map();
|
|
77
|
+
[...vars]
|
|
78
|
+
.sort((a, b) => (a.order ?? 0) - (b.order ?? 0))
|
|
79
|
+
.forEach((entry) => {
|
|
80
|
+
const list = grouped.get(entry.cssVar);
|
|
81
|
+
if (list)
|
|
82
|
+
list.push(entry);
|
|
83
|
+
else
|
|
84
|
+
grouped.set(entry.cssVar, [entry]);
|
|
85
|
+
});
|
|
86
|
+
return [...grouped].map(([cssVar, entries]) => {
|
|
87
|
+
let value = 'undefined';
|
|
88
|
+
entries.forEach((entry) => {
|
|
89
|
+
value = entry.test
|
|
90
|
+
? `((${entry.test}) ? ${entry.valueExpr} : ${value})`
|
|
91
|
+
: entry.valueExpr;
|
|
92
|
+
});
|
|
93
|
+
return `"${cssVar}": ${value}`;
|
|
94
|
+
});
|
|
95
|
+
};
|
|
96
|
+
const findVarProp = (style, cssVar) => {
|
|
97
|
+
for (const [prop, value] of Object.entries(style)) {
|
|
98
|
+
if (typeof value === 'string' && value.includes(cssVar))
|
|
99
|
+
return prop;
|
|
100
|
+
if (value !== null && typeof value === 'object') {
|
|
101
|
+
const nested = findVarProp(value, cssVar);
|
|
102
|
+
if (nested)
|
|
103
|
+
return nested;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return undefined;
|
|
107
|
+
};
|
|
44
108
|
const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
45
109
|
const filter = (0, pluginutils_1.createFilter)(options.include, options.exclude);
|
|
46
110
|
const styleProp = options.styleProp ?? utils_1.DEFAULT_STYLE_PROP;
|
|
@@ -384,6 +448,7 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
384
448
|
}
|
|
385
449
|
};
|
|
386
450
|
const replacements = [];
|
|
451
|
+
const dynamicFnCalls = [];
|
|
387
452
|
const processedDecls = new Set();
|
|
388
453
|
const idSpans = new Set();
|
|
389
454
|
const excludedSpans = new Set();
|
|
@@ -461,6 +526,7 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
461
526
|
if (actualBody && actualBody.type === 'ObjectExpression') {
|
|
462
527
|
styleFunctions[prop.key.value] = {
|
|
463
528
|
params,
|
|
529
|
+
named: namedParamsOf(func.params),
|
|
464
530
|
body: actualBody,
|
|
465
531
|
};
|
|
466
532
|
}
|
|
@@ -801,7 +867,110 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
801
867
|
}
|
|
802
868
|
return null;
|
|
803
869
|
};
|
|
804
|
-
const
|
|
870
|
+
const resolveDynamicCall = (expr) => {
|
|
871
|
+
if (!utils_1.t.isCallExpression(expr) || !utils_1.t.isMemberExpression(expr.callee))
|
|
872
|
+
return null;
|
|
873
|
+
const callee = expr.callee;
|
|
874
|
+
if (!utils_1.t.isIdentifier(callee.object) || !utils_1.t.isIdentifier(callee.property))
|
|
875
|
+
return null;
|
|
876
|
+
const styleInfo = localCreateStyles[callee.object.value];
|
|
877
|
+
const func = styleInfo?.functions?.[callee.property.value];
|
|
878
|
+
if (!func)
|
|
879
|
+
return null;
|
|
880
|
+
const callArgs = expr.arguments;
|
|
881
|
+
if (callArgs.some((a) => a.spread) || callArgs.length === 0)
|
|
882
|
+
return null;
|
|
883
|
+
const tempStaticTable = { ...mergedStaticTable };
|
|
884
|
+
const runtime = [];
|
|
885
|
+
const resolveObjectArg = (argExpr) => (0, utils_1.objectExpressionToObject)(argExpr, mergedStaticTable, mergedKeyframesTable, mergedViewTransitionTable, mergedCreateThemeHashTable, scannedTables.createThemeObjectTable, mergedCreateTable, mergedCreateStaticHashTable, scannedTables.createStaticObjectTable, mergedVariantsTable);
|
|
886
|
+
if (func.named) {
|
|
887
|
+
const argExpr = callArgs[0].expression;
|
|
888
|
+
if (callArgs.length !== 1 || argExpr.type !== 'ObjectExpression') {
|
|
889
|
+
throwCompilationError(`Plumeria: ${getSource(expr)} takes one object argument, because ${callee.property.value} destructures its parameter.`, expr);
|
|
890
|
+
}
|
|
891
|
+
const given = new Map();
|
|
892
|
+
argExpr.properties.forEach((prop) => {
|
|
893
|
+
if (prop.type === 'Identifier') {
|
|
894
|
+
given.set(prop.value, prop);
|
|
895
|
+
}
|
|
896
|
+
else if (prop.type === 'KeyValueProperty' &&
|
|
897
|
+
(utils_1.t.isIdentifier(prop.key) || utils_1.t.isStringLiteral(prop.key))) {
|
|
898
|
+
given.set(String(prop.key.value), prop.value);
|
|
899
|
+
}
|
|
900
|
+
});
|
|
901
|
+
const argObj = resolveObjectArg(argExpr) ?? {};
|
|
902
|
+
func.named.forEach(({ key, local }) => {
|
|
903
|
+
const source = given.get(key);
|
|
904
|
+
if (!source) {
|
|
905
|
+
throwCompilationError(`Plumeria: ${getSource(expr)} leaves "${key}" unset, and a dynamic style function has no value to fall back on.`, expr);
|
|
906
|
+
return;
|
|
907
|
+
}
|
|
908
|
+
if (isStaticArgValue(source) && argObj[key] !== undefined)
|
|
909
|
+
tempStaticTable[local] = argObj[key];
|
|
910
|
+
else
|
|
911
|
+
runtime.push({ param: local, source });
|
|
912
|
+
});
|
|
913
|
+
}
|
|
914
|
+
else if (callArgs.length === 1 &&
|
|
915
|
+
callArgs[0].expression.type === 'ObjectExpression') {
|
|
916
|
+
const argObj = resolveObjectArg(callArgs[0].expression) ?? {};
|
|
917
|
+
func.params.forEach((p) => {
|
|
918
|
+
if (argObj[p] !== undefined)
|
|
919
|
+
tempStaticTable[p] = argObj[p];
|
|
920
|
+
});
|
|
921
|
+
}
|
|
922
|
+
else {
|
|
923
|
+
callArgs.forEach((callArg, i) => {
|
|
924
|
+
const p = func.params[i];
|
|
925
|
+
if (!p)
|
|
926
|
+
return;
|
|
927
|
+
runtime.push({ param: p, source: callArg.expression });
|
|
928
|
+
});
|
|
929
|
+
}
|
|
930
|
+
const cssVars = {};
|
|
931
|
+
if (runtime.length > 0) {
|
|
932
|
+
runtime.forEach(({ param }) => (tempStaticTable[param] = param));
|
|
933
|
+
const probe = (0, utils_1.objectExpressionToObject)(func.body, tempStaticTable, mergedKeyframesTable, mergedViewTransitionTable, mergedCreateThemeHashTable, scannedTables.createThemeObjectTable, mergedCreateTable, mergedCreateStaticHashTable, scannedTables.createStaticObjectTable, mergedVariantsTable);
|
|
934
|
+
const hash = (0, zss_engine_1.genBase36Hash)(probe ?? {}, 1, 8);
|
|
935
|
+
runtime.forEach(({ param }) => {
|
|
936
|
+
const cssVar = `--${hash}-${param}`;
|
|
937
|
+
tempStaticTable[param] = `var(${cssVar})`;
|
|
938
|
+
cssVars[param] = cssVar;
|
|
939
|
+
});
|
|
940
|
+
}
|
|
941
|
+
const style = (0, utils_1.objectExpressionToObject)(func.body, tempStaticTable, mergedKeyframesTable, mergedViewTransitionTable, mergedCreateThemeHashTable, scannedTables.createThemeObjectTable, mergedCreateTable, mergedCreateStaticHashTable, scannedTables.createStaticObjectTable, mergedVariantsTable);
|
|
942
|
+
if (!style)
|
|
943
|
+
return null;
|
|
944
|
+
const vars = [];
|
|
945
|
+
runtime.forEach(({ param, source }) => {
|
|
946
|
+
const cssVar = cssVars[param];
|
|
947
|
+
const targetProp = cssVar ? findVarProp(style, cssVar) : undefined;
|
|
948
|
+
if (!targetProp)
|
|
949
|
+
return;
|
|
950
|
+
const argStart = source.span.start - baseByteOffset;
|
|
951
|
+
const argEnd = source.span.end - baseByteOffset;
|
|
952
|
+
const argSource = sourceBuffer
|
|
953
|
+
.subarray(argStart, argEnd)
|
|
954
|
+
.toString('utf-8');
|
|
955
|
+
let valueExpr;
|
|
956
|
+
const maybeNumber = Number(argSource);
|
|
957
|
+
if (!isNaN(maybeNumber) && argSource.trim() === String(maybeNumber)) {
|
|
958
|
+
valueExpr = JSON.stringify((0, zss_engine_1.applyCssValue)(maybeNumber, targetProp));
|
|
959
|
+
}
|
|
960
|
+
else if ((argSource.startsWith('"') && argSource.endsWith('"')) ||
|
|
961
|
+
(argSource.startsWith("'") && argSource.endsWith("'"))) {
|
|
962
|
+
valueExpr = JSON.stringify((0, zss_engine_1.applyCssValue)(argSource.slice(1, -1), targetProp));
|
|
963
|
+
}
|
|
964
|
+
else {
|
|
965
|
+
valueExpr = zss_engine_1.exceptionCamelCase.includes(targetProp)
|
|
966
|
+
? argSource
|
|
967
|
+
: `(typeof (${argSource}) === 'number' ? (${argSource}) + 'px' : (${argSource}))`;
|
|
968
|
+
}
|
|
969
|
+
vars.push({ cssVar, valueExpr });
|
|
970
|
+
});
|
|
971
|
+
return { style, vars };
|
|
972
|
+
};
|
|
973
|
+
const buildClassParts = (args, dynamicClassParts = [], existingClass = '', isStyleProp = false) => {
|
|
805
974
|
args.forEach((arg) => {
|
|
806
975
|
const expr = arg.expression;
|
|
807
976
|
if (utils_1.t.isIdentifier(expr) && localStyleAliases[expr.value]) {
|
|
@@ -809,6 +978,7 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
809
978
|
}
|
|
810
979
|
});
|
|
811
980
|
const conditionals = [];
|
|
981
|
+
const dynamicVars = [];
|
|
812
982
|
let groupIdCounter = 0;
|
|
813
983
|
let sourceOrder = 0;
|
|
814
984
|
const baseChunks = [];
|
|
@@ -927,9 +1097,26 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
927
1097
|
const off = !scoped && groupKeys.has('') ? `${prefix}off` : '';
|
|
928
1098
|
return buildDecision(node, prefix, off, { n: 0 }, scoped);
|
|
929
1099
|
};
|
|
930
|
-
const collectConditions = (node, currentTestStrings = []) => {
|
|
931
|
-
|
|
932
|
-
if (
|
|
1100
|
+
const collectConditions = (node, currentTestStrings = [], argOrder) => {
|
|
1101
|
+
let branchStyle = resolveStyleObject(node);
|
|
1102
|
+
if (!branchStyle) {
|
|
1103
|
+
const dynamic = resolveDynamicCall(node);
|
|
1104
|
+
if (dynamic) {
|
|
1105
|
+
if (!isStyleProp) {
|
|
1106
|
+
throwCompilationError(`Plumeria: css.use(${getSource(node)}) does not support dynamic function keys.`, node);
|
|
1107
|
+
}
|
|
1108
|
+
branchStyle = dynamic.style;
|
|
1109
|
+
dynamic.vars.forEach((v) => dynamicVars.push({
|
|
1110
|
+
...v,
|
|
1111
|
+
test: currentTestStrings.length
|
|
1112
|
+
? currentTestStrings.join(' && ')
|
|
1113
|
+
: undefined,
|
|
1114
|
+
order: argOrder,
|
|
1115
|
+
}));
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
if (branchStyle) {
|
|
1119
|
+
const staticStyle = branchStyle;
|
|
933
1120
|
if (currentTestStrings.length === 0) {
|
|
934
1121
|
baseStyle = (0, utils_1.deepMerge)(baseStyle, staticStyle);
|
|
935
1122
|
baseChunks.push({ order: sourceOrder++, style: staticStyle });
|
|
@@ -963,26 +1150,17 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
963
1150
|
return true;
|
|
964
1151
|
}
|
|
965
1152
|
}
|
|
966
|
-
collectConditions(node.consequent, [
|
|
967
|
-
|
|
968
|
-
`(${testSource})`,
|
|
969
|
-
]);
|
|
970
|
-
collectConditions(node.alternate, [
|
|
971
|
-
...currentTestStrings,
|
|
972
|
-
`!(${testSource})`,
|
|
973
|
-
]);
|
|
1153
|
+
collectConditions(node.consequent, [...currentTestStrings, `(${testSource})`], argOrder);
|
|
1154
|
+
collectConditions(node.alternate, [...currentTestStrings, `!(${testSource})`], argOrder);
|
|
974
1155
|
return true;
|
|
975
1156
|
}
|
|
976
1157
|
else if (node.type === 'BinaryExpression' &&
|
|
977
1158
|
node.operator === '&&') {
|
|
978
|
-
collectConditions(node.right, [
|
|
979
|
-
...currentTestStrings,
|
|
980
|
-
`(${getSource(node.left)})`,
|
|
981
|
-
]);
|
|
1159
|
+
collectConditions(node.right, [...currentTestStrings, `(${getSource(node.left)})`], argOrder);
|
|
982
1160
|
return true;
|
|
983
1161
|
}
|
|
984
1162
|
else if (node.type === 'ParenthesisExpression') {
|
|
985
|
-
return collectConditions(node.expression, currentTestStrings);
|
|
1163
|
+
return collectConditions(node.expression, currentTestStrings, argOrder);
|
|
986
1164
|
}
|
|
987
1165
|
assertResolvable(node);
|
|
988
1166
|
return false;
|
|
@@ -1227,7 +1405,7 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
1227
1405
|
}));
|
|
1228
1406
|
continue;
|
|
1229
1407
|
}
|
|
1230
|
-
const handled = collectConditions(expr);
|
|
1408
|
+
const handled = collectConditions(expr, [], arg.order);
|
|
1231
1409
|
if (handled)
|
|
1232
1410
|
continue;
|
|
1233
1411
|
assertResolvable(expr);
|
|
@@ -1240,6 +1418,7 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
1240
1418
|
classParts: [...dynamicClassParts],
|
|
1241
1419
|
isOptimizable,
|
|
1242
1420
|
baseStyle,
|
|
1421
|
+
dynamicVars,
|
|
1243
1422
|
};
|
|
1244
1423
|
}
|
|
1245
1424
|
const participation = {};
|
|
@@ -1488,7 +1667,7 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
1488
1667
|
classParts.push(`(${JSON.stringify(results)}[${masterKeyExpr || '""'}] || ${baseConflictClass ? JSON.stringify(baseConflictClass) : '""'})`);
|
|
1489
1668
|
}
|
|
1490
1669
|
classParts.push(...dynamicClassParts);
|
|
1491
|
-
return { classParts, isOptimizable, baseStyle };
|
|
1670
|
+
return { classParts, isOptimizable, baseStyle, dynamicVars };
|
|
1492
1671
|
};
|
|
1493
1672
|
(0, utils_1.traverse)(ast, {
|
|
1494
1673
|
JSXOpeningElement({ node }) {
|
|
@@ -1722,13 +1901,13 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
1722
1901
|
if (!node.value || node.value.type !== 'JSXExpressionContainer')
|
|
1723
1902
|
return;
|
|
1724
1903
|
const expr = node.value.expression;
|
|
1725
|
-
|
|
1904
|
+
const args = expr.type === 'ArrayExpression'
|
|
1726
1905
|
? expr.elements
|
|
1727
1906
|
.filter((el) => el !== undefined)
|
|
1728
1907
|
.map((el) => ({ expression: el.expression }))
|
|
1729
1908
|
: [{ expression: expr }];
|
|
1730
1909
|
const dynamicClassParts = [];
|
|
1731
|
-
const
|
|
1910
|
+
const existingStyleParts = [];
|
|
1732
1911
|
let attributes = [];
|
|
1733
1912
|
for (const [, val] of jsxOpeningElementMap) {
|
|
1734
1913
|
const found = val.attributes
|
|
@@ -1782,99 +1961,19 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
1782
1961
|
if (innerExpr.type === 'ObjectExpression') {
|
|
1783
1962
|
const stripped = innerSource.slice(1, -1).trim();
|
|
1784
1963
|
if (stripped)
|
|
1785
|
-
|
|
1964
|
+
existingStyleParts.push(stripped);
|
|
1786
1965
|
}
|
|
1787
1966
|
else {
|
|
1788
1967
|
existingStyleExpr = `...(${innerSource})`;
|
|
1789
1968
|
}
|
|
1790
1969
|
}
|
|
1791
1970
|
}
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
if (!utils_1.t.isIdentifier(callee.object) ||
|
|
1798
|
-
!utils_1.t.isIdentifier(callee.property))
|
|
1799
|
-
return true;
|
|
1800
|
-
const varName = callee.object.value;
|
|
1801
|
-
const propKey = callee.property.value;
|
|
1802
|
-
const styleInfo = localCreateStyles[varName];
|
|
1803
|
-
if (styleInfo?.functions?.[propKey]) {
|
|
1804
|
-
const func = styleInfo.functions[propKey];
|
|
1805
|
-
const callArgs = expr.arguments;
|
|
1806
|
-
const hasSpread = callArgs.some((a) => a.spread);
|
|
1807
|
-
if (!hasSpread && callArgs.length >= 1) {
|
|
1808
|
-
const tempStaticTable = { ...mergedStaticTable };
|
|
1809
|
-
const cssVarInfo = {};
|
|
1810
|
-
if (callArgs.length === 1 &&
|
|
1811
|
-
callArgs[0].expression.type === 'ObjectExpression') {
|
|
1812
|
-
const argObj = (0, utils_1.objectExpressionToObject)(callArgs[0].expression, mergedStaticTable, mergedKeyframesTable, mergedViewTransitionTable, mergedCreateThemeHashTable, scannedTables.createThemeObjectTable, mergedCreateTable, mergedCreateStaticHashTable, scannedTables.createStaticObjectTable, mergedVariantsTable);
|
|
1813
|
-
func.params.forEach((p) => {
|
|
1814
|
-
if (argObj[p] !== undefined)
|
|
1815
|
-
tempStaticTable[p] = argObj[p];
|
|
1816
|
-
});
|
|
1817
|
-
}
|
|
1818
|
-
else {
|
|
1819
|
-
callArgs.forEach((_callArg, i) => {
|
|
1820
|
-
const p = func.params[i];
|
|
1821
|
-
if (!p)
|
|
1822
|
-
return;
|
|
1823
|
-
const cssVar = `--${propKey}-${p}`;
|
|
1824
|
-
tempStaticTable[p] = `var(${cssVar})`;
|
|
1825
|
-
cssVarInfo[p] = { cssVar, propKey: '' };
|
|
1826
|
-
});
|
|
1827
|
-
}
|
|
1828
|
-
const substituted = (0, utils_1.objectExpressionToObject)(func.body, tempStaticTable, mergedKeyframesTable, mergedViewTransitionTable, mergedCreateThemeHashTable, scannedTables.createThemeObjectTable, mergedCreateTable, mergedCreateStaticHashTable, scannedTables.createStaticObjectTable, mergedVariantsTable);
|
|
1829
|
-
if (substituted) {
|
|
1830
|
-
const records = processStyleRecords(substituted);
|
|
1831
|
-
const hashes = records.map((r) => r.hash).join(' ');
|
|
1832
|
-
if (hashes)
|
|
1833
|
-
dynamicClassParts.push(JSON.stringify(hashes));
|
|
1834
|
-
if (Object.keys(cssVarInfo).length > 0) {
|
|
1835
|
-
Object.entries(cssVarInfo).forEach(([paramName, info]) => {
|
|
1836
|
-
const targetProp = Object.keys(substituted).find((k) => typeof substituted[k] === 'string' &&
|
|
1837
|
-
substituted[k].includes(info.cssVar));
|
|
1838
|
-
if (targetProp) {
|
|
1839
|
-
const paramIndex = func.params.indexOf(paramName);
|
|
1840
|
-
const srcArg = paramIndex >= 0 && callArgs[paramIndex]
|
|
1841
|
-
? callArgs[paramIndex].expression
|
|
1842
|
-
: callArgs[0].expression;
|
|
1843
|
-
const argStart = srcArg.span.start - baseByteOffset;
|
|
1844
|
-
const argEnd = srcArg.span.end - baseByteOffset;
|
|
1845
|
-
const argSource = sourceBuffer
|
|
1846
|
-
.subarray(argStart, argEnd)
|
|
1847
|
-
.toString('utf-8');
|
|
1848
|
-
let valueExpr;
|
|
1849
|
-
const maybeNumber = Number(argSource);
|
|
1850
|
-
if (!isNaN(maybeNumber) &&
|
|
1851
|
-
argSource.trim() === String(maybeNumber)) {
|
|
1852
|
-
valueExpr = JSON.stringify((0, zss_engine_1.applyCssValue)(maybeNumber, targetProp));
|
|
1853
|
-
}
|
|
1854
|
-
else if ((argSource.startsWith('"') &&
|
|
1855
|
-
argSource.endsWith('"')) ||
|
|
1856
|
-
(argSource.startsWith("'") && argSource.endsWith("'"))) {
|
|
1857
|
-
valueExpr = JSON.stringify((0, zss_engine_1.applyCssValue)(argSource.slice(1, -1), targetProp));
|
|
1858
|
-
}
|
|
1859
|
-
else {
|
|
1860
|
-
valueExpr = zss_engine_1.exceptionCamelCase.includes(targetProp)
|
|
1861
|
-
? argSource
|
|
1862
|
-
: `(typeof (${argSource}) === 'number' ? (${argSource}) + 'px' : (${argSource}))`;
|
|
1863
|
-
}
|
|
1864
|
-
dynamicStyleParts.push(`"${info.cssVar}": ${valueExpr}`);
|
|
1865
|
-
}
|
|
1866
|
-
});
|
|
1867
|
-
}
|
|
1868
|
-
return false;
|
|
1869
|
-
}
|
|
1870
|
-
}
|
|
1871
|
-
}
|
|
1872
|
-
return true;
|
|
1873
|
-
});
|
|
1874
|
-
const styleAttr = dynamicStyleParts.length > 0 || existingStyleExpr
|
|
1875
|
-
? ` style={{ ${[existingStyleExpr, ...dynamicStyleParts].filter(Boolean).join(', ')} }}`
|
|
1971
|
+
const { classParts, isOptimizable, baseStyle, dynamicVars } = buildClassParts(args, dynamicClassParts, existingClassExpr, true);
|
|
1972
|
+
const dynamicStyleParts = foldDynamicVars(dynamicVars);
|
|
1973
|
+
const styleParts = [...existingStyleParts, ...dynamicStyleParts];
|
|
1974
|
+
const styleAttr = styleParts.length > 0 || existingStyleExpr
|
|
1975
|
+
? ` style={{ ${[existingStyleExpr, ...styleParts].filter(Boolean).join(', ')} }}`
|
|
1876
1976
|
: '';
|
|
1877
|
-
const { classParts, isOptimizable, baseStyle } = buildClassParts(args, dynamicClassParts, existingClassExpr);
|
|
1878
1977
|
if (isOptimizable &&
|
|
1879
1978
|
(args.length > 0 ||
|
|
1880
1979
|
Object.keys(baseStyle).length > 0 ||
|
|
@@ -1902,6 +2001,9 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
1902
2001
|
utils_1.t.isIdentifier(callee.property)) {
|
|
1903
2002
|
const objectName = callee.object.value;
|
|
1904
2003
|
const propertyName = callee.property.value;
|
|
2004
|
+
if (localCreateStyles[objectName]?.functions?.[propertyName]) {
|
|
2005
|
+
dynamicFnCalls.push(node);
|
|
2006
|
+
}
|
|
1905
2007
|
const alias = plumeriaAliases[objectName];
|
|
1906
2008
|
if (alias === 'NAMESPACE' && propertyName === 'use') {
|
|
1907
2009
|
isUseCall = true;
|
|
@@ -1975,6 +2077,16 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
1975
2077
|
});
|
|
1976
2078
|
}
|
|
1977
2079
|
});
|
|
2080
|
+
dynamicFnCalls.forEach((call) => {
|
|
2081
|
+
const start = call.span.start - baseByteOffset;
|
|
2082
|
+
const end = call.span.end - baseByteOffset;
|
|
2083
|
+
const isResolved = replacements.some((r) => r.start <= start && r.end >= end);
|
|
2084
|
+
if (!isResolved) {
|
|
2085
|
+
throwCompilationError(`Plumeria: ${getSource(call)} is only supported in the ${styleProp} prop. ` +
|
|
2086
|
+
`A dynamic style function resolves to a class name and a CSS variable on the element itself, ` +
|
|
2087
|
+
`so it cannot be passed through another prop or read as a value.`, call);
|
|
2088
|
+
}
|
|
2089
|
+
});
|
|
1978
2090
|
const buffer = Buffer.from(source);
|
|
1979
2091
|
let offset = 0;
|
|
1980
2092
|
const parts = [];
|
package/dist/core.mjs
CHANGED
|
@@ -5,6 +5,70 @@ import { applyCssValue, genBase36Hash, exceptionCamelCase, camelToKebabCase, isA
|
|
|
5
5
|
import { traverse, collectReferenceIdentifiers, getStyleRecords, collectLocalConsts, objectExpressionToObject, t, getRootIdentifier, extractOndemandStyles, deepMerge, scanAll, resolveImportPath, getLeadingCommentLength, optimizer, getFileDependencies, resolveExport, resolveComponentKey, DEFAULT_STYLE_PROP, } from '@plumeria/utils';
|
|
6
6
|
export const TARGET_EXTENSIONS = ['ts', 'tsx', 'js', 'jsx'];
|
|
7
7
|
export const EXTENSION_PATTERN = /\.(ts|tsx|js|jsx)$/;
|
|
8
|
+
const isStaticArgValue = (node) => node.type === 'StringLiteral' ||
|
|
9
|
+
node.type === 'NumericLiteral' ||
|
|
10
|
+
node.type === 'BooleanLiteral' ||
|
|
11
|
+
(node.type === 'TemplateLiteral' && node.expressions.length === 0) ||
|
|
12
|
+
t.isIdentifier(node) ||
|
|
13
|
+
t.isMemberExpression(node);
|
|
14
|
+
const namedParamsOf = (params) => {
|
|
15
|
+
if (params.length !== 1)
|
|
16
|
+
return undefined;
|
|
17
|
+
const first = params[0];
|
|
18
|
+
const pattern = (first?.pat ?? first);
|
|
19
|
+
if (pattern?.type !== 'ObjectPattern')
|
|
20
|
+
return undefined;
|
|
21
|
+
const named = [];
|
|
22
|
+
for (const prop of pattern.properties ?? []) {
|
|
23
|
+
if (prop.type === 'AssignmentPatternProperty' &&
|
|
24
|
+
t.isIdentifier(prop.key) &&
|
|
25
|
+
!prop.value) {
|
|
26
|
+
named.push({ key: prop.key.value, local: prop.key.value });
|
|
27
|
+
}
|
|
28
|
+
else if (prop.type === 'KeyValuePatternProperty' &&
|
|
29
|
+
t.isIdentifier(prop.key) &&
|
|
30
|
+
t.isIdentifier(prop.value)) {
|
|
31
|
+
named.push({ key: prop.key.value, local: prop.value.value });
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return named.length > 0 ? named : undefined;
|
|
38
|
+
};
|
|
39
|
+
const foldDynamicVars = (vars) => {
|
|
40
|
+
const grouped = new Map();
|
|
41
|
+
[...vars]
|
|
42
|
+
.sort((a, b) => (a.order ?? 0) - (b.order ?? 0))
|
|
43
|
+
.forEach((entry) => {
|
|
44
|
+
const list = grouped.get(entry.cssVar);
|
|
45
|
+
if (list)
|
|
46
|
+
list.push(entry);
|
|
47
|
+
else
|
|
48
|
+
grouped.set(entry.cssVar, [entry]);
|
|
49
|
+
});
|
|
50
|
+
return [...grouped].map(([cssVar, entries]) => {
|
|
51
|
+
let value = 'undefined';
|
|
52
|
+
entries.forEach((entry) => {
|
|
53
|
+
value = entry.test
|
|
54
|
+
? `((${entry.test}) ? ${entry.valueExpr} : ${value})`
|
|
55
|
+
: entry.valueExpr;
|
|
56
|
+
});
|
|
57
|
+
return `"${cssVar}": ${value}`;
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
const findVarProp = (style, cssVar) => {
|
|
61
|
+
for (const [prop, value] of Object.entries(style)) {
|
|
62
|
+
if (typeof value === 'string' && value.includes(cssVar))
|
|
63
|
+
return prop;
|
|
64
|
+
if (value !== null && typeof value === 'object') {
|
|
65
|
+
const nested = findVarProp(value, cssVar);
|
|
66
|
+
if (nested)
|
|
67
|
+
return nested;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return undefined;
|
|
71
|
+
};
|
|
8
72
|
export const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
9
73
|
const filter = createFilter(options.include, options.exclude);
|
|
10
74
|
const styleProp = options.styleProp ?? DEFAULT_STYLE_PROP;
|
|
@@ -348,6 +412,7 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
348
412
|
}
|
|
349
413
|
};
|
|
350
414
|
const replacements = [];
|
|
415
|
+
const dynamicFnCalls = [];
|
|
351
416
|
const processedDecls = new Set();
|
|
352
417
|
const idSpans = new Set();
|
|
353
418
|
const excludedSpans = new Set();
|
|
@@ -425,6 +490,7 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
425
490
|
if (actualBody && actualBody.type === 'ObjectExpression') {
|
|
426
491
|
styleFunctions[prop.key.value] = {
|
|
427
492
|
params,
|
|
493
|
+
named: namedParamsOf(func.params),
|
|
428
494
|
body: actualBody,
|
|
429
495
|
};
|
|
430
496
|
}
|
|
@@ -765,7 +831,110 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
765
831
|
}
|
|
766
832
|
return null;
|
|
767
833
|
};
|
|
768
|
-
const
|
|
834
|
+
const resolveDynamicCall = (expr) => {
|
|
835
|
+
if (!t.isCallExpression(expr) || !t.isMemberExpression(expr.callee))
|
|
836
|
+
return null;
|
|
837
|
+
const callee = expr.callee;
|
|
838
|
+
if (!t.isIdentifier(callee.object) || !t.isIdentifier(callee.property))
|
|
839
|
+
return null;
|
|
840
|
+
const styleInfo = localCreateStyles[callee.object.value];
|
|
841
|
+
const func = styleInfo?.functions?.[callee.property.value];
|
|
842
|
+
if (!func)
|
|
843
|
+
return null;
|
|
844
|
+
const callArgs = expr.arguments;
|
|
845
|
+
if (callArgs.some((a) => a.spread) || callArgs.length === 0)
|
|
846
|
+
return null;
|
|
847
|
+
const tempStaticTable = { ...mergedStaticTable };
|
|
848
|
+
const runtime = [];
|
|
849
|
+
const resolveObjectArg = (argExpr) => objectExpressionToObject(argExpr, mergedStaticTable, mergedKeyframesTable, mergedViewTransitionTable, mergedCreateThemeHashTable, scannedTables.createThemeObjectTable, mergedCreateTable, mergedCreateStaticHashTable, scannedTables.createStaticObjectTable, mergedVariantsTable);
|
|
850
|
+
if (func.named) {
|
|
851
|
+
const argExpr = callArgs[0].expression;
|
|
852
|
+
if (callArgs.length !== 1 || argExpr.type !== 'ObjectExpression') {
|
|
853
|
+
throwCompilationError(`Plumeria: ${getSource(expr)} takes one object argument, because ${callee.property.value} destructures its parameter.`, expr);
|
|
854
|
+
}
|
|
855
|
+
const given = new Map();
|
|
856
|
+
argExpr.properties.forEach((prop) => {
|
|
857
|
+
if (prop.type === 'Identifier') {
|
|
858
|
+
given.set(prop.value, prop);
|
|
859
|
+
}
|
|
860
|
+
else if (prop.type === 'KeyValueProperty' &&
|
|
861
|
+
(t.isIdentifier(prop.key) || t.isStringLiteral(prop.key))) {
|
|
862
|
+
given.set(String(prop.key.value), prop.value);
|
|
863
|
+
}
|
|
864
|
+
});
|
|
865
|
+
const argObj = resolveObjectArg(argExpr) ?? {};
|
|
866
|
+
func.named.forEach(({ key, local }) => {
|
|
867
|
+
const source = given.get(key);
|
|
868
|
+
if (!source) {
|
|
869
|
+
throwCompilationError(`Plumeria: ${getSource(expr)} leaves "${key}" unset, and a dynamic style function has no value to fall back on.`, expr);
|
|
870
|
+
return;
|
|
871
|
+
}
|
|
872
|
+
if (isStaticArgValue(source) && argObj[key] !== undefined)
|
|
873
|
+
tempStaticTable[local] = argObj[key];
|
|
874
|
+
else
|
|
875
|
+
runtime.push({ param: local, source });
|
|
876
|
+
});
|
|
877
|
+
}
|
|
878
|
+
else if (callArgs.length === 1 &&
|
|
879
|
+
callArgs[0].expression.type === 'ObjectExpression') {
|
|
880
|
+
const argObj = resolveObjectArg(callArgs[0].expression) ?? {};
|
|
881
|
+
func.params.forEach((p) => {
|
|
882
|
+
if (argObj[p] !== undefined)
|
|
883
|
+
tempStaticTable[p] = argObj[p];
|
|
884
|
+
});
|
|
885
|
+
}
|
|
886
|
+
else {
|
|
887
|
+
callArgs.forEach((callArg, i) => {
|
|
888
|
+
const p = func.params[i];
|
|
889
|
+
if (!p)
|
|
890
|
+
return;
|
|
891
|
+
runtime.push({ param: p, source: callArg.expression });
|
|
892
|
+
});
|
|
893
|
+
}
|
|
894
|
+
const cssVars = {};
|
|
895
|
+
if (runtime.length > 0) {
|
|
896
|
+
runtime.forEach(({ param }) => (tempStaticTable[param] = param));
|
|
897
|
+
const probe = objectExpressionToObject(func.body, tempStaticTable, mergedKeyframesTable, mergedViewTransitionTable, mergedCreateThemeHashTable, scannedTables.createThemeObjectTable, mergedCreateTable, mergedCreateStaticHashTable, scannedTables.createStaticObjectTable, mergedVariantsTable);
|
|
898
|
+
const hash = genBase36Hash(probe ?? {}, 1, 8);
|
|
899
|
+
runtime.forEach(({ param }) => {
|
|
900
|
+
const cssVar = `--${hash}-${param}`;
|
|
901
|
+
tempStaticTable[param] = `var(${cssVar})`;
|
|
902
|
+
cssVars[param] = cssVar;
|
|
903
|
+
});
|
|
904
|
+
}
|
|
905
|
+
const style = objectExpressionToObject(func.body, tempStaticTable, mergedKeyframesTable, mergedViewTransitionTable, mergedCreateThemeHashTable, scannedTables.createThemeObjectTable, mergedCreateTable, mergedCreateStaticHashTable, scannedTables.createStaticObjectTable, mergedVariantsTable);
|
|
906
|
+
if (!style)
|
|
907
|
+
return null;
|
|
908
|
+
const vars = [];
|
|
909
|
+
runtime.forEach(({ param, source }) => {
|
|
910
|
+
const cssVar = cssVars[param];
|
|
911
|
+
const targetProp = cssVar ? findVarProp(style, cssVar) : undefined;
|
|
912
|
+
if (!targetProp)
|
|
913
|
+
return;
|
|
914
|
+
const argStart = source.span.start - baseByteOffset;
|
|
915
|
+
const argEnd = source.span.end - baseByteOffset;
|
|
916
|
+
const argSource = sourceBuffer
|
|
917
|
+
.subarray(argStart, argEnd)
|
|
918
|
+
.toString('utf-8');
|
|
919
|
+
let valueExpr;
|
|
920
|
+
const maybeNumber = Number(argSource);
|
|
921
|
+
if (!isNaN(maybeNumber) && argSource.trim() === String(maybeNumber)) {
|
|
922
|
+
valueExpr = JSON.stringify(applyCssValue(maybeNumber, targetProp));
|
|
923
|
+
}
|
|
924
|
+
else if ((argSource.startsWith('"') && argSource.endsWith('"')) ||
|
|
925
|
+
(argSource.startsWith("'") && argSource.endsWith("'"))) {
|
|
926
|
+
valueExpr = JSON.stringify(applyCssValue(argSource.slice(1, -1), targetProp));
|
|
927
|
+
}
|
|
928
|
+
else {
|
|
929
|
+
valueExpr = exceptionCamelCase.includes(targetProp)
|
|
930
|
+
? argSource
|
|
931
|
+
: `(typeof (${argSource}) === 'number' ? (${argSource}) + 'px' : (${argSource}))`;
|
|
932
|
+
}
|
|
933
|
+
vars.push({ cssVar, valueExpr });
|
|
934
|
+
});
|
|
935
|
+
return { style, vars };
|
|
936
|
+
};
|
|
937
|
+
const buildClassParts = (args, dynamicClassParts = [], existingClass = '', isStyleProp = false) => {
|
|
769
938
|
args.forEach((arg) => {
|
|
770
939
|
const expr = arg.expression;
|
|
771
940
|
if (t.isIdentifier(expr) && localStyleAliases[expr.value]) {
|
|
@@ -773,6 +942,7 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
773
942
|
}
|
|
774
943
|
});
|
|
775
944
|
const conditionals = [];
|
|
945
|
+
const dynamicVars = [];
|
|
776
946
|
let groupIdCounter = 0;
|
|
777
947
|
let sourceOrder = 0;
|
|
778
948
|
const baseChunks = [];
|
|
@@ -891,9 +1061,26 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
891
1061
|
const off = !scoped && groupKeys.has('') ? `${prefix}off` : '';
|
|
892
1062
|
return buildDecision(node, prefix, off, { n: 0 }, scoped);
|
|
893
1063
|
};
|
|
894
|
-
const collectConditions = (node, currentTestStrings = []) => {
|
|
895
|
-
|
|
896
|
-
if (
|
|
1064
|
+
const collectConditions = (node, currentTestStrings = [], argOrder) => {
|
|
1065
|
+
let branchStyle = resolveStyleObject(node);
|
|
1066
|
+
if (!branchStyle) {
|
|
1067
|
+
const dynamic = resolveDynamicCall(node);
|
|
1068
|
+
if (dynamic) {
|
|
1069
|
+
if (!isStyleProp) {
|
|
1070
|
+
throwCompilationError(`Plumeria: css.use(${getSource(node)}) does not support dynamic function keys.`, node);
|
|
1071
|
+
}
|
|
1072
|
+
branchStyle = dynamic.style;
|
|
1073
|
+
dynamic.vars.forEach((v) => dynamicVars.push({
|
|
1074
|
+
...v,
|
|
1075
|
+
test: currentTestStrings.length
|
|
1076
|
+
? currentTestStrings.join(' && ')
|
|
1077
|
+
: undefined,
|
|
1078
|
+
order: argOrder,
|
|
1079
|
+
}));
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
if (branchStyle) {
|
|
1083
|
+
const staticStyle = branchStyle;
|
|
897
1084
|
if (currentTestStrings.length === 0) {
|
|
898
1085
|
baseStyle = deepMerge(baseStyle, staticStyle);
|
|
899
1086
|
baseChunks.push({ order: sourceOrder++, style: staticStyle });
|
|
@@ -927,26 +1114,17 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
927
1114
|
return true;
|
|
928
1115
|
}
|
|
929
1116
|
}
|
|
930
|
-
collectConditions(node.consequent, [
|
|
931
|
-
|
|
932
|
-
`(${testSource})`,
|
|
933
|
-
]);
|
|
934
|
-
collectConditions(node.alternate, [
|
|
935
|
-
...currentTestStrings,
|
|
936
|
-
`!(${testSource})`,
|
|
937
|
-
]);
|
|
1117
|
+
collectConditions(node.consequent, [...currentTestStrings, `(${testSource})`], argOrder);
|
|
1118
|
+
collectConditions(node.alternate, [...currentTestStrings, `!(${testSource})`], argOrder);
|
|
938
1119
|
return true;
|
|
939
1120
|
}
|
|
940
1121
|
else if (node.type === 'BinaryExpression' &&
|
|
941
1122
|
node.operator === '&&') {
|
|
942
|
-
collectConditions(node.right, [
|
|
943
|
-
...currentTestStrings,
|
|
944
|
-
`(${getSource(node.left)})`,
|
|
945
|
-
]);
|
|
1123
|
+
collectConditions(node.right, [...currentTestStrings, `(${getSource(node.left)})`], argOrder);
|
|
946
1124
|
return true;
|
|
947
1125
|
}
|
|
948
1126
|
else if (node.type === 'ParenthesisExpression') {
|
|
949
|
-
return collectConditions(node.expression, currentTestStrings);
|
|
1127
|
+
return collectConditions(node.expression, currentTestStrings, argOrder);
|
|
950
1128
|
}
|
|
951
1129
|
assertResolvable(node);
|
|
952
1130
|
return false;
|
|
@@ -1191,7 +1369,7 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
1191
1369
|
}));
|
|
1192
1370
|
continue;
|
|
1193
1371
|
}
|
|
1194
|
-
const handled = collectConditions(expr);
|
|
1372
|
+
const handled = collectConditions(expr, [], arg.order);
|
|
1195
1373
|
if (handled)
|
|
1196
1374
|
continue;
|
|
1197
1375
|
assertResolvable(expr);
|
|
@@ -1204,6 +1382,7 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
1204
1382
|
classParts: [...dynamicClassParts],
|
|
1205
1383
|
isOptimizable,
|
|
1206
1384
|
baseStyle,
|
|
1385
|
+
dynamicVars,
|
|
1207
1386
|
};
|
|
1208
1387
|
}
|
|
1209
1388
|
const participation = {};
|
|
@@ -1452,7 +1631,7 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
1452
1631
|
classParts.push(`(${JSON.stringify(results)}[${masterKeyExpr || '""'}] || ${baseConflictClass ? JSON.stringify(baseConflictClass) : '""'})`);
|
|
1453
1632
|
}
|
|
1454
1633
|
classParts.push(...dynamicClassParts);
|
|
1455
|
-
return { classParts, isOptimizable, baseStyle };
|
|
1634
|
+
return { classParts, isOptimizable, baseStyle, dynamicVars };
|
|
1456
1635
|
};
|
|
1457
1636
|
traverse(ast, {
|
|
1458
1637
|
JSXOpeningElement({ node }) {
|
|
@@ -1686,13 +1865,13 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
1686
1865
|
if (!node.value || node.value.type !== 'JSXExpressionContainer')
|
|
1687
1866
|
return;
|
|
1688
1867
|
const expr = node.value.expression;
|
|
1689
|
-
|
|
1868
|
+
const args = expr.type === 'ArrayExpression'
|
|
1690
1869
|
? expr.elements
|
|
1691
1870
|
.filter((el) => el !== undefined)
|
|
1692
1871
|
.map((el) => ({ expression: el.expression }))
|
|
1693
1872
|
: [{ expression: expr }];
|
|
1694
1873
|
const dynamicClassParts = [];
|
|
1695
|
-
const
|
|
1874
|
+
const existingStyleParts = [];
|
|
1696
1875
|
let attributes = [];
|
|
1697
1876
|
for (const [, val] of jsxOpeningElementMap) {
|
|
1698
1877
|
const found = val.attributes
|
|
@@ -1746,99 +1925,19 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
1746
1925
|
if (innerExpr.type === 'ObjectExpression') {
|
|
1747
1926
|
const stripped = innerSource.slice(1, -1).trim();
|
|
1748
1927
|
if (stripped)
|
|
1749
|
-
|
|
1928
|
+
existingStyleParts.push(stripped);
|
|
1750
1929
|
}
|
|
1751
1930
|
else {
|
|
1752
1931
|
existingStyleExpr = `...(${innerSource})`;
|
|
1753
1932
|
}
|
|
1754
1933
|
}
|
|
1755
1934
|
}
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
if (!t.isIdentifier(callee.object) ||
|
|
1762
|
-
!t.isIdentifier(callee.property))
|
|
1763
|
-
return true;
|
|
1764
|
-
const varName = callee.object.value;
|
|
1765
|
-
const propKey = callee.property.value;
|
|
1766
|
-
const styleInfo = localCreateStyles[varName];
|
|
1767
|
-
if (styleInfo?.functions?.[propKey]) {
|
|
1768
|
-
const func = styleInfo.functions[propKey];
|
|
1769
|
-
const callArgs = expr.arguments;
|
|
1770
|
-
const hasSpread = callArgs.some((a) => a.spread);
|
|
1771
|
-
if (!hasSpread && callArgs.length >= 1) {
|
|
1772
|
-
const tempStaticTable = { ...mergedStaticTable };
|
|
1773
|
-
const cssVarInfo = {};
|
|
1774
|
-
if (callArgs.length === 1 &&
|
|
1775
|
-
callArgs[0].expression.type === 'ObjectExpression') {
|
|
1776
|
-
const argObj = objectExpressionToObject(callArgs[0].expression, mergedStaticTable, mergedKeyframesTable, mergedViewTransitionTable, mergedCreateThemeHashTable, scannedTables.createThemeObjectTable, mergedCreateTable, mergedCreateStaticHashTable, scannedTables.createStaticObjectTable, mergedVariantsTable);
|
|
1777
|
-
func.params.forEach((p) => {
|
|
1778
|
-
if (argObj[p] !== undefined)
|
|
1779
|
-
tempStaticTable[p] = argObj[p];
|
|
1780
|
-
});
|
|
1781
|
-
}
|
|
1782
|
-
else {
|
|
1783
|
-
callArgs.forEach((_callArg, i) => {
|
|
1784
|
-
const p = func.params[i];
|
|
1785
|
-
if (!p)
|
|
1786
|
-
return;
|
|
1787
|
-
const cssVar = `--${propKey}-${p}`;
|
|
1788
|
-
tempStaticTable[p] = `var(${cssVar})`;
|
|
1789
|
-
cssVarInfo[p] = { cssVar, propKey: '' };
|
|
1790
|
-
});
|
|
1791
|
-
}
|
|
1792
|
-
const substituted = objectExpressionToObject(func.body, tempStaticTable, mergedKeyframesTable, mergedViewTransitionTable, mergedCreateThemeHashTable, scannedTables.createThemeObjectTable, mergedCreateTable, mergedCreateStaticHashTable, scannedTables.createStaticObjectTable, mergedVariantsTable);
|
|
1793
|
-
if (substituted) {
|
|
1794
|
-
const records = processStyleRecords(substituted);
|
|
1795
|
-
const hashes = records.map((r) => r.hash).join(' ');
|
|
1796
|
-
if (hashes)
|
|
1797
|
-
dynamicClassParts.push(JSON.stringify(hashes));
|
|
1798
|
-
if (Object.keys(cssVarInfo).length > 0) {
|
|
1799
|
-
Object.entries(cssVarInfo).forEach(([paramName, info]) => {
|
|
1800
|
-
const targetProp = Object.keys(substituted).find((k) => typeof substituted[k] === 'string' &&
|
|
1801
|
-
substituted[k].includes(info.cssVar));
|
|
1802
|
-
if (targetProp) {
|
|
1803
|
-
const paramIndex = func.params.indexOf(paramName);
|
|
1804
|
-
const srcArg = paramIndex >= 0 && callArgs[paramIndex]
|
|
1805
|
-
? callArgs[paramIndex].expression
|
|
1806
|
-
: callArgs[0].expression;
|
|
1807
|
-
const argStart = srcArg.span.start - baseByteOffset;
|
|
1808
|
-
const argEnd = srcArg.span.end - baseByteOffset;
|
|
1809
|
-
const argSource = sourceBuffer
|
|
1810
|
-
.subarray(argStart, argEnd)
|
|
1811
|
-
.toString('utf-8');
|
|
1812
|
-
let valueExpr;
|
|
1813
|
-
const maybeNumber = Number(argSource);
|
|
1814
|
-
if (!isNaN(maybeNumber) &&
|
|
1815
|
-
argSource.trim() === String(maybeNumber)) {
|
|
1816
|
-
valueExpr = JSON.stringify(applyCssValue(maybeNumber, targetProp));
|
|
1817
|
-
}
|
|
1818
|
-
else if ((argSource.startsWith('"') &&
|
|
1819
|
-
argSource.endsWith('"')) ||
|
|
1820
|
-
(argSource.startsWith("'") && argSource.endsWith("'"))) {
|
|
1821
|
-
valueExpr = JSON.stringify(applyCssValue(argSource.slice(1, -1), targetProp));
|
|
1822
|
-
}
|
|
1823
|
-
else {
|
|
1824
|
-
valueExpr = exceptionCamelCase.includes(targetProp)
|
|
1825
|
-
? argSource
|
|
1826
|
-
: `(typeof (${argSource}) === 'number' ? (${argSource}) + 'px' : (${argSource}))`;
|
|
1827
|
-
}
|
|
1828
|
-
dynamicStyleParts.push(`"${info.cssVar}": ${valueExpr}`);
|
|
1829
|
-
}
|
|
1830
|
-
});
|
|
1831
|
-
}
|
|
1832
|
-
return false;
|
|
1833
|
-
}
|
|
1834
|
-
}
|
|
1835
|
-
}
|
|
1836
|
-
return true;
|
|
1837
|
-
});
|
|
1838
|
-
const styleAttr = dynamicStyleParts.length > 0 || existingStyleExpr
|
|
1839
|
-
? ` style={{ ${[existingStyleExpr, ...dynamicStyleParts].filter(Boolean).join(', ')} }}`
|
|
1935
|
+
const { classParts, isOptimizable, baseStyle, dynamicVars } = buildClassParts(args, dynamicClassParts, existingClassExpr, true);
|
|
1936
|
+
const dynamicStyleParts = foldDynamicVars(dynamicVars);
|
|
1937
|
+
const styleParts = [...existingStyleParts, ...dynamicStyleParts];
|
|
1938
|
+
const styleAttr = styleParts.length > 0 || existingStyleExpr
|
|
1939
|
+
? ` style={{ ${[existingStyleExpr, ...styleParts].filter(Boolean).join(', ')} }}`
|
|
1840
1940
|
: '';
|
|
1841
|
-
const { classParts, isOptimizable, baseStyle } = buildClassParts(args, dynamicClassParts, existingClassExpr);
|
|
1842
1941
|
if (isOptimizable &&
|
|
1843
1942
|
(args.length > 0 ||
|
|
1844
1943
|
Object.keys(baseStyle).length > 0 ||
|
|
@@ -1866,6 +1965,9 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
1866
1965
|
t.isIdentifier(callee.property)) {
|
|
1867
1966
|
const objectName = callee.object.value;
|
|
1868
1967
|
const propertyName = callee.property.value;
|
|
1968
|
+
if (localCreateStyles[objectName]?.functions?.[propertyName]) {
|
|
1969
|
+
dynamicFnCalls.push(node);
|
|
1970
|
+
}
|
|
1869
1971
|
const alias = plumeriaAliases[objectName];
|
|
1870
1972
|
if (alias === 'NAMESPACE' && propertyName === 'use') {
|
|
1871
1973
|
isUseCall = true;
|
|
@@ -1939,6 +2041,16 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
1939
2041
|
});
|
|
1940
2042
|
}
|
|
1941
2043
|
});
|
|
2044
|
+
dynamicFnCalls.forEach((call) => {
|
|
2045
|
+
const start = call.span.start - baseByteOffset;
|
|
2046
|
+
const end = call.span.end - baseByteOffset;
|
|
2047
|
+
const isResolved = replacements.some((r) => r.start <= start && r.end >= end);
|
|
2048
|
+
if (!isResolved) {
|
|
2049
|
+
throwCompilationError(`Plumeria: ${getSource(call)} is only supported in the ${styleProp} prop. ` +
|
|
2050
|
+
`A dynamic style function resolves to a class name and a CSS variable on the element itself, ` +
|
|
2051
|
+
`so it cannot be passed through another prop or read as a value.`, call);
|
|
2052
|
+
}
|
|
2053
|
+
});
|
|
1942
2054
|
const buffer = Buffer.from(source);
|
|
1943
2055
|
let offset = 0;
|
|
1944
2056
|
const parts = [];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plumeria/unplugin",
|
|
3
|
-
"version": "18.1.
|
|
3
|
+
"version": "18.1.7",
|
|
4
4
|
"description": "Universal Plumeria plugin for various build tools",
|
|
5
5
|
"author": "Refirst 11",
|
|
6
6
|
"license": "MIT",
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
"dependencies": {
|
|
90
90
|
"@rollup/pluginutils": "^5.4.0",
|
|
91
91
|
"unplugin": "^3.0.0",
|
|
92
|
-
"@plumeria/utils": "^18.1.
|
|
92
|
+
"@plumeria/utils": "^18.1.7"
|
|
93
93
|
},
|
|
94
94
|
"devDependencies": {
|
|
95
95
|
"@swc/core": "1.15.47",
|