@emeryld/rrroutes-export 1.0.20 → 1.0.21

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.20",
4
+ "version": "1.0.21",
5
5
  "private": false,
6
6
  "type": "module",
7
7
  "main": "dist/index.cjs",
@@ -378,6 +378,22 @@
378
378
  gap: 4px;
379
379
  }
380
380
 
381
+ .changelog-commit-separator {
382
+ margin-top: 12px;
383
+ padding-top: 10px;
384
+ border-top: 1px solid var(--accent);
385
+ }
386
+
387
+ .changelog-commit-separator:first-child {
388
+ margin-top: 0;
389
+ }
390
+
391
+ .changelog-commit-label {
392
+ color: var(--accent);
393
+ font-weight: 700;
394
+ font-size: 12px;
395
+ }
396
+
381
397
  .changelog-diff-line {
382
398
  display: flex;
383
399
  flex-wrap: wrap;
@@ -1758,21 +1774,96 @@
1758
1774
  return `${type}${schemaFlags(Boolean(entry.nullable), Boolean(entry.optional))}`
1759
1775
  }
1760
1776
 
1777
+ function splitTypeOptions(type) {
1778
+ if (typeof type !== 'string' || !type.includes('|')) return []
1779
+ return type
1780
+ .split('|')
1781
+ .map((item) => item.trim())
1782
+ .filter(Boolean)
1783
+ }
1784
+
1785
+ function hasDefinedLiteral(entry) {
1786
+ return (
1787
+ entry &&
1788
+ typeof entry === 'object' &&
1789
+ Object.prototype.hasOwnProperty.call(entry, 'literal') &&
1790
+ entry.literal !== undefined
1791
+ )
1792
+ }
1793
+
1794
+ function reduceEnumTypeDiff(beforeEntry, afterEntry) {
1795
+ if (!beforeEntry || !afterEntry) return null
1796
+ if (hasDefinedLiteral(beforeEntry) || hasDefinedLiteral(afterEntry)) {
1797
+ return null
1798
+ }
1799
+
1800
+ const beforeOptions = splitTypeOptions(beforeEntry.type)
1801
+ const afterOptions = splitTypeOptions(afterEntry.type)
1802
+ if (beforeOptions.length === 0 || afterOptions.length === 0) return null
1803
+
1804
+ const afterSet = new Set(afterOptions)
1805
+ const beforeSet = new Set(beforeOptions)
1806
+ const beforeOnly = beforeOptions.filter((option) => !afterSet.has(option))
1807
+ const afterOnly = afterOptions.filter((option) => !beforeSet.has(option))
1808
+ if (beforeOnly.length === 0 && afterOnly.length === 0) return null
1809
+
1810
+ const beforeType = `${beforeOnly.join('|') || 'none'}${schemaFlags(
1811
+ Boolean(beforeEntry.nullable),
1812
+ Boolean(beforeEntry.optional),
1813
+ )}`
1814
+ const afterType = `${afterOnly.join('|') || 'none'}${schemaFlags(
1815
+ Boolean(afterEntry.nullable),
1816
+ Boolean(afterEntry.optional),
1817
+ )}`
1818
+ return { beforeType, afterType }
1819
+ }
1820
+
1761
1821
  function formatPathLabel(path) {
1762
1822
  const basePath = typeof path === 'string' ? path : ''
1763
1823
  return basePath
1764
1824
  }
1765
1825
 
