@plumeria/turbopack-loader 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.
@@ -1,2 +1,2 @@
1
- export declare function acquireLock(lockDir: string, delayMs?: number, maxDelayMs?: number): Promise<void>;
1
+ export declare function acquireLock(lockDir: string, delayMs?: number, maxDelayMs?: number, timeoutMs?: number): Promise<void>;
2
2
  export declare function releaseLockSync(lockDir: string): void;
package/dist/file-lock.js CHANGED
@@ -37,7 +37,8 @@ exports.acquireLock = acquireLock;
37
37
  exports.releaseLockSync = releaseLockSync;
38
38
  const fs = __importStar(require("fs"));
39
39
  const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
40
- async function acquireLock(lockDir, delayMs = 2, maxDelayMs = 50) {
40
+ async function acquireLock(lockDir, delayMs = 2, maxDelayMs = 50, timeoutMs = 30_000) {
41
+ const started = Date.now();
41
42
  let delay = delayMs;
42
43
  while (true) {
43
44
  try {
@@ -46,7 +47,11 @@ async function acquireLock(lockDir, delayMs = 2, maxDelayMs = 50) {
46
47
  }
47
48
  catch (err) {
48
49
  if (err.code === 'EEXIST') {
49
- await sleep(delay);
50
+ const remaining = timeoutMs - (Date.now() - started);
51
+ if (remaining <= 0) {
52
+ throw new Error(`Plumeria: Timed out waiting for CSS lock "${lockDir}". If no build is running, remove the stale lock directory and retry.`, { cause: err });
53
+ }
54
+ await sleep(Math.min(delay, remaining));
50
55
  delay = Math.min(delay * 2, maxDelayMs);
51
56
  continue;
52
57
  }
package/dist/index.js CHANGED
@@ -77,7 +77,10 @@ async function generateProductionCss(virtualFilePath, options) {
77
77
  }
78
78
  const ensureProductionCss = (virtualFilePath, options) => {
79
79
  if (!productionCss) {
80
- productionCss = generateProductionCss(virtualFilePath, options);
80
+ productionCss = generateProductionCss(virtualFilePath, options).catch((error) => {
81
+ productionCss = null;
82
+ throw error;
83
+ });
81
84
  }
82
85
  return productionCss;
83
86
  };
@@ -105,12 +108,37 @@ const componentFunctionOf = (node) => {
105
108
  }
106
109
  return undefined;
107
110
  };
111
+ const unwrapPatternDefault = (pattern) => pattern?.type === 'AssignmentPattern' ? pattern.left : pattern;
112
+ const destructuredPropAliases = (fn) => {
113
+ const aliases = new Map();
114
+ const first = fn.params[0];
115
+ const pattern = unwrapPatternDefault(first?.pat ?? first);
116
+ if (pattern?.type !== 'ObjectPattern')
117
+ return aliases;
118
+ for (const item of pattern.properties ?? []) {
119
+ if (item.type !== 'KeyValuePatternProperty')
120
+ continue;
121
+ const local = unwrapPatternDefault(item.value);
122
+ const key = item.key;
123
+ if (!utils_1.t.isIdentifier(local))
124
+ continue;
125
+ if (!utils_1.t.isIdentifier(key) && !utils_1.t.isStringLiteral(key))
126
+ continue;
127
+ const name = String(key.value);
128
+ if (name !== local.value)
129
+ aliases.set(local.value, name);
130
+ }
131
+ return aliases;
132
+ };
108
133
  const isStaticArgValue = (node) => node.type === 'StringLiteral' ||
109
134
  node.type === 'NumericLiteral' ||
110
135
  node.type === 'BooleanLiteral' ||
111
136
  (node.type === 'TemplateLiteral' && node.expressions.length === 0) ||
112
137
  utils_1.t.isIdentifier(node) ||
113
138
  utils_1.t.isMemberExpression(node);
139
+ const isNoOpStyle = (node) => utils_1.t.isNullLiteral(node) ||
140
+ (utils_1.t.isBooleanLiteral(node) && node.value === false) ||
141
+ (utils_1.t.isIdentifier(node) && node.value === 'undefined');
114
142
  const foldDynamicVars = (vars) => {
115
143
  const grouped = new Map();
116
144
  [...vars]
@@ -188,6 +216,7 @@ async function loader(source) {
188
216
  utils_1.t.isFunctionExpression(node)) {
189
217
  const rootId = (0, utils_1.getRootIdentifier)(node);
190
218
  const isPlumeriaStyle = rootId &&
219
+ isVisibleReference(node) &&
191
220
  ((localCreateStyles[rootId] !== undefined &&
192
221
  localCreateStyles[rootId].type !== 'constant') ||
193
222
  mergedCreateTable[rootId] !== undefined ||
@@ -204,6 +233,10 @@ async function loader(source) {
204
233
  }
205
234
  }
206
235
  };
236
+ const scannedTables = (0, utils_1.scanAll)();
237
+ const ownFailure = (0, utils_1.resolveFileError)(resourcePath, '');
238
+ if (ownFailure)
239
+ throwCompilationError(`Plumeria: ${ownFailure.message}`);
207
240
  for (const node of ast.body) {
208
241
  if (node.type === 'ImportDeclaration') {
209
242
  const sourcePath = node.source.value;
@@ -217,7 +250,6 @@ async function loader(source) {
217
250
  }
218
251
  }
219
252
  }
220
- const scannedTables = (0, utils_1.scanAll)();
221
253
  if (scannedTables.componentPropsTable) {
222
254
  const parentFiles = new Set();
223
255
  for (const compKey of Object.keys(scannedTables.componentPropsTable)) {
@@ -237,18 +269,22 @@ async function loader(source) {
237
269
  }
238
270
  }
239
271
  const components = [];
272
+ const propAliases = new Map();
273
+ const addComponent = (name, fn) => {
274
+ components.push({ name, node: fn });
275
+ const aliases = destructuredPropAliases(fn);
276
+ if (aliases.size > 0)
277
+ propAliases.set(name, aliases);
278
+ };
240
279
  for (const node of ast.body) {
241
280
  const statement = unwrapExport(node);
242
281
  if (isFunctionNode(statement)) {
243
- components.push({
244
- name: statement.identifier?.value ?? 'default',
245
- node: statement,
246
- });
282
+ addComponent(statement.identifier?.value ?? 'default', statement);
247
283
  }
248
284
  else if (statement?.type === 'CallExpression') {
249
285
  const fn = componentFunctionOf(statement);
250
286
  if (fn)
251
- components.push({ name: 'default', node: fn });
287
+ addComponent('default', fn);
252
288
  }
253
289
  else if (utils_1.t.isVariableDeclaration(statement)) {
254
290
  for (const decl of statement.declarations) {
@@ -256,7 +292,7 @@ async function loader(source) {
256
292
  continue;
257
293
  const fn = componentFunctionOf(decl.init);
258
294
  if (fn)
259
- components.push({ name: decl.id.value, node: fn });
295
+ addComponent(decl.id.value, fn);
260
296
  }
261
297
  }
262
298
  }
@@ -481,14 +517,70 @@ async function loader(source) {
481
517
  }
482
518
  };
483
519
  const replacements = [];
520
+ const deferredSources = [];
521
+ const deferSource = (node, stripObject = false) => {
522
+ const token = `__plumeria_preserved_${deferredSources.length}__`;
523
+ deferredSources.push({
524
+ token,
525
+ start: node.span.start - baseByteOffset,
526
+ end: node.span.end - baseByteOffset,
527
+ stripObject,
528
+ });
529
+ return token;
530
+ };
484
531
  const dynamicFnCalls = [];
485
532
  const processedDecls = new Set();
533
+ const separatelyExported = new Set();
534
+ for (const statement of ast.body) {
535
+ if (statement.type !== 'ExportNamedDeclaration' || statement.source)
536
+ continue;
537
+ for (const specifier of statement.specifiers) {
538
+ if (specifier.type === 'ExportSpecifier' &&
539
+ utils_1.t.isIdentifier(specifier.orig)) {
540
+ separatelyExported.add(specifier.orig.value);
541
+ }
542
+ }
543
+ }
486
544
  const idSpans = new Set();
487
545
  const excludedSpans = new Set();
488
546
  const referenceIdents = (0, utils_1.collectReferenceIdentifiers)(ast);
547
+ const topLevelDeclarators = new Set();
548
+ for (const statement of ast.body) {
549
+ const declaration = unwrapExport(statement);
550
+ if (utils_1.t.isVariableDeclaration(declaration)) {
551
+ declaration.declarations.forEach((decl) => topLevelDeclarators.add(decl));
552
+ }
553
+ }
554
+ const unwrapStyleExpression = (node) => {
555
+ while (node &&
556
+ [
557
+ 'ParenthesisExpression',
558
+ 'TsAsExpression',
559
+ 'TsSatisfiesExpression',
560
+ 'TsNonNullExpression',
561
+ 'TsConstAssertion',
562
+ 'TsTypeAssertion',
563
+ ].includes(node.type))
564
+ node = node.expression;
565
+ return node;
566
+ };
567
+ const literalObjectArgument = (node, seen = new Set()) => {
568
+ node = unwrapStyleExpression(node);
569
+ if (utils_1.t.isObjectExpression(node))
570
+ return node;
571
+ if (!utils_1.t.isIdentifier(node) || seen.has(node.value))
572
+ return null;
573
+ seen.add(node.value);
574
+ const declaration = [...topLevelDeclarators].find((decl) => utils_1.t.isIdentifier(decl.id) &&
575
+ decl.id.value === node.value);
576
+ return declaration?.init
577
+ ? literalObjectArgument(declaration.init, seen)
578
+ : null;
579
+ };
580
+ const registeredStyleCalls = new Set();
489
581
  const registerStyle = (node, declSpan, isExported) => {
490
582
  let propName;
491
- const init = node.init;
583
+ const init = unwrapStyleExpression(node.init);
492
584
  if (utils_1.t.isIdentifier(node.id) &&
493
585
  init &&
494
586
  utils_1.t.isCallExpression(init) &&
@@ -513,6 +605,19 @@ async function loader(source) {
513
605
  }
514
606
  }
515
607
  if (propName && init && utils_1.t.isCallExpression(init)) {
608
+ if (['create', 'createTheme', 'createStatic'].includes(propName) &&
609
+ !topLevelDeclarators.has(node)) {
610
+ 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);
611
+ }
612
+ if (['create', 'createTheme', 'createStatic'].includes(propName)) {
613
+ const argumentIndex = propName === 'createTheme' ? 1 : 0;
614
+ const argument = init.arguments[argumentIndex];
615
+ const object = argument && literalObjectArgument(argument.expression);
616
+ if (!object)
617
+ 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);
618
+ argument.expression = object;
619
+ registeredStyleCalls.add(init.span.start);
620
+ }
516
621
  if (propName === 'create' &&
517
622
  utils_1.t.isObjectExpression(init.arguments[0].expression)) {
518
623
  const obj = (0, utils_1.objectExpressionToObject)(init.arguments[0].expression, mergedStaticTable, mergedKeyframesTable, mergedViewTransitionTable, mergedCreateThemeHashTable, scannedTables.createThemeObjectTable, mergedCreateTable, mergedCreateStaticHashTable, scannedTables.createStaticObjectTable, mergedVariantsTable);
@@ -683,7 +788,9 @@ async function loader(source) {
683
788
  if (processedDecls.has(node))
684
789
  return;
685
790
  node.declarations.forEach((decl) => {
686
- registerStyle(decl, node.span, false);
791
+ registerStyle(decl, node.span, node.declarations.length > 1 ||
792
+ (utils_1.t.isIdentifier(decl.id) &&
793
+ separatelyExported.has(decl.id.value)));
687
794
  checkStyleAliasAssignment(decl);
688
795
  });
689
796
  },
@@ -708,6 +815,10 @@ async function loader(source) {
708
815
  }
709
816
  }
710
817
  if (propName) {
818
+ if (['create', 'createTheme', 'createStatic'].includes(propName) &&
819
+ !registeredStyleCalls.has(node.span.start)) {
820
+ throwCompilationError(`Plumeria: css.${propName} must be assigned to a named top-level variable. Destructuring, assignment statements, and default-exported calls cannot be compiled.`, node);
821
+ }
711
822
  const args = node.arguments;
712
823
  if (propName === 'keyframes' && args.length > 0) {
713
824
  const expr = args[0].expression;
@@ -773,12 +884,17 @@ async function loader(source) {
773
884
  const jsxOpeningElementMap = new Map();
774
885
  const componentParamNames = new Set();
775
886
  const addFirstParamName = (fn) => {
776
- const p = fn.params[0];
887
+ const first = fn.params[0];
888
+ const p = unwrapPatternDefault(first?.pat ?? first);
777
889
  if (utils_1.t.isIdentifier(p)) {
778
890
  componentParamNames.add(p.value);
779
891
  }
780
- else if (p?.pat && utils_1.t.isIdentifier(p.pat)) {
781
- componentParamNames.add(p.pat.value);
892
+ else if (p?.type === 'ObjectPattern') {
893
+ for (const item of p.properties) {
894
+ if (item.type === 'RestElement' && utils_1.t.isIdentifier(item.argument)) {
895
+ componentParamNames.add(item.argument.value);
896
+ }
897
+ }
782
898
  }
783
899
  };
784
900
  for (const node of ast.body) {
@@ -814,7 +930,21 @@ async function loader(source) {
814
930
  const end = node.span.end - baseByteOffset;
815
931
  return sourceBuffer.subarray(start, end).toString('utf-8');
816
932
  };
933
+ const isVisibleReference = (expr) => {
934
+ if (utils_1.t.isIdentifier(expr))
935
+ return referenceIdents.references.has(expr.span.start);
936
+ if (utils_1.t.isMemberExpression(expr))
937
+ return isVisibleReference(expr.object);
938
+ if (utils_1.t.isCallExpression(expr) &&
939
+ expr.callee.type !== 'Super' &&
940
+ expr.callee.type !== 'Import')
941
+ return isVisibleReference(expr.callee);
942
+ return true;
943
+ };
817
944
  const resolveStyleObject = (expr) => {
945
+ expr = (0, utils_1.unwrapExpression)(expr);
946
+ if (!isVisibleReference(expr))
947
+ return null;
818
948
  if (utils_1.t.isObjectExpression(expr)) {
819
949
  return (0, utils_1.objectExpressionToObject)(expr, mergedStaticTable, mergedKeyframesTable, mergedViewTransitionTable, mergedCreateThemeHashTable, scannedTables.createThemeObjectTable, mergedCreateTable, mergedCreateStaticHashTable, scannedTables.createStaticObjectTable, mergedVariantsTable);
820
950
  }
@@ -880,6 +1010,8 @@ async function loader(source) {
880
1010
  const callee = expr.callee;
881
1011
  if (!utils_1.t.isIdentifier(callee.object) || !utils_1.t.isIdentifier(callee.property))
882
1012
  return null;
1013
+ if (!isVisibleReference(callee.object))
1014
+ return null;
883
1015
  const styleInfo = localCreateStyles[callee.object.value];
884
1016
  const func = styleInfo?.functions?.[callee.property.value] ??
885
1017
  createFunctionImportMap[callee.object.value]?.[callee.property.value];
@@ -890,7 +1022,12 @@ async function loader(source) {
890
1022
  return null;
891
1023
  const tempStaticTable = { ...mergedStaticTable };
892
1024
  const runtime = [];
893
- const resolveObjectArg = (argExpr) => (0, utils_1.objectExpressionToObject)(argExpr, mergedStaticTable, mergedKeyframesTable, mergedViewTransitionTable, mergedCreateThemeHashTable, scannedTables.createThemeObjectTable, mergedCreateTable, mergedCreateStaticHashTable, scannedTables.createStaticObjectTable, mergedVariantsTable);
1025
+ const resolveObjectArg = (argExpr) => (0, utils_1.objectExpressionToObject)({
1026
+ ...argExpr,
1027
+ properties: argExpr.properties.filter((prop) => prop.type === 'Identifier' ||
1028
+ (prop.type === 'KeyValueProperty' &&
1029
+ isStaticArgValue(prop.value))),
1030
+ }, mergedStaticTable, mergedKeyframesTable, mergedViewTransitionTable, mergedCreateThemeHashTable, scannedTables.createThemeObjectTable, mergedCreateTable, mergedCreateStaticHashTable, scannedTables.createStaticObjectTable, mergedVariantsTable);
894
1031
  if (func.named) {
895
1032
  const argExpr = callArgs[0]?.expression;
896
1033
  if (callArgs.length > 1 ||
@@ -1012,6 +1149,8 @@ async function loader(source) {
1012
1149
  utils_1.t.isStringLiteral(node.property.expression)) {
1013
1150
  return null;
1014
1151
  }
1152
+ if (!isVisibleReference(node.object))
1153
+ return null;
1015
1154
  const varName = node.object.value;
1016
1155
  const obj = resolveCreateObject(varName);
1017
1156
  return obj ? { varName, keyExpr: node.property.expression, obj } : null;
@@ -1105,6 +1244,14 @@ async function loader(source) {
1105
1244
  return buildDecision(node, prefix, off, { n: 0 }, scoped);
1106
1245
  };
1107
1246
  const collectConditions = (node, currentTestStrings = [], argOrder) => {
1247
+ node = (0, utils_1.unwrapExpression)(node);
1248
+ if (isNoOpStyle(node))
1249
+ return true;
1250
+ if (node.type === 'ArrayExpression') {
1251
+ return node.elements.every((element) => !element ||
1252
+ (!element.spread &&
1253
+ collectConditions(element.expression, currentTestStrings, argOrder)));
1254
+ }
1108
1255
  let branchStyle = resolveStyleObject(node);
1109
1256
  if (!branchStyle) {
1110
1257
  const dynamic = resolveDynamicCall(node);
@@ -1157,13 +1304,12 @@ async function loader(source) {
1157
1304
  return true;
1158
1305
  }
1159
1306
  }
1160
- collectConditions(node.consequent, [...currentTestStrings, `(${testSource})`], argOrder);
1161
- collectConditions(node.alternate, [...currentTestStrings, `!(${testSource})`], argOrder);
1162
- return true;
1307
+ const consequentHandled = collectConditions(node.consequent, [...currentTestStrings, `(${testSource})`], argOrder);
1308
+ const alternateHandled = collectConditions(node.alternate, [...currentTestStrings, `!(${testSource})`], argOrder);
1309
+ return consequentHandled && alternateHandled;
1163
1310
  }
1164
1311
  else if (node.type === 'BinaryExpression' && node.operator === '&&') {
1165
- collectConditions(node.right, [...currentTestStrings, `(${getSource(node.left)})`], argOrder);
1166
- return true;
1312
+ return collectConditions(node.right, [...currentTestStrings, `(${getSource(node.left)})`], argOrder);
1167
1313
  }
1168
1314
  else if (node.type === 'ParenthesisExpression') {
1169
1315
  return collectConditions(node.expression, currentTestStrings, argOrder);
@@ -1184,17 +1330,20 @@ async function loader(source) {
1184
1330
  ? expr.value
1185
1331
  : expr.property.value;
1186
1332
  const source = utils_1.t.isIdentifier(expr) ? varName : getSource(expr);
1187
- markStylePropApplied(varName, expr);
1188
1333
  const owner = ownerComponentOf(expr);
1334
+ const propName = (utils_1.t.isIdentifier(expr) && owner
1335
+ ? propAliases.get(owner)?.get(varName)
1336
+ : undefined) ?? varName;
1337
+ markStylePropApplied(propName, expr);
1189
1338
  let possibilities = owner
1190
- ? scannedTables.componentPropsTable?.[`${resourcePath}-${owner}`]?.[varName]
1339
+ ? scannedTables.componentPropsTable?.[`${resourcePath}-${owner}`]?.[propName]
1191
1340
  : undefined;
1192
1341
  if (!possibilities) {
1193
1342
  const candidates = [];
1194
1343
  for (const key of Object.keys(scannedTables.componentPropsTable || {})) {
1195
1344
  if (!key.startsWith(`${resourcePath}-`))
1196
1345
  continue;
1197
- const entries = scannedTables.componentPropsTable?.[key]?.[varName];
1346
+ const entries = scannedTables.componentPropsTable?.[key]?.[propName];
1198
1347
  if (entries)
1199
1348
  candidates.push(...entries);
1200
1349
  }
@@ -1249,6 +1398,8 @@ async function loader(source) {
1249
1398
  };
1250
1399
  for (const arg of args) {
1251
1400
  const expr = arg.expression;
1401
+ if (isNoOpStyle(expr))
1402
+ continue;
1252
1403
  if (pushPropPossibilities(expr, []))
1253
1404
  continue;
1254
1405
  if (utils_1.t.isCallExpression(expr) && utils_1.t.isIdentifier(expr.callee)) {
@@ -1260,7 +1411,11 @@ async function loader(source) {
1260
1411
  hash = mergedVariantsTable[varName];
1261
1412
  if (hash && scannedTables.variantsObjectTable[hash])
1262
1413
  variantObj = scannedTables.variantsObjectTable[hash];
1263
- if (!variantObj && localCreateStyles[varName]?.obj)
1414
+ if (!isVisibleReference(expr))
1415
+ variantObj = undefined;
1416
+ if (isVisibleReference(expr) &&
1417
+ !variantObj &&
1418
+ localCreateStyles[varName]?.obj)
1264
1419
  variantObj = localCreateStyles[varName].obj;
1265
1420
  if (variantObj) {
1266
1421
  const callArgs = expr.arguments;
@@ -1371,7 +1526,11 @@ async function loader(source) {
1371
1526
  hash = mergedVariantsTable[varName];
1372
1527
  if (hash && scannedTables.variantsObjectTable[hash])
1373
1528
  variantObj = scannedTables.variantsObjectTable[hash];
1374
- if (!variantObj && localCreateStyles[varName]?.obj)
1529
+ if (!isVisibleReference(expr))
1530
+ variantObj = undefined;
1531
+ if (isVisibleReference(expr) &&
1532
+ !variantObj &&
1533
+ localCreateStyles[varName]?.obj)
1375
1534
  variantObj = localCreateStyles[varName].obj;
1376
1535
  if (variantObj) {
1377
1536
  Object.entries(variantObj).forEach(([groupName, groupVariants]) => {
@@ -1401,7 +1560,9 @@ async function loader(source) {
1401
1560
  utils_1.t.isIdentifier(expr.object) &&
1402
1561
  expr.property.type === 'Computed') {
1403
1562
  const varName = expr.object.value;
1404
- const styleObj = resolveCreateObject(varName);
1563
+ const styleObj = isVisibleReference(expr)
1564
+ ? resolveCreateObject(varName)
1565
+ : null;
1405
1566
  if (styleObj) {
1406
1567
  const dynExpr = expr.property.expression;
1407
1568
  const dynSource = getSource(dynExpr);
@@ -1730,6 +1891,8 @@ async function loader(source) {
1730
1891
  });
1731
1892
  },
1732
1893
  MemberExpression({ node }) {
1894
+ if (!isVisibleReference(node))
1895
+ return;
1733
1896
  if (utils_1.t.isIdentifier(node.object) &&
1734
1897
  (utils_1.t.isIdentifier(node.property) || node.property.type === 'Computed')) {
1735
1898
  const varName = node.object.value;
@@ -1921,45 +2084,54 @@ async function loader(source) {
1921
2084
  node.value &&
1922
2085
  node.value.type === 'JSXExpressionContainer') {
1923
2086
  const expr = node.value.expression;
1924
- const carrierFor = (subNode) => {
2087
+ const carrierFor = (subNode, calls) => {
1925
2088
  const vars = [];
1926
2089
  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
- });
2090
+ for (const expression of calls ?? [subNode])
2091
+ (0, utils_1.traverse)(expression, {
2092
+ CallExpression({ node: call }) {
2093
+ if (!isStyleFunctionCall(call))
2094
+ return;
2095
+ const resolved = resolveDynamicCall(call, true);
2096
+ if (!resolved) {
2097
+ unresolved = true;
2098
+ return;
2099
+ }
2100
+ vars.push(...resolved.vars);
2101
+ },
2102
+ });
1939
2103
  if (unresolved)
1940
2104
  return null;
1941
2105
  return `{ ${foldDynamicVars(vars).join(', ')} }`;
1942
2106
  };
1943
2107
  const replaceWithKey = (subNode) => {
1944
- const entry = list.find((x) => x.spanStart === subNode.span.start &&
1945
- x.filePath === resourcePath);
1946
- if (entry) {
1947
- let content = JSON.stringify(entry.key);
2108
+ const entries = list.filter((entry) => entry.spanStart === subNode.span.start &&
2109
+ entry.filePath === resourcePath);
2110
+ if (!entries.length)
2111
+ return false;
2112
+ let content = '""';
2113
+ for (const entry of [...entries].reverse()) {
2114
+ let value = JSON.stringify(entry.key);
1948
2115
  if (entry.hasVars) {
1949
- const carrier = carrierFor(subNode);
2116
+ const carrier = carrierFor(subNode, entry.dynamicCalls);
1950
2117
  if (!carrier)
1951
2118
  return false;
1952
- content = `{ key: ${content}, vars: ${carrier} }`;
2119
+ value = `{ key: ${value}, vars: ${carrier} }`;
1953
2120
  }
1954
- replacements.push({
1955
- start: subNode.span.start - baseByteOffset,
1956
- end: subNode.span.end - baseByteOffset,
1957
- content,
1958
- });
2121
+ const condition = entry.conditions
2122
+ ?.map(({ test, truthy }) => `${truthy ? '' : '!'}(${getSource(test)})`)
2123
+ .join(' && ');
2124
+ content = condition
2125
+ ? `((${condition}) ? ${value} : ${content})`
2126
+ : value;
1959
2127
  processStyleRecords(entry.styleObj);
1960
- return true;
1961
2128
  }
1962
- return false;
2129
+ replacements.push({
2130
+ start: subNode.span.start - baseByteOffset,
2131
+ end: subNode.span.end - baseByteOffset,
2132
+ content,
2133
+ });
2134
+ return true;
1963
2135
  };
1964
2136
  (0, utils_1.traverse)(expr, {
1965
2137
  MemberExpression({ node: subNode }) {
@@ -1987,7 +2159,7 @@ async function loader(source) {
1987
2159
  const expr = node.value.expression;
1988
2160
  const args = expr.type === 'ArrayExpression'
1989
2161
  ? expr.elements
1990
- .filter((el) => el !== undefined)
2162
+ .filter((el) => el != null)
1991
2163
  .map((el) => ({ expression: el.expression }))
1992
2164
  : [{ expression: expr }];
1993
2165
  const dynamicClassParts = [];
@@ -2016,13 +2188,7 @@ async function loader(source) {
2016
2188
  existingClassExpr = JSON.stringify(classNameAttr.value.value);
2017
2189
  }
2018
2190
  else if (classNameAttr.value?.type === 'JSXExpressionContainer') {
2019
- const start = classNameAttr.value.expression.span.start -
2020
- baseByteOffset;
2021
- const end = classNameAttr.value.expression.span.end -
2022
- baseByteOffset;
2023
- existingClassExpr = `(${sourceBuffer
2024
- .subarray(start, end)
2025
- .toString('utf-8')})`;
2191
+ existingClassExpr = `(${deferSource(classNameAttr.value.expression)})`;
2026
2192
  }
2027
2193
  }
2028
2194
  const styleAttrExisting = attributes.find((attr) => attr.type === 'JSXAttribute' &&
@@ -2037,22 +2203,19 @@ async function loader(source) {
2037
2203
  });
2038
2204
  if (styleAttrExisting.value?.type === 'JSXExpressionContainer') {
2039
2205
  const innerExpr = styleAttrExisting.value?.expression;
2040
- const start = innerExpr.span.start - baseByteOffset;
2041
- const end = innerExpr.span.end - baseByteOffset;
2042
- const innerSource = sourceBuffer
2043
- .subarray(start, end)
2044
- .toString('utf-8');
2045
2206
  if (innerExpr.type === 'ObjectExpression') {
2046
- const stripped = innerSource.slice(1, -1).trim();
2047
- if (stripped)
2048
- existingStyleParts.push(stripped);
2207
+ if (innerExpr.properties.length > 0)
2208
+ existingStyleParts.push(deferSource(innerExpr, true));
2049
2209
  }
2050
2210
  else {
2051
- existingStyleExpr = `...(${innerSource})`;
2211
+ existingStyleExpr = `...(${deferSource(innerExpr)})`;
2052
2212
  }
2053
2213
  }
2054
2214
  }
2055
2215
  const { classParts, isOptimizable, baseStyle, dynamicVars, propVarSpreads, } = buildClassParts(args, dynamicClassParts, existingClassExpr, true);
2216
+ if (!isOptimizable) {
2217
+ throwCompilationError(`Plumeria: Dynamic or unresolvable style object "${getSource(expr)}" is not supported.`, expr);
2218
+ }
2056
2219
  const styleParts = [
2057
2220
  ...existingStyleParts,
2058
2221
  ...foldDynamicVars(dynamicVars),
@@ -2073,10 +2236,13 @@ async function loader(source) {
2073
2236
  });
2074
2237
  }
2075
2238
  else {
2239
+ const keptClass = existingClassExpr
2240
+ ? `className={${existingClassExpr}}`
2241
+ : '';
2076
2242
  replacements.push({
2077
2243
  start: node.span.start - baseByteOffset,
2078
2244
  end: node.span.end - baseByteOffset,
2079
- content: styleAttr || '',
2245
+ content: `${keptClass}${styleAttr}`,
2080
2246
  });
2081
2247
  }
2082
2248
  },
@@ -2188,6 +2354,22 @@ async function loader(source) {
2188
2354
  `so it cannot be passed through another prop or read as a value.`, call);
2189
2355
  }
2190
2356
  });
2357
+ for (const deferred of deferredSources) {
2358
+ let cursor = deferred.start;
2359
+ const pieces = [];
2360
+ for (const replacement of [...replacements].sort((a, b) => a.start - b.start || b.end - a.end)) {
2361
+ if (replacement.start < cursor || replacement.end > deferred.end)
2362
+ continue;
2363
+ pieces.push(sourceBuffer.subarray(cursor, replacement.start).toString('utf-8'), replacement.content);
2364
+ cursor = replacement.end;
2365
+ }
2366
+ pieces.push(sourceBuffer.subarray(cursor, deferred.end).toString('utf-8'));
2367
+ let content = pieces.join('');
2368
+ if (deferred.stripObject)
2369
+ content = content.slice(1, -1).trim();
2370
+ for (const replacement of replacements)
2371
+ replacement.content = replacement.content.replaceAll(deferred.token, content);
2372
+ }
2191
2373
  const buffer = Buffer.from(source);
2192
2374
  let offset = 0;
2193
2375
  const parts = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plumeria/turbopack-loader",
3
- "version": "18.4.1",
3
+ "version": "18.5.0",
4
4
  "description": "Plumeria Turbopack-loader",
5
5
  "author": "Refirst 11",
6
6
  "license": "MIT",
@@ -29,8 +29,8 @@
29
29
  "zero-virtual.css"
30
30
  ],
31
31
  "dependencies": {
32
- "@plumeria/compiler": "^18.4.1",
33
- "@plumeria/utils": "^18.4.1"
32
+ "@plumeria/compiler": "^18.5.0",
33
+ "@plumeria/utils": "^18.5.0"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@swc/core": "1.15.47",