domflax 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +25 -8
  2. package/dist/{chunk-DNHOGPYV.js → chunk-3Z5ZWLXX.js} +407 -51
  3. package/dist/chunk-3Z5ZWLXX.js.map +1 -0
  4. package/dist/{chunk-DOQEBGWB.js → chunk-5FWENSD2.js} +63 -8
  5. package/dist/chunk-5FWENSD2.js.map +1 -0
  6. package/dist/chunk-EVENAJYI.js +336 -0
  7. package/dist/chunk-EVENAJYI.js.map +1 -0
  8. package/dist/{chunk-DWLB7FRR.js → chunk-H5KTGI3A.js} +153 -7
  9. package/dist/chunk-H5KTGI3A.js.map +1 -0
  10. package/dist/{chunk-6WVVF6AD.js → chunk-U5GOONKV.js} +5 -2
  11. package/dist/{chunk-6WVVF6AD.js.map → chunk-U5GOONKV.js.map} +1 -1
  12. package/dist/cli.cjs +995 -166
  13. package/dist/cli.cjs.map +1 -1
  14. package/dist/cli.js +245 -229
  15. package/dist/cli.js.map +1 -1
  16. package/dist/index.cjs +614 -68
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.d.cts +34 -18
  19. package/dist/index.d.ts +34 -18
  20. package/dist/index.js +4 -4
  21. package/dist/{pattern-F5xBtIE-.d.cts → pattern-CP9_HpVK.d.cts} +1 -1
  22. package/dist/{pattern-CV607P87.d.ts → pattern-CYgsv-jO.d.ts} +1 -1
  23. package/dist/pattern-kit.cjs.map +1 -1
  24. package/dist/pattern-kit.d.cts +2 -2
  25. package/dist/pattern-kit.d.ts +2 -2
  26. package/dist/pattern-kit.js +2 -2
  27. package/dist/{resolve-ops-DIwEelH-.d.ts → resolve-ops-Ci7LgYHC.d.cts} +9 -0
  28. package/dist/{resolve-ops-DIwEelH-.d.cts → resolve-ops-Ci7LgYHC.d.ts} +9 -0
  29. package/dist/verify.d.cts +1 -1
  30. package/dist/verify.d.ts +1 -1
  31. package/dist/verify.js +1 -1
  32. package/dist/webpack-loader.cjs +614 -68
  33. package/dist/webpack-loader.cjs.map +1 -1
  34. package/dist/webpack-loader.d.cts +2 -2
  35. package/dist/webpack-loader.d.ts +2 -2
  36. package/dist/webpack-loader.js +4 -4
  37. package/dist/worker.cjs +5955 -0
  38. package/dist/worker.cjs.map +1 -0
  39. package/dist/worker.d.cts +2 -0
  40. package/dist/worker.d.ts +2 -0
  41. package/dist/worker.js +72 -0
  42. package/dist/worker.js.map +1 -0
  43. package/package.json +4 -2
  44. package/dist/chunk-DNHOGPYV.js.map +0 -1
  45. package/dist/chunk-DOQEBGWB.js.map +0 -1
  46. package/dist/chunk-DWLB7FRR.js.map +0 -1
package/dist/index.cjs CHANGED
@@ -179,6 +179,7 @@ function defaultMeta(safetyFloor = 0) {
179
179
  declaresCustomProperties: false,
180
180
  whitespaceSensitive: false,
181
181
  touched: false,
182
+ styleDirty: false,
182
183
  synthetic: false,
183
184
  safetyFloor
184
185
  };
@@ -392,6 +393,14 @@ function markTouched(state, id) {
392
393
  state.touched.add(id);
393
394
  }
394
395
  }
396
+ function markStyleDirty(state, id) {
397
+ const n = state.doc.nodes.get(id);
398
+ if (n) {
399
+ n.meta.touched = true;
400
+ n.meta.styleDirty = true;
401
+ state.touched.add(id);
402
+ }
403
+ }
395
404
  function removeSubtree(state, id) {
396
405
  const node = state.doc.nodes.get(id);
397
406
  if (!node) return;
@@ -683,7 +692,7 @@ function applyOne(state, op) {
683
692
  return [precond(op, op.target, "setClassList target is not an element")];
684
693
  }
685
694
  el.computed = cloneStyleMap(op.style);
686
- markTouched(state, op.target);
695
+ markStyleDirty(state, op.target);
687
696
  return [];
688
697
  }
689
698
  case "mergeStyle": {
@@ -706,7 +715,7 @@ function applyOne(state, op) {
706
715
  const src = doc.nodes.get(op.source);
707
716
  if (src) markTouched(state, op.source);
708
717
  }
709
- markTouched(state, op.target);
718
+ markStyleDirty(state, op.target);
710
719
  return [];
711
720
  }
712
721
  case "foldInheritedStyles":
@@ -757,7 +766,7 @@ function applyFold(state, op) {
757
766
  }
758
767
  if (folded) {
759
768
  into.computed = { blocks: nextBlocks };
760
- markTouched(state, intoId);
769
+ markStyleDirty(state, intoId);
761
770
  }
762
771
  }
763
772
  for (const d of issues) state.diagnostics.push(d);
