@plumeria/unplugin 18.4.1 → 18.5.0
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 +144 -38
- package/dist/core.mjs +145 -39
- package/package.json +2 -2
package/dist/core.js
CHANGED
|
@@ -65,12 +65,37 @@ const componentFunctionOf = (node) => {
|
|
|
65
65
|
}
|
|
66
66
|
return undefined;
|
|
67
67
|
};
|
|
68
|
+
const unwrapPatternDefault = (pattern) => pattern?.type === 'AssignmentPattern' ? pattern.left : pattern;
|
|
69
|
+
const destructuredPropAliases = (fn) => {
|
|
70
|
+
const aliases = new Map();
|
|
71
|
+
const first = fn.params[0];
|
|
72
|
+
const pattern = unwrapPatternDefault(first?.pat ?? first);
|
|
73
|
+
if (pattern?.type !== 'ObjectPattern')
|
|
74
|
+
return aliases;
|
|
75
|
+
for (const item of pattern.properties ?? []) {
|
|
76
|
+
if (item.type !== 'KeyValuePatternProperty')
|
|
77
|
+
continue;
|
|
78
|
+
const local = unwrapPatternDefault(item.value);
|
|
79
|
+
const key = item.key;
|
|
80
|
+
if (!utils_1.t.isIdentifier(local))
|
|
81
|
+
continue;
|
|
82
|
+
if (!utils_1.t.isIdentifier(key) && !utils_1.t.isStringLiteral(key))
|
|
83
|
+
continue;
|
|
84
|
+
const name = String(key.value);
|
|
85
|
+
if (name !== local.value)
|
|
86
|
+
aliases.set(local.value, name);
|
|
87
|
+
}
|
|
88
|
+
return aliases;
|
|
89
|
+
};
|
|
68
90
|
const isStaticArgValue = (node) => node.type === 'StringLiteral' ||
|
|
69
91
|
node.type === 'NumericLiteral' ||
|
|
70
92
|
node.type === 'BooleanLiteral' ||
|
|
71
93
|
(node.type === 'TemplateLiteral' && node.expressions.length === 0) ||
|
|
72
94
|
utils_1.t.isIdentifier(node) ||
|
|
73
95
|
utils_1.t.isMemberExpression(node);
|
|
96
|
+
const isNoOpStyle = (node) => utils_1.t.isNullLiteral(node) ||
|
|
97
|
+
(utils_1.t.isBooleanLiteral(node) && node.value === false) ||
|
|
98
|
+
(utils_1.t.isIdentifier(node) && node.value === 'undefined');
|
|
74
99
|
const foldDynamicVars = (vars) => {
|
|
75
100
|
const grouped = new Map();
|
|
76
101
|
[...vars]
|
|
@@ -247,18 +272,22 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
247
272
|
}
|
|
248
273
|
}
|
|
249
274
|
const components = [];
|
|
275
|
+
const propAliases = new Map();
|
|
276
|
+
const addComponent = (name, fn) => {
|
|
277
|
+
components.push({ name, node: fn });
|
|
278
|
+
const aliases = destructuredPropAliases(fn);
|
|
279
|
+
if (aliases.size > 0)
|
|
280
|
+
propAliases.set(name, aliases);
|
|
281
|
+
};
|
|
250
282
|
for (const node of ast.body) {
|
|
251
283
|
const statement = unwrapExport(node);
|
|
252
284
|
if (isFunctionNode(statement)) {
|
|
253
|
-
|
|
254
|
-
name: statement.identifier?.value ?? 'default',
|
|
255
|
-
node: statement,
|
|
256
|
-
});
|
|
285
|
+
addComponent(statement.identifier?.value ?? 'default', statement);
|
|
257
286
|
}
|
|
258
287
|
else if (statement?.type === 'CallExpression') {
|
|
259
288
|
const fn = componentFunctionOf(statement);
|
|
260
289
|
if (fn)
|
|
261
|
-
|
|
290
|
+
addComponent('default', fn);
|
|
262
291
|
}
|
|
263
292
|
else if (utils_1.t.isVariableDeclaration(statement)) {
|
|
264
293
|
for (const decl of statement.declarations) {
|
|
@@ -266,7 +295,7 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
266
295
|
continue;
|
|
267
296
|
const fn = componentFunctionOf(decl.init);
|
|
268
297
|
if (fn)
|
|
269
|
-
|
|
298
|
+
addComponent(decl.id.value, fn);
|
|
270
299
|
}
|
|
271
300
|
}
|
|
272
301
|
}
|
|
@@ -496,9 +525,43 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
496
525
|
const idSpans = new Set();
|
|
497
526
|
const excludedSpans = new Set();
|
|
498
527
|
const referenceIdents = (0, utils_1.collectReferenceIdentifiers)(ast);
|
|
528
|
+
const topLevelDeclarators = new Set();
|
|
529
|
+
for (const statement of ast.body) {
|
|
530
|
+
const declaration = unwrapExport(statement);
|
|
531
|
+
if (utils_1.t.isVariableDeclaration(declaration)) {
|
|
532
|
+
declaration.declarations.forEach((decl) => topLevelDeclarators.add(decl));
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
const unwrapStyleExpression = (node) => {
|
|
536
|
+
while (node &&
|
|
537
|
+
[
|
|
538
|
+
'ParenthesisExpression',
|
|
539
|
+
'TsAsExpression',
|
|
540
|
+
'TsSatisfiesExpression',
|
|
541
|
+
'TsNonNullExpression',
|
|
542
|
+
'TsConstAssertion',
|
|
543
|
+
'TsTypeAssertion',
|
|
544
|
+
].includes(node.type))
|
|
545
|
+
node = node.expression;
|
|
546
|
+
return node;
|
|
547
|
+
};
|
|
548
|
+
const literalObjectArgument = (node, seen = new Set()) => {
|
|
549
|
+
node = unwrapStyleExpression(node);
|
|
550
|
+
if (utils_1.t.isObjectExpression(node))
|
|
551
|
+
return node;
|
|
552
|
+
if (!utils_1.t.isIdentifier(node) || seen.has(node.value))
|
|
553
|
+
return null;
|
|
554
|
+
seen.add(node.value);
|
|
555
|
+
const declaration = [...topLevelDeclarators].find((decl) => utils_1.t.isIdentifier(decl.id) &&
|
|
556
|
+
decl.id.value === node.value);
|
|
557
|
+
return declaration?.init
|
|
558
|
+
? literalObjectArgument(declaration.init, seen)
|
|
559
|
+
: null;
|
|
560
|
+
};
|
|
561
|
+
const registeredStyleCalls = new Set();
|
|
499
562
|
const registerStyle = (node, declSpan, isExported) => {
|
|
500
563
|
let propName;
|
|
501
|
-
const init = node.init;
|
|
564
|
+
const init = unwrapStyleExpression(node.init);
|
|
502
565
|
if (utils_1.t.isIdentifier(node.id) &&
|
|
503
566
|
init &&
|
|
504
567
|
utils_1.t.isCallExpression(init) &&
|
|
@@ -523,6 +586,19 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
523
586
|
}
|
|
524
587
|
}
|
|
525
588
|
if (propName && init && utils_1.t.isCallExpression(init)) {
|
|
589
|
+
if (['create', 'createTheme', 'createStatic'].includes(propName) &&
|
|
590
|
+
!topLevelDeclarators.has(node)) {
|
|
591
|
+
throwCompilationError(`Plumeria: css.${propName} must be assigned to a top-level variable so its styles can be resolved across files. Move this declaration outside the function or block.`, node);
|
|
592
|
+
}
|
|
593
|
+
if (['create', 'createTheme', 'createStatic'].includes(propName)) {
|
|
594
|
+
const argumentIndex = propName === 'createTheme' ? 1 : 0;
|
|
595
|
+
const argument = init.arguments[argumentIndex];
|
|
596
|
+
const object = argument && literalObjectArgument(argument.expression);
|
|
597
|
+
if (!object)
|
|
598
|
+
throwCompilationError(`Plumeria: css.${propName} needs a style object it can read at build time. Pass an object literal or a top-level constant containing one.`, init);
|
|
599
|
+
argument.expression = object;
|
|
600
|
+
registeredStyleCalls.add(init.span.start);
|
|
601
|
+
}
|
|
526
602
|
if (propName === 'create' &&
|
|
527
603
|
utils_1.t.isObjectExpression(init.arguments[0].expression)) {
|
|
528
604
|
const obj = (0, utils_1.objectExpressionToObject)(init.arguments[0].expression, mergedStaticTable, mergedKeyframesTable, mergedViewTransitionTable, mergedCreateThemeHashTable, scannedTables.createThemeObjectTable, mergedCreateTable, mergedCreateStaticHashTable, scannedTables.createStaticObjectTable, mergedVariantsTable);
|
|
@@ -720,6 +796,10 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
720
796
|
}
|
|
721
797
|
}
|
|
722
798
|
if (propName) {
|
|
799
|
+
if (['create', 'createTheme', 'createStatic'].includes(propName) &&
|
|
800
|
+
!registeredStyleCalls.has(node.span.start)) {
|
|
801
|
+
throwCompilationError(`Plumeria: css.${propName} must be assigned to a named top-level variable. Destructuring, assignment statements, and default-exported calls cannot be compiled.`, node);
|
|
802
|
+
}
|
|
723
803
|
const args = node.arguments;
|
|
724
804
|
if (propName === 'keyframes' && args.length > 0) {
|
|
725
805
|
const expr = args[0].expression;
|
|
@@ -827,6 +907,7 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
827
907
|
return sourceBuffer.subarray(start, end).toString('utf-8');
|
|
828
908
|
};
|
|
829
909
|
const resolveStyleObject = (expr) => {
|
|
910
|
+
expr = (0, utils_1.unwrapExpression)(expr);
|
|
830
911
|
if (utils_1.t.isObjectExpression(expr)) {
|
|
831
912
|
return (0, utils_1.objectExpressionToObject)(expr, mergedStaticTable, mergedKeyframesTable, mergedViewTransitionTable, mergedCreateThemeHashTable, scannedTables.createThemeObjectTable, mergedCreateTable, mergedCreateStaticHashTable, scannedTables.createStaticObjectTable, mergedVariantsTable);
|
|
832
913
|
}
|
|
@@ -902,7 +983,12 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
902
983
|
return null;
|
|
903
984
|
const tempStaticTable = { ...mergedStaticTable };
|
|
904
985
|
const runtime = [];
|
|
905
|
-
const resolveObjectArg = (argExpr) => (0, utils_1.objectExpressionToObject)(
|
|
986
|
+
const resolveObjectArg = (argExpr) => (0, utils_1.objectExpressionToObject)({
|
|
987
|
+
...argExpr,
|
|
988
|
+
properties: argExpr.properties.filter((prop) => prop.type === 'Identifier' ||
|
|
989
|
+
(prop.type === 'KeyValueProperty' &&
|
|
990
|
+
isStaticArgValue(prop.value))),
|
|
991
|
+
}, mergedStaticTable, mergedKeyframesTable, mergedViewTransitionTable, mergedCreateThemeHashTable, scannedTables.createThemeObjectTable, mergedCreateTable, mergedCreateStaticHashTable, scannedTables.createStaticObjectTable, mergedVariantsTable);
|
|
906
992
|
if (func.named) {
|
|
907
993
|
const argExpr = callArgs[0]?.expression;
|
|
908
994
|
if (callArgs.length > 1 ||
|
|
@@ -1121,6 +1207,9 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
1121
1207
|
return buildDecision(node, prefix, off, { n: 0 }, scoped);
|
|
1122
1208
|
};
|
|
1123
1209
|
const collectConditions = (node, currentTestStrings = [], argOrder) => {
|
|
1210
|
+
node = (0, utils_1.unwrapExpression)(node);
|
|
1211
|
+
if (isNoOpStyle(node))
|
|
1212
|
+
return true;
|
|
1124
1213
|
let branchStyle = resolveStyleObject(node);
|
|
1125
1214
|
if (!branchStyle) {
|
|
1126
1215
|
const dynamic = resolveDynamicCall(node);
|
|
@@ -1201,17 +1290,20 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
1201
1290
|
? expr.value
|
|
1202
1291
|
: expr.property.value;
|
|
1203
1292
|
const source = utils_1.t.isIdentifier(expr) ? varName : getSource(expr);
|
|
1204
|
-
markStylePropApplied(varName, expr);
|
|
1205
1293
|
const owner = ownerComponentOf(expr);
|
|
1294
|
+
const propName = (utils_1.t.isIdentifier(expr) && owner
|
|
1295
|
+
? propAliases.get(owner)?.get(varName)
|
|
1296
|
+
: undefined) ?? varName;
|
|
1297
|
+
markStylePropApplied(propName, expr);
|
|
1206
1298
|
let possibilities = owner
|
|
1207
|
-
? scannedTables.componentPropsTable?.[`${resourcePath}-${owner}`]?.[
|
|
1299
|
+
? scannedTables.componentPropsTable?.[`${resourcePath}-${owner}`]?.[propName]
|
|
1208
1300
|
: undefined;
|
|
1209
1301
|
if (!possibilities) {
|
|
1210
1302
|
const candidates = [];
|
|
1211
1303
|
for (const key of Object.keys(scannedTables.componentPropsTable || {})) {
|
|
1212
1304
|
if (!key.startsWith(`${resourcePath}-`))
|
|
1213
1305
|
continue;
|
|
1214
|
-
const entries = scannedTables.componentPropsTable?.[key]?.[
|
|
1306
|
+
const entries = scannedTables.componentPropsTable?.[key]?.[propName];
|
|
1215
1307
|
if (entries)
|
|
1216
1308
|
candidates.push(...entries);
|
|
1217
1309
|
}
|
|
@@ -1266,6 +1358,8 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
1266
1358
|
};
|
|
1267
1359
|
for (const arg of args) {
|
|
1268
1360
|
const expr = arg.expression;
|
|
1361
|
+
if (isNoOpStyle(expr))
|
|
1362
|
+
continue;
|
|
1269
1363
|
if (pushPropPossibilities(expr, []))
|
|
1270
1364
|
continue;
|
|
1271
1365
|
if (utils_1.t.isCallExpression(expr) && utils_1.t.isIdentifier(expr.callee)) {
|
|
@@ -1938,45 +2032,54 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
1938
2032
|
node.value &&
|
|
1939
2033
|
node.value.type === 'JSXExpressionContainer') {
|
|
1940
2034
|
const expr = node.value.expression;
|
|
1941
|
-
const carrierFor = (subNode) => {
|
|
2035
|
+
const carrierFor = (subNode, calls) => {
|
|
1942
2036
|
const vars = [];
|
|
1943
2037
|
let unresolved = false;
|
|
1944
|
-
(
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
2038
|
+
for (const expression of calls ?? [subNode])
|
|
2039
|
+
(0, utils_1.traverse)(expression, {
|
|
2040
|
+
CallExpression({ node: call }) {
|
|
2041
|
+
if (!isStyleFunctionCall(call))
|
|
2042
|
+
return;
|
|
2043
|
+
const resolved = resolveDynamicCall(call, true);
|
|
2044
|
+
if (!resolved) {
|
|
2045
|
+
unresolved = true;
|
|
2046
|
+
return;
|
|
2047
|
+
}
|
|
2048
|
+
vars.push(...resolved.vars);
|
|
2049
|
+
},
|
|
2050
|
+
});
|
|
1956
2051
|
if (unresolved)
|
|
1957
2052
|
return null;
|
|
1958
2053
|
return `{ ${foldDynamicVars(vars).join(', ')} }`;
|
|
1959
2054
|
};
|
|
1960
2055
|
const replaceWithKey = (subNode) => {
|
|
1961
|
-
const
|
|
1962
|
-
|
|
1963
|
-
if (
|
|
1964
|
-
|
|
2056
|
+
const entries = list.filter((entry) => entry.spanStart === subNode.span.start &&
|
|
2057
|
+
entry.filePath === resourcePath);
|
|
2058
|
+
if (!entries.length)
|
|
2059
|
+
return false;
|
|
2060
|
+
let content = '""';
|
|
2061
|
+
for (const entry of [...entries].reverse()) {
|
|
2062
|
+
let value = JSON.stringify(entry.key);
|
|
1965
2063
|
if (entry.hasVars) {
|
|
1966
|
-
const carrier = carrierFor(subNode);
|
|
2064
|
+
const carrier = carrierFor(subNode, entry.dynamicCalls);
|
|
1967
2065
|
if (!carrier)
|
|
1968
2066
|
return false;
|
|
1969
|
-
|
|
2067
|
+
value = `{ key: ${value}, vars: ${carrier} }`;
|
|
1970
2068
|
}
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
2069
|
+
const condition = entry.conditions
|
|
2070
|
+
?.map(({ test, truthy }) => `${truthy ? '' : '!'}(${getSource(test)})`)
|
|
2071
|
+
.join(' && ');
|
|
2072
|
+
content = condition
|
|
2073
|
+
? `((${condition}) ? ${value} : ${content})`
|
|
2074
|
+
: value;
|
|
1976
2075
|
processStyleRecords(entry.styleObj);
|
|
1977
|
-
return true;
|
|
1978
2076
|
}
|
|
1979
|
-
|
|
2077
|
+
replacements.push({
|
|
2078
|
+
start: subNode.span.start - baseByteOffset,
|
|
2079
|
+
end: subNode.span.end - baseByteOffset,
|
|
2080
|
+
content,
|
|
2081
|
+
});
|
|
2082
|
+
return true;
|
|
1980
2083
|
};
|
|
1981
2084
|
(0, utils_1.traverse)(expr, {
|
|
1982
2085
|
MemberExpression({ node: subNode }) {
|
|
@@ -2090,10 +2193,13 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
2090
2193
|
});
|
|
2091
2194
|
}
|
|
2092
2195
|
else {
|
|
2196
|
+
const keptClass = existingClassExpr
|
|
2197
|
+
? `className={${existingClassExpr}}`
|
|
2198
|
+
: '';
|
|
2093
2199
|
replacements.push({
|
|
2094
2200
|
start: node.span.start - baseByteOffset,
|
|
2095
2201
|
end: node.span.end - baseByteOffset,
|
|
2096
|
-
content: styleAttr
|
|
2202
|
+
content: `${keptClass}${styleAttr}`,
|
|
2097
2203
|
});
|
|
2098
2204
|
}
|
|
2099
2205
|
},
|
package/dist/core.mjs
CHANGED
|
@@ -2,7 +2,7 @@ import { createFilter } from '@rollup/pluginutils';
|
|
|
2
2
|
import { parseSync } from '@swc/core';
|
|
3
3
|
import * as path from 'path';
|
|
4
4
|
import { applyCssValue, genBase36Hash, camelToKebabCase, isAtRule, } from 'zss-engine';
|
|
5
|
-
import { traverse, resolvePropertyPolicy, assertPropertyPolicy, collectReferenceIdentifiers, getStyleRecords, getStateWeights, collectLocalConsts, objectExpressionToObject, t, getRootIdentifier, extractOndemandStyles, deepMerge, scanAll, resolveFileError, resolveImportPath, getLeadingCommentLength, optimizer, styleFunctionsOf, isUnitlessProp, resolveDynamicStyle, themeHashOf, getFileDependencies, resolveExport, resolveComponentKey, resolveThemeSelector, DEFAULT_STYLE_PROP, } from '@plumeria/utils';
|
|
5
|
+
import { traverse, resolvePropertyPolicy, assertPropertyPolicy, collectReferenceIdentifiers, getStyleRecords, getStateWeights, collectLocalConsts, objectExpressionToObject, t, getRootIdentifier, unwrapExpression, extractOndemandStyles, deepMerge, scanAll, resolveFileError, resolveImportPath, getLeadingCommentLength, optimizer, styleFunctionsOf, isUnitlessProp, resolveDynamicStyle, themeHashOf, getFileDependencies, resolveExport, resolveComponentKey, resolveThemeSelector, 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
8
|
const unwrapExport = (node) => {
|
|
@@ -29,12 +29,37 @@ const componentFunctionOf = (node) => {
|
|
|
29
29
|
}
|
|
30
30
|
return undefined;
|
|
31
31
|
};
|
|
32
|
+
const unwrapPatternDefault = (pattern) => pattern?.type === 'AssignmentPattern' ? pattern.left : pattern;
|
|
33
|
+
const destructuredPropAliases = (fn) => {
|
|
34
|
+
const aliases = new Map();
|
|
35
|
+
const first = fn.params[0];
|
|
36
|
+
const pattern = unwrapPatternDefault(first?.pat ?? first);
|
|
37
|
+
if (pattern?.type !== 'ObjectPattern')
|
|
38
|
+
return aliases;
|
|
39
|
+
for (const item of pattern.properties ?? []) {
|
|
40
|
+
if (item.type !== 'KeyValuePatternProperty')
|
|
41
|
+
continue;
|
|
42
|
+
const local = unwrapPatternDefault(item.value);
|
|
43
|
+
const key = item.key;
|
|
44
|
+
if (!t.isIdentifier(local))
|
|
45
|
+
continue;
|
|
46
|
+
if (!t.isIdentifier(key) && !t.isStringLiteral(key))
|
|
47
|
+
continue;
|
|
48
|
+
const name = String(key.value);
|
|
49
|
+
if (name !== local.value)
|
|
50
|
+
aliases.set(local.value, name);
|
|
51
|
+
}
|
|
52
|
+
return aliases;
|
|
53
|
+
};
|
|
32
54
|
const isStaticArgValue = (node) => node.type === 'StringLiteral' ||
|
|
33
55
|
node.type === 'NumericLiteral' ||
|
|
34
56
|
node.type === 'BooleanLiteral' ||
|
|
35
57
|
(node.type === 'TemplateLiteral' && node.expressions.length === 0) ||
|
|
36
58
|
t.isIdentifier(node) ||
|
|
37
59
|
t.isMemberExpression(node);
|
|
60
|
+
const isNoOpStyle = (node) => t.isNullLiteral(node) ||
|
|
61
|
+
(t.isBooleanLiteral(node) && node.value === false) ||
|
|
62
|
+
(t.isIdentifier(node) && node.value === 'undefined');
|
|
38
63
|
const foldDynamicVars = (vars) => {
|
|
39
64
|
const grouped = new Map();
|
|
40
65
|
[...vars]
|
|
@@ -211,18 +236,22 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
211
236
|
}
|
|
212
237
|
}
|
|
213
238
|
const components = [];
|
|
239
|
+
const propAliases = new Map();
|
|
240
|
+
const addComponent = (name, fn) => {
|
|
241
|
+
components.push({ name, node: fn });
|
|
242
|
+
const aliases = destructuredPropAliases(fn);
|
|
243
|
+
if (aliases.size > 0)
|
|
244
|
+
propAliases.set(name, aliases);
|
|
245
|
+
};
|
|
214
246
|
for (const node of ast.body) {
|
|
215
247
|
const statement = unwrapExport(node);
|
|
216
248
|
if (isFunctionNode(statement)) {
|
|
217
|
-
|
|
218
|
-
name: statement.identifier?.value ?? 'default',
|
|
219
|
-
node: statement,
|
|
220
|
-
});
|
|
249
|
+
addComponent(statement.identifier?.value ?? 'default', statement);
|
|
221
250
|
}
|
|
222
251
|
else if (statement?.type === 'CallExpression') {
|
|
223
252
|
const fn = componentFunctionOf(statement);
|
|
224
253
|
if (fn)
|
|
225
|
-
|
|
254
|
+
addComponent('default', fn);
|
|
226
255
|
}
|
|
227
256
|
else if (t.isVariableDeclaration(statement)) {
|
|
228
257
|
for (const decl of statement.declarations) {
|
|
@@ -230,7 +259,7 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
230
259
|
continue;
|
|
231
260
|
const fn = componentFunctionOf(decl.init);
|
|
232
261
|
if (fn)
|
|
233
|
-
|
|
262
|
+
addComponent(decl.id.value, fn);
|
|
234
263
|
}
|
|
235
264
|
}
|
|
236
265
|
}
|
|
@@ -460,9 +489,43 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
460
489
|
const idSpans = new Set();
|
|
461
490
|
const excludedSpans = new Set();
|
|
462
491
|
const referenceIdents = collectReferenceIdentifiers(ast);
|
|
492
|
+
const topLevelDeclarators = new Set();
|
|
493
|
+
for (const statement of ast.body) {
|
|
494
|
+
const declaration = unwrapExport(statement);
|
|
495
|
+
if (t.isVariableDeclaration(declaration)) {
|
|
496
|
+
declaration.declarations.forEach((decl) => topLevelDeclarators.add(decl));
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
const unwrapStyleExpression = (node) => {
|
|
500
|
+
while (node &&
|
|
501
|
+
[
|
|
502
|
+
'ParenthesisExpression',
|
|
503
|
+
'TsAsExpression',
|
|
504
|
+
'TsSatisfiesExpression',
|
|
505
|
+
'TsNonNullExpression',
|
|
506
|
+
'TsConstAssertion',
|
|
507
|
+
'TsTypeAssertion',
|
|
508
|
+
].includes(node.type))
|
|
509
|
+
node = node.expression;
|
|
510
|
+
return node;
|
|
511
|
+
};
|
|
512
|
+
const literalObjectArgument = (node, seen = new Set()) => {
|
|
513
|
+
node = unwrapStyleExpression(node);
|
|
514
|
+
if (t.isObjectExpression(node))
|
|
515
|
+
return node;
|
|
516
|
+
if (!t.isIdentifier(node) || seen.has(node.value))
|
|
517
|
+
return null;
|
|
518
|
+
seen.add(node.value);
|
|
519
|
+
const declaration = [...topLevelDeclarators].find((decl) => t.isIdentifier(decl.id) &&
|
|
520
|
+
decl.id.value === node.value);
|
|
521
|
+
return declaration?.init
|
|
522
|
+
? literalObjectArgument(declaration.init, seen)
|
|
523
|
+
: null;
|
|
524
|
+
};
|
|
525
|
+
const registeredStyleCalls = new Set();
|
|
463
526
|
const registerStyle = (node, declSpan, isExported) => {
|
|
464
527
|
let propName;
|
|
465
|
-
const init = node.init;
|
|
528
|
+
const init = unwrapStyleExpression(node.init);
|
|
466
529
|
if (t.isIdentifier(node.id) &&
|
|
467
530
|
init &&
|
|
468
531
|
t.isCallExpression(init) &&
|
|
@@ -487,6 +550,19 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
487
550
|
}
|
|
488
551
|
}
|
|
489
552
|
if (propName && init && t.isCallExpression(init)) {
|
|
553
|
+
if (['create', 'createTheme', 'createStatic'].includes(propName) &&
|
|
554
|
+
!topLevelDeclarators.has(node)) {
|
|
555
|
+
throwCompilationError(`Plumeria: css.${propName} must be assigned to a top-level variable so its styles can be resolved across files. Move this declaration outside the function or block.`, node);
|
|
556
|
+
}
|
|
557
|
+
if (['create', 'createTheme', 'createStatic'].includes(propName)) {
|
|
558
|
+
const argumentIndex = propName === 'createTheme' ? 1 : 0;
|
|
559
|
+
const argument = init.arguments[argumentIndex];
|
|
560
|
+
const object = argument && literalObjectArgument(argument.expression);
|
|
561
|
+
if (!object)
|
|
562
|
+
throwCompilationError(`Plumeria: css.${propName} needs a style object it can read at build time. Pass an object literal or a top-level constant containing one.`, init);
|
|
563
|
+
argument.expression = object;
|
|
564
|
+
registeredStyleCalls.add(init.span.start);
|
|
565
|
+
}
|
|
490
566
|
if (propName === 'create' &&
|
|
491
567
|
t.isObjectExpression(init.arguments[0].expression)) {
|
|
492
568
|
const obj = objectExpressionToObject(init.arguments[0].expression, mergedStaticTable, mergedKeyframesTable, mergedViewTransitionTable, mergedCreateThemeHashTable, scannedTables.createThemeObjectTable, mergedCreateTable, mergedCreateStaticHashTable, scannedTables.createStaticObjectTable, mergedVariantsTable);
|
|
@@ -684,6 +760,10 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
684
760
|
}
|
|
685
761
|
}
|
|
686
762
|
if (propName) {
|
|
763
|
+
if (['create', 'createTheme', 'createStatic'].includes(propName) &&
|
|
764
|
+
!registeredStyleCalls.has(node.span.start)) {
|
|
765
|
+
throwCompilationError(`Plumeria: css.${propName} must be assigned to a named top-level variable. Destructuring, assignment statements, and default-exported calls cannot be compiled.`, node);
|
|
766
|
+
}
|
|
687
767
|
const args = node.arguments;
|
|
688
768
|
if (propName === 'keyframes' && args.length > 0) {
|
|
689
769
|
const expr = args[0].expression;
|
|
@@ -791,6 +871,7 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
791
871
|
return sourceBuffer.subarray(start, end).toString('utf-8');
|
|
792
872
|
};
|
|
793
873
|
const resolveStyleObject = (expr) => {
|
|
874
|
+
expr = unwrapExpression(expr);
|
|
794
875
|
if (t.isObjectExpression(expr)) {
|
|
795
876
|
return objectExpressionToObject(expr, mergedStaticTable, mergedKeyframesTable, mergedViewTransitionTable, mergedCreateThemeHashTable, scannedTables.createThemeObjectTable, mergedCreateTable, mergedCreateStaticHashTable, scannedTables.createStaticObjectTable, mergedVariantsTable);
|
|
796
877
|
}
|
|
@@ -866,7 +947,12 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
866
947
|
return null;
|
|
867
948
|
const tempStaticTable = { ...mergedStaticTable };
|
|
868
949
|
const runtime = [];
|
|
869
|
-
const resolveObjectArg = (argExpr) => objectExpressionToObject(
|
|
950
|
+
const resolveObjectArg = (argExpr) => objectExpressionToObject({
|
|
951
|
+
...argExpr,
|
|
952
|
+
properties: argExpr.properties.filter((prop) => prop.type === 'Identifier' ||
|
|
953
|
+
(prop.type === 'KeyValueProperty' &&
|
|
954
|
+
isStaticArgValue(prop.value))),
|
|
955
|
+
}, mergedStaticTable, mergedKeyframesTable, mergedViewTransitionTable, mergedCreateThemeHashTable, scannedTables.createThemeObjectTable, mergedCreateTable, mergedCreateStaticHashTable, scannedTables.createStaticObjectTable, mergedVariantsTable);
|
|
870
956
|
if (func.named) {
|
|
871
957
|
const argExpr = callArgs[0]?.expression;
|
|
872
958
|
if (callArgs.length > 1 ||
|
|
@@ -1085,6 +1171,9 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
1085
1171
|
return buildDecision(node, prefix, off, { n: 0 }, scoped);
|
|
1086
1172
|
};
|
|
1087
1173
|
const collectConditions = (node, currentTestStrings = [], argOrder) => {
|
|
1174
|
+
node = unwrapExpression(node);
|
|
1175
|
+
if (isNoOpStyle(node))
|
|
1176
|
+
return true;
|
|
1088
1177
|
let branchStyle = resolveStyleObject(node);
|
|
1089
1178
|
if (!branchStyle) {
|
|
1090
1179
|
const dynamic = resolveDynamicCall(node);
|
|
@@ -1165,17 +1254,20 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
1165
1254
|
? expr.value
|
|
1166
1255
|
: expr.property.value;
|
|
1167
1256
|
const source = t.isIdentifier(expr) ? varName : getSource(expr);
|
|
1168
|
-
markStylePropApplied(varName, expr);
|
|
1169
1257
|
const owner = ownerComponentOf(expr);
|
|
1258
|
+
const propName = (t.isIdentifier(expr) && owner
|
|
1259
|
+
? propAliases.get(owner)?.get(varName)
|
|
1260
|
+
: undefined) ?? varName;
|
|
1261
|
+
markStylePropApplied(propName, expr);
|
|
1170
1262
|
let possibilities = owner
|
|
1171
|
-
? scannedTables.componentPropsTable?.[`${resourcePath}-${owner}`]?.[
|
|
1263
|
+
? scannedTables.componentPropsTable?.[`${resourcePath}-${owner}`]?.[propName]
|
|
1172
1264
|
: undefined;
|
|
1173
1265
|
if (!possibilities) {
|
|
1174
1266
|
const candidates = [];
|
|
1175
1267
|
for (const key of Object.keys(scannedTables.componentPropsTable || {})) {
|
|
1176
1268
|
if (!key.startsWith(`${resourcePath}-`))
|
|
1177
1269
|
continue;
|
|
1178
|
-
const entries = scannedTables.componentPropsTable?.[key]?.[
|
|
1270
|
+
const entries = scannedTables.componentPropsTable?.[key]?.[propName];
|
|
1179
1271
|
if (entries)
|
|
1180
1272
|
candidates.push(...entries);
|
|
1181
1273
|
}
|
|
@@ -1230,6 +1322,8 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
1230
1322
|
};
|
|
1231
1323
|
for (const arg of args) {
|
|
1232
1324
|
const expr = arg.expression;
|
|
1325
|
+
if (isNoOpStyle(expr))
|
|
1326
|
+
continue;
|
|
1233
1327
|
if (pushPropPossibilities(expr, []))
|
|
1234
1328
|
continue;
|
|
1235
1329
|
if (t.isCallExpression(expr) && t.isIdentifier(expr.callee)) {
|
|
@@ -1902,45 +1996,54 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
1902
1996
|
node.value &&
|
|
1903
1997
|
node.value.type === 'JSXExpressionContainer') {
|
|
1904
1998
|
const expr = node.value.expression;
|
|
1905
|
-
const carrierFor = (subNode) => {
|
|
1999
|
+
const carrierFor = (subNode, calls) => {
|
|
1906
2000
|
const vars = [];
|
|
1907
2001
|
let unresolved = false;
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
2002
|
+
for (const expression of calls ?? [subNode])
|
|
2003
|
+
traverse(expression, {
|
|
2004
|
+
CallExpression({ node: call }) {
|
|
2005
|
+
if (!isStyleFunctionCall(call))
|
|
2006
|
+
return;
|
|
2007
|
+
const resolved = resolveDynamicCall(call, true);
|
|
2008
|
+
if (!resolved) {
|
|
2009
|
+
unresolved = true;
|
|
2010
|
+
return;
|
|
2011
|
+
}
|
|
2012
|
+
vars.push(...resolved.vars);
|
|
2013
|
+
},
|
|
2014
|
+
});
|
|
1920
2015
|
if (unresolved)
|
|
1921
2016
|
return null;
|
|
1922
2017
|
return `{ ${foldDynamicVars(vars).join(', ')} }`;
|
|
1923
2018
|
};
|
|
1924
2019
|
const replaceWithKey = (subNode) => {
|
|
1925
|
-
const
|
|
1926
|
-
|
|
1927
|
-
if (
|
|
1928
|
-
|
|
2020
|
+
const entries = list.filter((entry) => entry.spanStart === subNode.span.start &&
|
|
2021
|
+
entry.filePath === resourcePath);
|
|
2022
|
+
if (!entries.length)
|
|
2023
|
+
return false;
|
|
2024
|
+
let content = '""';
|
|
2025
|
+
for (const entry of [...entries].reverse()) {
|
|
2026
|
+
let value = JSON.stringify(entry.key);
|
|
1929
2027
|
if (entry.hasVars) {
|
|
1930
|
-
const carrier = carrierFor(subNode);
|
|
2028
|
+
const carrier = carrierFor(subNode, entry.dynamicCalls);
|
|
1931
2029
|
if (!carrier)
|
|
1932
2030
|
return false;
|
|
1933
|
-
|
|
2031
|
+
value = `{ key: ${value}, vars: ${carrier} }`;
|
|
1934
2032
|
}
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
2033
|
+
const condition = entry.conditions
|
|
2034
|
+
?.map(({ test, truthy }) => `${truthy ? '' : '!'}(${getSource(test)})`)
|
|
2035
|
+
.join(' && ');
|
|
2036
|
+
content = condition
|
|
2037
|
+
? `((${condition}) ? ${value} : ${content})`
|
|
2038
|
+
: value;
|
|
1940
2039
|
processStyleRecords(entry.styleObj);
|
|
1941
|
-
return true;
|
|
1942
2040
|
}
|
|
1943
|
-
|
|
2041
|
+
replacements.push({
|
|
2042
|
+
start: subNode.span.start - baseByteOffset,
|
|
2043
|
+
end: subNode.span.end - baseByteOffset,
|
|
2044
|
+
content,
|
|
2045
|
+
});
|
|
2046
|
+
return true;
|
|
1944
2047
|
};
|
|
1945
2048
|
traverse(expr, {
|
|
1946
2049
|
MemberExpression({ node: subNode }) {
|
|
@@ -2054,10 +2157,13 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
2054
2157
|
});
|
|
2055
2158
|
}
|
|
2056
2159
|
else {
|
|
2160
|
+
const keptClass = existingClassExpr
|
|
2161
|
+
? `className={${existingClassExpr}}`
|
|
2162
|
+
: '';
|
|
2057
2163
|
replacements.push({
|
|
2058
2164
|
start: node.span.start - baseByteOffset,
|
|
2059
2165
|
end: node.span.end - baseByteOffset,
|
|
2060
|
-
content: styleAttr
|
|
2166
|
+
content: `${keptClass}${styleAttr}`,
|
|
2061
2167
|
});
|
|
2062
2168
|
}
|
|
2063
2169
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plumeria/unplugin",
|
|
3
|
-
"version": "18.
|
|
3
|
+
"version": "18.5.0",
|
|
4
4
|
"description": "Universal Plumeria plugin for various build tools",
|
|
5
5
|
"author": "Refirst 11",
|
|
6
6
|
"license": "MIT",
|
|
@@ -94,7 +94,7 @@
|
|
|
94
94
|
"dependencies": {
|
|
95
95
|
"@rollup/pluginutils": "^5.4.0",
|
|
96
96
|
"unplugin": "^3.0.0",
|
|
97
|
-
"@plumeria/utils": "^18.
|
|
97
|
+
"@plumeria/utils": "^18.5.0"
|
|
98
98
|
},
|
|
99
99
|
"devDependencies": {
|
|
100
100
|
"@swc/core": "1.15.47",
|