jssm 5.158.2 → 5.159.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -359,10 +359,20 @@ function peg$parse(input, options) {
359
359
  node.loc = location();
360
360
  }
361
361
  return node;
362
- }, peg$c1235 = "milliseconds", peg$c1236 = peg$literalExpectation("milliseconds", false), peg$c1237 = function () { return 1; }, peg$c1238 = "millisecond", peg$c1239 = peg$literalExpectation("millisecond", false), peg$c1240 = "msecs", peg$c1241 = peg$literalExpectation("msecs", false), peg$c1242 = "msec", peg$c1243 = peg$literalExpectation("msec", false), peg$c1244 = "ms", peg$c1245 = peg$literalExpectation("ms", false), peg$c1246 = "seconds", peg$c1247 = peg$literalExpectation("seconds", false), peg$c1248 = function () { return 1000; }, peg$c1249 = "second", peg$c1250 = peg$literalExpectation("second", false), peg$c1251 = "secs", peg$c1252 = peg$literalExpectation("secs", false), peg$c1253 = "sec", peg$c1254 = peg$literalExpectation("sec", false), peg$c1255 = "s", peg$c1256 = peg$literalExpectation("s", false), peg$c1257 = "minutes", peg$c1258 = peg$literalExpectation("minutes", false), peg$c1259 = function () { return 1000 * 60; }, peg$c1260 = "minute", peg$c1261 = peg$literalExpectation("minute", false), peg$c1262 = "mins", peg$c1263 = peg$literalExpectation("mins", false), peg$c1264 = "min", peg$c1265 = peg$literalExpectation("min", false), peg$c1266 = "m", peg$c1267 = peg$literalExpectation("m", false), peg$c1268 = "hours", peg$c1269 = peg$literalExpectation("hours", false), peg$c1270 = function () { return 1000 * 60 * 60; }, peg$c1271 = "hour", peg$c1272 = peg$literalExpectation("hour", false), peg$c1273 = "hrs", peg$c1274 = peg$literalExpectation("hrs", false), peg$c1275 = "hr", peg$c1276 = peg$literalExpectation("hr", false), peg$c1277 = "h", peg$c1278 = peg$literalExpectation("h", false), peg$c1279 = "days", peg$c1280 = peg$literalExpectation("days", false), peg$c1281 = function () { return 1000 * 60 * 60 * 24; }, peg$c1282 = "day", peg$c1283 = peg$literalExpectation("day", false), peg$c1284 = "d", peg$c1285 = peg$literalExpectation("d", false), peg$c1286 = "weeks", peg$c1287 = peg$literalExpectation("weeks", false), peg$c1288 = function () { return 1000 * 60 * 60 * 24 * 7; }, peg$c1289 = "week", peg$c1290 = peg$literalExpectation("week", false), peg$c1291 = "wks", peg$c1292 = peg$literalExpectation("wks", false), peg$c1293 = "wk", peg$c1294 = peg$literalExpectation("wk", false), peg$c1295 = "w", peg$c1296 = peg$literalExpectation("w", false), peg$c1297 = "after", peg$c1298 = peg$literalExpectation("after", false), peg$c1299 = function (value, timescale) { return value * (timescale || 1000); }, peg$c1300 = function (names) { return names.map(i => i[0]); }, peg$c1301 = peg$otherExpectation("group reference"), peg$c1302 = "&", peg$c1303 = peg$literalExpectation("&", false), peg$c1304 = function (name) { return { key: 'group_ref', name }; }, peg$c1305 = "...", peg$c1306 = peg$literalExpectation("...", false), peg$c1307 = function (name) { return { kind: 'group', name, mode: 'spread' }; }, peg$c1308 = function (name) { return { kind: 'group', name, mode: 'nest' }; }, peg$c1309 = function (name) { return { kind: 'state', name }; }, peg$c1310 = function (members) {
362
+ }, peg$c1235 = "milliseconds", peg$c1236 = peg$literalExpectation("milliseconds", false), peg$c1237 = function () { return 1; }, peg$c1238 = "millisecond", peg$c1239 = peg$literalExpectation("millisecond", false), peg$c1240 = "msecs", peg$c1241 = peg$literalExpectation("msecs", false), peg$c1242 = "msec", peg$c1243 = peg$literalExpectation("msec", false), peg$c1244 = "ms", peg$c1245 = peg$literalExpectation("ms", false), peg$c1246 = "seconds", peg$c1247 = peg$literalExpectation("seconds", false), peg$c1248 = function () { return 1000; }, peg$c1249 = "second", peg$c1250 = peg$literalExpectation("second", false), peg$c1251 = "secs", peg$c1252 = peg$literalExpectation("secs", false), peg$c1253 = "sec", peg$c1254 = peg$literalExpectation("sec", false), peg$c1255 = "s", peg$c1256 = peg$literalExpectation("s", false), peg$c1257 = "minutes", peg$c1258 = peg$literalExpectation("minutes", false), peg$c1259 = function () { return 1000 * 60; }, peg$c1260 = "minute", peg$c1261 = peg$literalExpectation("minute", false), peg$c1262 = "mins", peg$c1263 = peg$literalExpectation("mins", false), peg$c1264 = "min", peg$c1265 = peg$literalExpectation("min", false), peg$c1266 = "m", peg$c1267 = peg$literalExpectation("m", false), peg$c1268 = "hours", peg$c1269 = peg$literalExpectation("hours", false), peg$c1270 = function () { return 1000 * 60 * 60; }, peg$c1271 = "hour", peg$c1272 = peg$literalExpectation("hour", false), peg$c1273 = "hrs", peg$c1274 = peg$literalExpectation("hrs", false), peg$c1275 = "hr", peg$c1276 = peg$literalExpectation("hr", false), peg$c1277 = "h", peg$c1278 = peg$literalExpectation("h", false), peg$c1279 = "days", peg$c1280 = peg$literalExpectation("days", false), peg$c1281 = function () { return 1000 * 60 * 60 * 24; }, peg$c1282 = "day", peg$c1283 = peg$literalExpectation("day", false), peg$c1284 = "d", peg$c1285 = peg$literalExpectation("d", false), peg$c1286 = "weeks", peg$c1287 = peg$literalExpectation("weeks", false), peg$c1288 = function () { return 1000 * 60 * 60 * 24 * 7; }, peg$c1289 = "week", peg$c1290 = peg$literalExpectation("week", false), peg$c1291 = "wks", peg$c1292 = peg$literalExpectation("wks", false), peg$c1293 = "wk", peg$c1294 = peg$literalExpectation("wk", false), peg$c1295 = "w", peg$c1296 = peg$literalExpectation("w", false), peg$c1297 = "after", peg$c1298 = peg$literalExpectation("after", false), peg$c1299 = function (value, timescale) { return value * (timescale || 1000); }, peg$c1300 = function (names) { return names.map(i => i[0]); }, peg$c1301 = peg$otherExpectation("group reference"), peg$c1302 = "&", peg$c1303 = peg$literalExpectation("&", false), peg$c1304 = function (name) { return { key: 'group_ref', name }; }, peg$c1305 = "...", peg$c1306 = peg$literalExpectation("...", false), peg$c1307 = function (name) { const m = { kind: 'group', name, mode: 'spread' }; if (options.locations) {
363
+ m.__loc = location();
364
+ } return m; }, peg$c1308 = function (name) { const m = { kind: 'group', name, mode: 'nest' }; if (options.locations) {
365
+ m.__loc = location();
366
+ } return m; }, peg$c1309 = function (name) { const m = { kind: 'state', name }; if (options.locations) {
367
+ m.__loc = location();
368
+ } return m; }, peg$c1310 = function (members) {
363
369
  const items = members.map(m => m[0]);
364
370
  const has_group = items.some(m => m.kind === 'group');
365
- return has_group ? items : items.map(m => m.name);
371
+ const collapsed = has_group ? items : items.map(m => m.name);
372
+ if (options.locations) {
373
+ collapsed.__member_locs = items.map((m) => m.__loc);
374
+ }
375
+ return collapsed;
366
376
  }, peg$c1311 = "+|", peg$c1312 = peg$literalExpectation("+|", false), peg$c1313 = function (n) {
367
377
  const node = { key: 'stripe', value: parseInt(n, 10) };
368
378
  if (options.locations) {
@@ -812,69 +822,96 @@ function peg$parse(input, options) {
812
822
  const node = { key: 'named_list', name, value };
813
823
  if (options.locations) {
814
824
  node.loc = location();
825
+ node.value_locs = value.__member_locs;
826
+ delete value.__member_locs;
827
+ }
828
+ return node;
829
+ }, peg$c1549 = function (name, value) {
830
+ const node = { key: 'named_list', name, value: value.name };
831
+ if (options.locations) {
832
+ node.loc = location();
833
+ node.value_locs = [value.__loc];
815
834
  }
816
835
  return node;
817
- }, peg$c1549 = peg$otherExpectation("hook event (enter/exit)"), peg$c1550 = "enter", peg$c1551 = peg$literalExpectation("enter", false), peg$c1552 = "exit", peg$c1553 = peg$literalExpectation("exit", false), peg$c1554 = peg$otherExpectation("hook declaration"), peg$c1555 = "on", peg$c1556 = peg$literalExpectation("on", false), peg$c1557 = "do", peg$c1558 = peg$literalExpectation("do", false), peg$c1559 = function (event, subject, action) {
836
+ }, peg$c1550 = function (name) {
837
+ const m = { name };
838
+ if (options.locations) {
839
+ m.__loc = location();
840
+ }
841
+ return m;
842
+ }, peg$c1551 = peg$otherExpectation("hook event (enter/exit)"), peg$c1552 = "enter", peg$c1553 = peg$literalExpectation("enter", false), peg$c1554 = "exit", peg$c1555 = peg$literalExpectation("exit", false), peg$c1556 = peg$otherExpectation("hook declaration"), peg$c1557 = "on", peg$c1558 = peg$literalExpectation("on", false), peg$c1559 = "do", peg$c1560 = peg$literalExpectation("do", false), peg$c1561 = function (event, subject, action) {
818
843
  const node = { key: 'hook_decl', event, subject, action };
844
+ if (subject.key === 'hook_state_subject') {
845
+ node.subject = subject.name;
846
+ if (options.locations) {
847
+ node.subject_loc = subject.__loc;
848
+ }
849
+ }
819
850
  if (options.locations) {
820
851
  node.loc = location();
821
852
  }
822
853
  return node;
823
- }, peg$c1560 = function (name, default_value) {
854
+ }, peg$c1562 = function (name) {
855
+ const m = { key: 'hook_state_subject', name };
856
+ if (options.locations) {
857
+ m.__loc = location();
858
+ }
859
+ return m;
860
+ }, peg$c1563 = function (name, default_value) {
824
861
  const node = { key: 'property_definition', name, default_value, required: true };
825
862
  if (options.locations) {
826
863
  node.loc = location();
827
864
  }
828
865
  return node;
829
- }, peg$c1561 = function (name) {
866
+ }, peg$c1564 = function (name) {
830
867
  const node = { key: 'property_definition', name, required: true };
831
868
  if (options.locations) {
832
869
  node.loc = location();
833
870
  }
834
871
  return node;
835
- }, peg$c1562 = function (name, default_value) {
872
+ }, peg$c1565 = function (name, default_value) {
836
873
  const node = { key: 'property_definition', name, default_value };
837
874
  if (options.locations) {
838
875
  node.loc = location();
839
876
  }
840
877
  return node;
841
- }, peg$c1563 = function (name) {
878
+ }, peg$c1566 = function (name) {
842
879
  const node = { key: 'property_definition', name };
843
880
  if (options.locations) {
844
881
  node.loc = location();
845
882
  }
846
883
  return node;
847
- }, peg$c1564 = "arrange", peg$c1565 = peg$literalExpectation("arrange", false), peg$c1566 = function (value) {
884
+ }, peg$c1567 = "arrange", peg$c1568 = peg$literalExpectation("arrange", false), peg$c1569 = function (value) {
848
885
  const node = { key: 'arrange_declaration', value };
849
886
  if (options.locations) {
850
887
  node.loc = location();
851
888
  }
852
889
  return node;
853
- }, peg$c1567 = "arrange-start", peg$c1568 = peg$literalExpectation("arrange-start", false), peg$c1569 = function (value) {
890
+ }, peg$c1570 = "arrange-start", peg$c1571 = peg$literalExpectation("arrange-start", false), peg$c1572 = function (value) {
854
891
  const node = { key: 'arrange_start_declaration', value };
855
892
  if (options.locations) {
856
893
  node.loc = location();
857
894
  }
858
895
  return node;
859
- }, peg$c1570 = "arrange-end", peg$c1571 = peg$literalExpectation("arrange-end", false), peg$c1572 = function (value) {
896
+ }, peg$c1573 = "arrange-end", peg$c1574 = peg$literalExpectation("arrange-end", false), peg$c1575 = function (value) {
860
897
  const node = { key: 'arrange_end_declaration', value };
861
898
  if (options.locations) {
862
899
  node.loc = location();
863
900
  }
864
901
  return node;
865
- }, peg$c1573 = peg$otherExpectation("oarrange declaration"), peg$c1574 = "oarrange", peg$c1575 = peg$literalExpectation("oarrange", false), peg$c1576 = function (value) {
902
+ }, peg$c1576 = peg$otherExpectation("oarrange declaration"), peg$c1577 = "oarrange", peg$c1578 = peg$literalExpectation("oarrange", false), peg$c1579 = function (value) {
866
903
  const node = { key: 'oarrange_declaration', value };
867
904
  if (options.locations) {
868
905
  node.loc = location();
869
906
  }
870
907
  return node;
871
- }, peg$c1577 = peg$otherExpectation("farrange declaration"), peg$c1578 = "farrange", peg$c1579 = peg$literalExpectation("farrange", false), peg$c1580 = function (value) {
908
+ }, peg$c1580 = peg$otherExpectation("farrange declaration"), peg$c1581 = "farrange", peg$c1582 = peg$literalExpectation("farrange", false), peg$c1583 = function (value) {
872
909
  const node = { key: 'farrange_declaration', value };
873
910
  if (options.locations) {
874
911
  node.loc = location();
875
912
  }
876
913
  return node;
877
- }, peg$c1581 = peg$otherExpectation("arrange declaration"), peg$currPos = 0, peg$savedPos = 0, peg$posDetailsCache = [{ line: 1, column: 1 }], peg$maxFailPos = 0, peg$maxFailExpected = [], peg$silentFails = 0, peg$result;
914
+ }, peg$c1584 = peg$otherExpectation("arrange declaration"), peg$currPos = 0, peg$savedPos = 0, peg$posDetailsCache = [{ line: 1, column: 1 }], peg$maxFailPos = 0, peg$maxFailExpected = [], peg$silentFails = 0, peg$result;
878
915
  if ("startRule" in options) {
879
916
  if (!(options.startRule in peg$startRuleFunctions)) {
880
917
  throw new Error("Can't start parsing from rule \"" + options.startRule + "\".");
@@ -19498,7 +19535,7 @@ function peg$parse(input, options) {
19498
19535
  s7 = null;
19499
19536
  }
19500
19537
  if (s7 !== peg$FAILED) {
19501
- s8 = peg$parseLabel();
19538
+ s8 = peg$parseGroupAliasMember();
19502
19539
  if (s8 !== peg$FAILED) {
19503
19540
  s9 = peg$parseWS();
19504
19541
  if (s9 === peg$FAILED) {
@@ -19522,7 +19559,7 @@ function peg$parse(input, options) {
19522
19559
  }
19523
19560
  if (s11 !== peg$FAILED) {
19524
19561
  peg$savedPos = s0;
19525
- s1 = peg$c1548(s4, s8);
19562
+ s1 = peg$c1549(s4, s8);
19526
19563
  s0 = s1;
19527
19564
  }
19528
19565
  else {
@@ -19582,35 +19619,46 @@ function peg$parse(input, options) {
19582
19619
  }
19583
19620
  return s0;
19584
19621
  }
19622
+ function peg$parseGroupAliasMember() {
19623
+ var s0, s1;
19624
+ s0 = peg$currPos;
19625
+ s1 = peg$parseLabel();
19626
+ if (s1 !== peg$FAILED) {
19627
+ peg$savedPos = s0;
19628
+ s1 = peg$c1550(s1);
19629
+ }
19630
+ s0 = s1;
19631
+ return s0;
19632
+ }
19585
19633
  function peg$parseHookEvent() {
19586
19634
  var s0;
19587
19635
  peg$silentFails++;
19588
- if (input.substr(peg$currPos, 5) === peg$c1550) {
19589
- s0 = peg$c1550;
19636
+ if (input.substr(peg$currPos, 5) === peg$c1552) {
19637
+ s0 = peg$c1552;
19590
19638
  peg$currPos += 5;
19591
19639
  }
19592
19640
  else {
19593
19641
  s0 = peg$FAILED;
19594
19642
  if (peg$silentFails === 0 && peg$currPos >= peg$maxFailPos) {
19595
- peg$fail(peg$c1551);
19643
+ peg$fail(peg$c1553);
19596
19644
  }
19597
19645
  }
19598
19646
  if (s0 === peg$FAILED) {
19599
- if (input.substr(peg$currPos, 4) === peg$c1552) {
19600
- s0 = peg$c1552;
19647
+ if (input.substr(peg$currPos, 4) === peg$c1554) {
19648
+ s0 = peg$c1554;
19601
19649
  peg$currPos += 4;
19602
19650
  }
19603
19651
  else {
19604
19652
  s0 = peg$FAILED;
19605
19653
  if (peg$silentFails === 0 && peg$currPos >= peg$maxFailPos) {
19606
- peg$fail(peg$c1553);
19654
+ peg$fail(peg$c1555);
19607
19655
  }
19608
19656
  }
19609
19657
  }
19610
19658
  peg$silentFails--;
19611
19659
  if (s0 === peg$FAILED) {
19612
19660
  if (peg$silentFails === 0 && peg$currPos >= peg$maxFailPos) {
19613
- peg$fail(peg$c1549);
19661
+ peg$fail(peg$c1551);
19614
19662
  }
19615
19663
  }
19616
19664
  return s0;
@@ -19624,14 +19672,14 @@ function peg$parse(input, options) {
19624
19672
  s1 = null;
19625
19673
  }
19626
19674
  if (s1 !== peg$FAILED) {
19627
- if (input.substr(peg$currPos, 2) === peg$c1555) {
19628
- s2 = peg$c1555;
19675
+ if (input.substr(peg$currPos, 2) === peg$c1557) {
19676
+ s2 = peg$c1557;
19629
19677
  peg$currPos += 2;
19630
19678
  }
19631
19679
  else {
19632
19680
  s2 = peg$FAILED;
19633
19681
  if (peg$silentFails === 0 && peg$currPos >= peg$maxFailPos) {
19634
- peg$fail(peg$c1556);
19682
+ peg$fail(peg$c1558);
19635
19683
  }
19636
19684
  }
19637
19685
  if (s2 !== peg$FAILED) {
@@ -19643,19 +19691,19 @@ function peg$parse(input, options) {
19643
19691
  if (s5 !== peg$FAILED) {
19644
19692
  s6 = peg$parseGroupRef();
19645
19693
  if (s6 === peg$FAILED) {
19646
- s6 = peg$parseLabel();
19694
+ s6 = peg$parseHookStateSubject();
19647
19695
  }
19648
19696
  if (s6 !== peg$FAILED) {
19649
19697
  s7 = peg$parseWS();
19650
19698
  if (s7 !== peg$FAILED) {
19651
- if (input.substr(peg$currPos, 2) === peg$c1557) {
19652
- s8 = peg$c1557;
19699
+ if (input.substr(peg$currPos, 2) === peg$c1559) {
19700
+ s8 = peg$c1559;
19653
19701
  peg$currPos += 2;
19654
19702
  }
19655
19703
  else {
19656
19704
  s8 = peg$FAILED;
19657
19705
  if (peg$silentFails === 0 && peg$currPos >= peg$maxFailPos) {
19658
- peg$fail(peg$c1558);
19706
+ peg$fail(peg$c1560);
19659
19707
  }
19660
19708
  }
19661
19709
  if (s8 !== peg$FAILED) {
@@ -19685,7 +19733,7 @@ function peg$parse(input, options) {
19685
19733
  }
19686
19734
  if (s13 !== peg$FAILED) {
19687
19735
  peg$savedPos = s0;
19688
- s1 = peg$c1559(s4, s6, s10);
19736
+ s1 = peg$c1561(s4, s6, s10);
19689
19737
  s0 = s1;
19690
19738
  }
19691
19739
  else {
@@ -19756,11 +19804,22 @@ function peg$parse(input, options) {
19756
19804
  if (s0 === peg$FAILED) {
19757
19805
  s1 = peg$FAILED;
19758
19806
  if (peg$silentFails === 0 && peg$currPos >= peg$maxFailPos) {
19759
- peg$fail(peg$c1554);
19807
+ peg$fail(peg$c1556);
19760
19808
  }
19761
19809
  }
19762
19810
  return s0;
19763
19811
  }
19812
+ function peg$parseHookStateSubject() {
19813
+ var s0, s1;
19814
+ s0 = peg$currPos;
19815
+ s1 = peg$parseLabel();
19816
+ if (s1 !== peg$FAILED) {
19817
+ peg$savedPos = s0;
19818
+ s1 = peg$c1562(s1);
19819
+ }
19820
+ s0 = s1;
19821
+ return s0;
19822
+ }
19764
19823
  function peg$parseMachineProperty() {
19765
19824
  var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13;
19766
19825
  s0 = peg$currPos;
@@ -19836,7 +19895,7 @@ function peg$parse(input, options) {
19836
19895
  }
19837
19896
  if (s13 !== peg$FAILED) {
19838
19897
  peg$savedPos = s0;
19839
- s1 = peg$c1560(s4, s8);
19898
+ s1 = peg$c1563(s4, s8);
19840
19899
  s0 = s1;
19841
19900
  }
19842
19901
  else {
@@ -19960,7 +20019,7 @@ function peg$parse(input, options) {
19960
20019
  }
19961
20020
  if (s9 !== peg$FAILED) {
19962
20021
  peg$savedPos = s0;
19963
- s1 = peg$c1561(s4);
20022
+ s1 = peg$c1564(s4);
19964
20023
  s0 = s1;
19965
20024
  }
19966
20025
  else {
@@ -20068,7 +20127,7 @@ function peg$parse(input, options) {
20068
20127
  }
20069
20128
  if (s11 !== peg$FAILED) {
20070
20129
  peg$savedPos = s0;
20071
- s1 = peg$c1562(s4, s8);
20130
+ s1 = peg$c1565(s4, s8);
20072
20131
  s0 = s1;
20073
20132
  }
20074
20133
  else {
@@ -20169,7 +20228,7 @@ function peg$parse(input, options) {
20169
20228
  }
20170
20229
  if (s7 !== peg$FAILED) {
20171
20230
  peg$savedPos = s0;
20172
- s1 = peg$c1563(s4);
20231
+ s1 = peg$c1566(s4);
20173
20232
  s0 = s1;
20174
20233
  }
20175
20234
  else {
@@ -20214,14 +20273,14 @@ function peg$parse(input, options) {
20214
20273
  function peg$parseRegularArrangeDeclaration() {
20215
20274
  var s0, s1, s2, s3, s4, s5, s6;
20216
20275
  s0 = peg$currPos;
20217
- if (input.substr(peg$currPos, 7) === peg$c1564) {
20218
- s1 = peg$c1564;
20276
+ if (input.substr(peg$currPos, 7) === peg$c1567) {
20277
+ s1 = peg$c1567;
20219
20278
  peg$currPos += 7;
20220
20279
  }
20221
20280
  else {
20222
20281
  s1 = peg$FAILED;
20223
20282
  if (peg$silentFails === 0 && peg$currPos >= peg$maxFailPos) {
20224
- peg$fail(peg$c1565);
20283
+ peg$fail(peg$c1568);
20225
20284
  }
20226
20285
  }
20227
20286
  if (s1 !== peg$FAILED) {
@@ -20254,7 +20313,7 @@ function peg$parse(input, options) {
20254
20313
  }
20255
20314
  if (s6 !== peg$FAILED) {
20256
20315
  peg$savedPos = s0;
20257
- s1 = peg$c1566(s3);
20316
+ s1 = peg$c1569(s3);
20258
20317
  s0 = s1;
20259
20318
  }
20260
20319
  else {
@@ -20291,14 +20350,14 @@ function peg$parse(input, options) {
20291
20350
  function peg$parseArrangeStartDeclaration() {
20292
20351
  var s0, s1, s2, s3, s4, s5, s6;
20293
20352
  s0 = peg$currPos;
20294
- if (input.substr(peg$currPos, 13) === peg$c1567) {
20295
- s1 = peg$c1567;
20353
+ if (input.substr(peg$currPos, 13) === peg$c1570) {
20354
+ s1 = peg$c1570;
20296
20355
  peg$currPos += 13;
20297
20356
  }
20298
20357
  else {
20299
20358
  s1 = peg$FAILED;
20300
20359
  if (peg$silentFails === 0 && peg$currPos >= peg$maxFailPos) {
20301
- peg$fail(peg$c1568);
20360
+ peg$fail(peg$c1571);
20302
20361
  }
20303
20362
  }
20304
20363
  if (s1 !== peg$FAILED) {
@@ -20331,7 +20390,7 @@ function peg$parse(input, options) {
20331
20390
  }
20332
20391
  if (s6 !== peg$FAILED) {
20333
20392
  peg$savedPos = s0;
20334
- s1 = peg$c1569(s3);
20393
+ s1 = peg$c1572(s3);
20335
20394
  s0 = s1;
20336
20395
  }
20337
20396
  else {
@@ -20368,14 +20427,14 @@ function peg$parse(input, options) {
20368
20427
  function peg$parseArrangeEndDeclaration() {
20369
20428
  var s0, s1, s2, s3, s4, s5, s6;
20370
20429
  s0 = peg$currPos;
20371
- if (input.substr(peg$currPos, 11) === peg$c1570) {
20372
- s1 = peg$c1570;
20430
+ if (input.substr(peg$currPos, 11) === peg$c1573) {
20431
+ s1 = peg$c1573;
20373
20432
  peg$currPos += 11;
20374
20433
  }
20375
20434
  else {
20376
20435
  s1 = peg$FAILED;
20377
20436
  if (peg$silentFails === 0 && peg$currPos >= peg$maxFailPos) {
20378
- peg$fail(peg$c1571);
20437
+ peg$fail(peg$c1574);
20379
20438
  }
20380
20439
  }
20381
20440
  if (s1 !== peg$FAILED) {
@@ -20408,7 +20467,7 @@ function peg$parse(input, options) {
20408
20467
  }
20409
20468
  if (s6 !== peg$FAILED) {
20410
20469
  peg$savedPos = s0;
20411
- s1 = peg$c1572(s3);
20470
+ s1 = peg$c1575(s3);
20412
20471
  s0 = s1;
20413
20472
  }
20414
20473
  else {
@@ -20446,14 +20505,14 @@ function peg$parse(input, options) {
20446
20505
  var s0, s1, s2, s3, s4, s5, s6;
20447
20506
  peg$silentFails++;
20448
20507
  s0 = peg$currPos;
20449
- if (input.substr(peg$currPos, 8) === peg$c1574) {
20450
- s1 = peg$c1574;
20508
+ if (input.substr(peg$currPos, 8) === peg$c1577) {
20509
+ s1 = peg$c1577;
20451
20510
  peg$currPos += 8;
20452
20511
  }
20453
20512
  else {
20454
20513
  s1 = peg$FAILED;
20455
20514
  if (peg$silentFails === 0 && peg$currPos >= peg$maxFailPos) {
20456
- peg$fail(peg$c1575);
20515
+ peg$fail(peg$c1578);
20457
20516
  }
20458
20517
  }
20459
20518
  if (s1 !== peg$FAILED) {
@@ -20486,7 +20545,7 @@ function peg$parse(input, options) {
20486
20545
  }
20487
20546
  if (s6 !== peg$FAILED) {
20488
20547
  peg$savedPos = s0;
20489
- s1 = peg$c1576(s3);
20548
+ s1 = peg$c1579(s3);
20490
20549
  s0 = s1;
20491
20550
  }
20492
20551
  else {
@@ -20522,7 +20581,7 @@ function peg$parse(input, options) {
20522
20581
  if (s0 === peg$FAILED) {
20523
20582
  s1 = peg$FAILED;
20524
20583
  if (peg$silentFails === 0 && peg$currPos >= peg$maxFailPos) {
20525
- peg$fail(peg$c1573);
20584
+ peg$fail(peg$c1576);
20526
20585
  }
20527
20586
  }
20528
20587
  return s0;
@@ -20531,14 +20590,14 @@ function peg$parse(input, options) {
20531
20590
  var s0, s1, s2, s3, s4, s5, s6;
20532
20591
  peg$silentFails++;
20533
20592
  s0 = peg$currPos;
20534
- if (input.substr(peg$currPos, 8) === peg$c1578) {
20535
- s1 = peg$c1578;
20593
+ if (input.substr(peg$currPos, 8) === peg$c1581) {
20594
+ s1 = peg$c1581;
20536
20595
  peg$currPos += 8;
20537
20596
  }
20538
20597
  else {
20539
20598
  s1 = peg$FAILED;
20540
20599
  if (peg$silentFails === 0 && peg$currPos >= peg$maxFailPos) {
20541
- peg$fail(peg$c1579);
20600
+ peg$fail(peg$c1582);
20542
20601
  }
20543
20602
  }
20544
20603
  if (s1 !== peg$FAILED) {
@@ -20571,7 +20630,7 @@ function peg$parse(input, options) {
20571
20630
  }
20572
20631
  if (s6 !== peg$FAILED) {
20573
20632
  peg$savedPos = s0;
20574
- s1 = peg$c1580(s3);
20633
+ s1 = peg$c1583(s3);
20575
20634
  s0 = s1;
20576
20635
  }
20577
20636
  else {
@@ -20607,7 +20666,7 @@ function peg$parse(input, options) {
20607
20666
  if (s0 === peg$FAILED) {
20608
20667
  s1 = peg$FAILED;
20609
20668
  if (peg$silentFails === 0 && peg$currPos >= peg$maxFailPos) {
20610
- peg$fail(peg$c1577);
20669
+ peg$fail(peg$c1580);
20611
20670
  }
20612
20671
  }
20613
20672
  return s0;
@@ -20631,7 +20690,7 @@ function peg$parse(input, options) {
20631
20690
  peg$silentFails--;
20632
20691
  if (s0 === peg$FAILED) {
20633
20692
  if (peg$silentFails === 0 && peg$currPos >= peg$maxFailPos) {
20634
- peg$fail(peg$c1581);
20693
+ peg$fail(peg$c1584);
20635
20694
  }
20636
20695
  }
20637
20696
  return s0;
@@ -23625,7 +23684,8 @@ var constants = /*#__PURE__*/Object.freeze({
23625
23684
  const HEX8 = /^#[0-9a-f]{8}$/i;
23626
23685
  /** AST keys that hold source locations, not child nodes to recurse into. */
23627
23686
  const LOC_KEYS = new Set(['loc', 'value_loc', 'name_loc', 'from_loc', 'to_loc',
23628
- 'r_action_loc', 'l_action_loc']);
23687
+ 'r_action_loc', 'l_action_loc', 'value_locs',
23688
+ 'subject_loc', '__loc']);
23629
23689
  /** State-declaration item keys whose value is an enum lacking a value-precise loc. */
23630
23690
  const ENUM_VALUE_KEYS = new Set(['shape']);
23631
23691
  /** Locate a value substring inside a node's full-statement `loc` span. The
@@ -23662,6 +23722,31 @@ function collect(node, text, out) {
23662
23722
  if (ENUM_VALUE_KEYS.has(n.key) && typeof n.value === 'string' && n.loc && !n.value_loc) {
23663
23723
  out.push(Object.assign(Object.assign({}, valueSpanWithin(text, n.loc, n.value)), { kind: 'enum' }));
23664
23724
  }
23725
+ // group declarations (`&G : [a b c];` / `&G : a;`): every plain member is a
23726
+ // state reference. The grammar supplies value_locs parallel to value, so
23727
+ // positions come from the parser, never from text search. Nest/spread
23728
+ // entries (`&child` / `...&child`) are group references, not states, and
23729
+ // the group's own NAME is deliberately not a state span either.
23730
+ if (n.key === 'named_list') {
23731
+ const members = Array.isArray(n.value) ? n.value : [n.value];
23732
+ members.forEach((member, i) => {
23733
+ const m = member;
23734
+ const name = typeof m === 'string' ? m
23735
+ : m.kind === 'state' ? m.name
23736
+ : null;
23737
+ if (name !== null) {
23738
+ const at = n.value_locs[i];
23739
+ out.push({ from: at.start.offset, to: at.end.offset, kind: 'state', value: name });
23740
+ }
23741
+ });
23742
+ }
23743
+ // hook declarations (`on enter x do 'act';`): a plain-label subject is a
23744
+ // state reference and carries a grammar-supplied subject_loc. Group-ref
23745
+ // subjects (`on exit &G …`) are group references, not states — no
23746
+ // subject_loc, no span.
23747
+ if (n.key === 'hook_decl' && n.subject_loc) {
23748
+ out.push({ from: n.subject_loc.start.offset, to: n.subject_loc.end.offset, kind: 'state', value: n.subject });
23749
+ }
23665
23750
  for (const key of Object.keys(n)) {
23666
23751
  if (!LOC_KEYS.has(key)) {
23667
23752
  collect(n[key], text, out);
@@ -23669,11 +23754,21 @@ function collect(node, text, out) {
23669
23754
  }
23670
23755
  }
23671
23756
  /**
23672
- * Collect color / state / shape-enum semantic spans from `text`.
23757
+ * Collect color / state / shape-enum semantic spans from `text`. State spans
23758
+ * cover transition endpoints, state-declaration subjects, group-list members
23759
+ * (`&G : [a b c];` — but not the group's own name, nor `&`/`...&` nested
23760
+ * group references), and plain-label hook subjects (`on enter x do 'act';` —
23761
+ * but not `&group` subjects). Every state span's `value` is the parser's
23762
+ * resolved name (unquoted, unescaped), while `from`/`to` cover the source
23763
+ * spelling including any quotes.
23673
23764
  *
23674
23765
  * @example
23675
23766
  * fslSemanticSpans('state s : { color: crimson; };')
23676
23767
  * .find(s => s.kind === 'color')?.value; // => '#dc143cff'
23768
+ *
23769
+ * @example
23770
+ * fslSemanticSpans('&G : [a b];\na -> b;')
23771
+ * .filter(s => s.kind === 'state').length; // => 4 (two members + two endpoints)
23677
23772
  */
23678
23773
  function fslSemanticSpans(text) {
23679
23774
  let tree;
@@ -23694,7 +23789,7 @@ function fslSemanticSpans(text) {
23694
23789
  * Useful for runtime diagnostics and for embedding in serialized machine
23695
23790
  * snapshots so that deserializers can detect version-skew.
23696
23791
  */
23697
- const version = "5.158.2";
23792
+ const version = "5.159.1";
23698
23793
 
23699
23794
  /**
23700
23795
  * The FSL Markdown fence convention parser — pure, host-agnostic logic that
@@ -29379,6 +29474,26 @@ function vc(col) {
29379
29474
  function doublequote(txt) {
29380
29475
  return txt.replace(/"/g, '\\"');
29381
29476
  }
29477
+ /**
29478
+ * Reverse {@link doublequote}: turn DOT's `\"` escape back into the literal
29479
+ * `"` that graphviz renders into SVG `<text>` content. Used by
29480
+ * {@link state_svg_label_texts} to reconstruct a node's on-screen label from
29481
+ * the DOT label it was handed, so the fence renderer keys against exactly what
29482
+ * was drawn.
29483
+ *
29484
+ * ```typescript
29485
+ * undoublequote('a\\"b'); // 'a"b'
29486
+ * undoublequote('safe'); // 'safe'
29487
+ * ```
29488
+ *
29489
+ * @param txt A DOT-escaped attribute string (as produced by `doublequote`).
29490
+ * @returns The string with every `\"` collapsed back to `"`.
29491
+ *
29492
+ * @internal
29493
+ */
29494
+ function undoublequote(txt) {
29495
+ return txt.replace(/\\"/g, '"');
29496
+ }
29382
29497
  /**
29383
29498
  * Convert a state name into a URL-friendly slug suitable for use as the
29384
29499
  * body of a dot/SVG node identifier. The transformation is:
@@ -30262,6 +30377,71 @@ function node_block_for(u_jssm, l_states, state_index, state_kinds, hide_labels,
30262
30377
  const { clusters, ungrouped_nodes } = groups_to_subgraph_string(u_jssm, l_states, state_index, state_kinds, hide_labels);
30263
30378
  return `${clusters}${(clusters && ungrouped_nodes) ? ' ' : ''}${ungrouped_nodes}`;
30264
30379
  }
30380
+ /**
30381
+ * The per-state group-chip map that {@link node_block_for} appends to labels
30382
+ * in a given render mode. Mirrors that function's mode dispatch and calls the
30383
+ * very same chip sources — {@link chips_for_all_groups} for `'chips'`,
30384
+ * {@link plan_cluster_groups} (with identical inputs) for `'cluster'` — so a
30385
+ * reconstructed label can never disagree with the one graphviz was handed.
30386
+ * `'off'`, and any machine that declares no groups, yields an empty map.
30387
+ *
30388
+ * @internal
30389
+ */
30390
+ function chips_for_render_mode(u_jssm, l_states, mode) {
30391
+ if ((mode === 'off') || (u_jssm.groups().length === 0)) {
30392
+ return new Map();
30393
+ }
30394
+ if (mode === 'chips') {
30395
+ return chips_for_all_groups(u_jssm, l_states);
30396
+ }
30397
+ const order = u_jssm.groups();
30398
+ const parents = group_parent_map(u_jssm._group_registry, order);
30399
+ return plan_cluster_groups(u_jssm, l_states, order, parents).chips;
30400
+ }
30401
+ /**
30402
+ * The exact text graphviz places in each state's SVG `<text>` element(s) when
30403
+ * a machine is rendered via {@link machine_to_dot} / {@link fsl_to_svg_string}:
30404
+ * the state's display text plus any group chips the node builder appends, with
30405
+ * DOT's `\"` escaping undone (SVG carries the literal character). A label that
30406
+ * wraps across lines becomes several `<text>` elements; this returns the lines
30407
+ * joined by `\n`, exactly how {@link extract_state_fills} reads them back — so
30408
+ * the derived key and the extracted key meet at the same string.
30409
+ *
30410
+ * This is the single source of truth the static fence renderer keys its
30411
+ * highlight and recolor lookups against, so those lookups can never drift from
30412
+ * what was actually drawn — plain labels, group chips, and multi-line wraps
30413
+ * alike. It is built by running the node builder's own
30414
+ * `label_with_chips(doublequote(display_text), chips)` and inverting the one
30415
+ * escaping step, so it follows any change to the label format for free.
30416
+ *
30417
+ * @param u_jssm The machine being rendered.
30418
+ * @param opts Render flags; only `render_groups` affects the label text
30419
+ * (default `'cluster'`, matching `fsl_to_svg_string`).
30420
+ * @returns A map from each state name to its rendered SVG label text.
30421
+ *
30422
+ * ```typescript
30423
+ * import { sm } from 'jssm';
30424
+ * import { state_svg_label_texts } from 'jssm/viz';
30425
+ *
30426
+ * // a state in two groups renders a chip suffix in its node label
30427
+ * state_svg_label_texts(sm`&g1 : [a b]; &g2 : [a]; a -> b;`).get('a'); // 'a [g1]'
30428
+ * state_svg_label_texts(sm`a -> b;`).get('a'); // 'a'
30429
+ * ```
30430
+ *
30431
+ * @see extract_state_fills
30432
+ */
30433
+ function state_svg_label_texts(u_jssm, opts = {}) {
30434
+ var _a, _b;
30435
+ const l_states = u_jssm.states();
30436
+ const mode = (_a = opts.render_groups) !== null && _a !== void 0 ? _a : 'cluster';
30437
+ const chips = chips_for_render_mode(u_jssm, l_states, mode);
30438
+ const out = new Map();
30439
+ for (const s of l_states) {
30440
+ const dot_label = label_with_chips(doublequote(u_jssm.display_text(s)), (_b = chips.get(s)) !== null && _b !== void 0 ? _b : []);
30441
+ out.set(s, undoublequote(dot_label));
30442
+ }
30443
+ return out;
30444
+ }
30265
30445
  /**
30266
30446
  * Render a {@link jssm.Machine} as a graphviz dot string.
30267
30447
  *
@@ -30378,6 +30558,17 @@ async function fsl_to_svg_string(fsl, opts = {}) {
30378
30558
  return dot_to_svg(fsl_to_dot(fsl, opts), opts);
30379
30559
  }
30380
30560
 
30561
+ /**
30562
+ * The render targets supported in v1, in canonical order (the CLI `--target`
30563
+ * enum and `--help` list order). This tuple is the single runtime source of
30564
+ * truth: both the {@link RenderTarget} type and the `fsl-render` CLI's
30565
+ * `--target` enum derive from it, so a new target is declared in exactly one
30566
+ * place. Future targets (mermaid, plantuml, scxml, ascii, fsl) land here in
30567
+ * v0.2+.
30568
+ *
30569
+ * @example
30570
+ * RENDER_TARGETS.includes('gif' as RenderTarget); // true
30571
+ */
30381
30572
  /**
30382
30573
  * Base error class for render-time failures.
30383
30574
  */
@@ -31235,8 +31426,22 @@ function xml_unescape(s) {
31235
31426
  }
31236
31427
  /** Match one graphviz node group; capture [1] the group body. @internal */
31237
31428
  const NODE_GROUP_RE = /<g[^>]*\bclass="node"[^>]*>([\s\S]*?)<\/g>/g;
31238
- const TEXT_RE = /<text[^>]*>([\s\S]*?)<\/text>/;
31429
+ const TEXT_RE_G = /<text[^>]*>([\s\S]*?)<\/text>/g;
31239
31430
  const SHAPE_FILL_RE = /(<(?:ellipse|polygon|path)\b[^>]*\bfill=")([^"]*)(")/;
31431
+ /**
31432
+ * The state key for one node group: the XML-unescaped content of *every* one
31433
+ * of its `<text>` elements, joined by `\n`. Graphviz splits a label that
31434
+ * wraps across lines into one `<text>` per line, so reading only the first
31435
+ * would key on a truncated string; joining the lines with `\n` reconstructs
31436
+ * the machine's display text exactly (matching `state_svg_label_texts`).
31437
+ * Returns `null` for a node group carrying no `<text>` element at all.
31438
+ *
31439
+ * @internal
31440
+ */
31441
+ function node_label_text(body) {
31442
+ const lines = [...body.matchAll(TEXT_RE_G)].map(m => xml_unescape(m[1]));
31443
+ return lines.length === 0 ? null : lines.join('\n');
31444
+ }
31240
31445
  /**
31241
31446
  * Read each state's current fill color out of a graphviz-rendered machine
31242
31447
  * SVG, keyed by state name. States whose shape carries no `fill` attribute
@@ -31253,13 +31458,10 @@ function extract_state_fills(svg) {
31253
31458
  const out = new Map();
31254
31459
  for (const group of svg.matchAll(NODE_GROUP_RE)) {
31255
31460
  const body = group[1];
31256
- const text = body.match(TEXT_RE);
31461
+ const label = node_label_text(body);
31257
31462
  const shape = body.match(SHAPE_FILL_RE);
31258
- if (shape !== null && text !== null) {
31259
- const state_name = xml_unescape(text[1]);
31260
- if (state_name) {
31261
- out.set(state_name, shape[2]);
31262
- }
31463
+ if (shape !== null && label !== null && label !== '') {
31464
+ out.set(label, shape[2]);
31263
31465
  }
31264
31466
  }
31265
31467
  return out;
@@ -31284,11 +31486,11 @@ function patch_state_fill(svg, state, fill) {
31284
31486
  if (done) {
31285
31487
  return whole;
31286
31488
  }
31287
- const text = body.match(TEXT_RE);
31288
- if (text === null) {
31489
+ const label = node_label_text(body);
31490
+ if (label === null) {
31289
31491
  return whole;
31290
31492
  }
31291
- if (xml_unescape(text[1]) !== state) {
31493
+ if (label !== state) {
31292
31494
  return whole;
31293
31495
  }
31294
31496
  // Function-form replacements: `fill` is caller-supplied and may itself
@@ -48763,7 +48965,8 @@ function quantize(rgba, max_colors = 256) {
48763
48965
  throw new JssmError(undefined, 'quantize: max_colors must be 2..256');
48764
48966
  }
48765
48967
  const pixel_count = rgba.length / 4;
48766
- // composite over white, build histogram of packed rgb keys
48968
+ // composite over white, build histogram of packed rgb keys (packed[] retained
48969
+ // so the per-pixel index step below need not recompute the keys)
48767
48970
  const packed = new Uint32Array(pixel_count);
48768
48971
  const histogram = new Map();
48769
48972
  for (let i = 0; i < pixel_count; ++i) {
@@ -48771,6 +48974,48 @@ function quantize(rgba, max_colors = 256) {
48771
48974
  packed[i] = key;
48772
48975
  histogram.set(key, ((_a = histogram.get(key)) !== null && _a !== void 0 ? _a : 0) + 1);
48773
48976
  }
48977
+ const { palette, palette_count, index_of } = palette_from_histogram(histogram, max_colors);
48978
+ const indices = new Uint8Array(pixel_count);
48979
+ for (let i = 0; i < pixel_count; ++i) {
48980
+ indices[i] = index_of.get(packed[i]);
48981
+ }
48982
+ return { palette, palette_count, indices };
48983
+ }
48984
+ /**
48985
+ * Accumulate one RGBA frame's composited-over-white colors into a shared
48986
+ * packed-rgb histogram, so an animation's union palette can be built by
48987
+ * streaming frame-by-frame instead of concatenating every frame's pixels into
48988
+ * one buffer first. Iterating frames in order reproduces the exact key/count
48989
+ * sequence a concatenated buffer would yield, so the resulting palette is
48990
+ * byte-identical to quantizing the concatenation.
48991
+ *
48992
+ * @param rgba - Straight RGBA bytes; length must be a multiple of 4.
48993
+ * @param histogram - Packed 0xRRGGBB key → count, mutated in place.
48994
+ *
48995
+ * @example
48996
+ * const h = new Map<number, number>();
48997
+ * accumulate_histogram(new Uint8Array([255,0,0,255]), h); // h: { 0xff0000 => 1 }
48998
+ *
48999
+ * @internal
49000
+ */
49001
+ function accumulate_histogram(rgba, histogram) {
49002
+ var _a;
49003
+ const pixel_count = rgba.length / 4;
49004
+ for (let i = 0; i < pixel_count; ++i) {
49005
+ const key = packed_over_white(rgba, i);
49006
+ histogram.set(key, ((_a = histogram.get(key)) !== null && _a !== void 0 ? _a : 0) + 1);
49007
+ }
49008
+ }
49009
+ /**
49010
+ * Derive a color palette from a packed-rgb histogram: when the histogram holds
49011
+ * `max_colors` or fewer distinct colors they are preserved exactly (in
49012
+ * insertion order); otherwise a median-cut partition supplies the palette.
49013
+ * Returned alongside the palette is `index_of`, mapping each source color key
49014
+ * to its palette slot, so callers can translate their own pixels.
49015
+ *
49016
+ * @internal
49017
+ */
49018
+ function palette_from_histogram(histogram, max_colors) {
48774
49019
  const distinct = [...histogram.keys()];
48775
49020
  if (distinct.length <= max_colors) {
48776
49021
  const index_of = new Map();
@@ -48781,13 +49026,9 @@ function quantize(rgba, max_colors = 256) {
48781
49026
  palette[i * 3 + 1] = (key >> 8) & 0xff;
48782
49027
  palette[i * 3 + 2] = key & 0xff;
48783
49028
  });
48784
- const indices = new Uint8Array(pixel_count);
48785
- for (let i = 0; i < pixel_count; ++i) {
48786
- indices[i] = index_of.get(packed[i]);
48787
- }
48788
- return { palette, palette_count: distinct.length, indices };
49029
+ return { palette, palette_count: distinct.length, index_of };
48789
49030
  }
48790
- return median_cut(packed, histogram, max_colors);
49031
+ return median_cut_palette(histogram, max_colors);
48791
49032
  }
48792
49033
  /** Channel extractors for packed 0xRRGGBB keys. @internal */
48793
49034
  const CHANNELS = [
@@ -48796,13 +49037,15 @@ const CHANNELS = [
48796
49037
  key => key & 0xff,
48797
49038
  ];
48798
49039
  /**
48799
- * Median-cut quantization over a pre-built histogram. Splits the box with
48800
- * the widest channel range at its count-weighted median until `max_colors`
48801
- * boxes exist, then averages each box into a palette entry.
49040
+ * Median-cut palette over a pre-built histogram. Splits the box with the
49041
+ * widest channel range at its count-weighted median until `max_colors` boxes
49042
+ * exist, then averages each box into a palette entry. Returns the palette and
49043
+ * the color→slot map only; per-pixel indices are the caller's concern (the
49044
+ * animation encoder maps each frame separately, so it never needs them here).
48802
49045
  *
48803
49046
  * @internal
48804
49047
  */
48805
- function median_cut(packed, histogram, max_colors) {
49048
+ function median_cut_palette(histogram, max_colors) {
48806
49049
  const boxes = [[...histogram.keys()]];
48807
49050
  while (boxes.length < max_colors) {
48808
49051
  // pick the box with the widest single-channel range
@@ -48859,11 +49102,7 @@ function median_cut(packed, histogram, max_colors) {
48859
49102
  palette[bi * 3 + 1] = Math.round(g / n);
48860
49103
  palette[bi * 3 + 2] = Math.round(b / n);
48861
49104
  });
48862
- const indices = new Uint8Array(packed.length);
48863
- for (let i = 0; i < packed.length; ++i) {
48864
- indices[i] = index_of.get(packed[i]);
48865
- }
48866
- return { palette, palette_count: boxes.length, indices };
49105
+ return { palette, palette_count: boxes.length, index_of };
48867
49106
  }
48868
49107
  /**
48869
49108
  * GIF-variant LZW compression: emits a leading clear code, grows code width
@@ -48941,8 +49180,9 @@ function lzw_encode(indices, min_code_size) {
48941
49180
  * @param frames - At least one frame; all with identical width/height and
48942
49181
  * `rgba.length === 4 · width · height`.
48943
49182
  *
48944
- * @throws {JssmError} on zero frames, mismatched dimensions, or an rgba
48945
- * buffer whose length contradicts its stated dimensions.
49183
+ * @throws {JssmError} on zero frames, a zero-width or zero-height frame,
49184
+ * mismatched dimensions, or an rgba buffer whose length contradicts its
49185
+ * stated dimensions.
48946
49186
  *
48947
49187
  * @example
48948
49188
  * const red = { rgba: new Uint8Array([255,0,0,255]), width: 1, height: 1 };
@@ -48955,6 +49195,12 @@ function encode_gif(frames, opts = {}) {
48955
49195
  throw new JssmError(undefined, 'encode_gif: at least one frame is required');
48956
49196
  }
48957
49197
  const { width, height } = frames[0];
49198
+ if (width === 0 || height === 0) {
49199
+ // A 0×0 (or 0×h / w×0) frame passes the `4·w·h === rgba.length` check with
49200
+ // an empty buffer, then reaches lzw_encode where `indices[0]!` coerces
49201
+ // undefined into a bogus code 0 — a silently-corrupt GIF. Fail loudly here.
49202
+ throw new JssmError(undefined, `encode_gif: frame dimensions must be non-zero (got ${width}x${height})`);
49203
+ }
48958
49204
  for (const f of frames) {
48959
49205
  if (f.width !== width || f.height !== height) {
48960
49206
  throw new JssmError(undefined, `encode_gif: frame dimensions differ (${f.width}x${f.height} vs ${width}x${height})`);
@@ -48965,25 +49211,30 @@ function encode_gif(frames, opts = {}) {
48965
49211
  }
48966
49212
  const delay_cs = (_a = opts.delay_cs) !== null && _a !== void 0 ? _a : 70;
48967
49213
  const loop = (_b = opts.loop) !== null && _b !== void 0 ? _b : 0;
48968
- // global palette from all frames combined; when few distinct colors exist, preserve all exactly
48969
- const combined = new Uint8Array(frames.reduce((sum, f) => sum + f.rgba.length, 0));
48970
- let pos = 0;
49214
+ // Global palette over the UNION of every frame, built by streaming each
49215
+ // frame's histogram rather than concatenating all frames into one buffer
49216
+ // first (64 frames × w×h×4 can reach hundreds of MB on a big machine).
49217
+ // Frames are visited in order, so the key/count sequence — and therefore the
49218
+ // palette — is byte-identical to quantizing the concatenation.
49219
+ const union_histogram = new Map();
48971
49220
  for (const f of frames) {
48972
- combined.set(f.rgba, pos);
48973
- pos += f.rgba.length;
49221
+ accumulate_histogram(f.rgba, union_histogram);
48974
49222
  }
48975
- const quantized = quantize(combined, 256);
48976
- const gct_bits = Math.max(1, Math.ceil(Math.log2(Math.max(2, quantized.palette_count))));
49223
+ const { palette, palette_count } = palette_from_histogram(union_histogram, 256);
49224
+ const gct_bits = Math.max(1, Math.ceil(Math.log2(Math.max(2, palette_count))));
48977
49225
  const gct_size = 1 << gct_bits;
48978
49226
  const min_code_size = Math.max(2, gct_bits);
48979
- /** Map a frame's pixels to nearest entries of the union-quantized global palette. @internal */
49227
+ // One nearest-color cache for the whole encode: the global palette is
49228
+ // identical across frames, so a color's best index never changes frame to
49229
+ // frame — rebuilding the cache per frame only re-did the same work.
49230
+ const palette_cache = new Map();
49231
+ /** Map a frame's pixels to nearest entries of the union global palette. @internal */
48980
49232
  const map_to_palette = (rgba) => {
48981
49233
  const n = rgba.length / 4;
48982
49234
  const out = new Uint8Array(n);
48983
- const cache = new Map();
48984
49235
  for (let i = 0; i < n; ++i) {
48985
49236
  const key = packed_over_white(rgba, i);
48986
- const hit = cache.get(key);
49237
+ const hit = palette_cache.get(key);
48987
49238
  if (hit !== undefined) {
48988
49239
  out[i] = hit;
48989
49240
  continue;
@@ -48992,67 +49243,83 @@ function encode_gif(frames, opts = {}) {
48992
49243
  const g = (key >> 8) & 0xff;
48993
49244
  const b = key & 0xff;
48994
49245
  let best = 0, best_d = Infinity;
48995
- for (let p = 0; p < quantized.palette_count; ++p) {
48996
- const dr = r - quantized.palette[p * 3];
48997
- const dg = g - quantized.palette[p * 3 + 1];
48998
- const db = b - quantized.palette[p * 3 + 2];
49246
+ for (let p = 0; p < palette_count; ++p) {
49247
+ const dr = r - palette[p * 3];
49248
+ const dg = g - palette[p * 3 + 1];
49249
+ const db = b - palette[p * 3 + 2];
48999
49250
  const d = dr * dr + dg * dg + db * db;
49000
49251
  if (d < best_d) {
49001
49252
  best_d = d;
49002
49253
  best = p;
49003
49254
  }
49004
49255
  }
49005
- cache.set(key, best);
49256
+ palette_cache.set(key, best);
49006
49257
  out[i] = best;
49007
49258
  }
49008
49259
  return out;
49009
49260
  };
49010
- const bytes = [];
49011
- const push_u16 = (v) => { bytes.push(v & 0xff, (v >> 8) & 0xff); };
49261
+ // Output accumulates into a growable Uint8Array (doubling on demand) rather
49262
+ // than a boxed-integer number[]; the final GIF is `out.subarray(0, len)`.
49263
+ let out = new Uint8Array(1024);
49264
+ let len = 0;
49265
+ const need = (extra) => {
49266
+ if (len + extra > out.length) {
49267
+ const bigger = new Uint8Array(Math.max(out.length * 2, len + extra));
49268
+ bigger.set(out.subarray(0, len));
49269
+ out = bigger;
49270
+ }
49271
+ };
49272
+ const push = (...vals) => {
49273
+ need(vals.length);
49274
+ for (let k = 0; k < vals.length; ++k) {
49275
+ out[len++] = vals[k] & 0xff;
49276
+ }
49277
+ };
49278
+ const push_u16 = (v) => { push(v & 0xff, (v >> 8) & 0xff); };
49012
49279
  // header + logical screen descriptor
49013
- bytes.push(0x47, 0x49, 0x46, 0x38, 0x39, 0x61); // "GIF89a"
49280
+ push(0x47, 0x49, 0x46, 0x38, 0x39, 0x61); // "GIF89a"
49014
49281
  push_u16(width);
49015
49282
  push_u16(height);
49016
- bytes.push(0x80 | 0x70 | (gct_bits - 1)); // GCT present, color res 8-bit, size
49017
- bytes.push(0, 0); // background index, aspect
49283
+ push(0x80 | 0x70 | (gct_bits - 1)); // GCT present, color res 8-bit, size
49284
+ push(0, 0); // background index, aspect
49018
49285
  // global color table, padded to 2^gct_bits entries
49019
49286
  for (let p = 0; p < gct_size; ++p) {
49020
- if (p < quantized.palette_count) {
49021
- bytes.push(quantized.palette[p * 3], quantized.palette[p * 3 + 1], quantized.palette[p * 3 + 2]);
49287
+ if (p < palette_count) {
49288
+ push(palette[p * 3], palette[p * 3 + 1], palette[p * 3 + 2]);
49022
49289
  }
49023
49290
  else {
49024
- bytes.push(0, 0, 0);
49291
+ push(0, 0, 0);
49025
49292
  }
49026
49293
  }
49027
49294
  // Netscape looping extension
49028
- bytes.push(0x21, 0xFF, 0x0B);
49029
- bytes.push(...'NETSCAPE2.0'.split('').map(c => c.charCodeAt(0)));
49030
- bytes.push(0x03, 0x01);
49295
+ push(0x21, 0xFF, 0x0B);
49296
+ push(...'NETSCAPE2.0'.split('').map(c => c.charCodeAt(0)));
49297
+ push(0x03, 0x01);
49031
49298
  push_u16(loop);
49032
- bytes.push(0x00);
49299
+ push(0x00);
49033
49300
  for (let fi = 0; fi < frames.length; ++fi) {
49034
49301
  // graphics control extension: disposal 1 (leave in place), no transparency
49035
- bytes.push(0x21, 0xF9, 0x04, 0x04);
49302
+ push(0x21, 0xF9, 0x04, 0x04);
49036
49303
  push_u16(delay_cs);
49037
- bytes.push(0x00, 0x00);
49304
+ push(0x00, 0x00);
49038
49305
  // image descriptor: full frame, no local color table
49039
- bytes.push(0x2C);
49306
+ push(0x2C);
49040
49307
  push_u16(0);
49041
49308
  push_u16(0);
49042
49309
  push_u16(width);
49043
49310
  push_u16(height);
49044
- bytes.push(0x00);
49311
+ push(0x00);
49045
49312
  const indices = map_to_palette(frames[fi].rgba);
49046
- const packed = lzw_encode(indices, min_code_size);
49047
- bytes.push(min_code_size);
49048
- for (let at = 0; at < packed.length; at += 255) {
49049
- const chunk = packed.slice(at, at + 255);
49050
- bytes.push(chunk.length, ...chunk);
49313
+ const packed_lzw = lzw_encode(indices, min_code_size);
49314
+ push(min_code_size);
49315
+ for (let at = 0; at < packed_lzw.length; at += 255) {
49316
+ const chunk = packed_lzw.slice(at, at + 255);
49317
+ push(chunk.length, ...chunk);
49051
49318
  }
49052
- bytes.push(0x00); // block terminator
49319
+ push(0x00); // block terminator
49053
49320
  }
49054
- bytes.push(0x3B); // trailer
49055
- return new Uint8Array(bytes);
49321
+ push(0x3B); // trailer
49322
+ return out.slice(0, len);
49056
49323
  }
49057
49324
 
49058
49325
  /**
@@ -49083,32 +49350,33 @@ function error_box(source, message) {
49083
49350
  /** Note comment, invisible but inspectable. @internal */
49084
49351
  const note_comment = (note) => `<!-- fsl-fence: ${escape_html(note)} -->`;
49085
49352
  /**
49086
- * Remap a display-text-keyed fill map (as produced by
49087
- * {@link extract_state_fills} from a rendered SVG) to be keyed by state
49088
- * NAME instead. Graphviz nodes are labeled with each state's display text
49089
- * (`label ?? name` the same derivation `jssm_viz.ts`'s `state_node_line`
49090
- * uses via `machine.display_text(s)`), but `highlight_fsl_html`'s
49091
- * `state_colors` option is keyed by the state's own name (the code
49092
- * highlighter's semantic spans carry names, not labels). Without this
49093
- * remap, any labeled state's diagram color silently fails to reach its
49094
- * code span.
49095
- *
49096
- * Handles the simple one-label-per-state case only; group-chip-suffixed
49097
- * labels (`label_with_chips` in jssm_viz.ts) render extra text after the
49098
- * label that this remap does not account for — filed as a follow-up.
49099
- *
49100
- * @param machine - The constructed machine the fills were rendered from.
49101
- * @param fills - Display-text-keyed fills, from `extract_state_fills`.
49353
+ * Remap an SVG-label-keyed fill map (as produced by
49354
+ * {@link extract_state_fills} from a rendered SVG) to be keyed by state NAME
49355
+ * instead. Graphviz labels each node with its full rendered label text
49356
+ * display text, plus any group chips, plus any multi-line wrap — while
49357
+ * `highlight_fsl_html`'s `state_colors` option is keyed by the state's own
49358
+ * name (the code highlighter's semantic spans carry names, not labels).
49359
+ * Without this remap, any state whose label diverges from its name silently
49360
+ * fails to carry its diagram color to its code span.
49361
+ *
49362
+ * Both sides of the join derive the SVG label text from the same source:
49363
+ * `label_texts` comes from {@link state_svg_label_texts} (the viz's own label
49364
+ * builder) and `fills`'s keys are read straight off the SVG, so group chips
49365
+ * and multi-line labels are handled without either side drifting.
49366
+ *
49367
+ * @param label_texts - State name its rendered SVG label text, from
49368
+ * `state_svg_label_texts`.
49369
+ * @param fills - SVG-label-keyed fills, from `extract_state_fills`.
49102
49370
  * @returns Fills re-keyed by state name; states with no matching fill are omitted.
49103
49371
  *
49104
49372
  * @internal
49105
49373
  */
49106
- function state_colors_by_name(machine, fills) {
49374
+ function state_colors_by_name(label_texts, fills) {
49107
49375
  const out = new Map();
49108
- for (const s of machine.states()) {
49109
- const fill = fills.get(machine.display_text(s));
49376
+ for (const [state, label] of label_texts) {
49377
+ const fill = fills.get(label);
49110
49378
  if (fill !== undefined) {
49111
- out.set(s, fill);
49379
+ out.set(state, fill);
49112
49380
  }
49113
49381
  }
49114
49382
  return out;
@@ -49151,7 +49419,7 @@ async function render_fence_html(source, info, opts = {}) {
49151
49419
  }
49152
49420
  const svg = await fsl_to_svg_string(source);
49153
49421
  const fills = extract_state_fills(svg);
49154
- const state_colors = state_colors_by_name(machine, fills);
49422
+ const state_colors = state_colors_by_name(state_svg_label_texts(machine), fills);
49155
49423
  const chunks = desc.notes.map(note_comment);
49156
49424
  for (const part of desc.parts) {
49157
49425
  if (INTERACTIVE_PARTS.has(part)) {
@@ -49286,14 +49554,15 @@ async function render_fence_gif(source, opts = {}) {
49286
49554
  const base_svg = await fsl_to_svg_string(source);
49287
49555
  const highlight = (_b = opts.highlight_fill) !== null && _b !== void 0 ? _b : '#ff9930';
49288
49556
  const scale = (_c = opts.scale) !== null && _c !== void 0 ? _c : 100;
49557
+ const label_texts = state_svg_label_texts(machine);
49289
49558
  const frames = [];
49290
49559
  for (const state of walk) {
49291
- // base_svg's nodes are labeled with display text (label ?? name; the
49292
- // same `machine.display_text(s)` derivation jssm_viz.ts's
49293
- // state_node_line uses), not the walk's state NAME — patch by that or
49294
- // a labeled state's frame silently no-ops (see state_colors_by_name for
49295
- // the render_fence_html analog of this same fix).
49296
- const patched = patch_state_fill(base_svg, machine.display_text(state), highlight);
49560
+ // base_svg's nodes are labeled with their full SVG label text (display
49561
+ // text + any group chips + any multi-line wrap), not the walk's state
49562
+ // NAME — patch by the shared derivation or a labeled/chipped/wrapped
49563
+ // state's frame silently no-ops. `walk` is drawn from the machine's own
49564
+ // states, so every entry has a label_texts key.
49565
+ const patched = patch_state_fill(base_svg, label_texts.get(state), highlight);
49297
49566
  const raster = await rasterizeRgba(patched, { scale });
49298
49567
  frames.push({ rgba: raster.rgba, width: raster.width, height: raster.height });
49299
49568
  }