@emeryld/rrroutes-export 1.0.14 → 1.0.15

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@emeryld/rrroutes-export",
3
3
  "description": "Finalized leaves export helpers and CLI for RRRoutes",
4
- "version": "1.0.14",
4
+ "version": "1.0.15",
5
5
  "private": false,
6
6
  "type": "module",
7
7
  "main": "dist/index.cjs",
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <title>Finalized Leaves Viewer</title>
6
+ <title>RRRoutes Export Viewer</title>
7
7
  <style>
8
8
  :root {
9
9
  --bg: #212121;
@@ -472,7 +472,7 @@
472
472
  </head>
473
473
  <body>
474
474
  <div class="wrap">
475
- <h1>Finalized Leaves Viewer</h1>
475
+ <h1>RRRoutes Export Viewer</h1>
476
476
  <div class="card controls">
477
477
  <div class="primary-row">
478
478
  <label class="control-block">
@@ -536,8 +536,8 @@
536
536
  <button id="tabLeaves" class="field-chip" type="button" aria-pressed="true">
537
537
  Leaves
538
538
  </button>
539
- <button id="tabChangelogRoute" class="field-chip" type="button" aria-pressed="false">
540
- Changelog / By Route
539
+ <button id="tabChangelog" class="field-chip" type="button" aria-pressed="false">
540
+ Changelog
541
541
  </button>
542
542
  <button id="tabChangelogSource" class="field-chip" type="button" aria-pressed="false">
543
543
  Changelog / By Source
@@ -551,7 +551,7 @@
551
551
  <div id="activeFilterChips" class="chips filters"></div>
552
552
  </div>
553
553
 
554
- <div id="status" class="meta">Load a JSON export to begin.</div>
554
+ <div id="status" class="meta">Load a leaves export, changelog export, or unified bundle JSON to begin.</div>
555
555
  </div>
556
556
 
557
557
  <div id="results"></div>
@@ -629,36 +629,52 @@
629
629
  },
630
630
  ]
631
631
 
632
- const CHANGELOG_ROUTE_FIELDS = [
632
+ const CHANGELOG_TIMELINE_FIELDS = [
633
+ {
634
+ id: 'eventKind',
635
+ label: 'kind',
636
+ get: (item) => [item.eventKind],
637
+ },
638
+ {
639
+ id: 'eventType',
640
+ label: 'event',
641
+ get: (item) => [item.event.type],
642
+ },
633
643
  {
634
644
  id: 'routeKey',
635
645
  label: 'route',
636
646
  get: (item) => [item.routeKey],
637
647
  },
638
648
  {
639
- id: 'eventType',
640
- label: 'event type',
641
- get: (item) => item.events.map((event) => event.type),
649
+ id: 'sourceObject',
650
+ label: 'source object',
651
+ get: (item) => [item.sourceObjectId, item.displayName],
652
+ },
653
+ {
654
+ id: 'commit',
655
+ label: 'commit',
656
+ get: (item) => [
657
+ item.event.commitSha,
658
+ item.commit?.authorDate,
659
+ item.commit?.authorName,
660
+ item.commit?.subject,
661
+ ],
642
662
  },
643
663
  {
644
664
  id: 'schemaDiff',
645
665
  label: 'schema diff',
646
666
  get: (item) =>
647
- item.events.flatMap((event) =>
648
- Array.isArray(event.schemaDiff)
649
- ? event.schemaDiff.map((delta) => JSON.stringify(delta))
650
- : [],
651
- ),
667
+ Array.isArray(item.event.schemaDiff)
668
+ ? item.event.schemaDiff.map((delta) => JSON.stringify(delta))
669
+ : [],
652
670
  },
653
671
  {
654
672
  id: 'cfgDiff',
655
673
  label: 'cfg diff',
656
674
  get: (item) =>
657
- item.events.flatMap((event) =>
658
- Array.isArray(event.cfgDiff)
659
- ? event.cfgDiff.map((delta) => JSON.stringify(delta))
660
- : [],
661
- ),
675
+ Array.isArray(item.event.cfgDiff)
676
+ ? item.event.cfgDiff.map((delta) => JSON.stringify(delta))
677
+ : [],
662
678
  },
663
679
  ]
664
680
 
@@ -726,7 +742,7 @@
726
742
 
727
743
  const VIEW_IDS = {
728
744
  leaves: 'leaves',
729
- changelogRoute: 'changelogRoute',
745
+ changelog: 'changelog',
730
746
  changelogSource: 'changelogSource',
731
747
  }
732
748
 
@@ -735,9 +751,9 @@
735
751
  fieldDefs: SEARCH_FIELDS,
736
752
  defaultSelected: new Set(SEARCH_FIELDS.map((field) => field.id)),
737
753
  },
