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
@@ -107,6 +107,7 @@ function defaultMeta(safetyFloor = 0) {
107
107
  declaresCustomProperties: false,
108
108
  whitespaceSensitive: false,
109
109
  touched: false,
110
+ styleDirty: false,
110
111
  synthetic: false,
111
112
  safetyFloor
112
113
  };
@@ -287,6 +288,14 @@ function markTouched(state, id) {
287
288
  state.touched.add(id);
288
289
  }
289
290
  }
291
+ function markStyleDirty(state, id) {
292
+ const n = state.doc.nodes.get(id);
293
+ if (n) {
294
+ n.meta.touched = true;
295
+ n.meta.styleDirty = true;
296
+ state.touched.add(id);
297
+ }
298
+ }
290
299
  function removeSubtree(state, id) {
291
300
  const node = state.doc.nodes.get(id);
292
301
  if (!node) return;
@@ -578,7 +587,7 @@ function applyOne(state, op) {
578
587
  return [precond(op, op.target, "setClassList target is not an element")];
579
588
  }
580
589
  el.computed = cloneStyleMap(op.style);
581
- markTouched(state, op.target);
590
+ markStyleDirty(state, op.target);
582
591
  return [];
583
592
  }
584
593
  case "mergeStyle": {
@@ -601,7 +610,7 @@ function applyOne(state, op) {
601
610
  const src = doc.nodes.get(op.source);
602
611
  if (src) markTouched(state, op.source);
603
612
  }
604
- markTouched(state, op.target);
613
+ markStyleDirty(state, op.target);
605
614
  return [];
606
615
  }
607
616
  case "foldInheritedStyles":
@@ -652,7 +661,7 @@ function applyFold(state, op) {
652
661
  }
653
662
  if (folded) {
654
663
  into.computed = { blocks: nextBlocks };
655
- markTouched(state, intoId);
664
+ markStyleDirty(state, intoId);
656
665
  }
657
666
  }
658
667
  for (const d of issues) state.diagnostics.push(d);
