@plumeria/unplugin 18.0.1 → 18.1.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.
Files changed (3) hide show
  1. package/dist/core.js +198 -36
  2. package/dist/core.mjs +198 -36
  3. package/package.json +2 -2
package/dist/core.js CHANGED
@@ -813,6 +813,8 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
813
813
  });
814
814
  const conditionals = [];
815
815
  let groupIdCounter = 0;
816
+ let sourceOrder = 0;
817
+ const baseChunks = [];
816
818
  let baseStyle = {};
817
819
  let isOptimizable = true;
818
820
  const resolveCreateObject = (varName) => {
@@ -826,11 +828,104 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
826
828
  return scannedTables.createObjectTable[hash];
827
829
  return null;
828
830
  };
831
+ const resolveBracketGroup = (node) => {
832
+ if (!utils_1.t.isMemberExpression(node) ||
833
+ !utils_1.t.isIdentifier(node.object) ||
834
+ node.property.type !== 'Computed' ||
835
+ utils_1.t.isStringLiteral(node.property.expression)) {
836
+ return null;
837
+ }
838
+ const varName = node.object.value;
839
+ const obj = resolveCreateObject(varName);
840
+ return obj
841
+ ? { varName, keyExpr: node.property.expression, obj }
842
+ : null;
843
+ };
844
+ const buildDecision = (node, prefix, off, counter) => {
845
+ if (node.type === 'ParenthesisExpression') {
846
+ return buildDecision(node.expression, prefix, off, counter);
847
+ }
848
+ if (node.type === 'ConditionalExpression') {
849
+ const a = buildDecision(node.consequent, prefix, off, counter);
850
+ if (!a)
851
+ return null;
852
+ const b = buildDecision(node.alternate, prefix, off, counter);
853
+ if (!b)
854
+ return null;
855
+ return {
856
+ keyExpr: `((${getSource(node.test)}) ? ${a.keyExpr} : ${b.keyExpr})`,
857
+ options: [...a.options, ...b.options],
858
+ leaves: a.leaves + b.leaves,
859
+ hasGroup: a.hasGroup || b.hasGroup,
860
+ };
861
+ }
862
+ if (node.type === 'BinaryExpression' && node.operator === '&&') {
863
+ const right = buildDecision(node.right, prefix, off, counter);
864
+ if (!right)
865
+ return null;
866
+ return {
867
+ keyExpr: `((${getSource(node.left)}) ? ${right.keyExpr} : ${JSON.stringify(off)})`,
868
+ options: right.options,
869
+ leaves: right.leaves,
870
+ hasGroup: right.hasGroup,
871
+ };
872
+ }
873
+ const group = resolveBracketGroup(node);
874
+ if (group) {
875
+ return {
876
+ keyExpr: getSource(group.keyExpr),
877
+ options: Object.entries(group.obj).map(([value, style]) => ({
878
+ value,
879
+ style: style,
880
+ })),
881
+ leaves: 1,
882
+ hasGroup: true,
883
+ };
884
+ }
885
+ const style = resolveStyleObject(node);
886
+ if (!style)
887
+ return null;
888
+ const value = `${prefix}${counter.n++}`;
889
+ return {
890
+ keyExpr: JSON.stringify(value),
891
+ options: [{ value, style }],
892
+ leaves: 1,
893
+ hasGroup: false,
894
+ };
895
+ };
896
+ const collectGroupKeys = (node, acc) => {
897
+ if (node.type === 'ParenthesisExpression') {
898
+ collectGroupKeys(node.expression, acc);
899
+ }
900
+ else if (node.type === 'ConditionalExpression') {
901
+ collectGroupKeys(node.consequent, acc);
902
+ collectGroupKeys(node.alternate, acc);
903
+ }
904
+ else if (node.type === 'BinaryExpression' &&
905
+ node.operator === '&&') {
906
+ collectGroupKeys(node.right, acc);
907
+ }
908
+ else {
909
+ const group = resolveBracketGroup(node);
910
+ if (group)
911
+ Object.keys(group.obj).forEach((k) => acc.add(k));
912
+ }
913
+ };
914
+ const resolveDecision = (node) => {
915
+ const groupKeys = new Set();
916
+ collectGroupKeys(node, groupKeys);
917
+ let prefix = '#';
918
+ while ([...groupKeys].some((k) => k.startsWith(prefix)))
919
+ prefix += '#';
920
+ const off = groupKeys.has('') ? `${prefix}off` : '';
921
+ return buildDecision(node, prefix, off, { n: 0 });
922
+ };
829
923
  const collectConditions = (node, currentTestStrings = []) => {
830
924
  const staticStyle = resolveStyleObject(node);
831
925
  if (staticStyle) {
832
926
  if (currentTestStrings.length === 0) {
833
927
  baseStyle = (0, utils_1.deepMerge)(baseStyle, staticStyle);
928
+ baseChunks.push({ order: sourceOrder++, style: staticStyle });
834
929
  }
835
930
  else {
836
931
  conditionals.push({
@@ -839,6 +934,7 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
839
934
  truthy: staticStyle,
840
935
  falsy: {},
841
936
  varName: undefined,
937
+ order: sourceOrder++,
842
938
  });
843
939
  }
844
940
  return true;
@@ -855,6 +951,7 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
855
951
  truthy: trueStyle,
856
952
  falsy: falseStyle,
857
953
  varName: undefined,
954
+ order: sourceOrder++,
858
955
  });
