@emeryld/rrroutes-contract 2.7.4 → 2.7.6
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 +19 -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 +14 -0
- package/dist/export/extractLeafSourceByAst.d.ts +30 -0
- package/dist/export/index.d.ts +1 -0
- package/dist/index.cjs +540 -38
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +539 -38
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -2
- package/tools/finalized-leaves-viewer.html +272 -138
|
@@ -140,6 +140,12 @@
|
|
|
140
140
|
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
+
.grid-3 {
|
|
144
|
+
display: grid;
|
|
145
|
+
gap: 6px;
|
|
146
|
+
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
147
|
+
}
|
|
148
|
+
|
|
143
149
|
.kv {
|
|
144
150
|
border-bottom: 1px dashed #e2e8f2;
|
|
145
151
|
padding: 4px 0 6px;
|
|
@@ -179,6 +185,30 @@
|
|
|
179
185
|
background: #effbf4;
|
|
180
186
|
}
|
|
181
187
|
|
|
188
|
+
.icon-row {
|
|
189
|
+
display: flex;
|
|
190
|
+
gap: 6px;
|
|
191
|
+
margin-top: 2px;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.icon-badge {
|
|
195
|
+
display: inline-flex;
|
|
196
|
+
align-items: center;
|
|
197
|
+
justify-content: center;
|
|
198
|
+
width: 18px;
|
|
199
|
+
height: 18px;
|
|
200
|
+
border: 1px solid #e0e6f0;
|
|
201
|
+
border-radius: 4px;
|
|
202
|
+
font-size: 11px;
|
|
203
|
+
background: #f6f8fc;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.icon-badge.warn {
|
|
207
|
+
border-color: #f2d5d5;
|
|
208
|
+
color: #a02424;
|
|
209
|
+
background: #fff4f4;
|
|
210
|
+
}
|
|
211
|
+
|
|
182
212
|
.empty {
|
|
183
213
|
color: var(--muted);
|
|
184
214
|
}
|
|
@@ -244,6 +274,12 @@
|
|
|
244
274
|
font-size: 11px;
|
|
245
275
|
background: #f2f5fa;
|
|
246
276
|
}
|
|
277
|
+
|
|
278
|
+
@media (max-width: 720px) {
|
|
279
|
+
.grid-3 {
|
|
280
|
+
grid-template-columns: 1fr;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
247
283
|
</style>
|
|
248
284
|
</head>
|
|
249
285
|
<body>
|
|
@@ -260,11 +296,6 @@
|
|
|
260
296
|
<input id="searchInput" type="text" placeholder="Type to search..." />
|
|
261
297
|
</label>
|
|
262
298
|
|
|
263
|
-
<label>
|
|
264
|
-
Type filter:
|
|
265
|
-
<input id="typeFilterInput" type="text" placeholder='Type/kind/enum (e.g. "paid")' />
|
|
266
|
-
</label>
|
|
267
|
-
|
|
268
299
|
<div class="field-row">
|
|
269
300
|
<label class="field-item">
|
|
270
301
|
<input id="caseSensitive" type="checkbox" />
|
|
@@ -274,10 +305,6 @@
|
|
|
274
305
|
<input id="regexSearch" type="checkbox" />
|
|
275
306
|
<span>regex</span>
|
|
276
307
|
</label>
|
|
277
|
-
<label class="field-item">
|
|
278
|
-
<input id="hasEnumOnly" type="checkbox" />
|
|
279
|
-
<span>has enum only</span>
|
|
280
|
-
</label>
|
|
281
308
|
<label class="field-item">
|
|
282
309
|
<span>type match</span>
|
|
283
310
|
<select id="typeMatchMode">
|
|
@@ -285,6 +312,10 @@
|
|
|
285
312
|
<option value="exact">exact</option>
|
|
286
313
|
</select>
|
|
287
314
|
</label>
|
|
315
|
+
<label class="field-item">
|
|
316
|
+
<input id="schemaRowsMatchOnly" type="checkbox" />
|
|
317
|
+
<span>schema rows match filter</span>
|
|
318
|
+
</label>
|
|
288
319
|
</div>
|
|
289
320
|
|
|
290
321
|
<div id="fieldCheckboxes" class="field-row"></div>
|
|
@@ -319,6 +350,36 @@
|
|
|
319
350
|
{ id: 'tags', label: 'tags', get: (leaf) => leaf.cfg?.tags || [] },
|
|
320
351
|
{ id: 'stability', label: 'stability', get: (leaf) => [leaf.cfg?.stability] },
|
|
321
352
|
{ id: 'docsMeta', label: 'docsMeta', get: (leaf) => [leaf.cfg?.docsMeta] },
|
|
353
|
+
{
|
|
354
|
+
id: 'sourceDefinition',
|
|
355
|
+
label: 'source definition',
|
|
356
|
+
get: (leaf, schemaFlatByLeaf, payload) => {
|
|
357
|
+
const source = payload?.sourceByLeaf?.[leaf.key]?.definition
|
|
358
|
+
if (!source) return []
|
|
359
|
+
return [`${source.file}:${source.line}:${source.column}`]
|
|
360
|
+
},
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
id: 'sourceSchemas',
|
|
364
|
+
label: 'source schemas',
|
|
365
|
+
get: (leaf, schemaFlatByLeaf, payload) => {
|
|
366
|
+
const schemas = payload?.sourceByLeaf?.[leaf.key]?.schemas
|
|
367
|
+
if (!schemas || typeof schemas !== 'object') return []
|
|
368
|
+
return Object.values(schemas).flatMap((schema) => {
|
|
369
|
+
if (!schema || typeof schema !== 'object') return []
|
|
370
|
+
const tokens = []
|
|
371
|
+
if (schema.sourceName) tokens.push(schema.sourceName)
|
|
372
|
+
if (schema.tag) tokens.push(schema.tag)
|
|
373
|
+
tokens.push(`${schema.file}:${schema.line}:${schema.column}`)
|
|
374
|
+
return tokens
|
|
375
|
+
})
|
|
376
|
+
},
|
|
377
|
+
},
|
|
378
|
+
{
|
|
379
|
+
id: 'types',
|
|
380
|
+
label: 'types',
|
|
381
|
+
get: (leaf, schemaFlatByLeaf) => schemaTypeTokens(schemaFlatByLeaf?.[leaf.key]),
|
|
382
|
+
},
|
|
322
383
|
{
|
|
323
384
|
id: 'params',
|
|
324
385
|
label: 'params',
|
|
@@ -355,11 +416,10 @@
|
|
|
355
416
|
|
|
356
417
|
const fileInput = document.getElementById('fileInput')
|
|
357
418
|
const searchInput = document.getElementById('searchInput')
|
|
358
|
-
const typeFilterInput = document.getElementById('typeFilterInput')
|
|
359
419
|
const caseSensitiveInput = document.getElementById('caseSensitive')
|
|
360
420
|
const regexSearchInput = document.getElementById('regexSearch')
|
|
361
|
-
const hasEnumOnlyInput = document.getElementById('hasEnumOnly')
|
|
362
421
|
const typeMatchModeInput = document.getElementById('typeMatchMode')
|
|
422
|
+
const schemaRowsMatchOnlyInput = document.getElementById('schemaRowsMatchOnly')
|
|
363
423
|
const fieldCheckboxes = document.getElementById('fieldCheckboxes')
|
|
364
424
|
const activeFilterChips = document.getElementById('activeFilterChips')
|
|
365
425
|
const selectAllFieldsBtn = document.getElementById('selectAllFields')
|
|
@@ -394,6 +454,9 @@
|
|
|
394
454
|
if (!query) {
|
|
395
455
|
return {
|
|
396
456
|
active: false,
|
|
457
|
+
query,
|
|
458
|
+
caseSensitive,
|
|
459
|
+
regex,
|
|
397
460
|
error: null,
|
|
398
461
|
test: () => true,
|
|
399
462
|
highlight: (text) => escapeHtml(text ?? ''),
|
|
@@ -406,6 +469,9 @@
|
|
|
406
469
|
const rx = new RegExp(query, flags)
|
|
407
470
|
return {
|
|
408
471
|
active: true,
|
|
472
|
+
query,
|
|
473
|
+
caseSensitive,
|
|
474
|
+
regex,
|
|
409
475
|
error: null,
|
|
410
476
|
test: (text) => {
|
|
411
477
|
const source = String(text ?? '')
|
|
@@ -423,6 +489,9 @@
|
|
|
423
489
|
} catch (error) {
|
|
424
490
|
return {
|
|
425
491
|
active: true,
|
|
492
|
+
query,
|
|
493
|
+
caseSensitive,
|
|
494
|
+
regex,
|
|
426
495
|
error: error instanceof Error ? error.message : 'Invalid regex',
|
|
427
496
|
test: () => false,
|
|
428
497
|
highlight: (text) => escapeHtml(text ?? ''),
|
|
@@ -436,6 +505,9 @@
|
|
|
436
505
|
|
|
437
506
|
return {
|
|
438
507
|
active: true,
|
|
508
|
+
query,
|
|
509
|
+
caseSensitive,
|
|
510
|
+
regex,
|
|
439
511
|
error: null,
|
|
440
512
|
test: (text) => {
|
|
441
513
|
const source = String(text ?? '')
|
|
@@ -499,23 +571,77 @@
|
|
|
499
571
|
return flatSchemaToSearchTokens(Object.fromEntries(sectionEntries))
|
|
500
572
|
}
|
|
501
573
|
|
|
502
|
-
function
|
|
503
|
-
if (!flatSchema || typeof flatSchema !== 'object') return
|
|
574
|
+
function schemaTypeTokens(flatSchema) {
|
|
575
|
+
if (!flatSchema || typeof flatSchema !== 'object') return []
|
|
504
576
|
|
|
505
577
|
const tokens = new Set()
|
|
506
|
-
let hasEnum = false
|
|
507
|
-
|
|
508
578
|
Object.values(flatSchema).forEach((info) => {
|
|
509
579
|
if (!info || typeof info !== 'object') return
|
|
510
580
|
if (info.type) tokens.add(String(info.type))
|
|
511
581
|
if (info.kind) tokens.add(String(info.kind))
|
|
512
|
-
if (Array.isArray(info.enumValues)
|
|
513
|
-
hasEnum = true
|
|
582
|
+
if (Array.isArray(info.enumValues)) {
|
|
514
583
|
info.enumValues.forEach((value) => tokens.add(String(value)))
|
|
515
584
|
}
|
|
516
585
|
})
|
|
517
586
|
|
|
518
|
-
return
|
|
587
|
+
return Array.from(tokens)
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
function schemaEntryTokens(path, info) {
|
|
591
|
+
const tokens = new Set()
|
|
592
|
+
|
|
593
|
+
if (path) {
|
|
594
|
+
tokens.add(path)
|
|
595
|
+
path.split('.').forEach((segment) => {
|
|
596
|
+
if (segment) tokens.add(segment)
|
|
597
|
+
})
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
if (info && typeof info === 'object') {
|
|
601
|
+
tokens.add(JSON.stringify(info))
|
|
602
|
+
if (info.type) tokens.add(String(info.type))
|
|
603
|
+
if (info.kind) tokens.add(String(info.kind))
|
|
604
|
+
if (info.description) tokens.add(String(info.description))
|
|
605
|
+
if (Array.isArray(info.enumValues)) {
|
|
606
|
+
info.enumValues.forEach((value) => tokens.add(String(value)))
|
|
607
|
+
}
|
|
608
|
+
} else if (info !== null && info !== undefined) {
|
|
609
|
+
tokens.add(String(info))
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
return Array.from(tokens)
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
function schemaEntryMatchesActiveFilter(sectionName, fullPath, info, engine, selectedIds) {
|
|
616
|
+
if (!engine.active) return true
|
|
617
|
+
|
|
618
|
+
let matched = false
|
|
619
|
+
if (selectedIds.includes(sectionName)) {
|
|
620
|
+
matched = schemaEntryTokens(fullPath, info).some((token) => engine.test(token))
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
if (!matched && selectedIds.includes('types')) {
|
|
624
|
+
const typeTokens = []
|
|
625
|
+
if (info && typeof info === 'object') {
|
|
626
|
+
if (info.type) typeTokens.push(String(info.type))
|
|
627
|
+
if (info.kind) typeTokens.push(String(info.kind))
|
|
628
|
+
if (Array.isArray(info.enumValues)) {
|
|
629
|
+
info.enumValues.forEach((value) => typeTokens.push(String(value)))
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
if (typeMatchModeInput.value === 'exact' && !engine.regex) {
|
|
634
|
+
const needle = engine.caseSensitive ? engine.query : engine.query.toLowerCase()
|
|
635
|
+
const normalized = engine.caseSensitive
|
|
636
|
+
? typeTokens
|
|
637
|
+
: typeTokens.map((token) => token.toLowerCase())
|
|
638
|
+
matched = normalized.includes(needle)
|
|
639
|
+
} else {
|
|
640
|
+
matched = typeTokens.some((token) => engine.test(token))
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
return matched
|
|
519
645
|
}
|
|
520
646
|
|
|
521
647
|
function selectedFieldIds() {
|
|
@@ -529,50 +655,22 @@
|
|
|
529
655
|
if (!engine.active) return true
|
|
530
656
|
if (selectedIds.length === 0) return false
|
|
531
657
|
const schemaFlatByLeaf = state.payload?.schemaFlatByLeaf || {}
|
|
658
|
+
const payload = state.payload || {}
|
|
532
659
|
|
|
533
660
|
return SEARCH_FIELDS.some((field) => {
|
|
534
661
|
if (!selectedIds.includes(field.id)) return false
|
|
535
|
-
const tokens = toTokens(field.get(leaf, schemaFlatByLeaf))
|
|
662
|
+
const tokens = toTokens(field.get(leaf, schemaFlatByLeaf, payload))
|
|
663
|
+
if (field.id === 'types' && typeMatchModeInput.value === 'exact' && !engine.regex) {
|
|
664
|
+
const needle = engine.caseSensitive ? engine.query : engine.query.toLowerCase()
|
|
665
|
+
const normalized = engine.caseSensitive
|
|
666
|
+
? tokens
|
|
667
|
+
: tokens.map((token) => String(token).toLowerCase())
|
|
668
|
+
return normalized.includes(needle)
|
|
669
|
+
}
|
|
536
670
|
return tokens.some((token) => engine.test(token))
|
|
537
671
|
})
|
|
538
672
|
}
|
|
539
673
|
|
|
540
|
-
function matchesTypeFilter(leaf, typeEngine, matchMode, hasEnumOnly) {
|
|
541
|
-
const schemaFlatByLeaf = state.payload?.schemaFlatByLeaf || {}
|
|
542
|
-
const { tokens, hasEnum } = typeFilterTokensByLeaf(schemaFlatByLeaf?.[leaf.key])
|
|
543
|
-
|
|
544
|
-
if (hasEnumOnly && !hasEnum) return false
|
|
545
|
-
if (!typeEngine.active) return true
|
|
546
|
-
|
|
547
|
-
if (matchMode === 'exact') {
|
|
548
|
-
const sourceTokens = typeEngine.caseSensitive
|
|
549
|
-
? tokens
|
|
550
|
-
: tokens.map((token) => token.toLowerCase())
|
|
551
|
-
const needle = typeEngine.caseSensitive ? typeEngine.query : typeEngine.query.toLowerCase()
|
|
552
|
-
return sourceTokens.includes(needle)
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
return tokens.some((token) => typeEngine.test(token))
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
function createTypeSearchEngine(queryRaw) {
|
|
559
|
-
const query = queryRaw || ''
|
|
560
|
-
const caseSensitive = Boolean(caseSensitiveInput.checked)
|
|
561
|
-
if (!query) return { active: false, query, caseSensitive, test: () => true }
|
|
562
|
-
|
|
563
|
-
const needle = caseSensitive ? query : query.toLowerCase()
|
|
564
|
-
return {
|
|
565
|
-
active: true,
|
|
566
|
-
query,
|
|
567
|
-
caseSensitive,
|
|
568
|
-
test: (text) => {
|
|
569
|
-
const source = String(text ?? '')
|
|
570
|
-
const hay = caseSensitive ? source : source.toLowerCase()
|
|
571
|
-
return hay.includes(needle)
|
|
572
|
-
},
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
|
-
|
|
576
674
|
function el(tag, className, text) {
|
|
577
675
|
const node = document.createElement(tag)
|
|
578
676
|
if (className) node.className = className
|
|
@@ -619,6 +717,35 @@
|
|
|
619
717
|
return row
|
|
620
718
|
}
|
|
621
719
|
|
|
720
|
+
function sourceHref(source) {
|
|
721
|
+
if (!source || !source.file) return undefined
|
|
722
|
+
const normalizedPath = String(source.file).replace(/\\/g, '/')
|
|
723
|
+
const prefix = normalizedPath.startsWith('/') ? 'file://' : 'file:///'
|
|
724
|
+
return `${prefix}${encodeURI(normalizedPath)}`
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
function createSourceRow(key, source, engine) {
|
|
728
|
+
const box = el('div', 'kv')
|
|
729
|
+
box.appendChild(el('div', 'k', key))
|
|
730
|
+
const valueNode = el('div', 'v mono')
|
|
731
|
+
|
|
732
|
+
if (!source || !source.file) {
|
|
733
|
+
setHighlighted(valueNode, '—', engine)
|
|
734
|
+
box.appendChild(valueNode)
|
|
735
|
+
return box
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
const href = sourceHref(source)
|
|
739
|
+
const link = document.createElement('a')
|
|
740
|
+
link.href = href
|
|
741
|
+
link.target = '_blank'
|
|
742
|
+
link.rel = 'noopener noreferrer'
|
|
743
|
+
link.textContent = `${source.file}:${source.line}:${source.column}`
|
|
744
|
+
valueNode.appendChild(link)
|
|
745
|
+
box.appendChild(valueNode)
|
|
746
|
+
return box
|
|
747
|
+
}
|
|
748
|
+
|
|
622
749
|
function splitFlatSchemaBySection(flatSchema) {
|
|
623
750
|
const result = {
|
|
624
751
|
params: {},
|
|
@@ -727,33 +854,44 @@
|
|
|
727
854
|
return row
|
|
728
855
|
}
|
|
729
856
|
|
|
730
|
-
function renderSeparatedSchemas(flatSchema, engine) {
|
|
857
|
+
function renderSeparatedSchemas(flatSchema, engine, selectedIds) {
|
|
858
|
+
if (!flatSchema || typeof flatSchema !== 'object') return null
|
|
731
859
|
const section = el('div', 'section')
|
|
732
860
|
section.appendChild(el('h3', '', 'Schemas (separated by section)'))
|
|
733
861
|
|
|
734
862
|
const grouped = splitFlatSchemaBySection(flatSchema)
|
|
863
|
+
let hasAnySchemaEntries = false
|
|
864
|
+
const limitToMatchedRows = schemaRowsMatchOnlyInput.checked && engine.active
|
|
735
865
|
|
|
736
866
|
SCHEMA_SECTIONS.forEach((sectionName) => {
|
|
867
|
+
const rawEntries = grouped[sectionName]
|
|
868
|
+
if (!rawEntries || Object.keys(rawEntries).length === 0) return
|
|
869
|
+
|
|
870
|
+
const entries = limitToMatchedRows
|
|
871
|
+
? Object.fromEntries(
|
|
872
|
+
Object.entries(rawEntries).filter(([fullPath, info]) =>
|
|
873
|
+
schemaEntryMatchesActiveFilter(sectionName, fullPath, info, engine, selectedIds),
|
|
874
|
+
),
|
|
875
|
+
)
|
|
876
|
+
: rawEntries
|
|
877
|
+
if (Object.keys(entries).length === 0) return
|
|
878
|
+
|
|
879
|
+
hasAnySchemaEntries = true
|
|
737
880
|
const block = el('div', 'schema-block')
|
|
738
881
|
const header = el('div', 'schema-header mono')
|
|
739
882
|
setHighlighted(header, sectionName, engine)
|
|
740
883
|
block.appendChild(header)
|
|
741
884
|
|
|
742
|
-
const
|
|
743
|
-
|
|
744
|
-
block.appendChild(el('div', 'empty', 'No entries'))
|
|
745
|
-
} else {
|
|
746
|
-
const tree = buildSchemaTree(entries, sectionName)
|
|
747
|
-
block.appendChild(renderTreeNode(tree, engine, true))
|
|
748
|
-
}
|
|
885
|
+
const tree = buildSchemaTree(entries, sectionName)
|
|
886
|
+
block.appendChild(renderTreeNode(tree, engine, true))
|
|
749
887
|
|
|
750
888
|
section.appendChild(block)
|
|
751
889
|
})
|
|
752
890
|
|
|
753
|
-
return section
|
|
891
|
+
return hasAnySchemaEntries ? section : null
|
|
754
892
|
}
|
|
755
893
|
|
|
756
|
-
function renderLeaf(leaf, engine) {
|
|
894
|
+
function renderLeaf(leaf, engine, selectedIds) {
|
|
757
895
|
const details = el('details', 'leaf')
|
|
758
896
|
const summary = el('summary')
|
|
759
897
|
setHighlighted(summary, `${String(leaf.method || '').toUpperCase()} ${leaf.path || ''}`, engine)
|
|
@@ -765,60 +903,43 @@
|
|
|
765
903
|
|
|
766
904
|
const overview = el('div', 'section')
|
|
767
905
|
overview.appendChild(el('h3', '', 'Overview'))
|
|
768
|
-
const
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
docGrid.appendChild(kv('description', cfg.description, engine))
|
|
785
|
-
docs.appendChild(docGrid)
|
|
786
|
-
|
|
787
|
-
const tagsRow = el('div', 'chips')
|
|
788
|
-
;(cfg.tags || []).forEach((tag) => {
|
|
789
|
-
const chip = el('span', 'chip')
|
|
790
|
-
setHighlighted(chip, tag, engine)
|
|
791
|
-
tagsRow.appendChild(chip)
|
|
792
|
-
})
|
|
793
|
-
if ((cfg.tags || []).length === 0) {
|
|
794
|
-
tagsRow.appendChild(el('span', 'empty', 'No tags'))
|
|
906
|
+
const topGrid = el('div', 'grid-3')
|
|
907
|
+
topGrid.appendChild(kv('group', cfg.docsGroup, engine))
|
|
908
|
+
topGrid.appendChild(
|
|
909
|
+
kv('tags', cfg.tags && cfg.tags.length > 0 ? cfg.tags.join(', ') : undefined, engine),
|
|
910
|
+
)
|
|
911
|
+
topGrid.appendChild(kv('stability', cfg.stability, engine))
|
|
912
|
+
overview.appendChild(topGrid)
|
|
913
|
+
overview.appendChild(kv('summary', cfg.summary, engine))
|
|
914
|
+
overview.appendChild(kv('description', cfg.description, engine))
|
|
915
|
+
|
|
916
|
+
const iconRow = el('div', 'icon-row')
|
|
917
|
+
if (cfg.feed) {
|
|
918
|
+
const feed = el('span', 'icon-badge')
|
|
919
|
+
feed.title = 'Feed'
|
|
920
|
+
setHighlighted(feed, 'F', engine)
|
|
921
|
+
iconRow.appendChild(feed)
|
|
795
922
|
}
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
})
|
|
923
|
+
if (cfg.deprecated) {
|
|
924
|
+
const deprecated = el('span', 'icon-badge warn')
|
|
925
|
+
deprecated.title = 'Deprecated'
|
|
926
|
+
setHighlighted(deprecated, 'D', engine)
|
|
927
|
+
iconRow.appendChild(deprecated)
|
|
802
928
|
}
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
schemaGrid.appendChild(renderSchemaSummary('output', schemaObj.output, engine))
|
|
814
|
-
schemaGrid.appendChild(renderSchemaSummary('outputMeta', schemaObj.outputMeta, engine))
|
|
815
|
-
schemaGrid.appendChild(renderSchemaSummary('queryExtension', schemaObj.queryExtension, engine))
|
|
816
|
-
schemas.appendChild(schemaGrid)
|
|
817
|
-
content.appendChild(schemas)
|
|
929
|
+
if (cfg.docsHidden) {
|
|
930
|
+
const hidden = el('span', 'icon-badge warn')
|
|
931
|
+
hidden.title = 'Hidden'
|
|
932
|
+
setHighlighted(hidden, 'H', engine)
|
|
933
|
+
iconRow.appendChild(hidden)
|
|
934
|
+
}
|
|
935
|
+
if (iconRow.childNodes.length > 0) {
|
|
936
|
+
overview.appendChild(iconRow)
|
|
937
|
+
}
|
|
938
|
+
content.appendChild(overview)
|
|
818
939
|
|
|
819
940
|
const files = el('div', 'section')
|
|
820
|
-
files.appendChild(el('h3', '', 'Body Files'))
|
|
821
941
|
if (Array.isArray(cfg.bodyFiles) && cfg.bodyFiles.length > 0) {
|
|
942
|
+
files.appendChild(el('h3', '', 'Body Files'))
|
|
822
943
|
const chips = el('div', 'chips')
|
|
823
944
|
cfg.bodyFiles.forEach((file) => {
|
|
824
945
|
const chip = el('span', 'chip ok')
|
|
@@ -826,12 +947,38 @@
|
|
|
826
947
|
chips.appendChild(chip)
|
|
827
948
|
})
|
|
828
949
|
files.appendChild(chips)
|
|
829
|
-
|
|
830
|
-
|
|
950
|
+
content.appendChild(files)
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
const sourceByLeaf = state.payload?.sourceByLeaf || {}
|
|
954
|
+
const source = sourceByLeaf[leaf.key]
|
|
955
|
+
if (source) {
|
|
956
|
+
const sourceSection = el('div', 'section')
|
|
957
|
+
sourceSection.appendChild(el('h3', '', 'Source'))
|
|
958
|
+
sourceSection.appendChild(createSourceRow('definition', source.definition, engine))
|
|
959
|
+
|
|
960
|
+
const schemaSources = source.schemas || {}
|
|
961
|
+
const schemaEntries = Object.entries(schemaSources)
|
|
962
|
+
if (schemaEntries.length > 0) {
|
|
963
|
+
const schemaGrid = el('div', 'grid-2')
|
|
964
|
+
schemaEntries.forEach(([schemaName, schemaSource]) => {
|
|
965
|
+
const display = schemaSource?.sourceName
|
|
966
|
+
? `${schemaName}: ${schemaSource.sourceName}`
|
|
967
|
+
: schemaSource?.tag
|
|
968
|
+
? `${schemaName}: ${schemaSource.tag}`
|
|
969
|
+
: schemaName
|
|
970
|
+
schemaGrid.appendChild(createSourceRow(display, schemaSource, engine))
|
|
971
|
+
})
|
|
972
|
+
sourceSection.appendChild(schemaGrid)
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
content.appendChild(sourceSection)
|
|
831
976
|
}
|
|
832
|
-
content.appendChild(files)
|
|
833
977
|
|
|
834
|
-
|
|
978
|
+
const separatedSchemas = renderSeparatedSchemas(flatSchema, engine, selectedIds)
|
|
979
|
+
if (separatedSchemas) {
|
|
980
|
+
content.appendChild(separatedSchemas)
|
|
981
|
+
}
|
|
835
982
|
|
|
836
983
|
details.appendChild(content)
|
|
837
984
|
return details
|
|
@@ -842,9 +989,6 @@
|
|
|
842
989
|
caseSensitive: caseSensitiveInput.checked,
|
|
843
990
|
regex: regexSearchInput.checked,
|
|
844
991
|
})
|
|
845
|
-
const typeEngine = createTypeSearchEngine(typeFilterInput.value.trim())
|
|
846
|
-
const hasEnumOnly = Boolean(hasEnumOnlyInput.checked)
|
|
847
|
-
const typeMatchMode = typeMatchModeInput.value === 'exact' ? 'exact' : 'contains'
|
|
848
992
|
|
|
849
993
|
if (engine.error) {
|
|
850
994
|
statusEl.textContent = `Invalid regex: ${engine.error}`
|
|
@@ -858,11 +1002,7 @@
|
|
|
858
1002
|
}
|
|
859
1003
|
|
|
860
1004
|
const selectedIds = selectedFieldIds()
|
|
861
|
-
const filtered = state.leaves.filter(
|
|
862
|
-
(leaf) =>
|
|
863
|
-
matchesLeaf(leaf, engine, selectedIds) &&
|
|
864
|
-
matchesTypeFilter(leaf, typeEngine, typeMatchMode, hasEnumOnly),
|
|
865
|
-
)
|
|
1005
|
+
const filtered = state.leaves.filter((leaf) => matchesLeaf(leaf, engine, selectedIds))
|
|
866
1006
|
|
|
867
1007
|
statusEl.textContent = `${filtered.length} / ${state.leaves.length} routes matched.`
|
|
868
1008
|
resultsEl.innerHTML = ''
|
|
@@ -875,7 +1015,7 @@
|
|
|
875
1015
|
}
|
|
876
1016
|
|
|
877
1017
|
filtered.forEach((leaf) => {
|
|
878
|
-
resultsEl.appendChild(renderLeaf(leaf, engine))
|
|
1018
|
+
resultsEl.appendChild(renderLeaf(leaf, engine, selectedIds))
|
|
879
1019
|
})
|
|
880
1020
|
syncFilterStateToUrl()
|
|
881
1021
|
}
|
|
@@ -906,11 +1046,10 @@
|
|
|
906
1046
|
|
|
907
1047
|
function resetFiltersToDefault() {
|
|
908
1048
|
searchInput.value = ''
|
|
909
|
-
typeFilterInput.value = ''
|
|
910
1049
|
caseSensitiveInput.checked = false
|
|
911
1050
|
regexSearchInput.checked = false
|
|
912
|
-
hasEnumOnlyInput.checked = false
|
|
913
1051
|
typeMatchModeInput.value = 'contains'
|
|
1052
|
+
schemaRowsMatchOnlyInput.checked = false
|
|
914
1053
|
setFieldSelection(new Set(SEARCH_FIELDS.map((field) => field.id)))
|
|
915
1054
|
}
|
|
916
1055
|
|
|
@@ -919,14 +1058,12 @@
|
|
|
919
1058
|
const chips = []
|
|
920
1059
|
|
|
921
1060
|
const searchValue = searchInput.value.trim()
|
|
922
|
-
const typeValue = typeFilterInput.value.trim()
|
|
923
1061
|
|
|
924
1062
|
if (searchValue) chips.push(`search: ${searchValue}`)
|
|
925
|
-
if (typeValue) chips.push(`type: ${typeValue}`)
|
|
926
1063
|
if (typeMatchModeInput.value === 'exact') chips.push('type mode: exact')
|
|
1064
|
+
if (schemaRowsMatchOnlyInput.checked) chips.push('schema rows: matched only')
|
|
927
1065
|
if (caseSensitiveInput.checked) chips.push('case sensitive')
|
|
928
1066
|
if (regexSearchInput.checked) chips.push('regex')
|
|
929
|
-
if (hasEnumOnlyInput.checked) chips.push('has enum only')
|
|
930
1067
|
if (hasRegexError) chips.push('regex error')
|
|
931
1068
|
|
|
932
1069
|
const allIds = SEARCH_FIELDS.map((field) => field.id)
|
|
@@ -949,11 +1086,10 @@
|
|
|
949
1086
|
function collectFilterState() {
|
|
950
1087
|
return {
|
|
951
1088
|
search: searchInput.value,
|
|
952
|
-
typeFilter: typeFilterInput.value,
|
|
953
1089
|
caseSensitive: caseSensitiveInput.checked,
|
|
954
1090
|
regex: regexSearchInput.checked,
|
|
955
|
-
hasEnumOnly: hasEnumOnlyInput.checked,
|
|
956
1091
|
typeMatchMode: typeMatchModeInput.value === 'exact' ? 'exact' : 'contains',
|
|
1092
|
+
schemaRowsMatchOnly: schemaRowsMatchOnlyInput.checked,
|
|
957
1093
|
selectedFields: selectedFieldIds(),
|
|
958
1094
|
}
|
|
959
1095
|
}
|
|
@@ -980,13 +1116,12 @@
|
|
|
980
1116
|
const parsed = JSON.parse(decodeURIComponent(raw))
|
|
981
1117
|
isHydratingFromUrl = true
|
|
982
1118
|
if (typeof parsed.search === 'string') searchInput.value = parsed.search
|
|
983
|
-
if (typeof parsed.typeFilter === 'string') typeFilterInput.value = parsed.typeFilter
|
|
984
1119
|
caseSensitiveInput.checked = Boolean(parsed.caseSensitive)
|
|
985
1120
|
regexSearchInput.checked = Boolean(parsed.regex)
|
|
986
|
-
hasEnumOnlyInput.checked = Boolean(parsed.hasEnumOnly)
|
|
987
1121
|
if (parsed.typeMatchMode === 'exact' || parsed.typeMatchMode === 'contains') {
|
|
988
1122
|
typeMatchModeInput.value = parsed.typeMatchMode
|
|
989
1123
|
}
|
|
1124
|
+
schemaRowsMatchOnlyInput.checked = Boolean(parsed.schemaRowsMatchOnly)
|
|
990
1125
|
|
|
991
1126
|
if (Array.isArray(parsed.selectedFields)) {
|
|
992
1127
|
const allowed = new Set(parsed.selectedFields)
|
|
@@ -1038,11 +1173,10 @@
|
|
|
1038
1173
|
})
|
|
1039
1174
|
|
|
1040
1175
|
searchInput.addEventListener('input', renderResults)
|
|
1041
|
-
typeFilterInput.addEventListener('input', renderResults)
|
|
1042
1176
|
caseSensitiveInput.addEventListener('change', renderResults)
|
|
1043
1177
|
regexSearchInput.addEventListener('change', renderResults)
|
|
1044
|
-
hasEnumOnlyInput.addEventListener('change', renderResults)
|
|
1045
1178
|
typeMatchModeInput.addEventListener('change', renderResults)
|
|
1179
|
+
schemaRowsMatchOnlyInput.addEventListener('change', renderResults)
|
|
1046
1180
|
|
|
1047
1181
|
selectAllFieldsBtn.addEventListener('click', () =>
|
|
1048
1182
|
setFieldSelection(new Set(SEARCH_FIELDS.map((field) => field.id))),
|