@bitcobblers/wod-wiki-lang 0.10.42 → 0.35.2115
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/dist/{browserRuntimeNow-je1Vb5bU.d.cts → browserRuntimeNow-CoR7dCNU.d.cts} +146 -134
- package/dist/{browserRuntimeNow-je1Vb5bU.d.ts → browserRuntimeNow-CoR7dCNU.d.ts} +146 -134
- package/dist/index.cjs +632 -108
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +194 -42
- package/dist/index.d.ts +194 -42
- package/dist/index.mjs +626 -106
- package/dist/index.mjs.map +1 -1
- package/dist/react.cjs +16 -21
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +3 -3
- package/dist/react.d.ts +3 -3
- package/dist/react.mjs +16 -21
- package/dist/react.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -74,8 +74,8 @@ function metricsOf(source) {
|
|
|
74
74
|
if (Array.isArray(m)) return m;
|
|
75
75
|
return m.rawMetrics ?? [];
|
|
76
76
|
}
|
|
77
|
-
function hintMetric(hint, origin = "dialect") {
|
|
78
|
-
return { type: wodWikiCore.MetricType.Hint, value: hint, image: hint, origin };
|
|
77
|
+
function hintMetric(hint, origin = "dialect", icon) {
|
|
78
|
+
return { type: wodWikiCore.MetricType.Hint, value: hint, image: hint, origin, ...icon ? { icon } : {} };
|
|
79
79
|
}
|
|
80
80
|
function hintsToContainer(hints, existing, origin = "dialect") {
|
|
81
81
|
const container = existing ?? wodWikiCore.MetricContainer.empty("dialect");
|
|
@@ -496,6 +496,19 @@ var ChoiceGroupMetric = class {
|
|
|
496
496
|
value;
|
|
497
497
|
image;
|
|
498
498
|
};
|
|
499
|
+
var IntensityMetric = class {
|
|
500
|
+
constructor(value, unit = "%") {
|
|
501
|
+
this.unit = unit;
|
|
502
|
+
this.value = { amount: value, unit };
|
|
503
|
+
this.image = value !== void 0 ? `${value}${unit}` : `?${unit}`;
|
|
504
|
+
this.origin = value === void 0 ? "hinted" : "parser";
|
|
505
|
+
}
|
|
506
|
+
unit;
|
|
507
|
+
value;
|
|
508
|
+
image;
|
|
509
|
+
origin;
|
|
510
|
+
type = wodWikiCore.MetricType.Intensity;
|
|
511
|
+
};
|
|
499
512
|
|
|
500
513
|
// src/dialects/units/fuseUnits.ts
|
|
501
514
|
function isBareNumber(m) {
|
|
@@ -654,6 +667,17 @@ function fusePairs(pairs, units) {
|
|
|
654
667
|
}
|
|
655
668
|
}
|
|
656
669
|
}
|
|
670
|
+
if (next && isBareNumber(cur.metric)) {
|
|
671
|
+
const text = effortText(next.metric);
|
|
672
|
+
if (text !== null && text.trim() === "%") {
|
|
673
|
+
out.push({
|
|
674
|
+
metric: new IntensityMetric(cur.metric.value),
|
|
675
|
+
meta: fusedMeta(cur.meta, next.meta, "%")
|
|
676
|
+
});
|
|
677
|
+
i++;
|
|
678
|
+
continue;
|
|
679
|
+
}
|
|
680
|
+
}
|
|
657
681
|
if (next) {
|
|
658
682
|
const fusable = isBareNumber(cur.metric) || hasEmptyUnit(cur.metric);
|
|
659
683
|
if (fusable) {
|
|
@@ -1168,6 +1192,11 @@ var ClimbDialect = class {
|
|
|
1168
1192
|
}
|
|
1169
1193
|
};
|
|
1170
1194
|
|
|
1195
|
+
// src/logger.ts
|
|
1196
|
+
function langWarn(message) {
|
|
1197
|
+
console.warn(message);
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1171
1200
|
// src/dialects/DialectStack.ts
|
|
1172
1201
|
var UNITS_DIALECT_ID = "units";
|
|
1173
1202
|
var SPORT_ALIASES = {
|
|
@@ -1210,7 +1239,7 @@ var DialectStack = class {
|
|
|
1210
1239
|
if (!all.some((d) => d.id === id)) {
|
|
1211
1240
|
if (!warnedSports.has(sport)) {
|
|
1212
1241
|
warnedSports.add(sport);
|
|
1213
|
-
|
|
1242
|
+
langWarn(
|
|
1214
1243
|
`[DialectStack] Unknown :sport suffix "${sport}" \u2014 falling back to the full dialect stack. Known dialect ids: ${all.map((d) => d.id).join(", ")}.`
|
|
1215
1244
|
);
|
|
1216
1245
|
}
|
|
@@ -1392,8 +1421,20 @@ var PropertyMetric = class {
|
|
|
1392
1421
|
this.image = options.image ?? `${key}: ${formatPropertyValue(value)}`;
|
|
1393
1422
|
this.origin = options.origin ?? "parser";
|
|
1394
1423
|
this.type = options.type ?? wodWikiCore.MetricType.Custom;
|
|
1424
|
+
const kind = wodWikiCore.valueKindOf(value);
|
|
1425
|
+
this.metadata = {
|
|
1426
|
+
originalKey: key,
|
|
1427
|
+
...kind !== "object" && kind !== "undefined" ? {
|
|
1428
|
+
fieldRef: {
|
|
1429
|
+
path: wodWikiCore.normalizeFieldPath(key),
|
|
1430
|
+
kind,
|
|
1431
|
+
...options.dimension ? { dimension: options.dimension } : {}
|
|
1432
|
+
}
|
|
1433
|
+
} : {}
|
|
1434
|
+
};
|
|
1395
1435
|
}
|
|
1396
1436
|
type;
|
|
1437
|
+
metadata;
|
|
1397
1438
|
};
|
|
1398
1439
|
var RepMetric = class {
|
|
1399
1440
|
constructor(reps) {
|
|
@@ -1496,6 +1537,12 @@ function classifyPrimitive(primitive) {
|
|
|
1496
1537
|
}
|
|
1497
1538
|
return primitive.label ? [{ metrics: new RoundsMetric(primitive.label), meta: primitive.meta }] : [];
|
|
1498
1539
|
}
|
|
1540
|
+
case "round_scheme": {
|
|
1541
|
+
return [
|
|
1542
|
+
{ metrics: new RoundsMetric(primitive.rounds), meta: primitive.meta },
|
|
1543
|
+
{ metrics: new RepMetric(primitive.reps), meta: primitive.meta }
|
|
1544
|
+
];
|
|
1545
|
+
}
|
|
1499
1546
|
case "action": {
|
|
1500
1547
|
const actionText = primitive.hasColonPrefix ? primitive.raw.substring(2, primitive.raw.length - 1).trim() : primitive.raw.substring(1, primitive.raw.length - 1).trim();
|
|
1501
1548
|
return [{ metrics: new ActionMetric(actionText, { raw: actionText }), meta: primitive.meta }];
|
|
@@ -1607,17 +1654,17 @@ function mergeFragments(pairs) {
|
|
|
1607
1654
|
}
|
|
1608
1655
|
var parser = lr.LRParser.deserialize({
|
|
1609
1656
|
version: 14,
|
|
1610
|
-
states: "(
|
|
1611
|
-
stateData: "*
|
|
1612
|
-
goto: "$
|
|
1613
|
-
nodeNames: "\u26A0 Program Property Identifier String Number Block Lap Fragment Duration Trend CollectibleTimer Timer Rounds Sequence Action Text Heading Quantity AtSign Question Slash Pipe Effort MetricObject True False Null",
|
|
1614
|
-
maxTerm:
|
|
1657
|
+
states: "(WQVQPOOO!jQPO'#C}O#}QPO'#CcOOQO'#Cc'#CcOOQO'#Cf'#CfOOQO'#Cg'#CgOOQO'#Ce'#CeO%_QPO'#CeO%gQPO'#CiOOQO'#Ck'#CkOOQO'#C}'#C}OOQO'#Ct'#CtO%oQPO'#ClOOQO'#Cm'#CmOOQO'#Cn'#CnOOQO'#Cp'#CpOOQO'#Cq'#CqOOQO'#Co'#CoO%tQPO'#CoOOQO'#Cr'#CrOOQO'#Cs'#CsO&kQPO'#CuOOQO'#Cd'#CdOOQO'#Cz'#CzO(PQPO'#CbO&rQPO'#CbOOQO'#Cy'#CyQVQPOOO(WQPO,58xOOQO,59P,59PO(cQPO'#CjOOQO'#C{'#C{O(qQPO,59TOOQO-E6{-E6{O(|QPO,59WOOQO,59Z,59ZOOQO'#DO'#DOO)XQPO,59aOOQO,59a,59aOOQO-E6x-E6xOOQO,58|,58|O)`QPO,58|OOQO-E6w-E6wOOQO1G.d1G.dO)gQPO'#C|O)lQPO,59UOOQO-E6y-E6yOOQO1G.o1G.oO)zQPO1G.rOOQO-E6|-E6|OOQO1G.{1G.{OOQO1G.h1G.hOOQO,59h,59hOOQO-E6z-E6zOOQO7+$^7+$^",
|
|
1658
|
+
stateData: "*u~OuOS~ORPOTaO[UOwQOxROySOzVO{TO|WO!OXO!PXO!Q[O!RYO!T]O!U^O!V_O!W`O!XcO!YdO!ZeO!^jO~OvlORqXTqX[qXwqXyqXzqX{qX|qX!OqX!PqX!QqX!RqX!TqX!UqX!VqX!WqX!XqX!YqX!ZqX!^qX~ORVXTVX[VXwVXyVXzVX{VX|VX!OVX!PVX!QVX!RVX!TVX!UVX!VVX!WVX!XVX!YVX!ZVX!^qX~O[mO{TO~ORoOTnO~OvrO~OTsO!W`O~ORtOStOTtOjtOktOltOvtO!RtO![tO~O!]vO~P%|ORYOTaO[UOwYOySOzVO{TO|WO!OXO!PXO!Q[O!RYO!T]O!U^O!V_O!W`O!XcO!YdO!ZeO~O!^xO~P&rOR{OS{OT{O~Ow|OR^XT^X}^X~ORoOTnO}!PO~ORYOwYO!RYO~O!]!SO~P%|O!^!TO~P&rOT!UO~Ow|OR^aT^a}^a~ORYOwYO!RYO!S!WO~O!T!U!O!P{[!Vyzv!X!Y!R!Z!]![jklRwxT!^u!R~",
|
|
1659
|
+
goto: "$UsPPtPPPtx|!T![!cP!T!m!T!T!T!T!T!q!x!T!T!T!TPPP#S#Y#e#k#q$OTjOkTiOkZgOhikyZfOhikyZVOhikyYUOhikyRmVToWpZbOhikyYaOhikyRsbQkORzkShOkSwhyRyiQpWR!OpQ}nR!V}YZOhikyQq!QR!QrQueR!Ru",
|
|
1660
|
+
nodeNames: "\u26A0 Program Property Identifier String Number Block Lap Fragment Duration Trend CollectibleTimer Timer Rounds Sequence RoundScheme Action Text Heading Quantity AtSign Question Slash Pipe Effort MetricObject True False Null",
|
|
1661
|
+
maxTerm: 60,
|
|
1615
1662
|
skippedNodes: [0],
|
|
1616
1663
|
repeatNodeCount: 6,
|
|
1617
|
-
tokenData: "
|
|
1664
|
+
tokenData: "6k~RvXY#iYZ#z]^$Ppq#iqr$Vrs$}st'dtu$Vuv$Vvw$Vxy(Oyz(Tz{(Y{|)S|})X}!O*R!O!P*W!P!Q+Z!Q![+}![!].Q!_!`$V!a!b.j!b!c.o!c!}/i!}#O/w#O#P$V#P#Q/|#Q#R0R#T#Y/i#Y#Z0{#Z#b/i#b#c2|#c#h/i#h#i4l#i#o/i#o#p6[#p#q6a#q#r6f~#nSu~XY#iYZ#z]^$Ppq#i~$PO!^~~$SPYZ#z~$[Z!R~qr$Vtu$Vuv$Vvw$Vz{$V|}$V!O!P$V!_!`$V!b!c$V#O#P$V#Q#R$V~%QXOY$}Z]$}^r$}rs%ms#O$}#O#P&_#P;'S$};'S;=`'^<%lO$}~%rXS~OY$}Z]$}^r$}rs%ms#O$}#O#P&_#P;'S$};'S;=`'^<%lO$}~&bRO;'S$};'S;=`&k;=`O$}~&nYOY$}Z]$}^r$}rs%ms#O$}#O#P&_#P;'S$};'S;=`'^;=`<%l$}<%lO$}~'aP;=`<%l$}~'iT!U~OY'dZ]'d^;'S'd;'S;=`'x<%lO'd~'{P;=`<%l'd~(TO|~~(YO}~~(aZz~!R~qr$Vtu$Vuv$Vvw$Vz{$V|}$V!O!P$V!_!`$V!b!c$V#O#P$V#Q#R$V~)XOx~~)`Z!R~![~qr$Vtu$Vuv$Vvw$Vz{$V|}$V!O!P$V!_!`$V!b!c$V#O#P$V#Q#R$V~*WOw~~*][!R~qr$Vtu$Vuv$Vvw$Vz{$V|}$V!O!P$V!Q![+R!_!`$V!b!c$V#O#P$V#Q#R$V~+WPT~!Q![+R~+`P!X~!P!Q+c~+hT!T~OY+cZ]+c^;'S+c;'S;=`+w<%lO+c~+zP;=`<%l+c~,SUT~pq,f!O!P-Z!Q![+}![!]-a!z!{-r#l#m-r~,iRpq,f!z!{,r#l#m,r~,uPpq,x~,{Qpq,x!Q![-R~-WP!P~!Q![-R~-^P!Q![+R~-dP!Q![-g~-lQ[~!Q![-g![!]-a~-uP!Q![-x~-}P!O~!Q![-x~.VQv~!Q![.]!a!b.e~.bP[~!Q![.]~.jO{~~.oO!W~~.vZ!V~!R~qr$Vtu$Vuv$Vvw$Vz{$V|}$V!O!P$V!_!`$V!b!c$V#O#P$V#Q#R$V~/nRR~!Q![/i!c!}/i#T#o/i~/|O!Q~~0RO!S~~0YZy~!R~qr$Vtu$Vuv$Vvw$Vz{$V|}$V!O!P$V!_!`$V!b!c$V#O#P$V#Q#R$V~1QSR~!Q![/i!c!}/i#T#U1^#U#o/i~1cTR~!Q![/i!c!}/i#T#`/i#`#a1r#a#o/i~1wTR~!Q![/i!c!}/i#T#g/i#g#h2W#h#o/i~2]TR~!Q![/i!c!}/i#T#X/i#X#Y2l#Y#o/i~2sRk~R~!Q![/i!c!}/i#T#o/i~3RTR~!Q![/i!c!}/i#T#i/i#i#j3b#j#o/i~3gTR~!Q![/i!c!}/i#T#`/i#`#a3v#a#o/i~3{TR~!Q![/i!c!}/i#T#`/i#`#a4[#a#o/i~4cRl~R~!Q![/i!c!}/i#T#o/i~4qTR~!Q![/i!c!}/i#T#f/i#f#g5Q#g#o/i~5VTR~!Q![/i!c!}/i#T#i/i#i#j5f#j#o/i~5kTR~!Q![/i!c!}/i#T#X/i#X#Y5z#Y#o/i~6RRj~R~!Q![/i!c!}/i#T#o/i~6aO!Z~~6fO!Y~~6kO!]~",
|
|
1618
1665
|
tokenizers: [0],
|
|
1619
1666
|
topRules: { "Program": [0, 1] },
|
|
1620
|
-
tokenPrec:
|
|
1667
|
+
tokenPrec: 424
|
|
1621
1668
|
});
|
|
1622
1669
|
|
|
1623
1670
|
// src/grammar/parser.terms.ts
|
|
@@ -1625,14 +1672,15 @@ var Lap = 7;
|
|
|
1625
1672
|
var Fragment = 8;
|
|
1626
1673
|
var Duration = 9;
|
|
1627
1674
|
var Rounds = 13;
|
|
1628
|
-
var
|
|
1629
|
-
var
|
|
1630
|
-
var
|
|
1631
|
-
var
|
|
1632
|
-
var
|
|
1633
|
-
var
|
|
1634
|
-
var
|
|
1635
|
-
var
|
|
1675
|
+
var RoundScheme = 15;
|
|
1676
|
+
var Action = 16;
|
|
1677
|
+
var Text = 17;
|
|
1678
|
+
var Heading = 18;
|
|
1679
|
+
var Quantity = 19;
|
|
1680
|
+
var Slash = 22;
|
|
1681
|
+
var Pipe = 23;
|
|
1682
|
+
var Effort = 24;
|
|
1683
|
+
var MetricObject = 25;
|
|
1636
1684
|
|
|
1637
1685
|
// src/parser/syntax-parser.ts
|
|
1638
1686
|
function createLineLocator(source) {
|
|
@@ -1681,7 +1729,7 @@ function extractSyntaxFacts(sourceOrState, treeArg) {
|
|
|
1681
1729
|
if (primitive) {
|
|
1682
1730
|
const meta2 = primitive.meta;
|
|
1683
1731
|
statements.push({
|
|
1684
|
-
id:
|
|
1732
|
+
id: statements.length,
|
|
1685
1733
|
line: meta2.line,
|
|
1686
1734
|
meta: meta2,
|
|
1687
1735
|
primitives: [primitive],
|
|
@@ -1696,7 +1744,7 @@ function extractSyntaxFacts(sourceOrState, treeArg) {
|
|
|
1696
1744
|
lastProperty = null;
|
|
1697
1745
|
const statementMeta = createMeta(locator, node.from, node.to, source.slice(node.from, node.to));
|
|
1698
1746
|
const statement = {
|
|
1699
|
-
id:
|
|
1747
|
+
id: statements.length,
|
|
1700
1748
|
line: statementMeta.line,
|
|
1701
1749
|
meta: statementMeta,
|
|
1702
1750
|
primitives: [],
|
|
@@ -1789,6 +1837,18 @@ function mapFragmentToPrimitive(locator, source, node) {
|
|
|
1789
1837
|
};
|
|
1790
1838
|
return primitive;
|
|
1791
1839
|
}
|
|
1840
|
+
case RoundScheme: {
|
|
1841
|
+
const match = raw.match(/^(\d+)\s*[xX]\s*(\d+)$/);
|
|
1842
|
+
if (!match) return null;
|
|
1843
|
+
const primitive = {
|
|
1844
|
+
kind: "round_scheme",
|
|
1845
|
+
raw,
|
|
1846
|
+
meta: meta2,
|
|
1847
|
+
rounds: parseInt(match[1], 10),
|
|
1848
|
+
reps: parseInt(match[2], 10)
|
|
1849
|
+
};
|
|
1850
|
+
return primitive;
|
|
1851
|
+
}
|
|
1792
1852
|
case Action: {
|
|
1793
1853
|
const primitive = {
|
|
1794
1854
|
kind: "action",
|
|
@@ -1923,23 +1983,22 @@ function createMeta(locator, from, to, raw) {
|
|
|
1923
1983
|
raw
|
|
1924
1984
|
};
|
|
1925
1985
|
}
|
|
1926
|
-
|
|
1927
|
-
// src/parser/lezer-mapper.ts
|
|
1928
|
-
function extractStatementsRaw(sourceOrTree, treeArg) {
|
|
1929
|
-
let source;
|
|
1930
|
-
let tree = treeArg;
|
|
1986
|
+
function resolveSourceInput(sourceOrTree, treeArg) {
|
|
1931
1987
|
if (typeof sourceOrTree === "string") {
|
|
1932
|
-
source
|
|
1933
|
-
}
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
} else if ("doc" in sourceOrTree) {
|
|
1937
|
-
source = sourceOrTree.doc.toString();
|
|
1938
|
-
} else {
|
|
1939
|
-
source = "";
|
|
1988
|
+
return { source: sourceOrTree, tree: treeArg };
|
|
1989
|
+
}
|
|
1990
|
+
if ("source" in sourceOrTree) {
|
|
1991
|
+
return { source: sourceOrTree.source, tree: treeArg ?? sourceOrTree.tree };
|
|
1940
1992
|
}
|
|
1993
|
+
if ("doc" in sourceOrTree) {
|
|
1994
|
+
return { source: sourceOrTree.doc.toString(), tree: treeArg };
|
|
1995
|
+
}
|
|
1996
|
+
return { source: "" };
|
|
1997
|
+
}
|
|
1998
|
+
function extractStatementsRaw(sourceOrTree, treeArg) {
|
|
1999
|
+
const { source, tree } = resolveSourceInput(sourceOrTree, treeArg);
|
|
1941
2000
|
const facts = extractSyntaxFacts(source, tree);
|
|
1942
|
-
return classifyStatements(facts);
|
|
2001
|
+
return normalizeInlineRounds(classifyStatements(facts));
|
|
1943
2002
|
}
|
|
1944
2003
|
function extractStatements(sourceOrTree, sportOrTree, sportArg) {
|
|
1945
2004
|
let sport;
|
|
@@ -1950,9 +2009,70 @@ function extractStatements(sourceOrTree, sportOrTree, sportArg) {
|
|
|
1950
2009
|
tree = sportOrTree;
|
|
1951
2010
|
sport = sportArg;
|
|
1952
2011
|
}
|
|
1953
|
-
const
|
|
2012
|
+
const resolved = resolveSourceInput(sourceOrTree, tree);
|
|
2013
|
+
const facts = extractSyntaxFacts(resolved.source, resolved.tree);
|
|
2014
|
+
const statements = classifyStatements(facts);
|
|
1954
2015
|
dialectStack.processAll(statements, sport);
|
|
1955
|
-
return statements;
|
|
2016
|
+
return normalizeInlineRounds(statements);
|
|
2017
|
+
}
|
|
2018
|
+
function isInlineRoundsPrescription(stmt) {
|
|
2019
|
+
if (stmt.children.length > 0) return false;
|
|
2020
|
+
return stmt.metrics.some((m) => m.type === wodWikiCore.MetricType.Rounds) && stmt.metrics.some((m) => m.type === wodWikiCore.MetricType.Rep) && !stmt.metrics.some((m) => m.type === wodWikiCore.MetricType.Duration);
|
|
2021
|
+
}
|
|
2022
|
+
function cloneStatement(stmt) {
|
|
2023
|
+
const clone = Object.create(Object.getPrototypeOf(stmt));
|
|
2024
|
+
Object.assign(clone, stmt);
|
|
2025
|
+
return clone;
|
|
2026
|
+
}
|
|
2027
|
+
function normalizeInlineRounds(statements) {
|
|
2028
|
+
if (!statements.some(isInlineRoundsPrescription)) return statements;
|
|
2029
|
+
const out = [];
|
|
2030
|
+
const oldToNew = /* @__PURE__ */ new Map();
|
|
2031
|
+
const directParentOf = /* @__PURE__ */ new Map();
|
|
2032
|
+
const childCloneOf = /* @__PURE__ */ new Map();
|
|
2033
|
+
const splitOriginOf = /* @__PURE__ */ new Map();
|
|
2034
|
+
for (const stmt of statements) {
|
|
2035
|
+
if (!isInlineRoundsPrescription(stmt)) {
|
|
2036
|
+
oldToNew.set(stmt.id, out.length);
|
|
2037
|
+
out.push(stmt);
|
|
2038
|
+
continue;
|
|
2039
|
+
}
|
|
2040
|
+
if (stmt.parent !== void 0) directParentOf.set(stmt.id, stmt.parent);
|
|
2041
|
+
const parent = cloneStatement(stmt);
|
|
2042
|
+
const child = cloneStatement(stmt);
|
|
2043
|
+
const isScheme = (m) => m.type === wodWikiCore.MetricType.Rounds || m.type === wodWikiCore.MetricType.Rep;
|
|
2044
|
+
parent.metrics = wodWikiCore.MetricContainer.from(stmt.metrics.filter(isScheme), parent.id);
|
|
2045
|
+
child.metrics = wodWikiCore.MetricContainer.from(stmt.metrics.filter((m) => !isScheme(m)), child.id);
|
|
2046
|
+
parent.metricMeta = new Map([...stmt.metricMeta].filter(([m]) => isScheme(m)));
|
|
2047
|
+
child.metricMeta = new Map([...stmt.metricMeta].filter(([m]) => !isScheme(m)));
|
|
2048
|
+
parent.isLeaf = false;
|
|
2049
|
+
child.isLeaf = true;
|
|
2050
|
+
parent.children = [];
|
|
2051
|
+
child.children = [];
|
|
2052
|
+
childCloneOf.set(child, parent);
|
|
2053
|
+
splitOriginOf.set(parent, stmt.id);
|
|
2054
|
+
oldToNew.set(stmt.id, out.length);
|
|
2055
|
+
out.push(parent, child);
|
|
2056
|
+
}
|
|
2057
|
+
return out.map((stmt, id) => {
|
|
2058
|
+
const oldId = stmt.id;
|
|
2059
|
+
stmt.id = id;
|
|
2060
|
+
stmt.metrics = wodWikiCore.MetricContainer.from(stmt.metrics, stmt.id);
|
|
2061
|
+
const parentClone = childCloneOf.get(stmt);
|
|
2062
|
+
if (parentClone) {
|
|
2063
|
+
stmt.parent = id - 1;
|
|
2064
|
+
return stmt;
|
|
2065
|
+
}
|
|
2066
|
+
if (splitOriginOf.has(stmt)) {
|
|
2067
|
+
stmt.children = [[id + 1]];
|
|
2068
|
+
const oldParent = directParentOf.get(splitOriginOf.get(stmt));
|
|
2069
|
+
stmt.parent = oldParent === void 0 ? void 0 : oldToNew.get(oldParent);
|
|
2070
|
+
return stmt;
|
|
2071
|
+
}
|
|
2072
|
+
stmt.parent = stmt.parent === void 0 ? void 0 : oldToNew.get(stmt.parent);
|
|
2073
|
+
stmt.children = stmt.children.map((group) => group.filter((childId) => !directParentOf.has(childId) || directParentOf.get(childId) === oldId).map((childId) => oldToNew.get(childId) ?? childId)).filter((group) => group.length > 0);
|
|
2074
|
+
return stmt;
|
|
2075
|
+
});
|
|
1956
2076
|
}
|
|
1957
2077
|
|
|
1958
2078
|
// src/parser/WhiteboardScript.ts
|
|
@@ -2026,7 +2146,7 @@ function parseScript(inputText, options = {}) {
|
|
|
2026
2146
|
const statements = options.withoutDialects ? extractStatementsRaw(inputText, tree) : extractStatements(inputText, tree, sport);
|
|
2027
2147
|
return new WhiteboardScript(inputText, statements, []);
|
|
2028
2148
|
} catch (error) {
|
|
2029
|
-
const msg = error
|
|
2149
|
+
const msg = error instanceof Error ? error.message : "Unknown parse error";
|
|
2030
2150
|
return new WhiteboardScript(inputText, [], [{ message: msg }]);
|
|
2031
2151
|
}
|
|
2032
2152
|
}
|
|
@@ -2687,6 +2807,7 @@ var whiteboardScriptLanguage = language.LRLanguage.define({
|
|
|
2687
2807
|
Identifier: tags.variableName,
|
|
2688
2808
|
String: tags.string,
|
|
2689
2809
|
Number: tags.number,
|
|
2810
|
+
"schemeNumber schemeSpaced": tags.number,
|
|
2690
2811
|
Timer: tags.keyword,
|
|
2691
2812
|
collectibleTimer: tags.keyword,
|
|
2692
2813
|
textComment: tags.lineComment,
|
|
@@ -3059,6 +3180,7 @@ var BUNDLED_EFFORT_COUNT = bundledEfforts.length;
|
|
|
3059
3180
|
var InMemoryEffortRegistry = class {
|
|
3060
3181
|
efforts = /* @__PURE__ */ new Map();
|
|
3061
3182
|
sourceFilter = null;
|
|
3183
|
+
initialized = false;
|
|
3062
3184
|
constructor(sourceFilter) {
|
|
3063
3185
|
this.sourceFilter = sourceFilter ?? null;
|
|
3064
3186
|
}
|
|
@@ -3069,6 +3191,10 @@ var InMemoryEffortRegistry = class {
|
|
|
3069
3191
|
this.efforts.set(effort.slug, effort);
|
|
3070
3192
|
}
|
|
3071
3193
|
}
|
|
3194
|
+
this.initialized = true;
|
|
3195
|
+
}
|
|
3196
|
+
isInitialized() {
|
|
3197
|
+
return this.initialized;
|
|
3072
3198
|
}
|
|
3073
3199
|
/** Seed with arbitrary efforts (useful for tests) */
|
|
3074
3200
|
seed(efforts) {
|
|
@@ -3079,10 +3205,21 @@ var InMemoryEffortRegistry = class {
|
|
|
3079
3205
|
/** Clear all efforts */
|
|
3080
3206
|
clear() {
|
|
3081
3207
|
this.efforts.clear();
|
|
3208
|
+
this.initialized = false;
|
|
3082
3209
|
}
|
|
3083
3210
|
resolve(slug) {
|
|
3084
3211
|
return this.efforts.get(slug) ?? null;
|
|
3085
3212
|
}
|
|
3213
|
+
resolveByAlias(label) {
|
|
3214
|
+
const normalized = normalizeForFuzzy(label);
|
|
3215
|
+
for (const effort of this.efforts.values()) {
|
|
3216
|
+
if (normalizeForFuzzy(effort.label) === normalized) return effort;
|
|
3217
|
+
for (const alias of effort.aliases) {
|
|
3218
|
+
if (normalizeForFuzzy(alias) === normalized) return effort;
|
|
3219
|
+
}
|
|
3220
|
+
}
|
|
3221
|
+
return null;
|
|
3222
|
+
}
|
|
3086
3223
|
list() {
|
|
3087
3224
|
return Array.from(this.efforts.values());
|
|
3088
3225
|
}
|
|
@@ -3108,6 +3245,159 @@ var InMemoryEffortRegistry = class {
|
|
|
3108
3245
|
}
|
|
3109
3246
|
};
|
|
3110
3247
|
|
|
3248
|
+
// src/effort-registry/CompositeEffortRegistry.ts
|
|
3249
|
+
var CompositeEffortRegistry = class {
|
|
3250
|
+
userEfforts = /* @__PURE__ */ new Map();
|
|
3251
|
+
bundledEfforts = /* @__PURE__ */ new Map();
|
|
3252
|
+
initialized = false;
|
|
3253
|
+
initialBundled;
|
|
3254
|
+
storage;
|
|
3255
|
+
constructor(options) {
|
|
3256
|
+
if (options) {
|
|
3257
|
+
this.initialBundled = options.bundled;
|
|
3258
|
+
this.storage = options.storage;
|
|
3259
|
+
}
|
|
3260
|
+
}
|
|
3261
|
+
/**
|
|
3262
|
+
* Initialize the registry:
|
|
3263
|
+
* 1. Load bundled efforts into memory
|
|
3264
|
+
* 2. Load user efforts from storage adapter into memory
|
|
3265
|
+
*/
|
|
3266
|
+
async loadBundled(customBundled) {
|
|
3267
|
+
const seed = customBundled ?? this.initialBundled ?? bundledEfforts;
|
|
3268
|
+
for (const effort of seed) {
|
|
3269
|
+
this.bundledEfforts.set(effort.slug, effort);
|
|
3270
|
+
}
|
|
3271
|
+
if (this.storage) {
|
|
3272
|
+
try {
|
|
3273
|
+
const userEfforts = await this.storage.load();
|
|
3274
|
+
for (const effort of userEfforts) {
|
|
3275
|
+
if (effort.registrySource === "user") {
|
|
3276
|
+
this.userEfforts.set(effort.slug, effort);
|
|
3277
|
+
}
|
|
3278
|
+
}
|
|
3279
|
+
} catch (err) {
|
|
3280
|
+
console.warn("[CompositeEffortRegistry] Failed to load user efforts from storage adapter:", err);
|
|
3281
|
+
}
|
|
3282
|
+
}
|
|
3283
|
+
this.initialized = true;
|
|
3284
|
+
}
|
|
3285
|
+
/** True after loadBundled() has resolved */
|
|
3286
|
+
isInitialized() {
|
|
3287
|
+
return this.initialized;
|
|
3288
|
+
}
|
|
3289
|
+
resolve(slug) {
|
|
3290
|
+
return this.userEfforts.get(slug) ?? this.bundledEfforts.get(slug) ?? null;
|
|
3291
|
+
}
|
|
3292
|
+
resolveByAlias(label) {
|
|
3293
|
+
const normalized = normalizeForFuzzy(label);
|
|
3294
|
+
for (const effort of this.userEfforts.values()) {
|
|
3295
|
+
if (normalizeForFuzzy(effort.label) === normalized) return effort;
|
|
3296
|
+
for (const alias of effort.aliases) {
|
|
3297
|
+
if (normalizeForFuzzy(alias) === normalized) return effort;
|
|
3298
|
+
}
|
|
3299
|
+
}
|
|
3300
|
+
for (const effort of this.bundledEfforts.values()) {
|
|
3301
|
+
if (this.userEfforts.has(effort.slug)) continue;
|
|
3302
|
+
if (normalizeForFuzzy(effort.label) === normalized) return effort;
|
|
3303
|
+
for (const alias of effort.aliases) {
|
|
3304
|
+
if (normalizeForFuzzy(alias) === normalized) return effort;
|
|
3305
|
+
}
|
|
3306
|
+
}
|
|
3307
|
+
return null;
|
|
3308
|
+
}
|
|
3309
|
+
list() {
|
|
3310
|
+
const merged = new Map(this.bundledEfforts);
|
|
3311
|
+
for (const [slug, effort] of this.userEfforts) {
|
|
3312
|
+
merged.set(slug, effort);
|
|
3313
|
+
}
|
|
3314
|
+
return Array.from(merged.values());
|
|
3315
|
+
}
|
|
3316
|
+
listByOrigin(origin) {
|
|
3317
|
+
if (origin === "user") {
|
|
3318
|
+
return Array.from(this.userEfforts.values());
|
|
3319
|
+
}
|
|
3320
|
+
if (origin === "bundled") {
|
|
3321
|
+
return Array.from(this.bundledEfforts.values());
|
|
3322
|
+
}
|
|
3323
|
+
return this.list().filter((e) => e.registrySource === origin);
|
|
3324
|
+
}
|
|
3325
|
+
async upsert(effort) {
|
|
3326
|
+
if (effort.registrySource !== "user") {
|
|
3327
|
+
throw new Error(
|
|
3328
|
+
`CompositeEffortRegistry.upsert: only user efforts can be written. Received registrySource="${effort.registrySource}"`
|
|
3329
|
+
);
|
|
3330
|
+
}
|
|
3331
|
+
this.userEfforts.set(effort.slug, effort);
|
|
3332
|
+
if (this.storage) {
|
|
3333
|
+
try {
|
|
3334
|
+
await this.storage.save(effort);
|
|
3335
|
+
} catch (err) {
|
|
3336
|
+
console.warn("[CompositeEffortRegistry] Failed to persist effort to storage adapter:", err);
|
|
3337
|
+
}
|
|
3338
|
+
}
|
|
3339
|
+
}
|
|
3340
|
+
async delete(slug) {
|
|
3341
|
+
const existing = this.resolve(slug);
|
|
3342
|
+
if (existing && existing.registrySource !== "user") {
|
|
3343
|
+
throw new Error(
|
|
3344
|
+
`CompositeEffortRegistry.delete: cannot delete non-user effort "${slug}"`
|
|
3345
|
+
);
|
|
3346
|
+
}
|
|
3347
|
+
this.userEfforts.delete(slug);
|
|
3348
|
+
if (this.storage) {
|
|
3349
|
+
try {
|
|
3350
|
+
await this.storage.delete(slug);
|
|
3351
|
+
} catch (err) {
|
|
3352
|
+
console.warn("[CompositeEffortRegistry] Failed to delete effort from storage adapter:", err);
|
|
3353
|
+
}
|
|
3354
|
+
}
|
|
3355
|
+
}
|
|
3356
|
+
};
|
|
3357
|
+
|
|
3358
|
+
// src/effort-registry/aliasManagement.ts
|
|
3359
|
+
async function addAliasToEffort(registry, targetSlug, newAlias) {
|
|
3360
|
+
const trimmed = newAlias.trim();
|
|
3361
|
+
if (!trimmed) {
|
|
3362
|
+
throw new Error("Alias cannot be empty");
|
|
3363
|
+
}
|
|
3364
|
+
const existing = registry.resolve(targetSlug);
|
|
3365
|
+
if (!existing) {
|
|
3366
|
+
throw new Error(`Effort "${targetSlug}" not found in registry`);
|
|
3367
|
+
}
|
|
3368
|
+
const normalizedNew = normalizeForFuzzy(trimmed);
|
|
3369
|
+
const alreadyHas = normalizeForFuzzy(existing.label) === normalizedNew || existing.aliases.some((a) => normalizeForFuzzy(a) === normalizedNew);
|
|
3370
|
+
if (alreadyHas) {
|
|
3371
|
+
return existing;
|
|
3372
|
+
}
|
|
3373
|
+
const updatedAliases = [...existing.aliases, trimmed];
|
|
3374
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3375
|
+
if (existing.registrySource === "bundled") {
|
|
3376
|
+
const id = typeof crypto !== "undefined" && typeof crypto.randomUUID === "function" ? `effort-user-${crypto.randomUUID()}` : `effort-user-${Date.now()}`;
|
|
3377
|
+
const userEffort = {
|
|
3378
|
+
...existing,
|
|
3379
|
+
id,
|
|
3380
|
+
registrySource: "user",
|
|
3381
|
+
aliases: updatedAliases,
|
|
3382
|
+
updatedAt: now,
|
|
3383
|
+
derivation: existing.derivation ?? {
|
|
3384
|
+
parentSlug: existing.slug,
|
|
3385
|
+
coefficients: {},
|
|
3386
|
+
hardOverrides: {}
|
|
3387
|
+
}
|
|
3388
|
+
};
|
|
3389
|
+
await registry.upsert(userEffort);
|
|
3390
|
+
return userEffort;
|
|
3391
|
+
}
|
|
3392
|
+
const updatedUserEffort = {
|
|
3393
|
+
...existing,
|
|
3394
|
+
aliases: updatedAliases,
|
|
3395
|
+
updatedAt: now
|
|
3396
|
+
};
|
|
3397
|
+
await registry.upsert(updatedUserEffort);
|
|
3398
|
+
return updatedUserEffort;
|
|
3399
|
+
}
|
|
3400
|
+
|
|
3111
3401
|
// src/runtime/contracts/IRuntimeOptions.ts
|
|
3112
3402
|
var DEFAULT_RUNTIME_OPTIONS = {
|
|
3113
3403
|
debugMode: false,
|
|
@@ -3671,9 +3961,7 @@ var ExecutionContext = class {
|
|
|
3671
3961
|
this._workList.push(initialAction);
|
|
3672
3962
|
while (this._workList.length > 0) {
|
|
3673
3963
|
if (this._iteration >= this._maxIterations) {
|
|
3674
|
-
|
|
3675
|
-
console.error(errorMsg);
|
|
3676
|
-
throw new Error(errorMsg);
|
|
3964
|
+
throw new Error(`[ExecutionContext] Max iterations reached (${this._maxIterations}). Aborting to prevent infinite loop.`);
|
|
3677
3965
|
}
|
|
3678
3966
|
const action = this._workList.shift();
|
|
3679
3967
|
this._iteration++;
|
|
@@ -3736,6 +4024,7 @@ var OutputEmitter = class {
|
|
|
3736
4024
|
return;
|
|
3737
4025
|
}
|
|
3738
4026
|
const processed = this._analyticsEngine ? this._analyticsEngine.run(output) : output;
|
|
4027
|
+
this._propagateSourceLine(processed);
|
|
3739
4028
|
this._outputStatements.push(processed);
|
|
3740
4029
|
for (const listener of this._outputListeners) {
|
|
3741
4030
|
try {
|
|
@@ -3994,11 +4283,25 @@ var OutputEmitter = class {
|
|
|
3994
4283
|
// =========================================================================
|
|
3995
4284
|
// Private helpers
|
|
3996
4285
|
// =========================================================================
|
|
4286
|
+
/** Options-built outputs carry only sourceStatementId — copy the source
|
|
4287
|
+
* statement's line/text/dialect so persisted logs stay joinable by line. */
|
|
4288
|
+
_propagateSourceLine(output) {
|
|
4289
|
+
if (output.sourceStatementId === void 0 || output.line !== void 0) return;
|
|
4290
|
+
const src = this._script?.getId(output.sourceStatementId);
|
|
4291
|
+
if (!src) return;
|
|
4292
|
+
output.line = src.line;
|
|
4293
|
+
output.text ??= src.text;
|
|
4294
|
+
output.dialect ??= src.dialect;
|
|
4295
|
+
}
|
|
3997
4296
|
};
|
|
3998
4297
|
|
|
3999
4298
|
// src/runtime/RuntimeObservers.ts
|
|
4000
4299
|
var RuntimeObservers = class {
|
|
4001
4300
|
_stackObservers = /* @__PURE__ */ new Set();
|
|
4301
|
+
_logger;
|
|
4302
|
+
constructor(logger) {
|
|
4303
|
+
this._logger = logger;
|
|
4304
|
+
}
|
|
4002
4305
|
/**
|
|
4003
4306
|
* Subscribe to stack snapshots. The collaborator does NOT emit an
|
|
4004
4307
|
* `'initial'` snapshot automatically — the calling adapter is
|
|
@@ -4024,7 +4327,7 @@ var RuntimeObservers = class {
|
|
|
4024
4327
|
try {
|
|
4025
4328
|
observer(snapshot);
|
|
4026
4329
|
} catch (err) {
|
|
4027
|
-
|
|
4330
|
+
this._logger?.error?.("[RuntimeObservers] Stack observer error:", err);
|
|
4028
4331
|
}
|
|
4029
4332
|
}
|
|
4030
4333
|
}
|
|
@@ -4069,6 +4372,10 @@ var RuntimeObservers = class {
|
|
|
4069
4372
|
|
|
4070
4373
|
// src/runtime/RuntimeLogger.ts
|
|
4071
4374
|
var RuntimeLoggerImpl = class {
|
|
4375
|
+
// Console is this logger's designated output sink; all writes funnel
|
|
4376
|
+
// through this single reference so the no-console rule is waived once.
|
|
4377
|
+
// eslint-disable-next-line no-console
|
|
4378
|
+
_console = console;
|
|
4072
4379
|
_enabled = false;
|
|
4073
4380
|
_history = [];
|
|
4074
4381
|
_maxHistory = 500;
|
|
@@ -4091,7 +4398,8 @@ var RuntimeLoggerImpl = class {
|
|
|
4091
4398
|
};
|
|
4092
4399
|
constructor() {
|
|
4093
4400
|
if (typeof window !== "undefined") {
|
|
4094
|
-
|
|
4401
|
+
const debugWindow = window;
|
|
4402
|
+
this._enabled = !!debugWindow.__WOD_DEBUG__;
|
|
4095
4403
|
}
|
|
4096
4404
|
}
|
|
4097
4405
|
get enabled() {
|
|
@@ -4099,11 +4407,11 @@ var RuntimeLoggerImpl = class {
|
|
|
4099
4407
|
}
|
|
4100
4408
|
enable() {
|
|
4101
4409
|
this._enabled = true;
|
|
4102
|
-
|
|
4410
|
+
this._console.log("%c[RT] \u{1F527} Runtime logging ENABLED", "color: #22c55e; font-weight: bold");
|
|
4103
4411
|
}
|
|
4104
4412
|
disable() {
|
|
4105
4413
|
this._enabled = false;
|
|
4106
|
-
|
|
4414
|
+
this._console.log("%c[RT] Runtime logging disabled", "color: #64748b");
|
|
4107
4415
|
}
|
|
4108
4416
|
getHistory() {
|
|
4109
4417
|
return [...this._history];
|
|
@@ -4121,18 +4429,18 @@ var RuntimeLoggerImpl = class {
|
|
|
4121
4429
|
if (!this._enabled) return;
|
|
4122
4430
|
const behaviors = this.getBehaviorNames(block);
|
|
4123
4431
|
const memoryTypes = block.getAllMemory?.().map((loc) => loc.tag) ?? [];
|
|
4124
|
-
|
|
4432
|
+
this._console.groupCollapsed(
|
|
4125
4433
|
`%c[RT] \u25B6 PUSH %c${block.label || block.blockType || "Block"}%c [${block.key.toString().slice(0, 8)}]`,
|
|
4126
4434
|
this.STYLES.push,
|
|
4127
4435
|
"color: inherit; font-weight: bold",
|
|
4128
4436
|
"color: #64748b; font-weight: normal"
|
|
4129
4437
|
);
|
|
4130
|
-
|
|
4131
|
-
if (parentKey)
|
|
4132
|
-
|
|
4133
|
-
|
|
4134
|
-
if (memoryTypes.length > 0)
|
|
4135
|
-
|
|
4438
|
+
this._console.log("Key:", block.key.toString());
|
|
4439
|
+
if (parentKey) this._console.log("Parent:", parentKey);
|
|
4440
|
+
this._console.log("Source IDs:", block.sourceIds);
|
|
4441
|
+
this._console.log("Behaviors:", behaviors);
|
|
4442
|
+
if (memoryTypes.length > 0) this._console.log("Memory Types:", memoryTypes);
|
|
4443
|
+
this._console.groupEnd();
|
|
4136
4444
|
this.addToHistory("info", "push", `PUSH ${block.label}`, {
|
|
4137
4445
|
key: block.key.toString(),
|
|
4138
4446
|
parentKey,
|
|
@@ -4145,7 +4453,7 @@ var RuntimeLoggerImpl = class {
|
|
|
4145
4453
|
*/
|
|
4146
4454
|
logPop(block, reason) {
|
|
4147
4455
|
if (!this._enabled) return;
|
|
4148
|
-
|
|
4456
|
+
this._console.log(
|
|
4149
4457
|
`%c[RT] \u25C0 POP %c${block.label || block.blockType || "Block"}%c [${block.key.toString().slice(0, 8)}]${reason ? ` (${reason})` : ""}`,
|
|
4150
4458
|
this.STYLES.pop,
|
|
4151
4459
|
"color: inherit; font-weight: bold",
|
|
@@ -4165,15 +4473,15 @@ var RuntimeLoggerImpl = class {
|
|
|
4165
4473
|
if (actions.length === 0) {
|
|
4166
4474
|
return;
|
|
4167
4475
|
}
|
|
4168
|
-
|
|
4476
|
+
this._console.groupCollapsed(
|
|
4169
4477
|
`%c[RT] \u2192 NEXT %c${block.label || "Block"}%c \u2192 ${actions.length} action(s)`,
|
|
4170
4478
|
this.STYLES.next,
|
|
4171
4479
|
"color: inherit; font-weight: bold",
|
|
4172
4480
|
"color: #64748b; font-weight: normal"
|
|
4173
4481
|
);
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4482
|
+
this._console.log("Block:", block.key.toString());
|
|
4483
|
+
this._console.log("Actions:", actionNames);
|
|
4484
|
+
this._console.groupEnd();
|
|
4177
4485
|
this.addToHistory("info", "next", `NEXT ${block.label}`, {
|
|
4178
4486
|
key: block.key.toString(),
|
|
4179
4487
|
actions: actionNames
|
|
@@ -4186,15 +4494,15 @@ var RuntimeLoggerImpl = class {
|
|
|
4186
4494
|
if (!this._enabled) return;
|
|
4187
4495
|
if (actions.length === 0) return;
|
|
4188
4496
|
const actionNames = actions.map((a) => a.type || a.constructor?.name || "Action");
|
|
4189
|
-
|
|
4497
|
+
this._console.groupCollapsed(
|
|
4190
4498
|
`%c[RT] \u26A1 EVENT %c${event.name}%c \u2192 ${actions.length} action(s)`,
|
|
4191
4499
|
this.STYLES.event,
|
|
4192
4500
|
"color: inherit; font-weight: bold",
|
|
4193
4501
|
"color: #64748b; font-weight: normal"
|
|
4194
4502
|
);
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
|
|
4503
|
+
this._console.log("Event Data:", event.data);
|
|
4504
|
+
this._console.log("Actions:", actionNames);
|
|
4505
|
+
this._console.groupEnd();
|
|
4198
4506
|
this.addToHistory("info", "event", `EVENT ${event.name}`, {
|
|
4199
4507
|
eventName: event.name,
|
|
4200
4508
|
eventData: event.data,
|
|
@@ -4210,7 +4518,7 @@ var RuntimeLoggerImpl = class {
|
|
|
4210
4518
|
if (typeof value === "object" && value !== null) {
|
|
4211
4519
|
displayValue = this.summarizeObject(value);
|
|
4212
4520
|
}
|
|
4213
|
-
|
|
4521
|
+
this._console.log(
|
|
4214
4522
|
`%c[RT] \u{1F4DD} MEMORY %c${memoryType}%c on [${blockKey.slice(0, 8)}]:`,
|
|
4215
4523
|
this.STYLES.memory,
|
|
4216
4524
|
"color: inherit; font-weight: bold",
|
|
@@ -4230,17 +4538,35 @@ var RuntimeLoggerImpl = class {
|
|
|
4230
4538
|
if (!this._enabled) return;
|
|
4231
4539
|
const indent = " ".repeat(depth);
|
|
4232
4540
|
const actionName = action.type || action.constructor?.name || "Action";
|
|
4233
|
-
|
|
4541
|
+
this._console.log(
|
|
4234
4542
|
`%c[RT] ${indent}\u2699 %c${actionName}`,
|
|
4235
4543
|
this.STYLES.action,
|
|
4236
4544
|
"color: inherit"
|
|
4237
4545
|
);
|
|
4238
4546
|
}
|
|
4547
|
+
/**
|
|
4548
|
+
* General-purpose message log for runtime consumers.
|
|
4549
|
+
* Gates on _enabled; writes to the console sink and history.
|
|
4550
|
+
*/
|
|
4551
|
+
logMessage(level, category, message, data) {
|
|
4552
|
+
if (!this._enabled) return;
|
|
4553
|
+
this._console.log(`%c[RT] ${category} %c${message}`, this.styleFor(level), "color: inherit");
|
|
4554
|
+
this.addToHistory(level, category, message, data);
|
|
4555
|
+
}
|
|
4556
|
+
/**
|
|
4557
|
+
* Always-on variant of `logMessage`. Use sparingly for errors/warnings that
|
|
4558
|
+
* must be visible even when debug logging is disabled.
|
|
4559
|
+
*/
|
|
4560
|
+
logAlways(level, category, message, data) {
|
|
4561
|
+
this._console.log(`%c[RT] ${category} %c${message}`, this.styleFor(level), "color: inherit");
|
|
4562
|
+
this.addToHistory(level, category, message, data);
|
|
4563
|
+
}
|
|
4239
4564
|
// ============================================================================
|
|
4240
4565
|
// Helpers
|
|
4241
4566
|
// ============================================================================
|
|
4242
4567
|
getBehaviorNames(block) {
|
|
4243
|
-
const
|
|
4568
|
+
const blockWithBehaviors = block;
|
|
4569
|
+
const behaviors = blockWithBehaviors.behaviors;
|
|
4244
4570
|
if (!behaviors || !Array.isArray(behaviors)) return [];
|
|
4245
4571
|
return behaviors.map((b) => b.constructor?.name || "Behavior");
|
|
4246
4572
|
}
|
|
@@ -4257,6 +4583,18 @@ var RuntimeLoggerImpl = class {
|
|
|
4257
4583
|
}
|
|
4258
4584
|
return summary;
|
|
4259
4585
|
}
|
|
4586
|
+
styleFor(level) {
|
|
4587
|
+
switch (level) {
|
|
4588
|
+
case "error":
|
|
4589
|
+
return "color: #ef4444; font-weight: bold";
|
|
4590
|
+
case "warn":
|
|
4591
|
+
return "color: #f59e0b; font-weight: bold";
|
|
4592
|
+
case "info":
|
|
4593
|
+
return "color: #3b82f6; font-weight: bold";
|
|
4594
|
+
default:
|
|
4595
|
+
return "color: #64748b";
|
|
4596
|
+
}
|
|
4597
|
+
}
|
|
4260
4598
|
addToHistory(level, category, message, data) {
|
|
4261
4599
|
this._history.push({
|
|
4262
4600
|
timestamp: /* @__PURE__ */ new Date(),
|
|
@@ -4361,6 +4699,7 @@ var ScriptRuntime = class {
|
|
|
4361
4699
|
constructor(script, compiler, dependencies, options = {}, now = wallClockNow) {
|
|
4362
4700
|
this.script = script;
|
|
4363
4701
|
this.options = { ...DEFAULT_RUNTIME_OPTIONS, ...options };
|
|
4702
|
+
this._observers = new RuntimeObservers(this.options.logger);
|
|
4364
4703
|
this.stack = dependencies.stack;
|
|
4365
4704
|
this.clock = dependencies.clock;
|
|
4366
4705
|
this.eventBus = dependencies.eventBus;
|
|
@@ -4401,7 +4740,7 @@ var ScriptRuntime = class {
|
|
|
4401
4740
|
_output = new OutputEmitter();
|
|
4402
4741
|
// Shared observer collaborator — owns the stack subscriber Set and the
|
|
4403
4742
|
// post-mount snapshot contract. See `RuntimeObservers` for the seam.
|
|
4404
|
-
_observers
|
|
4743
|
+
_observers;
|
|
4405
4744
|
// The current execution context for the "turn"
|
|
4406
4745
|
_activeContext = null;
|
|
4407
4746
|
_now;
|
|
@@ -4548,12 +4887,12 @@ var ScriptRuntime = class {
|
|
|
4548
4887
|
if (block) {
|
|
4549
4888
|
try {
|
|
4550
4889
|
block.unmount(this);
|
|
4551
|
-
} catch
|
|
4890
|
+
} catch {
|
|
4552
4891
|
}
|
|
4553
4892
|
this.stack.pop();
|
|
4554
4893
|
try {
|
|
4555
4894
|
block.dispose(this);
|
|
4556
|
-
} catch
|
|
4895
|
+
} catch {
|
|
4557
4896
|
}
|
|
4558
4897
|
} else {
|
|
4559
4898
|
this.stack.pop();
|
|
@@ -4620,16 +4959,18 @@ var ScriptRuntime = class {
|
|
|
4620
4959
|
}
|
|
4621
4960
|
};
|
|
4622
4961
|
var TypedMemoryReference = class {
|
|
4623
|
-
constructor(_memory, ownerId, type, visibility = "private") {
|
|
4962
|
+
constructor(_memory, ownerId, type, visibility = "private", _logger) {
|
|
4624
4963
|
this._memory = _memory;
|
|
4625
4964
|
this.ownerId = ownerId;
|
|
4626
4965
|
this.type = type;
|
|
4627
4966
|
this.visibility = visibility;
|
|
4967
|
+
this._logger = _logger;
|
|
4628
4968
|
}
|
|
4629
4969
|
_memory;
|
|
4630
4970
|
ownerId;
|
|
4631
4971
|
type;
|
|
4632
4972
|
visibility;
|
|
4973
|
+
_logger;
|
|
4633
4974
|
id = uuid.v7();
|
|
4634
4975
|
_subscriptions = [];
|
|
4635
4976
|
/**
|
|
@@ -4700,7 +5041,7 @@ var TypedMemoryReference = class {
|
|
|
4700
5041
|
try {
|
|
4701
5042
|
subscription.callback(newValue, oldValue);
|
|
4702
5043
|
} catch (error) {
|
|
4703
|
-
|
|
5044
|
+
this._logger?.error?.("Error in memory subscription callback:", error);
|
|
4704
5045
|
}
|
|
4705
5046
|
}
|
|
4706
5047
|
}
|
|
@@ -5122,7 +5463,7 @@ var BehaviorContext = class {
|
|
|
5122
5463
|
try {
|
|
5123
5464
|
unsubscribe();
|
|
5124
5465
|
} catch (err) {
|
|
5125
|
-
|
|
5466
|
+
this.runtime.options.logger?.error?.("[BehaviorContext] Unsubscribe error:", err);
|
|
5126
5467
|
}
|
|
5127
5468
|
}
|
|
5128
5469
|
this.subscriptions = [];
|
|
@@ -5398,7 +5739,7 @@ var RuntimeBlock = class {
|
|
|
5398
5739
|
*/
|
|
5399
5740
|
next(runtime, options) {
|
|
5400
5741
|
if (!this._behaviorContext) {
|
|
5401
|
-
|
|
5742
|
+
RuntimeLogger.logAlways("warn", "RuntimeBlock", "next() called before mount()");
|
|
5402
5743
|
return [];
|
|
5403
5744
|
}
|
|
5404
5745
|
const clock = options?.clock ?? this._behaviorContext.clock;
|
|
@@ -5448,7 +5789,7 @@ var RuntimeBlock = class {
|
|
|
5448
5789
|
try {
|
|
5449
5790
|
unsub();
|
|
5450
5791
|
} catch (err) {
|
|
5451
|
-
|
|
5792
|
+
RuntimeLogger.logAlways("error", "RuntimeBlock", "Error unsubscribing event handler", { error: err });
|
|
5452
5793
|
}
|
|
5453
5794
|
}
|
|
5454
5795
|
this._eventUnsubscribers = [];
|
|
@@ -5626,8 +5967,7 @@ var CompletionTimestampBehavior = class {
|
|
|
5626
5967
|
return [];
|
|
5627
5968
|
}
|
|
5628
5969
|
onNext(ctx) {
|
|
5629
|
-
|
|
5630
|
-
if (blockState && blockState.isComplete && !this.wasComplete && !this.completionTime) {
|
|
5970
|
+
if (ctx.block.isComplete && !this.wasComplete && !this.completionTime) {
|
|
5631
5971
|
this.completionTime = new Date(ctx.clock.currentDate);
|
|
5632
5972
|
this.wasComplete = true;
|
|
5633
5973
|
const completionFragment = {
|
|
@@ -5810,7 +6150,10 @@ var ClearChildrenAction = class {
|
|
|
5810
6150
|
iterations++;
|
|
5811
6151
|
}
|
|
5812
6152
|
if (iterations >= MAX_ITERATIONS) {
|
|
5813
|
-
|
|
6153
|
+
runtime.options.logger?.error?.(
|
|
6154
|
+
"[ClearChildrenAction] Max iterations reached, possible infinite loop",
|
|
6155
|
+
new Error(`Exceeded ${MAX_ITERATIONS} pop iterations for target ${this.targetBlockKey}`)
|
|
6156
|
+
);
|
|
5814
6157
|
}
|
|
5815
6158
|
if (runtime.stack.current?.key.toString() === this.targetBlockKey) {
|
|
5816
6159
|
actions.push(new NextAction(void 0, runtime.nowProvider));
|
|
@@ -5990,7 +6333,7 @@ var CountdownTimerBehavior = class {
|
|
|
5990
6333
|
if (childLoc?.metrics[0]) {
|
|
5991
6334
|
ctx.updateMemory("children:status", [{ ...childLoc.metrics[0], value: newChildStatus }]);
|
|
5992
6335
|
} else {
|
|
5993
|
-
ctx.pushMemory("children:status", [{ type:
|
|
6336
|
+
ctx.pushMemory("children:status", [{ type: "status", image: "", origin: "runtime", value: newChildStatus }]);
|
|
5994
6337
|
}
|
|
5995
6338
|
}
|
|
5996
6339
|
}
|
|
@@ -6394,6 +6737,7 @@ function resolveDominantOrigin(origins) {
|
|
|
6394
6737
|
}
|
|
6395
6738
|
|
|
6396
6739
|
// src/runtime/compiler/EffortEnrichmentPass.ts
|
|
6740
|
+
var logTrace = (message) => console.log(message);
|
|
6397
6741
|
function applyEffortEnrichment(block, options) {
|
|
6398
6742
|
const { resolver, overwrite = false, debug = false } = options;
|
|
6399
6743
|
tryEnrichBlock(block, resolver, overwrite, debug);
|
|
@@ -6405,14 +6749,14 @@ function tryEnrichBlock(block, resolver, overwrite, debug) {
|
|
|
6405
6749
|
}
|
|
6406
6750
|
const label = block.label;
|
|
6407
6751
|
if (!label) {
|
|
6408
|
-
if (debug)
|
|
6752
|
+
if (debug) logTrace(`[EffortEnrichment] Skipping block with no label: ${block.key}`);
|
|
6409
6753
|
return;
|
|
6410
6754
|
}
|
|
6411
6755
|
const existingEffortData = block.getAllMemory().find(
|
|
6412
6756
|
(loc) => loc.metrics.toArray().some((m) => m.type === EFFORT_DATA_METRIC_TYPE)
|
|
6413
6757
|
);
|
|
6414
6758
|
if (existingEffortData && !overwrite) {
|
|
6415
|
-
if (debug)
|
|
6759
|
+
if (debug) logTrace(`[EffortEnrichment] Skipping block already enriched: ${label}`);
|
|
6416
6760
|
return;
|
|
6417
6761
|
}
|
|
6418
6762
|
try {
|
|
@@ -6422,7 +6766,7 @@ function tryEnrichBlock(block, resolver, overwrite, debug) {
|
|
|
6422
6766
|
block.mergeHints(effortHints);
|
|
6423
6767
|
}
|
|
6424
6768
|
if (debug) {
|
|
6425
|
-
|
|
6769
|
+
logTrace(`[EffortEnrichment] Resolved effort: ${label} \u2192 ${resolved.label} (MET: ${resolved.met})`);
|
|
6426
6770
|
}
|
|
6427
6771
|
const effortDataMetric = {
|
|
6428
6772
|
type: EFFORT_DATA_METRIC_TYPE,
|
|
@@ -6478,7 +6822,7 @@ var CompileAndPushBlockAction = class {
|
|
|
6478
6822
|
}
|
|
6479
6823
|
return [new PushBlockAction(compiledBlock, this.options)];
|
|
6480
6824
|
} catch (error) {
|
|
6481
|
-
|
|
6825
|
+
runtime.options.logger?.error?.("CompileAndPushBlockAction: Compilation failed", error);
|
|
6482
6826
|
return [];
|
|
6483
6827
|
}
|
|
6484
6828
|
}
|
|
@@ -6697,7 +7041,7 @@ var ChildSelectionBehavior = class _ChildSelectionBehavior {
|
|
|
6697
7041
|
if (childLoc?.metrics[0]) {
|
|
6698
7042
|
ctx.updateMemory("children:status", [{ ...childLoc.metrics[0], value: status }]);
|
|
6699
7043
|
} else {
|
|
6700
|
-
ctx.pushMemory("children:status", [{ type:
|
|
7044
|
+
ctx.pushMemory("children:status", [{ type: "status", image: "", origin: "runtime", value: status }]);
|
|
6701
7045
|
}
|
|
6702
7046
|
}
|
|
6703
7047
|
/**
|
|
@@ -7245,7 +7589,7 @@ var WaitingToStartBlock = class _WaitingToStartBlock extends RuntimeBlock {
|
|
|
7245
7589
|
*/
|
|
7246
7590
|
static buildBehaviors() {
|
|
7247
7591
|
const behaviors = [];
|
|
7248
|
-
behaviors.push(new ReportOutputBehavior({ label: "Ready to Start" }));
|
|
7592
|
+
behaviors.push(new ReportOutputBehavior({ label: "Ready to Start", emitSegmentOnMount: true }));
|
|
7249
7593
|
behaviors.push(new LabelingBehavior({
|
|
7250
7594
|
mode: "clock",
|
|
7251
7595
|
label: "Ready to Start"
|
|
@@ -7681,7 +8025,7 @@ var JitCompiler = class {
|
|
|
7681
8025
|
const promotion = this._promotionResolver.resolvePromotions(parentBlock, runtime);
|
|
7682
8026
|
if (promotion.hasPromotions) {
|
|
7683
8027
|
const promotedFragments = promotion.promotedFragments;
|
|
7684
|
-
effectiveNodes =
|
|
8028
|
+
effectiveNodes = effectiveNodes.map((node) => {
|
|
7685
8029
|
const clone = Object.create(Object.getPrototypeOf(node));
|
|
7686
8030
|
Object.assign(clone, node);
|
|
7687
8031
|
clone.metrics = node.metrics.clone(node.id).add(...promotedFragments);
|
|
@@ -7698,8 +8042,7 @@ var JitCompiler = class {
|
|
|
7698
8042
|
}
|
|
7699
8043
|
try {
|
|
7700
8044
|
return builder.build();
|
|
7701
|
-
} catch
|
|
7702
|
-
console.error("Failed to build block from composition:", e);
|
|
8045
|
+
} catch {
|
|
7703
8046
|
return void 0;
|
|
7704
8047
|
}
|
|
7705
8048
|
}
|
|
@@ -11637,7 +11980,7 @@ var RuntimeAdapter = class {
|
|
|
11637
11980
|
blocks: stackBlocks,
|
|
11638
11981
|
activeIndex: activeIndex >= 0 ? activeIndex : 0,
|
|
11639
11982
|
depth: stackBlocks.length,
|
|
11640
|
-
rootBlockKey: stackBlocks.
|
|
11983
|
+
rootBlockKey: stackBlocks.at(-1)?.key
|
|
11641
11984
|
},
|
|
11642
11985
|
memory: {
|
|
11643
11986
|
entries: memoryEntries,
|
|
@@ -11664,7 +12007,7 @@ var RuntimeAdapter = class {
|
|
|
11664
12007
|
const blocks = runtime.stack.blocks;
|
|
11665
12008
|
return blocks.map((block, index) => {
|
|
11666
12009
|
const blockType = this.mapBlockType(block);
|
|
11667
|
-
const isActive = index ===
|
|
12010
|
+
const isActive = index === 0;
|
|
11668
12011
|
const status = this.determineBlockStatus(isActive);
|
|
11669
12012
|
const metrics = this.extractBlockFragments(runtime, block);
|
|
11670
12013
|
const displayLocs = block.getMemoryByTag("metric:display");
|
|
@@ -11686,7 +12029,7 @@ var RuntimeAdapter = class {
|
|
|
11686
12029
|
metrics,
|
|
11687
12030
|
metricGroups,
|
|
11688
12031
|
sourceIds: block.sourceIds,
|
|
11689
|
-
lineNumber: block.sourceIds.length > 0 ? block.sourceIds[0] : void 0,
|
|
12032
|
+
lineNumber: block.sourceIds.length > 0 ? runtime.script.getId(block.sourceIds[0])?.line : void 0,
|
|
11690
12033
|
metadata: {
|
|
11691
12034
|
mountTime: void 0,
|
|
11692
12035
|
executionTime: void 0,
|
|
@@ -11713,9 +12056,8 @@ var RuntimeAdapter = class {
|
|
|
11713
12056
|
const ownerLabelMap = /* @__PURE__ */ new Map();
|
|
11714
12057
|
runtime.stack.blocks.forEach((block) => {
|
|
11715
12058
|
const key = block.key.toString();
|
|
11716
|
-
|
|
11717
|
-
|
|
11718
|
-
}
|
|
12059
|
+
const line = block.sourceIds.length > 0 ? runtime.script.getId(block.sourceIds[0])?.line : void 0;
|
|
12060
|
+
if (line !== void 0) ownerLineMap.set(key, line);
|
|
11719
12061
|
ownerLabelMap.set(key, block.label);
|
|
11720
12062
|
});
|
|
11721
12063
|
for (const block of runtime.stack.blocks) {
|
|
@@ -11853,8 +12195,7 @@ var RuntimeAdapter = class {
|
|
|
11853
12195
|
return "pending";
|
|
11854
12196
|
}
|
|
11855
12197
|
findParentKey(blocks, currentIndex) {
|
|
11856
|
-
|
|
11857
|
-
return blocks[currentIndex - 1].key.toString();
|
|
12198
|
+
return blocks[currentIndex + 1]?.key.toString();
|
|
11858
12199
|
}
|
|
11859
12200
|
findChildrenKeys(_blocks, _parentKey) {
|
|
11860
12201
|
return [];
|
|
@@ -12456,6 +12797,8 @@ function evaluateNode(node, context, row) {
|
|
|
12456
12797
|
return right === 0 ? void 0 : left / right;
|
|
12457
12798
|
case "^":
|
|
12458
12799
|
return Math.pow(left, right);
|
|
12800
|
+
default:
|
|
12801
|
+
return void 0;
|
|
12459
12802
|
}
|
|
12460
12803
|
}
|
|
12461
12804
|
case "call":
|
|
@@ -12796,8 +13139,6 @@ function compileLineForm(src, defaultScope) {
|
|
|
12796
13139
|
const sc = SCOPE_RE.exec(line);
|
|
12797
13140
|
if (sc && /^(on\s|when\s|:)/.test(line.slice(sc[0].length).trim())) {
|
|
12798
13141
|
scope = sc[1];
|
|
12799
|
-
fences = void 0;
|
|
12800
|
-
defWhen = void 0;
|
|
12801
13142
|
const header = parseSectionHeader(line.slice(sc[0].length).trim());
|
|
12802
13143
|
fences = header.fences;
|
|
12803
13144
|
defWhen = header.when;
|
|
@@ -13194,7 +13535,7 @@ function computeWorkloadRollups(loads, throughDay) {
|
|
|
13194
13535
|
return rollups;
|
|
13195
13536
|
}
|
|
13196
13537
|
function toStoredOutputStatement(output) {
|
|
13197
|
-
const metrics = output.metrics instanceof wodWikiCore.MetricContainer ? output.metrics.toArray() : Array.isArray(output.metrics) ? output.metrics : output.metrics
|
|
13538
|
+
const metrics = output.metrics instanceof wodWikiCore.MetricContainer ? output.metrics.toArray() : Array.isArray(output.metrics) ? output.metrics : typeof output.metrics.toArray === "function" ? output.metrics.toArray() : [];
|
|
13198
13539
|
const hints = getHints(output);
|
|
13199
13540
|
return {
|
|
13200
13541
|
id: output.id,
|
|
@@ -13213,15 +13554,194 @@ function toStoredOutputStatement(output) {
|
|
|
13213
13554
|
};
|
|
13214
13555
|
}
|
|
13215
13556
|
|
|
13216
|
-
// src/
|
|
13217
|
-
var
|
|
13218
|
-
var
|
|
13219
|
-
|
|
13220
|
-
|
|
13221
|
-
|
|
13222
|
-
|
|
13223
|
-
|
|
13224
|
-
|
|
13557
|
+
// src/parser-fixture/metricLine.ts
|
|
13558
|
+
var TAIL_TOKEN_RE = /[\w-]+:(?:"(?:[^"\\]|\\.)*"|[^ ]+)/g;
|
|
13559
|
+
var FixtureSyntaxError = class extends Error {
|
|
13560
|
+
constructor(message) {
|
|
13561
|
+
super(message);
|
|
13562
|
+
this.name = "FixtureSyntaxError";
|
|
13563
|
+
}
|
|
13564
|
+
};
|
|
13565
|
+
function canonicalizeType(token) {
|
|
13566
|
+
const kebab = token.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
|
|
13567
|
+
return kebab;
|
|
13568
|
+
}
|
|
13569
|
+
var TIME_RE = /^\d{1,2}(:\d{2}){1,2}$/;
|
|
13570
|
+
var NUMBER_RE = /^\d+(\.\d+)?$/;
|
|
13571
|
+
var TAIL_RE = /^[\w-]+:([^ ]+)$/;
|
|
13572
|
+
function parseTimeToMs(token) {
|
|
13573
|
+
const parts = token.split(":").map(Number);
|
|
13574
|
+
return parts.reduce((acc, p) => acc * 60 + p, 0) * 1e3;
|
|
13575
|
+
}
|
|
13576
|
+
function parseTails(sequence, at) {
|
|
13577
|
+
const fields = {};
|
|
13578
|
+
TAIL_TOKEN_RE.lastIndex = 0;
|
|
13579
|
+
let cursor = 0;
|
|
13580
|
+
let m;
|
|
13581
|
+
while ((m = TAIL_TOKEN_RE.exec(sequence)) !== null) {
|
|
13582
|
+
if (sequence.slice(cursor, m.index).trim() !== "") {
|
|
13583
|
+
at(`invalid object tail ${JSON.stringify(sequence.slice(cursor, m.index).trim())}`);
|
|
13584
|
+
}
|
|
13585
|
+
const sep = m[0].indexOf(":");
|
|
13586
|
+
const k = m[0].slice(0, sep);
|
|
13587
|
+
const raw = m[0].slice(sep + 1);
|
|
13588
|
+
fields[k] = raw.startsWith('"') ? JSON.parse(raw) : NUMBER_RE.test(raw) ? Number(raw) : raw;
|
|
13589
|
+
cursor = m.index + m[0].length;
|
|
13590
|
+
}
|
|
13591
|
+
if (sequence.slice(cursor).trim() !== "") {
|
|
13592
|
+
at(`invalid object tail ${JSON.stringify(sequence.slice(cursor).trim())}`);
|
|
13593
|
+
}
|
|
13594
|
+
return fields;
|
|
13595
|
+
}
|
|
13596
|
+
function parseMetricLine(line, file, lineNo) {
|
|
13597
|
+
const src = line.trim();
|
|
13598
|
+
function at(detail) {
|
|
13599
|
+
throw new FixtureSyntaxError(`${file} [line ${lineNo}]: ${detail}`);
|
|
13600
|
+
}
|
|
13601
|
+
if (!line.startsWith("- ")) {
|
|
13602
|
+
at(`metric line must start with "- " (got: ${JSON.stringify(line)})`);
|
|
13603
|
+
}
|
|
13604
|
+
const body = line.slice(2).trim();
|
|
13605
|
+
const tokens = body.split(/\s+/).filter(Boolean);
|
|
13606
|
+
if (tokens.length === 0) {
|
|
13607
|
+
at("metric line is empty");
|
|
13608
|
+
}
|
|
13609
|
+
const [typeToken, ...rest] = tokens;
|
|
13610
|
+
const type = canonicalizeType(typeToken);
|
|
13611
|
+
if (rest.length === 0) {
|
|
13612
|
+
at(`metric "${typeToken}" is missing a value`);
|
|
13613
|
+
}
|
|
13614
|
+
let origin;
|
|
13615
|
+
const lastToken = rest[rest.length - 1];
|
|
13616
|
+
const beforeLast = rest.slice(0, -1).join(" ");
|
|
13617
|
+
const quotesBeforeLast = (beforeLast.match(/"/g) ?? []).length;
|
|
13618
|
+
if (lastToken.startsWith("@") && quotesBeforeLast % 2 === 0) {
|
|
13619
|
+
origin = lastToken.slice(1);
|
|
13620
|
+
rest.pop();
|
|
13621
|
+
if (rest.length === 0) {
|
|
13622
|
+
at(`metric "${typeToken}" is missing a value before @${origin}`);
|
|
13623
|
+
}
|
|
13624
|
+
}
|
|
13625
|
+
const first = rest[0];
|
|
13626
|
+
if (first.startsWith('"')) {
|
|
13627
|
+
const joined = rest.join(" ");
|
|
13628
|
+
const m = joined.match(/^"(?:[^"\\]|\\.)*"/);
|
|
13629
|
+
if (!m) {
|
|
13630
|
+
at(`unterminated quoted string in: ${joined}`);
|
|
13631
|
+
}
|
|
13632
|
+
let value;
|
|
13633
|
+
try {
|
|
13634
|
+
value = JSON.parse(m[0]);
|
|
13635
|
+
} catch {
|
|
13636
|
+
at(`invalid quoted string ${m[0]} (JSON escapes only)`);
|
|
13637
|
+
}
|
|
13638
|
+
const tailPart = joined.slice(m[0].length).trim();
|
|
13639
|
+
if (tailPart) {
|
|
13640
|
+
at(`quoted string cannot combine with object tails (${tailPart}) \u2014 assert fields on the object-valued form instead`);
|
|
13641
|
+
}
|
|
13642
|
+
return { type, kind: "string", value, source: src, ...origin ? { origin } : {} };
|
|
13643
|
+
}
|
|
13644
|
+
if (TIME_RE.test(first)) {
|
|
13645
|
+
if (rest.length > 1) at(`unexpected tokens after time literal: ${rest.slice(1).join(" ")}`);
|
|
13646
|
+
return { type, kind: "number", value: parseTimeToMs(first), source: src, ...origin ? { origin } : {} };
|
|
13647
|
+
}
|
|
13648
|
+
if (NUMBER_RE.test(first)) {
|
|
13649
|
+
if (rest.length === 1) {
|
|
13650
|
+
return { type, kind: "number", value: Number(first), source: src, ...origin ? { origin } : {} };
|
|
13651
|
+
}
|
|
13652
|
+
const second = rest[1];
|
|
13653
|
+
if (!TAIL_RE.test(second)) {
|
|
13654
|
+
if (rest.length > 2) at(`unexpected tokens after amount+unit: ${rest.slice(2).join(" ")}`);
|
|
13655
|
+
return { type, kind: "amountUnit", amount: Number(first), unit: second, source: src, ...origin ? { origin } : {} };
|
|
13656
|
+
}
|
|
13657
|
+
at(`number literal followed by object tail is ambiguous: ${rest.join(" ")}`);
|
|
13658
|
+
}
|
|
13659
|
+
if (TAIL_RE.test(first)) {
|
|
13660
|
+
return { type, kind: "object", fields: parseTails(rest.join(" "), at), source: src, ...origin ? { origin } : {} };
|
|
13661
|
+
}
|
|
13662
|
+
if (first === "?" && rest.length === 1) {
|
|
13663
|
+
return { type, kind: "undefined", source: src, ...origin ? { origin } : {} };
|
|
13664
|
+
}
|
|
13665
|
+
if (rest.length === 1) {
|
|
13666
|
+
return { type, kind: "string", value: first, source: src, ...origin ? { origin } : {} };
|
|
13667
|
+
}
|
|
13668
|
+
at(`unquoted string value with spaces \u2014 use quotes: ${rest.join(" ")}`);
|
|
13669
|
+
}
|
|
13670
|
+
|
|
13671
|
+
// src/parser-fixture/compare.ts
|
|
13672
|
+
function renderMetric(m) {
|
|
13673
|
+
const type = canonicalizeType(String(m.type));
|
|
13674
|
+
const cap = type.charAt(0).toUpperCase() + type.slice(1);
|
|
13675
|
+
const origin = m.origin ? ` @${m.origin}` : "";
|
|
13676
|
+
if (m.value !== null && typeof m.value === "object") {
|
|
13677
|
+
const inner = Object.entries(m.value).map(([k, v]) => `${k}:${String(v)}`).join(" ");
|
|
13678
|
+
return `${cap} ${inner}${origin}`;
|
|
13679
|
+
}
|
|
13680
|
+
if (typeof m.value === "string") {
|
|
13681
|
+
return m.value.includes(" ") ? `${cap} "${m.value}"${origin}` : `${cap} ${m.value}${origin}`;
|
|
13682
|
+
}
|
|
13683
|
+
return `${cap} ${String(m.value)}${origin}`;
|
|
13684
|
+
}
|
|
13685
|
+
function literalMatches(line, metric) {
|
|
13686
|
+
const value = metric.value;
|
|
13687
|
+
switch (line.kind) {
|
|
13688
|
+
case "number":
|
|
13689
|
+
return typeof value === "number" && value === line.value;
|
|
13690
|
+
case "undefined":
|
|
13691
|
+
return metric.value === void 0;
|
|
13692
|
+
case "string":
|
|
13693
|
+
return value === line.value;
|
|
13694
|
+
case "amountUnit": {
|
|
13695
|
+
if (value === null || typeof value !== "object") return false;
|
|
13696
|
+
const v = value;
|
|
13697
|
+
return v.amount === line.amount && v.unit === line.unit && metric.unit === line.unit;
|
|
13698
|
+
}
|
|
13699
|
+
case "object": {
|
|
13700
|
+
if (value === null || typeof value !== "object") return false;
|
|
13701
|
+
const obj = value;
|
|
13702
|
+
return Object.entries(line.fields ?? {}).every(([k, expected]) => {
|
|
13703
|
+
const actual = obj[k];
|
|
13704
|
+
if (typeof actual === "number" && typeof expected === "number") {
|
|
13705
|
+
return actual === expected;
|
|
13706
|
+
}
|
|
13707
|
+
return String(actual) === String(expected);
|
|
13708
|
+
});
|
|
13709
|
+
}
|
|
13710
|
+
}
|
|
13711
|
+
}
|
|
13712
|
+
function lineMatches(line, metric) {
|
|
13713
|
+
if (canonicalizeType(String(metric.type)) !== line.type) return false;
|
|
13714
|
+
if (line.origin !== void 0 && metric.origin !== line.origin) return false;
|
|
13715
|
+
return literalMatches(line, metric);
|
|
13716
|
+
}
|
|
13717
|
+
function diffStatement(expected, actual) {
|
|
13718
|
+
const remaining = [...actual];
|
|
13719
|
+
const matched = [];
|
|
13720
|
+
const missingExpected = [];
|
|
13721
|
+
for (const line of expected) {
|
|
13722
|
+
const hit = remaining.findIndex((m) => lineMatches(line, m));
|
|
13723
|
+
if (hit === -1) {
|
|
13724
|
+
missingExpected.push(line);
|
|
13725
|
+
} else {
|
|
13726
|
+
matched.push({ expected: line, actual: remaining.splice(hit, 1)[0] });
|
|
13727
|
+
}
|
|
13728
|
+
}
|
|
13729
|
+
return { matched, missingExpected, extraActual: remaining };
|
|
13730
|
+
}
|
|
13731
|
+
function compareStatement(expectations, actual, mode) {
|
|
13732
|
+
const { missingExpected, extraActual } = diffStatement(expectations, actual);
|
|
13733
|
+
const diffs = [];
|
|
13734
|
+
const present = actual.map(renderMetric).join("; ") || "nothing";
|
|
13735
|
+
for (const line of missingExpected) {
|
|
13736
|
+
diffs.push(`unmatched expectation ${line.source} \u2014 statement carries: ${present}`);
|
|
13737
|
+
}
|
|
13738
|
+
if (mode === "closed" && missingExpected.length === 0) {
|
|
13739
|
+
for (const m of extraActual) {
|
|
13740
|
+
diffs.push(`unexpected metric ${renderMetric(m)} \u2014 not in the Expected block`);
|
|
13741
|
+
}
|
|
13742
|
+
}
|
|
13743
|
+
return diffs;
|
|
13744
|
+
}
|
|
13225
13745
|
|
|
13226
13746
|
exports.ABSENT = ABSENT;
|
|
13227
13747
|
exports.AGGREGATE_BUILTINS = AGGREGATE_BUILTINS;
|
|
@@ -13230,7 +13750,6 @@ exports.AbortSessionAction = AbortSessionAction;
|
|
|
13230
13750
|
exports.AmrapLogicStrategy = AmrapLogicStrategy;
|
|
13231
13751
|
exports.AnalyticsEngine = AnalyticsEngine;
|
|
13232
13752
|
exports.AnalyticsTransformer = AnalyticsTransformer;
|
|
13233
|
-
exports.BUILD_TIME = BUILD_TIME;
|
|
13234
13753
|
exports.BUILTIN_CALCS = BUILTIN_CALCS;
|
|
13235
13754
|
exports.BUNDLED_EFFORT_COUNT = BUNDLED_EFFORT_COUNT;
|
|
13236
13755
|
exports.BehaviorContext = BehaviorContext;
|
|
@@ -13256,6 +13775,7 @@ exports.ClimbDialect = ClimbDialect;
|
|
|
13256
13775
|
exports.ClimbMetricType = ClimbMetricType;
|
|
13257
13776
|
exports.CompileAndPushBlockAction = CompileAndPushBlockAction;
|
|
13258
13777
|
exports.CompletionTimestampBehavior = CompletionTimestampBehavior;
|
|
13778
|
+
exports.CompositeEffortRegistry = CompositeEffortRegistry;
|
|
13259
13779
|
exports.CountdownTimerBehavior = CountdownTimerBehavior;
|
|
13260
13780
|
exports.CountupTimerBehavior = CountupTimerBehavior;
|
|
13261
13781
|
exports.CrossFitDialect = CrossFitDialect;
|
|
@@ -13283,7 +13803,7 @@ exports.ErrorAction = ErrorAction;
|
|
|
13283
13803
|
exports.EventBus = EventBus;
|
|
13284
13804
|
exports.ExecutionContext = ExecutionContext;
|
|
13285
13805
|
exports.ExitBehavior = ExitBehavior;
|
|
13286
|
-
exports.
|
|
13806
|
+
exports.FixtureSyntaxError = FixtureSyntaxError;
|
|
13287
13807
|
exports.GenericGroupStrategy = GenericGroupStrategy;
|
|
13288
13808
|
exports.GenericLoopStrategy = GenericLoopStrategy;
|
|
13289
13809
|
exports.GenericTimerStrategy = GenericTimerStrategy;
|
|
@@ -13328,7 +13848,6 @@ exports.RuntimeLogger = RuntimeLogger;
|
|
|
13328
13848
|
exports.RuntimeMemory = RuntimeMemory;
|
|
13329
13849
|
exports.RuntimeObservers = RuntimeObservers;
|
|
13330
13850
|
exports.RuntimeStack = RuntimeStack;
|
|
13331
|
-
exports.SEMVER = SEMVER;
|
|
13332
13851
|
exports.STANDARD_UNITS = STANDARD_UNITS;
|
|
13333
13852
|
exports.STORE_CALCS = STORE_CALCS;
|
|
13334
13853
|
exports.STREAM_ATOMS = STREAM_ATOMS;
|
|
@@ -13354,7 +13873,6 @@ exports.UnitSet = UnitSet;
|
|
|
13354
13873
|
exports.UnitsDialect = UnitsDialect;
|
|
13355
13874
|
exports.UnregisterEventHandlerAction = UnregisterEventHandlerAction;
|
|
13356
13875
|
exports.UpdateNextPreviewAction = UpdateNextPreviewAction;
|
|
13357
|
-
exports.VERSION = VERSION;
|
|
13358
13876
|
exports.VISIBILITY_ICONS = VISIBILITY_ICONS;
|
|
13359
13877
|
exports.VISIBILITY_LABELS = VISIBILITY_LABELS;
|
|
13360
13878
|
exports.WaitingToStartBlock = WaitingToStartBlock;
|
|
@@ -13362,16 +13880,19 @@ exports.WaitingToStartInjectorBehavior = WaitingToStartInjectorBehavior;
|
|
|
13362
13880
|
exports.WhiteboardScript = WhiteboardScript;
|
|
13363
13881
|
exports.WodDialect = WodDialect;
|
|
13364
13882
|
exports.YogaDialect = YogaDialect;
|
|
13883
|
+
exports.addAliasToEffort = addAliasToEffort;
|
|
13365
13884
|
exports.addDim = addDim;
|
|
13366
13885
|
exports.buildStaticLookups = buildStaticLookups;
|
|
13367
13886
|
exports.buildTooltip = buildTooltip;
|
|
13368
13887
|
exports.bundledEfforts = bundledEfforts;
|
|
13369
13888
|
exports.calculateElapsed = calculateElapsed;
|
|
13889
|
+
exports.canonicalizeType = canonicalizeType;
|
|
13370
13890
|
exports.checkCalcLine = checkCalcLine;
|
|
13371
13891
|
exports.classifyStatements = classifyStatements;
|
|
13372
13892
|
exports.closeCurrentSpan = closeCurrentSpan;
|
|
13373
13893
|
exports.collapseUnresolvedChoices = collapseUnresolvedChoices;
|
|
13374
13894
|
exports.commonFixtureSet = commonFixtureSet;
|
|
13895
|
+
exports.compareStatement = compareStatement;
|
|
13375
13896
|
exports.compileLineForm = compileLineForm;
|
|
13376
13897
|
exports.composeDivUnit = composeDivUnit;
|
|
13377
13898
|
exports.composeMulUnit = composeMulUnit;
|
|
@@ -13398,6 +13919,7 @@ exports.dailySessionLoads = dailySessionLoads;
|
|
|
13398
13919
|
exports.dayBucket = dayBucket;
|
|
13399
13920
|
exports.dialectRegistry = dialectRegistry;
|
|
13400
13921
|
exports.dialectStack = dialectStack;
|
|
13922
|
+
exports.diffStatement = diffStatement;
|
|
13401
13923
|
exports.dimEquals = dimEquals;
|
|
13402
13924
|
exports.disciplineFactorFor = disciplineFactorFor;
|
|
13403
13925
|
exports.evaluate = evaluate;
|
|
@@ -13452,10 +13974,12 @@ exports.outputNodeIds = outputNodeIds;
|
|
|
13452
13974
|
exports.parseCalcLine = parseCalcLine;
|
|
13453
13975
|
exports.parseCalculateBlock = parseCalculateBlock;
|
|
13454
13976
|
exports.parseExpression = parseExpression;
|
|
13977
|
+
exports.parseMetricLine = parseMetricLine;
|
|
13455
13978
|
exports.parseScript = parseScript;
|
|
13456
13979
|
exports.printCalculation = printCalculation;
|
|
13457
13980
|
exports.readTimer = readTimer;
|
|
13458
13981
|
exports.realtimeProcessorRegistry = realtimeProcessorRegistry;
|
|
13982
|
+
exports.renderMetric = renderMetric;
|
|
13459
13983
|
exports.resolveDominantOrigin = resolveDominantOrigin;
|
|
13460
13984
|
exports.sharedParser = sharedParser;
|
|
13461
13985
|
exports.startSpan = startSpan;
|