@pyreon/compiler 0.22.0 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +138 -54
- package/lib/analysis/index.js.html +1 -1
- package/lib/index.js +414 -9
- package/lib/types/index.d.ts +94 -1
- package/package.json +12 -12
- package/src/index.ts +2 -0
- package/src/jsx.ts +425 -5
- package/src/lpih.ts +270 -0
- package/src/pyreon-intercept.ts +19 -8
- package/src/ssg-audit.ts +3 -3
- package/src/tests/collapse-bail-census.test.ts +101 -16
- package/src/tests/component-child-no-wrap.test.ts +204 -0
- package/src/tests/dynamic-collapse-detector.test.ts +164 -0
- package/src/tests/dynamic-collapse-emit.test.ts +192 -0
- package/src/tests/dynamic-collapse-scan.test.ts +111 -0
- package/src/tests/lpih.test.ts +404 -0
- package/src/tests/native-equivalence.test.ts +92 -0
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++}`;
|
|
@@ -1193,7 +1407,7 @@ function transformJSX_JS(code, filename = "input.tsx", options = {}) {
|
|
|
1193
1407
|
}
|
|
1194
1408
|
} else hoistOrWrap(expr);
|
|
1195
1409
|
}
|
|
1196
|
-
function handleJsxExpression(node) {
|
|
1410
|
+
function handleJsxExpression(node, parentJsx) {
|
|
1197
1411
|
const expr = node.expression;
|
|
1198
1412
|
if (!expr || expr.type === "JSXEmptyExpression") return;
|
|
1199
1413
|
const hoistName = maybeHoist(expr);
|
|
@@ -1206,11 +1420,64 @@ function transformJSX_JS(code, filename = "input.tsx", options = {}) {
|
|
|
1206
1420
|
return;
|
|
1207
1421
|
}
|
|
1208
1422
|
if (shouldWrap(expr)) {
|
|
1423
|
+
if (parentJsx && isComponentTag(jsxTagName(parentJsx)) && isStableReference(expr) && !referencesSignalVar(expr)) {
|
|
1424
|
+
const start = expr.start;
|
|
1425
|
+
const end = expr.end;
|
|
1426
|
+
const sliced = sliceExpr(unwrapTypeLayers(expr));
|
|
1427
|
+
replacements.push({
|
|
1428
|
+
start,
|
|
1429
|
+
end,
|
|
1430
|
+
text: sliced
|
|
1431
|
+
});
|
|
1432
|
+
return;
|
|
1433
|
+
}
|
|
1209
1434
|
wrap(expr);
|
|
1210
1435
|
return;
|
|
1211
1436
|
}
|
|
1212
1437
|
walkNode(expr);
|
|
1213
1438
|
}
|
|
1439
|
+
/** Component tag — uppercase first letter. Lowercase = DOM element. */
|
|
1440
|
+
function isComponentTag(tag) {
|
|
1441
|
+
return tag.length > 0 && tag.charAt(0) !== tag.charAt(0).toLowerCase();
|
|
1442
|
+
}
|
|
1443
|
+
/**
|
|
1444
|
+
* Stable reference — an expression whose value is a bare property read.
|
|
1445
|
+
* Bare Identifier (`children`) or a non-computed MemberExpression chain
|
|
1446
|
+
* (`obj.x.y`) terminating in an Identifier or `this`. These are the
|
|
1447
|
+
* shapes that survive the no-wrap path without losing reactivity:
|
|
1448
|
+
* reading them once captures the same value as reading them N times,
|
|
1449
|
+
* because the underlying getter (if any) is the source of truth either
|
|
1450
|
+
* way. Excludes CallExpression / TaggedTemplateExpression / BinaryExpression
|
|
1451
|
+
* / LogicalExpression / ConditionalExpression / etc. — those keep the
|
|
1452
|
+
* wrap so consumers can re-evaluate inside reactive scopes.
|
|
1453
|
+
*
|
|
1454
|
+
* TS type-only layers (`as T` / `satisfies T` / non-null `!`) and
|
|
1455
|
+
* parentheses are transparent — they don't change runtime semantics
|
|
1456
|
+
* so we unwrap to look at the underlying expression. Reproducer:
|
|
1457
|
+
* `<Comp>{children as VNode[]}</Comp>` in `createKineticComponent.tsx`
|
|
1458
|
+
* — the TS cast wraps the Identifier as a `TSAsExpression`; without
|
|
1459
|
+
* unwrap the carve-out misses the very pattern it was written for.
|
|
1460
|
+
*/
|
|
1461
|
+
function isStableReference(expr) {
|
|
1462
|
+
const u = unwrapTypeLayers(expr);
|
|
1463
|
+
if (u.type === "Identifier") return true;
|
|
1464
|
+
if (u.type === "MemberExpression") {
|
|
1465
|
+
let cur = u;
|
|
1466
|
+
while (cur.type === "MemberExpression") {
|
|
1467
|
+
if (cur.computed) return false;
|
|
1468
|
+
if (cur.property?.type !== "Identifier") return false;
|
|
1469
|
+
cur = cur.object;
|
|
1470
|
+
}
|
|
1471
|
+
return cur.type === "Identifier" || cur.type === "ThisExpression";
|
|
1472
|
+
}
|
|
1473
|
+
return false;
|
|
1474
|
+
}
|
|
1475
|
+
/** Strip TS type-only layers + parens that don't affect runtime value. */
|
|
1476
|
+
function unwrapTypeLayers(expr) {
|
|
1477
|
+
let cur = expr;
|
|
1478
|
+
while (cur.type === "TSAsExpression" || cur.type === "TSSatisfiesExpression" || cur.type === "TSNonNullExpression" || cur.type === "TSTypeAssertion" || cur.type === "ParenthesizedExpression") cur = cur.expression;
|
|
1479
|
+
return cur;
|
|
1480
|
+
}
|
|
1214
1481
|
const propsNames = /* @__PURE__ */ new Set();
|
|
1215
1482
|
const propDerivedVars = /* @__PURE__ */ new Map();
|
|
1216
1483
|
const elementVars = /* @__PURE__ */ new Set();
|
|
@@ -1514,7 +1781,7 @@ function transformJSX_JS(code, filename = "input.tsx", options = {}) {
|
|
|
1514
1781
|
checkForWarnings(node);
|
|
1515
1782
|
for (const attr of jsxAttrs(node)) if (attr.type === "JSXAttribute") handleJsxAttribute(attr, node);
|
|
1516
1783
|
else if (attr.type === "JSXSpreadAttribute") handleJsxSpreadAttribute(attr, node);
|
|
1517
|
-
for (const child of jsxChildren(node)) if (child.type === "JSXExpressionContainer") handleJsxExpression(child);
|
|
1784
|
+
for (const child of jsxChildren(node)) if (child.type === "JSXExpressionContainer") handleJsxExpression(child, node);
|
|
1518
1785
|
else walkNode(child);
|
|
1519
1786
|
return;
|
|
1520
1787
|
}
|
|
@@ -1559,12 +1826,17 @@ function transformJSX_JS(code, filename = "input.tsx", options = {}) {
|
|
|
1559
1826
|
if (needsWrapSpreadImport) coreImports.push("_wrapSpread");
|
|
1560
1827
|
preamble = `import { ${coreImports.join(", ")} } from "@pyreon/core";\n` + preamble;
|
|
1561
1828
|
}
|
|
1562
|
-
if (needsCollapse) {
|
|
1829
|
+
if (needsCollapse || needsCollapseDyn || needsCollapseDynH) {
|
|
1563
1830
|
const cfg = options.collapseRocketstyle;
|
|
1564
1831
|
const rd = cfg.runtimeDomSource ?? "@pyreon/runtime-dom";
|
|
1565
1832
|
const st = cfg.stylerSource ?? "@pyreon/styler";
|
|
1566
1833
|
const inj = collapseRules.map((r) => `__rsSheet.injectRules(${JSON.stringify(r.rules)},${JSON.stringify(r.ruleKey)});`).join("");
|
|
1567
|
-
|
|
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;
|
|
1568
1840
|
}
|
|
1569
1841
|
if (preamble) s.prepend(preamble);
|
|
1570
1842
|
const output = s.toString();
|
|
@@ -2754,7 +3026,7 @@ function detectPyreonPatterns(code, filename = "input.tsx") {
|
|
|
2754
3026
|
}
|
|
2755
3027
|
/** Fast regex pre-filter — returns true if the code is worth a full AST walk. */
|
|
2756
3028
|
function hasPyreonPatterns(code) {
|
|
2757
|
-
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
|
|
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);
|
|
2758
3030
|
}
|
|
2759
3031
|
|
|
2760
3032
|
//#endregion
|
|
@@ -2887,6 +3159,139 @@ function formatReactivityLens(code, result) {
|
|
|
2887
3159
|
return out.join("\n");
|
|
2888
3160
|
}
|
|
2889
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
|
+
|
|
2890
3295
|
//#endregion
|
|
2891
3296
|
//#region src/project-scanner.ts
|
|
2892
3297
|
/**
|
|
@@ -4687,7 +5092,7 @@ function detectDynamicRouteMissingGetStaticPaths(routeFiles, rootForRel) {
|
|
|
4687
5092
|
const findings = [];
|
|
4688
5093
|
for (const file of routeFiles) {
|
|
4689
5094
|
const base = file.split("/").pop() ?? "";
|
|
4690
|
-
if (!/\[
|
|
5095
|
+
if (!/\[[^\]]{1,200}\]/.test(base)) continue;
|
|
4691
5096
|
if (/^_(layout|error|loading|404|not-found)\./.test(base)) continue;
|
|
4692
5097
|
if (/[/\\]routes[/\\]api[/\\]/.test(file)) continue;
|
|
4693
5098
|
const source = parseSourceFile(file);
|
|
@@ -4778,7 +5183,7 @@ function auditSsg(rootDir) {
|
|
|
4778
5183
|
let revalidateExports = 0;
|
|
4779
5184
|
for (const file of routeFiles) {
|
|
4780
5185
|
const base = file.split("/").pop() ?? "";
|
|
4781
|
-
if (/\[
|
|
5186
|
+
if (/\[[^\]]{1,200}\]/.test(base) && !/^_(layout|error|loading|404|not-found)\./.test(base)) dynamicRoutes++;
|
|
4782
5187
|
const source = parseSourceFile(file);
|
|
4783
5188
|
if (!source) continue;
|
|
4784
5189
|
function visit(node) {
|
|
@@ -4838,5 +5243,5 @@ function formatSsgAudit(result, _options = {}) {
|
|
|
4838
5243
|
}
|
|
4839
5244
|
|
|
4840
5245
|
//#endregion
|
|
4841
|
-
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 };
|
|
4842
5247
|
//# sourceMappingURL=index.js.map
|
package/lib/types/index.d.ts
CHANGED
|
@@ -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.
|
|
3
|
+
"version": "0.24.0",
|
|
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.
|
|
52
|
-
"@pyreon/compiler-darwin-x64": "^0.
|
|
53
|
-
"@pyreon/compiler-linux-arm64-gnu": "^0.
|
|
54
|
-
"@pyreon/compiler-linux-arm64-musl": "^0.
|
|
55
|
-
"@pyreon/compiler-linux-x64-gnu": "^0.
|
|
56
|
-
"@pyreon/compiler-linux-x64-musl": "^0.
|
|
57
|
-
"@pyreon/compiler-win32-x64-msvc": "^0.
|
|
51
|
+
"@pyreon/compiler-darwin-arm64": "^0.24.0",
|
|
52
|
+
"@pyreon/compiler-darwin-x64": "^0.24.0",
|
|
53
|
+
"@pyreon/compiler-linux-arm64-gnu": "^0.24.0",
|
|
54
|
+
"@pyreon/compiler-linux-arm64-musl": "^0.24.0",
|
|
55
|
+
"@pyreon/compiler-linux-x64-gnu": "^0.24.0",
|
|
56
|
+
"@pyreon/compiler-linux-x64-musl": "^0.24.0",
|
|
57
|
+
"@pyreon/compiler-win32-x64-msvc": "^0.24.0"
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
60
|
-
"@pyreon/core": "^0.
|
|
60
|
+
"@pyreon/core": "^0.24.0",
|
|
61
61
|
"@pyreon/manifest": "0.13.1",
|
|
62
|
-
"@pyreon/reactivity": "^0.
|
|
63
|
-
"@pyreon/runtime-dom": "^0.
|
|
64
|
-
"@pyreon/test-utils": "^0.13.
|
|
62
|
+
"@pyreon/reactivity": "^0.24.0",
|
|
63
|
+
"@pyreon/runtime-dom": "^0.24.0",
|
|
64
|
+
"@pyreon/test-utils": "^0.13.11",
|
|
65
65
|
"happy-dom": "^20.8.3"
|
|
66
66
|
},
|
|
67
67
|
"peerDependencies": {
|