@plumeria/turbopack-loader 18.3.18 → 18.4.1

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/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- export interface LoaderOptions {
1
+ import type { PropertyPolicyOptions } from '@plumeria/utils';
2
+ export interface LoaderOptions extends PropertyPolicyOptions {
2
3
  include?: string[];
3
4
  exclude?: string[];
4
5
  styleProp?: string;
package/dist/index.js CHANGED
@@ -63,6 +63,8 @@ async function generateProductionCss(virtualFilePath, options) {
63
63
  exclude: options.exclude ?? DEFAULT_EXCLUDE,
64
64
  cwd: process.cwd(),
65
65
  styleProp: options.styleProp ?? utils_1.DEFAULT_STYLE_PROP,
66
+ withoutLogicalProperties: options.withoutLogicalProperties,
67
+ withoutPhysicalProperties: options.withoutPhysicalProperties,
66
68
  });
67
69
  const optimized = await (0, utils_1.optimizer)(css);
68
70
  const tempPath = `${virtualFilePath}.${process.pid}.tmp`;
@@ -109,81 +111,6 @@ const isStaticArgValue = (node) => node.type === 'StringLiteral' ||
109
111
  (node.type === 'TemplateLiteral' && node.expressions.length === 0) ||
110
112
  utils_1.t.isIdentifier(node) ||
111
113
  utils_1.t.isMemberExpression(node);
112
- const namedParamsOf = (params, defaults) => {
113
- if (params.length !== 1)
114
- return undefined;
115
- const first = params[0];
116
- const pattern = (first?.pat ?? first);
117
- if (pattern?.type !== 'ObjectPattern')
118
- return undefined;
119
- const named = [];
120
- for (const prop of pattern.properties ?? []) {
121
- if (prop.type === 'AssignmentPatternProperty' && utils_1.t.isIdentifier(prop.key)) {
122
- named.push({ key: prop.key.value, local: prop.key.value });
123
- if (prop.value)
124
- defaults[prop.key.value] = prop.value;
125
- }
126
- else if (prop.type === 'KeyValuePatternProperty' &&
127
- utils_1.t.isIdentifier(prop.key) &&
128
- utils_1.t.isIdentifier(prop.value)) {
129
- named.push({ key: prop.key.value, local: prop.value.value });
130
- }
131
- else if (prop.type === 'KeyValuePatternProperty' &&
132
- utils_1.t.isIdentifier(prop.key) &&
133
- prop.value?.type === 'AssignmentPattern' &&
134
- utils_1.t.isIdentifier(prop.value.left)) {
135
- const pattern = prop.value;
136
- named.push({ key: String(prop.key.value), local: pattern.left.value });
137
- defaults[pattern.left.value] = pattern.right;
138
- }
139
- else {
140
- return undefined;
141
- }
142
- }
143
- return named.length > 0 ? named : undefined;
144
- };
145
- const styleFunctionsOf = (objExpr) => {
146
- const styleFunctions = {};
147
- objExpr.properties.forEach((prop) => {
148
- if (prop.type !== 'KeyValueProperty' || prop.key.type !== 'Identifier')
149
- return;
150
- const func = prop.value;
151
- if (func.type !== 'ArrowFunctionExpression' &&
152
- func.type !== 'FunctionExpression')
153
- return;
154
- const defaults = {};
155
- const params = func.params.map((p) => {
156
- const pattern = typeof p === 'object' && p !== null && 'pat' in p ? p.pat : p;
157
- if (utils_1.t.isIdentifier(pattern))
158
- return pattern.value;
159
- if (pattern?.type === 'AssignmentPattern' &&
160
- utils_1.t.isIdentifier(pattern.left)) {
161
- defaults[pattern.left.value] = pattern.right;
162
- return pattern.left.value;
163
- }
164
- return 'arg';
165
- });
166
- let actualBody = func.body;
167
- if (actualBody?.type === 'ParenthesisExpression')
168
- actualBody = actualBody.expression;
169
- if (actualBody?.type === 'BlockStatement') {
170
- const first = actualBody.stmts?.[0];
171
- if (first?.type === 'ReturnStatement')
172
- actualBody = first.argument;
173
- if (actualBody?.type === 'ParenthesisExpression')
174
- actualBody = actualBody.expression;
175
- }
176
- if (actualBody && actualBody.type === 'ObjectExpression') {
177
- styleFunctions[prop.key.value] = {
178
- params,
179
- named: namedParamsOf(func.params, defaults),
180
- defaults,
181
- body: actualBody,
182
- };
183
- }
184
- });
185
- return styleFunctions;
186
- };
187
114
  const foldDynamicVars = (vars) => {
188
115
  const grouped = new Map();
189
116
  [...vars]
@@ -205,65 +132,13 @@ const foldDynamicVars = (vars) => {
205
132
  return `"${cssVar}": ${value}`;
206
133
  });
207
134
  };