@@ -1090,8 +1099,123 @@ function buildMatchContext(doc, elementId, resolver, selectors, safety, phase, i
1090
1099
  var DISPLAY = "display";
1091
1100
  var POSITION = "position";
1092
1101
  var TRANSFORM = "transform";
1102
+ var ALIGN_ITEMS = "align-items";
1103
+ var JUSTIFY_CONTENT = "justify-content";
1104
+ var JUSTIFY_ITEMS = "justify-items";
1105
+ var PLACE_ITEMS = "place-items";
1106
+ var PLACE_SELF = "place-self";
1093
1107
  var CONTEXT_SAFE_DISPLAYS = /* @__PURE__ */ new Set(["block", "contents", ""]);
1094
1108
  var STATIC_POSITIONS = /* @__PURE__ */ new Set(["static", ""]);
1109
+ var CENTERING_DISPLAYS = /* @__PURE__ */ new Set(["flex", "grid"]);
1110
+ var GRID_PARENT_DISPLAYS = /* @__PURE__ */ new Set(["grid"]);
1111
+ var STRETCHY_ITEM_ALIGN = /* @__PURE__ */ new Set(["normal", "stretch"]);
1112
+ var PARENT_ITEMS_ALIGN_PROPS = [ALIGN_ITEMS, JUSTIFY_ITEMS, PLACE_ITEMS];
1113
+ function isBaseCondition(block) {
1114
+ const c = block.condition;
1115
+ return c.media === "" && c.states.length === 0 && c.pseudoElement === "";
1116
+ }
1117
+ function baseValue(sm, prop) {
1118
+ for (const block of sm.blocks.values()) {
1119
+ if (!isBaseCondition(block)) continue;
1120
+ const d = block.decls.get(prop);
1121
+ return d ? String(d.value) : null;
1122
+ }
1123
+ return null;
1124
+ }
1125
+ function parentIsFillingGrid(before, wrapper, norm) {
1126
+ if (wrapper.parent == null) return false;
1127
+ const p = before.nodes.get(wrapper.parent);
1128
+ if (!p || p.kind !== "element") return false;
1129
+ const pc2 = norm.normalizeStyleMap(p.computed);
1130
+ let baseIsGrid = false;
1131
+ for (const block of pc2.blocks.values()) {
1132
+ const disp = block.decls.get(DISPLAY);
1133
+ if (disp) {
1134
+ if (!GRID_PARENT_DISPLAYS.has(String(disp.value))) return false;
1135
+ if (isBaseCondition(block)) baseIsGrid = true;
1136
+ }
1137
+ for (const prop of PARENT_ITEMS_ALIGN_PROPS) {
1138
+ const d = block.decls.get(prop);
1139
+ if (d && !STRETCHY_ITEM_ALIGN.has(String(d.value))) return false;
1140
+ }
1141
+ }
1142
+ return baseIsGrid;
1143
+ }
1144
+ function wrapperHasOnlyCenteringStyle(wrapperComputed, childComputed, norm) {
1145
+ for (const block of wrapperComputed.blocks.values()) {
1146
+ const base = isBaseCondition(block);
1147
+ const ck = conditionKey(block.condition);
1148
+ for (const [prop, decl] of block.decls) {
1149
+ const val = String(decl.value);
1150
+ if (prop === DISPLAY) {
1151
+ if (base && CENTERING_DISPLAYS.has(val)) continue;
1152
+ return false;
1153
+ }
1154
+ if (prop === ALIGN_ITEMS) {
1155
+ if (base && val === "center") continue;
1156
+ return false;
1157
+ }
1158
+ if (prop === JUSTIFY_CONTENT) {
1159
+ if (base && val === "center") continue;
1160
+ return false;
1161
+ }
1162
+ if (prop === POSITION) {
1163
+ if (STATIC_POSITIONS.has(val)) continue;
1164
+ return false;
1165
+ }
1166
+ if (prop === TRANSFORM) {
1167
+ if (val === "none") continue;
1168
+ return false;
1169
+ }
1170
+ if (isInherited2(decl, norm)) continue;
1171
+ if (childReproduces(childComputed, ck, prop, val)) continue;
1172
+ return false;
1173
+ }
1174
+ }
1175
+ return true;
1176
+ }
1177
+ function wrapperCentersSingleElement(before, wrapper) {
1178
+ let elements = 0;
1179
+ for (const cid of wrapper.children) {
1180
+ const n = before.nodes.get(cid);
1181
+ if (!n) continue;
1182
+ if (n.kind === "element") {
1183
+ elements += 1;
1184
+ continue;
1185
+ }
1186
+ if (n.kind === "comment") continue;
1187
+ if (n.kind === "text" && n.value.trim() === "") continue;
1188
+ return false;
1189
+ }
1190
+ return elements === 1;
1191
+ }
1192
+ function childHasSelfAlign(childBefore, norm) {
1193
+ if (!childBefore) return false;
1194
+ const sm = norm.normalizeStyleMap(childBefore);
1195
+ for (const block of sm.blocks.values()) {
1196
+ for (const prop of SELF_ALIGN_PROPS) {
1197
+ const d = block.decls.get(prop);
1198
+ if (d && !NEUTRAL_ALIGN.has(String(d.value))) return true;
1199
+ }
1200
+ }
1201
+ return false;
1202
+ }
1203
+ function childGainsPlaceSelfCenter(childAfter) {
1204
+ if (baseValue(childAfter, PLACE_SELF) === "center") return true;
1205
+ return baseValue(childAfter, "align-self") === "center" && baseValue(childAfter, "justify-self") === "center";
1206
+ }
1207
+ function isContextCompensatedCentering(before, wrapper, wrapperComputed, childBefore, childAfter, norm) {
1208
+ if (!childAfter) return false;
1209
+ if (!CENTERING_DISPLAYS.has(baseValue(wrapperComputed, DISPLAY) ?? "")) return false;
1210
+ if (baseValue(wrapperComputed, ALIGN_ITEMS) !== "center") return false;
1211
+ if (baseValue(wrapperComputed, JUSTIFY_CONTENT) !== "center") return false;
1212
+ const childAfterNorm = norm.normalizeStyleMap(childAfter);
1213
+ if (!childGainsPlaceSelfCenter(childAfterNorm)) return false;
1214
+ if (!wrapperHasOnlyCenteringStyle(wrapperComputed, childAfterNorm, norm)) return false;
1215
+ if (!wrapperCentersSingleElement(before, wrapper)) return false;
1216
+ if (childHasSelfAlign(childBefore, norm)) return false;
1217
+ return parentIsFillingGrid(before, wrapper, norm);
1218
+ }
1095
1219
  var SELF_ALIGN_PROPS = [
1096
1220
  "place-self",
1097
1221
  "align-self",
@@ -1191,6 +1315,9 @@ function classifyFlattenOps(before, after, ops, norm) {
1191
1315
  const wrapperComputed = norm.normalizeStyleMap(wrapper.computed);
1192
1316
  const childAfter = childId != null ? getElement(after, childId)?.computed ?? null : null;
1193
1317
  const childBefore = childId != null ? getElement(before, childId)?.computed ?? null : null;
1318
+ if (isContextCompensatedCentering(before, wrapper, wrapperComputed, childBefore, childAfter, norm)) {
1319
+ return { kind: "provably-safe", wrapperId, childId };
1320
+ }
1194
1321
  if (establishesChildContext(wrapperComputed)) {
1195
1322
  return { kind: "needs-verification", wrapperId, childId };
1196
1323
  }
@@ -1626,15 +1753,34 @@ function sameTokens(a, b) {
1626
1753
  for (let i = 0; i < a.length; i += 1) if (a[i] !== b[i]) return false;
1627
1754
  return true;
1628
1755
  }
1756
+ function residualStyle(computed2, covered, norm) {
1757
+ const cov = norm.normalizeStyleMap(covered);
1758
+ const blocks = /* @__PURE__ */ new Map();
1759
+ for (const [key, block] of norm.normalizeStyleMap(computed2).blocks) {
1760
+ const covBlock = cov.blocks.get(key);
1761
+ const decls = /* @__PURE__ */ new Map();
1762
+ for (const [prop, decl] of block.decls) {
1763
+ const covDecl = covBlock?.decls.get(prop);
1764
+ if (covDecl && covDecl.value === decl.value && covDecl.important === decl.important) continue;
1765
+ decls.set(prop, decl);
1766
+ }
1767
+ if (decls.size > 0) blocks.set(key, { condition: block.condition, decls });
1768
+ }
1769
+ return { blocks };
1770
+ }
1629
1771
  function syncClassesFromComputed(doc, resolver, norm) {
1630
1772
  const sink = createSyntheticSink();
1631
1773
  for (const id of elementIds(doc)) {
1632
1774
  const el = getElement(doc, id);
1633
- if (!el || !el.meta.touched) continue;
1775
+ if (!el) continue;
1776
+ if (!el.meta.styleDirty) continue;
1634
1777
  if (el.classes.opaque || el.classes.hasDynamic) continue;
1635
1778
  const tokens = staticTokensOf(el.classes);
1779
+ const retained = tokens.filter((t) => !resolver.selectorUsage(t).droppable);
1780
+ const covered = retained.length > 0 ? resolver.resolve({ classes: retained }).styles : null;
1781
+ const target = covered ? residualStyle(el.computed, covered, norm) : el.computed;
1636
1782
  const ctx = { normalizer: norm, sink };
1637
- const emitted = resolver.emit(el.computed, ctx).classes;
1783
+ const emitted = resolver.emit(target, ctx).classes;
1638
1784
  if (emitted.length === 0) continue;
1639
1785
  const emittedSet = new Set(emitted);
1640
1786
  const next = [];
@@ -2346,19 +2492,28 @@ var flexCenterWrapper = definePattern({
2346
2492
  flattenInto: "child",
2347
2493
  childGains: { placeSelf: "center" }
2348
2494
  },
2349
- // Collapsing a flex-centering wrapper to `place-self:center` on the child only stays centered when
2350
- // the child's NEW parent is flex/grid; moreover the wrapper's own `display:flex` establishes a
2351
- // formatting context. Both make this a `needs-verification` flatten, which the conservative
2352
- // production gate (`'provably-safe'`, used by the harness) intentionally REVERTSso every case
2353
- // here is a no-match: the wrapper is preserved. Op-level rewrite correctness (purity, id-preserving
2354
- // unwrap, opacity-barrier safety) is still asserted by the invariant suite over every pattern.
2495
+ // Collapsing a flex-centering wrapper to `place-self:center` on the child is render-identical ONLY
2496
+ // when the child's NEW parent is a statically-known GRID that lets the wrapper fill its area (there
2497
+ // `place-self`'s align-self AND justify-self both take effect). Under that ONE context the flatten is
2498
+ // classified `provably-safe` and commits; under a flex/block/unknown parentor when the wrapper
2499
+ // drops any own style it stays `needs-verification` and the conservative production gate PRESERVES
2500
+ // it. Op-level correctness (purity, id-preserving unwrap, opacity-barrier safety) is additionally
2501
+ // asserted by the invariant suite over every pattern.
2355
2502
  test: {
2503
+ cases: [
2504
+ {
2505
+ name: "grid parent \u2192 flattened (child gains place-self-center)",
2506
+ before: '<div className="grid"><div className="flex items-center justify-center"><span className="bg-red-200">x</span></div></div>',
2507
+ after: '<div className="grid"><span className="bg-red-200 place-self-center">x</span></div>'
2508
+ }
2509
+ ],
2356
2510
  noMatch: [
2357
- // Even under a static flex/grid parent the centering flatten is not provably layout-neutral
2358
- // (the wrapper itself establishes a flex formatting context) → left unchanged.
2359
- '<div className="grid"><div className="flex items-center justify-center"><span className="bg-red-200">x</span></div></div>',
2360
- // Non-flex/grid parent (document root): place-self centering would not hold → left unchanged.
2511
+ // Non-grid (flex) parent (document root): `justify-self` is ignored in flex → not provably safe.
2361
2512
  '<div className="flex justify-center items-center"><div className="bg-red-200">Hello</div></div>',
2513
+ // Grid parent, but the wrapper drops padding when removed → not layout-neutral (rule 3).
2514
+ '<div className="grid"><div className="p-4 flex items-center justify-center"><span className="bg-red-200">x</span></div></div>',
2515
+ // Grid parent forcing place-items-center: the wrapper would not fill its area → fill guard skips.
2516
+ '<div className="grid place-items-center"><div className="flex items-center justify-center"><span className="bg-red-200">x</span></div></div>',
2362
2517
  // onClick is a hard opacity barrier → the wrapper is load-bearing regardless of the gate.
2363
2518
  '<div className="flex justify-center items-center" onClick={handleClick}><div className="bg-red-200">Hello</div></div>'
2364
2519
  ]
@@ -3562,11 +3717,11 @@ var paddingShorthand = definePattern({
3562
3717
  });
3563
3718
 
3564
3719
  // ../patterns/src/library/compress/place-shorthand.pattern.ts
3565
- var ALIGN_ITEMS = "align-items";
3566
- var JUSTIFY_ITEMS = "justify-items";
3567
- var PLACE_ITEMS = "place-items";
3720
+ var ALIGN_ITEMS2 = "align-items";
3721
+ var JUSTIFY_ITEMS2 = "justify-items";
3722
+ var PLACE_ITEMS2 = "place-items";
3568
3723
  var ALIGN_CONTENT = "align-content";
3569
- var JUSTIFY_CONTENT = "justify-content";
3724
+ var JUSTIFY_CONTENT2 = "justify-content";
3570
3725
  var PLACE_CONTENT = "place-content";
3571
3726
  var BASE_KEY8 = conditionKey(BASE_CONDITION);
3572
3727
  function samePair(a, b) {
@@ -3606,21 +3761,21 @@ var placeShorthand = definePattern({
3606
3761
  rewriteClasses(computed2) {
3607
3762
  const base = computed2.blocks.get(BASE_KEY8);
3608
3763
  if (!base) return null;
3609
- const alignItems = base.decls.get(ALIGN_ITEMS);
3610
- const justifyItems = base.decls.get(JUSTIFY_ITEMS);
3764
+ const alignItems = base.decls.get(ALIGN_ITEMS2);
3765
+ const justifyItems = base.decls.get(JUSTIFY_ITEMS2);
3611
3766
  const alignContent = base.decls.get(ALIGN_CONTENT);
3612
- const justifyContent = base.decls.get(JUSTIFY_CONTENT);
3767
+ const justifyContent = base.decls.get(JUSTIFY_CONTENT2);
3613
3768
  const next = new Map(base.decls);
3614
3769
  let collapsed = false;
3615
3770
  if (samePair(alignItems, justifyItems)) {
3616
- next.delete(ALIGN_ITEMS);
3617
- next.delete(JUSTIFY_ITEMS);
3618
- next.set(PLACE_ITEMS, placeDecl(PLACE_ITEMS, alignItems));
3771
+ next.delete(ALIGN_ITEMS2);
3772
+ next.delete(JUSTIFY_ITEMS2);
3773
+ next.set(PLACE_ITEMS2, placeDecl(PLACE_ITEMS2, alignItems));
3619
3774
  collapsed = true;
3620
3775
  }
3621
3776
  if (samePair(alignContent, justifyContent)) {
3622
3777
  next.delete(ALIGN_CONTENT);
3623
- next.delete(JUSTIFY_CONTENT);
3778
+ next.delete(JUSTIFY_CONTENT2);
3624
3779
  next.set(PLACE_CONTENT, placeDecl(PLACE_CONTENT, alignContent));
3625
3780
  collapsed = true;
3626
3781
  }
@@ -4809,11 +4964,349 @@ function createCssResolver(cssFiles = [], options) {
4809
4964
  var import_node_path = require("path");
4810
4965
  var import_node_url = require("url");
4811
4966
 
4967
+ // ../frontend-html/src/backend.ts
4968
+ var import_magic_string = __toESM(require("magic-string"), 1);
4969
+ function staticTokensOf2(classes) {
4970
+ const out = [];
4971
+ for (const seg of classes.segments) {
4972
+ if (seg.kind === "static") for (const t of seg.tokens) out.push(t.value);
4973
+ }
4974
+ return out;
4975
+ }
4976
+ function sameTokens2(a, b) {
4977
+ if (a.length !== b.length) return false;
4978
+ for (let i = 0; i < a.length; i += 1) if (a[i] !== b[i]) return false;
4979
+ return true;
4980
+ }
4981
+ function primarySource(doc) {
4982
+ for (const sf of doc.sources.values()) {
4983
+ if (typeof sf.text === "string" && sf.text.length > 0) return sf;
4984
+ }
4985
+ return null;
4986
+ }
4987
+ function collectKept(doc) {
4988
+ const out = [];
4989
+ const seen = /* @__PURE__ */ new Set();
4990
+ const visit = (id) => {
4991
+ if (seen.has(id)) return;
4992
+ seen.add(id);
4993
+ const n = doc.nodes.get(id);
4994
+ if (!n) return;
4995
+ out.push(n);
4996
+ if (n.kind === "element" || n.kind === "fragment") for (const c of n.children) visit(c);
4997
+ };
4998
+ visit(doc.root);
4999
+ return out;
5000
+ }
5001
+ function strictlyContains(a, b) {
5002
+ if (a.file !== b.file) return false;
5003
+ if (a.start <= b.start && b.end <= a.end) return !(a.start === b.start && a.end === b.end);
5004
+ return false;
5005
+ }
5006
+ function backrefIds(doc) {
5007
+ const out = [];
5008
+ const max = doc.alloc.peek;
5009
+ for (let i = 1; i < max; i += 1) {
5010
+ const id = i;
5011
+ if (doc.backref.get(id)) out.push(id);
5012
+ }
5013
+ return out;
5014
+ }
5015
+ function currentTokens(sf, valueSpan) {
5016
+ const raw = sf.text.slice(valueSpan.start, valueSpan.end).trim();
5017
+ const unquoted = raw.replace(/^['"]/, "").replace(/['"]$/, "");
5018
+ return unquoted.split(/\s+/).filter((t) => t.length > 0);
5019
+ }
5020
+ function editClasses(ms, doc, sf, el) {
5021
+ const classes = el.classes;
5022
+ if (classes.hasDynamic || classes.opaque) return false;
5023
+ const tokens = staticTokensOf2(classes);
5024
+ const valueSpan = classes.valueSpan;
5025
+ if (valueSpan && valueSpan.file === sf.id) {
5026
+ if (sameTokens2(currentTokens(sf, valueSpan), tokens)) return false;
5027
+ const current = sf.text.slice(valueSpan.start, valueSpan.end).trim();
5028
+ const quote = current.startsWith("'") ? "'" : '"';
5029
+ ms.overwrite(valueSpan.start, valueSpan.end, `${quote}${tokens.join(" ")}${quote}`);
5030
+ return true;
5031
+ }
5032
+ if (tokens.length === 0) return false;
5033
+ const openTag = doc.backref.get(el.id)?.openTagSpan;
5034
+ if (!openTag || openTag.file !== sf.id) return false;
5035
+ ms.appendLeft(openTag.start + 1 + el.tag.length, ` class="${tokens.join(" ")}"`);
5036
+ return true;
5037
+ }
5038
+ function surgicalPrint(doc) {
5039
+ const sf = primarySource(doc);
5040
+ if (!sf) return null;
5041
+ const ms = new import_magic_string.default(sf.text);
5042
+ const kept = collectKept(doc);
5043
+ const keptSpans = [];
5044
+ for (const n of kept) if (n.span && n.span.file === sf.id) keptSpans.push(n.span);
5045
+ const removed = [];
5046
+ for (const id of backrefIds(doc)) {
5047
+ if (doc.nodes.has(id)) continue;
5048
+ const back = doc.backref.get(id);
5049
+ if (!back || back.span.file !== sf.id) continue;
5050
+ const unwrapped = keptSpans.some((k) => strictlyContains(back.span, k));
5051
+ removed.push({ backref: back, unwrapped });
5052
+ }
5053
+ const fullRemovals = removed.filter((r) => !r.unwrapped).map((r) => r.backref.span);
5054
+ for (const r of removed) {
5055
+ const s = r.backref.span;
5056
+ if (fullRemovals.some((f) => f !== s && strictlyContains(f, s))) continue;
5057
+ if (r.unwrapped) {
5058
+ const open = r.backref.openTagSpan;
5059
+ const close = r.backref.closeTagSpan;
5060
+ if (open && open.file === sf.id && open.end > open.start) ms.remove(open.start, open.end);
5061
+ if (close && close.file === sf.id && close.end > close.start) ms.remove(close.start, close.end);
5062
+ } else {
5063
+ ms.remove(s.start, s.end);
5064
+ }
5065
+ }
5066
+ for (const n of kept) if (n.kind === "element") editClasses(ms, doc, sf, n);
5067
+ return ms.toString();
5068
+ }
5069
+ function doPrint(doc) {
5070
+ return surgicalPrint(doc) ?? "";
5071
+ }
5072
+
5073
+ // ../frontend-html/src/parse.ts
5074
+ var import_node_module3 = require("module");
5075
+
5076
+ // ../frontend-html/src/walk.ts
5077
+ var HTML_LANGS = ["html"];
5078
+ var FILE_ID = 1;
5079
+ function looksLikeHtml(id, code) {
5080
+ if (/\.html?$/i.test(id)) return true;
5081
+ const head = code.slice(0, 256).trimStart().toLowerCase();
5082
+ return head.startsWith("<!doctype html") || head.startsWith("<html") || head.startsWith("<");
5083
+ }
5084
+ var OPAQUE_SUBTREE_TAGS = /* @__PURE__ */ new Set([
5085
+ "script",
5086
+ "style",
5087
+ "template",
5088
+ "svg",
5089
+ "pre",
5090
+ "textarea"
5091
+ ]);
5092
+ function isOpaqueSubtreeTag(tag) {
5093
+ return OPAQUE_SUBTREE_TAGS.has(tag);
5094
+ }
5095
+ function elementIsOpaque(attrs) {
5096
+ for (const a of attrs) {
5097
+ const n = a.name.toLowerCase();
5098
+ if (n === "id" || n === "contenteditable") return true;
5099
+ if (n.startsWith("on")) return true;
5100
+ }
5101
+ return false;
5102
+ }
5103
+ function hasEventHandler(attrs) {
5104
+ for (const a of attrs) if (/^on/i.test(a.name)) return true;
5105
+ return false;
5106
+ }
5107
+ function span(start, end) {
5108
+ return { file: FILE_ID, start, end };
5109
+ }
5110
+ function attrsLocOf(loc) {
5111
+ if (!loc) return void 0;
5112
+ return loc.startTag?.attrs ?? loc.attrs;
5113
+ }
5114
+ function classValueSpan(loc, source) {
5115
+ const attrsLoc = attrsLocOf(loc);
5116
+ const cl = attrsLoc?.["class"];
5117
+ if (!cl) return null;
5118
+ const text = source.slice(cl.startOffset, cl.endOffset);
5119
+ const eq = text.indexOf("=");
5120
+ if (eq === -1) return null;
5121
+ let i = eq + 1;
5122
+ while (i < text.length && /\s/.test(text[i])) i += 1;
5123
+ if (i >= text.length) return null;
5124
+ return span(cl.startOffset + i, cl.endOffset);
5125
+ }
5126
+
5127
+ // ../frontend-html/src/parse.ts
5128
+ var cachedParse5 = null;
5129
+ function loadParse5() {
5130
+ if (cachedParse5) return cachedParse5;
5131
+ const req = (0, import_node_module3.createRequire)(importMetaUrl);
5132
+ cachedParse5 = req("parse5");
5133
+ return cachedParse5;
5134
+ }
5135
+ function doParse(code, ctx) {
5136
+ const diagnostics = [];
5137
+ const doc = createDocument("html");
5138
+ const backref = doc.backref;
5139
+ const parse5 = loadParse5();
5140
+ const document2 = parse5.parse(code, { sourceCodeLocationInfo: true });
5141
+ const eol = code.includes("\r\n") ? "\r\n" : "\n";
5142
+ const sourceFile = {
5143
+ id: FILE_ID,
5144
+ path: ctx.id,
5145
+ text: code,
5146
+ frontend: "html",
5147
+ eol,
5148
+ indentUnit: " ",
5149
+ native: document2
5150
+ };
5151
+ doc.sources.set(FILE_ID, sourceFile);
5152
+ const resolveComputed = (tokens, tag, nodeId) => {
5153
+ if (tokens.length === 0) return emptyStyleMap();
5154
+ const res = ctx.resolver.resolve({ classes: tokens, element: { tagName: tag, namespace: "html" } });
5155
+ for (const w of res.warnings) {
5156
+ diagnostics.push({
5157
+ code: "DF_STYLE_CONFLICT_UNRESOLVED",
5158
+ severity: w.severity,
5159
+ message: w.message,
5160
+ nodeId
5161
+ });
5162
+ }
5163
+ return ctx.normalizer.normalizeStyleMap(res.styles);
5164
+ };
5165
+ const splitTokens = (raw) => raw.split(/\s+/).filter((t) => t.length > 0);
5166
+ const appendChild = (node, parentId, out) => {
5167
+ const name = node.nodeName;
5168
+ if (name === "#text") {
5169
+ const value = node.value ?? "";
5170
+ const id = doc.alloc.next();
5171
+ const loc = node.sourceCodeLocation ?? null;
5172
+ doc.nodes.set(
5173
+ id,
5174
+ createText(id, value, {
5175
+ parent: parentId,
5176
+ span: loc ? span(loc.startOffset, loc.endOffset) : null,
5177
+ collapsible: /^\s*$/.test(value)
5178
+ })
5179
+ );
5180
+ out.push(id);
5181
+ return;
5182
+ }
5183
+ if (name === "#comment") {
5184
+ const id = doc.alloc.next();
5185
+ const loc = node.sourceCodeLocation ?? null;
5186
+ doc.nodes.set(
5187
+ id,
5188
+ createComment(id, node.data ?? "", {
5189
+ parent: parentId,
5190
+ span: loc ? span(loc.startOffset, loc.endOffset) : null
5191
+ })
5192
+ );
5193
+ out.push(id);
5194
+ return;
5195
+ }
5196
+ if (name === "#documentType") return;
5197
+ if (name.startsWith("#")) {
5198
+ for (const c of node.childNodes ?? []) appendChild(c, parentId, out);
5199
+ return;
5200
+ }
5201
+ out.push(buildElement(node, parentId));
5202
+ };
5203
+ const buildElement = (node, parentId) => {
5204
+ const id = doc.alloc.next();
5205
+ const tag = (node.tagName ?? node.nodeName).toLowerCase();
5206
+ const loc = node.sourceCodeLocation ?? null;
5207
+ const attrsArr = node.attrs ?? [];
5208
+ const opaqueSubtree = isOpaqueSubtreeTag(tag);
5209
+ const synthetic = loc == null;
5210
+ const opaque2 = opaqueSubtree || synthetic || elementIsOpaque(attrsArr);
5211
+ const meta = defaultMeta();
5212
+ meta.hasEventHandlers = hasEventHandler(attrsArr);
5213
+ meta.safetyFloor = opaque2 ? 0 : 3;
5214
+ let classes = emptyClassList();
5215
+ let classTokens = [];
5216
+ const entries = /* @__PURE__ */ new Map();
5217
+ const order = [];
5218
+ for (const a of attrsArr) {
5219
+ if (a.name.toLowerCase() === "class") {
5220
+ classTokens = splitTokens(a.value);
5221
+ const valueSpan = classValueSpan(loc, code);
5222
+ const clAttr = attrsLocOf(loc)?.["class"];
5223
+ const seg = {
5224
+ kind: "static",
5225
+ span: valueSpan ?? void 0,
5226
+ tokens: classTokens.map((value) => ({ value }))
5227
+ };
5228
+ classes = {
5229
+ form: "string-literal",
5230
+ segments: [seg],
5231
+ valueSpan,
5232
+ attrSpan: clAttr ? span(clAttr.startOffset, clAttr.endOffset) : void 0,
5233
+ hasDynamic: false,
5234
+ opaque: false,
5235
+ rewritable: valueSpan != null
5236
+ };
5237
+ continue;
5238
+ }
5239
+ const v = a.value;
5240
+ entries.set(a.name, { kind: "static", value: v === "" ? true : v });
5241
+ order.push(a.name);
5242
+ }
5243
+ const attrs = { entries, spreads: [], order };
5244
+ const computed2 = resolveComputed(classTokens, tag, id);
5245
+ const children = [];
5246
+ if (!opaqueSubtree) {
5247
+ for (const c of node.childNodes ?? []) appendChild(c, id, children);
5248
+ }
5249
+ const el = createElement(id, {
5250
+ tag,
5251
+ namespace: "html",
5252
+ isComponent: false,
5253
+ selfClosing: loc ? loc.endTag == null : false,
5254
+ classes,
5255
+ computed: computed2,
5256
+ attrs,
5257
+ children,
5258
+ parent: parentId,
5259
+ span: loc ? span(loc.startOffset, loc.endOffset) : null,
5260
+ meta
5261
+ });
5262
+ doc.nodes.set(id, el);
5263
+ if (loc) {
5264
+ backref.set(id, {
5265
+ nodeId: id,
5266
+ span: span(loc.startOffset, loc.endOffset),
5267
+ openTagSpan: loc.startTag ? span(loc.startTag.startOffset, loc.startTag.endOffset) : null,
5268
+ closeTagSpan: loc.endTag ? span(loc.endTag.startOffset, loc.endTag.endOffset) : null,
5269
+ innerSpan: null,
5270
+ selfClosing: loc.endTag == null
5271
+ });
5272
+ }
5273
+ return id;
5274
+ };
5275
+ const rootFrag = doc.nodes.get(doc.root);
5276
+ appendChild(document2, doc.root, rootFrag.children);
5277
+ return { doc, diagnostics };
5278
+ }
5279
+
5280
+ // ../frontend-html/src/index.ts
5281
+ var htmlFrontend = {
5282
+ name: "html",
5283
+ langs: HTML_LANGS,
5284
+ canParse(id, code) {
5285
+ return looksLikeHtml(id, code);
5286
+ },
5287
+ parse(code, ctx) {
5288
+ return doParse(code, ctx);
5289
+ }
5290
+ };
5291
+ function createHtmlFrontend() {
5292
+ return htmlFrontend;
5293
+ }
5294
+ var htmlBackend = {
5295
+ name: "html",
5296
+ langs: HTML_LANGS,
5297
+ print(doc, _plan, _ctx) {
5298
+ return { code: doPrint(doc), map: null, edits: [], diagnostics: [] };
5299
+ }
5300
+ };
5301
+ function createHtmlBackend() {
5302
+ return htmlBackend;
5303
+ }
5304
+
4812
5305
  // ../frontend-jsx/src/frontend-ast.ts
4813
5306
  var import_traverse = __toESM(require("@babel/traverse"), 1);
4814
5307
  var traverse = typeof import_traverse.default === "function" ? import_traverse.default : import_traverse.default.default;
4815
5308
  var JSX_LANGS = ["jsx", "tsx"];
4816
- var FILE_ID = 1;
5309
+ var FILE_ID2 = 1;
4817
5310
  function jsxName(node) {
4818
5311
  switch (node.type) {
4819
5312
  case "JSXIdentifier":
@@ -4937,7 +5430,7 @@ function looksLikeJsx(id, code) {
4937
5430
 
4938
5431
  // ../frontend-jsx/src/frontend-parse.ts
4939
5432
  var import_parser = require("@babel/parser");
4940
- function doParse(code, ctx) {
5433
+ function doParse2(code, ctx) {
4941
5434
  const diagnostics = [];
4942
5435
  const doc = createDocument("jsx");
4943
5436
  const backref = doc.backref;
@@ -4947,7 +5440,7 @@ function doParse(code, ctx) {
4947
5440
  });
4948
5441
  const eol = code.includes("\r\n") ? "\r\n" : "\n";
4949
5442
  const sourceFile = {
4950
- id: FILE_ID,
5443
+ id: FILE_ID2,
4951
5444
  path: ctx.id,
4952
5445
  text: code,
4953
5446
  frontend: "jsx",
@@ -4955,23 +5448,23 @@ function doParse(code, ctx) {
4955
5448
  indentUnit: " ",
4956
5449
  native: ast
4957
5450
  };
4958
- doc.sources.set(FILE_ID, sourceFile);
5451
+ doc.sources.set(FILE_ID2, sourceFile);
4959
5452
  const spanOf = (node) => {
4960
5453
  if (node.start == null || node.end == null) return null;
4961
- const span = {
4962
- file: FILE_ID,
5454
+ const span2 = {
5455
+ file: FILE_ID2,
4963
5456
  start: node.start,
4964
5457
  end: node.end,
4965
5458
  startLoc: node.loc ? { line: node.loc.start.line, column: node.loc.start.column } : void 0,
4966
5459
  endLoc: node.loc ? { line: node.loc.end.line, column: node.loc.end.column } : void 0
4967
5460
  };
4968
- return span;
5461
+ return span2;
4969
5462
  };
4970
5463
  const sliceOf = (node) => node.start == null || node.end == null ? "" : code.slice(node.start, node.end);
4971
5464
  const internExpr = (node, spread) => {
4972
5465
  const payload = { text: sliceOf(node), spread };
4973
5466
  return doc.exprs.intern({
4974
- span: spanOf(node) ?? { file: FILE_ID, start: 0, end: 0 },
5467
+ span: spanOf(node) ?? { file: FILE_ID2, start: 0, end: 0 },
4975
5468
  kind: exprKind(node),
4976
5469
  payload
4977
5470
  });
@@ -5017,7 +5510,7 @@ function doParse(code, ctx) {
5017
5510
  }
5018
5511
  return emptyClassList();
5019
5512
  };
5020
- const staticTokensOf3 = (classes) => {
5513
+ const staticTokensOf4 = (classes) => {
5021
5514
  const out = [];
5022
5515
  for (const seg of classes.segments) {
5023
5516
  if (seg.kind === "static") for (const t of seg.tokens) out.push(t.value);
@@ -5095,7 +5588,7 @@ function doParse(code, ctx) {
5095
5588
  doc.nodes.set(id, createFragment(id, { children, parent: parentId, span: spanOf(node) }));
5096
5589
  backref.set(id, {
5097
5590
  nodeId: id,
5098
- span: spanOf(node) ?? { file: FILE_ID, start: 0, end: 0 },
5591
+ span: spanOf(node) ?? { file: FILE_ID2, start: 0, end: 0 },
5099
5592
  openTagSpan: spanOf(node.openingFragment),
5100
5593
  closeTagSpan: spanOf(node.closingFragment),
5101
5594
  innerSpan: null,
@@ -5144,7 +5637,7 @@ function doParse(code, ctx) {
5144
5637
  }
5145
5638
  let computed2 = emptyStyleMap();
5146
5639
  if (!classes.hasDynamic) {
5147
- const tokens = staticTokensOf3(classes);
5640
+ const tokens = staticTokensOf4(classes);
5148
5641
  if (tokens.length > 0) {
5149
5642
  const res = ctx.resolver.resolve({
5150
5643
  classes: tokens,
@@ -5177,13 +5670,13 @@ function doParse(code, ctx) {
5177
5670
  });
5178
5671
  doc.nodes.set(id, el);
5179
5672
  const inner = children.length > 0 ? spanOf(node.children[0]) && spanOf(node.children.at(-1)) ? {
5180
- file: FILE_ID,
5673
+ file: FILE_ID2,
5181
5674
  start: spanOf(node.children[0]).start,
5182
5675
  end: spanOf(node.children.at(-1)).end
5183
5676
  } : null : null;
5184
5677
  backref.set(id, {
5185
5678
  nodeId: id,
5186
- span: spanOf(node) ?? { file: FILE_ID, start: 0, end: 0 },
5679
+ span: spanOf(node) ?? { file: FILE_ID2, start: 0, end: 0 },
5187
5680
  openTagSpan: spanOf(opening),
5188
5681
  closeTagSpan: node.closingElement ? spanOf(node.closingElement) : null,
5189
5682
  innerSpan: inner,
@@ -5218,7 +5711,7 @@ var jsxFrontend = {
5218
5711
  return looksLikeJsx(id, code);
5219
5712
  },
5220
5713
  parse(code, ctx) {
5221
- return doParse(code, ctx);
5714
+ return doParse2(code, ctx);
5222
5715
  }
5223
5716
  };
5224
5717
  function createJsxFrontend() {
@@ -5226,7 +5719,7 @@ function createJsxFrontend() {
5226
5719
  }
5227
5720
 
5228
5721
  // ../frontend-jsx/src/backend.ts
5229
- var import_magic_string = __toESM(require("magic-string"), 1);
5722
+ var import_magic_string2 = __toESM(require("magic-string"), 1);
5230
5723
  var JSX_LANGS2 = ["jsx", "tsx"];
5231
5724
  function exprText(doc, ref) {
5232
5725
  const rec = doc.exprs.get(ref);
@@ -5240,20 +5733,20 @@ function exprText(doc, ref) {
5240
5733
  }
5241
5734
  return { text: "", spread: false };
5242
5735
  }
5243
- function staticTokensOf2(classes) {
5736
+ function staticTokensOf3(classes) {
5244
5737
  const out = [];
5245
5738
  for (const seg of classes.segments) {
5246
5739
  if (seg.kind === "static") for (const t of seg.tokens) out.push(t.value);
5247
5740
  }
5248
5741
  return out;
5249
5742
  }
5250
- function primarySource(doc) {
5743
+ function primarySource2(doc) {
5251
5744
  for (const sf of doc.sources.values()) {
5252
5745
  if (typeof sf.text === "string" && sf.text.length > 0) return sf;
5253
5746
  }
5254
5747
  return null;
5255
5748
  }
5256
- function collectKept(doc) {
5749
+ function collectKept2(doc) {
5257
5750
  const out = [];
5258
5751
  const seen = /* @__PURE__ */ new Set();
5259
5752
  const visit = (id) => {
@@ -5267,15 +5760,15 @@ function collectKept(doc) {
5267
5760
  visit(doc.root);
5268
5761
  return out;
5269
5762
  }
5270
- function strictlyContains(a, b) {
5763
+ function strictlyContains2(a, b) {
5271
5764
  if (a.file !== b.file) return false;
5272
5765
  if (a.start <= b.start && b.end <= a.end) return !(a.start === b.start && a.end === b.end);
5273
5766
  return false;
5274
5767
  }
5275
- function editClasses(ms, doc, sf, el) {
5768
+ function editClasses2(ms, doc, sf, el) {
5276
5769
  const classes = el.classes;
5277
5770
  if (classes.hasDynamic || classes.opaque) return false;
5278
- const tokens = staticTokensOf2(classes);
5771
+ const tokens = staticTokensOf3(classes);
5279
5772
  const valueSpan = classes.valueSpan;
5280
5773
  if (valueSpan && valueSpan.file === sf.id) {
5281
5774
  const current = sf.text.slice(valueSpan.start, valueSpan.end);
@@ -5339,10 +5832,10 @@ function transferKeyOnUnwrap(ms, doc, sf, region, kept) {
5339
5832
  const inside = [];
5340
5833
  for (const n of kept) {
5341
5834
  if (n.kind !== "element" || !n.span || n.span.file !== sf.id) continue;
5342
- if (strictlyContains(region.span, n.span)) inside.push(n);
5835
+ if (strictlyContains2(region.span, n.span)) inside.push(n);
5343
5836
  }
5344
5837
  const maximal = inside.filter(
5345
- (n) => !inside.some((o) => o !== n && o.span && n.span && strictlyContains(o.span, n.span))
5838
+ (n) => !inside.some((o) => o !== n && o.span && n.span && strictlyContains2(o.span, n.span))
5346
5839
  );
5347
5840
  if (maximal.length !== 1) return;
5348
5841
  const child = maximal[0];
@@ -5351,25 +5844,25 @@ function transferKeyOnUnwrap(ms, doc, sf, region, kept) {
5351
5844
  if (extractKeyAttr(sf.text.slice(childOpen.start, childOpen.end))) return;
5352
5845
  ms.appendLeft(childOpen.start + 1 + child.tag.length, ` ${keyAttr}`);
5353
5846
  }
5354
- function surgicalPrint(doc) {
5355
- const sf = primarySource(doc);
5847
+ function surgicalPrint2(doc) {
5848
+ const sf = primarySource2(doc);
5356
5849
  if (!sf) return null;
5357
- const ms = new import_magic_string.default(sf.text);
5358
- const kept = collectKept(doc);
5850
+ const ms = new import_magic_string2.default(sf.text);
5851
+ const kept = collectKept2(doc);
5359
5852
  const keptSpans = [];
5360
5853
  for (const n of kept) if (n.span && n.span.file === sf.id) keptSpans.push(n.span);
5361
5854
  const removed = [];
5362
- for (const id of backrefIds(doc)) {
5855
+ for (const id of backrefIds2(doc)) {
5363
5856
  if (doc.nodes.has(id)) continue;
5364
5857
  const back = doc.backref.get(id);
5365
5858
  if (!back || back.span.file !== sf.id) continue;
5366
- const unwrapped = keptSpans.some((k) => strictlyContains(back.span, k));
5859
+ const unwrapped = keptSpans.some((k) => strictlyContains2(back.span, k));
5367
5860
  removed.push({ backref: back, unwrapped });
5368
5861
  }
5369
5862
  const fullRemovals = removed.filter((r) => !r.unwrapped).map((r) => r.backref.span);
5370
5863
  for (const r of removed) {
5371
- const span = r.backref.span;
5372
- const coveredByFull = fullRemovals.some((f) => f !== span && strictlyContains(f, span));
5864
+ const span2 = r.backref.span;
5865
+ const coveredByFull = fullRemovals.some((f) => f !== span2 && strictlyContains2(f, span2));
5373
5866
  if (coveredByFull) continue;
5374
5867
  if (r.unwrapped) {
5375
5868
  transferKeyOnUnwrap(ms, doc, sf, r.backref, kept);
@@ -5380,15 +5873,15 @@ function surgicalPrint(doc) {
5380
5873
  ms.remove(close.start, close.end);
5381
5874
  }
5382
5875
  } else {
5383
- ms.remove(span.start, span.end);
5876
+ ms.remove(span2.start, span2.end);
5384
5877
  }
5385
5878
  }
5386
5879
  for (const n of kept) {
5387
- if (n.kind === "element") editClasses(ms, doc, sf, n);
5880
+ if (n.kind === "element") editClasses2(ms, doc, sf, n);
5388
5881
  }
5389
5882
  return ms.toString();
5390
5883
  }
5391
- function backrefIds(doc) {
5884
+ function backrefIds2(doc) {
5392
5885
  const out = [];
5393
5886
  const max = doc.alloc.peek;
5394
5887
  for (let i = 1; i < max; i += 1) {
@@ -5403,7 +5896,7 @@ function classText(doc, classes) {
5403
5896
  if (dynamic && dynamic.kind === "dynamic") {
5404
5897
  return `className={${exprText(doc, dynamic.expr).text}}`;
5405
5898
  }
5406
- const tokens = staticTokensOf2(classes);
5899
+ const tokens = staticTokensOf3(classes);
5407
5900
  return `className="${tokens.join(" ")}"`;
5408
5901
  }
5409
5902
  function attrText(doc, name, value) {
@@ -5456,15 +5949,15 @@ function rePrint(doc) {
5456
5949
  if (!root || root.kind !== "fragment") return printNode(doc, doc.root);
5457
5950
  return root.children.map((c) => printNode(doc, c)).join("");
5458
5951
  }
5459
- function doPrint(doc) {
5460
- const surgical = surgicalPrint(doc);
5952
+ function doPrint2(doc) {
5953
+ const surgical = surgicalPrint2(doc);
5461
5954
  return surgical ?? rePrint(doc);
5462
5955
  }
5463
5956
  var jsxBackend = {
5464
5957
  name: "babel-jsx",
5465
5958
  langs: JSX_LANGS2,
5466
5959
  print(doc, _plan, _ctx) {
5467
- const code = doPrint(doc);
5960
+ const code = doPrint2(doc);
5468
5961
  return { code, map: null, edits: [], diagnostics: [] };
5469
5962
  }
5470
5963
  };
@@ -5479,6 +5972,11 @@ function jsxKindOf(id) {
5479
5972
  if (clean.endsWith(".jsx")) return "jsx";
5480
5973
  return null;
5481
5974
  }
5975
+ function htmlKindOf(id) {
5976
+ const clean = (id.split("?", 1)[0] ?? id).toLowerCase();
5977
+ if (clean.endsWith(".html") || clean.endsWith(".htm")) return "html";
5978
+ return null;
5979
+ }
5482
5980
  function eolOf2(doc) {
5483
5981
  for (const src of doc.sources.values()) return src.eol;
5484
5982
  return "\n";
@@ -5546,9 +6044,51 @@ function runJsxPipeline(code, id, kind, resolver, patterns, safety) {
5546
6044
  const { doc: optimized } = runPasses(doc, passes, ctx);
5547
6045
  return finishPipeline(optimized, id, resolver);
5548
6046
  }
6047
+ function prepareHtml(code, id, resolver, patterns, safety, gate) {
6048
+ const parsed = createHtmlFrontend().parse(code, {
6049
+ id,
6050
+ kind: "html",
6051
+ resolver,
6052
+ normalizer,
6053
+ config: {},
6054
+ onDiagnostic: () => {
6055
+ }
6056
+ });
6057
+ const doc = parsed.doc;
6058
+ const ctx = {
6059
+ doc,
6060
+ safetyCeiling: safety,
6061
+ normalizer,
6062
+ selectors: buildSelectorIndex(doc, resolver),
6063
+ resolver,
6064
+ gate
6065
+ };
6066
+ return { doc, ctx, passes: buildPasses(patterns) };
6067
+ }
6068
+ function finishHtmlPipeline(optimized, id, resolver) {
6069
+ syncClassesFromComputed(optimized, resolver, normalizer);
6070
+ const printed = createHtmlBackend().print(
6071
+ optimized,
6072
+ { moduleId: id, ops: [], provenance: /* @__PURE__ */ new Map() },
6073
+ {
6074
+ normalizer,
6075
+ resolver,
6076
+ sink: createSyntheticSink(),
6077
+ eol: eolOf2(optimized),
6078
+ onDiagnostic: () => {
6079
+ }
6080
+ }
6081
+ );
6082
+ return printed.code;
6083
+ }
6084
+ function runHtmlPipeline(code, id, resolver, patterns, safety) {
6085
+ const { doc, ctx, passes } = prepareHtml(code, id, resolver, patterns, safety, "provably-safe");
6086
+ const { doc: optimized } = runPasses(doc, passes, ctx);
6087
+ return finishHtmlPipeline(optimized, id, resolver);
6088
+ }
5549
6089
 
5550
6090
  // src/index.ts
5551
- var DEFAULT_INCLUDE = [".jsx", ".tsx", ".html"];
6091
+ var DEFAULT_INCLUDE = [".jsx", ".tsx", ".html", ".htm"];
5552
6092
  function resolveOptions(options) {
5553
6093
  return {
5554
6094
  provider: options.provider ?? "auto",
@@ -5584,9 +6124,15 @@ function createDomflax(options = {}) {
5584
6124
  transform(code, id) {
5585
6125
  if (!isSupported(id, resolved.include)) return { code, map: null };
5586
6126
  const kind = jsxKindOf(id);
5587
- if (kind === null) return { code, map: null };
5588
- const out = runJsxPipeline(code, id, kind, getResolver(), patterns, resolved.safety);
5589
- return { code: out, map: null };
6127
+ if (kind !== null) {
6128
+ const out = runJsxPipeline(code, id, kind, getResolver(), patterns, resolved.safety);
6129
+ return { code: out, map: null };
6130
+ }
6131
+ if (htmlKindOf(id) !== null) {
6132
+ const out = runHtmlPipeline(code, id, getResolver(), patterns, resolved.safety);
6133
+ return { code: out, map: null };
6134
+ }
6135
+ return { code, map: null };
5590
6136
  }
5591
6137
  };
5592
6138
  }