@pyreon/compiler 0.23.0 → 0.24.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.
@@ -5386,7 +5386,7 @@ var drawChart = (function (exports) {
5386
5386
  </script>
5387
5387
  <script>
5388
5388
  /*<!--*/
5389
- const data = {"version":2,"tree":{"name":"root","children":[{"name":"index.js","children":[{"name":"src","children":[{"uid":"826b944a-1","name":"defer-inline.ts"},{"uid":"826b944a-3","name":"event-names.ts"},{"uid":"826b944a-5","name":"load-native.ts"},{"uid":"826b944a-7","name":"jsx.ts"},{"uid":"826b944a-9","name":"pyreon-intercept.ts"},{"uid":"826b944a-11","name":"reactivity-lens.ts"},{"uid":"826b944a-13","name":"project-scanner.ts"},{"uid":"826b944a-15","name":"react-intercept.ts"},{"uid":"826b944a-17","name":"test-audit.ts"},{"uid":"826b944a-19","name":"island-audit.ts"},{"uid":"826b944a-21","name":"ssg-audit.ts"},{"uid":"826b944a-23","name":"index.ts"}]}]}],"isRoot":true},"nodeParts":{"826b944a-1":{"renderedLength":15789,"gzipLength":5000,"brotliLength":0,"metaUid":"826b944a-0"},"826b944a-3":{"renderedLength":2941,"gzipLength":1335,"brotliLength":0,"metaUid":"826b944a-2"},"826b944a-5":{"renderedLength":3959,"gzipLength":1744,"brotliLength":0,"metaUid":"826b944a-4"},"826b944a-7":{"renderedLength":66047,"gzipLength":16428,"brotliLength":0,"metaUid":"826b944a-6"},"826b944a-9":{"renderedLength":29336,"gzipLength":9283,"brotliLength":0,"metaUid":"826b944a-8"},"826b944a-11":{"renderedLength":4373,"gzipLength":2130,"brotliLength":0,"metaUid":"826b944a-10"},"826b944a-13":{"renderedLength":4762,"gzipLength":1730,"brotliLength":0,"metaUid":"826b944a-12"},"826b944a-15":{"renderedLength":28896,"gzipLength":7322,"brotliLength":0,"metaUid":"826b944a-14"},"826b944a-17":{"renderedLength":13167,"gzipLength":5060,"brotliLength":0,"metaUid":"826b944a-16"},"826b944a-19":{"renderedLength":18208,"gzipLength":6051,"brotliLength":0,"metaUid":"826b944a-18"},"826b944a-21":{"renderedLength":12773,"gzipLength":4183,"brotliLength":0,"metaUid":"826b944a-20"},"826b944a-23":{"renderedLength":0,"gzipLength":0,"brotliLength":0,"metaUid":"826b944a-22"}},"nodeMetas":{"826b944a-0":{"id":"/src/defer-inline.ts","moduleParts":{"index.js":"826b944a-1"},"imported":[{"uid":"826b944a-24"}],"importedBy":[{"uid":"826b944a-22"}]},"826b944a-2":{"id":"/src/event-names.ts","moduleParts":{"index.js":"826b944a-3"},"imported":[],"importedBy":[{"uid":"826b944a-6"}]},"826b944a-4":{"id":"/src/load-native.ts","moduleParts":{"index.js":"826b944a-5"},"imported":[{"uid":"826b944a-29"},{"uid":"826b944a-30"},{"uid":"826b944a-27"}],"importedBy":[{"uid":"826b944a-6"}]},"826b944a-6":{"id":"/src/jsx.ts","moduleParts":{"index.js":"826b944a-7"},"imported":[{"uid":"826b944a-25"},{"uid":"826b944a-24"},{"uid":"826b944a-2"},{"uid":"826b944a-4"}],"importedBy":[{"uid":"826b944a-22"},{"uid":"826b944a-10"}]},"826b944a-8":{"id":"/src/pyreon-intercept.ts","moduleParts":{"index.js":"826b944a-9"},"imported":[{"uid":"826b944a-28"}],"importedBy":[{"uid":"826b944a-22"},{"uid":"826b944a-10"}]},"826b944a-10":{"id":"/src/reactivity-lens.ts","moduleParts":{"index.js":"826b944a-11"},"imported":[{"uid":"826b944a-6"},{"uid":"826b944a-8"}],"importedBy":[{"uid":"826b944a-22"}]},"826b944a-12":{"id":"/src/project-scanner.ts","moduleParts":{"index.js":"826b944a-13"},"imported":[{"uid":"826b944a-26"},{"uid":"826b944a-27"}],"importedBy":[{"uid":"826b944a-22"}]},"826b944a-14":{"id":"/src/react-intercept.ts","moduleParts":{"index.js":"826b944a-15"},"imported":[{"uid":"826b944a-28"}],"importedBy":[{"uid":"826b944a-22"}]},"826b944a-16":{"id":"/src/test-audit.ts","moduleParts":{"index.js":"826b944a-17"},"imported":[{"uid":"826b944a-26"},{"uid":"826b944a-27"}],"importedBy":[{"uid":"826b944a-22"}]},"826b944a-18":{"id":"/src/island-audit.ts","moduleParts":{"index.js":"826b944a-19"},"imported":[{"uid":"826b944a-26"},{"uid":"826b944a-27"},{"uid":"826b944a-28"}],"importedBy":[{"uid":"826b944a-22"}]},"826b944a-20":{"id":"/src/ssg-audit.ts","moduleParts":{"index.js":"826b944a-21"},"imported":[{"uid":"826b944a-26"},{"uid":"826b944a-27"},{"uid":"826b944a-28"}],"importedBy":[{"uid":"826b944a-22"}]},"826b944a-22":{"id":"/src/index.ts","moduleParts":{"index.js":"826b944a-23"},"imported":[{"uid":"826b944a-0"},{"uid":"826b944a-6"},{"uid":"826b944a-10"},{"uid":"826b944a-12"},{"uid":"826b944a-14"},{"uid":"826b944a-8"},{"uid":"826b944a-16"},{"uid":"826b944a-18"},{"uid":"826b944a-20"}],"importedBy":[],"isEntry":true},"826b944a-24":{"id":"oxc-parser","moduleParts":{},"imported":[],"importedBy":[{"uid":"826b944a-0"},{"uid":"826b944a-6"}]},"826b944a-25":{"id":"magic-string","moduleParts":{},"imported":[],"importedBy":[{"uid":"826b944a-6"}]},"826b944a-26":{"id":"node:fs","moduleParts":{},"imported":[],"importedBy":[{"uid":"826b944a-12"},{"uid":"826b944a-16"},{"uid":"826b944a-18"},{"uid":"826b944a-20"}]},"826b944a-27":{"id":"node:path","moduleParts":{},"imported":[],"importedBy":[{"uid":"826b944a-12"},{"uid":"826b944a-16"},{"uid":"826b944a-18"},{"uid":"826b944a-20"},{"uid":"826b944a-4"}]},"826b944a-28":{"id":"typescript","moduleParts":{},"imported":[],"importedBy":[{"uid":"826b944a-14"},{"uid":"826b944a-8"},{"uid":"826b944a-18"},{"uid":"826b944a-20"}]},"826b944a-29":{"id":"node:module","moduleParts":{},"imported":[],"importedBy":[{"uid":"826b944a-4"}]},"826b944a-30":{"id":"node:url","moduleParts":{},"imported":[],"importedBy":[{"uid":"826b944a-4"}]}},"env":{"rollup":"4.23.0"},"options":{"gzip":true,"brotli":false,"sourcemap":false}};
5389
+ const data = {"version":2,"tree":{"name":"root","children":[{"name":"index.js","children":[{"name":"src","children":[{"uid":"6eb92b25-1","name":"defer-inline.ts"},{"uid":"6eb92b25-3","name":"event-names.ts"},{"uid":"6eb92b25-5","name":"load-native.ts"},{"uid":"6eb92b25-7","name":"jsx.ts"},{"uid":"6eb92b25-9","name":"pyreon-intercept.ts"},{"uid":"6eb92b25-11","name":"reactivity-lens.ts"},{"uid":"6eb92b25-13","name":"lpih.ts"},{"uid":"6eb92b25-15","name":"project-scanner.ts"},{"uid":"6eb92b25-17","name":"react-intercept.ts"},{"uid":"6eb92b25-19","name":"test-audit.ts"},{"uid":"6eb92b25-21","name":"island-audit.ts"},{"uid":"6eb92b25-23","name":"ssg-audit.ts"},{"uid":"6eb92b25-25","name":"index.ts"}]}]}],"isRoot":true},"nodeParts":{"6eb92b25-1":{"renderedLength":15789,"gzipLength":5000,"brotliLength":0,"metaUid":"6eb92b25-0"},"6eb92b25-3":{"renderedLength":2941,"gzipLength":1335,"brotliLength":0,"metaUid":"6eb92b25-2"},"6eb92b25-5":{"renderedLength":3959,"gzipLength":1744,"brotliLength":0,"metaUid":"6eb92b25-4"},"6eb92b25-7":{"renderedLength":75616,"gzipLength":18800,"brotliLength":0,"metaUid":"6eb92b25-6"},"6eb92b25-9":{"renderedLength":29341,"gzipLength":9289,"brotliLength":0,"metaUid":"6eb92b25-8"},"6eb92b25-11":{"renderedLength":4373,"gzipLength":2130,"brotliLength":0,"metaUid":"6eb92b25-10"},"6eb92b25-13":{"renderedLength":5266,"gzipLength":2166,"brotliLength":0,"metaUid":"6eb92b25-12"},"6eb92b25-15":{"renderedLength":4762,"gzipLength":1730,"brotliLength":0,"metaUid":"6eb92b25-14"},"6eb92b25-17":{"renderedLength":28896,"gzipLength":7322,"brotliLength":0,"metaUid":"6eb92b25-16"},"6eb92b25-19":{"renderedLength":13167,"gzipLength":5060,"brotliLength":0,"metaUid":"6eb92b25-18"},"6eb92b25-21":{"renderedLength":18208,"gzipLength":6051,"brotliLength":0,"metaUid":"6eb92b25-20"},"6eb92b25-23":{"renderedLength":12773,"gzipLength":4183,"brotliLength":0,"metaUid":"6eb92b25-22"},"6eb92b25-25":{"renderedLength":0,"gzipLength":0,"brotliLength":0,"metaUid":"6eb92b25-24"}},"nodeMetas":{"6eb92b25-0":{"id":"/src/defer-inline.ts","moduleParts":{"index.js":"6eb92b25-1"},"imported":[{"uid":"6eb92b25-26"}],"importedBy":[{"uid":"6eb92b25-24"}]},"6eb92b25-2":{"id":"/src/event-names.ts","moduleParts":{"index.js":"6eb92b25-3"},"imported":[],"importedBy":[{"uid":"6eb92b25-6"}]},"6eb92b25-4":{"id":"/src/load-native.ts","moduleParts":{"index.js":"6eb92b25-5"},"imported":[{"uid":"6eb92b25-31"},{"uid":"6eb92b25-32"},{"uid":"6eb92b25-29"}],"importedBy":[{"uid":"6eb92b25-6"}]},"6eb92b25-6":{"id":"/src/jsx.ts","moduleParts":{"index.js":"6eb92b25-7"},"imported":[{"uid":"6eb92b25-27"},{"uid":"6eb92b25-26"},{"uid":"6eb92b25-2"},{"uid":"6eb92b25-4"}],"importedBy":[{"uid":"6eb92b25-24"},{"uid":"6eb92b25-10"}]},"6eb92b25-8":{"id":"/src/pyreon-intercept.ts","moduleParts":{"index.js":"6eb92b25-9"},"imported":[{"uid":"6eb92b25-30"}],"importedBy":[{"uid":"6eb92b25-24"},{"uid":"6eb92b25-10"}]},"6eb92b25-10":{"id":"/src/reactivity-lens.ts","moduleParts":{"index.js":"6eb92b25-11"},"imported":[{"uid":"6eb92b25-6"},{"uid":"6eb92b25-8"}],"importedBy":[{"uid":"6eb92b25-24"}]},"6eb92b25-12":{"id":"/src/lpih.ts","moduleParts":{"index.js":"6eb92b25-13"},"imported":[],"importedBy":[{"uid":"6eb92b25-24"}]},"6eb92b25-14":{"id":"/src/project-scanner.ts","moduleParts":{"index.js":"6eb92b25-15"},"imported":[{"uid":"6eb92b25-28"},{"uid":"6eb92b25-29"}],"importedBy":[{"uid":"6eb92b25-24"}]},"6eb92b25-16":{"id":"/src/react-intercept.ts","moduleParts":{"index.js":"6eb92b25-17"},"imported":[{"uid":"6eb92b25-30"}],"importedBy":[{"uid":"6eb92b25-24"}]},"6eb92b25-18":{"id":"/src/test-audit.ts","moduleParts":{"index.js":"6eb92b25-19"},"imported":[{"uid":"6eb92b25-28"},{"uid":"6eb92b25-29"}],"importedBy":[{"uid":"6eb92b25-24"}]},"6eb92b25-20":{"id":"/src/island-audit.ts","moduleParts":{"index.js":"6eb92b25-21"},"imported":[{"uid":"6eb92b25-28"},{"uid":"6eb92b25-29"},{"uid":"6eb92b25-30"}],"importedBy":[{"uid":"6eb92b25-24"}]},"6eb92b25-22":{"id":"/src/ssg-audit.ts","moduleParts":{"index.js":"6eb92b25-23"},"imported":[{"uid":"6eb92b25-28"},{"uid":"6eb92b25-29"},{"uid":"6eb92b25-30"}],"importedBy":[{"uid":"6eb92b25-24"}]},"6eb92b25-24":{"id":"/src/index.ts","moduleParts":{"index.js":"6eb92b25-25"},"imported":[{"uid":"6eb92b25-0"},{"uid":"6eb92b25-6"},{"uid":"6eb92b25-10"},{"uid":"6eb92b25-12"},{"uid":"6eb92b25-14"},{"uid":"6eb92b25-16"},{"uid":"6eb92b25-8"},{"uid":"6eb92b25-18"},{"uid":"6eb92b25-20"},{"uid":"6eb92b25-22"}],"importedBy":[],"isEntry":true},"6eb92b25-26":{"id":"oxc-parser","moduleParts":{},"imported":[],"importedBy":[{"uid":"6eb92b25-0"},{"uid":"6eb92b25-6"}]},"6eb92b25-27":{"id":"magic-string","moduleParts":{},"imported":[],"importedBy":[{"uid":"6eb92b25-6"}]},"6eb92b25-28":{"id":"node:fs","moduleParts":{},"imported":[],"importedBy":[{"uid":"6eb92b25-14"},{"uid":"6eb92b25-18"},{"uid":"6eb92b25-20"},{"uid":"6eb92b25-22"}]},"6eb92b25-29":{"id":"node:path","moduleParts":{},"imported":[],"importedBy":[{"uid":"6eb92b25-14"},{"uid":"6eb92b25-18"},{"uid":"6eb92b25-20"},{"uid":"6eb92b25-22"},{"uid":"6eb92b25-4"}]},"6eb92b25-30":{"id":"typescript","moduleParts":{},"imported":[],"importedBy":[{"uid":"6eb92b25-16"},{"uid":"6eb92b25-8"},{"uid":"6eb92b25-20"},{"uid":"6eb92b25-22"}]},"6eb92b25-31":{"id":"node:module","moduleParts":{},"imported":[],"importedBy":[{"uid":"6eb92b25-4"}]},"6eb92b25-32":{"id":"node:url","moduleParts":{},"imported":[],"importedBy":[{"uid":"6eb92b25-4"}]}},"env":{"rollup":"4.23.0"},"options":{"gzip":true,"brotli":false,"sourcemap":false}};
5390
5390
 
5391
5391
  const run = () => {
5392
5392
  const width = window.innerWidth;
package/lib/index.js CHANGED
@@ -785,6 +785,23 @@ function scanCollapsibleSites(code, filename, collapsibleSources) {
785
785
  childrenText: site.childrenText,
786
786
  key: rocketstyleCollapseKey(tag, site.props, site.childrenText)
787
787
  });
788
+ else {
789
+ const dyn = detectDynamicCollapsibleShape(node, tag);
790
+ if (dyn) for (const value of [dyn.dynamicProp.valueTruthy, dyn.dynamicProp.valueFalsy]) {
791
+ const expandedProps = {
792
+ ...dyn.props,
793
+ [dyn.dynamicProp.name]: value
794
+ };
795
+ out.push({
796
+ componentName: tag,
797
+ source: imp.source,
798
+ importedName: imp.imported,
799
+ props: expandedProps,
800
+ childrenText: dyn.childrenText,
801
+ key: rocketstyleCollapseKey(tag, expandedProps, dyn.childrenText)
802
+ });
803
+ }
804
+ }
788
805
  }
789
806
  }