1766
- function parseSignatureTypeLabel(signature) {
1826
+ function parseSignatureEntry(signature) {
1767
1827
  if (typeof signature !== 'string') return null
1768
1828
  const typeMatch = signature.match(/(?:^|,\s*)type=([^,]+)/)
1769
- const nullableMatch = signature.match(/(?:^|,\s*)nullable=(true|false)/)
1770
- const optionalMatch = signature.match(/(?:^|,\s*)optional=(true|false)/)
1771
- if (!typeMatch) return null
1772
- const type = typeMatch[1]
1773
- const nullable = nullableMatch?.[1] === 'true'
1774
- const optional = optionalMatch?.[1] === 'true'
1775
- return `${type}${schemaFlags(nullable, optional)}`
1829
+ if (typeMatch) {
1830
+ const nullableMatch = signature.match(
1831
+ /(?:^|,\s*)nullable=(true|false)/,
1832
+ )
1833
+ const optionalMatch = signature.match(
1834
+ /(?:^|,\s*)optional=(true|false)/,
1835
+ )
1836
+ return {
1837
+ type: typeMatch[1],
1838
+ nullable: nullableMatch?.[1] === 'true',
1839
+ optional: optionalMatch?.[1] === 'true',
1840
+ literal: undefined,
1841
+ }
1842
+ }
1843
+ try {
1844
+ const parsed = JSON.parse(signature)
1845
+ if (!parsed || typeof parsed !== 'object') return null
1846
+ if (typeof parsed.type !== 'string') return null
1847
+ return {
1848
+ type: parsed.type,
1849
+ nullable: Boolean(parsed.nullable),
1850
+ optional: Boolean(parsed.optional),
1851
+ literal: Object.prototype.hasOwnProperty.call(parsed, 'literal')
1852
+ ? parsed.literal
1853
+ : undefined,
1854
+ }
1855
+ } catch {
1856
+ return null
1857
+ }
1858
+ }
1859
+
1860
+ function parseSignatureTypeLabel(signature) {
1861
+ const entry = parseSignatureEntry(signature)
1862
+ if (!entry) return null
1863
+ return `${entry.type}${schemaFlags(
1864
+ Boolean(entry.nullable),
1865
+ Boolean(entry.optional),
1866
+ )}`
1776
1867
  }
1777
1868
 
1778
1869
  function formatSourceTypeLabel(signatures) {
@@ -1784,6 +1875,18 @@
1784
1875
  return labels.join(' | ')
1785
1876
  }
1786
1877
 
1878
+ function formatSourceChangedTypes(beforeSignatures, afterSignatures) {
1879
+ if (!Array.isArray(beforeSignatures) || !Array.isArray(afterSignatures)) {
1880
+ return null
1881
+ }
1882
+ if (beforeSignatures.length !== 1 || afterSignatures.length !== 1) {
1883
+ return null
1884
+ }
1885
+ const beforeEntry = parseSignatureEntry(beforeSignatures[0])
1886
+ const afterEntry = parseSignatureEntry(afterSignatures[0])
1887
+ return reduceEnumTypeDiff(beforeEntry, afterEntry)
1888
+ }
1889
+
1787
1890
  function schemaDiffOperation(op) {
1788
1891
  if (op === 'added') {
1789
1892
  return { symbol: '+', word: 'added', className: 'added' }
@@ -1839,8 +1942,9 @@
1839
1942
  `removed ${location}: ${JSON.stringify(delta.before || [])}`,
1840
1943
  )
1841
1944
  }
1842
- const beforeType = formatSourceTypeLabel(delta.before)
1843
- const afterType = formatSourceTypeLabel(delta.after)
1945
+ const reducedTypes = formatSourceChangedTypes(delta.before, delta.after)
1946
+ const beforeType = reducedTypes?.beforeType || formatSourceTypeLabel(delta.before)
1947
+ const afterType = reducedTypes?.afterType || formatSourceTypeLabel(delta.after)
1844
1948
  if (beforeType || afterType) {
1845
1949
  return buildSchemaDiffLine(
1846
1950
  delta.op,
@@ -1871,8 +1975,11 @@
1871
1975
  `removed ${delta.path}: ${formatRouteSchemaEntry(delta.before)}`,
1872
1976
  )
1873
1977
  }
1874
- const beforeType = formatEntryTypeLabel(delta.before) || 'unknown'
1875
- const afterType = formatEntryTypeLabel(delta.after) || 'unknown'
1978
+ const reducedTypes = reduceEnumTypeDiff(delta.before, delta.after)
1979
+ const beforeType =
1980
+ reducedTypes?.beforeType || formatEntryTypeLabel(delta.before) || 'unknown'
1981
+ const afterType =
1982
+ reducedTypes?.afterType || formatEntryTypeLabel(delta.after) || 'unknown'
1876
1983
  const pathLabel =
1877
1984
  formatPathLabel(delta.path) || delta.path
1878
1985
  return buildSchemaDiffLine(delta.op, beforeType, pathLabel, afterType)
@@ -1899,10 +2006,14 @@
1899
2006
  function eventVisualByType(type) {
1900
2007
  switch (type) {
1901
2008
  case 'route_added':
1902
- return { actionText: 'added', actionClass: 'event-action-added', icon: 'route' }
2009
+ return {
2010
+ actionText: 'added route',
2011
+ actionClass: 'event-action-added',
2012
+ icon: 'route',
2013
+ }
1903
2014
  case 'route_removed':
1904
2015
  return {
1905
- actionText: 'removed',
2016
+ actionText: 'removed route',
1906
2017
  actionClass: 'event-action-removed',
1907
2018
  icon: 'route',
1908
2019
  }
@@ -1919,18 +2030,22 @@
1919
2030
  icon: 'config',
1920
2031
  }
1921
2032
  case 'source_object_added':
1922
- return { actionText: 'added', actionClass: 'event-action-added', icon: 'source' }
2033
+ return {
2034
+ actionText: 'added source object',
2035
+ actionClass: 'event-action-added',
2036
+ icon: 'source',
2037
+ }
1923
2038
  case 'source_object_removed':
1924
2039
  return {
1925
- actionText: 'removed',
2040
+ actionText: 'removed source object',
1926
2041
  actionClass: 'event-action-removed',
1927
2042
  icon: 'source',
1928
2043
  }
1929
2044
  case 'source_schema_changed':
1930
2045
  return {
1931
- actionText: 'modified source object',
2046
+ actionText: 'modified schema',
1932
2047
  actionClass: 'event-action-modified',
1933
- icon: 'source',
2048
+ icon: 'schema',
1934
2049
  }
1935
2050
  default:
1936
2051
  return {
@@ -2038,6 +2153,34 @@
2038
2153
  .join(' - ')
2039
2154
  }
2040
2155
 
2156
+ function renderCommitSeparator(commitSha, commitBySha) {
2157
+ const box = el('div', 'changelog-commit-separator')
2158
+ const commit = commitBySha.get(commitSha)
2159
+ const commitDateTime = formatCommitDateTime(commit?.authorDate)
2160
+ const label = `commit ${String(commitSha || '').slice(0, 12)}`
2161
+ const meta = [commitDateTime, commit?.authorName || null, commit?.subject || null]
2162
+ .filter(Boolean)
2163
+ .join(' - ')
2164
+ box.appendChild(el('div', 'changelog-commit-label mono', label))
2165
+ if (meta) {
2166
+ box.appendChild(el('div', 'meta', meta))
2167
+ }
2168
+ return box
2169
+ }
2170
+
2171
+ function renderChangelogWithCommitSeparators(items, commitBySha, renderItem) {
2172
+ if (!Array.isArray(items) || items.length === 0) return
2173
+ let previousCommitSha = null
2174
+ items.forEach((item) => {
2175
+ const currentCommitSha = item?.event?.commitSha || null
2176
+ if (currentCommitSha !== previousCommitSha) {
2177
+ resultsEl.appendChild(renderCommitSeparator(currentCommitSha, commitBySha))
2178
+ previousCommitSha = currentCommitSha
2179
+ }
2180
+ resultsEl.appendChild(renderItem(item))
2181
+ })
2182
+ }
2183
+
2041
2184
  function renderChangelogEventLines(item, commitBySha) {
2042
2185
  const event = item.event
2043
2186
  const row = el('div', 'changelog-line-item')
@@ -2247,30 +2390,26 @@
2247
2390
  commit,
2248
2391
  ]),
2249
2392
  )
