@emeryld/rrroutes-export 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +132 -3
- package/bin/rrroutes-export-changelog.mjs +16 -0
- package/dist/defaultViewerTemplate.d.ts +1 -0
- package/dist/exportFinalizedLeaves.changelog.cli.d.ts +15 -0
- package/dist/exportFinalizedLeaves.changelog.d.ts +145 -0
- package/dist/exportFinalizedLeaves.cli.d.ts +14 -0
- package/dist/exportFinalizedLeaves.d.ts +61 -0
- package/dist/extractLeafSourceByAst.d.ts +38 -0
- package/dist/flattenSchema.d.ts +12 -0
- package/dist/index.cjs +882 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +9 -0
- package/dist/index.mjs +877 -14
- package/dist/index.mjs.map +1 -1
- package/dist/schemaIntrospection.d.ts +47 -0
- package/dist/serializeLeafContract.d.ts +31 -0
- package/package.json +10 -5
- package/tools/finalized-leaves-viewer.html +129 -1
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type AnyLeafLowProfile, type FileField } from '@emeryld/rrroutes-contract';
|
|
2
|
+
import { type IntrospectSchemaOptions, type SerializableSchema } from './schemaIntrospection';
|
|
3
|
+
export type ContractLeafSchemas = {
|
|
4
|
+
body?: SerializableSchema;
|
|
5
|
+
query?: SerializableSchema;
|
|
6
|
+
params?: SerializableSchema;
|
|
7
|
+
output?: SerializableSchema;
|
|
8
|
+
outputMeta?: SerializableSchema;
|
|
9
|
+
queryExtension?: SerializableSchema;
|
|
10
|
+
};
|
|
11
|
+
export type SerializedLeafContract = {
|
|
12
|
+
key: string;
|
|
13
|
+
method: AnyLeafLowProfile['method'];
|
|
14
|
+
path: string;
|
|
15
|
+
cfg: {
|
|
16
|
+
description?: string;
|
|
17
|
+
summary?: string;
|
|
18
|
+
docsGroup?: string;
|
|
19
|
+
tags?: string[];
|
|
20
|
+
deprecated?: boolean;
|
|
21
|
+
stability?: 'experimental' | 'beta' | 'stable' | 'deprecated';
|
|
22
|
+
docsHidden?: boolean;
|
|
23
|
+
docsMeta?: Record<string, unknown>;
|
|
24
|
+
feed?: boolean;
|
|
25
|
+
bodyFiles?: FileField[];
|
|
26
|
+
schemas: ContractLeafSchemas;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
export type SerializeLeafContractOptions = IntrospectSchemaOptions;
|
|
30
|
+
export declare function serializeLeafContract(leaf: AnyLeafLowProfile, options?: SerializeLeafContractOptions): SerializedLeafContract;
|
|
31
|
+
export declare function serializeLeavesContract(leaves: readonly AnyLeafLowProfile[], options?: SerializeLeafContractOptions): SerializedLeafContract[];
|
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.
|
|
4
|
+
"version": "1.0.5",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "dist/index.cjs",
|
|
@@ -15,12 +15,14 @@
|
|
|
15
15
|
}
|
|
16
16
|
},
|
|
17
17
|
"bin": {
|
|
18
|
-
"rrroutes-export-finalized-leaves": "./bin/rrroutes-export-finalized-leaves.mjs"
|
|
18
|
+
"rrroutes-export-finalized-leaves": "./bin/rrroutes-export-finalized-leaves.mjs",
|
|
19
|
+
"rrroutes-export-changelog": "./bin/rrroutes-export-changelog.mjs"
|
|
19
20
|
},
|
|
20
21
|
"files": [
|
|
21
22
|
"dist",
|
|
22
23
|
"tools/finalized-leaves-viewer.html",
|
|
23
|
-
"bin/rrroutes-export-finalized-leaves.mjs"
|
|
24
|
+
"bin/rrroutes-export-finalized-leaves.mjs",
|
|
25
|
+
"bin/rrroutes-export-changelog.mjs"
|
|
24
26
|
],
|
|
25
27
|
"dependencies": {
|
|
26
28
|
"@emeryld/rrroutes-contract": "^2.8.0",
|
|
@@ -36,10 +38,13 @@
|
|
|
36
38
|
},
|
|
37
39
|
"scripts": {
|
|
38
40
|
"clean": "rimraf dist && rimraf node_modules",
|
|
39
|
-
"build": "pnpm run clean && pnpm install && pnpm run build:js",
|
|
41
|
+
"build": "pnpm run clean && pnpm install && pnpm run build:js && pnpm run build:types",
|
|
40
42
|
"build:js": "tsup --config tsup.config.ts",
|
|
43
|
+
"build:types": "tsc -p tsconfig.build.json",
|
|
41
44
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
42
45
|
"test": "NODE_OPTIONS=--experimental-vm-modules jest --config ../../jest.base.config.js --watchman=false --runInBand",
|
|
43
|
-
"export:finalized-leaves": "TS_NODE_PROJECT=tsconfig.tools.json TS_NODE_TRANSPILE_ONLY=1 node --experimental-specifier-resolution=node --loader ts-node/esm ./scripts/export-finalized-leaves.ts"
|
|
46
|
+
"export:finalized-leaves": "TS_NODE_PROJECT=tsconfig.tools.json TS_NODE_TRANSPILE_ONLY=1 node --experimental-specifier-resolution=node --loader ts-node/esm ./scripts/export-finalized-leaves.ts",
|
|
47
|
+
"export:changelog": "TS_NODE_PROJECT=tsconfig.tools.json TS_NODE_TRANSPILE_ONLY=1 node --experimental-specifier-resolution=node --loader ts-node/esm ./scripts/export-finalized-leaves-changelog.ts",
|
|
48
|
+
"export:bundle": "TS_NODE_PROJECT=tsconfig.tools.json TS_NODE_TRANSPILE_ONLY=1 node --experimental-specifier-resolution=node --loader ts-node/esm ./scripts/export-release-bundle.ts"
|
|
44
49
|
}
|
|
45
50
|
}
|
|
@@ -648,6 +648,7 @@
|
|
|
648
648
|
const state = {
|
|
649
649
|
payload: null,
|
|
650
650
|
leaves: [],
|
|
651
|
+
mode: 'snapshot',
|
|
651
652
|
selectedFieldIds: new Set(SEARCH_FIELDS.map((field) => field.id)),
|
|
652
653
|
}
|
|
653
654
|
|
|
@@ -667,6 +668,7 @@
|
|
|
667
668
|
const resetFiltersBtn = document.getElementById('resetFilters')
|
|
668
669
|
const statusEl = document.getElementById('status')
|
|
669
670
|
const resultsEl = document.getElementById('results')
|
|
671
|
+
const controlsEl = document.querySelector('.controls')
|
|
670
672
|
|
|
671
673
|
const URL_PARAM_KEY = 'filters'
|
|
672
674
|
let isHydratingFromUrl = false
|
|
@@ -1306,7 +1308,115 @@
|
|
|
1306
1308
|
return details
|
|
1307
1309
|
}
|
|
1308
1310
|
|
|
1311
|
+
function isChangelogPayload(value) {
|
|
1312
|
+
return (
|
|
1313
|
+
value &&
|
|
1314
|
+
value.kind === 'finalized-leaves-changelog' &&
|
|
1315
|
+
Array.isArray(value.commits)
|
|
1316
|
+
)
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
function renderChangelogPayload(payload) {
|
|
1320
|
+
state.mode = 'changelog'
|
|
1321
|
+
state.payload = payload
|
|
1322
|
+
state.leaves = []
|
|
1323
|
+
|
|
1324
|
+
if (controlsEl) {
|
|
1325
|
+
controlsEl.style.display = 'none'
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
const commitBySha = new Map(
|
|
1329
|
+
(payload.commits || []).map((commit) => [commit.sha, commit]),
|
|
1330
|
+
)
|
|
1331
|
+
const routeEntries = Object.entries(payload.byRoute || {}).sort(
|
|
1332
|
+
([a], [b]) => a.localeCompare(b),
|
|
1333
|
+
)
|
|
1334
|
+
const sourceEntries = Object.entries(payload.bySourceObject || {}).sort(
|
|
1335
|
+
([a], [b]) => a.localeCompare(b),
|
|
1336
|
+
)
|
|
1337
|
+
|
|
1338
|
+
statusEl.textContent = `Loaded changelog payload with ${payload.commits.length} commits.`
|
|
1339
|
+
resultsEl.innerHTML = ''
|
|
1340
|
+
|
|
1341
|
+
const tabs = el('div', 'chips')
|
|
1342
|
+
const byRouteBtn = el('button', 'chip chip-btn', 'By Route')
|
|
1343
|
+
const bySourceBtn = el('button', 'chip chip-btn', 'By Source Object')
|
|
1344
|
+
byRouteBtn.type = 'button'
|
|
1345
|
+
bySourceBtn.type = 'button'
|
|
1346
|
+
tabs.appendChild(byRouteBtn)
|
|
1347
|
+
tabs.appendChild(bySourceBtn)
|
|
1348
|
+
resultsEl.appendChild(tabs)
|
|
1349
|
+
|
|
1350
|
+
const view = el('div')
|
|
1351
|
+
resultsEl.appendChild(view)
|
|
1352
|
+
|
|
1353
|
+
const renderEventDetails = (event) => {
|
|
1354
|
+
const card = el('div', 'leaf-content')
|
|
1355
|
+
const commit = commitBySha.get(event.commitSha)
|
|
1356
|
+
card.appendChild(
|
|
1357
|
+
el(
|
|
1358
|
+
'div',
|
|
1359
|
+
'meta',
|
|
1360
|
+
`${event.commitSha.slice(0, 12)}${commit?.subject ? ` - ${commit.subject}` : ''}`,
|
|
1361
|
+
),
|
|
1362
|
+
)
|
|
1363
|
+
card.appendChild(el('div', 'mono', event.type))
|
|
1364
|
+
if (Array.isArray(event.schemaDiff) && event.schemaDiff.length > 0) {
|
|
1365
|
+
card.appendChild(el('div', 'meta', `schema changes: ${event.schemaDiff.length}`))
|
|
1366
|
+
}
|
|
1367
|
+
if (Array.isArray(event.cfgDiff) && event.cfgDiff.length > 0) {
|
|
1368
|
+
card.appendChild(el('div', 'meta', `cfg changes: ${event.cfgDiff.length}`))
|
|
1369
|
+
}
|
|
1370
|
+
if (Array.isArray(event.impactedRoutes) && event.impactedRoutes.length > 0) {
|
|
1371
|
+
card.appendChild(
|
|
1372
|
+
el('div', 'meta', `impacted routes: ${event.impactedRoutes.length}`),
|
|
1373
|
+
)
|
|
1374
|
+
}
|
|
1375
|
+
return card
|
|
1376
|
+
}
|
|
1377
|
+
|
|
1378
|
+
const renderByRoute = () => {
|
|
1379
|
+
view.innerHTML = ''
|
|
1380
|
+
if (routeEntries.length === 0) {
|
|
1381
|
+
view.appendChild(el('div', 'empty', 'No route changes found in this range.'))
|
|
1382
|
+
return
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
routeEntries.forEach(([routeKey, events]) => {
|
|
1386
|
+
const details = el('details', 'leaf')
|
|
1387
|
+
details.appendChild(el('summary', '', `${routeKey} (${events.length})`))
|
|
1388
|
+
events.forEach((event) => details.appendChild(renderEventDetails(event)))
|
|
1389
|
+
view.appendChild(details)
|
|
1390
|
+
})
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
const renderBySource = () => {
|
|
1394
|
+
view.innerHTML = ''
|
|
1395
|
+
if (sourceEntries.length === 0) {
|
|
1396
|
+
view.appendChild(
|
|
1397
|
+
el('div', 'empty', 'No source-object changes found in this range.'),
|
|
1398
|
+
)
|
|
1399
|
+
return
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1402
|
+
sourceEntries.forEach(([sourceId, events]) => {
|
|
1403
|
+
const details = el('details', 'leaf')
|
|
1404
|
+
const display = events[0]?.displayName || sourceId
|
|
1405
|
+
details.appendChild(el('summary', '', `${display} (${events.length})`))
|
|
1406
|
+
events.forEach((event) => details.appendChild(renderEventDetails(event)))
|
|
1407
|
+
view.appendChild(details)
|
|
1408
|
+
})
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
byRouteBtn.addEventListener('click', renderByRoute)
|
|
1412
|
+
bySourceBtn.addEventListener('click', renderBySource)
|
|
1413
|
+
renderByRoute()
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1309
1416
|
function renderResults() {
|
|
1417
|
+
if (state.mode === 'changelog') {
|
|
1418
|
+
return
|
|
1419
|
+
}
|
|
1310
1420
|
const engine = createSearchEngine(searchInput.value.trim(), {
|
|
1311
1421
|
caseSensitive: isPressed(caseSensitiveToggle),
|
|
1312
1422
|
regex: isPressed(regexSearchToggle),
|
|
@@ -1529,10 +1639,20 @@
|
|
|
1529
1639
|
async function handleFile(file) {
|
|
1530
1640
|
const text = await file.text()
|
|
1531
1641
|
const parsed = JSON.parse(text)
|
|
1642
|
+
if (isChangelogPayload(parsed)) {
|
|
1643
|
+
renderChangelogPayload(parsed)
|
|
1644
|
+
return
|
|
1645
|
+
}
|
|
1532
1646
|
if (!parsed || !Array.isArray(parsed.leaves)) {
|
|
1533
|
-
throw new Error(
|
|
1647
|
+
throw new Error(
|
|
1648
|
+
'Invalid export file: expected top-level "leaves" array or changelog payload.',
|
|
1649
|
+
)
|
|
1534
1650
|
}
|
|
1535
1651
|
|
|
1652
|
+
state.mode = 'snapshot'
|
|
1653
|
+
if (controlsEl) {
|
|
1654
|
+
controlsEl.style.display = ''
|
|
1655
|
+
}
|
|
1536
1656
|
state.payload = parsed
|
|
1537
1657
|
state.leaves = parsed.leaves
|
|
1538
1658
|
renderResults()
|
|
@@ -1540,8 +1660,16 @@
|
|
|
1540
1660
|
|
|
1541
1661
|
function initializeFromBakedPayload() {
|
|
1542
1662
|
const baked = window.__FINALIZED_LEAVES_PAYLOAD
|
|
1663
|
+
if (isChangelogPayload(baked)) {
|
|
1664
|
+
renderChangelogPayload(baked)
|
|
1665
|
+
return
|
|
1666
|
+
}
|
|
1543
1667
|
if (!baked || !Array.isArray(baked.leaves)) return
|
|
1544
1668
|
|
|
1669
|
+
state.mode = 'snapshot'
|
|
1670
|
+
if (controlsEl) {
|
|
1671
|
+
controlsEl.style.display = ''
|
|
1672
|
+
}
|
|
1545
1673
|
state.payload = baked
|
|
1546
1674
|
state.leaves = baked.leaves
|
|
1547
1675
|
statusEl.textContent = `Loaded baked payload with ${state.leaves.length} routes.`
|