790
807
  for (const k in node) {
@@ -880,6 +897,104 @@ function detectPartialCollapsibleShape(node, _tag) {
880
897
  handlers
881
898
  };
882
899
  }
900
+ /**
901
+ * Dynamic-prop partial-collapse detector — PR 2 of the dynamic-prop
902
+ * partial-collapse build (`.claude/plans/open-work-2026-q3.md` → #1
903
+ * dynamic-prop bucket = 15.3% of all real-corpus sites; the next-bigger
904
+ * bite after the `on*`-handler partial-collapse).
905
+ *
906
+ * Mirrors `detectPartialCollapsibleShape`'s "extend the bail catalogue
907
+ * with ONE relaxation" pattern (see that detector's docstring + `PR 1`
908
+ * `_rsCollapseDyn` runtime helper, PR #765). The single relaxation: a
909
+ * `JSXExpressionContainer` wrapping a `ConditionalExpression` whose
910
+ * `consequent` AND `alternate` are BOTH `StringLiteral` is acceptable as
911
+ * a "ternary-of-two-literals" dynamic prop — captured as a {@link DynamicCollapsibleProp}
912
+ * with the cond source span + the two literal values.
913
+ *
914
+ * Constraint: **AT MOST ONE** such dynamic prop per site. Multiple
915
+ * ternaries would compound into a 2^N value-set per site at build time
916
+ * and an N-axis dispatcher at runtime — that's a separable scope
917
+ * (potential PR 5+), NOT this PR. Sites with 2+ ternaries bail (return
918
+ * null), keeping the normal mount; same conservative shape as the rest
919
+ * of the detector family.
920
+ *
921
+ * Constraint: the FULL `on*`-handler relaxation is also folded in — a
922
+ * site can have ONE ternary AND `on*` handlers in the same call. This
923
+ * matches the real-corpus shape (a Button with `state={cond ? 'a' : 'b'}`
924
+ * almost always also has an `onClick`). The two relaxations compose
925
+ * cleanly because they're orthogonal at the resolver layer (handlers
926
+ * don't change rendered CSS; the ternary picks among pre-resolved
927
+ * classes). PR 3's emit will use `_rsCollapseDyn` when handlers are
928
+ * absent and a future combined helper when both are present — for THIS
929
+ * PR (detector-only) the structure carries both so PR 3 can dispatch.
930
+ *
931
+ * Every OTHER non-literal shape still bails (spread, non-handler
932
+ * non-ternary `{expr}` prop, multi-literal ternary anywhere, computed-
933
+ * expression ternary, element/expression child, boolean attr) —
934
+ * conservative by construction, exactly like the rest of the family.
935
+ * Returns `null` when there are ZERO ternaries so the on*-only path
936
+ * (`detectPartialCollapsibleShape`) and the full-collapse path
937
+ * (`detectCollapsibleShape`) stay byte-unchanged and no detector both
938
+ * claims the same site.
939
+ *
940
+ * A consistency test (PR 3) will lock this catalogue against the
941
+ * plugin scan, mirroring the `detectCollapsibleShape` ↔ `scanCollapsibleSites`
942
+ * + `detectPartialCollapsibleShape` ↔ scan invariants — keys cannot drift.
943
+ */
944
+ function detectDynamicCollapsibleShape(node, _tag) {
945
+ const props = {};
946
+ const handlers = [];
947
+ const dynamicProps = [];
948
+ for (const attr of jsxAttrs(node)) {
949
+ if (attr.type !== "JSXAttribute") return null;
950
+ const nm = attr.name?.type === "JSXIdentifier" ? attr.name.name : null;
951
+ if (!nm) return null;
952
+ const v = attr.value;
953
+ if (!v) return null;
954
+ if (v.type === "StringLiteral" || v.type === "Literal" && typeof v.value === "string") {
955
+ props[nm] = String(v.value);
956
+ continue;
957
+ }
958
+ if (v.type === "JSXExpressionContainer" && v.expression && typeof v.expression.start === "number" && typeof v.expression.end === "number") {
959
+ if (/^on[A-Z]/.test(nm)) {
960
+ handlers.push({
961
+ name: nm,
962
+ exprStart: v.expression.start,
963
+ exprEnd: v.expression.end
964
+ });
965
+ continue;
966
+ }
967
+ const expr = v.expression;
968
+ if (expr.type === "ConditionalExpression" && expr.test && typeof expr.test.start === "number" && typeof expr.test.end === "number" && expr.consequent && expr.alternate) {
969
+ const isLitStr = (n) => {
970
+ const x = n;
971
+ return x?.type === "StringLiteral" || x?.type === "Literal" && typeof x.value === "string";
972
+ };
973
+ if (isLitStr(expr.consequent) && isLitStr(expr.alternate)) {
974
+ dynamicProps.push({
975
+ name: nm,
976
+ condStart: expr.test.start,
977
+ condEnd: expr.test.end,
978
+ valueTruthy: String(expr.consequent.value),
979
+ valueFalsy: String(expr.alternate.value)
980
+ });
981
+ continue;
982
+ }
983
+ }
984
+ }
985
+ return null;
986
+ }
987
+ let childrenText = "";
988
+ for (const c of jsxChildren(node)) if (c.type === "JSXText") childrenText += c.value ?? "";
989
+ else return null;
990
+ if (dynamicProps.length !== 1) return null;
991
+ return {
992
+ props,
993
+ childrenText: childrenText.trim(),
994
+ handlers,
995
+ dynamicProp: dynamicProps[0]
996
+ };
997
+ }
883
998
  function transformJSX(code, filename = "input.tsx", options = {}) {
884
999
  if (options.collapseRocketstyle) return transformJSX_JS(code, filename, options);
885
1000
  if (nativeTransformJsx) try {
@@ -975,6 +1090,8 @@ function transformJSX_JS(code, filename = "input.tsx", options = {}) {
975
1090
  let needsMountSlotImportGlobal = false;
976
1091
  let needsCollapse = false;
977
1092
  let needsCollapseH = false;
1093
+ let needsCollapseDyn = false;
1094
+ let needsCollapseDynH = false;
978
1095
  const collapseRuleKeys = /* @__PURE__ */ new Set();
979
1096
  const collapseRules = [];
980
1097
  /**
@@ -997,7 +1114,7 @@ function transformJSX_JS(code, filename = "input.tsx", options = {}) {
997
1114
  if (!tag || tag.charAt(0) === tag.charAt(0).toLowerCase()) return false;
998
1115
  if (!cfg.candidates.has(tag)) return false;
999
1116
  const shape = detectCollapsibleShape(node, tag);
1000
- if (!shape) return tryPartialCollapse(node, tag);
1117
+ if (!shape) return tryPartialCollapse(node, tag) || tryDynamicCollapse(node, tag);
1001
1118
  const { props, childrenText } = shape;
1002
1119
  const key = rocketstyleCollapseKey(tag, props, childrenText);
1003
1120
  const site = cfg.sites.get(key);
@@ -1069,6 +1186,103 @@ function transformJSX_JS(code, filename = "input.tsx", options = {}) {
1069
1186
  }
1070
1187
  return true;
1071
1188
  }
1189
+ /**
1190
+ * PR 3 of the dynamic-prop partial-collapse build (open-work #1
1191
+ * dynamic-prop bucket = 15.3% of all real-corpus sites; the
1192
+ * next-bigger bite after the just-shipped `on*`-handler partial).
1193
+ * The dynamic-prop fallback `tryRocketstyleCollapse` defers to when
1194
+ * BOTH the full and the on*-handler-partial paths bail.
1195
+ *
1196
+ * Same site-resolution contract as the full path — the dynamic prop
1197
+ * is replaced with EACH literal value to compute TWO keys; the
1198
+ * resolver pre-renders both via the existing SSR pipeline; if both
1199
+ * lookups succeed AND the structural template is byte-identical
1200
+ * across values, emit `__rsCollapseDyn(html, [classes...], () =>
1201
+ * cond ? 0 : 1, () => __pyrMode() === "dark")` — the PR 1 runtime
1202
+ * helper (#765) dispatches across `(value × mode)` with a stride-2
1203
+ * value-major class layout.
1204
+ *
1205
+ * Conservative discipline:
1206
+ * - Either expanded key missing from sites map ⇒ bail (an
1207
+ * intermittent resolver failure on one value mustn't half-collapse)
1208
+ * - Divergent template HTML across values ⇒ bail (the dispatcher
1209
+ * assumes a shared template; deriveCollapseDyn cannot be done
1210
+ * across values that produce structurally different markup —
1211
+ * this is the cross-value parallel of `deriveCollapse`'s
1212
+ * light↔dark template-divergence bail)
1213
+ *
1214
+ * Handler-combined sites: when the detected dynamic site has `on*`
1215
+ * handlers (the most common real-corpus shape — bail-census measured
1216
+ * the no-handler subset at 0.2% of all sites; handler-combined is
1217
+ * the bulk of the 15.4% dynamic-prop bucket), emit
1218
+ * `__rsCollapseDynH(...)` (PR A: runtime helper) instead of
1219
+ * `__rsCollapseDyn(...)`. Handlers are orthogonal to the SSR-
1220
+ * resolved styler class (the resolver pre-renders both values
1221
+ * identically regardless of handlers); the union helper just
1222
+ * re-attaches them through the same canonical `_bindEvent` path
1223
+ * `tryPartialCollapse` uses.
1224
+ *
1225
+ * Rule injection unions the rule sets across both values (each value
1226
+ * may inject distinct CSS rules — e.g. `state="primary"` and
1227
+ * `state="secondary"` produce different background-color rules); the
1228
+ * union is the byte-set the dispatcher will need at runtime regardless
1229
+ * of which value the cond resolves to. Idempotent by per-value
1230
+ * `ruleKey` so a re-resolve / HMR is a no-op.
1231
+ */
1232
+ function tryDynamicCollapse(node, tag) {
1233
+ const cfg = options.collapseRocketstyle;
1234
+ if (!cfg) return false;
1235
+ const dyn = detectDynamicCollapsibleShape(node, tag);
1236
+ if (!dyn) return false;
1237
+ const { props, childrenText, dynamicProp, handlers } = dyn;
1238
+ const truthyProps = {
1239
+ ...props,
1240
+ [dynamicProp.name]: dynamicProp.valueTruthy
1241
+ };
1242
+ const falsyProps = {
1243
+ ...props,
1244
+ [dynamicProp.name]: dynamicProp.valueFalsy
1245
+ };
1246
+ const truthyKey = rocketstyleCollapseKey(tag, truthyProps, childrenText);
1247
+ const falsyKey = rocketstyleCollapseKey(tag, falsyProps, childrenText);
1248
+ const truthySite = cfg.sites.get(truthyKey);
1249
+ const falsySite = cfg.sites.get(falsyKey);
1250
+ if (!truthySite || !falsySite) return false;
1251
+ if (truthySite.templateHtml !== falsySite.templateHtml) return false;
1252
+ const classes = [
1253
+ truthySite.lightClass,
1254
+ truthySite.darkClass,
1255
+ falsySite.lightClass,
1256
+ falsySite.darkClass
1257
+ ];
1258
+ const condSrc = code.slice(dynamicProp.condStart, dynamicProp.condEnd);
1259
+ let call;
1260
+ if (handlers.length > 0) {
1261
+ const handlerObj = `{ ${handlers.map((h) => `${JSON.stringify(h.name)}: (${code.slice(h.exprStart, h.exprEnd)})`).join(", ")} }`;
1262
+ call = `__rsCollapseDynH(${JSON.stringify(truthySite.templateHtml)}, ${JSON.stringify(classes)}, () => (${condSrc}) ? 0 : 1, () => __pyrMode() === "dark", ${handlerObj})`;
1263
+ needsCollapseDynH = true;
1264
+ } else {
1265
+ call = `__rsCollapseDyn(${JSON.stringify(truthySite.templateHtml)}, ${JSON.stringify(classes)}, () => (${condSrc}) ? 0 : 1, () => __pyrMode() === "dark")`;
1266
+ needsCollapseDyn = true;
1267
+ }
1268
+ const start = node.start;
1269
+ const end = node.end;
1270
+ const parent = findParent(node);
1271
+ const needsBraces = parent && (parent.type === "JSXElement" || parent.type === "JSXFragment");
1272
+ replacements.push({
1273
+ start,
1274
+ end,
1275
+ text: needsBraces ? `{${call}}` : call
1276
+ });
1277
+ for (const site of [truthySite, falsySite]) if (!collapseRuleKeys.has(site.ruleKey)) {
1278
+ collapseRuleKeys.add(site.ruleKey);
1279
+ collapseRules.push({
1280
+ ruleKey: site.ruleKey,
1281
+ rules: site.rules
1282
+ });
1283
+ }
1284
+ return true;
1285
+ }
1072
1286
  function maybeHoist(node) {
1073
1287
  if ((node.type === "JSXElement" || node.type === "JSXFragment") && isStaticJSXNode(node)) {
1074
1288
  const name = `_$h${hoistIdx++}`;
@@ -1612,12 +1826,17 @@ function transformJSX_JS(code, filename = "input.tsx", options = {}) {
1612
1826
  if (needsWrapSpreadImport) coreImports.push("_wrapSpread");
1613
1827
  preamble = `import { ${coreImports.join(", ")} } from "@pyreon/core";\n` + preamble;
1614
1828
  }
1615
- if (needsCollapse) {
1829
+ if (needsCollapse || needsCollapseDyn || needsCollapseDynH) {
1616
1830
  const cfg = options.collapseRocketstyle;
1617
1831
  const rd = cfg.runtimeDomSource ?? "@pyreon/runtime-dom";
1618
1832
  const st = cfg.stylerSource ?? "@pyreon/styler";
1619
1833
  const inj = collapseRules.map((r) => `__rsSheet.injectRules(${JSON.stringify(r.rules)},${JSON.stringify(r.ruleKey)});`).join("");
1620
- preamble = `import { _rsCollapse as __rsCollapse${needsCollapseH ? ", _rsCollapseH as __rsCollapseH" : ""} } from "${rd}";\nimport { sheet as __rsSheet } from "${st}";\nimport { ${cfg.mode.name} as __pyrMode } from "${cfg.mode.source}";\n${inj}\n` + preamble;
1834
+ const rdImports = [];
1835
+ if (needsCollapse) rdImports.push("_rsCollapse as __rsCollapse");
1836
+ if (needsCollapseH) rdImports.push("_rsCollapseH as __rsCollapseH");
1837
+ if (needsCollapseDyn) rdImports.push("_rsCollapseDyn as __rsCollapseDyn");
1838
+ if (needsCollapseDynH) rdImports.push("_rsCollapseDynH as __rsCollapseDynH");
1839
+ preamble = `import { ${rdImports.join(", ")} } from "${rd}";\nimport { sheet as __rsSheet } from "${st}";\nimport { ${cfg.mode.name} as __pyrMode } from "${cfg.mode.source}";\n${inj}\n` + preamble;
1621
1840
  }
1622
1841
  if (preamble) s.prepend(preamble);
1623
1842
  const output = s.toString();
@@ -2807,7 +3026,7 @@ function detectPyreonPatterns(code, filename = "input.tsx") {
2807
3026
  }
2808
3027
  /** Fast regex pre-filter — returns true if the code is worth a full AST walk. */
2809
3028
  function hasPyreonPatterns(code) {
2810
- return /\bFor\b[^=]*\beach\s*=/.test(code) || /\btypeof\s+process\b/.test(code) || /\.theme\s*\(\s*\{\s*\}\s*\)/.test(code) || /\b(?:add|remove)EventListener\s*\(/.test(code) || /\bDate\.now\s*\(/.test(code) && /\bMath\.random\s*\(/.test(code) || /on[A-Z]\w*\s*=\s*\{\s*undefined\s*\}/.test(code) || /=\s*\(\s*\{[^}]{1,500}\}\s*[:)]/.test(code) || /\b(?:const|let|var)\s+\{[^}]{0,500}\}\s*=\s*[A-Za-z_$]/.test(code) || /\b(?:signal|computed)\s*[<(]/.test(code) || /\bif\s*\([^)]{1,500}\)[\s{]{0,20}return\s+null\b/.test(code) || /\bas\s+unknown\s+as\s+VNodeChild\b/.test(code) || /\b(?:useQuery|useInfiniteQuery|useQueries|useSuspenseQuery)\s*\(\s*\{/.test(code) || /\bisland\s*\(/.test(code) && /\bhydrate\s*:\s*['"]never['"]/.test(code);
3029
+ return /\bFor\b[^=]*\beach\s*=/.test(code) || /\btypeof\s+process\b/.test(code) || /\.theme\s*\(\s*\{\s*\}\s*\)/.test(code) || /\b(?:add|remove)EventListener\s*\(/.test(code) || /\bDate\.now\s*\(/.test(code) && /\bMath\.random\s*\(/.test(code) || /on[A-Z]\w{0,60}\s*=\s*\{\s*undefined\s*\}/.test(code) || /=\s*\(\s*\{[^}]{1,500}\}\s*[:)]/.test(code) || /\b(?:const|let|var)\s+\{[^}]{0,500}\}\s*=\s*[A-Za-z_$]/.test(code) || /\b(?:signal|computed)\s*[<(]/.test(code) || /\bif\s*\([^)]{1,500}\)[\s{]{0,20}return\s+null\b/.test(code) || /\bas\s+unknown\s+as\s+VNodeChild\b/.test(code) || /\b(?:useQuery|useInfiniteQuery|useQueries|useSuspenseQuery)\s*\(\s*\{/.test(code) || /\bisland\s*\(/.test(code) && /\bhydrate\s*:\s*['"]never['"]/.test(code);
2811
3030
  }
2812
3031
 
2813
3032
  //#endregion
@@ -2940,6 +3159,139 @@ function formatReactivityLens(code, result) {
2940
3159
  return out.join("\n");
2941
3160
  }
2942
3161
 
3162
+ //#endregion
3163
+ //#region src/lpih.ts
3164
+ /**
3165
+ * Threshold below which the rate suffix is omitted. A long-dormant node
3166
+ * decays toward 0; showing "0/s" or "0.001/s" is noise. The 0.5 cutoff
3167
+ * means "less than once every 2 seconds at steady state" — at that
3168
+ * rate, the cumulative count is the more useful signal.
3169
+ *
3170
+ * @internal — exported for tests + tunability.
3171
+ */
3172
+ const _LPIH_RATE_VISIBLE_THRESHOLD = .5;
3173
+ function _formatRate(rate1s) {
3174
+ if (rate1s < .5) return "";
3175
+ return rate1s < 10 ? ` (${rate1s.toFixed(1)}/s)` : ` (${Math.round(rate1s)}/s)`;
3176
+ }
3177
+ const DEFAULT_FORMAT = (detail, fire) => {
3178
+ const kindLabel = fire.kind ? `${fire.kind} ` : "";
3179
+ const rate = typeof fire.rate1s === "number" ? _formatRate(fire.rate1s) : "";
3180
+ return `${detail} — ${kindLabel}fired ${fire.count}×${rate}`;
3181
+ };
3182
+ /**
3183
+ * Merge runtime fire data onto static reactivity findings. Pure function,
3184
+ * deterministic, input not mutated.
3185
+ *
3186
+ * Matching rules:
3187
+ * - Only fires whose normalized `file` matches the analyzed source file
3188
+ * are considered (cross-file fires are silently skipped).
3189
+ * - Line-level matching only (column is ignored). V8 stack columns
3190
+ * differ from compiler-emitted span columns by 1+ chars in practice,
3191
+ * and the user-visible affordance is "this signal at this line is
3192
+ * firing" — line precision is sufficient.
3193
+ * - Multiple fires at the same `line` are summed; latest `lastFire`
3194
+ * and corresponding `kind` win.
3195
+ * - Findings of kind `footgun`, `hoisted-static`, or `static-text` are
3196
+ * passed through unchanged — they're not runtime-active reactive
3197
+ * reads, so a fire count at their location is unrelated to them.
3198
+ */
3199
+ function mergeFireDataIntoFindings(findings, fires, sourceFile, options = {}) {
3200
+ if (fires.length === 0) return findings;
3201
+ const norm = options.normalizeFile ?? ((p) => p);
3202
+ const format = options.formatDetail ?? DEFAULT_FORMAT;
3203
+ const targetFile = norm(sourceFile);
3204
+ const byLine = /* @__PURE__ */ new Map();
3205
+ for (const f of fires) {
3206
+ if (norm(f.file) !== targetFile) continue;
3207
+ const existing = byLine.get(f.line);
3208
+ if (existing) {
3209
+ existing.count += f.count;
3210
+ if (typeof f.rate1s === "number") existing.rate1s = (existing.rate1s ?? 0) + f.rate1s;
3211
+ if ((f.lastFire ?? -Infinity) > (existing.lastFire ?? -Infinity)) {
3212
+ existing.lastFire = f.lastFire;
3213
+ existing.kind = f.kind ?? existing.kind;
3214
+ }
3215
+ } else byLine.set(f.line, { ...f });
3216
+ }
3217
+ if (byLine.size === 0) return findings;
3218
+ return findings.map((finding) => {
3219
+ if (finding.kind === "footgun" || finding.kind === "hoisted-static" || finding.kind === "static-text") return finding;
3220
+ const fire = byLine.get(finding.line);
3221
+ if (!fire) return finding;
3222
+ return {
3223
+ ...finding,
3224
+ detail: format(finding.detail, fire)
3225
+ };
3226
+ });
3227
+ }
3228
+ /**
3229
+ * Synthesize "creation-site" inlay-hint findings directly from fire data.
3230
+ *
3231
+ * `analyzeReactivity()` produces findings at REACTIVE READ sites (JSX
3232
+ * expressions). But the runtime captures fires at CREATION sites
3233
+ * (`signal(0)`, `computed(...)`, `effect(...)`). These are usually
3234
+ * different source lines — so the merge function above only helps when
3235
+ * they happen to coincide.
3236
+ *
3237
+ * The simpler, more useful editor surface is: show fire counts AT THE
3238
+ * CREATION LINE. The user writes `const count = signal(0)` and sees
3239
+ * `(signal fired 129×)` as ghost text on that line, the same way
3240
+ * TypeScript shows the inferred type.
3241
+ *
3242
+ * This function turns each fire datum into a synthetic finding the LSP
3243
+ * can serve as an inlay hint. No static analysis required — pure runtime
3244
+ * data → editor hint.
3245
+ *
3246
+ * Returns findings sorted by (line, column). Files that don't match
3247
+ * `sourceFile` (after normalization) are skipped.
3248
+ *
3249
+ * @example
3250
+ * import { firesToCreationSiteFindings } from '@pyreon/compiler'
3251
+ * import { getFireSummaries } from '@pyreon/reactivity'
3252
+ *
3253
+ * const fires = getFireSummaries().map(s => ({
3254
+ * file: s.loc.file, line: s.loc.line, count: s.count, kind: s.kind,
3255
+ * }))
3256
+ * const findings = firesToCreationSiteFindings(fires, 'app.tsx')
3257
+ * // [{ kind: 'live-fire', line: 5, detail: 'signal fired 129×', ... }]
3258
+ */
3259
+ function firesToCreationSiteFindings(fires, sourceFile, options = {}) {
3260
+ if (fires.length === 0) return [];
3261
+ const norm = options.normalizeFile ?? ((p) => p);
3262
+ const targetFile = norm(sourceFile);
3263
+ const byLine = /* @__PURE__ */ new Map();
3264
+ for (const f of fires) {
3265
+ if (norm(f.file) !== targetFile) continue;
3266
+ const existing = byLine.get(f.line);
3267
+ if (existing) {
3268
+ existing.count += f.count;
3269
+ if (typeof f.rate1s === "number") existing.rate1s = (existing.rate1s ?? 0) + f.rate1s;
3270
+ if ((f.lastFire ?? -Infinity) > (existing.lastFire ?? -Infinity)) {
3271
+ existing.lastFire = f.lastFire;
3272
+ existing.kind = f.kind ?? existing.kind;
3273
+ }
3274
+ } else byLine.set(f.line, { ...f });
3275
+ }
3276
+ const format = options.formatDetail ?? ((_, fire) => {
3277
+ const kindLabel = fire.kind ?? "node";
3278
+ const rate = typeof fire.rate1s === "number" ? _formatRate(fire.rate1s) : "";
3279
+ return `${kindLabel} fired ${fire.count}×${rate}`;
3280
+ });
3281
+ const LIVE_KIND = "live-fire";
3282
+ const out = [];
3283
+ for (const [line, fire] of byLine) out.push({
3284
+ kind: LIVE_KIND,
3285
+ line,
3286
+ column: 0,
3287
+ endLine: line,
3288
+ endColumn: 9999,
3289
+ detail: format("", fire)
3290
+ });
3291
+ out.sort((a, b) => a.line - b.line || a.column - b.column);
3292
+ return out;
3293
+ }
3294
+
2943
3295
  //#endregion
2944
3296
  //#region src/project-scanner.ts
2945
3297
  /**
@@ -4891,5 +5243,5 @@ function formatSsgAudit(result, _options = {}) {
4891
5243
  }
4892
5244
 
4893
5245
  //#endregion
4894
- export { analyzeReactivity, auditIslands, auditSsg, auditTestEnvironment, detectPyreonPatterns, detectReactPatterns, diagnoseError, formatIslandAudit, formatReactivityLens, formatSsgAudit, formatTestAudit, generateContext, hasPyreonPatterns, hasReactPatterns, migrateReactCode, rocketstyleCollapseKey, scanCollapsibleSites, transformDeferInline, transformJSX, transformJSX_JS };
5246
+ export { analyzeReactivity, auditIslands, auditSsg, auditTestEnvironment, detectPyreonPatterns, detectReactPatterns, diagnoseError, firesToCreationSiteFindings, formatIslandAudit, formatReactivityLens, formatSsgAudit, formatTestAudit, generateContext, hasPyreonPatterns, hasReactPatterns, mergeFireDataIntoFindings, migrateReactCode, rocketstyleCollapseKey, scanCollapsibleSites, transformDeferInline, transformJSX, transformJSX_JS };
4895
5247
  //# sourceMappingURL=index.js.map
@@ -419,6 +419,99 @@ declare function analyzeReactivity(code: string, filename?: string, options?: {
419
419
  */
420
420
  declare function formatReactivityLens(code: string, result: AnalyzeReactivityResult): string;
421
421
  //#endregion
422
+ //#region src/lpih.d.ts
423
+ /**
424
+ * Runtime fire data carried into the merge function. Shape mirrors
425
+ * `@pyreon/reactivity`'s `FireSummary` but is duplicated here to keep
426
+ * `@pyreon/compiler` free of a runtime-package import. The consumer
427
+ * adapts the shape at the call site.
428
+ */
429
+ interface LPIHFireDatum {
430
+ /** Source file path captured from `new Error().stack`. */
431
+ file: string;
432
+ /** 1-based line number (V8 stack format). */
433
+ line: number;
434
+ /** Total fires recorded at this location. */
435
+ count: number;
436
+ /** `performance.now()` of most recent fire, or null. */
437
+ lastFire?: number | null | undefined;
438
+ /** Node kind that fired (signal / derived / effect). */
439
+ kind?: 'signal' | 'derived' | 'effect' | undefined;
440
+ /**
441
+ * Exponentially-decayed fire rate, fires/sec (1s time constant). 0
442
+ * when the node has been idle longer than several time constants.
443
+ * Used by the default formatter to add a "12/s" suffix when active.
444
+ * See `@pyreon/reactivity`'s `FireSummary.rate1s` for the math.
445
+ */
446
+ rate1s?: number | undefined;
447
+ }
448
+ /** Options for `mergeFireDataIntoFindings`. */
449
+ interface LPIHMergeOptions {
450
+ /**
451
+ * Optional file-path normalizer. Used for both the analyzed source
452
+ * file and each fire's `file` field. Useful when fires come from
453
+ * runtime stacks (absolute paths) but the source file is identified
454
+ * relative (e.g. workspace-rooted). Defaults to identity.
455
+ */
456
+ normalizeFile?: (path: string) => string;
457
+ /**
458
+ * Optional formatter for the enriched detail. Receives the original
459
+ * detail + the matched fire datum. Defaults to:
460
+ * `${detail} — ${kind ? kind + ' ' : ''}fired ${count}×`
461
+ */
462
+ formatDetail?: (detail: string, fire: LPIHFireDatum) => string;
463
+ }
464
+ /**
465
+ * Merge runtime fire data onto static reactivity findings. Pure function,
466
+ * deterministic, input not mutated.
467
+ *
468
+ * Matching rules:
469
+ * - Only fires whose normalized `file` matches the analyzed source file
470
+ * are considered (cross-file fires are silently skipped).
471
+ * - Line-level matching only (column is ignored). V8 stack columns
472
+ * differ from compiler-emitted span columns by 1+ chars in practice,
473
+ * and the user-visible affordance is "this signal at this line is
474
+ * firing" — line precision is sufficient.
475
+ * - Multiple fires at the same `line` are summed; latest `lastFire`
476
+ * and corresponding `kind` win.
477
+ * - Findings of kind `footgun`, `hoisted-static`, or `static-text` are
478
+ * passed through unchanged — they're not runtime-active reactive
479
+ * reads, so a fire count at their location is unrelated to them.
480
+ */
481
+ declare function mergeFireDataIntoFindings(findings: ReactivityFinding[], fires: readonly LPIHFireDatum[], sourceFile: string, options?: LPIHMergeOptions): ReactivityFinding[];
482
+ /**
483
+ * Synthesize "creation-site" inlay-hint findings directly from fire data.
484
+ *
485
+ * `analyzeReactivity()` produces findings at REACTIVE READ sites (JSX
486
+ * expressions). But the runtime captures fires at CREATION sites
487
+ * (`signal(0)`, `computed(...)`, `effect(...)`). These are usually
488
+ * different source lines — so the merge function above only helps when
489
+ * they happen to coincide.
490
+ *
491
+ * The simpler, more useful editor surface is: show fire counts AT THE
492
+ * CREATION LINE. The user writes `const count = signal(0)` and sees
493
+ * `(signal fired 129×)` as ghost text on that line, the same way
494
+ * TypeScript shows the inferred type.
495
+ *
496
+ * This function turns each fire datum into a synthetic finding the LSP
497
+ * can serve as an inlay hint. No static analysis required — pure runtime
498
+ * data → editor hint.
499
+ *
500
+ * Returns findings sorted by (line, column). Files that don't match
501
+ * `sourceFile` (after normalization) are skipped.
502
+ *
503
+ * @example
504
+ * import { firesToCreationSiteFindings } from '@pyreon/compiler'
505
+ * import { getFireSummaries } from '@pyreon/reactivity'
506
+ *
507
+ * const fires = getFireSummaries().map(s => ({
508
+ * file: s.loc.file, line: s.loc.line, count: s.count, kind: s.kind,
509
+ * }))
510
+ * const findings = firesToCreationSiteFindings(fires, 'app.tsx')
511
+ * // [{ kind: 'live-fire', line: 5, detail: 'signal fired 129×', ... }]
512
+ */
513
+ declare function firesToCreationSiteFindings(fires: readonly LPIHFireDatum[], sourceFile: string, options?: LPIHMergeOptions): ReactivityFinding[];
514
+ //#endregion
422
515
  //#region src/project-scanner.d.ts
423
516
  /**
424
517
  * Project scanner — extracts route, component, and island information from source files.
@@ -642,5 +735,5 @@ interface SsgAuditFormatOptions {
642
735
  }
643
736
  declare function formatSsgAudit(result: SsgAuditResult, _options?: SsgAuditFormatOptions): string;
644
737
  //#endregion
645
- export { type AnalyzeReactivityResult, type AuditFormatOptions, type AuditRisk, type CollapsibleSite, type CompilerWarning, type ComponentInfo, type DeferInlineResult, type DeferInlineWarning, type ErrorDiagnosis, type IslandAuditFormatOptions, type IslandAuditResult, type IslandFinding, type IslandFindingCode, type IslandInfo, type IslandLocation, type MigrationChange, type MigrationResult, type ProjectContext, type PyreonDiagnostic, type PyreonDiagnosticCode, type ReactDiagnostic, type ReactDiagnosticCode, type ReactivityFinding, type ReactivityFindingKind, type ReactivityKind, type ReactivitySpan, type RouteInfo, type SsgAuditFormatOptions, type SsgAuditResult, type SsgFinding, type SsgFindingCode, type SsgLocation, type TestAuditEntry, type TestAuditResult, type TransformResult, analyzeReactivity, auditIslands, auditSsg, auditTestEnvironment, detectPyreonPatterns, detectReactPatterns, diagnoseError, formatIslandAudit, formatReactivityLens, formatSsgAudit, formatTestAudit, generateContext, hasPyreonPatterns, hasReactPatterns, migrateReactCode, rocketstyleCollapseKey, scanCollapsibleSites, transformDeferInline, transformJSX, transformJSX_JS };
738
+ export { type AnalyzeReactivityResult, type AuditFormatOptions, type AuditRisk, type CollapsibleSite, type CompilerWarning, type ComponentInfo, type DeferInlineResult, type DeferInlineWarning, type ErrorDiagnosis, type IslandAuditFormatOptions, type IslandAuditResult, type IslandFinding, type IslandFindingCode, type IslandInfo, type IslandLocation, type LPIHFireDatum, type LPIHMergeOptions, type MigrationChange, type MigrationResult, type ProjectContext, type PyreonDiagnostic, type PyreonDiagnosticCode, type ReactDiagnostic, type ReactDiagnosticCode, type ReactivityFinding, type ReactivityFindingKind, type ReactivityKind, type ReactivitySpan, type RouteInfo, type SsgAuditFormatOptions, type SsgAuditResult, type SsgFinding, type SsgFindingCode, type SsgLocation, type TestAuditEntry, type TestAuditResult, type TransformResult, analyzeReactivity, auditIslands, auditSsg, auditTestEnvironment, detectPyreonPatterns, detectReactPatterns, diagnoseError, firesToCreationSiteFindings, formatIslandAudit, formatReactivityLens, formatSsgAudit, formatTestAudit, generateContext, hasPyreonPatterns, hasReactPatterns, mergeFireDataIntoFindings, migrateReactCode, rocketstyleCollapseKey, scanCollapsibleSites, transformDeferInline, transformJSX, transformJSX_JS };
646
739
  //# sourceMappingURL=index2.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pyreon/compiler",
3
- "version": "0.23.0",
3
+ "version": "0.24.1",
4
4
  "description": "Template and JSX compiler for Pyreon",
5
5
  "homepage": "https://github.com/pyreon/pyreon/tree/main/packages/compiler#readme",
6
6
  "bugs": {
@@ -48,20 +48,20 @@
48
48
  "oxc-parser": "^0.129.0"
49
49
  },
50
50
  "optionalDependencies": {
51
- "@pyreon/compiler-darwin-arm64": "^0.23.0",
52
- "@pyreon/compiler-darwin-x64": "^0.23.0",
53
- "@pyreon/compiler-linux-arm64-gnu": "^0.23.0",
54
- "@pyreon/compiler-linux-arm64-musl": "^0.23.0",
55
- "@pyreon/compiler-linux-x64-gnu": "^0.23.0",
56
- "@pyreon/compiler-linux-x64-musl": "^0.23.0",
57
- "@pyreon/compiler-win32-x64-msvc": "^0.23.0"
51
+ "@pyreon/compiler-darwin-arm64": "^0.24.1",
52
+ "@pyreon/compiler-darwin-x64": "^0.24.1",
53
+ "@pyreon/compiler-linux-arm64-gnu": "^0.24.1",
54
+ "@pyreon/compiler-linux-arm64-musl": "^0.24.1",
55
+ "@pyreon/compiler-linux-x64-gnu": "^0.24.1",
56
+ "@pyreon/compiler-linux-x64-musl": "^0.24.1",
57
+ "@pyreon/compiler-win32-x64-msvc": "^0.24.1"
58
58
  },
59
59
  "devDependencies": {
60
- "@pyreon/core": "^0.23.0",
60
+ "@pyreon/core": "^0.24.1",
61
61
  "@pyreon/manifest": "0.13.1",
62
- "@pyreon/reactivity": "^0.23.0",
63
- "@pyreon/runtime-dom": "^0.23.0",
64
- "@pyreon/test-utils": "^0.13.10",
62
+ "@pyreon/reactivity": "^0.24.1",
63
+ "@pyreon/runtime-dom": "^0.24.1",
64
+ "@pyreon/test-utils": "^0.13.11",
65
65
  "happy-dom": "^20.8.3"
66
66
  },
67
67
  "peerDependencies": {
package/src/index.ts CHANGED
@@ -16,6 +16,8 @@ export type {
16
16
  ReactivityFindingKind,
17
17
  } from './reactivity-lens'
18
18
  export { analyzeReactivity, formatReactivityLens } from './reactivity-lens'
19
+ export type { LPIHFireDatum, LPIHMergeOptions } from './lpih'
20
+ export { firesToCreationSiteFindings, mergeFireDataIntoFindings } from './lpih'
19
21
  export type { ComponentInfo, IslandInfo, ProjectContext, RouteInfo } from './project-scanner'
20
22
  export { generateContext } from './project-scanner'
21
23
  export type {