859
956
  return true;
860
957
  }
@@ -880,14 +977,6 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
880
977
  else if (node.type === 'ParenthesisExpression') {
881
978
  return collectConditions(node.expression, currentTestStrings);
882
979
  }
883
- if (currentTestStrings.length > 0 &&
884
- utils_1.t.isMemberExpression(node) &&
885
- utils_1.t.isIdentifier(node.object) &&
886
- node.property.type === 'Computed' &&
887
- resolveCreateObject(node.object.value)) {
888
- const varName = node.object.value;
889
- throwCompilationError(`Plumeria: "${getSource(node)}" cannot be used inside a condition, because its bracket key is not a literal.\nMove the condition into the brackets instead, e.g. ${varName}[cond ? 'a' : 'b'].`, node);
890
- }
891
980
  assertResolvable(node);
892
981
  return false;
893
982
  };
@@ -914,6 +1003,7 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
914
1003
  }
915
1004
  if (propPossibilities && propPossibilities.length > 0) {
916
1005
  const currentGroupId = ++groupIdCounter;
1006
+ const currentOrder = sourceOrder++;
917
1007
  const uniqueEntries = [];
918
1008
  propPossibilities.forEach((entry) => {
919
1009
  if (!uniqueEntries.some((x) => x.key === entry.key)) {
@@ -928,6 +1018,7 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
928
1018
  truthy: entry.styleObj,
929
1019
  falsy: {},
930
1020
  groupId: currentGroupId,
1021
+ order: currentOrder,
931
1022
  groupName: undefined,
932
1023
  valueName: entry.key,
933
1024
  varName,
@@ -984,11 +1075,18 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
984
1075
  if (!groupVariants)
985
1076
  continue;
986
1077
  const currentGroupId = ++groupIdCounter;
1078
+ const currentOrder = sourceOrder++;
987
1079
  const valSource = getSource(valExpr);
988
1080
  if (valExpr.type === 'StringLiteral') {
989
1081
  const groupVariantsAsObj = groupVariants;
990
- if (groupVariantsAsObj[valExpr.value])
991
- baseStyle = (0, utils_1.deepMerge)(baseStyle, groupVariantsAsObj[valExpr.value]);
1082
+ const picked = groupVariantsAsObj[valExpr.value];
1083
+ if (picked) {
1084
+ baseStyle = (0, utils_1.deepMerge)(baseStyle, picked);
1085
+ baseChunks.push({
1086
+ order: sourceOrder++,
1087
+ style: picked,
1088
+ });
1089
+ }
992
1090
  continue;
993
1091
  }
994
1092
  Object.entries(groupVariants).forEach(([optionName, style]) => {
@@ -999,6 +1097,7 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
999
1097
  truthy: style,
1000
1098
  falsy: {},
1001
1099
  groupId: currentGroupId,
1100
+ order: currentOrder,
1002
1101
  groupName,
1003
1102
  valueName: optionName,
1004
1103
  varName,
@@ -1010,11 +1109,15 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
1010
1109
  }
1011
1110
  const argSource = getSource(arg);
1012
1111
  if (utils_1.t.isStringLiteral(arg)) {
1013
- if (variantObj[arg.value])
1014
- baseStyle = (0, utils_1.deepMerge)(baseStyle, variantObj[arg.value]);
1112
+ const picked = variantObj[arg.value];
1113
+ if (picked) {
1114
+ baseStyle = (0, utils_1.deepMerge)(baseStyle, picked);
1115
+ baseChunks.push({ order: sourceOrder++, style: picked });
1116
+ }
1015
1117
  continue;
1016
1118
  }
1017
1119
  const currentGroupId = ++groupIdCounter;
1120
+ const currentOrder = sourceOrder++;
1018
1121
  Object.entries(variantObj).forEach(([key, style]) => {
1019
1122
  conditionals.push({
1020
1123
  test: arg,
@@ -1023,6 +1126,7 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
1023
1126
  truthy: style,
1024
1127
  falsy: {},
1025
1128
  groupId: currentGroupId,
1129
+ order: currentOrder,
1026
1130
  groupName: undefined,
1027
1131
  valueName: key,
1028
1132
  varName,
@@ -1050,6 +1154,7 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
1050
1154
  if (!groupVariants)
1051
1155
  return;
1052
1156
  const currentGroupId = ++groupIdCounter;
1157
+ const currentOrder = sourceOrder++;
1053
1158
  Object.entries(groupVariants).forEach(([optionName, style]) => {
1054
1159
  conditionals.push({
1055
1160
  test: expr,
@@ -1058,6 +1163,7 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
1058
1163
  truthy: style,
1059
1164
  falsy: {},
1060
1165
  groupId: currentGroupId,
1166
+ order: currentOrder,
1061
1167
  groupName,
1062
1168
  valueName: optionName,
1063
1169
  varName,
@@ -1076,6 +1182,7 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
1076
1182
  const dynExpr = expr.property.expression;
1077
1183
  const dynSource = getSource(dynExpr);
1078
1184
  const currentGroupId = ++groupIdCounter;
1185
+ const currentOrder = sourceOrder++;
1079
1186
  Object.entries(styleObj).forEach(([optionName, style]) => {
1080
1187
  conditionals.push({
1081
1188
  test: dynExpr,
@@ -1084,6 +1191,7 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
1084
1191
  truthy: style,
1085
1192
  falsy: {},
1086
1193
  groupId: currentGroupId,
1194
+ order: currentOrder,
1087
1195
  groupName: undefined,
1088
1196
  valueName: optionName,
1089
1197
  varName,
@@ -1092,6 +1200,24 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
1092
1200
  continue;
1093
1201
  }
1094
1202
  }
1203
+ const decision = resolveDecision(expr);
1204
+ if (decision && (decision.hasGroup || decision.leaves > 2)) {
1205
+ const groupId = ++groupIdCounter;
1206
+ const currentOrder = sourceOrder++;
1207
+ decision.options.forEach(({ value, style }) => conditionals.push({
1208
+ test: expr,
1209
+ testLHS: decision.keyExpr,
1210
+ testString: `${decision.keyExpr} === '${value}'`,
1211
+ truthy: style,
1212
+ falsy: {},
1213
+ groupId,
1214
+ order: currentOrder,
1215
+ groupName: undefined,
1216
+ valueName: value,
1217
+ varName: undefined,
1218
+ }));
1219
+ continue;
1220
+ }
1095
1221
  const handled = collectConditions(expr);
1096
1222
  if (handled)
1097
1223
  continue;
@@ -1225,7 +1351,7 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
1225
1351
  getSource(options[0].test);
1226
1352
  const lookupMap = {};
1227
1353
  options.forEach((opt) => {
1228
- if (opt.valueName && opt.truthy) {
1354
+ if (opt.valueName !== undefined && opt.truthy) {
1229
1355
  const className = processStyleRecords(opt.truthy)
1230
1356
  .map((r) => r.hash)
1231
1357
  .join(' ');
@@ -1242,17 +1368,38 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
1242
1368
  });
1243
1369
  if (Object.keys(baseConflict).length > 0 ||
1244
1370
  conflictConditionals.length > 0) {
1245
- const dimensions = [];
1371
+ const ordered = [];
1372
+ baseChunks.forEach(({ order, style }) => {
1373
+ const conflicting = {};
1374
+ Object.entries(style).forEach(([key, value]) => {
1375
+ if (conflictingKeys.has(key))
1376
+ conflicting[key] = value;
1377
+ });
1378
+ if (Object.keys(conflicting).length === 0)
1379
+ return;
1380
+ ordered.push({
1381
+ order,
1382
+ dimension: {
1383
+ type: 'const',
1384
+ options: [
1385
+ { value: undefined, style: conflicting, label: 'base' },
1386
+ ],
1387
+ },
1388
+ });
1389
+ });
1246
1390
  conflictConditionals
1247
1391
  .filter((c) => c.groupId === undefined)
1248
1392
  .forEach((c) => {
1249
- dimensions.push({
1250
- type: 'std',
1251
- testExpr: c.testString ?? getSource(c.test),
1252
- options: [
1253
- { value: 0, style: c.falsy, label: 'false' },
1254
- { value: 1, style: c.truthy, label: 'true' },
1255
- ],
1393
+ ordered.push({
1394
+ order: c.order ?? 0,
1395
+ dimension: {
1396
+ type: 'std',
1397
+ testExpr: c.testString ?? getSource(c.test),
1398
+ options: [
1399
+ { value: 0, style: c.falsy, label: 'false' },
1400
+ { value: 1, style: c.truthy, label: 'true' },
1401
+ ],
1402
+ },
1256
1403
  });
1257
1404
  });
1258
1405
  const conflictVarGroups = {};
@@ -1263,19 +1410,33 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
1263
1410
  conflictVarGroups[c.groupId].push(c);
1264
1411
  }
1265
1412
  });
1413
+ Object.keys(conflictVarGroups).forEach((id) => {
1414
+ const groupId = Number(id);
1415
+ const opts = conflictVarGroups[groupId];
1416
+ if (opts.some((c) => c.valueName === ''))
1417
+ return;
1418
+ const off = conditionals.find((c) => c.groupId === groupId && c.valueName === '');
1419
+ if (off)
1420
+ opts.push({ ...off, truthy: {}, falsy: {} });
1421
+ });
1266
1422
  Object.entries(conflictVarGroups).forEach(([, opts]) => {
1267
- dimensions.push({
1268
- type: 'var',
1269
- testExpr: opts[0].testLHS ??
1270
- opts[0].testString ??
1271
- getSource(opts[0].test),
1272
- options: opts.map((opt) => ({
1273
- value: opt.valueName,
1274
- style: opt.truthy,
1275
- label: opt.valueName || 'default',
1276
- })),
1423
+ ordered.push({
1424
+ order: opts[0].order ?? 0,
1425
+ dimension: {
1426
+ type: 'var',
1427
+ testExpr: opts[0].testLHS ??
1428
+ opts[0].testString ??
1429
+ getSource(opts[0].test),
1430
+ options: opts.map((opt) => ({
1431
+ value: opt.valueName,
1432
+ style: opt.truthy,
1433
+ label: opt.valueName || 'default',
1434
+ })),
1435
+ },
1277
1436
  });
1278
1437
  });
1438
+ ordered.sort((a, b) => a.order - b.order);
1439
+ const dimensions = ordered.map((o) => o.dimension);
1279
1440
  const results = {};
1280
1441
  const recurse = (dimIndex, currentStyle, keyParts) => {
1281
1442
  if (dimIndex >= dimensions.length) {
@@ -1286,18 +1447,19 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
1286
1447
  results[keyParts.join('__')] = className;
1287
1448
  return;
1288
1449
  }
1289
- dimensions[dimIndex].options.forEach((opt) => recurse(dimIndex + 1, (0, utils_1.deepMerge)(currentStyle, opt.style), [
1290
- ...keyParts,
1291
- String(opt.value),
1292
- ]));
1450
+ const dimension = dimensions[dimIndex];
1451
+ dimension.options.forEach((opt) => recurse(dimIndex + 1, (0, utils_1.deepMerge)(currentStyle, opt.style), dimension.type === 'const'
1452
+ ? keyParts
1453
+ : [...keyParts, String(opt.value)]));
1293
1454
  };
1294
- recurse(0, baseConflict, []);
1455
+ recurse(0, {}, []);
1295
1456
  const baseConflictClass = Object.keys(baseConflict).length > 0
1296
1457
  ? processStyleRecords(baseConflict)
1297
1458
  .map((r) => r.hash)
1298
1459
  .join(' ')
1299
1460
  : '';
1300
1461
  const masterKeyExpr = dimensions
1462
+ .filter((dim) => dim.type !== 'const')
1301
1463
  .map((dim) => dim.type === 'std'
1302
1464
  ? `(${dim.testExpr} ? "1" : "0")`
1303
1465
  : dim.testExpr || '""')
package/dist/core.mjs CHANGED
@@ -777,6 +777,8 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
777
777
  });
778
778
  const conditionals = [];
779
779
  let groupIdCounter = 0;
780
+ let sourceOrder = 0;
781
+ const baseChunks = [];
780
782
  let baseStyle = {};
781
783
  let isOptimizable = true;
782
784
  const resolveCreateObject = (varName) => {
@@ -790,11 +792,104 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
790
792
  return scannedTables.createObjectTable[hash];
791
793
  return null;
792
794
  };
795
+ const resolveBracketGroup = (node) => {
796
+ if (!t.isMemberExpression(node) ||
797
+ !t.isIdentifier(node.object) ||
798
+ node.property.type !== 'Computed' ||
799
+ t.isStringLiteral(node.property.expression)) {
800
+ return null;
801
+ }
802
+ const varName = node.object.value;
803
+ const obj = resolveCreateObject(varName);
804
+ return obj
805
+ ? { varName, keyExpr: node.property.expression, obj }
806
+ : null;
807
+ };
808
+ const buildDecision = (node, prefix, off, counter) => {
809
+ if (node.type === 'ParenthesisExpression') {
810
+ return buildDecision(node.expression, prefix, off, counter);
811
+ }
812
+ if (node.type === 'ConditionalExpression') {
813
+ const a = buildDecision(node.consequent, prefix, off, counter);
814
+ if (!a)
815
+ return null;
816
+ const b = buildDecision(node.alternate, prefix, off, counter);
817
+ if (!b)
818
+ return null;
819
+ return {
820
+ keyExpr: `((${getSource(node.test)}) ? ${a.keyExpr} : ${b.keyExpr})`,
821
+ options: [...a.options, ...b.options],
822
+ leaves: a.leaves + b.leaves,
823
+ hasGroup: a.hasGroup || b.hasGroup,
824
+ };
825
+ }
826
+ if (node.type === 'BinaryExpression' && node.operator === '&&') {
827
+ const right = buildDecision(node.right, prefix, off, counter);
828
+ if (!right)
829
+ return null;
830
+ return {
831
+ keyExpr: `((${getSource(node.left)}) ? ${right.keyExpr} : ${JSON.stringify(off)})`,
832
+ options: right.options,
833
+ leaves: right.leaves,
834
+ hasGroup: right.hasGroup,
835
+ };
836
+ }
837
+ const group = resolveBracketGroup(node);
838
+ if (group) {
839
+ return {
840
+ keyExpr: getSource(group.keyExpr),
841
+ options: Object.entries(group.obj).map(([value, style]) => ({
842
+ value,
843
+ style: style,
844
+ })),
845
+ leaves: 1,
846
+ hasGroup: true,
847
+ };
848
+ }
849
+ const style = resolveStyleObject(node);
850
+ if (!style)
851
+ return null;
852
+ const value = `${prefix}${counter.n++}`;
853
+ return {
854
+ keyExpr: JSON.stringify(value),
855
+ options: [{ value, style }],
856
+ leaves: 1,
857
+ hasGroup: false,
858
+ };
859
+ };
860
+ const collectGroupKeys = (node, acc) => {
861
+ if (node.type === 'ParenthesisExpression') {
862
+ collectGroupKeys(node.expression, acc);
863
+ }
864
+ else if (node.type === 'ConditionalExpression') {
865
+ collectGroupKeys(node.consequent, acc);
866
+ collectGroupKeys(node.alternate, acc);
867
+ }
868
+ else if (node.type === 'BinaryExpression' &&
869
+ node.operator === '&&') {
870
+ collectGroupKeys(node.right, acc);
871
+ }
872
+ else {
873
+ const group = resolveBracketGroup(node);
874
+ if (group)
875
+ Object.keys(group.obj).forEach((k) => acc.add(k));
876
+ }
877
+ };
878
+ const resolveDecision = (node) => {
879
+ const groupKeys = new Set();
880
+ collectGroupKeys(node, groupKeys);
881
+ let prefix = '#';
882
+ while ([...groupKeys].some((k) => k.startsWith(prefix)))
883
+ prefix += '#';
884
+ const off = groupKeys.has('') ? `${prefix}off` : '';
885
+ return buildDecision(node, prefix, off, { n: 0 });
886
+ };
793
887
  const collectConditions = (node, currentTestStrings = []) => {
794
888
  const staticStyle = resolveStyleObject(node);
795
889
  if (staticStyle) {
796
890
  if (currentTestStrings.length === 0) {
797
891
  baseStyle = deepMerge(baseStyle, staticStyle);
892
+ baseChunks.push({ order: sourceOrder++, style: staticStyle });
798
893
  }
799
894
  else {
800
895
  conditionals.push({
@@ -803,6 +898,7 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
803
898
  truthy: staticStyle,
804
899
  falsy: {},
805
900
  varName: undefined,
901
+ order: sourceOrder++,
806
902
  });
807
903
  }
808
904
  return true;
@@ -819,6 +915,7 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
819
915
  truthy: trueStyle,
820
916
  falsy: falseStyle,
821
917
  varName: undefined,
918
+ order: sourceOrder++,
822
919
  });
823
920
  return true;
824
921
  }
@@ -844,14 +941,6 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
844
941
  else if (node.type === 'ParenthesisExpression') {
845
942
  return collectConditions(node.expression, currentTestStrings);
846
943
  }
847
- if (currentTestStrings.length > 0 &&
848
- t.isMemberExpression(node) &&
849
- t.isIdentifier(node.object) &&
850
- node.property.type === 'Computed' &&
851
- resolveCreateObject(node.object.value)) {
852
- const varName = node.object.value;
853
- throwCompilationError(`Plumeria: "${getSource(node)}" cannot be used inside a condition, because its bracket key is not a literal.\nMove the condition into the brackets instead, e.g. ${varName}[cond ? 'a' : 'b'].`, node);
854
- }
855
944
  assertResolvable(node);
856
945
  return false;
857
946
  };
@@ -878,6 +967,7 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
878
967
  }
879
968
  if (propPossibilities && propPossibilities.length > 0) {
880
969
  const currentGroupId = ++groupIdCounter;
970
+ const currentOrder = sourceOrder++;
881
971
  const uniqueEntries = [];
882
972
  propPossibilities.forEach((entry) => {
883
973
  if (!uniqueEntries.some((x) => x.key === entry.key)) {
@@ -892,6 +982,7 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
892
982
  truthy: entry.styleObj,
893
983
  falsy: {},
894
984
  groupId: currentGroupId,
985
+ order: currentOrder,
895
986
  groupName: undefined,
896
987
  valueName: entry.key,
897
988
  varName,
@@ -948,11 +1039,18 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
948
1039
  if (!groupVariants)
949
1040
  continue;
950
1041
  const currentGroupId = ++groupIdCounter;
1042
+ const currentOrder = sourceOrder++;
951
1043
  const valSource = getSource(valExpr);
952
1044
  if (valExpr.type === 'StringLiteral') {
953
1045
  const groupVariantsAsObj = groupVariants;
954
- if (groupVariantsAsObj[valExpr.value])
955
- baseStyle = deepMerge(baseStyle, groupVariantsAsObj[valExpr.value]);
1046
+ const picked = groupVariantsAsObj[valExpr.value];
1047
+ if (picked) {
1048
+ baseStyle = deepMerge(baseStyle, picked);
1049
+ baseChunks.push({
1050
+ order: sourceOrder++,
1051
+ style: picked,
1052
+ });
1053
+ }
956
1054
  continue;
957
1055
  }
958
1056
  Object.entries(groupVariants).forEach(([optionName, style]) => {
@@ -963,6 +1061,7 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
963
1061
  truthy: style,
964
1062
  falsy: {},
965
1063
  groupId: currentGroupId,
1064
+ order: currentOrder,
966
1065
  groupName,
967
1066
  valueName: optionName,
968
1067
  varName,
@@ -974,11 +1073,15 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
974
1073
  }
975
1074
  const argSource = getSource(arg);
976
1075
  if (t.isStringLiteral(arg)) {
977
- if (variantObj[arg.value])
978
- baseStyle = deepMerge(baseStyle, variantObj[arg.value]);
1076
+ const picked = variantObj[arg.value];
1077
+ if (picked) {
1078
+ baseStyle = deepMerge(baseStyle, picked);
1079
+ baseChunks.push({ order: sourceOrder++, style: picked });
1080
+ }
979
1081
  continue;
980
1082
  }
981
1083
  const currentGroupId = ++groupIdCounter;
1084
+ const currentOrder = sourceOrder++;
982
1085
  Object.entries(variantObj).forEach(([key, style]) => {
983
1086
  conditionals.push({
984
1087
  test: arg,
@@ -987,6 +1090,7 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
987
1090
  truthy: style,
988
1091
  falsy: {},
989
1092
  groupId: currentGroupId,
1093
+ order: currentOrder,
990
1094
  groupName: undefined,
991
1095
  valueName: key,
992
1096
  varName,
@@ -1014,6 +1118,7 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
1014
1118
  if (!groupVariants)
1015
1119
  return;
1016
1120
  const currentGroupId = ++groupIdCounter;
1121
+ const currentOrder = sourceOrder++;
1017
1122
  Object.entries(groupVariants).forEach(([optionName, style]) => {
1018
1123
  conditionals.push({
1019
1124
  test: expr,
@@ -1022,6 +1127,7 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
1022
1127
  truthy: style,
1023
1128
  falsy: {},
1024
1129
  groupId: currentGroupId,
1130
+ order: currentOrder,
1025
1131
  groupName,
1026
1132
  valueName: optionName,
1027
1133
  varName,
@@ -1040,6 +1146,7 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
1040
1146
  const dynExpr = expr.property.expression;
1041
1147
  const dynSource = getSource(dynExpr);
1042
1148
  const currentGroupId = ++groupIdCounter;
1149
+ const currentOrder = sourceOrder++;
1043
1150
  Object.entries(styleObj).forEach(([optionName, style]) => {
1044
1151
  conditionals.push({
1045
1152
  test: dynExpr,
@@ -1048,6 +1155,7 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
1048
1155
  truthy: style,
1049
1156
  falsy: {},
1050
1157
  groupId: currentGroupId,
1158
+ order: currentOrder,
1051
1159
  groupName: undefined,
1052
1160
  valueName: optionName,
1053
1161
  varName,
@@ -1056,6 +1164,24 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
1056
1164
  continue;
1057
1165
  }
1058
1166
  }
1167
+ const decision = resolveDecision(expr);
1168
+ if (decision && (decision.hasGroup || decision.leaves > 2)) {
1169
+ const groupId = ++groupIdCounter;
1170
+ const currentOrder = sourceOrder++;
1171
+ decision.options.forEach(({ value, style }) => conditionals.push({
1172
+ test: expr,
1173
+ testLHS: decision.keyExpr,
1174
+ testString: `${decision.keyExpr} === '${value}'`,
1175
+ truthy: style,
1176
+ falsy: {},
1177
+ groupId,
1178
+ order: currentOrder,
1179
+ groupName: undefined,
1180
+ valueName: value,
1181
+ varName: undefined,
1182
+ }));
1183
+ continue;
1184
+ }
1059
1185
  const handled = collectConditions(expr);
1060
1186
  if (handled)
1061
1187
  continue;
@@ -1189,7 +1315,7 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
1189
1315
  getSource(options[0].test);
1190
1316
  const lookupMap = {};
1191
1317
  options.forEach((opt) => {
1192
- if (opt.valueName && opt.truthy) {
1318
+ if (opt.valueName !== undefined && opt.truthy) {
1193
1319
  const className = processStyleRecords(opt.truthy)
1194
1320
  .map((r) => r.hash)
1195
1321
  .join(' ');
@@ -1206,17 +1332,38 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
1206
1332
  });
1207
1333
  if (Object.keys(baseConflict).length > 0 ||
1208
1334
  conflictConditionals.length > 0) {
1209
- const dimensions = [];
1335
+ const ordered = [];
1336
+ baseChunks.forEach(({ order, style }) => {
1337
+ const conflicting = {};
1338
+ Object.entries(style).forEach(([key, value]) => {
1339
+ if (conflictingKeys.has(key))
1340
+ conflicting[key] = value;
1341
+ });
1342
+ if (Object.keys(conflicting).length === 0)
1343
+ return;
1344
+ ordered.push({
1345
+ order,
1346
+ dimension: {
1347
+ type: 'const',
1348
+ options: [
1349
+ { value: undefined, style: conflicting, label: 'base' },
1350
+ ],
1351
+ },
1352
+ });
1353
+ });
1210
1354
  conflictConditionals
1211
1355
  .filter((c) => c.groupId === undefined)
1212
1356
  .forEach((c) => {
1213
- dimensions.push({
1214
- type: 'std',
1215
- testExpr: c.testString ?? getSource(c.test),
1216
- options: [
1217
- { value: 0, style: c.falsy, label: 'false' },
1218
- { value: 1, style: c.truthy, label: 'true' },
1219
- ],
1357
+ ordered.push({
1358
+ order: c.order ?? 0,
1359
+ dimension: {
1360
+ type: 'std',
1361
+ testExpr: c.testString ?? getSource(c.test),
1362
+ options: [
1363
+ { value: 0, style: c.falsy, label: 'false' },
1364
+ { value: 1, style: c.truthy, label: 'true' },
1365
+ ],
1366
+ },
1220
1367
  });
1221
1368
  });
1222
1369
  const conflictVarGroups = {};
@@ -1227,19 +1374,33 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
1227
1374
  conflictVarGroups[c.groupId].push(c);
1228
1375
  }
1229
1376
  });
1377
+ Object.keys(conflictVarGroups).forEach((id) => {
1378
+ const groupId = Number(id);
1379
+ const opts = conflictVarGroups[groupId];
1380
+ if (opts.some((c) => c.valueName === ''))
1381
+ return;
1382
+ const off = conditionals.find((c) => c.groupId === groupId && c.valueName === '');
1383
+ if (off)
1384
+ opts.push({ ...off, truthy: {}, falsy: {} });
1385
+ });
1230
1386
  Object.entries(conflictVarGroups).forEach(([, opts]) => {
1231
- dimensions.push({
1232
- type: 'var',
1233
- testExpr: opts[0].testLHS ??
1234
- opts[0].testString ??
1235
- getSource(opts[0].test),
1236
- options: opts.map((opt) => ({
1237
- value: opt.valueName,
1238
- style: opt.truthy,
1239
- label: opt.valueName || 'default',
1240
- })),
1387
+ ordered.push({
1388
+ order: opts[0].order ?? 0,
1389
+ dimension: {
1390
+ type: 'var',
1391
+ testExpr: opts[0].testLHS ??
1392
+ opts[0].testString ??
1393
+ getSource(opts[0].test),
1394
+ options: opts.map((opt) => ({
1395
+ value: opt.valueName,
1396
+ style: opt.truthy,
1397
+ label: opt.valueName || 'default',
1398
+ })),
1399
+ },
1241
1400
  });
1242
1401
  });
1402
+ ordered.sort((a, b) => a.order - b.order);
1403
+ const dimensions = ordered.map((o) => o.dimension);
1243
1404
  const results = {};
1244
1405
  const recurse = (dimIndex, currentStyle, keyParts) => {
1245
1406
  if (dimIndex >= dimensions.length) {
@@ -1250,18 +1411,19 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
1250
1411
  results[keyParts.join('__')] = className;
1251
1412
  return;
1252
1413
  }
1253
- dimensions[dimIndex].options.forEach((opt) => recurse(dimIndex + 1, deepMerge(currentStyle, opt.style), [
1254
- ...keyParts,
1255
- String(opt.value),
1256
- ]));
1414
+ const dimension = dimensions[dimIndex];
1415
+ dimension.options.forEach((opt) => recurse(dimIndex + 1, deepMerge(currentStyle, opt.style), dimension.type === 'const'
1416
+ ? keyParts
1417
+ : [...keyParts, String(opt.value)]));
1257
1418
  };
1258
- recurse(0, baseConflict, []);
1419
+ recurse(0, {}, []);
1259
1420
  const baseConflictClass = Object.keys(baseConflict).length > 0
1260
1421
  ? processStyleRecords(baseConflict)
1261
1422
  .map((r) => r.hash)
1262
1423
  .join(' ')
1263
1424
  : '';
1264
1425
  const masterKeyExpr = dimensions
1426
+ .filter((dim) => dim.type !== 'const')
1265
1427
  .map((dim) => dim.type === 'std'
1266
1428
  ? `(${dim.testExpr} ? "1" : "0")`
1267
1429
  : dim.testExpr || '""')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plumeria/unplugin",
3
- "version": "18.0.1",
3
+ "version": "18.1.1",
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.0.1"
92
+ "@plumeria/utils": "^18.1.1"
93
93
  },
94
94
  "devDependencies": {
95
95
  "@swc/core": "1.15.43",