@emeryld/rrroutes-contract 2.7.5 → 2.7.7
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 +20 -1
- package/bin/rrroutes-export-finalized-leaves.mjs +14 -0
- package/dist/export/defaultViewerTemplate.d.ts +1 -1
- package/dist/export/exportFinalizedLeaves.cli.d.ts +2 -0
- package/dist/export/exportFinalizedLeaves.d.ts +20 -0
- package/dist/export/extractLeafSourceByAst.d.ts +38 -0
- package/dist/export/index.d.ts +1 -0
- package/dist/index.cjs +705 -38
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +704 -38
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -2
- package/tools/finalized-leaves-viewer.html +175 -7
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@emeryld/rrroutes-contract",
|
|
3
3
|
"description": "TypeScript contract definitions for RRRoutes",
|
|
4
|
-
"version": "2.7.
|
|
4
|
+
"version": "2.7.7",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "dist/index.cjs",
|
|
@@ -14,11 +14,16 @@
|
|
|
14
14
|
"require": "./dist/index.cjs"
|
|
15
15
|
}
|
|
16
16
|
},
|
|
17
|
+
"bin": {
|
|
18
|
+
"rrroutes-export-finalized-leaves": "./bin/rrroutes-export-finalized-leaves.mjs"
|
|
19
|
+
},
|
|
17
20
|
"files": [
|
|
18
21
|
"dist",
|
|
19
|
-
"tools/finalized-leaves-viewer.html"
|
|
22
|
+
"tools/finalized-leaves-viewer.html",
|
|
23
|
+
"bin/rrroutes-export-finalized-leaves.mjs"
|
|
20
24
|
],
|
|
21
25
|
"dependencies": {
|
|
26
|
+
"typescript": "^5.9.3",
|
|
22
27
|
"zod": "^4.3.6"
|
|
23
28
|
},
|
|
24
29
|
"devDependencies": {
|
|
@@ -156,6 +156,12 @@
|
|
|
156
156
|
color: var(--muted);
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
+
.kv .k a {
|
|
160
|
+
color: inherit;
|
|
161
|
+
text-decoration: underline;
|
|
162
|
+
text-underline-offset: 2px;
|
|
163
|
+
}
|
|
164
|
+
|
|
159
165
|
.kv .v {
|
|
160
166
|
margin-top: 2px;
|
|
161
167
|
word-break: break-word;
|
|
@@ -312,6 +318,10 @@
|
|
|
312
318
|
<option value="exact">exact</option>
|
|
313
319
|
</select>
|
|
314
320
|
</label>
|
|
321
|
+
<label class="field-item">
|
|
322
|
+
<input id="schemaRowsMatchOnly" type="checkbox" />
|
|
323
|
+
<span>schema rows match filter</span>
|
|
324
|
+
</label>
|
|
315
325
|
</div>
|
|
316
326
|
|
|
317
327
|
<div id="fieldCheckboxes" class="field-row"></div>
|
|
@@ -346,6 +356,31 @@
|
|
|
346
356
|
{ id: 'tags', label: 'tags', get: (leaf) => leaf.cfg?.tags || [] },
|
|
347
357
|
{ id: 'stability', label: 'stability', get: (leaf) => [leaf.cfg?.stability] },
|
|
348
358
|
{ id: 'docsMeta', label: 'docsMeta', get: (leaf) => [leaf.cfg?.docsMeta] },
|
|
359
|
+
{
|
|
360
|
+
id: 'sourceDefinition',
|
|
361
|
+
label: 'source definition',
|
|
362
|
+
get: (leaf, schemaFlatByLeaf, payload) => {
|
|
363
|
+
const source = payload?.sourceByLeaf?.[leaf.key]?.definition
|
|
364
|
+
if (!source) return []
|
|
365
|
+
return [`${source.file}:${source.line}:${source.column}`]
|
|
366
|
+
},
|
|
367
|
+
},
|
|
368
|
+
{
|
|
369
|
+
id: 'sourceSchemas',
|
|
370
|
+
label: 'source schemas',
|
|
371
|
+
get: (leaf, schemaFlatByLeaf, payload) => {
|
|
372
|
+
const schemas = payload?.sourceByLeaf?.[leaf.key]?.schemas
|
|
373
|
+
if (!schemas || typeof schemas !== 'object') return []
|
|
374
|
+
return Object.values(schemas).flatMap((schema) => {
|
|
375
|
+
if (!schema || typeof schema !== 'object') return []
|
|
376
|
+
const tokens = []
|
|
377
|
+
if (schema.sourceName) tokens.push(schema.sourceName)
|
|
378
|
+
if (schema.tag) tokens.push(schema.tag)
|
|
379
|
+
tokens.push(`${schema.file}:${schema.line}:${schema.column}`)
|
|
380
|
+
return tokens
|
|
381
|
+
})
|
|
382
|
+
},
|
|
383
|
+
},
|
|
349
384
|
{
|
|
350
385
|
id: 'types',
|
|
351
386
|
label: 'types',
|
|
@@ -390,6 +425,7 @@
|
|
|
390
425
|
const caseSensitiveInput = document.getElementById('caseSensitive')
|
|
391
426
|
const regexSearchInput = document.getElementById('regexSearch')
|
|
392
427
|
const typeMatchModeInput = document.getElementById('typeMatchMode')
|
|
428
|
+
const schemaRowsMatchOnlyInput = document.getElementById('schemaRowsMatchOnly')
|
|
393
429
|
const fieldCheckboxes = document.getElementById('fieldCheckboxes')
|
|
394
430
|
const activeFilterChips = document.getElementById('activeFilterChips')
|
|
395
431
|
const selectAllFieldsBtn = document.getElementById('selectAllFields')
|
|
@@ -557,6 +593,63 @@
|
|
|
557
593
|
return Array.from(tokens)
|
|
558
594
|
}
|
|
559
595
|
|
|
596
|
+
function schemaEntryTokens(path, info) {
|
|
597
|
+
const tokens = new Set()
|
|
598
|
+
|
|
599
|
+
if (path) {
|
|
600
|
+
tokens.add(path)
|
|
601
|
+
path.split('.').forEach((segment) => {
|
|
602
|
+
if (segment) tokens.add(segment)
|
|
603
|
+
})
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
if (info && typeof info === 'object') {
|
|
607
|
+
tokens.add(JSON.stringify(info))
|
|
608
|
+
if (info.type) tokens.add(String(info.type))
|
|
609
|
+
if (info.kind) tokens.add(String(info.kind))
|
|
610
|
+
if (info.description) tokens.add(String(info.description))
|
|
611
|
+
if (Array.isArray(info.enumValues)) {
|
|
612
|
+
info.enumValues.forEach((value) => tokens.add(String(value)))
|
|
613
|
+
}
|
|
614
|
+
} else if (info !== null && info !== undefined) {
|
|
615
|
+
tokens.add(String(info))
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
return Array.from(tokens)
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
function schemaEntryMatchesActiveFilter(sectionName, fullPath, info, engine, selectedIds) {
|
|
622
|
+
if (!engine.active) return true
|
|
623
|
+
|
|
624
|
+
let matched = false
|
|
625
|
+
if (selectedIds.includes(sectionName)) {
|
|
626
|
+
matched = schemaEntryTokens(fullPath, info).some((token) => engine.test(token))
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
if (!matched && selectedIds.includes('types')) {
|
|
630
|
+
const typeTokens = []
|
|
631
|
+
if (info && typeof info === 'object') {
|
|
632
|
+
if (info.type) typeTokens.push(String(info.type))
|
|
633
|
+
if (info.kind) typeTokens.push(String(info.kind))
|
|
634
|
+
if (Array.isArray(info.enumValues)) {
|
|
635
|
+
info.enumValues.forEach((value) => typeTokens.push(String(value)))
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
if (typeMatchModeInput.value === 'exact' && !engine.regex) {
|
|
640
|
+
const needle = engine.caseSensitive ? engine.query : engine.query.toLowerCase()
|
|
641
|
+
const normalized = engine.caseSensitive
|
|
642
|
+
? typeTokens
|
|
643
|
+
: typeTokens.map((token) => token.toLowerCase())
|
|
644
|
+
matched = normalized.includes(needle)
|
|
645
|
+
} else {
|
|
646
|
+
matched = typeTokens.some((token) => engine.test(token))
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
return matched
|
|
651
|
+
}
|
|
652
|
+
|
|
560
653
|
function selectedFieldIds() {
|
|
561
654
|
return SEARCH_FIELDS.filter((field) => {
|
|
562
655
|
const input = document.getElementById(`field-${field.id}`)
|
|
@@ -568,10 +661,11 @@
|
|
|
568
661
|
if (!engine.active) return true
|
|
569
662
|
if (selectedIds.length === 0) return false
|
|
570
663
|
const schemaFlatByLeaf = state.payload?.schemaFlatByLeaf || {}
|
|
664
|
+
const payload = state.payload || {}
|
|
571
665
|
|
|
572
666
|
return SEARCH_FIELDS.some((field) => {
|
|
573
667
|
if (!selectedIds.includes(field.id)) return false
|
|
574
|
-
const tokens = toTokens(field.get(leaf, schemaFlatByLeaf))
|
|
668
|
+
const tokens = toTokens(field.get(leaf, schemaFlatByLeaf, payload))
|
|
575
669
|
if (field.id === 'types' && typeMatchModeInput.value === 'exact' && !engine.regex) {
|
|
576
670
|
const needle = engine.caseSensitive ? engine.query : engine.query.toLowerCase()
|
|
577
671
|
const normalized = engine.caseSensitive
|
|
@@ -629,6 +723,40 @@
|
|
|
629
723
|
return row
|
|
630
724
|
}
|
|
631
725
|
|
|
726
|
+
function sourceHref(source) {
|
|
727
|
+
if (!source || !source.file) return undefined
|
|
728
|
+
const normalizedPath = String(source.file).replace(/\\/g, '/')
|
|
729
|
+
const prefix = normalizedPath.startsWith('/') ? 'file://' : 'file:///'
|
|
730
|
+
return `${prefix}${encodeURI(normalizedPath)}`
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
function createSourceRow(key, source, engine) {
|
|
734
|
+
const box = el('div', 'kv')
|
|
735
|
+
const keyNode = el('div', 'k')
|
|
736
|
+
const valueNode = el('div', 'v mono')
|
|
737
|
+
|
|
738
|
+
if (!source || !source.file) {
|
|
739
|
+
setHighlighted(keyNode, key, engine)
|
|
740
|
+
box.appendChild(keyNode)
|
|
741
|
+
setHighlighted(valueNode, '—', engine)
|
|
742
|
+
box.appendChild(valueNode)
|
|
743
|
+
return box
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
const href = sourceHref(source)
|
|
747
|
+
const keyLink = document.createElement('a')
|
|
748
|
+
keyLink.href = href
|
|
749
|
+
keyLink.target = '_blank'
|
|
750
|
+
keyLink.rel = 'noopener noreferrer'
|
|
751
|
+
keyLink.textContent = key
|
|
752
|
+
keyNode.appendChild(keyLink)
|
|
753
|
+
|
|
754
|
+
setHighlighted(valueNode, `${source.file}:${source.line}:${source.column}`, engine)
|
|
755
|
+
box.appendChild(keyNode)
|
|
756
|
+
box.appendChild(valueNode)
|
|
757
|
+
return box
|
|
758
|
+
}
|
|
759
|
+
|
|
632
760
|
function splitFlatSchemaBySection(flatSchema) {
|
|
633
761
|
const result = {
|
|
634
762
|
params: {},
|
|
@@ -737,17 +865,27 @@
|
|
|
737
865
|
return row
|
|
738
866
|
}
|
|
739
867
|
|
|
740
|
-
function renderSeparatedSchemas(flatSchema, engine) {
|
|
868
|
+
function renderSeparatedSchemas(flatSchema, engine, selectedIds) {
|
|
741
869
|
if (!flatSchema || typeof flatSchema !== 'object') return null
|
|
742
870
|
const section = el('div', 'section')
|
|
743
871
|
section.appendChild(el('h3', '', 'Schemas (separated by section)'))
|
|
744
872
|
|
|
745
873
|
const grouped = splitFlatSchemaBySection(flatSchema)
|
|
746
874
|
let hasAnySchemaEntries = false
|
|
875
|
+
const limitToMatchedRows = schemaRowsMatchOnlyInput.checked && engine.active
|
|
747
876
|
|
|
748
877
|
SCHEMA_SECTIONS.forEach((sectionName) => {
|
|
749
|
-
const
|
|
750
|
-
if (!
|
|
878
|
+
const rawEntries = grouped[sectionName]
|
|
879
|
+
if (!rawEntries || Object.keys(rawEntries).length === 0) return
|
|
880
|
+
|
|
881
|
+
const entries = limitToMatchedRows
|
|
882
|
+
? Object.fromEntries(
|
|
883
|
+
Object.entries(rawEntries).filter(([fullPath, info]) =>
|
|
884
|
+
schemaEntryMatchesActiveFilter(sectionName, fullPath, info, engine, selectedIds),
|
|
885
|
+
),
|
|
886
|
+
)
|
|
887
|
+
: rawEntries
|
|
888
|
+
if (Object.keys(entries).length === 0) return
|
|
751
889
|
|
|
752
890
|
hasAnySchemaEntries = true
|
|
753
891
|
const block = el('div', 'schema-block')
|
|
@@ -764,7 +902,7 @@
|
|
|
764
902
|
return hasAnySchemaEntries ? section : null
|
|
765
903
|
}
|
|
766
904
|
|
|
767
|
-
function renderLeaf(leaf, engine) {
|
|
905
|
+
function renderLeaf(leaf, engine, selectedIds) {
|
|
768
906
|
const details = el('details', 'leaf')
|
|
769
907
|
const summary = el('summary')
|
|
770
908
|
setHighlighted(summary, `${String(leaf.method || '').toUpperCase()} ${leaf.path || ''}`, engine)
|
|
@@ -823,7 +961,32 @@
|
|
|
823
961
|
content.appendChild(files)
|
|
824
962
|
}
|
|
825
963
|
|
|
826
|
-
const
|
|
964
|
+
const sourceByLeaf = state.payload?.sourceByLeaf || {}
|
|
965
|
+
const source = sourceByLeaf[leaf.key]
|
|
966
|
+
if (source) {
|
|
967
|
+
const sourceSection = el('div', 'section')
|
|
968
|
+
sourceSection.appendChild(el('h3', '', 'Source'))
|
|
969
|
+
sourceSection.appendChild(createSourceRow('definition', source.definition, engine))
|
|
970
|
+
|
|
971
|
+
const schemaSources = source.schemas || {}
|
|
972
|
+
const schemaEntries = Object.entries(schemaSources)
|
|
973
|
+
if (schemaEntries.length > 0) {
|
|
974
|
+
const schemaGrid = el('div', 'grid-2')
|
|
975
|
+
schemaEntries.forEach(([schemaName, schemaSource]) => {
|
|
976
|
+
const display = schemaSource?.sourceName
|
|
977
|
+
? `${schemaName}: ${schemaSource.sourceName}`
|
|
978
|
+
: schemaSource?.tag
|
|
979
|
+
? `${schemaName}: ${schemaSource.tag}`
|
|
980
|
+
: schemaName
|
|
981
|
+
schemaGrid.appendChild(createSourceRow(display, schemaSource, engine))
|
|
982
|
+
})
|
|
983
|
+
sourceSection.appendChild(schemaGrid)
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
content.appendChild(sourceSection)
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
const separatedSchemas = renderSeparatedSchemas(flatSchema, engine, selectedIds)
|
|
827
990
|
if (separatedSchemas) {
|
|
828
991
|
content.appendChild(separatedSchemas)
|
|
829
992
|
}
|
|
@@ -863,7 +1026,7 @@
|
|
|
863
1026
|
}
|
|
864
1027
|
|
|
865
1028
|
filtered.forEach((leaf) => {
|
|
866
|
-
resultsEl.appendChild(renderLeaf(leaf, engine))
|
|
1029
|
+
resultsEl.appendChild(renderLeaf(leaf, engine, selectedIds))
|
|
867
1030
|
})
|
|
868
1031
|
syncFilterStateToUrl()
|
|
869
1032
|
}
|
|
@@ -897,6 +1060,7 @@
|
|
|
897
1060
|
caseSensitiveInput.checked = false
|
|
898
1061
|
regexSearchInput.checked = false
|
|
899
1062
|
typeMatchModeInput.value = 'contains'
|
|
1063
|
+
schemaRowsMatchOnlyInput.checked = false
|
|
900
1064
|
setFieldSelection(new Set(SEARCH_FIELDS.map((field) => field.id)))
|
|
901
1065
|
}
|
|
902
1066
|
|
|
@@ -908,6 +1072,7 @@
|
|
|
908
1072
|
|
|
909
1073
|
if (searchValue) chips.push(`search: ${searchValue}`)
|
|
910
1074
|
if (typeMatchModeInput.value === 'exact') chips.push('type mode: exact')
|
|
1075
|
+
if (schemaRowsMatchOnlyInput.checked) chips.push('schema rows: matched only')
|
|
911
1076
|
if (caseSensitiveInput.checked) chips.push('case sensitive')
|
|
912
1077
|
if (regexSearchInput.checked) chips.push('regex')
|
|
913
1078
|
if (hasRegexError) chips.push('regex error')
|
|
@@ -935,6 +1100,7 @@
|
|
|
935
1100
|
caseSensitive: caseSensitiveInput.checked,
|
|
936
1101
|
regex: regexSearchInput.checked,
|
|
937
1102
|
typeMatchMode: typeMatchModeInput.value === 'exact' ? 'exact' : 'contains',
|
|
1103
|
+
schemaRowsMatchOnly: schemaRowsMatchOnlyInput.checked,
|
|
938
1104
|
selectedFields: selectedFieldIds(),
|
|
939
1105
|
}
|
|
940
1106
|
}
|
|
@@ -966,6 +1132,7 @@
|
|
|
966
1132
|
if (parsed.typeMatchMode === 'exact' || parsed.typeMatchMode === 'contains') {
|
|
967
1133
|
typeMatchModeInput.value = parsed.typeMatchMode
|
|
968
1134
|
}
|
|
1135
|
+
schemaRowsMatchOnlyInput.checked = Boolean(parsed.schemaRowsMatchOnly)
|
|
969
1136
|
|
|
970
1137
|
if (Array.isArray(parsed.selectedFields)) {
|
|
971
1138
|
const allowed = new Set(parsed.selectedFields)
|
|
@@ -1020,6 +1187,7 @@
|
|
|
1020
1187
|
caseSensitiveInput.addEventListener('change', renderResults)
|
|
1021
1188
|
regexSearchInput.addEventListener('change', renderResults)
|
|
1022
1189
|
typeMatchModeInput.addEventListener('change', renderResults)
|
|
1190
|
+
schemaRowsMatchOnlyInput.addEventListener('change', renderResults)
|
|
1023
1191
|
|
|
1024
1192
|
selectAllFieldsBtn.addEventListener('click', () =>
|
|
1025
1193
|
setFieldSelection(new Set(SEARCH_FIELDS.map((field) => field.id))),
|