2250
- if (state.viewerMode === VIEWER_MODE.changelog) {
2251
- renderCollection(
2252
- filtered,
2253
- (item) => renderChangelogEventLines(item, commitBySha),
2254
- 'No matches.',
2393
+ if (filtered.length === 0) {
2394
+ resultsEl.appendChild(el('div', 'empty', 'No matches.'))
2395
+ } else if (state.viewerMode === VIEWER_MODE.changelog) {
2396
+ renderChangelogWithCommitSeparators(filtered, commitBySha, (item) =>
2397
+ renderChangelogEventLines(item, commitBySha),
2255
2398
  )
2256
2399
  } else {
2257
- renderCollection(
2258
- filtered,
2259
- (item) => {
2260
- const details = el('details', 'leaf')
2261
- const summary = el('summary')
2262
- summary.appendChild(renderEventTitle(item))
2263
- details.appendChild(summary)
2264
- details.appendChild(
2265
- renderEventCard(item.event, commitBySha, {
2266
- showTitle: false,
2267
- item,
2268
- }),
2269
- )
2270
- return details
2271
- },
2272
- 'No matches.',
2273
- )
2400
+ renderChangelogWithCommitSeparators(filtered, commitBySha, (item) => {
2401
+ const details = el('details', 'leaf')
2402
+ const summary = el('summary')
2403
+ summary.appendChild(renderEventTitle(item))
2404
+ details.appendChild(summary)
2405
+ details.appendChild(
2406
+ renderEventCard(item.event, commitBySha, {
2407
+ showTitle: false,
2408
+ item,
2409
+ }),
2410
+ )
2411
+ return details
2412
+ })
2274
2413
  }
2275
2414
  }
2276
2415
  syncFilterStateToUrl()