@emeryld/rrroutes-contract 2.7.11 → 2.7.13
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 +1 -1
- package/dist/export/flattenSchema.d.ts +1 -0
- package/dist/index.cjs +22 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +22 -7
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/tools/finalized-leaves-viewer.html +436 -159
|
@@ -50,22 +50,68 @@
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
.controls {
|
|
53
|
+
display: grid;
|
|
54
|
+
gap: 14px;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.primary-row {
|
|
53
58
|
display: grid;
|
|
54
59
|
gap: 10px;
|
|
60
|
+
grid-template-columns: minmax(220px, 0.9fr) minmax(300px, 1.4fr) minmax(220px, 1fr);
|
|
61
|
+
align-items: end;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.control-block {
|
|
65
|
+
display: grid;
|
|
66
|
+
gap: 6px;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.control-label {
|
|
70
|
+
font-size: 12px;
|
|
71
|
+
color: var(--muted);
|
|
55
72
|
}
|
|
56
73
|
|
|
57
|
-
.
|
|
74
|
+
.quick-toggles {
|
|
58
75
|
display: flex;
|
|
59
76
|
flex-wrap: wrap;
|
|
60
77
|
gap: 8px;
|
|
78
|
+
align-items: center;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.scope-row {
|
|
82
|
+
border-top: 1px solid var(--border);
|
|
83
|
+
padding-top: 12px;
|
|
84
|
+
display: grid;
|
|
85
|
+
gap: 10px;
|
|
61
86
|
}
|
|
62
87
|
|
|
63
|
-
.
|
|
88
|
+
.scope-actions {
|
|
64
89
|
display: flex;
|
|
65
90
|
flex-wrap: wrap;
|
|
66
91
|
gap: 8px;
|
|
67
92
|
}
|
|
68
93
|
|
|
94
|
+
.scope-groups {
|
|
95
|
+
display: grid;
|
|
96
|
+
gap: 10px;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.scope-group {
|
|
100
|
+
display: grid;
|
|
101
|
+
gap: 6px;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.scope-group-title {
|
|
105
|
+
font-size: 12px;
|
|
106
|
+
color: var(--muted);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.scope-group-chips {
|
|
110
|
+
display: flex;
|
|
111
|
+
flex-wrap: wrap;
|
|
112
|
+
gap: 6px;
|
|
113
|
+
}
|
|
114
|
+
|
|
69
115
|
.field-item {
|
|
70
116
|
display: inline-flex;
|
|
71
117
|
align-items: center;
|
|
@@ -86,7 +132,7 @@
|
|
|
86
132
|
|
|
87
133
|
button {
|
|
88
134
|
border: 1px solid var(--border);
|
|
89
|
-
border-radius:
|
|
135
|
+
border-radius: 6px;
|
|
90
136
|
padding: 7px 10px;
|
|
91
137
|
font: inherit;
|
|
92
138
|
background: var(--surface-2);
|
|
@@ -190,12 +236,82 @@
|
|
|
190
236
|
background: var(--surface-2);
|
|
191
237
|
}
|
|
192
238
|
|
|
239
|
+
.chip-btn {
|
|
240
|
+
cursor: pointer;
|
|
241
|
+
}
|
|
242
|
+
|
|
193
243
|
.chip.ok {
|
|
194
244
|
border-color: #b5e4c8;
|
|
195
245
|
color: var(--ok);
|
|
196
246
|
background: #effbf4;
|
|
197
247
|
}
|
|
198
248
|
|
|
249
|
+
.pill-toggle {
|
|
250
|
+
border: 1px solid var(--border);
|
|
251
|
+
border-radius: 999px;
|
|
252
|
+
padding: 6px 12px;
|
|
253
|
+
font-size: 12px;
|
|
254
|
+
background: var(--surface-2);
|
|
255
|
+
color: var(--text);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.pill-toggle[aria-pressed='true'] {
|
|
259
|
+
border-color: var(--accent);
|
|
260
|
+
background: rgba(167, 100, 211, 0.25);
|
|
261
|
+
color: #f0d8ff;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
.scope-action {
|
|
265
|
+
font-size: 12px;
|
|
266
|
+
padding: 5px 10px;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.field-chip {
|
|
270
|
+
font-size: 12px;
|
|
271
|
+
padding: 5px 10px;
|
|
272
|
+
border-radius: 999px;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.field-chip[aria-pressed='true'] {
|
|
276
|
+
border-color: var(--schema-accent);
|
|
277
|
+
background: rgba(251, 189, 35, 0.22);
|
|
278
|
+
color: #ffe7aa;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
.advanced-panel {
|
|
282
|
+
border-top: 1px solid var(--border);
|
|
283
|
+
padding-top: 10px;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
.advanced-panel > summary {
|
|
287
|
+
color: var(--text);
|
|
288
|
+
font-size: 13px;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
.advanced-content {
|
|
292
|
+
margin-top: 10px;
|
|
293
|
+
display: flex;
|
|
294
|
+
flex-wrap: wrap;
|
|
295
|
+
gap: 12px;
|
|
296
|
+
align-items: center;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
.advanced-content .field-item {
|
|
300
|
+
padding: 0;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.active-filters-row {
|
|
304
|
+
border-top: 1px solid var(--border);
|
|
305
|
+
padding-top: 10px;
|
|
306
|
+
display: grid;
|
|
307
|
+
gap: 6px;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
.active-filters-title {
|
|
311
|
+
color: var(--muted);
|
|
312
|
+
font-size: 12px;
|
|
313
|
+
}
|
|
314
|
+
|
|
199
315
|
.icon-row {
|
|
200
316
|
display: flex;
|
|
201
317
|
gap: 6px;
|
|
@@ -214,6 +330,16 @@
|
|
|
214
330
|
background: var(--surface-2);
|
|
215
331
|
}
|
|
216
332
|
|
|
333
|
+
.icon-badge.feed {
|
|
334
|
+
width: auto;
|
|
335
|
+
min-width: 46px;
|
|
336
|
+
padding: 2px 8px;
|
|
337
|
+
font-weight: 700;
|
|
338
|
+
border-color: var(--schema-accent);
|
|
339
|
+
color: var(--schema-accent);
|
|
340
|
+
background: rgba(251, 189, 35, 0.15);
|
|
341
|
+
}
|
|
342
|
+
|
|
217
343
|
.icon-badge.warn {
|
|
218
344
|
border-color: #f2d5d5;
|
|
219
345
|
color: #a02424;
|
|
@@ -329,6 +455,11 @@
|
|
|
329
455
|
}
|
|
330
456
|
|
|
331
457
|
@media (max-width: 720px) {
|
|
458
|
+
.primary-row {
|
|
459
|
+
grid-template-columns: 1fr;
|
|
460
|
+
align-items: stretch;
|
|
461
|
+
}
|
|
462
|
+
|
|
332
463
|
.grid-3 {
|
|
333
464
|
grid-template-columns: 1fr;
|
|
334
465
|
}
|
|
@@ -339,47 +470,65 @@
|
|
|
339
470
|
<div class="wrap">
|
|
340
471
|
<h1>Finalized Leaves Viewer</h1>
|
|
341
472
|
<div class="card controls">
|
|
342
|
-
<
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
<label>
|
|
348
|
-
Search text:
|
|
349
|
-
<input id="searchInput" type="text" placeholder="Type to search..." />
|
|
350
|
-
</label>
|
|
351
|
-
|
|
352
|
-
<div class="field-row">
|
|
353
|
-
<label class="field-item">
|
|
354
|
-
<input id="caseSensitive" type="checkbox" />
|
|
355
|
-
<span>case sensitive</span>
|
|
356
|
-
</label>
|
|
357
|
-
<label class="field-item">
|
|
358
|
-
<input id="regexSearch" type="checkbox" />
|
|
359
|
-
<span>regex</span>
|
|
473
|
+
<div class="primary-row">
|
|
474
|
+
<label class="control-block">
|
|
475
|
+
<span class="control-label">Load export JSON file</span>
|
|
476
|
+
<input id="fileInput" type="file" accept="application/json,.json" />
|
|
360
477
|
</label>
|
|
361
|
-
<label class="
|
|
362
|
-
<span>
|
|
363
|
-
<
|
|
364
|
-
<option value="contains" selected>contains</option>
|
|
365
|
-
<option value="exact">exact</option>
|
|
366
|
-
</select>
|
|
367
|
-
</label>
|
|
368
|
-
<label class="field-item">
|
|
369
|
-
<input id="schemaRowsMatchOnly" type="checkbox" />
|
|
370
|
-
<span>schema rows match filter</span>
|
|
478
|
+
<label class="control-block">
|
|
479
|
+
<span class="control-label">Search text</span>
|
|
480
|
+
<input id="searchInput" type="text" placeholder="Type to search..." />
|
|
371
481
|
</label>
|
|
482
|
+
<div class="control-block">
|
|
483
|
+
<span class="control-label">Quick filters</span>
|
|
484
|
+
<div class="quick-toggles">
|
|
485
|
+
<button id="caseSensitive" class="pill-toggle" type="button" aria-pressed="false">
|
|
486
|
+
Case sensitive
|
|
487
|
+
</button>
|
|
488
|
+
<button id="regexSearch" class="pill-toggle" type="button" aria-pressed="false">
|
|
489
|
+
Regex
|
|
490
|
+
</button>
|
|
491
|
+
</div>
|
|
492
|
+
</div>
|
|
493
|
+
</div>
|
|
494
|
+
|
|
495
|
+
<div class="scope-row">
|
|
496
|
+
<div class="scope-actions">
|
|
497
|
+
<button id="selectAllFields" class="scope-action" type="button">All</button>
|
|
498
|
+
<button id="clearAllFields" class="scope-action" type="button">None</button>
|
|
499
|
+
<button id="coreFields" class="scope-action" type="button">Core</button>
|
|
500
|
+
<button id="schemasOnlyFields" class="scope-action" type="button">Schema</button>
|
|
501
|
+
<button id="sourceOnlyFields" class="scope-action" type="button">Source</button>
|
|
502
|
+
</div>
|
|
503
|
+
<div id="fieldChipGroups" class="scope-groups"></div>
|
|
372
504
|
</div>
|
|
373
505
|
|
|
374
|
-
<
|
|
375
|
-
|
|
376
|
-
<
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
506
|
+
<details class="advanced-panel">
|
|
507
|
+
<summary>Advanced filters</summary>
|
|
508
|
+
<div class="advanced-content">
|
|
509
|
+
<label class="field-item">
|
|
510
|
+
<span>type match</span>
|
|
511
|
+
<select id="typeMatchMode">
|
|
512
|
+
<option value="contains" selected>contains</option>
|
|
513
|
+
<option value="exact">exact</option>
|
|
514
|
+
</select>
|
|
515
|
+
</label>
|
|
516
|
+
<button
|
|
517
|
+
id="schemaRowsMatchOnly"
|
|
518
|
+
class="pill-toggle"
|
|
519
|
+
type="button"
|
|
520
|
+
aria-pressed="false"
|
|
521
|
+
>
|
|
522
|
+
Schema rows match only
|
|
523
|
+
</button>
|
|
524
|
+
<button id="resetFilters" type="button">Reset filters</button>
|
|
525
|
+
</div>
|
|
526
|
+
</details>
|
|
527
|
+
|
|
528
|
+
<div class="active-filters-row">
|
|
529
|
+
<div class="active-filters-title">Active filters</div>
|
|
530
|
+
<div id="activeFilterChips" class="chips filters"></div>
|
|
381
531
|
</div>
|
|
382
|
-
<div id="activeFilterChips" class="chips filters"></div>
|
|
383
532
|
|
|
384
533
|
<div id="status" class="meta">Load a JSON export to begin.</div>
|
|
385
534
|
</div>
|
|
@@ -461,24 +610,56 @@
|
|
|
461
610
|
|
|
462
611
|
const SCHEMA_SECTIONS = ['params', 'query', 'body', 'output']
|
|
463
612
|
const SCHEMA_FIELD_IDS = new Set(SCHEMA_SECTIONS)
|
|
464
|
-
const
|
|
465
|
-
|
|
613
|
+
const SOURCE_FIELD_IDS = new Set(['sourceDefinition', 'sourceSchemas'])
|
|
614
|
+
const SCHEMA_SCOPE_FIELD_IDS = new Set([...SCHEMA_SECTIONS, 'types'])
|
|
615
|
+
const CORE_FIELD_IDS = new Set(
|
|
616
|
+
SEARCH_FIELDS.map((field) => field.id).filter(
|
|
617
|
+
(id) => !SCHEMA_SCOPE_FIELD_IDS.has(id) && !SOURCE_FIELD_IDS.has(id),
|
|
618
|
+
),
|
|
466
619
|
)
|
|
620
|
+
const FIELD_GROUPS = [
|
|
621
|
+
{
|
|
622
|
+
id: 'core',
|
|
623
|
+
label: 'Core fields',
|
|
624
|
+
fieldIds: SEARCH_FIELDS.filter((field) => CORE_FIELD_IDS.has(field.id)).map(
|
|
625
|
+
(field) => field.id,
|
|
626
|
+
),
|
|
627
|
+
},
|
|
628
|
+
{
|
|
629
|
+
id: 'schema',
|
|
630
|
+
label: 'Schema fields',
|
|
631
|
+
fieldIds: SEARCH_FIELDS.filter((field) => SCHEMA_SCOPE_FIELD_IDS.has(field.id)).map(
|
|
632
|
+
(field) => field.id,
|
|
633
|
+
),
|
|
634
|
+
},
|
|
635
|
+
{
|
|
636
|
+
id: 'source',
|
|
637
|
+
label: 'Source fields',
|
|
638
|
+
fieldIds: SEARCH_FIELDS.filter((field) => SOURCE_FIELD_IDS.has(field.id)).map(
|
|
639
|
+
(field) => field.id,
|
|
640
|
+
),
|
|
641
|
+
},
|
|
642
|
+
]
|
|
467
643
|
|
|
468
|
-
const state = {
|
|
644
|
+
const state = {
|
|
645
|
+
payload: null,
|
|
646
|
+
leaves: [],
|
|
647
|
+
selectedFieldIds: new Set(SEARCH_FIELDS.map((field) => field.id)),
|
|
648
|
+
}
|
|
469
649
|
|
|
470
650
|
const fileInput = document.getElementById('fileInput')
|
|
471
651
|
const searchInput = document.getElementById('searchInput')
|
|
472
|
-
const
|
|
473
|
-
const
|
|
652
|
+
const caseSensitiveToggle = document.getElementById('caseSensitive')
|
|
653
|
+
const regexSearchToggle = document.getElementById('regexSearch')
|
|
474
654
|
const typeMatchModeInput = document.getElementById('typeMatchMode')
|
|
475
|
-
const
|
|
476
|
-
const
|
|
655
|
+
const schemaRowsMatchOnlyToggle = document.getElementById('schemaRowsMatchOnly')
|
|
656
|
+
const fieldChipGroups = document.getElementById('fieldChipGroups')
|
|
477
657
|
const activeFilterChips = document.getElementById('activeFilterChips')
|
|
478
658
|
const selectAllFieldsBtn = document.getElementById('selectAllFields')
|
|
479
659
|
const clearAllFieldsBtn = document.getElementById('clearAllFields')
|
|
660
|
+
const coreFieldsBtn = document.getElementById('coreFields')
|
|
480
661
|
const schemasOnlyFieldsBtn = document.getElementById('schemasOnlyFields')
|
|
481
|
-
const
|
|
662
|
+
const sourceOnlyFieldsBtn = document.getElementById('sourceOnlyFields')
|
|
482
663
|
const resetFiltersBtn = document.getElementById('resetFilters')
|
|
483
664
|
const statusEl = document.getElementById('status')
|
|
484
665
|
const resultsEl = document.getElementById('results')
|
|
@@ -499,6 +680,21 @@
|
|
|
499
680
|
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
500
681
|
}
|
|
501
682
|
|
|
683
|
+
function isPressed(button) {
|
|
684
|
+
return button?.getAttribute('aria-pressed') === 'true'
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
function setPressed(button, pressed) {
|
|
688
|
+
if (!button) return
|
|
689
|
+
button.setAttribute('aria-pressed', pressed ? 'true' : 'false')
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
function togglePressed(button) {
|
|
693
|
+
const next = !isPressed(button)
|
|
694
|
+
setPressed(button, next)
|
|
695
|
+
return next
|
|
696
|
+
}
|
|
697
|
+
|
|
502
698
|
function createSearchEngine(queryRaw, options) {
|
|
503
699
|
const query = queryRaw || ''
|
|
504
700
|
const caseSensitive = Boolean(options.caseSensitive)
|
|
@@ -697,13 +893,6 @@
|
|
|
697
893
|
return matched
|
|
698
894
|
}
|
|
699
895
|
|
|
700
|
-
function selectedFieldIds() {
|
|
701
|
-
return SEARCH_FIELDS.filter((field) => {
|
|
702
|
-
const input = document.getElementById(`field-${field.id}`)
|
|
703
|
-
return Boolean(input && input.checked)
|
|
704
|
-
}).map((field) => field.id)
|
|
705
|
-
}
|
|
706
|
-
|
|
707
896
|
function matchesLeaf(leaf, engine, selectedIds) {
|
|
708
897
|
if (!engine.active) return true
|
|
709
898
|
if (selectedIds.length === 0) return false
|
|
@@ -789,34 +978,24 @@
|
|
|
789
978
|
return `vscode://file/${encodeURI(vscodePath)}:${line}:${column}`
|
|
790
979
|
}
|
|
791
980
|
|
|
792
|
-
function
|
|
793
|
-
return ''
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
function createSourceRow(key, source, engine) {
|
|
981
|
+
function createSourceRow(label, source, engine) {
|
|
797
982
|
const box = el('div', 'kv')
|
|
798
|
-
const
|
|
799
|
-
const valueNode = el('div', 'v mono')
|
|
983
|
+
const labelNode = el('div', 'v mono')
|
|
800
984
|
|
|
801
985
|
if (!source || !source.file) {
|
|
802
|
-
setHighlighted(
|
|
803
|
-
box.appendChild(
|
|
804
|
-
setHighlighted(valueNode, '—', engine)
|
|
805
|
-
box.appendChild(valueNode)
|
|
986
|
+
setHighlighted(labelNode, label, engine)
|
|
987
|
+
box.appendChild(labelNode)
|
|
806
988
|
return box
|
|
807
989
|
}
|
|
808
990
|
|
|
809
991
|
const href = sourceHref(source)
|
|
810
|
-
const
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
setHighlighted(valueNode, sourceDisplay(source), engine)
|
|
818
|
-
box.appendChild(keyNode)
|
|
819
|
-
box.appendChild(valueNode)
|
|
992
|
+
const link = document.createElement('a')
|
|
993
|
+
link.href = href
|
|
994
|
+
link.target = '_blank'
|
|
995
|
+
link.rel = 'noopener noreferrer'
|
|
996
|
+
link.innerHTML = engine.highlight(label)
|
|
997
|
+
labelNode.appendChild(link)
|
|
998
|
+
box.appendChild(labelNode)
|
|
820
999
|
return box
|
|
821
1000
|
}
|
|
822
1001
|
|
|
@@ -841,6 +1020,33 @@
|
|
|
841
1020
|
return result
|
|
842
1021
|
}
|
|
843
1022
|
|
|
1023
|
+
const SCHEMA_SOURCE_KEYS_BY_SECTION = {
|
|
1024
|
+
params: 'paramsSchema',
|
|
1025
|
+
query: 'querySchema',
|
|
1026
|
+
body: 'bodySchema',
|
|
1027
|
+
output: 'outputSchema',
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
function getSchemaSource(source, sectionName) {
|
|
1031
|
+
const schemaKey = SCHEMA_SOURCE_KEYS_BY_SECTION[sectionName]
|
|
1032
|
+
if (!schemaKey || !source?.schemas || typeof source.schemas !== 'object') {
|
|
1033
|
+
return {
|
|
1034
|
+
schemaKey,
|
|
1035
|
+
sourceValue: undefined,
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
return {
|
|
1040
|
+
schemaKey,
|
|
1041
|
+
sourceValue: source.schemas[schemaKey],
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
function resolveSchemaSourceLabel(schemaKey, sourceValue) {
|
|
1046
|
+
if (!sourceValue || typeof sourceValue !== 'object') return schemaKey || 'schema'
|
|
1047
|
+
return sourceValue.sourceName || sourceValue.tag || schemaKey || 'schema'
|
|
1048
|
+
}
|
|
1049
|
+
|
|
844
1050
|
function createTreeNode(name = '') {
|
|
845
1051
|
return {
|
|
846
1052
|
name,
|
|
@@ -928,14 +1134,14 @@
|
|
|
928
1134
|
return row
|
|
929
1135
|
}
|
|
930
1136
|
|
|
931
|
-
function renderSeparatedSchemas(flatSchema, engine, selectedIds) {
|
|
1137
|
+
function renderSeparatedSchemas(flatSchema, engine, selectedIds, source) {
|
|
932
1138
|
if (!flatSchema || typeof flatSchema !== 'object') return null
|
|
933
1139
|
const section = el('div', 'section')
|
|
934
1140
|
section.appendChild(el('h3', '', 'Schemas (separated by section)'))
|
|
935
1141
|
|
|
936
1142
|
const grouped = splitFlatSchemaBySection(flatSchema)
|
|
937
1143
|
let hasAnySchemaEntries = false
|
|
938
|
-
const limitToMatchedRows =
|
|
1144
|
+
const limitToMatchedRows = isPressed(schemaRowsMatchOnlyToggle) && engine.active
|
|
939
1145
|
|
|
940
1146
|
SCHEMA_SECTIONS.forEach((sectionName) => {
|
|
941
1147
|
const rawEntries = grouped[sectionName]
|
|
@@ -956,6 +1162,20 @@
|
|
|
956
1162
|
setHighlighted(header, sectionName, engine)
|
|
957
1163
|
block.appendChild(header)
|
|
958
1164
|
|
|
1165
|
+
const schemaSource = getSchemaSource(source, sectionName)
|
|
1166
|
+
if (schemaSource.sourceValue) {
|
|
1167
|
+
block.appendChild(
|
|
1168
|
+
createSourceRow(
|
|
1169
|
+
resolveSchemaSourceLabel(
|
|
1170
|
+
schemaSource.schemaKey || `${sectionName}Schema`,
|
|
1171
|
+
schemaSource.sourceValue,
|
|
1172
|
+
),
|
|
1173
|
+
schemaSource.sourceValue,
|
|
1174
|
+
engine,
|
|
1175
|
+
),
|
|
1176
|
+
)
|
|
1177
|
+
}
|
|
1178
|
+
|
|
959
1179
|
const tree = buildSchemaTree(entries, sectionName)
|
|
960
1180
|
block.appendChild(renderTreeNode(tree, engine, true))
|
|
961
1181
|
|
|
@@ -989,9 +1209,9 @@
|
|
|
989
1209
|
|
|
990
1210
|
const iconRow = el('div', 'icon-row')
|
|
991
1211
|
if (cfg.feed) {
|
|
992
|
-
const feed = el('span', 'icon-badge')
|
|
993
|
-
feed.title = 'Feed'
|
|
994
|
-
setHighlighted(feed, '
|
|
1212
|
+
const feed = el('span', 'icon-badge feed')
|
|
1213
|
+
feed.title = 'Feed endpoint'
|
|
1214
|
+
setHighlighted(feed, 'Feed', engine)
|
|
995
1215
|
iconRow.appendChild(feed)
|
|
996
1216
|
}
|
|
997
1217
|
if (cfg.deprecated) {
|
|
@@ -1026,30 +1246,11 @@
|
|
|
1026
1246
|
|
|
1027
1247
|
const sourceByLeaf = state.payload?.sourceByLeaf || {}
|
|
1028
1248
|
const source = sourceByLeaf[leaf.key]
|
|
1029
|
-
if (source) {
|
|
1030
|
-
|
|
1031
|
-
sourceSection.appendChild(el('h3', '', 'Source'))
|
|
1032
|
-
sourceSection.appendChild(createSourceRow('definition', source.definition, engine))
|
|
1033
|
-
|
|
1034
|
-
const schemaSources = source.schemas || {}
|
|
1035
|
-
const schemaEntries = Object.entries(schemaSources)
|
|
1036
|
-
if (schemaEntries.length > 0) {
|
|
1037
|
-
const schemaGrid = el('div', 'grid-2')
|
|
1038
|
-
schemaEntries.forEach(([schemaName, schemaSource]) => {
|
|
1039
|
-
const display = schemaSource?.sourceName
|
|
1040
|
-
? `${schemaName}: ${schemaSource.sourceName}`
|
|
1041
|
-
: schemaSource?.tag
|
|
1042
|
-
? `${schemaName}: ${schemaSource.tag}`
|
|
1043
|
-
: schemaName
|
|
1044
|
-
schemaGrid.appendChild(createSourceRow(display, schemaSource, engine))
|
|
1045
|
-
})
|
|
1046
|
-
sourceSection.appendChild(schemaGrid)
|
|
1047
|
-
}
|
|
1048
|
-
|
|
1049
|
-
content.appendChild(sourceSection)
|
|
1249
|
+
if (source?.definition) {
|
|
1250
|
+
overview.appendChild(createSourceRow('definition', source.definition, engine))
|
|
1050
1251
|
}
|
|
1051
1252
|
|
|
1052
|
-
const separatedSchemas = renderSeparatedSchemas(flatSchema, engine, selectedIds)
|
|
1253
|
+
const separatedSchemas = renderSeparatedSchemas(flatSchema, engine, selectedIds, source)
|
|
1053
1254
|
if (separatedSchemas) {
|
|
1054
1255
|
content.appendChild(separatedSchemas)
|
|
1055
1256
|
}
|
|
@@ -1060,8 +1261,8 @@
|
|
|
1060
1261
|
|
|
1061
1262
|
function renderResults() {
|
|
1062
1263
|
const engine = createSearchEngine(searchInput.value.trim(), {
|
|
1063
|
-
caseSensitive:
|
|
1064
|
-
regex:
|
|
1264
|
+
caseSensitive: isPressed(caseSensitiveToggle),
|
|
1265
|
+
regex: isPressed(regexSearchToggle),
|
|
1065
1266
|
})
|
|
1066
1267
|
|
|
1067
1268
|
if (engine.error) {
|
|
@@ -1094,65 +1295,136 @@
|
|
|
1094
1295
|
syncFilterStateToUrl()
|
|
1095
1296
|
}
|
|
1096
1297
|
|
|
1097
|
-
function
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
const input = document.createElement('input')
|
|
1102
|
-
input.type = 'checkbox'
|
|
1103
|
-
input.id = `field-${field.id}`
|
|
1104
|
-
input.checked = true
|
|
1105
|
-
input.addEventListener('change', renderResults)
|
|
1106
|
-
label.appendChild(input)
|
|
1107
|
-
label.appendChild(el('span', '', field.label))
|
|
1108
|
-
fieldCheckboxes.appendChild(label)
|
|
1109
|
-
})
|
|
1298
|
+
function selectedFieldIds() {
|
|
1299
|
+
return SEARCH_FIELDS.filter((field) => state.selectedFieldIds.has(field.id)).map(
|
|
1300
|
+
(field) => field.id,
|
|
1301
|
+
)
|
|
1110
1302
|
}
|
|
1111
1303
|
|
|
1112
|
-
function
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1304
|
+
function renderFieldChips() {
|
|
1305
|
+
fieldChipGroups.innerHTML = ''
|
|
1306
|
+
FIELD_GROUPS.forEach((group) => {
|
|
1307
|
+
const groupWrap = el('div', 'scope-group')
|
|
1308
|
+
groupWrap.appendChild(el('div', 'scope-group-title', group.label))
|
|
1309
|
+
const chipsWrap = el('div', 'scope-group-chips')
|
|
1310
|
+
|
|
1311
|
+
group.fieldIds.forEach((fieldId) => {
|
|
1312
|
+
const field = SEARCH_FIELDS.find((item) => item.id === fieldId)
|
|
1313
|
+
if (!field) return
|
|
1314
|
+
const chip = document.createElement('button')
|
|
1315
|
+
chip.type = 'button'
|
|
1316
|
+
chip.className = 'field-chip'
|
|
1317
|
+
chip.textContent = field.label
|
|
1318
|
+
setPressed(chip, state.selectedFieldIds.has(field.id))
|
|
1319
|
+
chip.addEventListener('click', () => {
|
|
1320
|
+
if (state.selectedFieldIds.has(field.id)) {
|
|
1321
|
+
state.selectedFieldIds.delete(field.id)
|
|
1322
|
+
} else {
|
|
1323
|
+
state.selectedFieldIds.add(field.id)
|
|
1324
|
+
}
|
|
1325
|
+
renderFieldChips()
|
|
1326
|
+
renderResults()
|
|
1327
|
+
})
|
|
1328
|
+
chipsWrap.appendChild(chip)
|
|
1329
|
+
})
|
|
1330
|
+
|
|
1331
|
+
groupWrap.appendChild(chipsWrap)
|
|
1332
|
+
fieldChipGroups.appendChild(groupWrap)
|
|
1117
1333
|
})
|
|
1118
|
-
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
function setFieldSelection(allowedIds, options = {}) {
|
|
1337
|
+
const { rerender = true } = options
|
|
1338
|
+
state.selectedFieldIds = new Set(
|
|
1339
|
+
SEARCH_FIELDS.map((field) => field.id).filter((id) => allowedIds.has(id)),
|
|
1340
|
+
)
|
|
1341
|
+
renderFieldChips()
|
|
1342
|
+
if (rerender) renderResults()
|
|
1119
1343
|
}
|
|
1120
1344
|
|
|
1121
1345
|
function resetFiltersToDefault() {
|
|
1122
1346
|
searchInput.value = ''
|
|
1123
|
-
|
|
1124
|
-
|
|
1347
|
+
setPressed(caseSensitiveToggle, false)
|
|
1348
|
+
setPressed(regexSearchToggle, false)
|
|
1125
1349
|
typeMatchModeInput.value = 'contains'
|
|
1126
|
-
|
|
1127
|
-
setFieldSelection(new Set(SEARCH_FIELDS.map((field) => field.id)))
|
|
1350
|
+
setPressed(schemaRowsMatchOnlyToggle, false)
|
|
1351
|
+
setFieldSelection(new Set(SEARCH_FIELDS.map((field) => field.id)), { rerender: false })
|
|
1352
|
+
renderResults()
|
|
1128
1353
|
}
|
|
1129
1354
|
|
|
1130
1355
|
function renderActiveFilterChips({ selectedIds, hasRegexError }) {
|
|
1131
1356
|
activeFilterChips.innerHTML = ''
|
|
1132
|
-
const chips = []
|
|
1133
|
-
|
|
1134
1357
|
const searchValue = searchInput.value.trim()
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
if (
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1358
|
+
const chipModels = []
|
|
1359
|
+
|
|
1360
|
+
if (searchValue) {
|
|
1361
|
+
chipModels.push({
|
|
1362
|
+
text: `search: ${searchValue}`,
|
|
1363
|
+
onClick: () => {
|
|
1364
|
+
searchInput.value = ''
|
|
1365
|
+
renderResults()
|
|
1366
|
+
},
|
|
1367
|
+
})
|
|
1368
|
+
}
|
|
1369
|
+
if (typeMatchModeInput.value === 'exact') {
|
|
1370
|
+
chipModels.push({
|
|
1371
|
+
text: 'type mode: exact',
|
|
1372
|
+
onClick: () => {
|
|
1373
|
+
typeMatchModeInput.value = 'contains'
|
|
1374
|
+
renderResults()
|
|
1375
|
+
},
|
|
1376
|
+
})
|
|
1377
|
+
}
|
|
1378
|
+
if (isPressed(schemaRowsMatchOnlyToggle)) {
|
|
1379
|
+
chipModels.push({
|
|
1380
|
+
text: 'schema rows: matched only',
|
|
1381
|
+
onClick: () => {
|
|
1382
|
+
setPressed(schemaRowsMatchOnlyToggle, false)
|
|
1383
|
+
renderResults()
|
|
1384
|
+
},
|
|
1385
|
+
})
|
|
1386
|
+
}
|
|
1387
|
+
if (isPressed(caseSensitiveToggle)) {
|
|
1388
|
+
chipModels.push({
|
|
1389
|
+
text: 'case sensitive',
|
|
1390
|
+
onClick: () => {
|
|
1391
|
+
setPressed(caseSensitiveToggle, false)
|
|
1392
|
+
renderResults()
|
|
1393
|
+
},
|
|
1394
|
+
})
|
|
1395
|
+
}
|
|
1396
|
+
if (isPressed(regexSearchToggle)) {
|
|
1397
|
+
chipModels.push({
|
|
1398
|
+
text: 'regex',
|
|
1399
|
+
onClick: () => {
|
|
1400
|
+
setPressed(regexSearchToggle, false)
|
|
1401
|
+
renderResults()
|
|
1402
|
+
},
|
|
1403
|
+
})
|
|
1404
|
+
}
|
|
1405
|
+
if (hasRegexError) chipModels.push({ text: 'regex error' })
|
|
1142
1406
|
|
|
1143
1407
|
const allIds = SEARCH_FIELDS.map((field) => field.id)
|
|
1144
1408
|
if (selectedIds.length !== allIds.length) {
|
|
1145
|
-
|
|
1409
|
+
chipModels.push({
|
|
1410
|
+
text: `fields: ${selectedIds.join(', ') || 'none'}`,
|
|
1411
|
+
onClick: () => setFieldSelection(new Set(allIds)),
|
|
1412
|
+
})
|
|
1146
1413
|
}
|
|
1147
1414
|
|
|
1148
|
-
if (
|
|
1415
|
+
if (chipModels.length === 0) {
|
|
1149
1416
|
activeFilterChips.appendChild(el('span', 'empty', 'No active filters'))
|
|
1150
1417
|
return
|
|
1151
1418
|
}
|
|
1152
1419
|
|
|
1153
|
-
|
|
1154
|
-
const chip =
|
|
1155
|
-
chip.
|
|
1420
|
+
chipModels.forEach((chipModel) => {
|
|
1421
|
+
const chip = document.createElement(chipModel.onClick ? 'button' : 'span')
|
|
1422
|
+
chip.className = chipModel.onClick ? 'chip chip-btn' : 'chip'
|
|
1423
|
+
chip.textContent = chipModel.text
|
|
1424
|
+
if (chipModel.onClick) {
|
|
1425
|
+
chip.type = 'button'
|
|
1426
|
+
chip.addEventListener('click', chipModel.onClick)
|
|
1427
|
+
}
|
|
1156
1428
|
activeFilterChips.appendChild(chip)
|
|
1157
1429
|
})
|
|
1158
1430
|
}
|
|
@@ -1160,10 +1432,10 @@
|
|
|
1160
1432
|
function collectFilterState() {
|
|
1161
1433
|
return {
|
|
1162
1434
|
search: searchInput.value,
|
|
1163
|
-
caseSensitive:
|
|
1164
|
-
regex:
|
|
1435
|
+
caseSensitive: isPressed(caseSensitiveToggle),
|
|
1436
|
+
regex: isPressed(regexSearchToggle),
|
|
1165
1437
|
typeMatchMode: typeMatchModeInput.value === 'exact' ? 'exact' : 'contains',
|
|
1166
|
-
schemaRowsMatchOnly:
|
|
1438
|
+
schemaRowsMatchOnly: isPressed(schemaRowsMatchOnlyToggle),
|
|
1167
1439
|
selectedFields: selectedFieldIds(),
|
|
1168
1440
|
}
|
|
1169
1441
|
}
|
|
@@ -1190,20 +1462,15 @@
|
|
|
1190
1462
|
const parsed = JSON.parse(decodeURIComponent(raw))
|
|
1191
1463
|
isHydratingFromUrl = true
|
|
1192
1464
|
if (typeof parsed.search === 'string') searchInput.value = parsed.search
|
|
1193
|
-
|
|
1194
|
-
|
|
1465
|
+
setPressed(caseSensitiveToggle, Boolean(parsed.caseSensitive))
|
|
1466
|
+
setPressed(regexSearchToggle, Boolean(parsed.regex))
|
|
1195
1467
|
if (parsed.typeMatchMode === 'exact' || parsed.typeMatchMode === 'contains') {
|
|
1196
1468
|
typeMatchModeInput.value = parsed.typeMatchMode
|
|
1197
1469
|
}
|
|
1198
|
-
|
|
1470
|
+
setPressed(schemaRowsMatchOnlyToggle, Boolean(parsed.schemaRowsMatchOnly))
|
|
1199
1471
|
|
|
1200
1472
|
if (Array.isArray(parsed.selectedFields)) {
|
|
1201
|
-
|
|
1202
|
-
SEARCH_FIELDS.forEach((field) => {
|
|
1203
|
-
const input = document.getElementById(`field-${field.id}`)
|
|
1204
|
-
if (!input) return
|
|
1205
|
-
input.checked = allowed.has(field.id)
|
|
1206
|
-
})
|
|
1473
|
+
setFieldSelection(new Set(parsed.selectedFields), { rerender: false })
|
|
1207
1474
|
}
|
|
1208
1475
|
} catch (error) {
|
|
1209
1476
|
// Ignore malformed hash state.
|
|
@@ -1247,20 +1514,30 @@
|
|
|
1247
1514
|
})
|
|
1248
1515
|
|
|
1249
1516
|
searchInput.addEventListener('input', renderResults)
|
|
1250
|
-
|
|
1251
|
-
|
|
1517
|
+
caseSensitiveToggle.addEventListener('click', () => {
|
|
1518
|
+
togglePressed(caseSensitiveToggle)
|
|
1519
|
+
renderResults()
|
|
1520
|
+
})
|
|
1521
|
+
regexSearchToggle.addEventListener('click', () => {
|
|
1522
|
+
togglePressed(regexSearchToggle)
|
|
1523
|
+
renderResults()
|
|
1524
|
+
})
|
|
1252
1525
|
typeMatchModeInput.addEventListener('change', renderResults)
|
|
1253
|
-
|
|
1526
|
+
schemaRowsMatchOnlyToggle.addEventListener('click', () => {
|
|
1527
|
+
togglePressed(schemaRowsMatchOnlyToggle)
|
|
1528
|
+
renderResults()
|
|
1529
|
+
})
|
|
1254
1530
|
|
|
1255
1531
|
selectAllFieldsBtn.addEventListener('click', () =>
|
|
1256
1532
|
setFieldSelection(new Set(SEARCH_FIELDS.map((field) => field.id))),
|
|
1257
1533
|
)
|
|
1258
1534
|
clearAllFieldsBtn.addEventListener('click', () => setFieldSelection(new Set()))
|
|
1259
|
-
|
|
1260
|
-
|
|
1535
|
+
coreFieldsBtn.addEventListener('click', () => setFieldSelection(CORE_FIELD_IDS))
|
|
1536
|
+
schemasOnlyFieldsBtn.addEventListener('click', () => setFieldSelection(SCHEMA_SCOPE_FIELD_IDS))
|
|
1537
|
+
sourceOnlyFieldsBtn.addEventListener('click', () => setFieldSelection(SOURCE_FIELD_IDS))
|
|
1261
1538
|
resetFiltersBtn.addEventListener('click', resetFiltersToDefault)
|
|
1262
1539
|
|
|
1263
|
-
|
|
1540
|
+
renderFieldChips()
|
|
1264
1541
|
hydrateFilterStateFromUrl()
|
|
1265
1542
|
initializeFromBakedPayload()
|
|
1266
1543
|
renderResults()
|