208
- const isUnitlessProp = (prop) => zss_engine_1.exceptionCamelCase.includes(prop) || prop.startsWith('--');
209
- const collectVarProps = (style, cssVar, props) => {
210
- const reference = `var(${cssVar})`;
211
- for (const [prop, value] of Object.entries(style)) {
212
- if (typeof value === 'string' && value.includes(reference))
213
- props.push(prop);
214
- else if (value !== null && typeof value === 'object')
215
- collectVarProps(value, cssVar, props);
216
- }
217
- };
218
- const retargetVar = (style, cssVar, next, unitless) => {
219
- const reference = `var(${cssVar})`;
220
- for (const [prop, value] of Object.entries(style)) {
221
- if (typeof value === 'string' && value.includes(reference)) {
222
- if (isUnitlessProp(prop) === unitless)
223
- style[prop] = value
224
- .split(reference)
225
- .join(`var(${next})`);
226
- }
227
- else if (value !== null && typeof value === 'object') {
228
- retargetVar(value, cssVar, next, unitless);
229
- }
230
- }
231
- };
232
- const splitVarByUnit = (style, cssVar) => {
233
- const props = [];
234
- collectVarProps(style, cssVar, props);
235
- if (props.length === 0)
236
- return [];
237
- const lead = props[0];
238
- const split = props.find((prop) => isUnitlessProp(prop) !== isUnitlessProp(lead));
239
- if (!split)
240
- return [{ cssVar, prop: lead }];
241
- const splitVar = `${cssVar}-${(0, zss_engine_1.camelToKebabCase)(split).replace(/^-+/, '')}`;
242
- retargetVar(style, cssVar, splitVar, isUnitlessProp(split));
243
- return [
244
- { cssVar, prop: lead },
245
- { cssVar: splitVar, prop: split },
246
- ];
247
- };
248
- const applyVarFallback = (style, cssVar, literal) => {
249
- const reference = `var(${cssVar})`;
250
- for (const [prop, value] of Object.entries(style)) {
251
- if (typeof value === 'string' && value.includes(reference)) {
252
- style[prop] = value
253
- .split(reference)
254
- .join(`var(${cssVar}, ${(0, zss_engine_1.applyCssValue)(literal, (0, zss_engine_1.camelToKebabCase)(prop))})`);
255
- }
256
- else if (value !== null && typeof value === 'object') {
257
- applyVarFallback(value, cssVar, literal);
258
- }
259
- }
260
- };
261
135
  async function loader(source) {
262
136
  const callback = this.async();
263
137
  const loaderOptions = this.getOptions?.() ??
264
138
  (typeof this.query === 'object' ? this.query : undefined) ??
265
139
  {};
266
140
  const styleProp = loaderOptions.styleProp ?? utils_1.DEFAULT_STYLE_PROP;
141
+ const propertyPolicy = (0, utils_1.resolvePropertyPolicy)(loaderOptions);
267
142
  const resourcePath = this.resourcePath;
268
143
  const isProduction = process.env.NODE_ENV === 'production';
269
144
  const VIRTUAL_FILE_PATH = path.resolve(__dirname, '..', 'zero-virtual.css');
@@ -279,6 +154,7 @@ async function loader(source) {
279
154
  tsx: true,
280
155
  target: 'es2022',
281
156
  });
157
+ (0, utils_1.assertPropertyPolicy)(ast, propertyPolicy, resourcePath);
282
158
  const leadingLen = (0, utils_1.getLeadingCommentLength)(source);
283
159
  const sourceBuffer = Buffer.from(source, 'utf-8');
284
160
  const leadingBytes = Buffer.byteLength(source.slice(0, leadingLen), 'utf-8');
@@ -480,7 +356,7 @@ async function loader(source) {
480
356
  scannedTables.createHashTable[uniqueKey];
481
357
  }
482
358
  if (scannedTables.createFunctionTable[uniqueKey]) {
483
- createFunctionImportMap[localName] = styleFunctionsOf(scannedTables.createFunctionTable[uniqueKey]);
359
+ createFunctionImportMap[localName] = (0, utils_1.styleFunctionsOf)(scannedTables.createFunctionTable[uniqueKey]);
484
360
  }