738
- [VIEW_IDS.changelogRoute]: {
739
- fieldDefs: CHANGELOG_ROUTE_FIELDS,
740
- defaultSelected: new Set(CHANGELOG_ROUTE_FIELDS.map((field) => field.id)),
754
+ [VIEW_IDS.changelog]: {
755
+ fieldDefs: CHANGELOG_TIMELINE_FIELDS,
756
+ defaultSelected: new Set(CHANGELOG_TIMELINE_FIELDS.map((field) => field.id)),
741
757
  },
742
758
  [VIEW_IDS.changelogSource]: {
743
759
  fieldDefs: CHANGELOG_SOURCE_FIELDS,
@@ -754,7 +770,7 @@
754
770
  availableTabs: new Set([VIEW_IDS.leaves]),
755
771
  selectedFieldIdsByTab: {
756
772
  [VIEW_IDS.leaves]: new Set(TAB_CONFIG[VIEW_IDS.leaves].defaultSelected),
757
- [VIEW_IDS.changelogRoute]: new Set(TAB_CONFIG[VIEW_IDS.changelogRoute].defaultSelected),
773
+ [VIEW_IDS.changelog]: new Set(TAB_CONFIG[VIEW_IDS.changelog].defaultSelected),
758
774
  [VIEW_IDS.changelogSource]: new Set(TAB_CONFIG[VIEW_IDS.changelogSource].defaultSelected),
759
775
  },
760
776
  }
@@ -777,7 +793,7 @@
777
793
  const resultsEl = document.getElementById('results')
778
794
  const controlsEl = document.querySelector('.controls')
779
795
  const tabLeavesBtn = document.getElementById('tabLeaves')
780
- const tabChangelogRouteBtn = document.getElementById('tabChangelogRoute')
796
+ const tabChangelogBtn = document.getElementById('tabChangelog')
781
797
  const tabChangelogSourceBtn = document.getElementById('tabChangelogSource')
782
798
 
783
799
  const URL_PARAM_KEY = 'filters'
@@ -1414,6 +1430,29 @@
1414
1430
  content.appendChild(separatedSchemas)
1415
1431
  }
1416
1432
 
1433
+ const routeHistory = state.changelogPayload?.byRoute?.[leaf.key]
1434
+ if (Array.isArray(routeHistory) && routeHistory.length > 0) {
1435
+ const commitBySha = new Map(
1436
+ (state.changelogPayload?.commits || []).map((commit) => [commit.sha, commit]),
1437
+ )
1438
+ const routeChangelogSection = el('div', 'section')
1439
+ const routeChangelogDetails = el('details')
1440
+ const routeChangelogSummary = el(
1441
+ 'summary',
1442
+ '',
1443
+ `Route Changelog (${routeHistory.length} event${routeHistory.length === 1 ? '' : 's'})`,
1444
+ )
1445
+ routeChangelogDetails.appendChild(routeChangelogSummary)
1446
+
1447
+ const routeChangelogBody = el('div', 'leaf-content')
1448
+ routeHistory.forEach((event) => {
1449
+ routeChangelogBody.appendChild(renderEventCard(event, commitBySha))
1450
+ })
1451
+ routeChangelogDetails.appendChild(routeChangelogBody)
1452
+ routeChangelogSection.appendChild(routeChangelogDetails)
1453
+ content.appendChild(routeChangelogSection)
1454
+ }
1455
+
1417
1456
  details.appendChild(content)
1418
1457
  return details
1419
1458
  }
@@ -1520,13 +1559,53 @@
1520
1559
  return card
1521
1560
  }
1522
1561
 