@@ -912,8 +921,123 @@ function buildMatchContext(doc, elementId, resolver, selectors, safety, phase, i
912
921
  var DISPLAY = "display";
913
922
  var POSITION = "position";
914
923
  var TRANSFORM = "transform";
924
+ var ALIGN_ITEMS = "align-items";
925
+ var JUSTIFY_CONTENT = "justify-content";
926
+ var JUSTIFY_ITEMS = "justify-items";
927
+ var PLACE_ITEMS = "place-items";
928
+ var PLACE_SELF = "place-self";
915
929
  var CONTEXT_SAFE_DISPLAYS = /* @__PURE__ */ new Set(["block", "contents", ""]);
916
930
  var STATIC_POSITIONS = /* @__PURE__ */ new Set(["static", ""]);
931
+ var CENTERING_DISPLAYS = /* @__PURE__ */ new Set(["flex", "grid"]);
932
+ var GRID_PARENT_DISPLAYS = /* @__PURE__ */ new Set(["grid"]);
933
+ var STRETCHY_ITEM_ALIGN = /* @__PURE__ */ new Set(["normal", "stretch"]);
934
+ var PARENT_ITEMS_ALIGN_PROPS = [ALIGN_ITEMS, JUSTIFY_ITEMS, PLACE_ITEMS];
935
+ function isBaseCondition(block) {
936
+ const c = block.condition;
937
+ return c.media === "" && c.states.length === 0 && c.pseudoElement === "";
938
+ }
939
+ function baseValue(sm, prop) {
940
+ for (const block of sm.blocks.values()) {
941
+ if (!isBaseCondition(block)) continue;
942
+ const d = block.decls.get(prop);
943
+ return d ? String(d.value) : null;
944
+ }
945
+ return null;
946
+ }
947
+ function parentIsFillingGrid(before, wrapper, norm) {
948
+ if (wrapper.parent == null) return false;
949
+ const p = before.nodes.get(wrapper.parent);
950
+ if (!p || p.kind !== "element") return false;
951
+ const pc2 = norm.normalizeStyleMap(p.computed);
952
+ let baseIsGrid = false;
953
+ for (const block of pc2.blocks.values()) {
954
+ const disp = block.decls.get(DISPLAY);
955
+ if (disp) {
956
+ if (!GRID_PARENT_DISPLAYS.has(String(disp.value))) return false;
957
+ if (isBaseCondition(block)) baseIsGrid = true;
958
+ }
959
+ for (const prop of PARENT_ITEMS_ALIGN_PROPS) {
960
+ const d = block.decls.get(prop);
961
+ if (d && !STRETCHY_ITEM_ALIGN.has(String(d.value))) return false;
962
+ }
963
+ }
964
+ return baseIsGrid;
965
+ }
966
+ function wrapperHasOnlyCenteringStyle(wrapperComputed, childComputed, norm) {
967
+ for (const block of wrapperComputed.blocks.values()) {
968
+ const base = isBaseCondition(block);
969
+ const ck = conditionKey(block.condition);
970
+ for (const [prop, decl] of block.decls) {
971
+ const val = String(decl.value);
972
+ if (prop === DISPLAY) {
973
+ if (base && CENTERING_DISPLAYS.has(val)) continue;
974
+ return false;
975
+ }
976
+ if (prop === ALIGN_ITEMS) {
977
+ if (base && val === "center") continue;
978
+ return false;
979
+ }
980
+ if (prop === JUSTIFY_CONTENT) {
981
+ if (base && val === "center") continue;
982
+ return false;
983
+ }
984
+ if (prop === POSITION) {
985
+ if (STATIC_POSITIONS.has(val)) continue;
986
+ return false;
987
+ }
988
+ if (prop === TRANSFORM) {
989
+ if (val === "none") continue;
990
+ return false;
991
+ }
992
+ if (isInherited2(decl, norm)) continue;
993
+ if (childReproduces(childComputed, ck, prop, val)) continue;
994
+ return false;
995
+ }
996
+ }
997
+ return true;
998
+ }
999
+ function wrapperCentersSingleElement(before, wrapper) {
1000
+ let elements = 0;
1001
+ for (const cid of wrapper.children) {
1002
+ const n = before.nodes.get(cid);
1003
+ if (!n) continue;
1004
+ if (n.kind === "element") {
1005
+ elements += 1;
1006
+ continue;
1007
+ }
1008
+ if (n.kind === "comment") continue;
1009
+ if (n.kind === "text" && n.value.trim() === "") continue;
1010
+ return false;
1011
+ }
1012
+ return elements === 1;
1013
+ }
1014
+ function childHasSelfAlign(childBefore, norm) {
1015
+ if (!childBefore) return false;
1016
+ const sm = norm.normalizeStyleMap(childBefore);
1017
+ for (const block of sm.blocks.values()) {
1018
+ for (const prop of SELF_ALIGN_PROPS) {
1019
+ const d = block.decls.get(prop);
1020
+ if (d && !NEUTRAL_ALIGN.has(String(d.value))) return true;
1021
+ }
1022
+ }
1023
+ return false;
1024
+ }
1025
+ function childGainsPlaceSelfCenter(childAfter) {
1026
+ if (baseValue(childAfter, PLACE_SELF) === "center") return true;
1027
+ return baseValue(childAfter, "align-self") === "center" && baseValue(childAfter, "justify-self") === "center";
1028
+ }
1029
+ function isContextCompensatedCentering(before, wrapper, wrapperComputed, childBefore, childAfter, norm) {
1030
+ if (!childAfter) return false;
1031
+ if (!CENTERING_DISPLAYS.has(baseValue(wrapperComputed, DISPLAY) ?? "")) return false;
1032
+ if (baseValue(wrapperComputed, ALIGN_ITEMS) !== "center") return false;
1033
+ if (baseValue(wrapperComputed, JUSTIFY_CONTENT) !== "center") return false;
1034
+ const childAfterNorm = norm.normalizeStyleMap(childAfter);
1035
+ if (!childGainsPlaceSelfCenter(childAfterNorm)) return false;
1036
+ if (!wrapperHasOnlyCenteringStyle(wrapperComputed, childAfterNorm, norm)) return false;
1037
+ if (!wrapperCentersSingleElement(before, wrapper)) return false;
1038
+ if (childHasSelfAlign(childBefore, norm)) return false;
1039
+ return parentIsFillingGrid(before, wrapper, norm);
1040
+ }
917
1041
  var SELF_ALIGN_PROPS = [
918
1042
  "place-self",
919
1043
  "align-self",
@@ -1013,6 +1137,9 @@ function classifyFlattenOps(before, after, ops, norm) {
1013
1137
  const wrapperComputed = norm.normalizeStyleMap(wrapper.computed);
1014
1138
  const childAfter = childId != null ? getElement(after, childId)?.computed ?? null : null;
1015
1139
  const childBefore = childId != null ? getElement(before, childId)?.computed ?? null : null;
1140
+ if (isContextCompensatedCentering(before, wrapper, wrapperComputed, childBefore, childAfter, norm)) {
1141
+ return { kind: "provably-safe", wrapperId, childId };
1142
+ }
1016
1143
  if (establishesChildContext(wrapperComputed)) {
1017
1144
  return { kind: "needs-verification", wrapperId, childId };
1018
1145
  }
@@ -1441,15 +1568,34 @@ function sameTokens(a, b) {
1441
1568
  for (let i = 0; i < a.length; i += 1) if (a[i] !== b[i]) return false;
1442
1569
  return true;
1443
1570
  }
1571
+ function residualStyle(computed2, covered, norm) {
1572
+ const cov = norm.normalizeStyleMap(covered);
1573
+ const blocks = /* @__PURE__ */ new Map();
1574
+ for (const [key, block] of norm.normalizeStyleMap(computed2).blocks) {
1575
+ const covBlock = cov.blocks.get(key);
1576
+ const decls = /* @__PURE__ */ new Map();
1577
+ for (const [prop, decl] of block.decls) {
1578
+ const covDecl = covBlock?.decls.get(prop);
1579
+ if (covDecl && covDecl.value === decl.value && covDecl.important === decl.important) continue;
1580
+ decls.set(prop, decl);
1581
+ }
1582
+ if (decls.size > 0) blocks.set(key, { condition: block.condition, decls });
1583
+ }
1584
+ return { blocks };
1585
+ }
1444
1586
  function syncClassesFromComputed(doc, resolver, norm) {
1445
1587
  const sink = createSyntheticSink();
1446
1588
  for (const id of elementIds(doc)) {
1447
1589
  const el = getElement(doc, id);
1448
- if (!el || !el.meta.touched) continue;
1590
+ if (!el) continue;
1591
+ if (!el.meta.styleDirty) continue;
1449
1592
  if (el.classes.opaque || el.classes.hasDynamic) continue;
1450
1593
  const tokens = staticTokensOf(el.classes);
1594
+ const retained = tokens.filter((t) => !resolver.selectorUsage(t).droppable);
1595
+ const covered = retained.length > 0 ? resolver.resolve({ classes: retained }).styles : null;
1596
+ const target = covered ? residualStyle(el.computed, covered, norm) : el.computed;
1451
1597
  const ctx = { normalizer: norm, sink };
1452
- const emitted = resolver.emit(el.computed, ctx).classes;
1598
+ const emitted = resolver.emit(target, ctx).classes;
1453
1599
  if (emitted.length === 0) continue;
1454
1600
  const emittedSet = new Set(emitted);
1455
1601
  const next = [];
@@ -2161,19 +2307,28 @@ var flexCenterWrapper = definePattern({
2161
2307
  flattenInto: "child",
2162
2308
  childGains: { placeSelf: "center" }
2163
2309
  },
2164
- // Collapsing a flex-centering wrapper to `place-self:center` on the child only stays centered when
2165
- // the child's NEW parent is flex/grid; moreover the wrapper's own `display:flex` establishes a
2166
- // formatting context. Both make this a `needs-verification` flatten, which the conservative
2167
- // production gate (`'provably-safe'`, used by the harness) intentionally REVERTSso every case
2168
- // here is a no-match: the wrapper is preserved. Op-level rewrite correctness (purity, id-preserving
2169
- // unwrap, opacity-barrier safety) is still asserted by the invariant suite over every pattern.
2310
+ // Collapsing a flex-centering wrapper to `place-self:center` on the child is render-identical ONLY
2311
+ // when the child's NEW parent is a statically-known GRID that lets the wrapper fill its area (there
2312
+ // `place-self`'s align-self AND justify-self both take effect). Under that ONE context the flatten is
2313
+ // classified `provably-safe` and commits; under a flex/block/unknown parentor when the wrapper
2314
+ // drops any own style it stays `needs-verification` and the conservative production gate PRESERVES
2315
+ // it. Op-level correctness (purity, id-preserving unwrap, opacity-barrier safety) is additionally
2316
+ // asserted by the invariant suite over every pattern.
2170
2317
  test: {
2318
+ cases: [
2319
+ {
2320
+ name: "grid parent \u2192 flattened (child gains place-self-center)",
2321
+ before: '<div className="grid"><div className="flex items-center justify-center"><span className="bg-red-200">x</span></div></div>',
2322
+ after: '<div className="grid"><span className="bg-red-200 place-self-center">x</span></div>'
2323
+ }
2324
+ ],
2171
2325
  noMatch: [
2172
- // Even under a static flex/grid parent the centering flatten is not provably layout-neutral
2173
- // (the wrapper itself establishes a flex formatting context) → left unchanged.
2174
- '<div className="grid"><div className="flex items-center justify-center"><span className="bg-red-200">x</span></div></div>',
2175
- // Non-flex/grid parent (document root): place-self centering would not hold → left unchanged.
2326
+ // Non-grid (flex) parent (document root): `justify-self` is ignored in flex → not provably safe.
2176
2327
  '<div className="flex justify-center items-center"><div className="bg-red-200">Hello</div></div>',
2328
+ // Grid parent, but the wrapper drops padding when removed → not layout-neutral (rule 3).
2329
+ '<div className="grid"><div className="p-4 flex items-center justify-center"><span className="bg-red-200">x</span></div></div>',
2330
+ // Grid parent forcing place-items-center: the wrapper would not fill its area → fill guard skips.
2331
+ '<div className="grid place-items-center"><div className="flex items-center justify-center"><span className="bg-red-200">x</span></div></div>',
2177
2332
  // onClick is a hard opacity barrier → the wrapper is load-bearing regardless of the gate.
2178
2333
  '<div className="flex justify-center items-center" onClick={handleClick}><div className="bg-red-200">Hello</div></div>'
2179
2334
  ]
@@ -3377,11 +3532,11 @@ var paddingShorthand = definePattern({
3377
3532
  });
3378
3533
 
3379
3534
  // ../patterns/src/library/compress/place-shorthand.pattern.ts
3380
- var ALIGN_ITEMS = "align-items";
3381
- var JUSTIFY_ITEMS = "justify-items";
3382
- var PLACE_ITEMS = "place-items";
3535
+ var ALIGN_ITEMS2 = "align-items";
3536
+ var JUSTIFY_ITEMS2 = "justify-items";
3537
+ var PLACE_ITEMS2 = "place-items";
3383
3538
  var ALIGN_CONTENT = "align-content";
3384
- var JUSTIFY_CONTENT = "justify-content";
3539
+ var JUSTIFY_CONTENT2 = "justify-content";
3385
3540
  var PLACE_CONTENT = "place-content";
3386
3541
  var BASE_KEY8 = conditionKey(BASE_CONDITION);
3387
3542
  function samePair(a, b) {
@@ -3421,21 +3576,21 @@ var placeShorthand = definePattern({
3421
3576
  rewriteClasses(computed2) {
3422
3577
  const base = computed2.blocks.get(BASE_KEY8);
3423
3578
  if (!base) return null;
3424
- const alignItems = base.decls.get(ALIGN_ITEMS);
3425
- const justifyItems = base.decls.get(JUSTIFY_ITEMS);
3579
+ const alignItems = base.decls.get(ALIGN_ITEMS2);
3580
+ const justifyItems = base.decls.get(JUSTIFY_ITEMS2);
3426
3581
  const alignContent = base.decls.get(ALIGN_CONTENT);
3427
- const justifyContent = base.decls.get(JUSTIFY_CONTENT);
3582
+ const justifyContent = base.decls.get(JUSTIFY_CONTENT2);
3428
3583
  const next = new Map(base.decls);
3429
3584
  let collapsed = false;
3430
3585
  if (samePair(alignItems, justifyItems)) {
3431
- next.delete(ALIGN_ITEMS);
3432
- next.delete(JUSTIFY_ITEMS);
3433
- next.set(PLACE_ITEMS, placeDecl(PLACE_ITEMS, alignItems));
3586
+ next.delete(ALIGN_ITEMS2);
3587
+ next.delete(JUSTIFY_ITEMS2);
3588
+ next.set(PLACE_ITEMS2, placeDecl(PLACE_ITEMS2, alignItems));
3434
3589
  collapsed = true;
3435
3590
  }
3436
3591
  if (samePair(alignContent, justifyContent)) {
3437
3592
  next.delete(ALIGN_CONTENT);
3438
- next.delete(JUSTIFY_CONTENT);
3593
+ next.delete(JUSTIFY_CONTENT2);
3439
3594
  next.set(PLACE_CONTENT, placeDecl(PLACE_CONTENT, alignContent));
3440
3595
  collapsed = true;
3441
3596
  }
@@ -4624,11 +4779,349 @@ function createCssResolver(cssFiles = [], options) {
4624
4779
  var import_node_path = require("path");
4625
4780
  var import_node_url = require("url");
4626
4781
 
4782
+ // ../frontend-html/src/backend.ts
4783
+ var import_magic_string = __toESM(require("magic-string"), 1);
4784
+ function staticTokensOf2(classes) {
4785
+ const out = [];
4786
+ for (const seg of classes.segments) {
4787
+ if (seg.kind === "static") for (const t of seg.tokens) out.push(t.value);
4788
+ }
4789
+ return out;
4790
+ }
4791
+ function sameTokens2(a, b) {
4792
+ if (a.length !== b.length) return false;
4793
+ for (let i = 0; i < a.length; i += 1) if (a[i] !== b[i]) return false;
4794
+ return true;
4795
+ }
4796
+ function primarySource(doc) {
4797
+ for (const sf of doc.sources.values()) {
4798
+ if (typeof sf.text === "string" && sf.text.length > 0) return sf;
4799
+ }
4800
+ return null;
4801
+ }
4802
+ function collectKept(doc) {
4803
+ const out = [];
4804
+ const seen = /* @__PURE__ */ new Set();
4805
+ const visit = (id) => {
4806
+ if (seen.has(id)) return;
4807
+ seen.add(id);
4808
+ const n = doc.nodes.get(id);
4809
+ if (!n) return;
4810
+ out.push(n);
4811
+ if (n.kind === "element" || n.kind === "fragment") for (const c of n.children) visit(c);
4812
+ };
4813
+ visit(doc.root);
4814
+ return out;
4815
+ }
4816
+ function strictlyContains(a, b) {
4817
+ if (a.file !== b.file) return false;
4818
+ if (a.start <= b.start && b.end <= a.end) return !(a.start === b.start && a.end === b.end);
4819
+ return false;
4820
+ }
4821
+ function backrefIds(doc) {
4822
+ const out = [];
4823
+ const max = doc.alloc.peek;
4824
+ for (let i = 1; i < max; i += 1) {
4825
+ const id = i;
4826
+ if (doc.backref.get(id)) out.push(id);
4827
+ }
4828
+ return out;
4829
+ }
4830
+ function currentTokens(sf, valueSpan) {
4831
+ const raw = sf.text.slice(valueSpan.start, valueSpan.end).trim();
4832
+ const unquoted = raw.replace(/^['"]/, "").replace(/['"]$/, "");
4833
+ return unquoted.split(/\s+/).filter((t) => t.length > 0);
4834
+ }
4835
+ function editClasses(ms, doc, sf, el) {
4836
+ const classes = el.classes;
4837
+ if (classes.hasDynamic || classes.opaque) return false;
4838
+ const tokens = staticTokensOf2(classes);
4839
+ const valueSpan = classes.valueSpan;
4840
+ if (valueSpan && valueSpan.file === sf.id) {
4841
+ if (sameTokens2(currentTokens(sf, valueSpan), tokens)) return false;
4842
+ const current = sf.text.slice(valueSpan.start, valueSpan.end).trim();
4843
+ const quote = current.startsWith("'") ? "'" : '"';
4844
+ ms.overwrite(valueSpan.start, valueSpan.end, `${quote}${tokens.join(" ")}${quote}`);
4845
+ return true;
4846
+ }
4847
+ if (tokens.length === 0) return false;
4848
+ const openTag = doc.backref.get(el.id)?.openTagSpan;
4849
+ if (!openTag || openTag.file !== sf.id) return false;
4850
+ ms.appendLeft(openTag.start + 1 + el.tag.length, ` class="${tokens.join(" ")}"`);
4851
+ return true;
4852
+ }
4853
+ function surgicalPrint(doc) {
4854
+ const sf = primarySource(doc);
4855
+ if (!sf) return null;
4856
+ const ms = new import_magic_string.default(sf.text);
4857
+ const kept = collectKept(doc);
4858
+ const keptSpans = [];
4859
+ for (const n of kept) if (n.span && n.span.file === sf.id) keptSpans.push(n.span);
4860
+ const removed = [];
4861
+ for (const id of backrefIds(doc)) {
4862
+ if (doc.nodes.has(id)) continue;
4863
+ const back = doc.backref.get(id);
4864
+ if (!back || back.span.file !== sf.id) continue;
4865
+ const unwrapped = keptSpans.some((k) => strictlyContains(back.span, k));
4866
+ removed.push({ backref: back, unwrapped });
4867
+ }
4868
+ const fullRemovals = removed.filter((r) => !r.unwrapped).map((r) => r.backref.span);
4869
+ for (const r of removed) {
4870
+ const s = r.backref.span;
4871
+ if (fullRemovals.some((f) => f !== s && strictlyContains(f, s))) continue;
4872
+ if (r.unwrapped) {
4873
+ const open = r.backref.openTagSpan;
4874
+ const close = r.backref.closeTagSpan;
4875
+ if (open && open.file === sf.id && open.end > open.start) ms.remove(open.start, open.end);
4876
+ if (close && close.file === sf.id && close.end > close.start) ms.remove(close.start, close.end);
4877
+ } else {
4878
+ ms.remove(s.start, s.end);
4879
+ }
4880
+ }
4881
+ for (const n of kept) if (n.kind === "element") editClasses(ms, doc, sf, n);
4882
+ return ms.toString();
4883
+ }
4884
+ function doPrint(doc) {
4885
+ return surgicalPrint(doc) ?? "";
4886
+ }
4887
+
4888
+ // ../frontend-html/src/parse.ts
4889
+ var import_node_module3 = require("module");
4890
+
4891
+ // ../frontend-html/src/walk.ts
4892
+ var HTML_LANGS = ["html"];
4893
+ var FILE_ID = 1;
4894
+ function looksLikeHtml(id, code) {
4895
+ if (/\.html?$/i.test(id)) return true;
4896
+ const head = code.slice(0, 256).trimStart().toLowerCase();
4897
+ return head.startsWith("<!doctype html") || head.startsWith("<html") || head.startsWith("<");
4898
+ }
4899
+ var OPAQUE_SUBTREE_TAGS = /* @__PURE__ */ new Set([
4900
+ "script",
4901
+ "style",
4902
+ "template",
4903
+ "svg",
4904
+ "pre",
4905
+ "textarea"
4906
+ ]);
4907
+ function isOpaqueSubtreeTag(tag) {
4908
+ return OPAQUE_SUBTREE_TAGS.has(tag);
4909
+ }
4910
+ function elementIsOpaque(attrs) {
4911
+ for (const a of attrs) {
4912
+ const n = a.name.toLowerCase();
4913
+ if (n === "id" || n === "contenteditable") return true;
4914
+ if (n.startsWith("on")) return true;
4915
+ }
4916
+ return false;
4917
+ }
4918
+ function hasEventHandler(attrs) {
4919
+ for (const a of attrs) if (/^on/i.test(a.name)) return true;
4920
+ return false;
4921
+ }
4922
+ function span(start, end) {
4923
+ return { file: FILE_ID, start, end };
4924
+ }
4925
+ function attrsLocOf(loc) {
4926
+ if (!loc) return void 0;
4927
+ return loc.startTag?.attrs ?? loc.attrs;
4928
+ }
4929
+ function classValueSpan(loc, source) {
4930
+ const attrsLoc = attrsLocOf(loc);
4931
+ const cl = attrsLoc?.["class"];
4932
+ if (!cl) return null;
4933
+ const text = source.slice(cl.startOffset, cl.endOffset);
4934
+ const eq = text.indexOf("=");
4935
+ if (eq === -1) return null;
4936
+ let i = eq + 1;
4937
+ while (i < text.length && /\s/.test(text[i])) i += 1;
4938
+ if (i >= text.length) return null;
4939
+ return span(cl.startOffset + i, cl.endOffset);
4940
+ }
4941
+
4942
+ // ../frontend-html/src/parse.ts
4943
+ var cachedParse5 = null;
4944
+ function loadParse5() {
4945
+ if (cachedParse5) return cachedParse5;
4946
+ const req = (0, import_node_module3.createRequire)(importMetaUrl);
4947
+ cachedParse5 = req("parse5");
4948
+ return cachedParse5;
4949
+ }
4950
+ function doParse(code, ctx) {
4951
+ const diagnostics = [];
4952
+ const doc = createDocument("html");
4953
+ const backref = doc.backref;
4954
+ const parse5 = loadParse5();
4955
+ const document2 = parse5.parse(code, { sourceCodeLocationInfo: true });
4956
+ const eol = code.includes("\r\n") ? "\r\n" : "\n";
4957
+ const sourceFile = {
4958
+ id: FILE_ID,
4959
+ path: ctx.id,
4960
+ text: code,
4961
+ frontend: "html",
4962
+ eol,
4963
+ indentUnit: " ",
4964
+ native: document2
4965
+ };
4966
+ doc.sources.set(FILE_ID, sourceFile);
4967
+ const resolveComputed = (tokens, tag, nodeId) => {
4968
+ if (tokens.length === 0) return emptyStyleMap();
4969
+ const res = ctx.resolver.resolve({ classes: tokens, element: { tagName: tag, namespace: "html" } });
4970
+ for (const w of res.warnings) {
4971
+ diagnostics.push({
4972
+ code: "DF_STYLE_CONFLICT_UNRESOLVED",
4973
+ severity: w.severity,
4974
+ message: w.message,
4975
+ nodeId
4976
+ });
4977
+ }
4978
+ return ctx.normalizer.normalizeStyleMap(res.styles);
4979
+ };
4980
+ const splitTokens = (raw) => raw.split(/\s+/).filter((t) => t.length > 0);
4981
+ const appendChild = (node, parentId, out) => {
4982
+ const name = node.nodeName;
4983
+ if (name === "#text") {
4984
+ const value = node.value ?? "";
4985
+ const id = doc.alloc.next();
4986
+ const loc = node.sourceCodeLocation ?? null;
4987
+ doc.nodes.set(
4988
+ id,
4989
+ createText(id, value, {
4990
+ parent: parentId,
4991
+ span: loc ? span(loc.startOffset, loc.endOffset) : null,
4992
+ collapsible: /^\s*$/.test(value)
4993
+ })
4994
+ );
4995
+ out.push(id);
4996
+ return;
4997
+ }
4998
+ if (name === "#comment") {
4999
+ const id = doc.alloc.next();
5000
+ const loc = node.sourceCodeLocation ?? null;
5001
+ doc.nodes.set(
5002
+ id,
5003
+ createComment(id, node.data ?? "", {
5004
+ parent: parentId,
5005
+ span: loc ? span(loc.startOffset, loc.endOffset) : null
5006
+ })
5007
+ );
5008
+ out.push(id);
5009
+ return;
5010
+ }
5011
+ if (name === "#documentType") return;
5012
+ if (name.startsWith("#")) {
5013
+ for (const c of node.childNodes ?? []) appendChild(c, parentId, out);
5014
+ return;
5015
+ }
5016
+ out.push(buildElement(node, parentId));
5017
+ };
5018
+ const buildElement = (node, parentId) => {
5019
+ const id = doc.alloc.next();
5020
+ const tag = (node.tagName ?? node.nodeName).toLowerCase();
5021
+ const loc = node.sourceCodeLocation ?? null;
5022
+ const attrsArr = node.attrs ?? [];
5023
+ const opaqueSubtree = isOpaqueSubtreeTag(tag);
5024
+ const synthetic = loc == null;
5025
+ const opaque2 = opaqueSubtree || synthetic || elementIsOpaque(attrsArr);
5026
+ const meta = defaultMeta();
5027
+ meta.hasEventHandlers = hasEventHandler(attrsArr);
5028
+ meta.safetyFloor = opaque2 ? 0 : 3;
5029
+ let classes = emptyClassList();
5030
+ let classTokens = [];
5031
+ const entries = /* @__PURE__ */ new Map();
5032
+ const order = [];
5033
+ for (const a of attrsArr) {
5034
+ if (a.name.toLowerCase() === "class") {
5035
+ classTokens = splitTokens(a.value);
5036
+ const valueSpan = classValueSpan(loc, code);
5037
+ const clAttr = attrsLocOf(loc)?.["class"];
5038
+ const seg = {
5039
+ kind: "static",
5040
+ span: valueSpan ?? void 0,
5041
+ tokens: classTokens.map((value) => ({ value }))
5042
+ };
5043
+ classes = {
5044
+ form: "string-literal",
5045
+ segments: [seg],
5046
+ valueSpan,
5047
+ attrSpan: clAttr ? span(clAttr.startOffset, clAttr.endOffset) : void 0,
5048
+ hasDynamic: false,
5049
+ opaque: false,
5050
+ rewritable: valueSpan != null
5051
+ };
5052
+ continue;
5053
+ }
5054
+ const v = a.value;
5055
+ entries.set(a.name, { kind: "static", value: v === "" ? true : v });
5056
+ order.push(a.name);
5057
+ }
5058
+ const attrs = { entries, spreads: [], order };
5059
+ const computed2 = resolveComputed(classTokens, tag, id);
5060
+ const children = [];
5061
+ if (!opaqueSubtree) {
5062
+ for (const c of node.childNodes ?? []) appendChild(c, id, children);
5063
+ }
5064
+ const el = createElement(id, {
5065
+ tag,
5066
+ namespace: "html",
5067
+ isComponent: false,
5068
+ selfClosing: loc ? loc.endTag == null : false,
5069
+ classes,
5070
+ computed: computed2,
5071
+ attrs,
5072
+ children,
5073
+ parent: parentId,
5074
+ span: loc ? span(loc.startOffset, loc.endOffset) : null,
5075
+ meta
5076
+ });
5077
+ doc.nodes.set(id, el);
5078
+ if (loc) {
5079
+ backref.set(id, {
5080
+ nodeId: id,
5081
+ span: span(loc.startOffset, loc.endOffset),
5082
+ openTagSpan: loc.startTag ? span(loc.startTag.startOffset, loc.startTag.endOffset) : null,
5083
+ closeTagSpan: loc.endTag ? span(loc.endTag.startOffset, loc.endTag.endOffset) : null,
5084
+ innerSpan: null,
5085
+ selfClosing: loc.endTag == null
5086
+ });
5087
+ }
5088
+ return id;
5089
+ };
5090
+ const rootFrag = doc.nodes.get(doc.root);
5091
+ appendChild(document2, doc.root, rootFrag.children);
5092
+ return { doc, diagnostics };
5093
+ }
5094
+
5095
+ // ../frontend-html/src/index.ts
5096
+ var htmlFrontend = {
5097
+ name: "html",
5098
+ langs: HTML_LANGS,
5099
+ canParse(id, code) {
5100
+ return looksLikeHtml(id, code);
5101
+ },
5102
+ parse(code, ctx) {
5103
+ return doParse(code, ctx);
5104
+ }
5105
+ };
5106
+ function createHtmlFrontend() {
5107
+ return htmlFrontend;
5108
+ }
5109
+ var htmlBackend = {
5110
+ name: "html",
5111
+ langs: HTML_LANGS,
5112
+ print(doc, _plan, _ctx) {
5113
+ return { code: doPrint(doc), map: null, edits: [], diagnostics: [] };
5114
+ }
5115
+ };
5116
+ function createHtmlBackend() {
5117
+ return htmlBackend;
5118
+ }
5119
+
4627
5120
  // ../frontend-jsx/src/frontend-ast.ts
4628
5121
  var import_traverse = __toESM(require("@babel/traverse"), 1);
4629
5122
  var traverse = typeof import_traverse.default === "function" ? import_traverse.default : import_traverse.default.default;
4630
5123
  var JSX_LANGS = ["jsx", "tsx"];
4631
- var FILE_ID = 1;
5124
+ var FILE_ID2 = 1;
4632
5125
  function jsxName(node) {
4633
5126
  switch (node.type) {
4634
5127
  case "JSXIdentifier":
@@ -4752,7 +5245,7 @@ function looksLikeJsx(id, code) {
4752
5245
 
4753
5246
  // ../frontend-jsx/src/frontend-parse.ts
4754
5247
  var import_parser = require("@babel/parser");
4755
- function doParse(code, ctx) {
5248
+ function doParse2(code, ctx) {
4756
5249
  const diagnostics = [];
4757
5250
  const doc = createDocument("jsx");
4758
5251
  const backref = doc.backref;
@@ -4762,7 +5255,7 @@ function doParse(code, ctx) {
4762
5255
  });
4763
5256
  const eol = code.includes("\r\n") ? "\r\n" : "\n";
4764
5257
  const sourceFile = {
4765
- id: FILE_ID,
5258
+ id: FILE_ID2,
4766
5259
  path: ctx.id,
4767
5260
  text: code,
4768
5261
  frontend: "jsx",
@@ -4770,23 +5263,23 @@ function doParse(code, ctx) {
4770
5263
  indentUnit: " ",
4771
5264
  native: ast
4772
5265
  };
4773
- doc.sources.set(FILE_ID, sourceFile);
5266
+ doc.sources.set(FILE_ID2, sourceFile);
4774
5267
  const spanOf = (node) => {
4775
5268
  if (node.start == null || node.end == null) return null;
4776
- const span = {
4777
- file: FILE_ID,
5269
+ const span2 = {
5270
+ file: FILE_ID2,
4778
5271
  start: node.start,
4779
5272
  end: node.end,
4780
5273
  startLoc: node.loc ? { line: node.loc.start.line, column: node.loc.start.column } : void 0,
4781
5274
  endLoc: node.loc ? { line: node.loc.end.line, column: node.loc.end.column } : void 0
4782
5275
  };
4783
- return span;
5276
+ return span2;
4784
5277
  };
4785
5278
  const sliceOf = (node) => node.start == null || node.end == null ? "" : code.slice(node.start, node.end);
4786
5279
  const internExpr = (node, spread) => {
4787
5280
  const payload = { text: sliceOf(node), spread };
4788
5281
  return doc.exprs.intern({
4789
- span: spanOf(node) ?? { file: FILE_ID, start: 0, end: 0 },
5282
+ span: spanOf(node) ?? { file: FILE_ID2, start: 0, end: 0 },
4790
5283
  kind: exprKind(node),
4791
5284
  payload
4792
5285
  });
@@ -4832,7 +5325,7 @@ function doParse(code, ctx) {
4832
5325
  }
4833
5326
  return emptyClassList();
4834
5327
  };
4835
- const staticTokensOf3 = (classes) => {
5328
+ const staticTokensOf4 = (classes) => {
4836
5329
  const out = [];
4837
5330
  for (const seg of classes.segments) {
4838
5331
  if (seg.kind === "static") for (const t of seg.tokens) out.push(t.value);
@@ -4910,7 +5403,7 @@ function doParse(code, ctx) {
4910
5403
  doc.nodes.set(id, createFragment(id, { children, parent: parentId, span: spanOf(node) }));
4911
5404
  backref.set(id, {
4912
5405
  nodeId: id,
4913
- span: spanOf(node) ?? { file: FILE_ID, start: 0, end: 0 },
5406
+ span: spanOf(node) ?? { file: FILE_ID2, start: 0, end: 0 },
4914
5407
  openTagSpan: spanOf(node.openingFragment),
4915
5408
  closeTagSpan: spanOf(node.closingFragment),
4916
5409
  innerSpan: null,
@@ -4959,7 +5452,7 @@ function doParse(code, ctx) {
4959
5452
  }
4960
5453
  let computed2 = emptyStyleMap();
4961
5454
  if (!classes.hasDynamic) {
4962
- const tokens = staticTokensOf3(classes);
5455
+ const tokens = staticTokensOf4(classes);
4963
5456
  if (tokens.length > 0) {
4964
5457
  const res = ctx.resolver.resolve({
4965
5458
  classes: tokens,
@@ -4992,13 +5485,13 @@ function doParse(code, ctx) {
4992
5485
  });
4993
5486
  doc.nodes.set(id, el);
4994
5487
  const inner = children.length > 0 ? spanOf(node.children[0]) && spanOf(node.children.at(-1)) ? {
4995
- file: FILE_ID,
5488
+ file: FILE_ID2,
4996
5489
  start: spanOf(node.children[0]).start,
4997
5490
  end: spanOf(node.children.at(-1)).end
4998
5491
  } : null : null;
4999
5492
  backref.set(id, {
5000
5493
  nodeId: id,
5001
- span: spanOf(node) ?? { file: FILE_ID, start: 0, end: 0 },
5494
+ span: spanOf(node) ?? { file: FILE_ID2, start: 0, end: 0 },
5002
5495
  openTagSpan: spanOf(opening),
5003
5496
  closeTagSpan: node.closingElement ? spanOf(node.closingElement) : null,
5004
5497
  innerSpan: inner,
@@ -5033,7 +5526,7 @@ var jsxFrontend = {
5033
5526
  return looksLikeJsx(id, code);
5034
5527
  },
5035
5528
  parse(code, ctx) {
5036
- return doParse(code, ctx);
5529
+ return doParse2(code, ctx);
5037
5530
  }
5038
5531
  };
5039
5532
  function createJsxFrontend() {
@@ -5041,7 +5534,7 @@ function createJsxFrontend() {
5041
5534
  }
5042
5535
 
5043
5536
  // ../frontend-jsx/src/backend.ts
5044
- var import_magic_string = __toESM(require("magic-string"), 1);
5537
+ var import_magic_string2 = __toESM(require("magic-string"), 1);
5045
5538
  var JSX_LANGS2 = ["jsx", "tsx"];
5046
5539
  function exprText(doc, ref) {
5047
5540
  const rec = doc.exprs.get(ref);
@@ -5055,20 +5548,20 @@ function exprText(doc, ref) {
5055
5548
  }
5056
5549
  return { text: "", spread: false };
5057
5550
  }
5058
- function staticTokensOf2(classes) {
5551
+ function staticTokensOf3(classes) {
5059
5552
  const out = [];
5060
5553
  for (const seg of classes.segments) {
5061
5554
  if (seg.kind === "static") for (const t of seg.tokens) out.push(t.value);
5062
5555
  }
5063
5556
  return out;
5064
5557
  }
5065
- function primarySource(doc) {
5558
+ function primarySource2(doc) {
5066
5559
  for (const sf of doc.sources.values()) {
5067
5560
  if (typeof sf.text === "string" && sf.text.length > 0) return sf;
5068
5561
  }
5069
5562
  return null;
5070
5563
  }
5071
- function collectKept(doc) {
5564
+ function collectKept2(doc) {
5072
5565
  const out = [];
5073
5566
  const seen = /* @__PURE__ */ new Set();
5074
5567
  const visit = (id) => {
@@ -5082,15 +5575,15 @@ function collectKept(doc) {
5082
5575
  visit(doc.root);
5083
5576
  return out;
5084
5577
  }
5085
- function strictlyContains(a, b) {
5578
+ function strictlyContains2(a, b) {
5086
5579
  if (a.file !== b.file) return false;
5087
5580
  if (a.start <= b.start && b.end <= a.end) return !(a.start === b.start && a.end === b.end);
5088
5581
  return false;
5089
5582
  }
5090
- function editClasses(ms, doc, sf, el) {
5583
+ function editClasses2(ms, doc, sf, el) {
5091
5584
  const classes = el.classes;
5092
5585
  if (classes.hasDynamic || classes.opaque) return false;
5093
- const tokens = staticTokensOf2(classes);
5586
+ const tokens = staticTokensOf3(classes);
5094
5587
  const valueSpan = classes.valueSpan;
5095
5588
  if (valueSpan && valueSpan.file === sf.id) {
5096
5589
  const current = sf.text.slice(valueSpan.start, valueSpan.end);
@@ -5154,10 +5647,10 @@ function transferKeyOnUnwrap(ms, doc, sf, region, kept) {
5154
5647
  const inside = [];
5155
5648
  for (const n of kept) {
5156
5649
  if (n.kind !== "element" || !n.span || n.span.file !== sf.id) continue;
5157
- if (strictlyContains(region.span, n.span)) inside.push(n);
5650
+ if (strictlyContains2(region.span, n.span)) inside.push(n);
5158
5651
  }
5159
5652
  const maximal = inside.filter(
5160
- (n) => !inside.some((o) => o !== n && o.span && n.span && strictlyContains(o.span, n.span))
5653
+ (n) => !inside.some((o) => o !== n && o.span && n.span && strictlyContains2(o.span, n.span))
5161
5654
  );
5162
5655
  if (maximal.length !== 1) return;
5163
5656
  const child = maximal[0];
@@ -5166,25 +5659,25 @@ function transferKeyOnUnwrap(ms, doc, sf, region, kept) {
5166
5659
  if (extractKeyAttr(sf.text.slice(childOpen.start, childOpen.end))) return;
5167
5660
  ms.appendLeft(childOpen.start + 1 + child.tag.length, ` ${keyAttr}`);
5168
5661
  }
5169
- function surgicalPrint(doc) {
5170
- const sf = primarySource(doc);
5662
+ function surgicalPrint2(doc) {
5663
+ const sf = primarySource2(doc);
5171
5664
  if (!sf) return null;
5172
- const ms = new import_magic_string.default(sf.text);
5173
- const kept = collectKept(doc);
5665
+ const ms = new import_magic_string2.default(sf.text);
5666
+ const kept = collectKept2(doc);
5174
5667
  const keptSpans = [];
5175
5668
  for (const n of kept) if (n.span && n.span.file === sf.id) keptSpans.push(n.span);
5176
5669
  const removed = [];
5177
- for (const id of backrefIds(doc)) {
5670
+ for (const id of backrefIds2(doc)) {
5178
5671
  if (doc.nodes.has(id)) continue;
5179
5672
  const back = doc.backref.get(id);
5180
5673
  if (!back || back.span.file !== sf.id) continue;
5181
- const unwrapped = keptSpans.some((k) => strictlyContains(back.span, k));
5674
+ const unwrapped = keptSpans.some((k) => strictlyContains2(back.span, k));
5182
5675
  removed.push({ backref: back, unwrapped });
5183
5676
  }
5184
5677
  const fullRemovals = removed.filter((r) => !r.unwrapped).map((r) => r.backref.span);
5185
5678
  for (const r of removed) {
5186
- const span = r.backref.span;
5187
- const coveredByFull = fullRemovals.some((f) => f !== span && strictlyContains(f, span));
5679
+ const span2 = r.backref.span;
5680
+ const coveredByFull = fullRemovals.some((f) => f !== span2 && strictlyContains2(f, span2));
5188
5681
  if (coveredByFull) continue;
5189
5682
  if (r.unwrapped) {
5190
5683
  transferKeyOnUnwrap(ms, doc, sf, r.backref, kept);
@@ -5195,15 +5688,15 @@ function surgicalPrint(doc) {
5195
5688
  ms.remove(close.start, close.end);
5196
5689
  }
5197
5690
  } else {
5198
- ms.remove(span.start, span.end);
5691
+ ms.remove(span2.start, span2.end);
5199
5692
  }
5200
5693
  }
5201
5694
  for (const n of kept) {
5202
- if (n.kind === "element") editClasses(ms, doc, sf, n);
5695
+ if (n.kind === "element") editClasses2(ms, doc, sf, n);
5203
5696
  }
5204
5697
  return ms.toString();
5205
5698
  }
5206
- function backrefIds(doc) {
5699
+ function backrefIds2(doc) {
5207
5700
  const out = [];
5208
5701
  const max = doc.alloc.peek;
5209
5702
  for (let i = 1; i < max; i += 1) {
@@ -5218,7 +5711,7 @@ function classText(doc, classes) {
5218
5711
  if (dynamic && dynamic.kind === "dynamic") {
5219
5712
  return `className={${exprText(doc, dynamic.expr).text}}`;
5220
5713
  }
5221
- const tokens = staticTokensOf2(classes);
5714
+ const tokens = staticTokensOf3(classes);
5222
5715
  return `className="${tokens.join(" ")}"`;
5223
5716
  }
5224
5717
  function attrText(doc, name, value) {
@@ -5271,15 +5764,15 @@ function rePrint(doc) {
5271
5764
  if (!root || root.kind !== "fragment") return printNode(doc, doc.root);
5272
5765
  return root.children.map((c) => printNode(doc, c)).join("");
5273
5766
  }
5274
- function doPrint(doc) {
5275
- const surgical = surgicalPrint(doc);
5767
+ function doPrint2(doc) {
5768
+ const surgical = surgicalPrint2(doc);
5276
5769
  return surgical ?? rePrint(doc);
5277
5770
  }
5278
5771
  var jsxBackend = {
5279
5772
  name: "babel-jsx",
5280
5773
  langs: JSX_LANGS2,
5281
5774
  print(doc, _plan, _ctx) {
5282
- const code = doPrint(doc);
5775
+ const code = doPrint2(doc);
5283
5776
  return { code, map: null, edits: [], diagnostics: [] };
5284
5777
  }
5285
5778
  };
@@ -5294,6 +5787,11 @@ function jsxKindOf(id) {
5294
5787
  if (clean.endsWith(".jsx")) return "jsx";
5295
5788
  return null;
5296
5789
  }
5790
+ function htmlKindOf(id) {
5791
+ const clean = (id.split("?", 1)[0] ?? id).toLowerCase();
5792
+ if (clean.endsWith(".html") || clean.endsWith(".htm")) return "html";
5793
+ return null;
5794
+ }
5297
5795
  function eolOf2(doc) {
5298
5796
  for (const src of doc.sources.values()) return src.eol;
5299
5797
  return "\n";
@@ -5361,9 +5859,51 @@ function runJsxPipeline(code, id, kind, resolver, patterns, safety) {
5361
5859
  const { doc: optimized } = runPasses(doc, passes, ctx);
5362
5860
  return finishPipeline(optimized, id, resolver);
5363
5861
  }
5862
+ function prepareHtml(code, id, resolver, patterns, safety, gate) {
5863
+ const parsed = createHtmlFrontend().parse(code, {
5864
+ id,
5865
+ kind: "html",
5866
+ resolver,
5867
+ normalizer,
5868
+ config: {},
5869
+ onDiagnostic: () => {
5870
+ }
5871
+ });
5872
+ const doc = parsed.doc;
5873
+ const ctx = {
5874
+ doc,
5875
+ safetyCeiling: safety,
5876
+ normalizer,
5877
+ selectors: buildSelectorIndex(doc, resolver),
5878
+ resolver,
5879
+ gate
5880
+ };
5881
+ return { doc, ctx, passes: buildPasses(patterns) };
5882
+ }
5883
+ function finishHtmlPipeline(optimized, id, resolver) {
5884
+ syncClassesFromComputed(optimized, resolver, normalizer);
5885
+ const printed = createHtmlBackend().print(
5886
+ optimized,
5887
+ { moduleId: id, ops: [], provenance: /* @__PURE__ */ new Map() },
5888
+ {
5889
+ normalizer,
5890
+ resolver,
5891
+ sink: createSyntheticSink(),
5892
+ eol: eolOf2(optimized),
5893
+ onDiagnostic: () => {
5894
+ }
5895
+ }
5896
+ );
5897
+ return printed.code;
5898
+ }
5899
+ function runHtmlPipeline(code, id, resolver, patterns, safety) {
5900
+ const { doc, ctx, passes } = prepareHtml(code, id, resolver, patterns, safety, "provably-safe");
5901
+ const { doc: optimized } = runPasses(doc, passes, ctx);
5902
+ return finishHtmlPipeline(optimized, id, resolver);
5903
+ }
5364
5904
 
5365
5905
  // src/index.ts
5366
- var DEFAULT_INCLUDE = [".jsx", ".tsx", ".html"];
5906
+ var DEFAULT_INCLUDE = [".jsx", ".tsx", ".html", ".htm"];
5367
5907
  function resolveOptions(options) {
5368
5908
  return {
5369
5909
  provider: options.provider ?? "auto",
@@ -5399,9 +5939,15 @@ function createDomflax(options = {}) {
5399
5939
  transform(code, id) {
5400
5940
  if (!isSupported(id, resolved.include)) return { code, map: null };
5401
5941
  const kind = jsxKindOf(id);
5402
- if (kind === null) return { code, map: null };
5403
- const out = runJsxPipeline(code, id, kind, getResolver(), patterns, resolved.safety);
5404
- return { code: out, map: null };
5942
+ if (kind !== null) {
5943
+ const out = runJsxPipeline(code, id, kind, getResolver(), patterns, resolved.safety);
5944
+ return { code: out, map: null };
5945
+ }
5946
+ if (htmlKindOf(id) !== null) {
5947
+ const out = runHtmlPipeline(code, id, getResolver(), patterns, resolved.safety);
5948
+ return { code: out, map: null };
5949
+ }
5950
+ return { code, map: null };
5405
5951
  }
5406
5952
  };
5407
5953
  }