485
361
  if (scannedTables.variantsHashTable[uniqueKey]) {
486
362
  variantsImportMap[localName] =
@@ -580,6 +456,16 @@ async function loader(source) {
580
456
  for (const key of Object.keys(createStaticImportMap)) {
581
457
  mergedCreateStaticHashTable[key] = createStaticImportMap[key];
582
458
  }
459
+ const dynamicStyleTables = {
460
+ keyframesHashTable: mergedKeyframesTable,
461
+ viewTransitionHashTable: mergedViewTransitionTable,
462
+ createThemeHashTable: mergedCreateThemeHashTable,
463
+ createThemeObjectTable: scannedTables.createThemeObjectTable,
464
+ createHashTable: mergedCreateTable,
465
+ createStaticHashTable: mergedCreateStaticHashTable,
466
+ createStaticObjectTable: scannedTables.createStaticObjectTable,
467
+ variantsHashTable: mergedVariantsTable,
468
+ };
583
469
  const localCreateStyles = {};
584
470
  const localStyleAliases = {};
585
471
  const checkStyleAliasAssignment = (decl) => {
@@ -640,7 +526,7 @@ async function loader(source) {
640
526
  records.forEach((r) => (atomMap[r.key] = r.hash));
641
527
  hashMap[key] = atomMap;
642
528
  });
643
- const styleFunctions = styleFunctionsOf(init.arguments[0].expression);
529
+ const styleFunctions = (0, utils_1.styleFunctionsOf)(init.arguments[0].expression);
644
530
  if (utils_1.t.isIdentifier(node.id)) {
645
531
  idSpans.add(node.id.span.start);
646
532
  }
@@ -979,7 +865,16 @@ async function loader(source) {
979
865
  }
980
866
  return null;
981
867
  };
982
- const resolveDynamicCall = (expr) => {
868
+ const isStyleFunctionCall = (expr) => {
869
+ if (!utils_1.t.isCallExpression(expr) || !utils_1.t.isMemberExpression(expr.callee))
870
+ return false;
871
+ const callee = expr.callee;
872
+ if (!utils_1.t.isIdentifier(callee.object) || !utils_1.t.isIdentifier(callee.property))
873
+ return false;
874
+ return Boolean(localCreateStyles[callee.object.value]?.functions?.[callee.property.value] ??
875
+ createFunctionImportMap[callee.object.value]?.[callee.property.value]);
876
+ };
877
+ const resolveDynamicCall = (expr, forceRuntime = false) => {
983
878
  if (!utils_1.t.isCallExpression(expr) || !utils_1.t.isMemberExpression(expr.callee))
984
879
  return null;
985
880
  const callee = expr.callee;
@@ -1023,7 +918,9 @@ async function loader(source) {
1023
918
  throwCompilationError(`Plumeria: ${getSource(expr)} leaves "${key}" unset, and a dynamic style function has no value to fall back on.`, expr);
1024
919
  return;
1025
920
  }
1026
- if (isStaticArgValue(source) && argObj[key] !== undefined)
921
+ if (!forceRuntime &&
922
+ isStaticArgValue(source) &&
923
+ argObj[key] !== undefined)
1027
924
  tempStaticTable[local] = argObj[key];
1028
925
  else
1029
926
  runtime.push({ param: local, source });
@@ -1031,6 +928,8 @@ async function loader(source) {
1031
928
  }
1032
929
  else if (callArgs.length === 1 &&
1033
930
  callArgs[0].expression.type === 'ObjectExpression') {
931
+ if (forceRuntime)
932
+ return null;
1034
933
  const argObj = resolveObjectArg(callArgs[0].expression) ?? {};
1035
934
  func.params.forEach((p) => {
1036
935
  if (argObj[p] !== undefined)
@@ -1045,39 +944,10 @@ async function loader(source) {
1045
944
  runtime.push({ param: p, source: callArg.expression });
1046
945
  });
1047
946
  }
1048
- const withDefault = Object.entries(func.defaults ?? {}).filter(([param]) => tempStaticTable[param] === undefined);
1049
- const cssVars = {};
1050
- const varParams = Array.from(new Set([
1051
- ...runtime.map(({ param }) => param),
1052
- ...withDefault.map(([param]) => param),
1053
- ]));
1054
- if (varParams.length > 0) {
1055
- varParams.forEach((param) => (tempStaticTable[param] = param));
1056
- const probe = (0, utils_1.objectExpressionToObject)(func.body, tempStaticTable, mergedKeyframesTable, mergedViewTransitionTable, mergedCreateThemeHashTable, scannedTables.createThemeObjectTable, mergedCreateTable, mergedCreateStaticHashTable, scannedTables.createStaticObjectTable, mergedVariantsTable);
1057
- const hash = (0, zss_engine_1.genBase36Hash)(probe ?? {}, 1, 8);
1058
- varParams.forEach((param) => {
1059
- const cssVar = `--${hash}-${param}`;
1060
- tempStaticTable[param] = `var(${cssVar})`;
1061
- cssVars[param] = cssVar;
1062
- });
1063
- }
1064
- const style = (0, utils_1.objectExpressionToObject)(func.body, tempStaticTable, mergedKeyframesTable, mergedViewTransitionTable, mergedCreateThemeHashTable, scannedTables.createThemeObjectTable, mergedCreateTable, mergedCreateStaticHashTable, scannedTables.createStaticObjectTable, mergedVariantsTable);
1065
- if (!style)
947
+ const resolved = (0, utils_1.resolveDynamicStyle)(func, runtime.map(({ param }) => param), tempStaticTable, dynamicStyleTables);
948
+ if (!resolved)
1066
949
  return null;
1067
- const varGroups = new Map();
1068
- varParams.forEach((param) => {
1069
- const cssVar = cssVars[param];
1070
- if (cssVar)
1071
- varGroups.set(param, splitVarByUnit(style, cssVar));
1072
- });
1073
- withDefault.forEach(([param, expr]) => {
1074
- const literal = expr.type === 'StringLiteral' || expr.type === 'NumericLiteral'
1075
- ? expr.value
1076
- : undefined;
1077
- if (literal === undefined)
1078
- return;
1079
- (varGroups.get(param) ?? []).forEach(({ cssVar }) => applyVarFallback(style, cssVar, literal));
1080
- });
950
+ const { style, varGroups } = resolved;
1081
951
  const vars = [];
1082
952
  runtime.forEach(({ param, source }) => {
1083
953
  const groups = varGroups.get(param);
@@ -1100,7 +970,7 @@ async function loader(source) {
1100
970
  valueExpr = JSON.stringify((0, zss_engine_1.applyCssValue)(argSource.slice(1, -1), kebabProp));
1101
971
  }
1102
972
  else {
1103
- valueExpr = isUnitlessProp(prop)
973
+ valueExpr = (0, utils_1.isUnitlessProp)(prop)
1104
974
  ? argSource
1105
975
  : `(typeof (${argSource}) === 'number' ? (${argSource}) + 'px' : (${argSource}))`;
1106
976
  }
@@ -1118,6 +988,7 @@ async function loader(source) {
1118
988
  });
1119
989
  const conditionals = [];
1120
990
  const dynamicVars = [];
991
+ const propVarSpreads = [];
1121
992
  let groupIdCounter = 0;
1122
993
  let sourceOrder = 0;
1123
994
  const baseChunks = [];
@@ -1332,9 +1203,23 @@ async function loader(source) {
1332
1203
  }
1333
1204
  if (!possibilities || possibilities.length === 0)
1334
1205
  return false;
1335
- const testLHS = gates.length
1336
- ? `((${gates.join(' && ')}) ? ${source} : "")`
1206
+ const carriesVars = possibilities.some((entry) => entry.hasVars);
1207
+ if (carriesVars && !isStyleProp) {
1208
+ throwCompilationError(`Plumeria: "${varName}" carries a dynamic function key, and css.use() returns only a class name. ` +
1209
+ `Apply it to ${styleProp} on the element instead.`, expr);
1210
+ }
1211
+ const gate = gates.length ? `(${gates.join(' && ')}) && ` : '';
1212
+ if (carriesVars) {
1213
+ const spread = `...(${gate}${source} && ${source}.vars)`;
1214
+ if (!propVarSpreads.includes(spread))
1215
+ propVarSpreads.push(spread);
1216
+ }
1217
+ const token = carriesVars
1218
+ ? `((${source} && ${source}.key) || ${source})`
1337
1219
  : source;
1220
+ const testLHS = gates.length
1221
+ ? `((${gates.join(' && ')}) ? ${token} : "")`
1222
+ : token;
1338
1223
  const currentGroupId = ++groupIdCounter;
1339
1224
  const currentOrder = sourceOrder++;
1340
1225
  const seen = new Set();
@@ -1573,6 +1458,7 @@ async function loader(source) {
1573
1458
  isOptimizable,
1574
1459
  baseStyle,
1575
1460
  dynamicVars,
1461
+ propVarSpreads,
1576
1462
  };
1577
1463
  }
1578
1464
  const stateSources = baseChunks.map(({ order, style }) => ({ order, style: style }));
@@ -1828,7 +1714,13 @@ async function loader(source) {
1828
1714
  classParts.push(`(${JSON.stringify(results)}[${masterKeyExpr || '""'}] || ${baseConflictClass ? JSON.stringify(baseConflictClass) : '""'})`);
1829
1715
  }
1830
1716
  classParts.push(...dynamicClassParts);
1831
- return { classParts, isOptimizable, baseStyle, dynamicVars };
1717
+ return {
1718
+ classParts,
1719
+ isOptimizable,
1720
+ baseStyle,
1721
+ dynamicVars,
1722
+ propVarSpreads,
1723
+ };
1832
1724
  };
1833
1725
  (0, utils_1.traverse)(ast, {
1834
1726
  JSXOpeningElement({ node }) {
@@ -2029,14 +1921,40 @@ async function loader(source) {
2029
1921
  node.value &&
2030
1922
  node.value.type === 'JSXExpressionContainer') {
2031
1923
  const expr = node.value.expression;
1924
+ const carrierFor = (subNode) => {
1925
+ const vars = [];
1926
+ let unresolved = false;
1927
+ (0, utils_1.traverse)(subNode, {
1928
+ CallExpression({ node: call }) {
1929
+ if (!isStyleFunctionCall(call))
1930
+ return;
1931
+ const resolved = resolveDynamicCall(call, true);
1932
+ if (!resolved) {
1933
+ unresolved = true;
1934
+ return;
1935
+ }
1936
+ vars.push(...resolved.vars);
1937
+ },
1938
+ });
1939
+ if (unresolved)
1940
+ return null;
1941
+ return `{ ${foldDynamicVars(vars).join(', ')} }`;
1942
+ };
2032
1943
  const replaceWithKey = (subNode) => {
2033
1944
  const entry = list.find((x) => x.spanStart === subNode.span.start &&
2034
1945
  x.filePath === resourcePath);
2035
1946
  if (entry) {
1947
+ let content = JSON.stringify(entry.key);
1948
+ if (entry.hasVars) {
1949
+ const carrier = carrierFor(subNode);
1950
+ if (!carrier)
1951
+ return false;
1952
+ content = `{ key: ${content}, vars: ${carrier} }`;
1953
+ }
2036
1954
  replacements.push({
2037
1955
  start: subNode.span.start - baseByteOffset,
2038
1956
  end: subNode.span.end - baseByteOffset,
2039
- content: JSON.stringify(entry.key),
1957
+ content,
2040
1958
  });
2041
1959
  processStyleRecords(entry.styleObj);
2042
1960
  return true;
@@ -2054,6 +1972,11 @@ async function loader(source) {
2054
1972
  excludeSubtreeSpans(subNode);
2055
1973
  }
2056
1974
  },
1975
+ CallExpression({ node: subNode }) {
1976
+ if (replaceWithKey(subNode)) {
1977
+ excludeSubtreeSpans(subNode);
1978
+ }
1979
+ },
2057
1980
  });
2058
1981
  }
2059
1982
  }
@@ -2129,10 +2052,11 @@ async function loader(source) {
2129
2052
  }
2130
2053
  }
2131
2054
  }
2132
- const { classParts, isOptimizable, baseStyle, dynamicVars } = buildClassParts(args, dynamicClassParts, existingClassExpr, true);
2055
+ const { classParts, isOptimizable, baseStyle, dynamicVars, propVarSpreads, } = buildClassParts(args, dynamicClassParts, existingClassExpr, true);
2133
2056
  const styleParts = [
2134
2057
  ...existingStyleParts,
2135
2058
  ...foldDynamicVars(dynamicVars),
2059
+ ...propVarSpreads,
2136
2060
  ];
2137
2061
  const styleAttr = styleParts.length > 0 || existingStyleExpr
2138
2062
  ? ` style={{ ${[existingStyleExpr, ...styleParts].filter(Boolean).join(', ')} }}`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plumeria/turbopack-loader",
3
- "version": "18.3.18",
3
+ "version": "18.4.1",
4
4
  "description": "Plumeria Turbopack-loader",
5
5
  "author": "Refirst 11",
6
6
  "license": "MIT",
@@ -29,12 +29,12 @@
29
29
  "zero-virtual.css"
30
30
  ],
31
31
  "dependencies": {
32
- "@plumeria/compiler": "^18.3.18",
33
- "@plumeria/utils": "^18.3.18"
32
+ "@plumeria/compiler": "^18.4.1",
33
+ "@plumeria/utils": "^18.4.1"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@swc/core": "1.15.47",
37
- "zss-engine": "2.7.0"
37
+ "zss-engine": "2.8.0"
38
38
  },
39
39
  "publishConfig": {
40
40
  "access": "public",