1562
+ function buildChronologicalEvents(payload) {
1563
+ if (!payload) return []
1564
+ const commitBySha = new Map((payload.commits || []).map((commit) => [commit.sha, commit]))
1565
+ const commitOrder = new Map((payload.commits || []).map((commit, index) => [commit.sha, index]))
1566
+ const rows = []
1567
+ let sequence = 0
1568
+
1569
+ Object.entries(payload.byRoute || {}).forEach(([routeKey, events]) => {
1570
+ ;(events || []).forEach((event) => {
1571
+ rows.push({
1572
+ eventKind: 'route',
1573
+ routeKey,
1574
+ event,
1575
+ commit: commitBySha.get(event.commitSha),
1576
+ commitIndex: commitOrder.get(event.commitSha) ?? Number.MAX_SAFE_INTEGER,
1577
+ eventIndex: sequence++,
1578
+ })
1579
+ })
1580
+ })
1581
+
1582
+ Object.entries(payload.bySourceObject || {}).forEach(([sourceObjectId, events]) => {
1583
+ ;(events || []).forEach((event) => {
1584
+ rows.push({
1585
+ eventKind: 'source',
1586
+ sourceObjectId,
1587
+ displayName: event.displayName || sourceObjectId,
1588
+ event,
1589
+ commit: commitBySha.get(event.commitSha),
1590
+ commitIndex: commitOrder.get(event.commitSha) ?? Number.MAX_SAFE_INTEGER,
1591
+ eventIndex: sequence++,
1592
+ })
1593
+ })
1594
+ })
1595
+
1596
+ rows.sort((a, b) => {
1597
+ if (a.commitIndex !== b.commitIndex) return a.commitIndex - b.commitIndex
1598
+ return a.eventIndex - b.eventIndex
1599
+ })
1600
+
1601
+ return rows
1602
+ }
1603
+
1523
1604
  function changelogItemsByTab(tabId) {
1524
1605
  const payload = state.changelogPayload
1525
1606
  if (!payload) return []
1526
- if (tabId === VIEW_IDS.changelogRoute) {
1527
- return Object.entries(payload.byRoute || {})
1528
- .sort(([a], [b]) => a.localeCompare(b))
1529
- .map(([routeKey, events]) => ({ routeKey, events }))
1607
+ if (tabId === VIEW_IDS.changelog) {
1608
+ return buildChronologicalEvents(payload)
1530
1609
  }
1531
1610
  if (tabId === VIEW_IDS.changelogSource) {
1532
1611
  return Object.entries(payload.bySourceObject || {})
@@ -1561,10 +1640,10 @@
1561
1640
 
1562
1641
  function renderTabButtons() {
1563
1642
  setPressed(tabLeavesBtn, state.activeTab === VIEW_IDS.leaves)
1564
- setPressed(tabChangelogRouteBtn, state.activeTab === VIEW_IDS.changelogRoute)
1643
+ setPressed(tabChangelogBtn, state.activeTab === VIEW_IDS.changelog)
1565
1644
  setPressed(tabChangelogSourceBtn, state.activeTab === VIEW_IDS.changelogSource)
1566
1645
  tabLeavesBtn.style.display = state.availableTabs.has(VIEW_IDS.leaves) ? '' : 'none'
1567
- tabChangelogRouteBtn.style.display = state.availableTabs.has(VIEW_IDS.changelogRoute) ? '' : 'none'
1646
+ tabChangelogBtn.style.display = state.availableTabs.has(VIEW_IDS.changelog) ? '' : 'none'
1568
1647
  tabChangelogSourceBtn.style.display = state.availableTabs.has(VIEW_IDS.changelogSource) ? '' : 'none'
1569
1648
  const isLeavesTab = state.activeTab === VIEW_IDS.leaves
1570
1649
  coreFieldsBtn.style.display = isLeavesTab ? '' : 'none'
@@ -1602,8 +1681,8 @@
1602
1681
  const items = changelogItemsByTab(state.activeTab)
1603
1682
  const filtered = items.filter((item) => matchesGenericItem(item, fieldDefs, engine, selectedIds))
1604
1683
  statusEl.textContent =
1605
- state.activeTab === VIEW_IDS.changelogRoute
1606
- ? `${filtered.length} / ${items.length} route changelog groups matched.`
1684
+ state.activeTab === VIEW_IDS.changelog
1685
+ ? `${filtered.length} / ${items.length} changelog events matched.`
1607
1686
  : `${filtered.length} / ${items.length} source changelog groups matched.`
1608
1687
  const commitBySha = new Map(
1609
1688
  (state.changelogPayload?.commits || []).map((commit) => [commit.sha, commit]),
@@ -1613,11 +1692,15 @@
1613
1692
  (item) => {
1614
1693
  const details = el('details', 'leaf')
1615
1694
  const title =
1616
- state.activeTab === VIEW_IDS.changelogRoute
1617
- ? `${item.routeKey} (${item.events.length})`
1695
+ state.activeTab === VIEW_IDS.changelog
1696
+ ? `${item.eventKind === 'route' ? `Route: ${item.routeKey}` : `Source: ${item.displayName || item.sourceObjectId}`} (${item.event.type})`
1618
1697
  : `${item.displayName} (${item.events.length})`
1619
1698
  details.appendChild(el('summary', '', title))
1620
- item.events.forEach((event) => details.appendChild(renderEventCard(event, commitBySha)))
1699
+ if (state.activeTab === VIEW_IDS.changelog) {
1700
+ details.appendChild(renderEventCard(item.event, commitBySha))
1701
+ } else {
1702
+ item.events.forEach((event) => details.appendChild(renderEventCard(event, commitBySha)))
1703
+ }
1621
1704
  return details
1622
1705
  },
1623
1706
  'No matches.',
@@ -1643,7 +1726,7 @@
1643
1726
  : [
1644
1727
  {
1645
1728
  id: 'tabFields',
1646
- label: state.activeTab === VIEW_IDS.changelogRoute ? 'Route fields' : 'Source fields',
1729
+ label: state.activeTab === VIEW_IDS.changelog ? 'Changelog fields' : 'Source fields',
1647
1730
  fieldIds: fieldDefs.map((field) => field.id),
1648
1731
  },
1649
1732
  ]
@@ -1812,11 +1895,14 @@
1812
1895
  isHydratingFromUrl = true
1813
1896
  if (
1814
1897
  parsed.activeTab === VIEW_IDS.leaves ||
1815
- parsed.activeTab === VIEW_IDS.changelogRoute ||
1898
+ parsed.activeTab === VIEW_IDS.changelog ||
1816
1899
  parsed.activeTab === VIEW_IDS.changelogSource
1817
1900
  ) {
1818
1901
  state.activeTab = parsed.activeTab
1819
1902
  }
1903
+ if (parsed.activeTab === 'changelogRoute') {
1904
+ state.activeTab = VIEW_IDS.changelog
1905
+ }
1820
1906
  if (typeof parsed.search === 'string') searchInput.value = parsed.search
1821
1907
  setPressed(caseSensitiveToggle, Boolean(parsed.caseSensitive))
1822
1908
  setPressed(regexSearchToggle, Boolean(parsed.regex))
@@ -1883,15 +1969,15 @@
1883
1969
  state.leaves = state.leavesPayload.leaves || []
1884
1970
  }
1885
1971
  if (state.changelogPayload) {
1886
- state.availableTabs.add(VIEW_IDS.changelogRoute)
1972
+ state.availableTabs.add(VIEW_IDS.changelog)
1887
1973
  state.availableTabs.add(VIEW_IDS.changelogSource)
1888
1974
  }
1889
1975
 
1890
1976
  if (!state.availableTabs.has(state.activeTab)) {
1891
1977
  state.activeTab = state.availableTabs.has(VIEW_IDS.leaves)
1892
1978
  ? VIEW_IDS.leaves
1893
- : state.availableTabs.has(VIEW_IDS.changelogRoute)
1894
- ? VIEW_IDS.changelogRoute
1979
+ : state.availableTabs.has(VIEW_IDS.changelog)
1980
+ ? VIEW_IDS.changelog
1895
1981
  : VIEW_IDS.changelogSource
1896
1982
  }
1897
1983
 
@@ -1951,7 +2037,7 @@
1951
2037
  })
1952
2038
 
1953
2039
  tabLeavesBtn.addEventListener('click', () => setActiveTab(VIEW_IDS.leaves))
1954
- tabChangelogRouteBtn.addEventListener('click', () => setActiveTab(VIEW_IDS.changelogRoute))
2040
+ tabChangelogBtn.addEventListener('click', () => setActiveTab(VIEW_IDS.changelog))
1955
2041
  tabChangelogSourceBtn.addEventListener('click', () => setActiveTab(VIEW_IDS.changelogSource))
1956
2042
 
1957
2043
  selectAllFieldsBtn.addEventListener('click', () =>