domflax 0.1.0 → 0.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.
- package/README.md +159 -0
- package/dist/{chunk-4HHISSMR.js → chunk-DNHOGPYV.js} +2675 -1503
- package/dist/chunk-DNHOGPYV.js.map +1 -0
- package/dist/{chunk-ZJ2S36GY.js → chunk-DOQEBGWB.js} +33 -20
- package/dist/chunk-DOQEBGWB.js.map +1 -0
- package/dist/{chunk-77SLHRN6.js → chunk-DWLB7FRR.js} +341 -176
- package/dist/chunk-DWLB7FRR.js.map +1 -0
- package/dist/cli.cjs +2169 -760
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +183 -91
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +3021 -1699
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +477 -54
- package/dist/index.d.ts +477 -54
- package/dist/index.js +49 -3
- package/dist/pattern-CV607P87.d.ts +547 -0
- package/dist/pattern-F5xBtIE-.d.cts +547 -0
- package/dist/pattern-kit.cjs +60 -39
- package/dist/pattern-kit.cjs.map +1 -1
- package/dist/pattern-kit.d.cts +3 -18
- package/dist/pattern-kit.d.ts +3 -18
- package/dist/pattern-kit.js +3 -1
- package/dist/pattern-kit.js.map +1 -1
- package/dist/{types-BQ7l6dVe.d.ts → resolve-ops-DIwEelH-.d.cts} +26 -251
- package/dist/{types-BQ7l6dVe.d.cts → resolve-ops-DIwEelH-.d.ts} +26 -251
- package/dist/verify.d.cts +1 -1
- package/dist/verify.d.ts +1 -1
- package/dist/webpack-loader.cjs +2975 -1699
- package/dist/webpack-loader.cjs.map +1 -1
- package/dist/webpack-loader.d.cts +2 -2
- package/dist/webpack-loader.d.ts +2 -2
- package/dist/webpack-loader.js +3 -3
- package/package.json +3 -6
- package/dist/chunk-4HHISSMR.js.map +0 -1
- package/dist/chunk-77SLHRN6.js.map +0 -1
- package/dist/chunk-ZJ2S36GY.js.map +0 -1
- package/dist/pattern-CX6iBzTD.d.ts +0 -237
- package/dist/pattern-P4FIKAUB.d.cts +0 -237
package/dist/cli.cjs
CHANGED
|
@@ -176,8 +176,7 @@ init_cjs_shims();
|
|
|
176
176
|
// ../cli/src/index.ts
|
|
177
177
|
init_cjs_shims();
|
|
178
178
|
var import_node_fs2 = require("fs");
|
|
179
|
-
var
|
|
180
|
-
var import_node_url = require("url");
|
|
179
|
+
var path6 = __toESM(require("path"), 1);
|
|
181
180
|
|
|
182
181
|
// ../cli/src/options.ts
|
|
183
182
|
init_cjs_shims();
|
|
@@ -507,6 +506,9 @@ function elementIds(doc) {
|
|
|
507
506
|
|
|
508
507
|
// ../core/src/ops.ts
|
|
509
508
|
init_cjs_shims();
|
|
509
|
+
|
|
510
|
+
// ../core/src/ops/runtime.ts
|
|
511
|
+
init_cjs_shims();
|
|
510
512
|
function cloneStyleMap(sm) {
|
|
511
513
|
const blocks = /* @__PURE__ */ new Map();
|
|
512
514
|
for (const [key, block] of sm.blocks) {
|
|
@@ -573,6 +575,32 @@ function removeSubtree(state, id) {
|
|
|
573
575
|
state.doc.nodes.delete(id);
|
|
574
576
|
state.removed.add(id);
|
|
575
577
|
}
|
|
578
|
+
function precond(op, nodeId, message) {
|
|
579
|
+
return diag("DF_OP_PRECONDITION_FAILED", message, {
|
|
580
|
+
nodeId,
|
|
581
|
+
pattern: op.origin.pattern,
|
|
582
|
+
severity: "error"
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
function primaryTarget(op) {
|
|
586
|
+
switch (op.op) {
|
|
587
|
+
case "removeNode":
|
|
588
|
+
case "unwrap":
|
|
589
|
+
case "replaceWith":
|
|
590
|
+
case "wrap":
|
|
591
|
+
case "moveNode":
|
|
592
|
+
case "setClassList":
|
|
593
|
+
case "mergeStyle":
|
|
594
|
+
return op.target;
|
|
595
|
+
case "insertBefore":
|
|
596
|
+
case "insertAfter":
|
|
597
|
+
return op.anchor;
|
|
598
|
+
case "mergeSiblings":
|
|
599
|
+
return op.first;
|
|
600
|
+
case "foldInheritedStyles":
|
|
601
|
+
return op.from;
|
|
602
|
+
}
|
|
603
|
+
}
|
|
576
604
|
function specToAttrs(map) {
|
|
577
605
|
if (!map || map.size === 0) return { entries: /* @__PURE__ */ new Map(), spreads: [], order: [] };
|
|
578
606
|
const entries = /* @__PURE__ */ new Map();
|
|
@@ -681,6 +709,9 @@ function mergeStyleMaps(target, source, policy) {
|
|
|
681
709
|
}
|
|
682
710
|
return { map: { blocks }, conflict };
|
|
683
711
|
}
|
|
712
|
+
|
|
713
|
+
// ../core/src/ops/apply.ts
|
|
714
|
+
init_cjs_shims();
|
|
684
715
|
function safetyOk(state, op, targetId) {
|
|
685
716
|
const opSafety = op.origin.safety;
|
|
686
717
|
if (opSafety > state.ceiling) {
|
|
@@ -907,32 +938,6 @@ function applyFold(state, op) {
|
|
|
907
938
|
for (const d3 of issues) state.diagnostics.push(d3);
|
|
908
939
|
return [];
|
|
909
940
|
}
|
|
910
|
-
function precond(op, nodeId, message) {
|
|
911
|
-
return diag("DF_OP_PRECONDITION_FAILED", message, {
|
|
912
|
-
nodeId,
|
|
913
|
-
pattern: op.origin.pattern,
|
|
914
|
-
severity: "error"
|
|
915
|
-
});
|
|
916
|
-
}
|
|
917
|
-
function primaryTarget(op) {
|
|
918
|
-
switch (op.op) {
|
|
919
|
-
case "removeNode":
|
|
920
|
-
case "unwrap":
|
|
921
|
-
case "replaceWith":
|
|
922
|
-
case "wrap":
|
|
923
|
-
case "moveNode":
|
|
924
|
-
case "setClassList":
|
|
925
|
-
case "mergeStyle":
|
|
926
|
-
return op.target;
|
|
927
|
-
case "insertBefore":
|
|
928
|
-
case "insertAfter":
|
|
929
|
-
return op.anchor;
|
|
930
|
-
case "mergeSiblings":
|
|
931
|
-
return op.first;
|
|
932
|
-
case "foldInheritedStyles":
|
|
933
|
-
return op.from;
|
|
934
|
-
}
|
|
935
|
-
}
|
|
936
941
|
function applyOps(doc, ops, ctx) {
|
|
937
942
|
const cloned = cloneDocument(doc);
|
|
938
943
|
const state = {
|
|
@@ -974,13 +979,9 @@ function finalize(state) {
|
|
|
974
979
|
|
|
975
980
|
// ../core/src/pass-manager.ts
|
|
976
981
|
init_cjs_shims();
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
onBudgetExhausted: "warn",
|
|
981
|
-
detectOscillation: true
|
|
982
|
-
};
|
|
983
|
-
var PHASE_ORDER = ["flatten", "compress", "extract"];
|
|
982
|
+
|
|
983
|
+
// ../core/src/pass-context.ts
|
|
984
|
+
init_cjs_shims();
|
|
984
985
|
function createNullSelectorIndex() {
|
|
985
986
|
const none = /* @__PURE__ */ new Set();
|
|
986
987
|
return {
|
|
@@ -1190,10 +1191,137 @@ function buildMatchContext(doc, elementId, resolver, selectors, safety, phase, i
|
|
|
1190
1191
|
}
|
|
1191
1192
|
};
|
|
1192
1193
|
}
|
|
1193
|
-
|
|
1194
|
+
|
|
1195
|
+
// ../core/src/flatten-safety.ts
|
|
1196
|
+
init_cjs_shims();
|
|
1197
|
+
var DISPLAY = "display";
|
|
1198
|
+
var POSITION = "position";
|
|
1199
|
+
var TRANSFORM = "transform";
|
|
1200
|
+
var CONTEXT_SAFE_DISPLAYS = /* @__PURE__ */ new Set(["block", "contents", ""]);
|
|
1201
|
+
var STATIC_POSITIONS = /* @__PURE__ */ new Set(["static", ""]);
|
|
1202
|
+
var SELF_ALIGN_PROPS = [
|
|
1203
|
+
"place-self",
|
|
1204
|
+
"align-self",
|
|
1205
|
+
"justify-self"
|
|
1206
|
+
];
|
|
1207
|
+
var NEUTRAL_ALIGN = /* @__PURE__ */ new Set(["auto", "normal", "auto auto", ""]);
|
|
1208
|
+
var FLEX_GRID_DISPLAYS = /* @__PURE__ */ new Set(["flex", "inline-flex", "grid", "inline-grid"]);
|
|
1209
|
+
function establishesChildContext(sm) {
|
|
1210
|
+
for (const block of sm.blocks.values()) {
|
|
1211
|
+
const display = block.decls.get(DISPLAY);
|
|
1212
|
+
if (display && !CONTEXT_SAFE_DISPLAYS.has(String(display.value))) return true;
|
|
1213
|
+
const position = block.decls.get(POSITION);
|
|
1214
|
+
if (position && !STATIC_POSITIONS.has(String(position.value))) return true;
|
|
1215
|
+
const transform = block.decls.get(TRANSFORM);
|
|
1216
|
+
if (transform && String(transform.value) !== "none") return true;
|
|
1217
|
+
}
|
|
1218
|
+
return false;
|
|
1219
|
+
}
|
|
1220
|
+
function isInherited2(decl, norm) {
|
|
1221
|
+
if (decl.inherited) return true;
|
|
1222
|
+
try {
|
|
1223
|
+
return norm.inherited.isInherited(decl.property);
|
|
1224
|
+
} catch {
|
|
1225
|
+
return false;
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
function childReproduces(childComputed, conditionK, prop, value) {
|
|
1229
|
+
if (!childComputed) return false;
|
|
1230
|
+
const block = childComputed.blocks.get(conditionK);
|
|
1231
|
+
if (!block) return false;
|
|
1232
|
+
const d3 = block.decls.get(prop);
|
|
1233
|
+
return d3 != null && String(d3.value) === value;
|
|
1234
|
+
}
|
|
1235
|
+
function dropsOwnStyle(wrapperComputed, childComputed, norm) {
|
|
1236
|
+
for (const block of wrapperComputed.blocks.values()) {
|
|
1237
|
+
const ck = conditionKey(block.condition);
|
|
1238
|
+
for (const [prop, decl] of block.decls) {
|
|
1239
|
+
if (prop === DISPLAY || prop === POSITION || prop === TRANSFORM) continue;
|
|
1240
|
+
if (isInherited2(decl, norm)) continue;
|
|
1241
|
+
if (!childReproduces(childComputed, ck, prop, String(decl.value))) return true;
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
return false;
|
|
1245
|
+
}
|
|
1246
|
+
function displayOf(el, norm) {
|
|
1247
|
+
if (!el) return "";
|
|
1248
|
+
for (const block of norm.normalizeStyleMap(el.computed).blocks.values()) {
|
|
1249
|
+
if (block.condition.media === "" && block.condition.states.length === 0 && block.condition.pseudoElement === "") {
|
|
1250
|
+
const d3 = block.decls.get(DISPLAY);
|
|
1251
|
+
if (d3) return String(d3.value);
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
return "";
|
|
1255
|
+
}
|
|
1256
|
+
function newParentIsFlexOrGrid(before, wrapper, norm) {
|
|
1257
|
+
if (wrapper.parent == null) return false;
|
|
1258
|
+
const p2 = before.nodes.get(wrapper.parent);
|
|
1259
|
+
if (!p2 || p2.kind !== "element") return false;
|
|
1260
|
+
return FLEX_GRID_DISPLAYS.has(displayOf(p2, norm));
|
|
1261
|
+
}
|
|
1262
|
+
function addsParentContextStyle(childBefore, childAfter, norm) {
|
|
1263
|
+
if (!childAfter) return false;
|
|
1264
|
+
const before = childBefore ? norm.normalizeStyleMap(childBefore) : null;
|
|
1265
|
+
const after = norm.normalizeStyleMap(childAfter);
|
|
1266
|
+
for (const block of after.blocks.values()) {
|
|
1267
|
+
const ck = conditionKey(block.condition);
|
|
1268
|
+
for (const prop of SELF_ALIGN_PROPS) {
|
|
1269
|
+
const d3 = block.decls.get(prop);
|
|
1270
|
+
if (!d3 || NEUTRAL_ALIGN.has(String(d3.value))) continue;
|
|
1271
|
+
const prev = before?.blocks.get(ck)?.decls.get(prop);
|
|
1272
|
+
if (!prev || String(prev.value) !== String(d3.value)) return true;
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
return false;
|
|
1276
|
+
}
|
|
1277
|
+
function unwrapTargetOf(ops) {
|
|
1278
|
+
for (const op of ops) if (op.op === "unwrap") return op.target;
|
|
1279
|
+
return null;
|
|
1280
|
+
}
|
|
1281
|
+
function survivingChildOf(ops, wrapper, before) {
|
|
1282
|
+
for (const op of ops) if (op.op === "mergeStyle") return op.target;
|
|
1283
|
+
for (const op of ops) if (op.op === "foldInheritedStyles" && op.into.length > 0) return op.into[0];
|
|
1284
|
+
for (const c of wrapper.children) {
|
|
1285
|
+
const n = before.nodes.get(c);
|
|
1286
|
+
if (n && n.kind === "element") return c;
|
|
1287
|
+
}
|
|
1288
|
+
return null;
|
|
1289
|
+
}
|
|
1290
|
+
function classifyFlattenOps(before, after, ops, norm) {
|
|
1291
|
+
const wrapperId = unwrapTargetOf(ops);
|
|
1292
|
+
if (wrapperId == null) return { kind: "provably-safe", wrapperId: null, childId: null };
|
|
1293
|
+
const wrapper = before.nodes.get(wrapperId);
|
|
1294
|
+
if (!wrapper || wrapper.kind !== "element") {
|
|
1295
|
+
return { kind: "provably-safe", wrapperId: null, childId: null };
|
|
1296
|
+
}
|
|
1297
|
+
const childId = survivingChildOf(ops, wrapper, before);
|
|
1298
|
+
const wrapperComputed = norm.normalizeStyleMap(wrapper.computed);
|
|
1299
|
+
const childAfter = childId != null ? getElement(after, childId)?.computed ?? null : null;
|
|
1300
|
+
const childBefore = childId != null ? getElement(before, childId)?.computed ?? null : null;
|
|
1301
|
+
if (establishesChildContext(wrapperComputed)) {
|
|
1302
|
+
return { kind: "needs-verification", wrapperId, childId };
|
|
1303
|
+
}
|
|
1304
|
+
if (dropsOwnStyle(wrapperComputed, childAfter ? norm.normalizeStyleMap(childAfter) : null, norm)) {
|
|
1305
|
+
return { kind: "needs-verification", wrapperId, childId };
|
|
1306
|
+
}
|
|
1307
|
+
if (addsParentContextStyle(childBefore, childAfter, norm) && !newParentIsFlexOrGrid(before, wrapper, norm)) {
|
|
1308
|
+
return { kind: "needs-verification", wrapperId, childId };
|
|
1309
|
+
}
|
|
1310
|
+
return { kind: "provably-safe", wrapperId, childId };
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
// ../core/src/pass-manager.ts
|
|
1314
|
+
var DEFAULT_FIXPOINT = {
|
|
1315
|
+
maxIterations: 16,
|
|
1316
|
+
phases: { flatten: 16, compress: 8, extract: 4 },
|
|
1317
|
+
onBudgetExhausted: "warn",
|
|
1318
|
+
detectOscillation: true
|
|
1319
|
+
};
|
|
1320
|
+
var PHASE_ORDER = ["flatten", "compress", "extract"];
|
|
1321
|
+
function stampOrigin(draft, pattern) {
|
|
1194
1322
|
return {
|
|
1195
1323
|
...draft,
|
|
1196
|
-
origin: { pattern:
|
|
1324
|
+
origin: { pattern: pattern.name, category: pattern.category, safety: pattern.safety }
|
|
1197
1325
|
};
|
|
1198
1326
|
}
|
|
1199
1327
|
function patternsForPhase(passes, phase) {
|
|
@@ -1245,69 +1373,76 @@ function flattenWouldDropStyle(before, after, ops, resolver, normalizer2) {
|
|
|
1245
1373
|
}
|
|
1246
1374
|
return false;
|
|
1247
1375
|
}
|
|
1376
|
+
function flattenVerdict(before, after, ops, ctx) {
|
|
1377
|
+
if (flattenWouldDropStyle(before, after, ops, ctx.resolver, ctx.normalizer)) return "revert";
|
|
1378
|
+
const gate = ctx.gate ?? "all";
|
|
1379
|
+
if (gate === "all") return "commit";
|
|
1380
|
+
const cls = classifyFlattenOps(before, after, ops, ctx.normalizer);
|
|
1381
|
+
return cls.kind === "provably-safe" ? "commit" : "revert";
|
|
1382
|
+
}
|
|
1383
|
+
function evaluateElement(doc, elId, patterns, ctx, factory, phase, iteration, diagnostics) {
|
|
1384
|
+
for (const pattern of patterns) {
|
|
1385
|
+
if (pattern.safety > ctx.safetyCeiling) continue;
|
|
1386
|
+
let drafts = [];
|
|
1387
|
+
try {
|
|
1388
|
+
const mctx = buildMatchContext(doc, elId, ctx.resolver, ctx.selectors, ctx.safetyCeiling, phase, iteration);
|
|
1389
|
+
const result = pattern.evaluate(mctx, factory);
|
|
1390
|
+
if (!result) continue;
|
|
1391
|
+
drafts = result.ops;
|
|
1392
|
+
if (result.diagnostics) for (const d3 of result.diagnostics) diagnostics.push(d3);
|
|
1393
|
+
} catch (err) {
|
|
1394
|
+
diagnostics.push({
|
|
1395
|
+
code: "DF_PATTERN_THREW",
|
|
1396
|
+
severity: "error",
|
|
1397
|
+
message: `pattern '${pattern.name}' threw: ${String(err?.message ?? err)}`,
|
|
1398
|
+
nodeId: elId,
|
|
1399
|
+
pattern: pattern.name,
|
|
1400
|
+
phase,
|
|
1401
|
+
iteration,
|
|
1402
|
+
cause: err
|
|
1403
|
+
});
|
|
1404
|
+
continue;
|
|
1405
|
+
}
|
|
1406
|
+
if (drafts.length === 0) continue;
|
|
1407
|
+
return { ops: drafts.map((d3) => stampOrigin(d3, pattern)), pattern };
|
|
1408
|
+
}
|
|
1409
|
+
return null;
|
|
1410
|
+
}
|
|
1411
|
+
function revertDiagnostic(pattern, elId, phase, iteration, resolverId) {
|
|
1412
|
+
return {
|
|
1413
|
+
code: "DF_VERIFY_REVERTED",
|
|
1414
|
+
severity: "warn",
|
|
1415
|
+
message: `flatten '${pattern.name}' reverted on node ${elId}: it would change rendering (drops a style, establishes layout context, or assumes a parent context) and was not proven safe by resolver '${resolverId}'`,
|
|
1416
|
+
nodeId: elId,
|
|
1417
|
+
pattern: pattern.name,
|
|
1418
|
+
phase,
|
|
1419
|
+
iteration
|
|
1420
|
+
};
|
|
1421
|
+
}
|
|
1248
1422
|
function runSweep(state, patterns, ctx, factory, phase, iteration, touched, diagnostics, flattenBarred) {
|
|
1249
1423
|
let appliedOps = 0;
|
|
1250
|
-
const resolver = ctx.resolver;
|
|
1251
|
-
const selectors = ctx.selectors;
|
|
1252
1424
|
for (const elId of elementIds(state.doc)) {
|
|
1253
1425
|
const el = getElement(state.doc, elId);
|
|
1254
1426
|
if (!el) continue;
|
|
1255
1427
|
if (phase === "flatten" && flattenBarred.has(elId)) continue;
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
iteration
|
|
1268
|
-
);
|
|
1269
|
-
const result = pattern2.evaluate(mctx, factory);
|
|
1270
|
-
if (!result) continue;
|
|
1271
|
-
drafts = result.ops;
|
|
1272
|
-
if (result.diagnostics) for (const d3 of result.diagnostics) diagnostics.push(d3);
|
|
1273
|
-
} catch (err) {
|
|
1274
|
-
diagnostics.push({
|
|
1275
|
-
code: "DF_PATTERN_THREW",
|
|
1276
|
-
severity: "error",
|
|
1277
|
-
message: `pattern '${pattern2.name}' threw: ${String(err?.message ?? err)}`,
|
|
1278
|
-
nodeId: elId,
|
|
1279
|
-
pattern: pattern2.name,
|
|
1280
|
-
phase,
|
|
1281
|
-
iteration,
|
|
1282
|
-
cause: err
|
|
1283
|
-
});
|
|
1428
|
+
const evaluated = evaluateElement(state.doc, elId, patterns, ctx, factory, phase, iteration, diagnostics);
|
|
1429
|
+
if (!evaluated) continue;
|
|
1430
|
+
const { ops, pattern } = evaluated;
|
|
1431
|
+
const outcome = applyOps(state.doc, ops, ctx);
|
|
1432
|
+
for (const d3 of outcome.result.diagnostics) diagnostics.push(d3);
|
|
1433
|
+
if (outcome.result.appliedGroups === 0) continue;
|
|
1434
|
+
if (phase === "flatten") {
|
|
1435
|
+
const verdict = flattenVerdict(state.doc, outcome.doc, ops, ctx);
|
|
1436
|
+
if (verdict !== "commit") {
|
|
1437
|
+
diagnostics.push(revertDiagnostic(pattern, elId, phase, iteration, ctx.resolver.id));
|
|
1438
|
+
flattenBarred.add(elId);
|
|
1284
1439
|
continue;
|
|
1285
1440
|
}
|
|
1286
|
-
if (drafts.length === 0) continue;
|
|
1287
|
-
const ops = drafts.map((d3) => stampOrigin(d3, pattern2));
|
|
1288
|
-
const outcome = applyOps(state.doc, ops, ctx);
|
|
1289
|
-
for (const d3 of outcome.result.diagnostics) diagnostics.push(d3);
|
|
1290
|
-
if (outcome.result.appliedGroups > 0) {
|
|
1291
|
-
if (phase === "flatten" && flattenWouldDropStyle(state.doc, outcome.doc, ops, resolver, ctx.normalizer)) {
|
|
1292
|
-
diagnostics.push({
|
|
1293
|
-
code: "DF_VERIFY_REVERTED",
|
|
1294
|
-
severity: "warn",
|
|
1295
|
-
message: `flatten '${pattern2.name}' reverted on node ${elId}: residual style is not reproducible by resolver '${resolver.id}', so flattening would drop it`,
|
|
1296
|
-
nodeId: elId,
|
|
1297
|
-
pattern: pattern2.name,
|
|
1298
|
-
phase,
|
|
1299
|
-
iteration
|
|
1300
|
-
});
|
|
1301
|
-
flattenBarred.add(elId);
|
|
1302
|
-
break;
|
|
1303
|
-
}
|
|
1304
|
-
state.doc = outcome.doc;
|
|
1305
|
-
appliedOps += outcome.result.appliedGroups;
|
|
1306
|
-
for (const id of outcome.result.touched) touched.add(id);
|
|
1307
|
-
for (const id of outcome.result.created) touched.add(id);
|
|
1308
|
-
break;
|
|
1309
|
-
}
|
|
1310
1441
|
}
|
|
1442
|
+
state.doc = outcome.doc;
|
|
1443
|
+
appliedOps += outcome.result.appliedGroups;
|
|
1444
|
+
for (const id of outcome.result.touched) touched.add(id);
|
|
1445
|
+
for (const id of outcome.result.created) touched.add(id);
|
|
1311
1446
|
}
|
|
1312
1447
|
return appliedOps;
|
|
1313
1448
|
}
|
|
@@ -1322,6 +1457,26 @@ function docFingerprint(doc) {
|
|
|
1322
1457
|
visit(doc.root);
|
|
1323
1458
|
return parts.join("|");
|
|
1324
1459
|
}
|
|
1460
|
+
function finalizePhase(phase, s, budget, onBudgetExhausted) {
|
|
1461
|
+
if (!s.converged && s.haltReason !== "oscillation") {
|
|
1462
|
+
s.haltReason = "budget";
|
|
1463
|
+
s.diagnostics.push({
|
|
1464
|
+
code: "DF_FIXPOINT_BUDGET",
|
|
1465
|
+
severity: onBudgetExhausted === "error" ? "error" : "warn",
|
|
1466
|
+
message: `phase '${phase}' exhausted ${budget}-iteration budget`,
|
|
1467
|
+
phase,
|
|
1468
|
+
iteration: s.iterations
|
|
1469
|
+
});
|
|
1470
|
+
}
|
|
1471
|
+
return {
|
|
1472
|
+
phase,
|
|
1473
|
+
iterations: s.iterations,
|
|
1474
|
+
converged: s.converged,
|
|
1475
|
+
haltReason: s.haltReason,
|
|
1476
|
+
touched: s.touched,
|
|
1477
|
+
diagnostics: s.diagnostics
|
|
1478
|
+
};
|
|
1479
|
+
}
|
|
1325
1480
|
function runPasses(doc, passes, ctx, config) {
|
|
1326
1481
|
const cfg = { ...DEFAULT_FIXPOINT, ...config };
|
|
1327
1482
|
const factory = createRewriteFactory();
|
|
@@ -1330,76 +1485,54 @@ function runPasses(doc, passes, ctx, config) {
|
|
|
1330
1485
|
const flattenBarred = /* @__PURE__ */ new Set();
|
|
1331
1486
|
for (const phase of PHASE_ORDER) {
|
|
1332
1487
|
const patterns = patternsForPhase(passes, phase);
|
|
1333
|
-
const phaseTouched = /* @__PURE__ */ new Set();
|
|
1334
|
-
const diagnostics = [];
|
|
1335
1488
|
const budget = cfg.phases[phase] ?? cfg.maxIterations;
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1489
|
+
const s = {
|
|
1490
|
+
iterations: 0,
|
|
1491
|
+
converged: false,
|
|
1492
|
+
haltReason: "converged",
|
|
1493
|
+
touched: /* @__PURE__ */ new Set(),
|
|
1494
|
+
diagnostics: [],
|
|
1495
|
+
seen: /* @__PURE__ */ new Set()
|
|
1496
|
+
};
|
|
1340
1497
|
if (patterns.length === 0) {
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
iterations: 0,
|
|
1344
|
-
converged: true,
|
|
1345
|
-
haltReason: "converged",
|
|
1346
|
-
touched: phaseTouched,
|
|
1347
|
-
diagnostics
|
|
1348
|
-
});
|
|
1498
|
+
s.converged = true;
|
|
1499
|
+
results.push(finalizePhase(phase, s, budget, cfg.onBudgetExhausted));
|
|
1349
1500
|
continue;
|
|
1350
1501
|
}
|
|
1351
|
-
while (iterations < budget) {
|
|
1352
|
-
iterations += 1;
|
|
1502
|
+
while (s.iterations < budget) {
|
|
1503
|
+
s.iterations += 1;
|
|
1353
1504
|
const applied = runSweep(
|
|
1354
1505
|
state,
|
|
1355
1506
|
patterns,
|
|
1356
1507
|
ctx,
|
|
1357
1508
|
factory,
|
|
1358
1509
|
phase,
|
|
1359
|
-
iterations,
|
|
1360
|
-
|
|
1361
|
-
diagnostics,
|
|
1510
|
+
s.iterations,
|
|
1511
|
+
s.touched,
|
|
1512
|
+
s.diagnostics,
|
|
1362
1513
|
flattenBarred
|
|
1363
1514
|
);
|
|
1364
1515
|
if (applied === 0) {
|
|
1365
|
-
converged = true;
|
|
1366
|
-
haltReason = "converged";
|
|
1516
|
+
s.converged = true;
|
|
1367
1517
|
break;
|
|
1368
1518
|
}
|
|
1369
1519
|
if (cfg.detectOscillation) {
|
|
1370
1520
|
const fp = docFingerprint(state.doc);
|
|
1371
|
-
if (seen.has(fp)) {
|
|
1372
|
-
haltReason = "oscillation";
|
|
1373
|
-
diagnostics.push({
|
|
1521
|
+
if (s.seen.has(fp)) {
|
|
1522
|
+
s.haltReason = "oscillation";
|
|
1523
|
+
s.diagnostics.push({
|
|
1374
1524
|
code: "DF_FIXPOINT_OSCILLATION",
|
|
1375
1525
|
severity: "warn",
|
|
1376
1526
|
message: `phase '${phase}' oscillated; halting`,
|
|
1377
1527
|
phase,
|
|
1378
|
-
iteration: iterations
|
|
1528
|
+
iteration: s.iterations
|
|
1379
1529
|
});
|
|
1380
1530
|
break;
|
|
1381
1531
|
}
|
|
1382
|
-
seen.add(fp);
|
|
1532
|
+
s.seen.add(fp);
|
|
1383
1533
|
}
|
|
1384
1534
|
}
|
|
1385
|
-
|
|
1386
|
-
haltReason = "budget";
|
|
1387
|
-
diagnostics.push({
|
|
1388
|
-
code: "DF_FIXPOINT_BUDGET",
|
|
1389
|
-
severity: cfg.onBudgetExhausted === "error" ? "error" : "warn",
|
|
1390
|
-
message: `phase '${phase}' exhausted ${budget}-iteration budget`,
|
|
1391
|
-
phase,
|
|
1392
|
-
iteration: iterations
|
|
1393
|
-
});
|
|
1394
|
-
}
|
|
1395
|
-
results.push({
|
|
1396
|
-
phase,
|
|
1397
|
-
iterations,
|
|
1398
|
-
converged,
|
|
1399
|
-
haltReason,
|
|
1400
|
-
touched: phaseTouched,
|
|
1401
|
-
diagnostics
|
|
1402
|
-
});
|
|
1535
|
+
results.push(finalizePhase(phase, s, budget, cfg.onBudgetExhausted));
|
|
1403
1536
|
}
|
|
1404
1537
|
return { doc: state.doc, results };
|
|
1405
1538
|
}
|
|
@@ -1482,7 +1615,9 @@ init_cjs_shims();
|
|
|
1482
1615
|
|
|
1483
1616
|
// ../frontend-jsx/src/frontend.ts
|
|
1484
1617
|
init_cjs_shims();
|
|
1485
|
-
|
|
1618
|
+
|
|
1619
|
+
// ../frontend-jsx/src/frontend-ast.ts
|
|
1620
|
+
init_cjs_shims();
|
|
1486
1621
|
var import_traverse = __toESM(require("@babel/traverse"), 1);
|
|
1487
1622
|
var traverse = typeof import_traverse.default === "function" ? import_traverse.default : import_traverse.default.default;
|
|
1488
1623
|
var JSX_LANGS = ["jsx", "tsx"];
|
|
@@ -1546,10 +1681,71 @@ function classFormOf(node) {
|
|
|
1546
1681
|
return "call";
|
|
1547
1682
|
}
|
|
1548
1683
|
}
|
|
1684
|
+
function findNestedJsxRoots(root) {
|
|
1685
|
+
const out = [];
|
|
1686
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1687
|
+
const visit = (n) => {
|
|
1688
|
+
if (!n || seen.has(n)) return;
|
|
1689
|
+
seen.add(n);
|
|
1690
|
+
switch (n.type) {
|
|
1691
|
+
case "JSXElement":
|
|
1692
|
+
case "JSXFragment":
|
|
1693
|
+
out.push(n);
|
|
1694
|
+
return;
|
|
1695
|
+
case "ParenthesizedExpression":
|
|
1696
|
+
case "TSNonNullExpression":
|
|
1697
|
+
case "TSAsExpression":
|
|
1698
|
+
case "TSSatisfiesExpression":
|
|
1699
|
+
case "TSTypeAssertion":
|
|
1700
|
+
visit(n.expression);
|
|
1701
|
+
return;
|
|
1702
|
+
case "LogicalExpression":
|
|
1703
|
+
visit(n.left);
|
|
1704
|
+
visit(n.right);
|
|
1705
|
+
return;
|
|
1706
|
+
case "ConditionalExpression":
|
|
1707
|
+
visit(n.consequent);
|
|
1708
|
+
visit(n.alternate);
|
|
1709
|
+
return;
|
|
1710
|
+
case "SequenceExpression":
|
|
1711
|
+
for (const e2 of n.expressions) visit(e2);
|
|
1712
|
+
return;
|
|
1713
|
+
case "CallExpression":
|
|
1714
|
+
case "OptionalCallExpression":
|
|
1715
|
+
for (const a of n.arguments) visit(a);
|
|
1716
|
+
return;
|
|
1717
|
+
case "ArrowFunctionExpression":
|
|
1718
|
+
case "FunctionExpression":
|
|
1719
|
+
visit(n.body);
|
|
1720
|
+
return;
|
|
1721
|
+
case "BlockStatement":
|
|
1722
|
+
for (const s of n.body) visit(s);
|
|
1723
|
+
return;
|
|
1724
|
+
case "ReturnStatement":
|
|
1725
|
+
visit(n.argument);
|
|
1726
|
+
return;
|
|
1727
|
+
case "IfStatement":
|
|
1728
|
+
visit(n.consequent);
|
|
1729
|
+
visit(n.alternate);
|
|
1730
|
+
return;
|
|
1731
|
+
case "ArrayExpression":
|
|
1732
|
+
for (const el of n.elements) visit(el);
|
|
1733
|
+
return;
|
|
1734
|
+
default:
|
|
1735
|
+
return;
|
|
1736
|
+
}
|
|
1737
|
+
};
|
|
1738
|
+
visit(root);
|
|
1739
|
+
return out;
|
|
1740
|
+
}
|
|
1549
1741
|
function looksLikeJsx(id, code) {
|
|
1550
1742
|
if (/\.[jt]sx$/i.test(id)) return true;
|
|
1551
1743
|
return /<\/?[A-Za-z][\w.-]*|<>/.test(code);
|
|
1552
1744
|
}
|
|
1745
|
+
|
|
1746
|
+
// ../frontend-jsx/src/frontend-parse.ts
|
|
1747
|
+
init_cjs_shims();
|
|
1748
|
+
var import_parser = require("@babel/parser");
|
|
1553
1749
|
function doParse(code, ctx) {
|
|
1554
1750
|
const diagnostics = [];
|
|
1555
1751
|
const doc = createDocument("jsx");
|
|
@@ -1651,7 +1847,8 @@ function doParse(code, ctx) {
|
|
|
1651
1847
|
}
|
|
1652
1848
|
return { kind: "dynamic", expr: internExpr(v2, false), span: spanOf(v2) ?? void 0 };
|
|
1653
1849
|
};
|
|
1654
|
-
const
|
|
1850
|
+
const buildNestedRoot = (jsx, parentId) => jsx.type === "JSXFragment" ? buildFragment(jsx, parentId) : buildElement(jsx, parentId);
|
|
1851
|
+
const appendChild = (node, parentId, out) => {
|
|
1655
1852
|
switch (node.type) {
|
|
1656
1853
|
case "JSXText": {
|
|
1657
1854
|
const id = doc.alloc.next();
|
|
@@ -1663,36 +1860,47 @@ function doParse(code, ctx) {
|
|
|
1663
1860
|
collapsible: /^\s*$/.test(node.value)
|
|
1664
1861
|
})
|
|
1665
1862
|
);
|
|
1666
|
-
|
|
1863
|
+
out.push(id);
|
|
1864
|
+
return;
|
|
1667
1865
|
}
|
|
1668
1866
|
case "JSXExpressionContainer": {
|
|
1669
|
-
|
|
1867
|
+
const expr = node.expression;
|
|
1868
|
+
if (expr.type === "JSXEmptyExpression") return;
|
|
1869
|
+
if (expr.type === "JSXElement" || expr.type === "JSXFragment") {
|
|
1870
|
+
out.push(buildNestedRoot(expr, parentId));
|
|
1871
|
+
return;
|
|
1872
|
+
}
|
|
1670
1873
|
const id = doc.alloc.next();
|
|
1671
|
-
const ref = internExpr(
|
|
1874
|
+
const ref = internExpr(expr, false);
|
|
1672
1875
|
doc.nodes.set(id, createExpr(id, ref, { parent: parentId, span: spanOf(node) }));
|
|
1673
|
-
|
|
1876
|
+
out.push(id);
|
|
1877
|
+
for (const jsx of findNestedJsxRoots(expr)) out.push(buildNestedRoot(jsx, parentId));
|
|
1878
|
+
return;
|
|
1674
1879
|
}
|
|
1675
1880
|
case "JSXSpreadChild": {
|
|
1676
1881
|
const id = doc.alloc.next();
|
|
1677
1882
|
const ref = internExpr(node.expression, true);
|
|
1678
1883
|
doc.nodes.set(id, createExpr(id, ref, { parent: parentId, span: spanOf(node) }));
|
|
1679
|
-
|
|
1884
|
+
out.push(id);
|
|
1885
|
+
for (const jsx of findNestedJsxRoots(node.expression)) {
|
|
1886
|
+
out.push(buildNestedRoot(jsx, parentId));
|
|
1887
|
+
}
|
|
1888
|
+
return;
|
|
1680
1889
|
}
|
|
1681
1890
|
case "JSXElement":
|
|
1682
|
-
|
|
1891
|
+
out.push(buildElement(node, parentId));
|
|
1892
|
+
return;
|
|
1683
1893
|
case "JSXFragment":
|
|
1684
|
-
|
|
1894
|
+
out.push(buildFragment(node, parentId));
|
|
1895
|
+
return;
|
|
1685
1896
|
default:
|
|
1686
|
-
return
|
|
1897
|
+
return;
|
|
1687
1898
|
}
|
|
1688
1899
|
};
|
|
1689
1900
|
const buildFragment = (node, parentId) => {
|
|
1690
1901
|
const id = doc.alloc.next();
|
|
1691
1902
|
const children = [];
|
|
1692
|
-
for (const c of node.children)
|
|
1693
|
-
const cid = buildChild(c, id);
|
|
1694
|
-
if (cid != null) children.push(cid);
|
|
1695
|
-
}
|
|
1903
|
+
for (const c of node.children) appendChild(c, id, children);
|
|
1696
1904
|
doc.nodes.set(id, createFragment(id, { children, parent: parentId, span: spanOf(node) }));
|
|
1697
1905
|
backref.set(id, {
|
|
1698
1906
|
nodeId: id,
|
|
@@ -1735,10 +1943,7 @@ function doParse(code, ctx) {
|
|
|
1735
1943
|
}
|
|
1736
1944
|
const attrs = { entries, spreads, order };
|
|
1737
1945
|
const children = [];
|
|
1738
|
-
for (const c of node.children)
|
|
1739
|
-
const cid = buildChild(c, id);
|
|
1740
|
-
if (cid != null) children.push(cid);
|
|
1741
|
-
}
|
|
1946
|
+
for (const c of node.children) appendChild(c, id, children);
|
|
1742
1947
|
for (const cid of children) {
|
|
1743
1948
|
const cn = doc.nodes.get(cid);
|
|
1744
1949
|
if (cn && cn.kind === "expr") {
|
|
@@ -1797,13 +2002,13 @@ function doParse(code, ctx) {
|
|
|
1797
2002
|
};
|
|
1798
2003
|
const roots = [];
|
|
1799
2004
|
traverse(ast, {
|
|
1800
|
-
JSXElement(
|
|
1801
|
-
roots.push(
|
|
1802
|
-
|
|
2005
|
+
JSXElement(path7) {
|
|
2006
|
+
roots.push(path7.node);
|
|
2007
|
+
path7.skip();
|
|
1803
2008
|
},
|
|
1804
|
-
JSXFragment(
|
|
1805
|
-
roots.push(
|
|
1806
|
-
|
|
2009
|
+
JSXFragment(path7) {
|
|
2010
|
+
roots.push(path7.node);
|
|
2011
|
+
path7.skip();
|
|
1807
2012
|
}
|
|
1808
2013
|
});
|
|
1809
2014
|
const rootFrag = doc.nodes.get(doc.root);
|
|
@@ -1813,6 +2018,8 @@ function doParse(code, ctx) {
|
|
|
1813
2018
|
}
|
|
1814
2019
|
return { doc, diagnostics };
|
|
1815
2020
|
}
|
|
2021
|
+
|
|
2022
|
+
// ../frontend-jsx/src/frontend.ts
|
|
1816
2023
|
var jsxFrontend = {
|
|
1817
2024
|
name: "babel-jsx",
|
|
1818
2025
|
langs: JSX_LANGS,
|
|
@@ -1899,6 +2106,61 @@ function editClasses(ms, doc, sf, el) {
|
|
|
1899
2106
|
ms.appendLeft(insertAt, ` className="${tokens.join(" ")}"`);
|
|
1900
2107
|
return true;
|
|
1901
2108
|
}
|
|
2109
|
+
function extractKeyAttr(openTag) {
|
|
2110
|
+
const m2 = /(^|\s)key\s*=\s*/.exec(openTag);
|
|
2111
|
+
if (!m2) return null;
|
|
2112
|
+
const keyStart = m2.index + m2[1].length;
|
|
2113
|
+
let i = m2.index + m2[0].length;
|
|
2114
|
+
const ch = openTag[i];
|
|
2115
|
+
if (ch === "{") {
|
|
2116
|
+
let depth = 0;
|
|
2117
|
+
for (; i < openTag.length; i += 1) {
|
|
2118
|
+
const c = openTag[i];
|
|
2119
|
+
if (c === "{") depth += 1;
|
|
2120
|
+
else if (c === "}") {
|
|
2121
|
+
depth -= 1;
|
|
2122
|
+
if (depth === 0) {
|
|
2123
|
+
i += 1;
|
|
2124
|
+
break;
|
|
2125
|
+
}
|
|
2126
|
+
}
|
|
2127
|
+
}
|
|
2128
|
+
} else if (ch === '"' || ch === "'") {
|
|
2129
|
+
const q2 = ch;
|
|
2130
|
+
i += 1;
|
|
2131
|
+
for (; i < openTag.length; i += 1) {
|
|
2132
|
+
if (openTag[i] === q2) {
|
|
2133
|
+
i += 1;
|
|
2134
|
+
break;
|
|
2135
|
+
}
|
|
2136
|
+
}
|
|
2137
|
+
} else {
|
|
2138
|
+
for (; i < openTag.length; i += 1) {
|
|
2139
|
+
if (/[\s>/]/.test(openTag[i])) break;
|
|
2140
|
+
}
|
|
2141
|
+
}
|
|
2142
|
+
return openTag.slice(keyStart, i);
|
|
2143
|
+
}
|
|
2144
|
+
function transferKeyOnUnwrap(ms, doc, sf, region, kept) {
|
|
2145
|
+
const open = region.openTagSpan;
|
|
2146
|
+
if (!open || open.file !== sf.id) return;
|
|
2147
|
+
const keyAttr = extractKeyAttr(sf.text.slice(open.start, open.end));
|
|
2148
|
+
if (!keyAttr) return;
|
|
2149
|
+
const inside = [];
|
|
2150
|
+
for (const n of kept) {
|
|
2151
|
+
if (n.kind !== "element" || !n.span || n.span.file !== sf.id) continue;
|
|
2152
|
+
if (strictlyContains(region.span, n.span)) inside.push(n);
|
|
2153
|
+
}
|
|
2154
|
+
const maximal = inside.filter(
|
|
2155
|
+
(n) => !inside.some((o2) => o2 !== n && o2.span && n.span && strictlyContains(o2.span, n.span))
|
|
2156
|
+
);
|
|
2157
|
+
if (maximal.length !== 1) return;
|
|
2158
|
+
const child = maximal[0];
|
|
2159
|
+
const childOpen = doc.backref.get(child.id)?.openTagSpan;
|
|
2160
|
+
if (!childOpen || childOpen.file !== sf.id) return;
|
|
2161
|
+
if (extractKeyAttr(sf.text.slice(childOpen.start, childOpen.end))) return;
|
|
2162
|
+
ms.appendLeft(childOpen.start + 1 + child.tag.length, ` ${keyAttr}`);
|
|
2163
|
+
}
|
|
1902
2164
|
function surgicalPrint(doc) {
|
|
1903
2165
|
const sf = primarySource(doc);
|
|
1904
2166
|
if (!sf) return null;
|
|
@@ -1920,6 +2182,7 @@ function surgicalPrint(doc) {
|
|
|
1920
2182
|
const coveredByFull = fullRemovals.some((f) => f !== span && strictlyContains(f, span));
|
|
1921
2183
|
if (coveredByFull) continue;
|
|
1922
2184
|
if (r2.unwrapped) {
|
|
2185
|
+
transferKeyOnUnwrap(ms, doc, sf, r2.backref, kept);
|
|
1923
2186
|
const open = r2.backref.openTagSpan;
|
|
1924
2187
|
const close = r2.backref.closeTagSpan;
|
|
1925
2188
|
if (open && open.file === sf.id && open.end > open.start) ms.remove(open.start, open.end);
|
|
@@ -2022,40 +2285,6 @@ function createJsxBackend() {
|
|
|
2022
2285
|
// ../pattern-kit/src/index.ts
|
|
2023
2286
|
init_cjs_shims();
|
|
2024
2287
|
|
|
2025
|
-
// ../pattern-kit/src/define.ts
|
|
2026
|
-
init_cjs_shims();
|
|
2027
|
-
var PHASES = /* @__PURE__ */ new Set(["flatten", "compress", "extract"]);
|
|
2028
|
-
var SAFETY_LEVELS = /* @__PURE__ */ new Set([0, 1, 2, 3]);
|
|
2029
|
-
function fail(name, why) {
|
|
2030
|
-
throw new Error(`definePattern(${name || "<anonymous>"}): ${why}`);
|
|
2031
|
-
}
|
|
2032
|
-
function definePattern(spec) {
|
|
2033
|
-
if (spec == null || typeof spec !== "object") {
|
|
2034
|
-
throw new Error("definePattern: spec must be an object");
|
|
2035
|
-
}
|
|
2036
|
-
const name = spec.name;
|
|
2037
|
-
if (typeof name !== "string" || name.length === 0) {
|
|
2038
|
-
fail(String(name), "name must be a non-empty string");
|
|
2039
|
-
}
|
|
2040
|
-
if (typeof spec.category !== "string" || !spec.category.includes("/")) {
|
|
2041
|
-
fail(name, `category must be a "<phase>/<slug>" string (got ${JSON.stringify(spec.category)})`);
|
|
2042
|
-
}
|
|
2043
|
-
const phase = spec.category.split("/", 1)[0];
|
|
2044
|
-
if (!PHASES.has(phase)) {
|
|
2045
|
-
fail(name, `category phase must be one of flatten|compress|extract (got "${phase}")`);
|
|
2046
|
-
}
|
|
2047
|
-
if (!SAFETY_LEVELS.has(spec.safety)) {
|
|
2048
|
-
fail(name, `safety must be 0|1|2|3 (got ${JSON.stringify(spec.safety)})`);
|
|
2049
|
-
}
|
|
2050
|
-
if (typeof spec.evaluate !== "function") {
|
|
2051
|
-
fail(name, "evaluate must be a function");
|
|
2052
|
-
}
|
|
2053
|
-
if (spec.priority !== void 0 && !Number.isFinite(spec.priority)) {
|
|
2054
|
-
fail(name, "priority must be a finite number when provided");
|
|
2055
|
-
}
|
|
2056
|
-
return Object.freeze({ ...spec });
|
|
2057
|
-
}
|
|
2058
|
-
|
|
2059
2288
|
// ../pattern-kit/src/combinators.ts
|
|
2060
2289
|
init_cjs_shims();
|
|
2061
2290
|
|
|
@@ -2402,6 +2631,11 @@ var hasRef = (node) => asElement(node)?.meta.hasRef ?? false;
|
|
|
2402
2631
|
var hasEventHandlers = (node) => asElement(node)?.meta.hasEventHandlers ?? false;
|
|
2403
2632
|
var hasDynamicChildren = (node) => asElement(node)?.meta.hasDynamicChildren ?? false;
|
|
2404
2633
|
var hasDynamicClasses = (node) => asElement(node)?.classes.hasDynamic ?? false;
|
|
2634
|
+
var opaque = (node, ctx) => {
|
|
2635
|
+
const el = asElement(node);
|
|
2636
|
+
if (!el) return false;
|
|
2637
|
+
return ctx.isOpaque(el);
|
|
2638
|
+
};
|
|
2405
2639
|
var targetedByCombinator = (node, ctx) => {
|
|
2406
2640
|
const el = asElement(node);
|
|
2407
2641
|
if (!el) return false;
|
|
@@ -2414,9 +2648,45 @@ init_cjs_shims();
|
|
|
2414
2648
|
|
|
2415
2649
|
// ../pattern-kit/src/pattern.ts
|
|
2416
2650
|
init_cjs_shims();
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2651
|
+
|
|
2652
|
+
// ../pattern-kit/src/define.ts
|
|
2653
|
+
init_cjs_shims();
|
|
2654
|
+
var PHASES = /* @__PURE__ */ new Set(["flatten", "compress", "extract"]);
|
|
2655
|
+
var SAFETY_LEVELS = /* @__PURE__ */ new Set([0, 1, 2, 3]);
|
|
2656
|
+
function fail(name, why) {
|
|
2657
|
+
throw new Error(`definePattern(${name || "<anonymous>"}): ${why}`);
|
|
2658
|
+
}
|
|
2659
|
+
function validatePattern(spec) {
|
|
2660
|
+
if (spec == null || typeof spec !== "object") {
|
|
2661
|
+
throw new Error("definePattern: spec must be an object");
|
|
2662
|
+
}
|
|
2663
|
+
const name = spec.name;
|
|
2664
|
+
if (typeof name !== "string" || name.length === 0) {
|
|
2665
|
+
fail(String(name), "name must be a non-empty string");
|
|
2666
|
+
}
|
|
2667
|
+
if (typeof spec.category !== "string" || !spec.category.includes("/")) {
|
|
2668
|
+
fail(name, `category must be a "<phase>/<slug>" string (got ${JSON.stringify(spec.category)})`);
|
|
2669
|
+
}
|
|
2670
|
+
const phase = spec.category.split("/", 1)[0];
|
|
2671
|
+
if (!PHASES.has(phase)) {
|
|
2672
|
+
fail(name, `category phase must be one of flatten|compress|extract (got "${phase}")`);
|
|
2673
|
+
}
|
|
2674
|
+
if (!SAFETY_LEVELS.has(spec.safety)) {
|
|
2675
|
+
fail(name, `safety must be 0|1|2|3 (got ${JSON.stringify(spec.safety)})`);
|
|
2676
|
+
}
|
|
2677
|
+
if (typeof spec.evaluate !== "function") {
|
|
2678
|
+
fail(name, "evaluate must be a function");
|
|
2679
|
+
}
|
|
2680
|
+
if (spec.priority !== void 0 && !Number.isFinite(spec.priority)) {
|
|
2681
|
+
fail(name, "priority must be a finite number when provided");
|
|
2682
|
+
}
|
|
2683
|
+
return Object.freeze({ ...spec });
|
|
2684
|
+
}
|
|
2685
|
+
|
|
2686
|
+
// ../pattern-kit/src/pattern.ts
|
|
2687
|
+
function camelToKebab(key) {
|
|
2688
|
+
if (key.startsWith("--")) return key;
|
|
2689
|
+
return key.replace(/[A-Z]/g, (m2) => `-${m2.toLowerCase()}`);
|
|
2420
2690
|
}
|
|
2421
2691
|
function plainToStyleMap(style) {
|
|
2422
2692
|
const decls = /* @__PURE__ */ new Map();
|
|
@@ -2450,8 +2720,20 @@ var FLATTEN_GUARDS = and(
|
|
|
2450
2720
|
not(targetedByCombinator),
|
|
2451
2721
|
not(affectsSelectorMatching)
|
|
2452
2722
|
);
|
|
2453
|
-
|
|
2454
|
-
|
|
2723
|
+
var COMPRESS_GUARDS = and(
|
|
2724
|
+
not(hasDynamicClasses),
|
|
2725
|
+
not(opaque),
|
|
2726
|
+
not(targetedByCombinator)
|
|
2727
|
+
);
|
|
2728
|
+
function autoGuardsFor(category) {
|
|
2729
|
+
switch (category.split("/", 1)[0]) {
|
|
2730
|
+
case "flatten":
|
|
2731
|
+
return FLATTEN_GUARDS;
|
|
2732
|
+
case "compress":
|
|
2733
|
+
return COMPRESS_GUARDS;
|
|
2734
|
+
default:
|
|
2735
|
+
return null;
|
|
2736
|
+
}
|
|
2455
2737
|
}
|
|
2456
2738
|
function compileDeclarativeMatch(m2) {
|
|
2457
2739
|
const parts = [isElement(m2.tag)];
|
|
@@ -2467,7 +2749,8 @@ function compileDeclarativeMatch(m2) {
|
|
|
2467
2749
|
function compileMatch(match, category) {
|
|
2468
2750
|
if (typeof match === "function") return match;
|
|
2469
2751
|
const declarative = compileDeclarativeMatch(match ?? {});
|
|
2470
|
-
const
|
|
2752
|
+
const guards = autoGuardsFor(category);
|
|
2753
|
+
const guarded = guards ? and(declarative, guards) : declarative;
|
|
2471
2754
|
return (node, ctx) => guarded(node, ctx);
|
|
2472
2755
|
}
|
|
2473
2756
|
function pruneShadowed(sm, drop) {
|
|
@@ -2524,7 +2807,7 @@ function compileRewrite(rewrite) {
|
|
|
2524
2807
|
const onConflict = rewrite.onConflict ?? "abort";
|
|
2525
2808
|
return (ctx, rw) => [rw.mergeStyle(ctx.node, null, style, onConflict)];
|
|
2526
2809
|
}
|
|
2527
|
-
function
|
|
2810
|
+
function definePattern(config) {
|
|
2528
2811
|
const matchFn = compileMatch(config.match, config.category);
|
|
2529
2812
|
const rewriteFn = compileRewrite(config.rewrite);
|
|
2530
2813
|
const spec = {
|
|
@@ -2534,7 +2817,7 @@ function pattern(config) {
|
|
|
2534
2817
|
priority: config.priority,
|
|
2535
2818
|
precondition: config.precondition,
|
|
2536
2819
|
doc: config.doc,
|
|
2537
|
-
|
|
2820
|
+
test: config.test,
|
|
2538
2821
|
evaluate(ctx, rw) {
|
|
2539
2822
|
if (!matchFn(ctx.node, ctx)) return null;
|
|
2540
2823
|
const ops = rewriteFn(ctx, rw);
|
|
@@ -2542,7 +2825,7 @@ function pattern(config) {
|
|
|
2542
2825
|
return { ops };
|
|
2543
2826
|
}
|
|
2544
2827
|
};
|
|
2545
|
-
return
|
|
2828
|
+
return validatePattern(spec);
|
|
2546
2829
|
}
|
|
2547
2830
|
|
|
2548
2831
|
// ../patterns/src/index.ts
|
|
@@ -2551,38 +2834,103 @@ init_cjs_shims();
|
|
|
2551
2834
|
// ../patterns/src/_registry.generated.ts
|
|
2552
2835
|
init_cjs_shims();
|
|
2553
2836
|
|
|
2554
|
-
// ../patterns/src/flatten/
|
|
2837
|
+
// ../patterns/src/library/flatten/display-contents-wrapper.pattern.ts
|
|
2555
2838
|
init_cjs_shims();
|
|
2556
2839
|
function asEl(node) {
|
|
2557
2840
|
const n = node;
|
|
2558
2841
|
return n.kind === "element" ? n : null;
|
|
2559
2842
|
}
|
|
2843
|
+
function metaOf(node) {
|
|
2844
|
+
return asEl(node)?.meta ?? null;
|
|
2845
|
+
}
|
|
2846
|
+
var declaresCustomProperties = (node) => metaOf(node)?.declaresCustomProperties ?? false;
|
|
2847
|
+
var hasSpreadAttrs = (node) => metaOf(node)?.hasSpreadAttrs ?? false;
|
|
2848
|
+
var isComponentNode = (node) => metaOf(node)?.isComponent ?? false;
|
|
2849
|
+
var hasOwnAttrs = (node) => {
|
|
2850
|
+
const el = asEl(node);
|
|
2851
|
+
if (!el) return false;
|
|
2852
|
+
return el.attrs.entries.size > 0 || el.attrs.spreads.length > 0;
|
|
2853
|
+
};
|
|
2854
|
+
var targetedByStructuralPseudo = (node, ctx) => {
|
|
2855
|
+
const el = asEl(node);
|
|
2856
|
+
if (!el) return false;
|
|
2857
|
+
if (el.meta.targetedByStructuralPseudo) return true;
|
|
2858
|
+
return ctx.selectors.targetedByStructuralPseudo(el.id);
|
|
2859
|
+
};
|
|
2860
|
+
var displayContentsWrapper = definePattern({
|
|
2861
|
+
name: "display-contents-wrapper",
|
|
2862
|
+
category: "flatten/display-contents-wrapper",
|
|
2863
|
+
safety: 2,
|
|
2864
|
+
doc: {
|
|
2865
|
+
title: "Flatten display:contents wrapper",
|
|
2866
|
+
summary: "A div with display:contents (which generates no box) wrapping a single element child, with no own visual style, no attributes beyond an inert class, and no opacity barriers, is removed; its sole child is hoisted in its place.",
|
|
2867
|
+
before: '<div style="display:contents"><Child/></div>',
|
|
2868
|
+
after: "<Child/>",
|
|
2869
|
+
safetyRationale: "A display:contents element generates no box at all, so its children already render as direct children of its parent; removing it is layout-identical. It paints nothing, establishes no formatting/stacking/box context, is no containing block, carries no ref/handlers/dynamic-children/html/spread/component identity, owns no targetable attrs / custom-property coupling, and is not a combinator/structural-pseudo subject; inheritable styles are folded onto the child before removal."
|
|
2870
|
+
},
|
|
2871
|
+
match: {
|
|
2872
|
+
tag: "div",
|
|
2873
|
+
style: { display: "contents" },
|
|
2874
|
+
onlyChild: "element",
|
|
2875
|
+
paintsNothing: true,
|
|
2876
|
+
where: [
|
|
2877
|
+
not(declaresCustomProperties),
|
|
2878
|
+
not(hasOwnAttrs),
|
|
2879
|
+
not(hasDynamicClasses),
|
|
2880
|
+
not(hasSpreadAttrs),
|
|
2881
|
+
not(isComponentNode),
|
|
2882
|
+
not(targetedByStructuralPseudo)
|
|
2883
|
+
]
|
|
2884
|
+
},
|
|
2885
|
+
rewrite: { flattenInto: "child" },
|
|
2886
|
+
test: {
|
|
2887
|
+
cases: [
|
|
2888
|
+
{
|
|
2889
|
+
// `display:contents` generates no box, so removing it is provably layout-identical → the
|
|
2890
|
+
// wrapper is flattened even under the conservative gate; the child is hoisted.
|
|
2891
|
+
before: '<div className="contents"><a className="text-blue-500">Link</a></div>',
|
|
2892
|
+
after: '<a className="text-blue-500">Link</a>'
|
|
2893
|
+
}
|
|
2894
|
+
],
|
|
2895
|
+
noMatch: [
|
|
2896
|
+
// A ref pins the wrapper's element identity (a hard opacity barrier) → not a passthrough.
|
|
2897
|
+
'<div className="contents" ref={rootRef}><a className="text-blue-500">Link</a></div>'
|
|
2898
|
+
]
|
|
2899
|
+
}
|
|
2900
|
+
});
|
|
2901
|
+
|
|
2902
|
+
// ../patterns/src/library/flatten/empty-style-div.pattern.ts
|
|
2903
|
+
init_cjs_shims();
|
|
2904
|
+
function asEl2(node) {
|
|
2905
|
+
const n = node;
|
|
2906
|
+
return n.kind === "element" ? n : null;
|
|
2907
|
+
}
|
|
2560
2908
|
function metaFlag2(flag) {
|
|
2561
|
-
return (node) => Boolean(
|
|
2909
|
+
return (node) => Boolean(asEl2(node)?.meta[flag]);
|
|
2562
2910
|
}
|
|
2563
2911
|
var establishesBox = metaFlag2("establishesBox");
|
|
2564
2912
|
var establishesFormattingContext = metaFlag2("establishesFormattingContext");
|
|
2565
2913
|
var establishesStackingContext = metaFlag2("establishesStackingContext");
|
|
2566
2914
|
var isContainingBlock = metaFlag2("isContainingBlock");
|
|
2567
|
-
var
|
|
2568
|
-
var
|
|
2569
|
-
const el =
|
|
2915
|
+
var declaresCustomProperties2 = metaFlag2("declaresCustomProperties");
|
|
2916
|
+
var targetedByStructuralPseudo2 = (node, ctx) => {
|
|
2917
|
+
const el = asEl2(node);
|
|
2570
2918
|
if (!el) return false;
|
|
2571
2919
|
if (el.meta.targetedByStructuralPseudo) return true;
|
|
2572
2920
|
return ctx.selectors.targetedByStructuralPseudo(el.id);
|
|
2573
2921
|
};
|
|
2574
|
-
var
|
|
2922
|
+
var DISPLAY2 = "display";
|
|
2575
2923
|
var hasNonBlockDisplay = (node, ctx) => {
|
|
2576
|
-
const el =
|
|
2924
|
+
const el = asEl2(node);
|
|
2577
2925
|
if (!el) return false;
|
|
2578
2926
|
const sm = ctx.computedOf(el) ?? el.computed;
|
|
2579
2927
|
for (const block of sm.blocks.values()) {
|
|
2580
|
-
const decl = block.decls.get(
|
|
2928
|
+
const decl = block.decls.get(DISPLAY2);
|
|
2581
2929
|
if (decl && String(decl.value) !== "block") return true;
|
|
2582
2930
|
}
|
|
2583
2931
|
return false;
|
|
2584
2932
|
};
|
|
2585
|
-
var emptyStyleDiv =
|
|
2933
|
+
var emptyStyleDiv = definePattern({
|
|
2586
2934
|
name: "empty-style-div",
|
|
2587
2935
|
category: "flatten/empty-style-div",
|
|
2588
2936
|
safety: 1,
|
|
@@ -2603,26 +2951,29 @@ var emptyStyleDiv = pattern({
|
|
|
2603
2951
|
not(establishesFormattingContext),
|
|
2604
2952
|
not(establishesStackingContext),
|
|
2605
2953
|
not(isContainingBlock),
|
|
2606
|
-
not(
|
|
2607
|
-
not(
|
|
2954
|
+
not(declaresCustomProperties2),
|
|
2955
|
+
not(targetedByStructuralPseudo2)
|
|
2608
2956
|
]
|
|
2609
2957
|
},
|
|
2610
2958
|
rewrite: { flattenInto: "child" },
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2959
|
+
test: {
|
|
2960
|
+
cases: [
|
|
2961
|
+
{
|
|
2962
|
+
// A layout-neutral, style-free block div is a provably-safe flatten → removed, child hoisted.
|
|
2963
|
+
before: '<div><span className="bg-red-200">Hi</span></div>',
|
|
2964
|
+
after: '<span className="bg-red-200">Hi</span>'
|
|
2965
|
+
}
|
|
2966
|
+
],
|
|
2967
|
+
noMatch: [
|
|
2617
2968
|
// The wrapper paints its own background (own visual style) → not layout-neutral, kept.
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2969
|
+
'<div className="bg-blue-500"><span className="bg-red-200">Hi</span></div>'
|
|
2970
|
+
]
|
|
2971
|
+
}
|
|
2621
2972
|
});
|
|
2622
2973
|
|
|
2623
|
-
// ../patterns/src/flatten/flex-center-wrapper.pattern.ts
|
|
2974
|
+
// ../patterns/src/library/flatten/flex-center-wrapper.pattern.ts
|
|
2624
2975
|
init_cjs_shims();
|
|
2625
|
-
var flexCenterWrapper =
|
|
2976
|
+
var flexCenterWrapper = definePattern({
|
|
2626
2977
|
name: "flex-center-wrapper",
|
|
2627
2978
|
category: "flatten/flex-center-wrapper",
|
|
2628
2979
|
safety: 2,
|
|
@@ -2643,21 +2994,65 @@ var flexCenterWrapper = pattern({
|
|
|
2643
2994
|
flattenInto: "child",
|
|
2644
2995
|
childGains: { placeSelf: "center" }
|
|
2645
2996
|
},
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
//
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2997
|
+
// Collapsing a flex-centering wrapper to `place-self:center` on the child only stays centered when
|
|
2998
|
+
// the child's NEW parent is flex/grid; moreover the wrapper's own `display:flex` establishes a
|
|
2999
|
+
// formatting context. Both make this a `needs-verification` flatten, which the conservative
|
|
3000
|
+
// production gate (`'provably-safe'`, used by the harness) intentionally REVERTS — so every case
|
|
3001
|
+
// here is a no-match: the wrapper is preserved. Op-level rewrite correctness (purity, id-preserving
|
|
3002
|
+
// unwrap, opacity-barrier safety) is still asserted by the invariant suite over every pattern.
|
|
3003
|
+
test: {
|
|
3004
|
+
noMatch: [
|
|
3005
|
+
// Even under a static flex/grid parent the centering flatten is not provably layout-neutral
|
|
3006
|
+
// (the wrapper itself establishes a flex formatting context) → left unchanged.
|
|
3007
|
+
'<div className="grid"><div className="flex items-center justify-center"><span className="bg-red-200">x</span></div></div>',
|
|
3008
|
+
// Non-flex/grid parent (document root): place-self centering would not hold → left unchanged.
|
|
3009
|
+
'<div className="flex justify-center items-center"><div className="bg-red-200">Hello</div></div>',
|
|
3010
|
+
// onClick is a hard opacity barrier → the wrapper is load-bearing regardless of the gate.
|
|
3011
|
+
'<div className="flex justify-center items-center" onClick={handleClick}><div className="bg-red-200">Hello</div></div>'
|
|
3012
|
+
]
|
|
3013
|
+
}
|
|
3014
|
+
});
|
|
3015
|
+
|
|
3016
|
+
// ../patterns/src/library/flatten/inline-flex-center-wrapper.pattern.ts
|
|
3017
|
+
init_cjs_shims();
|
|
3018
|
+
var inlineFlexCenterWrapper = definePattern({
|
|
3019
|
+
name: "inline-flex-center-wrapper",
|
|
3020
|
+
category: "flatten/inline-flex-center-wrapper",
|
|
3021
|
+
safety: 2,
|
|
3022
|
+
doc: {
|
|
3023
|
+
title: "Flatten inline-flex-centering wrapper",
|
|
3024
|
+
summary: "A div that only centers a single child (display:inline-flex; align-items:center; justify-content:center) is removed; the child gains place-self:center.",
|
|
3025
|
+
before: '<div style="display:inline-flex;align-items:center;justify-content:center"><Child/></div>',
|
|
3026
|
+
after: '<Child style="place-self:center"/>',
|
|
3027
|
+
safetyRationale: "Wrapper paints nothing, carries no ref/handlers/dynamic children, and is not a combinator subject; inheritable styles are folded onto the child before removal."
|
|
3028
|
+
},
|
|
3029
|
+
match: {
|
|
3030
|
+
tag: "div",
|
|
3031
|
+
style: { display: "inline-flex", alignItems: "center", justifyContent: "center" },
|
|
3032
|
+
onlyChild: "element",
|
|
3033
|
+
paintsNothing: true
|
|
3034
|
+
},
|
|
3035
|
+
rewrite: {
|
|
3036
|
+
flattenInto: "child",
|
|
3037
|
+
childGains: { placeSelf: "center" }
|
|
3038
|
+
},
|
|
3039
|
+
// Like its block-level sibling, this centering flatten is `needs-verification` (the wrapper's own
|
|
3040
|
+
// `display:inline-flex` establishes a formatting context, and place-self centering only holds under
|
|
3041
|
+
// a flex/grid parent), so the conservative production gate (`'provably-safe'`) REVERTS it — every
|
|
3042
|
+
// case here is a no-match. Op-level correctness is covered by the invariant suite.
|
|
3043
|
+
test: {
|
|
3044
|
+
noMatch: [
|
|
3045
|
+
// Even under a static flex/grid parent the centering flatten is not provably layout-neutral.
|
|
3046
|
+
'<div className="grid"><div className="inline-flex items-center justify-center"><span className="bg-red-200">x</span></div></div>',
|
|
3047
|
+
// Non-flex/grid parent (document root) → left unchanged.
|
|
3048
|
+
'<div className="inline-flex justify-center items-center"><div className="bg-red-200">Hello</div></div>',
|
|
3049
|
+
// onClick is a hard opacity barrier → the wrapper is load-bearing regardless of the gate.
|
|
3050
|
+
'<div className="inline-flex justify-center items-center" onClick={handleClick}><div className="bg-red-200">Hello</div></div>'
|
|
3051
|
+
]
|
|
3052
|
+
}
|
|
2658
3053
|
});
|
|
2659
3054
|
|
|
2660
|
-
// ../patterns/src/flatten/nested-flex-merge.pattern.ts
|
|
3055
|
+
// ../patterns/src/library/flatten/nested-flex-merge.pattern.ts
|
|
2661
3056
|
init_cjs_shims();
|
|
2662
3057
|
function baseConditionStyleMap(decls) {
|
|
2663
3058
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -2724,7 +3119,7 @@ var isInnerFlex = and(
|
|
|
2724
3119
|
computed(DISPLAY_FLEX),
|
|
2725
3120
|
not(targetedByCombinator)
|
|
2726
3121
|
);
|
|
2727
|
-
var nestedFlexMerge =
|
|
3122
|
+
var nestedFlexMerge = definePattern({
|
|
2728
3123
|
name: "nested-flex-merge",
|
|
2729
3124
|
category: "flatten/nested-flex-merge",
|
|
2730
3125
|
safety: 2,
|
|
@@ -2760,24 +3155,148 @@ var nestedFlexMerge = pattern({
|
|
|
2760
3155
|
rw.unwrap(outer)
|
|
2761
3156
|
];
|
|
2762
3157
|
},
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
3158
|
+
// Merging the outer flex container into the inner removes the outer's box, but a `display:flex`
|
|
3159
|
+
// wrapper establishes a formatting context, so this is a `needs-verification` flatten that the
|
|
3160
|
+
// conservative production gate (`'provably-safe'`) REVERTS — every case here is a no-match. The
|
|
3161
|
+
// merge's op-level correctness (purity, id-preserving unwrap, opacity-barrier safety) is asserted
|
|
3162
|
+
// by the invariant suite over every pattern.
|
|
3163
|
+
test: {
|
|
3164
|
+
noMatch: [
|
|
3165
|
+
// The merge is real but not provably layout-neutral (the wrapper establishes a flex context),
|
|
3166
|
+
// so under the conservative gate the nested containers are left in place.
|
|
3167
|
+
'<div className="flex items-center gap-2" data-x="1"><div className="flex flex-col">X</div></div>',
|
|
3168
|
+
// A non-flex wrapper does not match the flex-container signature → left unchanged anyway.
|
|
3169
|
+
'<div className="block bg-blue-500"><div className="flex flex-col">X</div></div>'
|
|
3170
|
+
]
|
|
3171
|
+
}
|
|
3172
|
+
});
|
|
3173
|
+
|
|
3174
|
+
// ../patterns/src/library/flatten/nested-grid-merge.pattern.ts
|
|
3175
|
+
init_cjs_shims();
|
|
3176
|
+
function baseConditionStyleMap2(decls) {
|
|
3177
|
+
const map = /* @__PURE__ */ new Map();
|
|
3178
|
+
for (const [prop, value] of decls) {
|
|
3179
|
+
for (const decl of normalizer.normalizeDeclaration(prop, value, false)) {
|
|
3180
|
+
map.set(decl.property, decl);
|
|
2774
3181
|
}
|
|
2775
|
-
|
|
3182
|
+
}
|
|
3183
|
+
const block = { condition: BASE_CONDITION, decls: map };
|
|
3184
|
+
const blocks = /* @__PURE__ */ new Map([[conditionKey(BASE_CONDITION), block]]);
|
|
3185
|
+
return { blocks };
|
|
3186
|
+
}
|
|
3187
|
+
var DISPLAY_GRID = baseConditionStyleMap2([["display", "grid"]]);
|
|
3188
|
+
var GRID_CONTAINER_PROPERTIES = /* @__PURE__ */ new Set([
|
|
3189
|
+
"display",
|
|
3190
|
+
"grid-template-columns",
|
|
3191
|
+
"grid-template-rows",
|
|
3192
|
+
"grid-template-areas",
|
|
3193
|
+
"grid-auto-columns",
|
|
3194
|
+
"grid-auto-rows",
|
|
3195
|
+
"grid-auto-flow",
|
|
3196
|
+
"justify-content",
|
|
3197
|
+
"align-content",
|
|
3198
|
+
"place-content",
|
|
3199
|
+
"justify-items",
|
|
3200
|
+
"align-items",
|
|
3201
|
+
"place-items",
|
|
3202
|
+
"row-gap",
|
|
3203
|
+
"column-gap"
|
|
3204
|
+
]);
|
|
3205
|
+
function outerMergeSafe2(sm) {
|
|
3206
|
+
const norm = normalizer.normalizeStyleMap(sm);
|
|
3207
|
+
for (const block of norm.blocks.values()) {
|
|
3208
|
+
for (const decl of block.decls.values()) {
|
|
3209
|
+
if (GRID_CONTAINER_PROPERTIES.has(String(decl.property))) continue;
|
|
3210
|
+
if (decl.inherited) continue;
|
|
3211
|
+
return false;
|
|
3212
|
+
}
|
|
3213
|
+
}
|
|
3214
|
+
return true;
|
|
3215
|
+
}
|
|
3216
|
+
function gridConflict(outer, inner) {
|
|
3217
|
+
const a = normalizer.normalizeStyleMap(outer);
|
|
3218
|
+
const b3 = normalizer.normalizeStyleMap(inner);
|
|
3219
|
+
for (const [key, blockA] of a.blocks) {
|
|
3220
|
+
const blockB = b3.blocks.get(key);
|
|
3221
|
+
if (!blockB) continue;
|
|
3222
|
+
for (const [prop, declA] of blockA.decls) {
|
|
3223
|
+
if (!GRID_CONTAINER_PROPERTIES.has(String(prop))) continue;
|
|
3224
|
+
const declB = blockB.decls.get(prop);
|
|
3225
|
+
if (declB && declB.value !== declA.value) return true;
|
|
3226
|
+
}
|
|
3227
|
+
}
|
|
3228
|
+
return false;
|
|
3229
|
+
}
|
|
3230
|
+
function extractGridStyle(sm) {
|
|
3231
|
+
const blocks = /* @__PURE__ */ new Map();
|
|
3232
|
+
for (const [key, block] of sm.blocks) {
|
|
3233
|
+
const decls = /* @__PURE__ */ new Map();
|
|
3234
|
+
for (const [prop, decl] of block.decls) {
|
|
3235
|
+
if (GRID_CONTAINER_PROPERTIES.has(String(prop))) decls.set(prop, decl);
|
|
3236
|
+
}
|
|
3237
|
+
if (decls.size > 0) blocks.set(key, { condition: block.condition, decls });
|
|
3238
|
+
}
|
|
3239
|
+
return { blocks };
|
|
3240
|
+
}
|
|
3241
|
+
var isInnerGrid = and(
|
|
3242
|
+
isElement("div"),
|
|
3243
|
+
computed(DISPLAY_GRID),
|
|
3244
|
+
not(targetedByCombinator)
|
|
3245
|
+
);
|
|
3246
|
+
var nestedGridMerge = definePattern({
|
|
3247
|
+
name: "nested-grid-merge",
|
|
3248
|
+
category: "flatten/nested-grid-merge",
|
|
3249
|
+
safety: 2,
|
|
3250
|
+
doc: {
|
|
3251
|
+
title: "Merge nested grid containers",
|
|
3252
|
+
summary: "A grid container whose only child is itself a grid container with non-conflicting grid properties is collapsed into one; the wrapper is removed and its grid declarations merge onto the surviving child.",
|
|
3253
|
+
before: '<div style="display:grid;gap:8px"><div style="display:grid;grid-template-columns:1fr 1fr"/></div>',
|
|
3254
|
+
after: '<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px"/>',
|
|
3255
|
+
safetyRationale: "The wrapper paints nothing, declares only grid-container/inheritable properties, carries no ref/handlers/dynamic children, and is not a combinator subject; the two containers do not conflict on any grid property, so the union is unambiguous and lossless."
|
|
3256
|
+
},
|
|
3257
|
+
match: {
|
|
3258
|
+
tag: "div",
|
|
3259
|
+
style: { display: "grid" },
|
|
3260
|
+
onlyChild: "element",
|
|
3261
|
+
paintsNothing: true
|
|
3262
|
+
},
|
|
3263
|
+
rewrite: (ctx, rw) => {
|
|
3264
|
+
const outer = ctx.node;
|
|
3265
|
+
const inner = ctx.onlyElementChild();
|
|
3266
|
+
if (!inner) return null;
|
|
3267
|
+
if (!isInnerGrid(inner, ctx)) return null;
|
|
3268
|
+
const outerStyle = ctx.computed();
|
|
3269
|
+
const innerStyle = ctx.computedOf(inner);
|
|
3270
|
+
if (!outerMergeSafe2(outerStyle)) return null;
|
|
3271
|
+
if (gridConflict(outerStyle, innerStyle)) return null;
|
|
3272
|
+
return [
|
|
3273
|
+
// 1. Preserve inheritable values (color/font/…) by folding them onto the child first.
|
|
3274
|
+
rw.foldInheritedStyles(outer, inner, { conditions: "all" }),
|
|
3275
|
+
// 2. Transfer the wrapper's grid-container declarations onto the child (target-wins keeps the
|
|
3276
|
+
// child's value for any shared property — identical anyway, we proved non-conflict).
|
|
3277
|
+
rw.mergeStyle(inner, null, extractGridStyle(outerStyle), "target-wins"),
|
|
3278
|
+
// 3. Remove the wrapper (structural-safe; hoists the child and preserves its IRNodeId).
|
|
3279
|
+
rw.unwrap(outer)
|
|
3280
|
+
];
|
|
3281
|
+
},
|
|
3282
|
+
// Like its flex sibling, this merge removes the outer container's box, but a `display:grid` wrapper
|
|
3283
|
+
// establishes a formatting context, so it is a `needs-verification` flatten that the conservative
|
|
3284
|
+
// production gate (`'provably-safe'`) REVERTS — every case here is a no-match. Op-level correctness
|
|
3285
|
+
// is asserted by the invariant suite over every pattern.
|
|
3286
|
+
test: {
|
|
3287
|
+
noMatch: [
|
|
3288
|
+
// The merge is real but not provably layout-neutral (the wrapper establishes a grid context),
|
|
3289
|
+
// so under the conservative gate the nested containers are left in place.
|
|
3290
|
+
'<div className="grid gap-2" data-x="1"><div className="grid grid-cols-2">X</div></div>',
|
|
3291
|
+
// A non-grid wrapper does not match the grid-container signature → left unchanged anyway.
|
|
3292
|
+
'<div className="block bg-blue-500"><div className="grid grid-cols-2">X</div></div>'
|
|
3293
|
+
]
|
|
3294
|
+
}
|
|
2776
3295
|
});
|
|
2777
3296
|
|
|
2778
|
-
// ../patterns/src/flatten/passthrough-wrapper.pattern.ts
|
|
3297
|
+
// ../patterns/src/library/flatten/passthrough-wrapper.pattern.ts
|
|
2779
3298
|
init_cjs_shims();
|
|
2780
|
-
function
|
|
3299
|
+
function metaOf2(node) {
|
|
2781
3300
|
const n = node;
|
|
2782
3301
|
return n.kind === "element" ? n.meta : null;
|
|
2783
3302
|
}
|
|
@@ -2786,24 +3305,24 @@ function elementOf(node) {
|
|
|
2786
3305
|
return n.kind === "element" ? n : null;
|
|
2787
3306
|
}
|
|
2788
3307
|
var establishesContext = (node) => {
|
|
2789
|
-
const m2 =
|
|
3308
|
+
const m2 = metaOf2(node);
|
|
2790
3309
|
if (!m2) return false;
|
|
2791
3310
|
return m2.establishesBox || m2.establishesFormattingContext || m2.establishesStackingContext || m2.isContainingBlock || m2.declaresCustomProperties;
|
|
2792
3311
|
};
|
|
2793
|
-
var
|
|
2794
|
-
var
|
|
2795
|
-
var
|
|
3312
|
+
var hasSpreadAttrs2 = (node) => metaOf2(node)?.hasSpreadAttrs ?? false;
|
|
3313
|
+
var isComponentNode2 = (node) => metaOf2(node)?.isComponent ?? false;
|
|
3314
|
+
var hasOwnAttrs2 = (node) => {
|
|
2796
3315
|
const el = elementOf(node);
|
|
2797
3316
|
if (!el) return false;
|
|
2798
3317
|
return el.attrs.entries.size > 0 || el.attrs.spreads.length > 0;
|
|
2799
3318
|
};
|
|
2800
|
-
var
|
|
3319
|
+
var targetedByStructuralPseudo3 = (node, ctx) => {
|
|
2801
3320
|
const el = elementOf(node);
|
|
2802
3321
|
if (!el) return false;
|
|
2803
3322
|
if (el.meta.targetedByStructuralPseudo) return true;
|
|
2804
3323
|
return ctx.selectors.targetedByStructuralPseudo(el.id);
|
|
2805
3324
|
};
|
|
2806
|
-
var passthroughWrapper =
|
|
3325
|
+
var passthroughWrapper = definePattern({
|
|
2807
3326
|
name: "passthrough-wrapper",
|
|
2808
3327
|
category: "flatten/passthrough-wrapper",
|
|
2809
3328
|
safety: 2,
|
|
@@ -2820,27 +3339,34 @@ var passthroughWrapper = pattern({
|
|
|
2820
3339
|
paintsNothing: true,
|
|
2821
3340
|
where: [
|
|
2822
3341
|
not(establishesContext),
|
|
2823
|
-
not(
|
|
3342
|
+
not(hasOwnAttrs2),
|
|
2824
3343
|
not(hasDynamicClasses),
|
|
2825
|
-
not(
|
|
2826
|
-
not(
|
|
2827
|
-
not(
|
|
3344
|
+
not(hasSpreadAttrs2),
|
|
3345
|
+
not(isComponentNode2),
|
|
3346
|
+
not(targetedByStructuralPseudo3)
|
|
2828
3347
|
]
|
|
2829
3348
|
},
|
|
2830
3349
|
rewrite: { flattenInto: "child" },
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
3350
|
+
test: {
|
|
3351
|
+
cases: [
|
|
3352
|
+
{
|
|
3353
|
+
// A plain, style-free wrapper paints nothing and establishes no context → a provably-safe
|
|
3354
|
+
// flatten under the conservative gate: the wrapper is removed and its sole child hoisted.
|
|
3355
|
+
before: '<div><a className="bg-red-200">Link</a></div>',
|
|
3356
|
+
after: '<a className="bg-red-200">Link</a>'
|
|
3357
|
+
}
|
|
3358
|
+
],
|
|
3359
|
+
noMatch: [
|
|
2837
3360
|
// A ref pins the wrapper's element identity (a hard opacity barrier) → not a passthrough.
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
3361
|
+
'<div ref={rootRef}><a className="bg-red-200">Link</a></div>',
|
|
3362
|
+
// A `display:flex` wrapper establishes a formatting context, so removing its box is NOT
|
|
3363
|
+
// provably layout-neutral → the conservative gate leaves it in place.
|
|
3364
|
+
'<div className="flex"><a className="bg-red-200">Link</a></div>'
|
|
3365
|
+
]
|
|
3366
|
+
}
|
|
2841
3367
|
});
|
|
2842
3368
|
|
|
2843
|
-
// ../patterns/src/flatten/redundant-fragment.pattern.ts
|
|
3369
|
+
// ../patterns/src/library/flatten/redundant-fragment.pattern.ts
|
|
2844
3370
|
init_cjs_shims();
|
|
2845
3371
|
function parentIsRedundantFragment(node, ctx) {
|
|
2846
3372
|
const el = node;
|
|
@@ -2863,7 +3389,7 @@ function parentIsRedundantFragment(node, ctx) {
|
|
|
2863
3389
|
if (ctx.selectors.reparentImpact(fid).size > 0) return false;
|
|
2864
3390
|
return true;
|
|
2865
3391
|
}
|
|
2866
|
-
var redundantFragment =
|
|
3392
|
+
var redundantFragment = definePattern({
|
|
2867
3393
|
name: "redundant-fragment",
|
|
2868
3394
|
category: "flatten/redundant-fragment",
|
|
2869
3395
|
safety: 1,
|
|
@@ -2882,61 +3408,314 @@ var redundantFragment = pattern({
|
|
|
2882
3408
|
if (!fragment || fragment.kind !== "fragment") return null;
|
|
2883
3409
|
return [rw.unwrap(fragment)];
|
|
2884
3410
|
},
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
3411
|
+
test: {
|
|
3412
|
+
cases: [
|
|
3413
|
+
{
|
|
3414
|
+
// A fragment renders no box, so unwrapping a single-child fragment is always layout-identical
|
|
3415
|
+
// → a provably-safe flatten: the child is spliced up into the fragment's slot.
|
|
3416
|
+
before: '<><span className="bg-red-200">Hi</span></>',
|
|
3417
|
+
after: '<span className="bg-red-200">Hi</span>'
|
|
3418
|
+
}
|
|
3419
|
+
],
|
|
3420
|
+
noMatch: [
|
|
2891
3421
|
// Two children ⇒ not a single-child fragment, so the fragment is load-bearing and stays.
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
3422
|
+
'<><span className="bg-red-200">A</span><span className="bg-green-200">B</span></>'
|
|
3423
|
+
]
|
|
3424
|
+
}
|
|
2895
3425
|
});
|
|
2896
3426
|
|
|
2897
|
-
// ../patterns/src/
|
|
3427
|
+
// ../patterns/src/library/flatten/redundant-inline-wrapper.pattern.ts
|
|
2898
3428
|
init_cjs_shims();
|
|
2899
|
-
function
|
|
3429
|
+
function asEl3(node) {
|
|
2900
3430
|
const n = node;
|
|
2901
3431
|
return n.kind === "element" ? n : null;
|
|
2902
3432
|
}
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
function findRedundantClasses(computed2) {
|
|
2906
|
-
const winners = /* @__PURE__ */ new Set();
|
|
2907
|
-
const shadowed = /* @__PURE__ */ new Set();
|
|
2908
|
-
for (const block of computed2.blocks.values()) {
|
|
2909
|
-
for (const decl of block.decls.values()) {
|
|
2910
|
-
if (decl.origin && decl.origin.kind === "class") winners.add(decl.origin.className);
|
|
2911
|
-
for (const o2 of decl.shadowed ?? []) {
|
|
2912
|
-
if (o2.kind === "class") shadowed.add(o2.className);
|
|
2913
|
-
}
|
|
2914
|
-
}
|
|
2915
|
-
}
|
|
2916
|
-
return { winners, shadowed };
|
|
3433
|
+
function metaOf3(node) {
|
|
3434
|
+
return asEl3(node)?.meta ?? null;
|
|
2917
3435
|
}
|
|
2918
|
-
var
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
3436
|
+
var establishesContext2 = (node) => {
|
|
3437
|
+
const m2 = metaOf3(node);
|
|
3438
|
+
if (!m2) return false;
|
|
3439
|
+
return m2.establishesBox || m2.establishesFormattingContext || m2.establishesStackingContext || m2.isContainingBlock || m2.declaresCustomProperties;
|
|
3440
|
+
};
|
|
3441
|
+
var hasSpreadAttrs3 = (node) => metaOf3(node)?.hasSpreadAttrs ?? false;
|
|
3442
|
+
var isComponentNode3 = (node) => metaOf3(node)?.isComponent ?? false;
|
|
3443
|
+
var hasOwnAttrs3 = (node) => {
|
|
3444
|
+
const el = asEl3(node);
|
|
3445
|
+
if (!el) return false;
|
|
3446
|
+
return el.attrs.entries.size > 0 || el.attrs.spreads.length > 0;
|
|
3447
|
+
};
|
|
3448
|
+
var targetedByStructuralPseudo4 = (node, ctx) => {
|
|
3449
|
+
const el = asEl3(node);
|
|
3450
|
+
if (!el) return false;
|
|
3451
|
+
if (el.meta.targetedByStructuralPseudo) return true;
|
|
3452
|
+
return ctx.selectors.targetedByStructuralPseudo(el.id);
|
|
3453
|
+
};
|
|
3454
|
+
var DISPLAY3 = "display";
|
|
3455
|
+
var hasNonInlineDisplay = (node, ctx) => {
|
|
3456
|
+
const el = asEl3(node);
|
|
3457
|
+
if (!el) return false;
|
|
3458
|
+
const sm = ctx.computedOf(el) ?? el.computed;
|
|
3459
|
+
for (const block of sm.blocks.values()) {
|
|
3460
|
+
const decl = block.decls.get(DISPLAY3);
|
|
3461
|
+
if (decl && String(decl.value) !== "inline") return true;
|
|
3462
|
+
}
|
|
3463
|
+
return false;
|
|
3464
|
+
};
|
|
3465
|
+
var redundantInlineWrapper = definePattern({
|
|
3466
|
+
name: "redundant-inline-wrapper",
|
|
3467
|
+
category: "flatten/redundant-inline-wrapper",
|
|
3468
|
+
safety: 2,
|
|
2922
3469
|
doc: {
|
|
2923
|
-
title: "
|
|
2924
|
-
summary: "
|
|
2925
|
-
before:
|
|
2926
|
-
after:
|
|
2927
|
-
safetyRationale: "
|
|
3470
|
+
title: "Flatten redundant inline wrapper",
|
|
3471
|
+
summary: "An inline span with no own visual/box style, no attributes beyond an inert class, exactly one element child, and no opacity barriers is removed; its sole child is hoisted in its place.",
|
|
3472
|
+
before: "<span><Child/></span>",
|
|
3473
|
+
after: "<Child/>",
|
|
3474
|
+
safetyRationale: "An empty inline box paints nothing and establishes no layout/paint/var context; with the inline default display and a single element child its removal changes no paint and no flow. The span carries no ref/handlers/dynamic-children/html/spread/component identity, owns no targetable attrs, and is not a combinator/structural-pseudo subject; inheritable styles are folded onto the child before removal."
|
|
2928
3475
|
},
|
|
2929
3476
|
match: {
|
|
3477
|
+
tag: "span",
|
|
3478
|
+
onlyChild: "element",
|
|
3479
|
+
paintsNothing: true,
|
|
2930
3480
|
where: [
|
|
2931
|
-
not(
|
|
2932
|
-
not(
|
|
2933
|
-
not(
|
|
2934
|
-
not(hasDangerousHtml),
|
|
3481
|
+
not(hasNonInlineDisplay),
|
|
3482
|
+
not(establishesContext2),
|
|
3483
|
+
not(hasOwnAttrs3),
|
|
2935
3484
|
not(hasDynamicClasses),
|
|
2936
|
-
not(
|
|
2937
|
-
not(
|
|
3485
|
+
not(hasSpreadAttrs3),
|
|
3486
|
+
not(isComponentNode3),
|
|
3487
|
+
not(targetedByStructuralPseudo4)
|
|
2938
3488
|
]
|
|
2939
3489
|
},
|
|
3490
|
+
rewrite: { flattenInto: "child" },
|
|
3491
|
+
test: {
|
|
3492
|
+
cases: [
|
|
3493
|
+
{
|
|
3494
|
+
// An empty inline span paints nothing and establishes no context → a provably-safe flatten:
|
|
3495
|
+
// the span is removed and its sole child hoisted in place.
|
|
3496
|
+
before: '<span><a className="text-blue-500">Link</a></span>',
|
|
3497
|
+
after: '<a className="text-blue-500">Link</a>'
|
|
3498
|
+
}
|
|
3499
|
+
],
|
|
3500
|
+
noMatch: [
|
|
3501
|
+
// A ref pins the span's element identity (a hard opacity barrier) → not a passthrough.
|
|
3502
|
+
'<span ref={spanRef}><a className="text-blue-500">Link</a></span>',
|
|
3503
|
+
// The span paints its own background (own visual style) → kept.
|
|
3504
|
+
'<span className="bg-green-200"><a className="text-blue-500">Link</a></span>',
|
|
3505
|
+
// Non-inline display (inline-block) participates in layout differently → kept.
|
|
3506
|
+
'<span className="inline-block"><a className="text-blue-500">Link</a></span>'
|
|
3507
|
+
]
|
|
3508
|
+
}
|
|
3509
|
+
});
|
|
3510
|
+
|
|
3511
|
+
// ../patterns/src/library/compress/border-radius-shorthand.pattern.ts
|
|
3512
|
+
init_cjs_shims();
|
|
3513
|
+
var CORNERS = [
|
|
3514
|
+
"border-top-left-radius",
|
|
3515
|
+
"border-top-right-radius",
|
|
3516
|
+
"border-bottom-right-radius",
|
|
3517
|
+
"border-bottom-left-radius"
|
|
3518
|
+
];
|
|
3519
|
+
var CORNER_SET = new Set(CORNERS);
|
|
3520
|
+
var BASE_KEY = conditionKey(BASE_CONDITION);
|
|
3521
|
+
var RADIUS = "border-radius";
|
|
3522
|
+
var NON_COLLAPSIBLE_VALUES = /* @__PURE__ */ new Set([
|
|
3523
|
+
"initial",
|
|
3524
|
+
"inherit",
|
|
3525
|
+
"unset",
|
|
3526
|
+
"revert",
|
|
3527
|
+
"revert-layer"
|
|
3528
|
+
]);
|
|
3529
|
+
function analyzeRadius(sm) {
|
|
3530
|
+
const block = sm.blocks.get(BASE_KEY);
|
|
3531
|
+
if (!block) return null;
|
|
3532
|
+
const corners = [];
|
|
3533
|
+
for (const corner of CORNERS) {
|
|
3534
|
+
const decl = block.decls.get(corner);
|
|
3535
|
+
if (!decl) return null;
|
|
3536
|
+
corners.push(decl);
|
|
3537
|
+
}
|
|
3538
|
+
const important = corners[0].important;
|
|
3539
|
+
if (!corners.every((d3) => d3.important === important)) return null;
|
|
3540
|
+
const value = String(corners[0].value);
|
|
3541
|
+
if (NON_COLLAPSIBLE_VALUES.has(value)) return null;
|
|
3542
|
+
if (!corners.every((d3) => String(d3.value) === value)) return null;
|
|
3543
|
+
const relative4 = corners.some((d3) => d3.relativeToParent);
|
|
3544
|
+
return { value, important, relative: relative4 };
|
|
3545
|
+
}
|
|
3546
|
+
function withFoldedRadius(sm, fold) {
|
|
3547
|
+
const blocks = /* @__PURE__ */ new Map();
|
|
3548
|
+
for (const [key, block] of sm.blocks) {
|
|
3549
|
+
if (key !== BASE_KEY) {
|
|
3550
|
+
blocks.set(key, block);
|
|
3551
|
+
continue;
|
|
3552
|
+
}
|
|
3553
|
+
const decls = /* @__PURE__ */ new Map();
|
|
3554
|
+
for (const [prop, decl] of block.decls) {
|
|
3555
|
+
if (CORNER_SET.has(String(prop))) continue;
|
|
3556
|
+
decls.set(prop, decl);
|
|
3557
|
+
}
|
|
3558
|
+
const shorthand = {
|
|
3559
|
+
property: RADIUS,
|
|
3560
|
+
value: fold.value,
|
|
3561
|
+
important: fold.important,
|
|
3562
|
+
relativeToParent: fold.relative,
|
|
3563
|
+
inherited: false
|
|
3564
|
+
// border-radius is never inherited
|
|
3565
|
+
};
|
|
3566
|
+
decls.set(shorthand.property, shorthand);
|
|
3567
|
+
blocks.set(key, { condition: block.condition, decls });
|
|
3568
|
+
}
|
|
3569
|
+
return { blocks };
|
|
3570
|
+
}
|
|
3571
|
+
var borderRadiusShorthand = definePattern({
|
|
3572
|
+
name: "border-radius-shorthand",
|
|
3573
|
+
category: "compress/border-radius-shorthand",
|
|
3574
|
+
safety: 1,
|
|
3575
|
+
doc: {
|
|
3576
|
+
title: "Collapse equal corner radii into border-radius",
|
|
3577
|
+
summary: "An element whose four corner radii (border-*-radius longhands) are all equal is rewritten to the single Tailwind rounded-* utility (border-radius === the four equal corners).",
|
|
3578
|
+
before: '<div class="rounded-tl-lg rounded-tr-lg rounded-br-lg rounded-bl-lg"/>',
|
|
3579
|
+
after: '<div class="rounded-lg"/>',
|
|
3580
|
+
safetyRationale: "`border-radius` is value-identical to four equal corner radii \u2014 a class-only change. It is safe even on an element with a ref, event handler, dynamic child, or dangerouslySetInnerHTML \u2014 a className rewrite touches none of them; only a dynamic/opaque class list or a combinator-subject class is excluded, so no behaviour or project selector is disturbed."
|
|
3581
|
+
},
|
|
3582
|
+
rewrite: {
|
|
3583
|
+
rewriteClasses(computed2) {
|
|
3584
|
+
const fold = analyzeRadius(computed2);
|
|
3585
|
+
return fold ? withFoldedRadius(computed2, fold) : null;
|
|
3586
|
+
}
|
|
3587
|
+
},
|
|
3588
|
+
test: {
|
|
3589
|
+
cases: [
|
|
3590
|
+
{
|
|
3591
|
+
// The four equal corner longhands collapse to a `border-radius` decl at the IR level; the
|
|
3592
|
+
// minimizing reverse-emit then picks the single shortest utility (`rounded-lg`) that reproduces
|
|
3593
|
+
// it, replacing the four `rounded-{tl,tr,br,bl}-lg` tokens. `bg-red-200` is preserved.
|
|
3594
|
+
before: '<div className="rounded-tl-lg rounded-tr-lg rounded-br-lg rounded-bl-lg bg-red-200">box</div>',
|
|
3595
|
+
after: '<div className="bg-red-200 rounded-lg">box</div>'
|
|
3596
|
+
}
|
|
3597
|
+
],
|
|
3598
|
+
// Corners differ (top corners vs bottom corners) → no all-equal collapse.
|
|
3599
|
+
noMatch: ['<div className="rounded-t-lg rounded-b-sm bg-red-200">box</div>']
|
|
3600
|
+
}
|
|
3601
|
+
});
|
|
3602
|
+
|
|
3603
|
+
// ../patterns/src/library/compress/border-shorthand.pattern.ts
|
|
3604
|
+
init_cjs_shims();
|
|
3605
|
+
var WIDTH_SIDES = [
|
|
3606
|
+
"border-top-width",
|
|
3607
|
+
"border-right-width",
|
|
3608
|
+
"border-bottom-width",
|
|
3609
|
+
"border-left-width"
|
|
3610
|
+
];
|
|
3611
|
+
var WIDTH_SIDE_SET = new Set(WIDTH_SIDES);
|
|
3612
|
+
var BASE_KEY2 = conditionKey(BASE_CONDITION);
|
|
3613
|
+
var BORDER_WIDTH = "border-width";
|
|
3614
|
+
function analyzeWidth(sm) {
|
|
3615
|
+
const block = sm.blocks.get(BASE_KEY2);
|
|
3616
|
+
if (!block) return null;
|
|
3617
|
+
const sides = [];
|
|
3618
|
+
for (const side of WIDTH_SIDES) {
|
|
3619
|
+
const decl = block.decls.get(side);
|
|
3620
|
+
if (!decl) return null;
|
|
3621
|
+
sides.push(decl);
|
|
3622
|
+
}
|
|
3623
|
+
const [top, right, bottom, left] = sides;
|
|
3624
|
+
if (!(top.important === right.important && right.important === bottom.important && bottom.important === left.important)) {
|
|
3625
|
+
return null;
|
|
3626
|
+
}
|
|
3627
|
+
const tv = String(top.value);
|
|
3628
|
+
const rv = String(right.value);
|
|
3629
|
+
const bv = String(bottom.value);
|
|
3630
|
+
const lv = String(left.value);
|
|
3631
|
+
if (tv !== bv || lv !== rv) return null;
|
|
3632
|
+
const value = tv === lv ? tv : `${tv} ${lv}`;
|
|
3633
|
+
const relative4 = sides.some((d3) => d3.relativeToParent);
|
|
3634
|
+
return { value, important: top.important, relative: relative4 };
|
|
3635
|
+
}
|
|
3636
|
+
function withFoldedWidth(sm, fold) {
|
|
3637
|
+
const blocks = /* @__PURE__ */ new Map();
|
|
3638
|
+
for (const [key, block] of sm.blocks) {
|
|
3639
|
+
if (key !== BASE_KEY2) {
|
|
3640
|
+
blocks.set(key, block);
|
|
3641
|
+
continue;
|
|
3642
|
+
}
|
|
3643
|
+
const decls = /* @__PURE__ */ new Map();
|
|
3644
|
+
for (const [prop, decl] of block.decls) {
|
|
3645
|
+
if (WIDTH_SIDE_SET.has(String(prop))) continue;
|
|
3646
|
+
decls.set(prop, decl);
|
|
3647
|
+
}
|
|
3648
|
+
const shorthand = {
|
|
3649
|
+
property: BORDER_WIDTH,
|
|
3650
|
+
value: fold.value,
|
|
3651
|
+
important: fold.important,
|
|
3652
|
+
relativeToParent: fold.relative,
|
|
3653
|
+
inherited: false
|
|
3654
|
+
// border-width is never inherited
|
|
3655
|
+
};
|
|
3656
|
+
decls.set(shorthand.property, shorthand);
|
|
3657
|
+
blocks.set(key, { condition: block.condition, decls });
|
|
3658
|
+
}
|
|
3659
|
+
return { blocks };
|
|
3660
|
+
}
|
|
3661
|
+
var borderShorthand = definePattern({
|
|
3662
|
+
name: "border-shorthand",
|
|
3663
|
+
category: "compress/border-shorthand",
|
|
3664
|
+
safety: 1,
|
|
3665
|
+
doc: {
|
|
3666
|
+
title: "Collapse border-width longhands to shorthand",
|
|
3667
|
+
summary: "Equal border width on all four sides (or matching x/y pairs) expressed as separate longhand declarations is collapsed to the shortest equivalent border-width shorthand (border-* / border-x-* border-y-*).",
|
|
3668
|
+
before: '<div class="border-t-2 border-r-2 border-b-2 border-l-2"/>',
|
|
3669
|
+
after: '<div class="border-2"/>',
|
|
3670
|
+
safetyRationale: "A value-preserving re-serialization of the same computed border widths (style/color longhands untouched) \u2014 a class-only change. It is safe even on an element with a ref, event handler, dynamic child, or dangerouslySetInnerHTML \u2014 a className rewrite touches none of them; only a dynamic/opaque class list or a combinator-subject class is excluded, so no behaviour or project selector is disturbed."
|
|
3671
|
+
},
|
|
3672
|
+
rewrite: {
|
|
3673
|
+
rewriteClasses(computed2) {
|
|
3674
|
+
const fold = analyzeWidth(computed2);
|
|
3675
|
+
return fold ? withFoldedWidth(computed2, fold) : null;
|
|
3676
|
+
}
|
|
3677
|
+
},
|
|
3678
|
+
test: {
|
|
3679
|
+
cases: [
|
|
3680
|
+
{
|
|
3681
|
+
// The four equal width longhands collapse to a `border-width` shorthand at the IR level, and the
|
|
3682
|
+
// minimizing reverse-emit picks the single shortest utility (`border-2`) that reproduces it,
|
|
3683
|
+
// replacing the four `border-{t,r,b,l}-2` tokens. `bg-red-200` is preserved.
|
|
3684
|
+
before: '<div className="border-t-2 border-r-2 border-b-2 border-l-2 bg-red-200">box</div>',
|
|
3685
|
+
after: '<div className="bg-red-200 border-2">box</div>'
|
|
3686
|
+
}
|
|
3687
|
+
],
|
|
3688
|
+
// Asymmetric widths (top != bottom) cannot fold into a shorthand.
|
|
3689
|
+
noMatch: ['<div className="border-t-2 border-r-4 border-b-8 border-l-4 bg-red-200">box</div>']
|
|
3690
|
+
}
|
|
3691
|
+
});
|
|
3692
|
+
|
|
3693
|
+
// ../patterns/src/library/compress/dedupe-classes.pattern.ts
|
|
3694
|
+
init_cjs_shims();
|
|
3695
|
+
function findRedundantClasses(computed2) {
|
|
3696
|
+
const winners = /* @__PURE__ */ new Set();
|
|
3697
|
+
const shadowed = /* @__PURE__ */ new Set();
|
|
3698
|
+
for (const block of computed2.blocks.values()) {
|
|
3699
|
+
for (const decl of block.decls.values()) {
|
|
3700
|
+
if (decl.origin && decl.origin.kind === "class") winners.add(decl.origin.className);
|
|
3701
|
+
for (const o2 of decl.shadowed ?? []) {
|
|
3702
|
+
if (o2.kind === "class") shadowed.add(o2.className);
|
|
3703
|
+
}
|
|
3704
|
+
}
|
|
3705
|
+
}
|
|
3706
|
+
return { winners, shadowed };
|
|
3707
|
+
}
|
|
3708
|
+
var dedupeClasses = definePattern({
|
|
3709
|
+
name: "dedupe-classes",
|
|
3710
|
+
category: "compress/dedupe-classes",
|
|
3711
|
+
safety: 1,
|
|
3712
|
+
doc: {
|
|
3713
|
+
title: "Dedupe fully-overridden class tokens",
|
|
3714
|
+
summary: "Drops class tokens whose every declaration is overridden by a later token resolving to the same property; the surviving token set produces a byte-for-byte identical computed style.",
|
|
3715
|
+
before: '<p class="text-sm text-lg" />',
|
|
3716
|
+
after: '<p class="text-lg" />',
|
|
3717
|
+
safetyRationale: "A fully-overridden token contributes nothing to the computed style in any condition, so removing it changes no pixels \u2014 a class-only change. It is safe even on an element with a ref, event handler, dynamic child, or dangerouslySetInnerHTML \u2014 a className rewrite touches none of them; only a dynamic/opaque class list or a combinator-subject class is excluded, so no behaviour or project selector is disturbed."
|
|
3718
|
+
},
|
|
2940
3719
|
rewrite: {
|
|
2941
3720
|
dropClasses(computed2, ctx) {
|
|
2942
3721
|
const { winners, shadowed } = findRedundantClasses(computed2);
|
|
@@ -2949,22 +3728,91 @@ var dedupeClasses = pattern({
|
|
|
2949
3728
|
return drop;
|
|
2950
3729
|
}
|
|
2951
3730
|
},
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
3731
|
+
test: {
|
|
3732
|
+
cases: [
|
|
3733
|
+
{
|
|
3734
|
+
// `text-sm` is fully overridden by `text-lg` (both set font-size + line-height). The resolver
|
|
3735
|
+
// records that shadowing in provenance and reports the Tailwind utility as droppable, so the
|
|
3736
|
+
// pattern drops `text-sm`; the reverse-emit then re-derives the minimal set (`text-lg`).
|
|
3737
|
+
before: '<p className="text-sm text-lg">Hi</p>',
|
|
3738
|
+
after: '<p className="text-lg">Hi</p>'
|
|
3739
|
+
}
|
|
3740
|
+
],
|
|
3741
|
+
// Both tokens win a distinct property (no full override) → nothing to dedupe.
|
|
3742
|
+
noMatch: ['<p className="text-lg font-bold">Hi</p>']
|
|
3743
|
+
}
|
|
3744
|
+
});
|
|
3745
|
+
|
|
3746
|
+
// ../patterns/src/library/compress/gap-shorthand.pattern.ts
|
|
3747
|
+
init_cjs_shims();
|
|
3748
|
+
var ROW_GAP = "row-gap";
|
|
3749
|
+
var COLUMN_GAP = "column-gap";
|
|
3750
|
+
var GAP = "gap";
|
|
3751
|
+
var BASE_KEY3 = conditionKey(BASE_CONDITION);
|
|
3752
|
+
function withGapShorthand(sm, gapDecl) {
|
|
3753
|
+
const blocks = /* @__PURE__ */ new Map();
|
|
3754
|
+
for (const [key, block] of sm.blocks) {
|
|
3755
|
+
if (key !== BASE_KEY3) {
|
|
3756
|
+
blocks.set(key, block);
|
|
3757
|
+
continue;
|
|
2963
3758
|
}
|
|
2964
|
-
|
|
3759
|
+
const decls = /* @__PURE__ */ new Map();
|
|
3760
|
+
for (const [prop, decl] of block.decls) {
|
|
3761
|
+
if (prop === ROW_GAP || prop === COLUMN_GAP) continue;
|
|
3762
|
+
decls.set(prop, decl);
|
|
3763
|
+
}
|
|
3764
|
+
decls.set(gapDecl.property, gapDecl);
|
|
3765
|
+
blocks.set(key, { condition: block.condition, decls });
|
|
3766
|
+
}
|
|
3767
|
+
return { blocks };
|
|
3768
|
+
}
|
|
3769
|
+
var gapShorthand = definePattern({
|
|
3770
|
+
name: "gap-shorthand",
|
|
3771
|
+
category: "compress/gap-shorthand",
|
|
3772
|
+
safety: 1,
|
|
3773
|
+
doc: {
|
|
3774
|
+
title: "Collapse equal row/column gap into the `gap` shorthand",
|
|
3775
|
+
summary: "An element whose computed row-gap and column-gap are equal has the two axis longhands collapsed into a single-value `gap` shorthand (Tailwind gap-x-* gap-y-* \u2192 gap-*).",
|
|
3776
|
+
before: '<div style="row-gap:16px;column-gap:16px"/>',
|
|
3777
|
+
after: '<div style="gap:16px"/>',
|
|
3778
|
+
safetyRationale: "A single-value `gap` is value-identical to an equal row-gap+column-gap pair \u2014 a class-only change. It is safe even on an element with a ref, event handler, dynamic child, or dangerouslySetInnerHTML \u2014 a className rewrite touches none of them; only a dynamic/opaque class list or a combinator-subject class is excluded, so no behaviour or project selector is disturbed."
|
|
3779
|
+
},
|
|
3780
|
+
rewrite: {
|
|
3781
|
+
rewriteClasses(computed2) {
|
|
3782
|
+
const base = computed2.blocks.get(BASE_KEY3);
|
|
3783
|
+
if (!base) return null;
|
|
3784
|
+
const rowGap = base.decls.get(ROW_GAP);
|
|
3785
|
+
const colGap = base.decls.get(COLUMN_GAP);
|
|
3786
|
+
if (!rowGap || !colGap) return null;
|
|
3787
|
+
if (rowGap.important !== colGap.important) return null;
|
|
3788
|
+
if (rowGap.value !== colGap.value) return null;
|
|
3789
|
+
const gapDecl = {
|
|
3790
|
+
property: GAP,
|
|
3791
|
+
value: rowGap.value,
|
|
3792
|
+
important: rowGap.important,
|
|
3793
|
+
relativeToParent: rowGap.relativeToParent || colGap.relativeToParent,
|
|
3794
|
+
inherited: false
|
|
3795
|
+
// gap is not an inherited property
|
|
3796
|
+
};
|
|
3797
|
+
return withGapShorthand(computed2, gapDecl);
|
|
3798
|
+
}
|
|
3799
|
+
},
|
|
3800
|
+
test: {
|
|
3801
|
+
cases: [
|
|
3802
|
+
{
|
|
3803
|
+
// Equal row/column gap collapse to a `gap` decl at the IR level; the minimizing reverse-emit
|
|
3804
|
+
// re-expands `gap` to row-gap+column-gap and picks the single utility covering both (`gap-4`),
|
|
3805
|
+
// replacing the `gap-x-4`+`gap-y-4` pair. `bg-red-200` is preserved.
|
|
3806
|
+
before: '<div className="gap-x-4 gap-y-4 bg-red-200">box</div>',
|
|
3807
|
+
after: '<div className="bg-red-200 gap-4">box</div>'
|
|
3808
|
+
}
|
|
3809
|
+
],
|
|
3810
|
+
// Unequal axes (row-gap != column-gap) have no single-value `gap` equivalent → not collapsed.
|
|
3811
|
+
noMatch: ['<div className="gap-x-2 gap-y-4 bg-red-200">box</div>']
|
|
3812
|
+
}
|
|
2965
3813
|
});
|
|
2966
3814
|
|
|
2967
|
-
// ../patterns/src/compress/inset-shorthand.pattern.ts
|
|
3815
|
+
// ../patterns/src/library/compress/inset-shorthand.pattern.ts
|
|
2968
3816
|
init_cjs_shims();
|
|
2969
3817
|
var TOP = "top";
|
|
2970
3818
|
var RIGHT = "right";
|
|
@@ -2973,10 +3821,6 @@ var LEFT = "left";
|
|
|
2973
3821
|
var INSET = "inset";
|
|
2974
3822
|
var INSET_BLOCK = "inset-block";
|
|
2975
3823
|
var INSET_INLINE = "inset-inline";
|
|
2976
|
-
var hasRawHtml2 = (node) => {
|
|
2977
|
-
const n = node;
|
|
2978
|
-
return n.kind === "element" ? n.meta.hasDangerousHtml : false;
|
|
2979
|
-
};
|
|
2980
3824
|
function sameSide(a, b3) {
|
|
2981
3825
|
return a !== void 0 && b3 !== void 0 && a.value === b3.value && a.important === b3.important;
|
|
2982
3826
|
}
|
|
@@ -2991,7 +3835,7 @@ function withBaseDecls(src, baseDecls) {
|
|
|
2991
3835
|
}
|
|
2992
3836
|
return { blocks };
|
|
2993
3837
|
}
|
|
2994
|
-
var insetShorthand =
|
|
3838
|
+
var insetShorthand = definePattern({
|
|
2995
3839
|
name: "inset-shorthand",
|
|
2996
3840
|
category: "compress/inset-shorthand",
|
|
2997
3841
|
safety: 2,
|
|
@@ -3000,17 +3844,7 @@ var insetShorthand = pattern({
|
|
|
3000
3844
|
summary: "top/right/bottom/left set to one value collapse to `inset`; a matching top/bottom or left/right pair collapses to `inset-block` / `inset-inline` (Tailwind inset-y / inset-x).",
|
|
3001
3845
|
before: '<div style="top:10px;right:10px;bottom:10px;left:10px"/>',
|
|
3002
3846
|
after: '<div style="inset:10px"/>',
|
|
3003
|
-
safetyRationale: "Meaning-preserving shorthand compaction
|
|
3004
|
-
},
|
|
3005
|
-
match: {
|
|
3006
|
-
where: [
|
|
3007
|
-
not(hasRef),
|
|
3008
|
-
not(hasEventHandlers),
|
|
3009
|
-
not(hasDynamicChildren),
|
|
3010
|
-
not(hasRawHtml2),
|
|
3011
|
-
not(hasDynamicClasses),
|
|
3012
|
-
not(targetedByCombinator)
|
|
3013
|
-
]
|
|
3847
|
+
safetyRationale: "Meaning-preserving inset shorthand compaction \u2014 a class-only change. It is safe even on an element with a ref, event handler, dynamic child, or dangerouslySetInnerHTML \u2014 a className rewrite touches none of them; only a dynamic/opaque class list or a combinator-subject class is excluded, so no behaviour or project selector is disturbed."
|
|
3014
3848
|
},
|
|
3015
3849
|
rewrite: {
|
|
3016
3850
|
rewriteClasses(computed2) {
|
|
@@ -3046,22 +3880,22 @@ var insetShorthand = pattern({
|
|
|
3046
3880
|
return withBaseDecls(computed2, next);
|
|
3047
3881
|
}
|
|
3048
3882
|
},
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3883
|
+
test: {
|
|
3884
|
+
cases: [
|
|
3885
|
+
{
|
|
3886
|
+
// The four equal inset longhands collapse to an `inset` shorthand at the IR level; the
|
|
3887
|
+
// minimizing reverse-emit expands it back to top/right/bottom/left and picks the single utility
|
|
3888
|
+
// covering all four (`inset-0`), replacing the four physical-side tokens. `bg-red-200` survives.
|
|
3889
|
+
before: '<div className="top-0 right-0 bottom-0 left-0 bg-red-200">box</div>',
|
|
3890
|
+
after: '<div className="bg-red-200 inset-0">box</div>'
|
|
3891
|
+
}
|
|
3892
|
+
],
|
|
3893
|
+
// No matching inset pair (all four distinct) → nothing collapses.
|
|
3894
|
+
noMatch: ['<div className="top-0 right-1 bottom-2 left-3 bg-red-200">box</div>']
|
|
3895
|
+
}
|
|
3062
3896
|
});
|
|
3063
3897
|
|
|
3064
|
-
// ../patterns/src/compress/margin-shorthand.pattern.ts
|
|
3898
|
+
// ../patterns/src/library/compress/margin-shorthand.pattern.ts
|
|
3065
3899
|
init_cjs_shims();
|
|
3066
3900
|
var MARGIN_SIDES = [
|
|
3067
3901
|
"margin-top",
|
|
@@ -3070,12 +3904,7 @@ var MARGIN_SIDES = [
|
|
|
3070
3904
|
"margin-left"
|
|
3071
3905
|
];
|
|
3072
3906
|
var MARGIN_SIDE_SET = new Set(MARGIN_SIDES);
|
|
3073
|
-
var
|
|
3074
|
-
function asElement3(node) {
|
|
3075
|
-
const n = node;
|
|
3076
|
-
return n.kind === "element" ? n : null;
|
|
3077
|
-
}
|
|
3078
|
-
var hasDangerousHtml2 = (node) => asElement3(node)?.meta.hasDangerousHtml ?? false;
|
|
3907
|
+
var BASE_KEY4 = conditionKey(BASE_CONDITION);
|
|
3079
3908
|
function collapseMarginValue(top, right, bottom, left) {
|
|
3080
3909
|
if (right === left) {
|
|
3081
3910
|
if (top === bottom) {
|
|
@@ -3088,7 +3917,7 @@ function collapseMarginValue(top, right, bottom, left) {
|
|
|
3088
3917
|
function withFoldedMargin(sm, marginDecl) {
|
|
3089
3918
|
const blocks = /* @__PURE__ */ new Map();
|
|
3090
3919
|
for (const [key, block] of sm.blocks) {
|
|
3091
|
-
if (key !==
|
|
3920
|
+
if (key !== BASE_KEY4) {
|
|
3092
3921
|
blocks.set(key, block);
|
|
3093
3922
|
continue;
|
|
3094
3923
|
}
|
|
@@ -3101,7 +3930,7 @@ function withFoldedMargin(sm, marginDecl) {
|
|
|
3101
3930
|
}
|
|
3102
3931
|
return { blocks };
|
|
3103
3932
|
}
|
|
3104
|
-
var marginShorthand =
|
|
3933
|
+
var marginShorthand = definePattern({
|
|
3105
3934
|
name: "margin-shorthand",
|
|
3106
3935
|
category: "compress/margin-shorthand",
|
|
3107
3936
|
safety: 2,
|
|
@@ -3110,177 +3939,567 @@ var marginShorthand = pattern({
|
|
|
3110
3939
|
summary: "An element with margin-top/right/bottom/left all set has them collapsed into the shortest legal `margin` shorthand (the m / mx / my forms); meaning is preserved, declaration count drops.",
|
|
3111
3940
|
before: '<div style="margin-top:8px;margin-right:8px;margin-bottom:8px;margin-left:8px"/>',
|
|
3112
3941
|
after: '<div style="margin:8px"/>',
|
|
3113
|
-
safetyRationale: "
|
|
3942
|
+
safetyRationale: "A pure representation change of the same computed margins (no pixels move) \u2014 a class-only change. It is safe even on an element with a ref, event handler, dynamic child, or dangerouslySetInnerHTML \u2014 a className rewrite touches none of them; only a dynamic/opaque class list or a combinator-subject class is excluded, so no behaviour or project selector is disturbed."
|
|
3114
3943
|
},
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3944
|
+
rewrite: {
|
|
3945
|
+
rewriteClasses(computed2) {
|
|
3946
|
+
const base = computed2.blocks.get(BASE_KEY4);
|
|
3947
|
+
if (!base) return null;
|
|
3948
|
+
const sides = MARGIN_SIDES.map((p2) => base.decls.get(p2));
|
|
3949
|
+
if (sides.some((d3) => d3 === void 0)) return null;
|
|
3950
|
+
const [mt, mr, mb, ml] = sides;
|
|
3951
|
+
if (mt.important || mr.important || mb.important || ml.important) return null;
|
|
3952
|
+
const value = collapseMarginValue(
|
|
3953
|
+
String(mt.value),
|
|
3954
|
+
String(mr.value),
|
|
3955
|
+
String(mb.value),
|
|
3956
|
+
String(ml.value)
|
|
3957
|
+
);
|
|
3958
|
+
const marginDecl = {
|
|
3959
|
+
property: "margin",
|
|
3960
|
+
value,
|
|
3961
|
+
important: false,
|
|
3962
|
+
relativeToParent: mt.relativeToParent || mr.relativeToParent || mb.relativeToParent || ml.relativeToParent,
|
|
3963
|
+
inherited: false
|
|
3964
|
+
// margin is not an inherited property
|
|
3965
|
+
};
|
|
3966
|
+
return withFoldedMargin(computed2, marginDecl);
|
|
3967
|
+
}
|
|
3968
|
+
},
|
|
3969
|
+
test: {
|
|
3970
|
+
cases: [
|
|
3971
|
+
{
|
|
3972
|
+
// The four equal margin longhands collapse to a `margin` shorthand at the IR level, and the
|
|
3973
|
+
// minimizing reverse-emit picks the single shortest utility (`m-2`) reproducing it, replacing
|
|
3974
|
+
// the four `m{t,r,b,l}-2` tokens. `bg-red-200` is preserved.
|
|
3975
|
+
before: '<div className="mt-2 mr-2 mb-2 ml-2 bg-red-200">box</div>',
|
|
3976
|
+
after: '<div className="bg-red-200 m-2">box</div>'
|
|
3977
|
+
}
|
|
3978
|
+
],
|
|
3979
|
+
// Only two margin sides set → the four-longhand `margin` collapse does not apply.
|
|
3980
|
+
noMatch: ['<div className="mt-2 mb-2 bg-red-200">box</div>']
|
|
3981
|
+
}
|
|
3982
|
+
});
|
|
3983
|
+
|
|
3984
|
+
// ../patterns/src/library/compress/overflow-shorthand.pattern.ts
|
|
3985
|
+
init_cjs_shims();
|
|
3986
|
+
var OVERFLOW_X = "overflow-x";
|
|
3987
|
+
var OVERFLOW_Y = "overflow-y";
|
|
3988
|
+
var OVERFLOW = "overflow";
|
|
3989
|
+
var BASE_KEY5 = conditionKey(BASE_CONDITION);
|
|
3990
|
+
function withOverflowShorthand(sm, overflowDecl) {
|
|
3991
|
+
const blocks = /* @__PURE__ */ new Map();
|
|
3992
|
+
for (const [key, block] of sm.blocks) {
|
|
3993
|
+
if (key !== BASE_KEY5) {
|
|
3994
|
+
blocks.set(key, block);
|
|
3995
|
+
continue;
|
|
3996
|
+
}
|
|
3997
|
+
const decls = /* @__PURE__ */ new Map();
|
|
3998
|
+
for (const [prop, decl] of block.decls) {
|
|
3999
|
+
if (prop === OVERFLOW_X || prop === OVERFLOW_Y) continue;
|
|
4000
|
+
decls.set(prop, decl);
|
|
4001
|
+
}
|
|
4002
|
+
decls.set(overflowDecl.property, overflowDecl);
|
|
4003
|
+
blocks.set(key, { condition: block.condition, decls });
|
|
4004
|
+
}
|
|
4005
|
+
return { blocks };
|
|
4006
|
+
}
|
|
4007
|
+
var overflowShorthand = definePattern({
|
|
4008
|
+
name: "overflow-shorthand",
|
|
4009
|
+
category: "compress/overflow-shorthand",
|
|
4010
|
+
safety: 1,
|
|
4011
|
+
doc: {
|
|
4012
|
+
title: "Collapse equal overflow axes into the `overflow` shorthand",
|
|
4013
|
+
summary: "An element whose computed overflow-x and overflow-y are equal has the two axis longhands collapsed into a single `overflow` shorthand (Tailwind overflow-x-* overflow-y-* \u2192 overflow-*).",
|
|
4014
|
+
before: '<div style="overflow-x:auto;overflow-y:auto"/>',
|
|
4015
|
+
after: '<div style="overflow:auto"/>',
|
|
4016
|
+
safetyRationale: "A single-keyword `overflow` is value-identical to equal overflow-x+overflow-y \u2014 a class-only change. It is safe even on an element with a ref, event handler, dynamic child, or dangerouslySetInnerHTML \u2014 a className rewrite touches none of them; only a dynamic/opaque class list or a combinator-subject class is excluded, so no behaviour or project selector is disturbed."
|
|
4017
|
+
},
|
|
4018
|
+
rewrite: {
|
|
4019
|
+
rewriteClasses(computed2) {
|
|
4020
|
+
const base = computed2.blocks.get(BASE_KEY5);
|
|
4021
|
+
if (!base) return null;
|
|
4022
|
+
const overflowX = base.decls.get(OVERFLOW_X);
|
|
4023
|
+
const overflowY = base.decls.get(OVERFLOW_Y);
|
|
4024
|
+
if (!overflowX || !overflowY) return null;
|
|
4025
|
+
if (overflowX.important !== overflowY.important) return null;
|
|
4026
|
+
if (overflowX.value !== overflowY.value) return null;
|
|
4027
|
+
const overflowDecl = {
|
|
4028
|
+
property: OVERFLOW,
|
|
4029
|
+
value: overflowX.value,
|
|
4030
|
+
important: overflowX.important,
|
|
4031
|
+
relativeToParent: overflowX.relativeToParent || overflowY.relativeToParent,
|
|
4032
|
+
inherited: false
|
|
4033
|
+
// overflow is not an inherited property
|
|
4034
|
+
};
|
|
4035
|
+
return withOverflowShorthand(computed2, overflowDecl);
|
|
4036
|
+
}
|
|
4037
|
+
},
|
|
4038
|
+
test: {
|
|
4039
|
+
cases: [
|
|
4040
|
+
{
|
|
4041
|
+
// Equal overflow axes collapse to an `overflow` decl at the IR level; the minimizing
|
|
4042
|
+
// reverse-emit picks the single utility covering both (`overflow-auto`), replacing the
|
|
4043
|
+
// `overflow-x-auto`+`overflow-y-auto` pair. `bg-red-200` is preserved.
|
|
4044
|
+
before: '<div className="overflow-x-auto overflow-y-auto bg-red-200">box</div>',
|
|
4045
|
+
after: '<div className="bg-red-200 overflow-auto">box</div>'
|
|
4046
|
+
}
|
|
4047
|
+
],
|
|
4048
|
+
// Mismatched axes (overflow-x != overflow-y) have no single-keyword equivalent → not collapsed.
|
|
4049
|
+
noMatch: ['<div className="overflow-x-auto overflow-y-hidden bg-red-200">box</div>']
|
|
4050
|
+
}
|
|
4051
|
+
});
|
|
4052
|
+
|
|
4053
|
+
// ../patterns/src/library/compress/overscroll-behavior-shorthand.pattern.ts
|
|
4054
|
+
init_cjs_shims();
|
|
4055
|
+
var OVERSCROLL_X = "overscroll-behavior-x";
|
|
4056
|
+
var OVERSCROLL_Y = "overscroll-behavior-y";
|
|
4057
|
+
var OVERSCROLL = "overscroll-behavior";
|
|
4058
|
+
var BASE_KEY6 = conditionKey(BASE_CONDITION);
|
|
4059
|
+
var NON_COLLAPSIBLE_VALUES2 = /* @__PURE__ */ new Set([
|
|
4060
|
+
"initial",
|
|
4061
|
+
"inherit",
|
|
4062
|
+
"unset",
|
|
4063
|
+
"revert",
|
|
4064
|
+
"revert-layer"
|
|
4065
|
+
]);
|
|
4066
|
+
function withOverscrollShorthand(sm, shorthand) {
|
|
4067
|
+
const blocks = /* @__PURE__ */ new Map();
|
|
4068
|
+
for (const [key, block] of sm.blocks) {
|
|
4069
|
+
if (key !== BASE_KEY6) {
|
|
4070
|
+
blocks.set(key, block);
|
|
4071
|
+
continue;
|
|
4072
|
+
}
|
|
4073
|
+
const decls = /* @__PURE__ */ new Map();
|
|
4074
|
+
for (const [prop, decl] of block.decls) {
|
|
4075
|
+
if (prop === OVERSCROLL_X || prop === OVERSCROLL_Y) continue;
|
|
4076
|
+
decls.set(prop, decl);
|
|
4077
|
+
}
|
|
4078
|
+
decls.set(shorthand.property, shorthand);
|
|
4079
|
+
blocks.set(key, { condition: block.condition, decls });
|
|
4080
|
+
}
|
|
4081
|
+
return { blocks };
|
|
4082
|
+
}
|
|
4083
|
+
var overscrollBehaviorShorthand = definePattern({
|
|
4084
|
+
name: "overscroll-behavior-shorthand",
|
|
4085
|
+
category: "compress/overscroll-behavior-shorthand",
|
|
4086
|
+
safety: 1,
|
|
4087
|
+
doc: {
|
|
4088
|
+
title: "Collapse equal overscroll-behavior axes into overscroll-behavior",
|
|
4089
|
+
summary: "An element whose computed overscroll-behavior-x and overscroll-behavior-y are equal has the two axis longhands collapsed into a single `overscroll-behavior` shorthand (Tailwind overscroll-x-* overscroll-y-* \u2192 overscroll-*).",
|
|
4090
|
+
before: '<div style="overscroll-behavior-x:contain;overscroll-behavior-y:contain"/>',
|
|
4091
|
+
after: '<div class="overscroll-contain"/>',
|
|
4092
|
+
safetyRationale: "`overscroll-behavior` is value-identical to an equal x+y axis pair \u2014 a class-only change. It is safe even on an element with a ref, event handler, dynamic child, or dangerouslySetInnerHTML \u2014 a className rewrite touches none of them; only a dynamic/opaque class list or a combinator-subject class is excluded, so no behaviour or project selector is disturbed."
|
|
4093
|
+
},
|
|
4094
|
+
rewrite: {
|
|
4095
|
+
rewriteClasses(computed2) {
|
|
4096
|
+
const base = computed2.blocks.get(BASE_KEY6);
|
|
4097
|
+
if (!base) return null;
|
|
4098
|
+
const x2 = base.decls.get(OVERSCROLL_X);
|
|
4099
|
+
const y3 = base.decls.get(OVERSCROLL_Y);
|
|
4100
|
+
if (!x2 || !y3) return null;
|
|
4101
|
+
if (x2.important !== y3.important) return null;
|
|
4102
|
+
const value = String(x2.value);
|
|
4103
|
+
if (NON_COLLAPSIBLE_VALUES2.has(value)) return null;
|
|
4104
|
+
if (value !== String(y3.value)) return null;
|
|
4105
|
+
const shorthand = {
|
|
4106
|
+
property: OVERSCROLL,
|
|
4107
|
+
value: x2.value,
|
|
4108
|
+
important: x2.important,
|
|
4109
|
+
relativeToParent: x2.relativeToParent || y3.relativeToParent,
|
|
4110
|
+
inherited: false
|
|
4111
|
+
// overscroll-behavior is not an inherited property
|
|
4112
|
+
};
|
|
4113
|
+
return withOverscrollShorthand(computed2, shorthand);
|
|
4114
|
+
}
|
|
4115
|
+
},
|
|
4116
|
+
test: {
|
|
4117
|
+
cases: [
|
|
4118
|
+
{
|
|
4119
|
+
// Equal x/y axes collapse to an `overscroll-behavior` decl at the IR level; the minimizing
|
|
4120
|
+
// reverse-emit picks the single utility covering both (`overscroll-contain`), replacing the
|
|
4121
|
+
// `overscroll-x-contain`+`overscroll-y-contain` pair. `bg-red-200` is preserved.
|
|
4122
|
+
before: '<div className="overscroll-x-contain overscroll-y-contain bg-red-200">box</div>',
|
|
4123
|
+
after: '<div className="bg-red-200 overscroll-contain">box</div>'
|
|
4124
|
+
}
|
|
4125
|
+
],
|
|
4126
|
+
// Axes differ (x != y) → no equal-axis collapse.
|
|
4127
|
+
noMatch: ['<div className="overscroll-x-contain overscroll-y-auto bg-red-200">box</div>']
|
|
4128
|
+
}
|
|
4129
|
+
});
|
|
4130
|
+
|
|
4131
|
+
// ../patterns/src/library/compress/padding-shorthand.pattern.ts
|
|
4132
|
+
init_cjs_shims();
|
|
4133
|
+
var PADDING_SIDES = [
|
|
4134
|
+
"padding-top",
|
|
4135
|
+
"padding-right",
|
|
4136
|
+
"padding-bottom",
|
|
4137
|
+
"padding-left"
|
|
4138
|
+
];
|
|
4139
|
+
var PADDING_SIDE_SET = new Set(PADDING_SIDES);
|
|
4140
|
+
var BASE_KEY7 = conditionKey(BASE_CONDITION);
|
|
4141
|
+
function analyzePadding(sm) {
|
|
4142
|
+
const block = sm.blocks.get(BASE_KEY7);
|
|
4143
|
+
if (!block) return null;
|
|
4144
|
+
const sides = [];
|
|
4145
|
+
for (const side of PADDING_SIDES) {
|
|
4146
|
+
const decl = block.decls.get(side);
|
|
4147
|
+
if (!decl) return null;
|
|
4148
|
+
sides.push(decl);
|
|
4149
|
+
}
|
|
4150
|
+
const [top, right, bottom, left] = sides;
|
|
4151
|
+
if (!(top.important === right.important && right.important === bottom.important && bottom.important === left.important)) {
|
|
4152
|
+
return null;
|
|
4153
|
+
}
|
|
4154
|
+
const tv = String(top.value);
|
|
4155
|
+
const rv = String(right.value);
|
|
4156
|
+
const bv = String(bottom.value);
|
|
4157
|
+
const lv = String(left.value);
|
|
4158
|
+
if (tv !== bv || lv !== rv) return null;
|
|
4159
|
+
const value = tv === lv ? tv : `${tv} ${lv}`;
|
|
4160
|
+
const relative4 = sides.some((d3) => d3.relativeToParent);
|
|
4161
|
+
return { value, important: top.important, relative: relative4 };
|
|
4162
|
+
}
|
|
4163
|
+
function withFoldedPadding(sm, fold) {
|
|
4164
|
+
const blocks = /* @__PURE__ */ new Map();
|
|
4165
|
+
for (const [key, block] of sm.blocks) {
|
|
4166
|
+
if (key !== BASE_KEY7) {
|
|
4167
|
+
blocks.set(key, block);
|
|
4168
|
+
continue;
|
|
4169
|
+
}
|
|
4170
|
+
const decls = /* @__PURE__ */ new Map();
|
|
4171
|
+
for (const [prop, decl] of block.decls) {
|
|
4172
|
+
if (PADDING_SIDE_SET.has(String(prop))) continue;
|
|
4173
|
+
decls.set(prop, decl);
|
|
4174
|
+
}
|
|
4175
|
+
const shorthand = {
|
|
4176
|
+
property: "padding",
|
|
4177
|
+
value: fold.value,
|
|
4178
|
+
important: fold.important,
|
|
4179
|
+
relativeToParent: fold.relative,
|
|
4180
|
+
inherited: false
|
|
4181
|
+
// padding is never inherited
|
|
4182
|
+
};
|
|
4183
|
+
decls.set(shorthand.property, shorthand);
|
|
4184
|
+
blocks.set(key, { condition: block.condition, decls });
|
|
4185
|
+
}
|
|
4186
|
+
return { blocks };
|
|
4187
|
+
}
|
|
4188
|
+
var paddingShorthand = definePattern({
|
|
4189
|
+
name: "padding-shorthand",
|
|
4190
|
+
category: "compress/padding-shorthand",
|
|
4191
|
+
safety: 1,
|
|
4192
|
+
doc: {
|
|
4193
|
+
title: "Collapse padding longhands to shorthand",
|
|
4194
|
+
summary: "Equal padding on all four sides (or matching x/y pairs) expressed as separate longhand declarations is collapsed to the shortest equivalent padding shorthand (p-* / px-* py-*).",
|
|
4195
|
+
before: '<div class="pt-4 pr-4 pb-4 pl-4"/>',
|
|
4196
|
+
after: '<div class="p-4"/>',
|
|
4197
|
+
safetyRationale: "A value-preserving re-serialization of the same computed padding on the same node \u2014 a class-only change. It is safe even on an element with a ref, event handler, dynamic child, or dangerouslySetInnerHTML \u2014 a className rewrite touches none of them; only a dynamic/opaque class list or a combinator-subject class is excluded, so no behaviour or project selector is disturbed."
|
|
4198
|
+
},
|
|
4199
|
+
rewrite: {
|
|
4200
|
+
rewriteClasses(computed2) {
|
|
4201
|
+
const fold = analyzePadding(computed2);
|
|
4202
|
+
return fold ? withFoldedPadding(computed2, fold) : null;
|
|
4203
|
+
}
|
|
4204
|
+
},
|
|
4205
|
+
test: {
|
|
4206
|
+
cases: [
|
|
4207
|
+
{
|
|
4208
|
+
// The four equal padding longhands collapse to a `padding` shorthand at the IR level, and the
|
|
4209
|
+
// minimizing reverse-emit picks the single shortest utility (`p-4`) that reproduces it,
|
|
4210
|
+
// replacing the four `p{t,r,b,l}-4` tokens. `bg-red-200` is preserved (its order is stable).
|
|
4211
|
+
before: '<div className="pt-4 pr-4 pb-4 pl-4 bg-red-200">box</div>',
|
|
4212
|
+
after: '<div className="bg-red-200 p-4">box</div>'
|
|
4213
|
+
},
|
|
4214
|
+
{
|
|
4215
|
+
// A dynamic `{x}` child no longer blocks compress: only the element's OWN class tokens are
|
|
4216
|
+
// rewritten (px-4 py-4 → p-4); the dynamic child is untouched by a class-only change. This is
|
|
4217
|
+
// the real-app common case (most elements have dynamic content).
|
|
4218
|
+
before: '<div className="px-4 py-4">{x}</div>',
|
|
4219
|
+
after: '<div className="p-4">{x}</div>'
|
|
4220
|
+
}
|
|
4221
|
+
],
|
|
4222
|
+
// Asymmetric padding (top != bottom) cannot fold into a shorthand → left unchanged.
|
|
4223
|
+
noMatch: ['<div className="pt-2 pr-4 pb-8 pl-4 bg-red-200">box</div>']
|
|
4224
|
+
}
|
|
4225
|
+
});
|
|
4226
|
+
|
|
4227
|
+
// ../patterns/src/library/compress/place-shorthand.pattern.ts
|
|
4228
|
+
init_cjs_shims();
|
|
4229
|
+
var ALIGN_ITEMS = "align-items";
|
|
4230
|
+
var JUSTIFY_ITEMS = "justify-items";
|
|
4231
|
+
var PLACE_ITEMS = "place-items";
|
|
4232
|
+
var ALIGN_CONTENT = "align-content";
|
|
4233
|
+
var JUSTIFY_CONTENT = "justify-content";
|
|
4234
|
+
var PLACE_CONTENT = "place-content";
|
|
4235
|
+
var BASE_KEY8 = conditionKey(BASE_CONDITION);
|
|
4236
|
+
function samePair(a, b3) {
|
|
4237
|
+
return a !== void 0 && b3 !== void 0 && a.value === b3.value && a.important === b3.important;
|
|
4238
|
+
}
|
|
4239
|
+
function placeDecl(property, align) {
|
|
4240
|
+
return {
|
|
4241
|
+
property,
|
|
4242
|
+
value: align.value,
|
|
4243
|
+
important: align.important,
|
|
4244
|
+
relativeToParent: false,
|
|
4245
|
+
// alignment keywords (center/start/stretch/…) are not length-relative
|
|
4246
|
+
inherited: false
|
|
4247
|
+
// none of the place-* alignment properties are inherited
|
|
4248
|
+
};
|
|
4249
|
+
}
|
|
4250
|
+
function withBaseDecls2(sm, baseDecls) {
|
|
4251
|
+
const blocks = /* @__PURE__ */ new Map();
|
|
4252
|
+
for (const [key, block] of sm.blocks) {
|
|
4253
|
+
const decls = key === BASE_KEY8 ? new Map(baseDecls) : block.decls;
|
|
4254
|
+
blocks.set(key, { condition: block.condition, decls });
|
|
4255
|
+
}
|
|
4256
|
+
return { blocks };
|
|
4257
|
+
}
|
|
4258
|
+
var placeShorthand = definePattern({
|
|
4259
|
+
name: "place-shorthand",
|
|
4260
|
+
category: "compress/place-shorthand",
|
|
4261
|
+
safety: 1,
|
|
4262
|
+
doc: {
|
|
4263
|
+
title: "Collapse matching alignment pairs into `place-*` shorthands",
|
|
4264
|
+
summary: "When align-items equals justify-items they collapse to `place-items`; when align-content equals justify-content they collapse to `place-content`. The two collapses are independent.",
|
|
4265
|
+
before: '<div style="align-items:center;justify-items:center"/>',
|
|
4266
|
+
after: '<div style="place-items:center"/>',
|
|
4267
|
+
safetyRationale: "A `place-*` shorthand is value-identical to its equal align/justify pair \u2014 a class-only change. It is safe even on an element with a ref, event handler, dynamic child, or dangerouslySetInnerHTML \u2014 a className rewrite touches none of them; only a dynamic/opaque class list or a combinator-subject class is excluded, so no behaviour or project selector is disturbed."
|
|
4268
|
+
},
|
|
4269
|
+
rewrite: {
|
|
4270
|
+
rewriteClasses(computed2) {
|
|
4271
|
+
const base = computed2.blocks.get(BASE_KEY8);
|
|
4272
|
+
if (!base) return null;
|
|
4273
|
+
const alignItems = base.decls.get(ALIGN_ITEMS);
|
|
4274
|
+
const justifyItems = base.decls.get(JUSTIFY_ITEMS);
|
|
4275
|
+
const alignContent = base.decls.get(ALIGN_CONTENT);
|
|
4276
|
+
const justifyContent = base.decls.get(JUSTIFY_CONTENT);
|
|
4277
|
+
const next = new Map(base.decls);
|
|
4278
|
+
let collapsed = false;
|
|
4279
|
+
if (samePair(alignItems, justifyItems)) {
|
|
4280
|
+
next.delete(ALIGN_ITEMS);
|
|
4281
|
+
next.delete(JUSTIFY_ITEMS);
|
|
4282
|
+
next.set(PLACE_ITEMS, placeDecl(PLACE_ITEMS, alignItems));
|
|
4283
|
+
collapsed = true;
|
|
4284
|
+
}
|
|
4285
|
+
if (samePair(alignContent, justifyContent)) {
|
|
4286
|
+
next.delete(ALIGN_CONTENT);
|
|
4287
|
+
next.delete(JUSTIFY_CONTENT);
|
|
4288
|
+
next.set(PLACE_CONTENT, placeDecl(PLACE_CONTENT, alignContent));
|
|
4289
|
+
collapsed = true;
|
|
4290
|
+
}
|
|
4291
|
+
if (!collapsed) return null;
|
|
4292
|
+
return withBaseDecls2(computed2, next);
|
|
4293
|
+
}
|
|
4294
|
+
},
|
|
4295
|
+
test: {
|
|
4296
|
+
cases: [
|
|
4297
|
+
{
|
|
4298
|
+
// The matching items pair collapses to a `place-items` decl at the IR level; the minimizing
|
|
4299
|
+
// reverse-emit picks the single utility covering both (`place-items-center`), replacing the
|
|
4300
|
+
// `items-center`+`justify-items-center` pair. `bg-red-200` is preserved.
|
|
4301
|
+
before: '<div className="items-center justify-items-center bg-red-200">box</div>',
|
|
4302
|
+
after: '<div className="bg-red-200 place-items-center">box</div>'
|
|
4303
|
+
}
|
|
4304
|
+
],
|
|
4305
|
+
// Mismatched alignment (align-items != justify-items, no content pair) → nothing collapses.
|
|
4306
|
+
noMatch: ['<div className="items-center justify-items-start bg-red-200">box</div>']
|
|
4307
|
+
}
|
|
4308
|
+
});
|
|
4309
|
+
|
|
4310
|
+
// ../patterns/src/library/compress/scroll-margin-shorthand.pattern.ts
|
|
4311
|
+
init_cjs_shims();
|
|
4312
|
+
var SCROLL_MARGIN_SIDES = [
|
|
4313
|
+
"scroll-margin-top",
|
|
4314
|
+
"scroll-margin-right",
|
|
4315
|
+
"scroll-margin-bottom",
|
|
4316
|
+
"scroll-margin-left"
|
|
4317
|
+
];
|
|
4318
|
+
var SIDE_SET = new Set(SCROLL_MARGIN_SIDES);
|
|
4319
|
+
var BASE_KEY9 = conditionKey(BASE_CONDITION);
|
|
4320
|
+
var SCROLL_MARGIN = "scroll-margin";
|
|
4321
|
+
var NON_COLLAPSIBLE_VALUES3 = /* @__PURE__ */ new Set([
|
|
4322
|
+
"initial",
|
|
4323
|
+
"inherit",
|
|
4324
|
+
"unset",
|
|
4325
|
+
"revert",
|
|
4326
|
+
"revert-layer"
|
|
4327
|
+
]);
|
|
4328
|
+
function analyzeScrollMargin(sm) {
|
|
4329
|
+
const block = sm.blocks.get(BASE_KEY9);
|
|
4330
|
+
if (!block) return null;
|
|
4331
|
+
const sides = [];
|
|
4332
|
+
for (const side of SCROLL_MARGIN_SIDES) {
|
|
4333
|
+
const decl = block.decls.get(side);
|
|
4334
|
+
if (!decl) return null;
|
|
4335
|
+
sides.push(decl);
|
|
4336
|
+
}
|
|
4337
|
+
const important = sides[0].important;
|
|
4338
|
+
if (!sides.every((d3) => d3.important === important)) return null;
|
|
4339
|
+
const value = String(sides[0].value);
|
|
4340
|
+
if (NON_COLLAPSIBLE_VALUES3.has(value)) return null;
|
|
4341
|
+
if (!sides.every((d3) => String(d3.value) === value)) return null;
|
|
4342
|
+
const relative4 = sides.some((d3) => d3.relativeToParent);
|
|
4343
|
+
return { value, important, relative: relative4 };
|
|
4344
|
+
}
|
|
4345
|
+
function withFoldedScrollMargin(sm, fold) {
|
|
4346
|
+
const blocks = /* @__PURE__ */ new Map();
|
|
4347
|
+
for (const [key, block] of sm.blocks) {
|
|
4348
|
+
if (key !== BASE_KEY9) {
|
|
4349
|
+
blocks.set(key, block);
|
|
4350
|
+
continue;
|
|
4351
|
+
}
|
|
4352
|
+
const decls = /* @__PURE__ */ new Map();
|
|
4353
|
+
for (const [prop, decl] of block.decls) {
|
|
4354
|
+
if (SIDE_SET.has(String(prop))) continue;
|
|
4355
|
+
decls.set(prop, decl);
|
|
4356
|
+
}
|
|
4357
|
+
const shorthand = {
|
|
4358
|
+
property: SCROLL_MARGIN,
|
|
4359
|
+
value: fold.value,
|
|
4360
|
+
important: fold.important,
|
|
4361
|
+
relativeToParent: fold.relative,
|
|
4362
|
+
inherited: false
|
|
4363
|
+
// scroll-margin is never inherited
|
|
4364
|
+
};
|
|
4365
|
+
decls.set(shorthand.property, shorthand);
|
|
4366
|
+
blocks.set(key, { condition: block.condition, decls });
|
|
4367
|
+
}
|
|
4368
|
+
return { blocks };
|
|
4369
|
+
}
|
|
4370
|
+
var scrollMarginShorthand = definePattern({
|
|
4371
|
+
name: "scroll-margin-shorthand",
|
|
4372
|
+
category: "compress/scroll-margin-shorthand",
|
|
4373
|
+
safety: 1,
|
|
4374
|
+
doc: {
|
|
4375
|
+
title: "Collapse equal scroll-margin sides into scroll-margin",
|
|
4376
|
+
summary: "An element whose four scroll-margin sides are all equal is rewritten to the single Tailwind scroll-m-* utility (scroll-margin === the four equal sides).",
|
|
4377
|
+
before: '<div class="scroll-mt-4 scroll-mr-4 scroll-mb-4 scroll-ml-4"/>',
|
|
4378
|
+
after: '<div class="scroll-m-4"/>',
|
|
4379
|
+
safetyRationale: "`scroll-margin` is value-identical to four equal scroll-margin sides \u2014 a class-only change. It is safe even on an element with a ref, event handler, dynamic child, or dangerouslySetInnerHTML \u2014 a className rewrite touches none of them; only a dynamic/opaque class list or a combinator-subject class is excluded, so no behaviour or project selector is disturbed."
|
|
3124
4380
|
},
|
|
3125
4381
|
rewrite: {
|
|
3126
4382
|
rewriteClasses(computed2) {
|
|
3127
|
-
const
|
|
3128
|
-
|
|
3129
|
-
const sides = MARGIN_SIDES.map((p2) => base.decls.get(p2));
|
|
3130
|
-
if (sides.some((d3) => d3 === void 0)) return null;
|
|
3131
|
-
const [mt, mr, mb, ml] = sides;
|
|
3132
|
-
if (mt.important || mr.important || mb.important || ml.important) return null;
|
|
3133
|
-
const value = collapseMarginValue(
|
|
3134
|
-
String(mt.value),
|
|
3135
|
-
String(mr.value),
|
|
3136
|
-
String(mb.value),
|
|
3137
|
-
String(ml.value)
|
|
3138
|
-
);
|
|
3139
|
-
const marginDecl = {
|
|
3140
|
-
property: "margin",
|
|
3141
|
-
value,
|
|
3142
|
-
important: false,
|
|
3143
|
-
relativeToParent: mt.relativeToParent || mr.relativeToParent || mb.relativeToParent || ml.relativeToParent,
|
|
3144
|
-
inherited: false
|
|
3145
|
-
// margin is not an inherited property
|
|
3146
|
-
};
|
|
3147
|
-
return withFoldedMargin(computed2, marginDecl);
|
|
4383
|
+
const fold = analyzeScrollMargin(computed2);
|
|
4384
|
+
return fold ? withFoldedScrollMargin(computed2, fold) : null;
|
|
3148
4385
|
}
|
|
3149
4386
|
},
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
4387
|
+
test: {
|
|
4388
|
+
cases: [
|
|
4389
|
+
{
|
|
4390
|
+
// The four equal scroll-margin longhands collapse to a `scroll-margin` decl at the IR level; the
|
|
4391
|
+
// minimizing reverse-emit then picks the single shortest utility (`scroll-m-4`) that reproduces
|
|
4392
|
+
// it, replacing the four `scroll-m{t,r,b,l}-4` tokens. `bg-red-200` is preserved.
|
|
4393
|
+
before: '<div className="scroll-mt-4 scroll-mr-4 scroll-mb-4 scroll-ml-4 bg-red-200">box</div>',
|
|
4394
|
+
after: '<div className="bg-red-200 scroll-m-4">box</div>'
|
|
4395
|
+
}
|
|
4396
|
+
],
|
|
4397
|
+
// Sides differ (top != bottom) → no all-equal collapse.
|
|
4398
|
+
noMatch: ['<div className="scroll-mt-2 scroll-mr-4 scroll-mb-8 scroll-ml-4 bg-red-200">box</div>']
|
|
4399
|
+
}
|
|
3163
4400
|
});
|
|
3164
4401
|
|
|
3165
|
-
// ../patterns/src/compress/padding-shorthand.pattern.ts
|
|
4402
|
+
// ../patterns/src/library/compress/scroll-padding-shorthand.pattern.ts
|
|
3166
4403
|
init_cjs_shims();
|
|
3167
|
-
var
|
|
3168
|
-
"padding-top",
|
|
3169
|
-
"padding-right",
|
|
3170
|
-
"padding-bottom",
|
|
3171
|
-
"padding-left"
|
|
4404
|
+
var SCROLL_PADDING_SIDES = [
|
|
4405
|
+
"scroll-padding-top",
|
|
4406
|
+
"scroll-padding-right",
|
|
4407
|
+
"scroll-padding-bottom",
|
|
4408
|
+
"scroll-padding-left"
|
|
3172
4409
|
];
|
|
3173
|
-
var
|
|
3174
|
-
var
|
|
3175
|
-
|
|
3176
|
-
|
|
4410
|
+
var SIDE_SET2 = new Set(SCROLL_PADDING_SIDES);
|
|
4411
|
+
var BASE_KEY10 = conditionKey(BASE_CONDITION);
|
|
4412
|
+
var SCROLL_PADDING = "scroll-padding";
|
|
4413
|
+
var NON_COLLAPSIBLE_VALUES4 = /* @__PURE__ */ new Set([
|
|
4414
|
+
"initial",
|
|
4415
|
+
"inherit",
|
|
4416
|
+
"unset",
|
|
4417
|
+
"revert",
|
|
4418
|
+
"revert-layer"
|
|
4419
|
+
]);
|
|
4420
|
+
function analyzeScrollPadding(sm) {
|
|
4421
|
+
const block = sm.blocks.get(BASE_KEY10);
|
|
3177
4422
|
if (!block) return null;
|
|
3178
4423
|
const sides = [];
|
|
3179
|
-
for (const side of
|
|
4424
|
+
for (const side of SCROLL_PADDING_SIDES) {
|
|
3180
4425
|
const decl = block.decls.get(side);
|
|
3181
4426
|
if (!decl) return null;
|
|
3182
4427
|
sides.push(decl);
|
|
3183
4428
|
}
|
|
3184
|
-
const
|
|
3185
|
-
if (!(
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
const
|
|
3190
|
-
|
|
3191
|
-
const lv = String(left.value);
|
|
3192
|
-
if (tv !== bv || lv !== rv) return null;
|
|
3193
|
-
const value = tv === lv ? tv : `${tv} ${lv}`;
|
|
3194
|
-
const relative3 = sides.some((d3) => d3.relativeToParent);
|
|
3195
|
-
return { value, important: top.important, relative: relative3 };
|
|
4429
|
+
const important = sides[0].important;
|
|
4430
|
+
if (!sides.every((d3) => d3.important === important)) return null;
|
|
4431
|
+
const value = String(sides[0].value);
|
|
4432
|
+
if (NON_COLLAPSIBLE_VALUES4.has(value)) return null;
|
|
4433
|
+
if (!sides.every((d3) => String(d3.value) === value)) return null;
|
|
4434
|
+
const relative4 = sides.some((d3) => d3.relativeToParent);
|
|
4435
|
+
return { value, important, relative: relative4 };
|
|
3196
4436
|
}
|
|
3197
|
-
|
|
3198
|
-
const n = node;
|
|
3199
|
-
if (n.kind !== "element") return false;
|
|
3200
|
-
const el = n;
|
|
3201
|
-
return !el.meta.hasDangerousHtml && !el.meta.hasSpreadAttrs && !el.isComponent;
|
|
3202
|
-
};
|
|
3203
|
-
function withFoldedPadding(sm, fold) {
|
|
4437
|
+
function withFoldedScrollPadding(sm, fold) {
|
|
3204
4438
|
const blocks = /* @__PURE__ */ new Map();
|
|
3205
4439
|
for (const [key, block] of sm.blocks) {
|
|
3206
|
-
if (key !==
|
|
4440
|
+
if (key !== BASE_KEY10) {
|
|
3207
4441
|
blocks.set(key, block);
|
|
3208
4442
|
continue;
|
|
3209
4443
|
}
|
|
3210
4444
|
const decls = /* @__PURE__ */ new Map();
|
|
3211
4445
|
for (const [prop, decl] of block.decls) {
|
|
3212
|
-
if (
|
|
4446
|
+
if (SIDE_SET2.has(String(prop))) continue;
|
|
3213
4447
|
decls.set(prop, decl);
|
|
3214
4448
|
}
|
|
3215
4449
|
const shorthand = {
|
|
3216
|
-
property:
|
|
4450
|
+
property: SCROLL_PADDING,
|
|
3217
4451
|
value: fold.value,
|
|
3218
4452
|
important: fold.important,
|
|
3219
4453
|
relativeToParent: fold.relative,
|
|
3220
4454
|
inherited: false
|
|
3221
|
-
// padding is never inherited
|
|
4455
|
+
// scroll-padding is never inherited
|
|
3222
4456
|
};
|
|
3223
4457
|
decls.set(shorthand.property, shorthand);
|
|
3224
4458
|
blocks.set(key, { condition: block.condition, decls });
|
|
3225
4459
|
}
|
|
3226
4460
|
return { blocks };
|
|
3227
4461
|
}
|
|
3228
|
-
var
|
|
3229
|
-
name: "padding-shorthand",
|
|
3230
|
-
category: "compress/padding-shorthand",
|
|
4462
|
+
var scrollPaddingShorthand = definePattern({
|
|
4463
|
+
name: "scroll-padding-shorthand",
|
|
4464
|
+
category: "compress/scroll-padding-shorthand",
|
|
3231
4465
|
safety: 1,
|
|
3232
4466
|
doc: {
|
|
3233
|
-
title: "Collapse padding
|
|
3234
|
-
summary: "
|
|
3235
|
-
before: '<div class="pt-4 pr-4 pb-4 pl-4"/>',
|
|
3236
|
-
after: '<div class="p-4"/>',
|
|
3237
|
-
safetyRationale: "
|
|
3238
|
-
},
|
|
3239
|
-
match: {
|
|
3240
|
-
where: [
|
|
3241
|
-
not(hasRef),
|
|
3242
|
-
not(hasEventHandlers),
|
|
3243
|
-
not(hasDynamicChildren),
|
|
3244
|
-
not(hasDynamicClasses),
|
|
3245
|
-
not(targetedByCombinator),
|
|
3246
|
-
isInert
|
|
3247
|
-
]
|
|
4467
|
+
title: "Collapse equal scroll-padding sides into scroll-padding",
|
|
4468
|
+
summary: "An element whose four scroll-padding sides are all equal is rewritten to the single Tailwind scroll-p-* utility (scroll-padding === the four equal sides).",
|
|
4469
|
+
before: '<div class="scroll-pt-4 scroll-pr-4 scroll-pb-4 scroll-pl-4"/>',
|
|
4470
|
+
after: '<div class="scroll-p-4"/>',
|
|
4471
|
+
safetyRationale: "`scroll-padding` is value-identical to four equal scroll-padding sides \u2014 a class-only change. It is safe even on an element with a ref, event handler, dynamic child, or dangerouslySetInnerHTML \u2014 a className rewrite touches none of them; only a dynamic/opaque class list or a combinator-subject class is excluded, so no behaviour or project selector is disturbed."
|
|
3248
4472
|
},
|
|
3249
4473
|
rewrite: {
|
|
3250
4474
|
rewriteClasses(computed2) {
|
|
3251
|
-
const fold =
|
|
3252
|
-
return fold ?
|
|
4475
|
+
const fold = analyzeScrollPadding(computed2);
|
|
4476
|
+
return fold ? withFoldedScrollPadding(computed2, fold) : null;
|
|
3253
4477
|
}
|
|
3254
4478
|
},
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
4479
|
+
test: {
|
|
4480
|
+
cases: [
|
|
4481
|
+
{
|
|
4482
|
+
// The four equal scroll-padding longhands collapse to a `scroll-padding` decl at the IR level;
|
|
4483
|
+
// the minimizing reverse-emit then picks the single shortest utility (`scroll-p-4`) that
|
|
4484
|
+
// reproduces it, replacing the four `scroll-p{t,r,b,l}-4` tokens. `bg-red-200` is preserved.
|
|
4485
|
+
before: '<div className="scroll-pt-4 scroll-pr-4 scroll-pb-4 scroll-pl-4 bg-red-200">box</div>',
|
|
4486
|
+
after: '<div className="bg-red-200 scroll-p-4">box</div>'
|
|
4487
|
+
}
|
|
4488
|
+
],
|
|
4489
|
+
// Sides differ (top != bottom) → no all-equal collapse.
|
|
4490
|
+
noMatch: ['<div className="scroll-pt-2 scroll-pr-4 scroll-pb-8 scroll-pl-4 bg-red-200">box</div>']
|
|
4491
|
+
}
|
|
3268
4492
|
});
|
|
3269
4493
|
|
|
3270
|
-
// ../patterns/src/compress/size-shorthand.pattern.ts
|
|
4494
|
+
// ../patterns/src/library/compress/size-shorthand.pattern.ts
|
|
3271
4495
|
init_cjs_shims();
|
|
3272
4496
|
var WIDTH = "width";
|
|
3273
4497
|
var HEIGHT = "height";
|
|
3274
4498
|
var SIZE = "size";
|
|
3275
|
-
var
|
|
3276
|
-
function asElement4(node) {
|
|
3277
|
-
const n = node;
|
|
3278
|
-
return n.kind === "element" ? n : null;
|
|
3279
|
-
}
|
|
4499
|
+
var NON_COLLAPSIBLE_VALUES5 = /* @__PURE__ */ new Set(["auto", "initial", "unset"]);
|
|
3280
4500
|
function baseBlock(sm) {
|
|
3281
4501
|
return sm.blocks.get(conditionKey(BASE_CONDITION));
|
|
3282
4502
|
}
|
|
3283
|
-
var hasDangerousHtml3 = (node) => asElement4(node)?.meta.hasDangerousHtml ?? false;
|
|
3284
4503
|
function withSizeShorthand(sm, value, important) {
|
|
3285
4504
|
const baseKey = conditionKey(BASE_CONDITION);
|
|
3286
4505
|
const blocks = /* @__PURE__ */ new Map();
|
|
@@ -3299,7 +4518,7 @@ function withSizeShorthand(sm, value, important) {
|
|
|
3299
4518
|
}
|
|
3300
4519
|
return { blocks };
|
|
3301
4520
|
}
|
|
3302
|
-
var sizeShorthand =
|
|
4521
|
+
var sizeShorthand = definePattern({
|
|
3303
4522
|
name: "size-shorthand",
|
|
3304
4523
|
category: "compress/size-shorthand",
|
|
3305
4524
|
safety: 2,
|
|
@@ -3308,17 +4527,7 @@ var sizeShorthand = pattern({
|
|
|
3308
4527
|
summary: "An element whose computed width and height are equal is rewritten to the single Tailwind size-* utility (size-* === width + height at the same value).",
|
|
3309
4528
|
before: '<div style="width:1rem;height:1rem"/>',
|
|
3310
4529
|
after: '<div class="size-4"/>',
|
|
3311
|
-
safetyRationale: "size
|
|
3312
|
-
},
|
|
3313
|
-
match: {
|
|
3314
|
-
where: [
|
|
3315
|
-
not(hasRef),
|
|
3316
|
-
not(hasEventHandlers),
|
|
3317
|
-
not(hasDynamicChildren),
|
|
3318
|
-
not(hasDangerousHtml3),
|
|
3319
|
-
not(hasDynamicClasses),
|
|
3320
|
-
not(targetedByCombinator)
|
|
3321
|
-
]
|
|
4530
|
+
safetyRationale: "`size-*` is value-identical to equal width+height \u2014 a class-only change. It is safe even on an element with a ref, event handler, dynamic child, or dangerouslySetInnerHTML \u2014 a className rewrite touches none of them; only a dynamic/opaque class list or a combinator-subject class is excluded, so no behaviour or project selector is disturbed."
|
|
3322
4531
|
},
|
|
3323
4532
|
rewrite: {
|
|
3324
4533
|
rewriteClasses(computed2) {
|
|
@@ -3327,43 +4536,91 @@ var sizeShorthand = pattern({
|
|
|
3327
4536
|
const h2 = base?.decls.get(HEIGHT);
|
|
3328
4537
|
if (!w2 || !h2) return null;
|
|
3329
4538
|
if (w2.important !== h2.important) return null;
|
|
3330
|
-
if (
|
|
4539
|
+
if (NON_COLLAPSIBLE_VALUES5.has(String(w2.value))) return null;
|
|
3331
4540
|
if (w2.value !== h2.value) return null;
|
|
3332
4541
|
return withSizeShorthand(computed2, String(w2.value), w2.important);
|
|
3333
4542
|
}
|
|
3334
4543
|
},
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
4544
|
+
test: {
|
|
4545
|
+
cases: [
|
|
4546
|
+
{
|
|
4547
|
+
// Equal width/height collapse to a `size` decl at the IR level; the minimizing reverse-emit
|
|
4548
|
+
// expands `size` back to width+height, finds the single utility covering both (`size-10`), and
|
|
4549
|
+
// replaces the `h-10`+`w-10` pair with it. `bg-red-200` is preserved.
|
|
4550
|
+
before: '<div className="h-10 w-10 bg-red-200">box</div>',
|
|
4551
|
+
after: '<div className="bg-red-200 size-10">box</div>'
|
|
4552
|
+
}
|
|
4553
|
+
],
|
|
4554
|
+
// Width and height differ → no equal-axis collapse.
|
|
4555
|
+
noMatch: ['<div className="h-10 w-20 bg-red-200">box</div>']
|
|
4556
|
+
}
|
|
3348
4557
|
});
|
|
3349
4558
|
|
|
3350
4559
|
// ../patterns/src/_registry.generated.ts
|
|
3351
4560
|
var builtinPatterns = [
|
|
4561
|
+
displayContentsWrapper,
|
|
3352
4562
|
emptyStyleDiv,
|
|
3353
4563
|
flexCenterWrapper,
|
|
4564
|
+
inlineFlexCenterWrapper,
|
|
3354
4565
|
nestedFlexMerge,
|
|
4566
|
+
nestedGridMerge,
|
|
3355
4567
|
passthroughWrapper,
|
|
3356
4568
|
redundantFragment,
|
|
4569
|
+
redundantInlineWrapper,
|
|
4570
|
+
borderRadiusShorthand,
|
|
4571
|
+
borderShorthand,
|
|
3357
4572
|
dedupeClasses,
|
|
4573
|
+
gapShorthand,
|
|
3358
4574
|
insetShorthand,
|
|
3359
4575
|
marginShorthand,
|
|
4576
|
+
overflowShorthand,
|
|
4577
|
+
overscrollBehaviorShorthand,
|
|
3360
4578
|
paddingShorthand,
|
|
4579
|
+
placeShorthand,
|
|
4580
|
+
scrollMarginShorthand,
|
|
4581
|
+
scrollPaddingShorthand,
|
|
3361
4582
|
sizeShorthand
|
|
3362
4583
|
];
|
|
3363
4584
|
|
|
3364
4585
|
// ../resolver-css/src/index.ts
|
|
3365
4586
|
init_cjs_shims();
|
|
3366
|
-
|
|
4587
|
+
|
|
4588
|
+
// ../resolver-css/src/constants.ts
|
|
4589
|
+
init_cjs_shims();
|
|
4590
|
+
var CSS_RESOLVER_ID = "css";
|
|
4591
|
+
var CSS_RESOLVER_PROVIDER = "custom-css";
|
|
4592
|
+
var ENGINE_VERSION = "css-index@1";
|
|
4593
|
+
var STRUCTURAL_PSEUDOS = /* @__PURE__ */ new Set([
|
|
4594
|
+
":nth-child",
|
|
4595
|
+
":nth-last-child",
|
|
4596
|
+
":first-child",
|
|
4597
|
+
":last-child",
|
|
4598
|
+
":only-child",
|
|
4599
|
+
":nth-of-type",
|
|
4600
|
+
":nth-last-of-type",
|
|
4601
|
+
":first-of-type",
|
|
4602
|
+
":last-of-type",
|
|
4603
|
+
":only-of-type"
|
|
4604
|
+
]);
|
|
4605
|
+
var FUNCTIONAL_PSEUDOS = /* @__PURE__ */ new Set([
|
|
4606
|
+
":not",
|
|
4607
|
+
":is",
|
|
4608
|
+
":where",
|
|
4609
|
+
":has",
|
|
4610
|
+
":matches"
|
|
4611
|
+
]);
|
|
4612
|
+
var LEGACY_PSEUDO_ELEMENTS = /* @__PURE__ */ new Set([
|
|
4613
|
+
":before",
|
|
4614
|
+
":after",
|
|
4615
|
+
":first-line",
|
|
4616
|
+
":first-letter"
|
|
4617
|
+
]);
|
|
4618
|
+
|
|
4619
|
+
// ../resolver-css/src/resolver.ts
|
|
4620
|
+
init_cjs_shims();
|
|
4621
|
+
|
|
4622
|
+
// ../resolver-css/src/engine.ts
|
|
4623
|
+
init_cjs_shims();
|
|
3367
4624
|
var import_node_module = require("module");
|
|
3368
4625
|
var path2 = __toESM(require("path"), 1);
|
|
3369
4626
|
function moduleBase() {
|
|
@@ -3401,34 +4658,82 @@ function ensurePostcss(projectRoot) {
|
|
|
3401
4658
|
pc = engine.parse;
|
|
3402
4659
|
sp = engine.selectorParser;
|
|
3403
4660
|
}
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
"
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
4661
|
+
|
|
4662
|
+
// ../resolver-css/src/postcss-helpers.ts
|
|
4663
|
+
init_cjs_shims();
|
|
4664
|
+
function mediaContext(rule) {
|
|
4665
|
+
const parts = [];
|
|
4666
|
+
let skip = false;
|
|
4667
|
+
let parent = rule.parent;
|
|
4668
|
+
while (parent && parent.type === "atrule") {
|
|
4669
|
+
const at = parent;
|
|
4670
|
+
const name = at.name.toLowerCase();
|
|
4671
|
+
if (name === "media") parts.unshift(at.params.trim().replace(/\s+/g, " "));
|
|
4672
|
+
else if (name === "keyframes" || name.endsWith("keyframes") || name === "font-face") skip = true;
|
|
4673
|
+
parent = parent.parent;
|
|
4674
|
+
}
|
|
4675
|
+
return { media: parts.join(" and "), skip };
|
|
4676
|
+
}
|
|
4677
|
+
function collectDecls(rule) {
|
|
4678
|
+
const out = [];
|
|
4679
|
+
for (const node of rule.nodes) {
|
|
4680
|
+
if (node.type === "decl") out.push([node.prop, node.value, node.important === true]);
|
|
4681
|
+
}
|
|
4682
|
+
return out;
|
|
4683
|
+
}
|
|
4684
|
+
|
|
4685
|
+
// ../resolver-css/src/misc-helpers.ts
|
|
4686
|
+
init_cjs_shims();
|
|
4687
|
+
var import_node_fs = require("fs");
|
|
4688
|
+
function isPlainClassToken(token) {
|
|
4689
|
+
return token.length > 0 && !/[\s.#>+~:[\]()]/.test(token);
|
|
4690
|
+
}
|
|
4691
|
+
function readCssPath(path7) {
|
|
4692
|
+
try {
|
|
4693
|
+
return { id: path7, css: (0, import_node_fs.readFileSync)(path7, "utf8") };
|
|
4694
|
+
} catch (cause) {
|
|
4695
|
+
throw new Error(`resolver-css: cannot read CSS file "${path7}"`, { cause });
|
|
4696
|
+
}
|
|
4697
|
+
}
|
|
4698
|
+
function deriveFingerprint(provider, files) {
|
|
4699
|
+
const parts = files.map((f) => `${f.id}:${f.css.length}`).sort();
|
|
4700
|
+
return `${provider}/${ENGINE_VERSION}::${parts.join("|")}`;
|
|
4701
|
+
}
|
|
4702
|
+
|
|
4703
|
+
// ../resolver-css/src/selector-helpers.ts
|
|
4704
|
+
init_cjs_shims();
|
|
4705
|
+
function splitCompounds(selector) {
|
|
4706
|
+
const compounds = [];
|
|
4707
|
+
let current = [];
|
|
4708
|
+
let leftCombinator = null;
|
|
4709
|
+
for (const node of selector.nodes) {
|
|
4710
|
+
if (sp.isCombinator(node)) {
|
|
4711
|
+
compounds.push({ leftCombinator, nodes: current });
|
|
4712
|
+
current = [];
|
|
4713
|
+
leftCombinator = combinatorValue(node);
|
|
4714
|
+
} else {
|
|
4715
|
+
current.push(node);
|
|
4716
|
+
}
|
|
4717
|
+
}
|
|
4718
|
+
compounds.push({ leftCombinator, nodes: current });
|
|
4719
|
+
return compounds;
|
|
4720
|
+
}
|
|
4721
|
+
function combinatorValue(node) {
|
|
4722
|
+
const v2 = node.value;
|
|
4723
|
+
return v2.trim() === "" ? " " : v2.trim();
|
|
4724
|
+
}
|
|
4725
|
+
function pseudoName(node) {
|
|
4726
|
+
return node.value.toLowerCase();
|
|
4727
|
+
}
|
|
4728
|
+
function isPseudoElement(node) {
|
|
4729
|
+
return sp.isPseudoElement(node) || LEGACY_PSEUDO_ELEMENTS.has(pseudoName(node));
|
|
4730
|
+
}
|
|
4731
|
+
function normalizePseudoElement(node) {
|
|
4732
|
+
const name = pseudoName(node);
|
|
4733
|
+
return name.startsWith("::") ? name : `::${name.replace(/^:/, "")}`;
|
|
4734
|
+
}
|
|
4735
|
+
|
|
4736
|
+
// ../resolver-css/src/resolver.ts
|
|
3432
4737
|
var CustomCSSResolver = class {
|
|
3433
4738
|
id = CSS_RESOLVER_ID;
|
|
3434
4739
|
provider = CSS_RESOLVER_PROVIDER;
|
|
@@ -3478,7 +4783,7 @@ var CustomCSSResolver = class {
|
|
|
3478
4783
|
const remaining = /* @__PURE__ */ new Map();
|
|
3479
4784
|
for (const [ck, block] of norm.normalizeStyleMap(styles).blocks) {
|
|
3480
4785
|
for (const [prop, decl] of block.decls) {
|
|
3481
|
-
remaining.set(`${ck}
|
|
4786
|
+
remaining.set(`${ck} ${prop}`, String(decl.value));
|
|
3482
4787
|
}
|
|
3483
4788
|
}
|
|
3484
4789
|
if (remaining.size === 0) return { classes: [], exact: true, warnings: [] };
|
|
@@ -3498,6 +4803,15 @@ var CustomCSSResolver = class {
|
|
|
3498
4803
|
}
|
|
3499
4804
|
return { classes, exact: remaining.size === 0, warnings: [] };
|
|
3500
4805
|
}
|
|
4806
|
+
/**
|
|
4807
|
+
* Return a CSS stylesheet defining the given class tokens, so a verifier can render a subtree with
|
|
4808
|
+
* the project's real styling applied. The source stylesheets ARE the definition, so we hand back
|
|
4809
|
+
* their concatenation verbatim (every relevant rule — including combinator/structural selectors —
|
|
4810
|
+
* is preserved). `classes` is accepted for interface parity but the full source is always returned.
|
|
4811
|
+
*/
|
|
4812
|
+
cssFor(_classes) {
|
|
4813
|
+
return this.#files.map((f) => f.css).join("\n");
|
|
4814
|
+
}
|
|
3501
4815
|
selectorUsage(token) {
|
|
3502
4816
|
const u2 = this.#usage.get(token);
|
|
3503
4817
|
if (!u2) {
|
|
@@ -3682,87 +4996,79 @@ var CustomCSSResolver = class {
|
|
|
3682
4996
|
if (this.#reverse) return this.#reverse;
|
|
3683
4997
|
const out = [];
|
|
3684
4998
|
for (const token of this.#classIndex.keys()) {
|
|
3685
|
-
const styles = this.#resolveTokens([token], [token]);
|
|
3686
|
-
const keyed = /* @__PURE__ */ new Map();
|
|
3687
|
-
for (const [ck, block] of styles.blocks) {
|
|
3688
|
-
for (const [prop, decl] of block.decls) keyed.set(`${ck}
|
|
3689
|
-
}
|
|
3690
|
-
if (keyed.size > 0) out.push({ token, keyed });
|
|
3691
|
-
}
|
|
3692
|
-
out.sort((a, b3) => b3.keyed.size - a.keyed.size);
|
|
3693
|
-
this.#reverse = out;
|
|
3694
|
-
return out;
|
|
3695
|
-
}
|
|
3696
|
-
};
|
|
3697
|
-
function createCssResolver(cssFiles = [], options) {
|
|
3698
|
-
return new CustomCSSResolver(cssFiles, options);
|
|
3699
|
-
}
|
|
3700
|
-
function splitCompounds(selector) {
|
|
3701
|
-
const compounds = [];
|
|
3702
|
-
let current = [];
|
|
3703
|
-
let leftCombinator = null;
|
|
3704
|
-
for (const node of selector.nodes) {
|
|
3705
|
-
if (sp.isCombinator(node)) {
|
|
3706
|
-
compounds.push({ leftCombinator, nodes: current });
|
|
3707
|
-
current = [];
|
|
3708
|
-
leftCombinator = combinatorValue(node);
|
|
3709
|
-
} else {
|
|
3710
|
-
current.push(node);
|
|
4999
|
+
const styles = this.#resolveTokens([token], [token]);
|
|
5000
|
+
const keyed = /* @__PURE__ */ new Map();
|
|
5001
|
+
for (const [ck, block] of styles.blocks) {
|
|
5002
|
+
for (const [prop, decl] of block.decls) keyed.set(`${ck} ${prop}`, String(decl.value));
|
|
5003
|
+
}
|
|
5004
|
+
if (keyed.size > 0) out.push({ token, keyed });
|
|
3711
5005
|
}
|
|
5006
|
+
out.sort((a, b3) => b3.keyed.size - a.keyed.size);
|
|
5007
|
+
this.#reverse = out;
|
|
5008
|
+
return out;
|
|
3712
5009
|
}
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
function combinatorValue(node) {
|
|
3717
|
-
const v2 = node.value;
|
|
3718
|
-
return v2.trim() === "" ? " " : v2.trim();
|
|
3719
|
-
}
|
|
3720
|
-
function pseudoName(node) {
|
|
3721
|
-
return node.value.toLowerCase();
|
|
3722
|
-
}
|
|
3723
|
-
function isPseudoElement(node) {
|
|
3724
|
-
return sp.isPseudoElement(node) || LEGACY_PSEUDO_ELEMENTS.has(pseudoName(node));
|
|
3725
|
-
}
|
|
3726
|
-
function normalizePseudoElement(node) {
|
|
3727
|
-
const name = pseudoName(node);
|
|
3728
|
-
return name.startsWith("::") ? name : `::${name.replace(/^:/, "")}`;
|
|
5010
|
+
};
|
|
5011
|
+
function createCssResolver(cssFiles = [], options) {
|
|
5012
|
+
return new CustomCSSResolver(cssFiles, options);
|
|
3729
5013
|
}
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
5014
|
+
|
|
5015
|
+
// ../resolver-tailwind/src/index.ts
|
|
5016
|
+
init_cjs_shims();
|
|
5017
|
+
|
|
5018
|
+
// ../resolver-tailwind/src/tailwind/resolver.ts
|
|
5019
|
+
init_cjs_shims();
|
|
5020
|
+
|
|
5021
|
+
// ../resolver-tailwind/src/tailwind/emit.ts
|
|
5022
|
+
init_cjs_shims();
|
|
5023
|
+
|
|
5024
|
+
// ../resolver-tailwind/src/tailwind/fingerprint.ts
|
|
5025
|
+
init_cjs_shims();
|
|
5026
|
+
function fnv1a(input) {
|
|
5027
|
+
let h2 = 2166136261;
|
|
5028
|
+
for (let i = 0; i < input.length; i += 1) {
|
|
5029
|
+
h2 ^= input.charCodeAt(i);
|
|
5030
|
+
h2 = Math.imul(h2, 16777619);
|
|
3740
5031
|
}
|
|
3741
|
-
return
|
|
5032
|
+
return (h2 >>> 0).toString(16).padStart(8, "0");
|
|
3742
5033
|
}
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
|
|
5034
|
+
|
|
5035
|
+
// ../resolver-tailwind/src/tailwind/emit.ts
|
|
5036
|
+
function expandForEmit(norm, prop, value, important) {
|
|
5037
|
+
const pairsFor = (p2, v2) => norm.normalizeDeclaration(p2, v2, important).map((d3) => [d3.property, String(d3.value)]);
|
|
5038
|
+
if (prop === "size") {
|
|
5039
|
+
return [...pairsFor("width", value), ...pairsFor("height", value)];
|
|
3747
5040
|
}
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
5041
|
+
if (prop === "inset-block" || prop === "inset-inline") {
|
|
5042
|
+
const parts = value.split(/\s+/).filter((s) => s.length > 0);
|
|
5043
|
+
const a = parts[0] ?? value;
|
|
5044
|
+
const b3 = parts[1] ?? a;
|
|
5045
|
+
const sides = prop === "inset-block" ? ["top", "bottom"] : ["left", "right"];
|
|
5046
|
+
return [...pairsFor(sides[0], a), ...pairsFor(sides[1], b3)];
|
|
5047
|
+
}
|
|
5048
|
+
return pairsFor(prop, value);
|
|
3752
5049
|
}
|
|
3753
|
-
function
|
|
5050
|
+
function synthesizeResidual(remaining, ctx) {
|
|
5051
|
+
if (remaining.size === 0) return void 0;
|
|
5052
|
+
const norm = ctx.normalizer ?? normalizer;
|
|
5053
|
+
const decls = /* @__PURE__ */ new Map();
|
|
5054
|
+
for (const [prop, value] of remaining) {
|
|
5055
|
+
for (const decl of norm.normalizeDeclaration(String(prop), value, false)) {
|
|
5056
|
+
decls.set(decl.property, decl);
|
|
5057
|
+
}
|
|
5058
|
+
}
|
|
5059
|
+
const block = { condition: BASE_CONDITION, decls };
|
|
5060
|
+
const styleMap = { blocks: /* @__PURE__ */ new Map([[conditionKey(BASE_CONDITION), block]]) };
|
|
5061
|
+
const css = [...remaining].map(([p2, v2]) => `${p2}:${v2}`).join(";");
|
|
5062
|
+
const className = `df-${fnv1a(css)}`;
|
|
5063
|
+
const synthetic = { className, decls: styleMap, css: `.${className}{${css}}` };
|
|
3754
5064
|
try {
|
|
3755
|
-
|
|
3756
|
-
} catch
|
|
3757
|
-
throw new Error(`resolver-css: cannot read CSS file "${path6}"`, { cause });
|
|
5065
|
+
ctx.sink.register(synthetic);
|
|
5066
|
+
} catch {
|
|
3758
5067
|
}
|
|
3759
|
-
|
|
3760
|
-
function deriveFingerprint(provider, files) {
|
|
3761
|
-
const parts = files.map((f) => `${f.id}:${f.css.length}`).sort();
|
|
3762
|
-
return `${provider}/${ENGINE_VERSION}::${parts.join("|")}`;
|
|
5068
|
+
return synthetic;
|
|
3763
5069
|
}
|
|
3764
5070
|
|
|
3765
|
-
// ../resolver-tailwind/src/
|
|
5071
|
+
// ../resolver-tailwind/src/tailwind/engine.ts
|
|
3766
5072
|
init_cjs_shims();
|
|
3767
5073
|
var import_node_module2 = require("module");
|
|
3768
5074
|
var path3 = __toESM(require("path"), 1);
|
|
@@ -3811,6 +5117,12 @@ function loadEngine(options) {
|
|
|
3811
5117
|
return null;
|
|
3812
5118
|
}
|
|
3813
5119
|
}
|
|
5120
|
+
|
|
5121
|
+
// ../resolver-tailwind/src/tailwind/extract.ts
|
|
5122
|
+
init_cjs_shims();
|
|
5123
|
+
|
|
5124
|
+
// ../resolver-tailwind/src/tailwind/selector.ts
|
|
5125
|
+
init_cjs_shims();
|
|
3814
5126
|
var LEGACY_PSEUDO_ELEMENTS2 = /* @__PURE__ */ new Set([
|
|
3815
5127
|
":before",
|
|
3816
5128
|
":after",
|
|
@@ -3857,6 +5169,26 @@ function makeCondition(media, states, pseudoElement) {
|
|
|
3857
5169
|
pseudoElement
|
|
3858
5170
|
};
|
|
3859
5171
|
}
|
|
5172
|
+
function unescapeClass(selector) {
|
|
5173
|
+
const sel = selector.trim();
|
|
5174
|
+
if (sel[0] !== ".") return null;
|
|
5175
|
+
let out = "";
|
|
5176
|
+
for (let i = 1; i < sel.length; i += 1) {
|
|
5177
|
+
const c = sel[i];
|
|
5178
|
+
if (c === "\\") {
|
|
5179
|
+
i += 1;
|
|
5180
|
+
if (i < sel.length) out += sel[i];
|
|
5181
|
+
continue;
|
|
5182
|
+
}
|
|
5183
|
+
if (c === ":" || c === "." || c === "[" || c === " " || c === ">" || c === "+" || c === "~" || c === ",") {
|
|
5184
|
+
return null;
|
|
5185
|
+
}
|
|
5186
|
+
out += c;
|
|
5187
|
+
}
|
|
5188
|
+
return out.length > 0 ? out : null;
|
|
5189
|
+
}
|
|
5190
|
+
|
|
5191
|
+
// ../resolver-tailwind/src/tailwind/extract.ts
|
|
3860
5192
|
function collectRules(node, mediaStack, inUnsupportedAtRule, out) {
|
|
3861
5193
|
if (node.type === "rule") {
|
|
3862
5194
|
out.push({ rule: node, media: mediaStack, unsupported: inUnsupportedAtRule });
|
|
@@ -3896,9 +5228,33 @@ function extractToken(token, nodes) {
|
|
|
3896
5228
|
const mediaQuery = media.join(" and ");
|
|
3897
5229
|
blocks.push({ condition: makeCondition(mediaQuery, parsed.states, parsed.pseudoElement), decls });
|
|
3898
5230
|
}
|
|
3899
|
-
const
|
|
3900
|
-
return { blocks, produced: true, opaque };
|
|
5231
|
+
const opaque2 = sawComplex && blocks.length === 0 ? { token, reason: "combinator-variant", detail: "utility targets descendants/siblings, not its own box" } : void 0;
|
|
5232
|
+
return { blocks, produced: true, opaque: opaque2 };
|
|
5233
|
+
}
|
|
5234
|
+
|
|
5235
|
+
// ../resolver-tailwind/src/tailwind/serialize.ts
|
|
5236
|
+
init_cjs_shims();
|
|
5237
|
+
function serializeCssNode(node) {
|
|
5238
|
+
if (node.type === "decl") {
|
|
5239
|
+
const d3 = node;
|
|
5240
|
+
if (typeof d3.value !== "string") return "";
|
|
5241
|
+
return `${d3.prop}:${d3.value}${d3.important === true ? " !important" : ""}`;
|
|
5242
|
+
}
|
|
5243
|
+
if (node.type === "rule") {
|
|
5244
|
+
const r2 = node;
|
|
5245
|
+
const body = (r2.nodes ?? []).map((c) => serializeCssNode(c)).filter((s) => s.length > 0).join(";");
|
|
5246
|
+
return `${r2.selector}{${body}}`;
|
|
5247
|
+
}
|
|
5248
|
+
if (node.type === "atrule") {
|
|
5249
|
+
const a = node;
|
|
5250
|
+
const body = (a.nodes ?? []).map((c) => serializeCssNode(c)).filter((s) => s.length > 0).join("");
|
|
5251
|
+
return `@${a.name} ${a.params}{${body}}`;
|
|
5252
|
+
}
|
|
5253
|
+
return "";
|
|
3901
5254
|
}
|
|
5255
|
+
|
|
5256
|
+
// ../resolver-tailwind/src/tailwind/stylemap.ts
|
|
5257
|
+
init_cjs_shims();
|
|
3902
5258
|
function buildStyleMap(blockMaps) {
|
|
3903
5259
|
if (blockMaps.size === 0) return emptyStyleMap();
|
|
3904
5260
|
const blocks = /* @__PURE__ */ new Map();
|
|
@@ -3921,6 +5277,9 @@ function shadowedBy(prev) {
|
|
|
3921
5277
|
add(prev.origin);
|
|
3922
5278
|
return out.length > 0 ? out : void 0;
|
|
3923
5279
|
}
|
|
5280
|
+
|
|
5281
|
+
// ../resolver-tailwind/src/tailwind/usage.ts
|
|
5282
|
+
init_cjs_shims();
|
|
3924
5283
|
var OPAQUE_USAGE = {
|
|
3925
5284
|
asSubject: true,
|
|
3926
5285
|
asAncestor: true,
|
|
@@ -3939,14 +5298,8 @@ var DROPPABLE_USAGE = {
|
|
|
3939
5298
|
asStructural: false,
|
|
3940
5299
|
droppable: true
|
|
3941
5300
|
};
|
|
3942
|
-
|
|
3943
|
-
|
|
3944
|
-
for (let i = 0; i < input.length; i += 1) {
|
|
3945
|
-
h2 ^= input.charCodeAt(i);
|
|
3946
|
-
h2 = Math.imul(h2, 16777619);
|
|
3947
|
-
}
|
|
3948
|
-
return (h2 >>> 0).toString(16).padStart(8, "0");
|
|
3949
|
-
}
|
|
5301
|
+
|
|
5302
|
+
// ../resolver-tailwind/src/tailwind/resolver.ts
|
|
3950
5303
|
var TailwindResolver = class {
|
|
3951
5304
|
id = "tailwind";
|
|
3952
5305
|
provider;
|
|
@@ -3992,14 +5345,14 @@ var TailwindResolver = class {
|
|
|
3992
5345
|
const blockMaps = /* @__PURE__ */ new Map();
|
|
3993
5346
|
const resolved = [];
|
|
3994
5347
|
const unknown = [];
|
|
3995
|
-
const
|
|
5348
|
+
const opaque2 = [];
|
|
3996
5349
|
input.classes.forEach((token, tokenIndex) => {
|
|
3997
5350
|
const extracted = this.#extract(token);
|
|
3998
5351
|
if (!extracted.produced) {
|
|
3999
5352
|
unknown.push(token);
|
|
4000
5353
|
return;
|
|
4001
5354
|
}
|
|
4002
|
-
if (extracted.opaque)
|
|
5355
|
+
if (extracted.opaque) opaque2.push(extracted.opaque);
|
|
4003
5356
|
if (extracted.blocks.length === 0) return;
|
|
4004
5357
|
const origin = { kind: "class", tokenIndex, className: token };
|
|
4005
5358
|
let contributed = false;
|
|
@@ -4025,7 +5378,7 @@ var TailwindResolver = class {
|
|
|
4025
5378
|
styles: buildStyleMap(blockMaps),
|
|
4026
5379
|
resolved,
|
|
4027
5380
|
unknown,
|
|
4028
|
-
opaque,
|
|
5381
|
+
opaque: opaque2,
|
|
4029
5382
|
warnings: []
|
|
4030
5383
|
};
|
|
4031
5384
|
this.#resolveCache.set(key, result);
|
|
@@ -4121,6 +5474,21 @@ var TailwindResolver = class {
|
|
|
4121
5474
|
const residual = synthesizeResidual(remaining, ctx);
|
|
4122
5475
|
return residual ? { classes, residual, exact, warnings: [] } : { classes, exact, warnings: [] };
|
|
4123
5476
|
}
|
|
5477
|
+
/**
|
|
5478
|
+
* Generate a CSS stylesheet that defines `classes`, so a verifier can render a subtree with the
|
|
5479
|
+
* real Tailwind styling applied. Backed by the same engine `resolve` uses (`generate(candidates)`),
|
|
5480
|
+
* serialized to plain CSS. Returns `''` when the engine is unavailable or generates nothing.
|
|
5481
|
+
*/
|
|
5482
|
+
cssFor(classes) {
|
|
5483
|
+
if (!this.#engine) return "";
|
|
5484
|
+
const tokens = [...new Set(classes)].filter((c) => c.length > 0);
|
|
5485
|
+
if (tokens.length === 0) return "";
|
|
5486
|
+
try {
|
|
5487
|
+
return this.#engine.generate(tokens).map((n) => serializeCssNode(n)).filter((s) => s.length > 0).join("\n");
|
|
5488
|
+
} catch {
|
|
5489
|
+
return "";
|
|
5490
|
+
}
|
|
5491
|
+
}
|
|
4124
5492
|
selectorUsage(token) {
|
|
4125
5493
|
const ex = this.#extract(token);
|
|
4126
5494
|
if (!ex.produced || ex.opaque) return OPAQUE_USAGE;
|
|
@@ -4129,58 +5497,6 @@ var TailwindResolver = class {
|
|
|
4129
5497
|
return DROPPABLE_USAGE;
|
|
4130
5498
|
}
|
|
4131
5499
|
};
|
|
4132
|
-
function expandForEmit(norm, prop, value, important) {
|
|
4133
|
-
const pairsFor = (p2, v2) => norm.normalizeDeclaration(p2, v2, important).map((d3) => [d3.property, String(d3.value)]);
|
|
4134
|
-
if (prop === "size") {
|
|
4135
|
-
return [...pairsFor("width", value), ...pairsFor("height", value)];
|
|
4136
|
-
}
|
|
4137
|
-
if (prop === "inset-block" || prop === "inset-inline") {
|
|
4138
|
-
const parts = value.split(/\s+/).filter((s) => s.length > 0);
|
|
4139
|
-
const a = parts[0] ?? value;
|
|
4140
|
-
const b3 = parts[1] ?? a;
|
|
4141
|
-
const sides = prop === "inset-block" ? ["top", "bottom"] : ["left", "right"];
|
|
4142
|
-
return [...pairsFor(sides[0], a), ...pairsFor(sides[1], b3)];
|
|
4143
|
-
}
|
|
4144
|
-
return pairsFor(prop, value);
|
|
4145
|
-
}
|
|
4146
|
-
function synthesizeResidual(remaining, ctx) {
|
|
4147
|
-
if (remaining.size === 0) return void 0;
|
|
4148
|
-
const norm = ctx.normalizer ?? normalizer;
|
|
4149
|
-
const decls = /* @__PURE__ */ new Map();
|
|
4150
|
-
for (const [prop, value] of remaining) {
|
|
4151
|
-
for (const decl of norm.normalizeDeclaration(String(prop), value, false)) {
|
|
4152
|
-
decls.set(decl.property, decl);
|
|
4153
|
-
}
|
|
4154
|
-
}
|
|
4155
|
-
const block = { condition: BASE_CONDITION, decls };
|
|
4156
|
-
const styleMap = { blocks: /* @__PURE__ */ new Map([[conditionKey(BASE_CONDITION), block]]) };
|
|
4157
|
-
const css = [...remaining].map(([p2, v2]) => `${p2}:${v2}`).join(";");
|
|
4158
|
-
const className = `df-${fnv1a(css)}`;
|
|
4159
|
-
const synthetic = { className, decls: styleMap, css: `.${className}{${css}}` };
|
|
4160
|
-
try {
|
|
4161
|
-
ctx.sink.register(synthetic);
|
|
4162
|
-
} catch {
|
|
4163
|
-
}
|
|
4164
|
-
return synthetic;
|
|
4165
|
-
}
|
|
4166
|
-
function unescapeClass(selector) {
|
|
4167
|
-
const sel = selector.trim();
|
|
4168
|
-
if (sel[0] !== ".") return null;
|
|
4169
|
-
let out = "";
|
|
4170
|
-
for (let i = 1; i < sel.length; i += 1) {
|
|
4171
|
-
const c = sel[i];
|
|
4172
|
-
if (c === "\\") {
|
|
4173
|
-
i += 1;
|
|
4174
|
-
if (i < sel.length) out += sel[i];
|
|
4175
|
-
continue;
|
|
4176
|
-
}
|
|
4177
|
-
if (c === ":" || c === "." || c === "[" || c === " " || c === ">" || c === "+" || c === "~" || c === ",") {
|
|
4178
|
-
return null;
|
|
4179
|
-
}
|
|
4180
|
-
out += c;
|
|
4181
|
-
}
|
|
4182
|
-
return out.length > 0 ? out : null;
|
|
4183
|
-
}
|
|
4184
5500
|
function createTailwindResolver(config) {
|
|
4185
5501
|
return new TailwindResolver(config);
|
|
4186
5502
|
}
|
|
@@ -4255,66 +5571,68 @@ function createTransform(options) {
|
|
|
4255
5571
|
const projectRoot = options.projectRoot ?? process.cwd();
|
|
4256
5572
|
const resolver = buildResolver(options.provider, options.css, projectRoot);
|
|
4257
5573
|
const patterns = selectPatterns(options.passes);
|
|
5574
|
+
function prepare(code, id, kind, gate) {
|
|
5575
|
+
const parsed = createJsxFrontend().parse(code, {
|
|
5576
|
+
id,
|
|
5577
|
+
kind,
|
|
5578
|
+
resolver,
|
|
5579
|
+
normalizer,
|
|
5580
|
+
config: {},
|
|
5581
|
+
onDiagnostic: () => {
|
|
5582
|
+
}
|
|
5583
|
+
});
|
|
5584
|
+
const doc = parsed.doc;
|
|
5585
|
+
const nodesIn = doc.nodes.size;
|
|
5586
|
+
for (const node of doc.nodes.values()) node.meta.safetyFloor = 3;
|
|
5587
|
+
const ctx = {
|
|
5588
|
+
doc,
|
|
5589
|
+
safetyCeiling: options.safety,
|
|
5590
|
+
normalizer,
|
|
5591
|
+
// Real CSS-selector-safety index from the active resolver (custom-CSS reports combinator /
|
|
5592
|
+
// structural-pseudo coupling; Tailwind has none → null index, behaviour unchanged).
|
|
5593
|
+
selectors: buildSelectorIndex(doc, resolver),
|
|
5594
|
+
resolver,
|
|
5595
|
+
gate
|
|
5596
|
+
};
|
|
5597
|
+
return { doc, ctx, passes: buildPasses(patterns), nodesIn };
|
|
5598
|
+
}
|
|
5599
|
+
function finish(code, optimized, id, nodesIn) {
|
|
5600
|
+
syncClassesFromComputed(optimized, resolver, normalizer);
|
|
5601
|
+
const printed = createJsxBackend().print(
|
|
5602
|
+
optimized,
|
|
5603
|
+
{ moduleId: id, ops: [], provenance: /* @__PURE__ */ new Map() },
|
|
5604
|
+
{ normalizer, resolver, sink: createSyntheticSink(), eol: "\n", onDiagnostic: () => {
|
|
5605
|
+
} }
|
|
5606
|
+
);
|
|
5607
|
+
const out = printed.code;
|
|
5608
|
+
const nodesOut = optimized.nodes.size;
|
|
5609
|
+
const classesBefore = countClassTokens(code);
|
|
5610
|
+
const classesAfter = countClassTokens(out);
|
|
5611
|
+
return {
|
|
5612
|
+
code: out,
|
|
5613
|
+
changed: out !== code,
|
|
5614
|
+
passthrough: false,
|
|
5615
|
+
stats: {
|
|
5616
|
+
nodesIn,
|
|
5617
|
+
nodesOut,
|
|
5618
|
+
nodesRemoved: Math.max(0, nodesIn - nodesOut),
|
|
5619
|
+
classesBefore,
|
|
5620
|
+
classesAfter,
|
|
5621
|
+
classesSaved: Math.max(0, classesBefore - classesAfter),
|
|
5622
|
+
bytesBefore: bytes(code),
|
|
5623
|
+
bytesAfter: bytes(out),
|
|
5624
|
+
bytesSaved: bytes(code) - bytes(out)
|
|
5625
|
+
}
|
|
5626
|
+
};
|
|
5627
|
+
}
|
|
4258
5628
|
return {
|
|
4259
5629
|
resolver,
|
|
4260
5630
|
transformFile(code, id) {
|
|
4261
5631
|
const kind = jsxKindOf(id);
|
|
4262
5632
|
if (kind === null) return passthroughResult(code);
|
|
4263
|
-
const
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
resolver,
|
|
4267
|
-
normalizer,
|
|
4268
|
-
config: {},
|
|
4269
|
-
onDiagnostic: () => {
|
|
4270
|
-
}
|
|
4271
|
-
});
|
|
4272
|
-
const doc = parsed.doc;
|
|
4273
|
-
const nodesIn = doc.nodes.size;
|
|
4274
|
-
for (const node of doc.nodes.values()) node.meta.safetyFloor = 3;
|
|
4275
|
-
const ctx = {
|
|
4276
|
-
doc,
|
|
4277
|
-
safetyCeiling: options.safety,
|
|
4278
|
-
normalizer,
|
|
4279
|
-
// Real CSS-selector-safety index from the active resolver (custom-CSS reports combinator /
|
|
4280
|
-
// structural-pseudo coupling; Tailwind has none → null index, behaviour unchanged).
|
|
4281
|
-
selectors: buildSelectorIndex(doc, resolver),
|
|
4282
|
-
resolver
|
|
4283
|
-
};
|
|
4284
|
-
const { doc: optimized } = runPasses(doc, buildPasses(patterns), ctx);
|
|
4285
|
-
syncClassesFromComputed(optimized, resolver, normalizer);
|
|
4286
|
-
const printed = createJsxBackend().print(
|
|
4287
|
-
optimized,
|
|
4288
|
-
{ moduleId: id, ops: [], provenance: /* @__PURE__ */ new Map() },
|
|
4289
|
-
{
|
|
4290
|
-
normalizer,
|
|
4291
|
-
resolver,
|
|
4292
|
-
sink: createSyntheticSink(),
|
|
4293
|
-
eol: "\n",
|
|
4294
|
-
onDiagnostic: () => {
|
|
4295
|
-
}
|
|
4296
|
-
}
|
|
4297
|
-
);
|
|
4298
|
-
const out = printed.code;
|
|
4299
|
-
const nodesOut = optimized.nodes.size;
|
|
4300
|
-
const classesBefore = countClassTokens(code);
|
|
4301
|
-
const classesAfter = countClassTokens(out);
|
|
4302
|
-
return {
|
|
4303
|
-
code: out,
|
|
4304
|
-
changed: out !== code,
|
|
4305
|
-
passthrough: false,
|
|
4306
|
-
stats: {
|
|
4307
|
-
nodesIn,
|
|
4308
|
-
nodesOut,
|
|
4309
|
-
nodesRemoved: Math.max(0, nodesIn - nodesOut),
|
|
4310
|
-
classesBefore,
|
|
4311
|
-
classesAfter,
|
|
4312
|
-
classesSaved: Math.max(0, classesBefore - classesAfter),
|
|
4313
|
-
bytesBefore: bytes(code),
|
|
4314
|
-
bytesAfter: bytes(out),
|
|
4315
|
-
bytesSaved: bytes(code) - bytes(out)
|
|
4316
|
-
}
|
|
4317
|
-
};
|
|
5633
|
+
const { doc, ctx, passes, nodesIn } = prepare(code, id, kind, "provably-safe");
|
|
5634
|
+
const { doc: optimized } = runPasses(doc, passes, ctx);
|
|
5635
|
+
return finish(code, optimized, id, nodesIn);
|
|
4318
5636
|
}
|
|
4319
5637
|
};
|
|
4320
5638
|
}
|
|
@@ -4995,19 +6313,112 @@ ${import_picocolors2.default.gray(d2)} ${t}
|
|
|
4995
6313
|
};
|
|
4996
6314
|
var J2 = `${import_picocolors2.default.gray(o)} `;
|
|
4997
6315
|
|
|
6316
|
+
// ../cli/src/detect.ts
|
|
6317
|
+
init_cjs_shims();
|
|
6318
|
+
var fs2 = __toESM(require("fs"), 1);
|
|
6319
|
+
var path5 = __toESM(require("path"), 1);
|
|
6320
|
+
var SKIP_DIRS2 = /* @__PURE__ */ new Set([
|
|
6321
|
+
"node_modules",
|
|
6322
|
+
"dist",
|
|
6323
|
+
"build",
|
|
6324
|
+
".next",
|
|
6325
|
+
"out",
|
|
6326
|
+
"coverage",
|
|
6327
|
+
".git",
|
|
6328
|
+
"domflax-out"
|
|
6329
|
+
]);
|
|
6330
|
+
var COMMON_INPUT_DIRS = ["src", "app", "components", "pages", "lib", "ui", "public"];
|
|
6331
|
+
var CSS_FILE_CAP = 200;
|
|
6332
|
+
function toRelative(root, abs) {
|
|
6333
|
+
const rel = path5.relative(root, abs);
|
|
6334
|
+
return rel.split(path5.sep).join("/");
|
|
6335
|
+
}
|
|
6336
|
+
function detectCssFiles(root) {
|
|
6337
|
+
const found = [];
|
|
6338
|
+
let capped = false;
|
|
6339
|
+
const walk = (dir) => {
|
|
6340
|
+
if (capped) return;
|
|
6341
|
+
let entries;
|
|
6342
|
+
try {
|
|
6343
|
+
entries = fs2.readdirSync(dir, { withFileTypes: true });
|
|
6344
|
+
} catch {
|
|
6345
|
+
return;
|
|
6346
|
+
}
|
|
6347
|
+
for (const entry of entries) {
|
|
6348
|
+
const full = path5.join(dir, entry.name);
|
|
6349
|
+
if (entry.isDirectory()) {
|
|
6350
|
+
if (SKIP_DIRS2.has(entry.name)) continue;
|
|
6351
|
+
walk(full);
|
|
6352
|
+
if (capped) return;
|
|
6353
|
+
} else if (entry.isFile() && entry.name.toLowerCase().endsWith(".css")) {
|
|
6354
|
+
found.push(toRelative(root, full));
|
|
6355
|
+
if (found.length >= CSS_FILE_CAP) {
|
|
6356
|
+
capped = true;
|
|
6357
|
+
return;
|
|
6358
|
+
}
|
|
6359
|
+
}
|
|
6360
|
+
}
|
|
6361
|
+
};
|
|
6362
|
+
walk(path5.resolve(root));
|
|
6363
|
+
found.sort((a, b3) => a.localeCompare(b3));
|
|
6364
|
+
if (capped) {
|
|
6365
|
+
console.error(`domflax: more than ${CSS_FILE_CAP} CSS files found; showing the first ${CSS_FILE_CAP}.`);
|
|
6366
|
+
}
|
|
6367
|
+
return found;
|
|
6368
|
+
}
|
|
6369
|
+
function detectInputDirs(root) {
|
|
6370
|
+
const resolved = path5.resolve(root);
|
|
6371
|
+
return COMMON_INPUT_DIRS.filter((name) => {
|
|
6372
|
+
try {
|
|
6373
|
+
return fs2.statSync(path5.join(resolved, name)).isDirectory();
|
|
6374
|
+
} catch {
|
|
6375
|
+
return false;
|
|
6376
|
+
}
|
|
6377
|
+
});
|
|
6378
|
+
}
|
|
6379
|
+
|
|
4998
6380
|
// ../cli/src/wizard.ts
|
|
6381
|
+
var OTHER_INPUT = "\0domflax.other";
|
|
4999
6382
|
var WIZARD_CANCELLED = /* @__PURE__ */ Symbol("domflax.wizard.cancelled");
|
|
5000
6383
|
function cancelled(value) {
|
|
5001
6384
|
return pD(value);
|
|
5002
6385
|
}
|
|
5003
6386
|
async function runWizard(base) {
|
|
5004
6387
|
Ie("domflax \u2014 optimize your markup");
|
|
5005
|
-
const
|
|
5006
|
-
|
|
5007
|
-
|
|
5008
|
-
|
|
5009
|
-
|
|
5010
|
-
|
|
6388
|
+
const root = base.projectRoot ?? process.cwd();
|
|
6389
|
+
const detectedInputs = detectInputDirs(root);
|
|
6390
|
+
let inputPath;
|
|
6391
|
+
if (detectedInputs.length > 0) {
|
|
6392
|
+
const defaultInput = detectedInputs.includes("src") ? "src" : detectedInputs[0];
|
|
6393
|
+
const choice = await ve({
|
|
6394
|
+
message: "Which folder should domflax optimize?",
|
|
6395
|
+
options: [
|
|
6396
|
+
...detectedInputs.map((dir) => ({ value: dir, label: dir, hint: "detected" })),
|
|
6397
|
+
{ value: OTHER_INPUT, label: "Other (type a path)\u2026" }
|
|
6398
|
+
],
|
|
6399
|
+
initialValue: defaultInput
|
|
6400
|
+
});
|
|
6401
|
+
if (cancelled(choice)) return done();
|
|
6402
|
+
if (choice === OTHER_INPUT) {
|
|
6403
|
+
const typed = await he({
|
|
6404
|
+
message: "Which folder, glob, or file should domflax optimize?",
|
|
6405
|
+
placeholder: "src",
|
|
6406
|
+
defaultValue: "src"
|
|
6407
|
+
});
|
|
6408
|
+
if (cancelled(typed)) return done();
|
|
6409
|
+
inputPath = String(typed);
|
|
6410
|
+
} else {
|
|
6411
|
+
inputPath = String(choice);
|
|
6412
|
+
}
|
|
6413
|
+
} else {
|
|
6414
|
+
const typed = await he({
|
|
6415
|
+
message: "Which folder, glob, or file should domflax optimize?",
|
|
6416
|
+
placeholder: "src",
|
|
6417
|
+
defaultValue: "src"
|
|
6418
|
+
});
|
|
6419
|
+
if (cancelled(typed)) return done();
|
|
6420
|
+
inputPath = String(typed);
|
|
6421
|
+
}
|
|
5011
6422
|
const outputMode = await ve({
|
|
5012
6423
|
message: "Where should the optimized files go?",
|
|
5013
6424
|
options: [
|
|
@@ -5056,17 +6467,29 @@ async function runWizard(base) {
|
|
|
5056
6467
|
if (cancelled(provider)) return done();
|
|
5057
6468
|
let css = base.css;
|
|
5058
6469
|
if (provider === "custom") {
|
|
5059
|
-
const
|
|
5060
|
-
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
|
|
6470
|
+
const detectedCss = detectCssFiles(root);
|
|
6471
|
+
if (detectedCss.length > 0) {
|
|
6472
|
+
const picked = await fe({
|
|
6473
|
+
message: "Which CSS files should resolve your classes? (all detected files are pre-selected)",
|
|
6474
|
+
options: detectedCss.map((file) => ({ value: file, label: file })),
|
|
6475
|
+
initialValues: [...detectedCss],
|
|
6476
|
+
required: false
|
|
6477
|
+
});
|
|
6478
|
+
if (cancelled(picked)) return done();
|
|
6479
|
+
css = picked;
|
|
6480
|
+
} else {
|
|
6481
|
+
const cssInput = await he({
|
|
6482
|
+
message: "CSS files (space-separated):",
|
|
6483
|
+
placeholder: "src/styles.css"
|
|
6484
|
+
});
|
|
6485
|
+
if (cancelled(cssInput)) return done();
|
|
6486
|
+
css = String(cssInput).split(/\s+/).filter((s) => s.length > 0);
|
|
6487
|
+
}
|
|
5065
6488
|
}
|
|
5066
6489
|
Se("Ready \u2014 running domflax.");
|
|
5067
6490
|
return {
|
|
5068
6491
|
...base,
|
|
5069
|
-
paths: [
|
|
6492
|
+
paths: [inputPath],
|
|
5070
6493
|
out,
|
|
5071
6494
|
provider,
|
|
5072
6495
|
css,
|
|
@@ -5098,7 +6521,7 @@ function printReport(totals) {
|
|
|
5098
6521
|
console.log(` classes saved : ${totals.classesSaved}`);
|
|
5099
6522
|
console.log(` bytes saved : ${totals.bytesSaved}`);
|
|
5100
6523
|
}
|
|
5101
|
-
function execute(options) {
|
|
6524
|
+
async function execute(options) {
|
|
5102
6525
|
const { files, inputRoot, warnings } = discoverInputs(options.paths);
|
|
5103
6526
|
for (const w2 of warnings) console.error(`domflax: ${w2}`);
|
|
5104
6527
|
if (files.length === 0) {
|
|
@@ -5128,7 +6551,7 @@ function execute(options) {
|
|
|
5128
6551
|
const result = transform.transformFile(code, file);
|
|
5129
6552
|
addStats(totals, result.stats, result.changed);
|
|
5130
6553
|
if (options.dryRun) {
|
|
5131
|
-
const rel =
|
|
6554
|
+
const rel = path6.relative(inputRoot, file) || path6.basename(file);
|
|
5132
6555
|
if (result.changed) console.log(unifiedDiff(code, result.code, rel));
|
|
5133
6556
|
else if (!options.report) console.log(` (unchanged) ${rel}`);
|
|
5134
6557
|
continue;
|
|
@@ -5141,9 +6564,9 @@ function execute(options) {
|
|
|
5141
6564
|
continue;
|
|
5142
6565
|
}
|
|
5143
6566
|
try {
|
|
5144
|
-
(0, import_node_fs2.mkdirSync)(
|
|
6567
|
+
(0, import_node_fs2.mkdirSync)(path6.dirname(target.value), { recursive: true });
|
|
5145
6568
|
(0, import_node_fs2.writeFileSync)(target.value, result.code, "utf8");
|
|
5146
|
-
console.log(`domflax: wrote ${
|
|
6569
|
+
console.log(`domflax: wrote ${path6.relative(process.cwd(), target.value) || target.value}`);
|
|
5147
6570
|
} catch (err) {
|
|
5148
6571
|
console.error(`domflax: cannot write ${target.value}: ${String(err?.message ?? err)}`);
|
|
5149
6572
|
failures += 1;
|
|
@@ -5180,27 +6603,13 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
5180
6603
|
return;
|
|
5181
6604
|
}
|
|
5182
6605
|
try {
|
|
5183
|
-
const result = execute(options);
|
|
6606
|
+
const result = await execute(options);
|
|
5184
6607
|
process.exitCode = result.exitCode;
|
|
5185
6608
|
} catch (err) {
|
|
5186
6609
|
console.error(`domflax: ${err instanceof Error ? err.message : String(err)}`);
|
|
5187
6610
|
process.exitCode = 1;
|
|
5188
6611
|
}
|
|
5189
6612
|
}
|
|
5190
|
-
function isMainEntry() {
|
|
5191
|
-
const entry = process.argv[1];
|
|
5192
|
-
if (entry === void 0) return false;
|
|
5193
|
-
try {
|
|
5194
|
-
const self = path5.resolve((0, import_node_url.fileURLToPath)(importMetaUrl));
|
|
5195
|
-
const argv = path5.resolve(entry);
|
|
5196
|
-
return process.platform === "win32" ? self.toLowerCase() === argv.toLowerCase() : self === argv;
|
|
5197
|
-
} catch {
|
|
5198
|
-
return false;
|
|
5199
|
-
}
|
|
5200
|
-
}
|
|
5201
|
-
if (isMainEntry()) {
|
|
5202
|
-
void main();
|
|
5203
|
-
}
|
|
5204
6613
|
|
|
5205
6614
|
// src/cli.ts
|
|
5206
6615
|
main(process.argv.slice(2));
|