@archie/devtools 0.0.26 → 0.0.28
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/dist/chunk-4VGQJ3PW.mjs +577 -0
- package/dist/client/client.js +22 -27
- package/dist/client/client.mjs +22 -27
- package/dist/collection-binding.d.mts +221 -0
- package/dist/collection-binding.d.ts +221 -0
- package/dist/collection-binding.js +565 -0
- package/dist/collection-binding.mjs +533 -0
- package/dist/index.js +9 -10
- package/dist/index.mjs +7 -575
- package/dist/inspector.standalone.js +232 -7
- package/package.json +6 -1
|
@@ -367,13 +367,28 @@
|
|
|
367
367
|
return projected && projected.nodeId ? projected.nodeId : null
|
|
368
368
|
}
|
|
369
369
|
|
|
370
|
-
// The repeated-row boundary above `el`, or
|
|
371
|
-
// wins (a tag inside a card
|
|
370
|
+
// The repeated-row boundary above `el`, or a search outcome explaining
|
|
371
|
+
// why none was found. INNERMOST repetition wins (a tag inside a card
|
|
372
|
+
// inside a list is identified by the tag's key).
|
|
373
|
+
//
|
|
374
|
+
// ARCH-1065 D8-v1/D26 — three-way outcome, matching instance-identity.ts:
|
|
375
|
+
// a CollectionWindow object (found), the string "exhausted" (walked to
|
|
376
|
+
// the true DOM root having found nothing — a COMPLETED search, safe to
|
|
377
|
+
// report as SINGLETON), or null (gave up without a definitive answer:
|
|
378
|
+
// no ancestor to compare against at all, or the depth budget ran out
|
|
379
|
+
// before reaching the root). The PREVIOUS version of this function
|
|
380
|
+
// collapsed "exhausted" and budget-exhaustion into one `null` verdict
|
|
381
|
+
// that `resolveInstanceIdentity` then always read as SINGLETON — more
|
|
382
|
+
// permissive than the TS twin ever intended: a walk that stopped early
|
|
383
|
+
// because it ran out of depth budget never PROVED there was no
|
|
384
|
+
// collection ancestor above it.
|
|
372
385
|
function findCollectionWindow(el) {
|
|
386
|
+
if (!el.parentElement) return null
|
|
387
|
+
|
|
373
388
|
var node = el
|
|
374
389
|
for (var depth = 0; depth < MAX_ROW_ROOT_DEPTH; depth++) {
|
|
375
390
|
var parent = node.parentElement
|
|
376
|
-
if (!parent) return
|
|
391
|
+
if (!parent) return "exhausted"
|
|
377
392
|
|
|
378
393
|
var nodeId = ownMetaNodeId(node)
|
|
379
394
|
if (nodeId !== null) {
|
|
@@ -411,12 +426,19 @@
|
|
|
411
426
|
return null
|
|
412
427
|
}
|
|
413
428
|
|
|
414
|
-
// WHICH instance of a possibly-repeated node this element is
|
|
429
|
+
// WHICH instance of a possibly-repeated node this element is, or NULL
|
|
430
|
+
// when resolution could not reach a definitive answer (ARCH-1065
|
|
431
|
+
// D8-v1/D26 — matches `resolveInstanceIdentity` in instance-identity.ts;
|
|
432
|
+
// this file cannot import it, so the same three-way outcome is
|
|
433
|
+
// re-derived here rather than left more permissive than the TS twin).
|
|
415
434
|
// `scanOrdinal` is telemetry/UI only — the host must REJECT an intent
|
|
416
|
-
// with inCollection && fiberKey === null, never fall back to it
|
|
435
|
+
// with inCollection && fiberKey === null, never fall back to it, and
|
|
436
|
+
// must treat a NULL editorInstance exactly like that same refusal.
|
|
417
437
|
function resolveInstanceIdentity(el) {
|
|
438
|
+
if (!(el instanceof HTMLElement)) return null
|
|
418
439
|
var win = findCollectionWindow(el)
|
|
419
|
-
if (
|
|
440
|
+
if (win === null) return null
|
|
441
|
+
if (win === "exhausted") return { fiberKey: null, scanOrdinal: 0, inCollection: false }
|
|
420
442
|
return {
|
|
421
443
|
fiberKey: keyWithinWindow(win.rowRoot, win.container),
|
|
422
444
|
scanOrdinal: win.ordinal,
|
|
@@ -453,6 +475,146 @@
|
|
|
453
475
|
return anchors
|
|
454
476
|
}
|
|
455
477
|
|
|
478
|
+
// ARCH-1065 M3 — the D1 grammar attributes babel-plugin-collection-binding
|
|
479
|
+
// stamps at build time (data-agent-entity/-row/-field/-field-state/
|
|
480
|
+
// -field-parts/-field-slot/-collection-order). One frame per DOM
|
|
481
|
+
// attribute name; a leaf typically carries only `field` (+ `fieldSlot`
|
|
482
|
+
// or `fieldState`/`fieldParts`), while its row-root ancestor carries
|
|
483
|
+
// `entity` + `row` + `collectionOrder` — reading both frames is what
|
|
484
|
+
// lets the host recover the full (entity, field, rowId) triple for a
|
|
485
|
+
// click anywhere inside a bound leaf.
|
|
486
|
+
var BINDING_ATTRS = [
|
|
487
|
+
["entity", "data-agent-entity"],
|
|
488
|
+
["row", "data-agent-row"],
|
|
489
|
+
["field", "data-agent-field"],
|
|
490
|
+
["fieldState", "data-agent-field-state"],
|
|
491
|
+
["fieldParts", "data-agent-field-parts"],
|
|
492
|
+
["fieldSlot", "data-agent-field-slot"],
|
|
493
|
+
["collectionOrder", "data-agent-collection-order"],
|
|
494
|
+
]
|
|
495
|
+
|
|
496
|
+
function readBindingFrame(el) {
|
|
497
|
+
if (!el || el.nodeType !== 1 || typeof el.getAttribute !== "function") return null
|
|
498
|
+
var frame = null
|
|
499
|
+
for (var i = 0; i < BINDING_ATTRS.length; i++) {
|
|
500
|
+
var value = el.getAttribute(BINDING_ATTRS[i][1])
|
|
501
|
+
if (value !== null) {
|
|
502
|
+
if (!frame) frame = {}
|
|
503
|
+
frame[BINDING_ATTRS[i][0]] = value
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
return frame
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
// Walks SELF-outward (unlike collectAncestorAnchors, which is strict
|
|
510
|
+
// ancestors — a click on a leaf's own `data-agent-field` must appear in
|
|
511
|
+
// its own chain entry), one frame per element carrying >=1 binding
|
|
512
|
+
// attribute, bounded by MAX_ANCHOR_CHAIN (the same bound the ARCH-906
|
|
513
|
+
// anchor walk uses — a binding chain never needs to reach deeper than
|
|
514
|
+
// that one does).
|
|
515
|
+
function collectBindingChain(el) {
|
|
516
|
+
var chain = []
|
|
517
|
+
var node = el
|
|
518
|
+
for (var depth = 0; node && depth < MAX_ANCHOR_CHAIN; depth++) {
|
|
519
|
+
var frame = readBindingFrame(node)
|
|
520
|
+
if (frame) chain.push(frame)
|
|
521
|
+
node = node.parentElement
|
|
522
|
+
}
|
|
523
|
+
return chain
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
// The nearest data-agent-row value SELF-outward, or null. Used to
|
|
527
|
+
// resolve "the currently selected row" for QUERY_SLICE_FIELD when the
|
|
528
|
+
// caller does not pass an explicit rowId.
|
|
529
|
+
function nearestRowId(el) {
|
|
530
|
+
var node = el
|
|
531
|
+
for (var depth = 0; node && depth < MAX_ANCHOR_CHAIN; depth++) {
|
|
532
|
+
if (node.nodeType === 1 && typeof node.getAttribute === "function") {
|
|
533
|
+
var rowId = node.getAttribute("data-agent-row")
|
|
534
|
+
if (typeof rowId === "string" && rowId !== "") return rowId
|
|
535
|
+
}
|
|
536
|
+
node = node.parentElement
|
|
537
|
+
}
|
|
538
|
+
return null
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// ARCH-1065 — the BUILD-TIME contract version this page was stamped
|
|
542
|
+
// with. Opaque here; the host interprets it (SDD analog of `slot`).
|
|
543
|
+
function readBindingContractMeta() {
|
|
544
|
+
try {
|
|
545
|
+
var metaEl = document.querySelector('meta[name="archie-binding-contract"]')
|
|
546
|
+
if (metaEl && typeof metaEl.getAttribute === "function") {
|
|
547
|
+
var content = metaEl.getAttribute("content")
|
|
548
|
+
return typeof content === "string" && content !== "" ? content : null
|
|
549
|
+
}
|
|
550
|
+
} catch (e) {
|
|
551
|
+
// Best-effort — capability forwarding must never throw at boot.
|
|
552
|
+
}
|
|
553
|
+
return null
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
// ARCH-1065 M3 — `window.__slice` read live for the FE's typed controls
|
|
557
|
+
// (design D7): given an entity + field, the DISTINCT values that field
|
|
558
|
+
// takes across every row of that entity in the current slice (the
|
|
559
|
+
// vocabulary a status-SELECT control offers) and, when a row is known,
|
|
560
|
+
// that row's CURRENT value. Nothing about type/format is STAMPED at
|
|
561
|
+
// build time (per the M1/M2/M3 split) — it is read here, live, so it
|
|
562
|
+
// reflects the actual data the page is showing right now.
|
|
563
|
+
function resolveSliceEntityRows(entity) {
|
|
564
|
+
var slice = window.__slice
|
|
565
|
+
if (!slice || typeof slice !== "object") return null
|
|
566
|
+
var rows = slice[entity]
|
|
567
|
+
return Array.isArray(rows) ? rows : null
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
var ISO_DATE_PATTERN =
|
|
571
|
+
/^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}(:\d{2}(\.\d+)?)?(Z|[+-]\d{2}:\d{2})?)?$/
|
|
572
|
+
|
|
573
|
+
function inferSliceValueType(value) {
|
|
574
|
+
if (value === null || value === undefined || value === "") return "empty-null"
|
|
575
|
+
if (typeof value === "boolean") return "boolean"
|
|
576
|
+
if (typeof value === "number") return "number"
|
|
577
|
+
if (typeof value === "string") {
|
|
578
|
+
return ISO_DATE_PATTERN.test(value) ? "date" : "string"
|
|
579
|
+
}
|
|
580
|
+
return "unknown"
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
function querySliceField(entity, field, rowId) {
|
|
584
|
+
var rows = resolveSliceEntityRows(entity)
|
|
585
|
+
if (!rows) return null
|
|
586
|
+
|
|
587
|
+
var distinctValues = []
|
|
588
|
+
var seenDistinct = {}
|
|
589
|
+
for (var i = 0; i < rows.length; i++) {
|
|
590
|
+
var candidate = rows[i] ? rows[i][field] : undefined
|
|
591
|
+
if (candidate === undefined) continue
|
|
592
|
+
var key = String(candidate)
|
|
593
|
+
if (!seenDistinct[key]) {
|
|
594
|
+
seenDistinct[key] = true
|
|
595
|
+
distinctValues.push(candidate)
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
var currentValue = null
|
|
600
|
+
if (rowId != null) {
|
|
601
|
+
for (var j = 0; j < rows.length; j++) {
|
|
602
|
+
if (rows[j] && String(rows[j].id) === String(rowId)) {
|
|
603
|
+
var rowValue = rows[j][field]
|
|
604
|
+
currentValue = rowValue === undefined ? null : rowValue
|
|
605
|
+
break
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
var typeSample = currentValue !== null ? currentValue : distinctValues[0]
|
|
611
|
+
return {
|
|
612
|
+
currentValue: currentValue,
|
|
613
|
+
valueType: inferSliceValueType(typeSample),
|
|
614
|
+
distinctValues: distinctValues,
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
|
|
456
618
|
if (window._inspectorSharedTargetObserver) {
|
|
457
619
|
try {
|
|
458
620
|
window._inspectorSharedTargetObserver.disconnect()
|
|
@@ -1065,7 +1227,11 @@
|
|
|
1065
1227
|
postMessageToParent({
|
|
1066
1228
|
type: "INSPECTOR_SCRIPT_LOADED",
|
|
1067
1229
|
timestamp: Date.now(),
|
|
1068
|
-
|
|
1230
|
+
// 2.2.0 (ARCH-1065): additive only — `bindingChain` on element data,
|
|
1231
|
+
// `QUERY_SLICE_FIELD` in the message protocol, and
|
|
1232
|
+
// `capabilities.bindingContract` below. No existing field changed
|
|
1233
|
+
// shape, so `protocolVersion` stays 1.
|
|
1234
|
+
version: "2.2.0",
|
|
1069
1235
|
protocolVersion: 1,
|
|
1070
1236
|
capabilities: {
|
|
1071
1237
|
// 2.1.1: function-valued __editorMeta props are invoked before any
|
|
@@ -1085,6 +1251,21 @@
|
|
|
1085
1251
|
// feature-detect on this flag: a frozen 2.0.x inspector disables
|
|
1086
1252
|
// design mode on "inspect" and needs the legacy "design" mode.
|
|
1087
1253
|
unifiedInspectArrange: true,
|
|
1254
|
+
// ARCH-1065: the M2 codemod's data-agent-* grammar is readable
|
|
1255
|
+
// (`bindingChain` on element data) and slice-field-queryable
|
|
1256
|
+
// (`QUERY_SLICE_FIELD`). Hosts MUST feature-detect on this flag
|
|
1257
|
+
// before relying on either — a frozen pre-1065 inspector has
|
|
1258
|
+
// neither.
|
|
1259
|
+
collectionBinding: true,
|
|
1260
|
+
// The BUILD-TIME contract version this specific page was stamped
|
|
1261
|
+
// with, forwarded verbatim from `<meta name="archie-binding-contract">`
|
|
1262
|
+
// when the kit build emitted one — null on any page built before
|
|
1263
|
+
// that meta tag existed, or that never carried collection-bound
|
|
1264
|
+
// data. Opaque to this script: validating/interpreting the value is
|
|
1265
|
+
// the host's job (mirrors how `slot` and `bindingContract` — plural
|
|
1266
|
+
// concept, singular mechanism — are treated as opaque strings
|
|
1267
|
+
// elsewhere in this file).
|
|
1268
|
+
bindingContract: readBindingContractMeta(),
|
|
1088
1269
|
},
|
|
1089
1270
|
})
|
|
1090
1271
|
|
|
@@ -2282,6 +2463,12 @@
|
|
|
2282
2463
|
// nodeId is a source position and collides across instances; the
|
|
2283
2464
|
// only identity that survives an insert above the edited row is
|
|
2284
2465
|
// React's `key`, which exists on the fiber and nowhere else.
|
|
2466
|
+
// ARCH-1065 D8-v1/D26: NULL here means resolution never reached
|
|
2467
|
+
// a definitive answer (detached node, non-HTMLElement, or the
|
|
2468
|
+
// depth-bounded walk ran out before reaching the DOM root) — the
|
|
2469
|
+
// host MUST treat a null editorInstance exactly like the
|
|
2470
|
+
// existing `inCollection && fiberKey === null` refusal, never as
|
|
2471
|
+
// "not in a collection".
|
|
2285
2472
|
//
|
|
2286
2473
|
// Both are plain data, so an already-published copy of this script
|
|
2287
2474
|
// forwards them through structured clone unchanged.
|
|
@@ -2303,6 +2490,12 @@
|
|
|
2303
2490
|
// already-published copy of this script forwards it unchanged through
|
|
2304
2491
|
// structured clone; a host that does not read it is unaffected.
|
|
2305
2492
|
ancestorAnchors: collectAncestorAnchors(element),
|
|
2493
|
+
// ARCH-1065 M3 — the data-agent-* (D1 grammar) chain, self-outward,
|
|
2494
|
+
// for whatever binding attributes the M2 codemod (or a hand-written
|
|
2495
|
+
// kit component, M1) stamped. A host that does not read it is
|
|
2496
|
+
// unaffected; a pre-1065 page simply yields an empty array (`[]`),
|
|
2497
|
+
// same as `ancestorAnchors` does for a page with no anchors.
|
|
2498
|
+
bindingChain: collectBindingChain(element),
|
|
2306
2499
|
computedStyles: {
|
|
2307
2500
|
display: computed.display,
|
|
2308
2501
|
position: computed.position,
|
|
@@ -3656,6 +3849,38 @@
|
|
|
3656
3849
|
dispatchHostCommand({
|
|
3657
3850
|
type: "external-drag-cancel",
|
|
3658
3851
|
})
|
|
3852
|
+
} else if (event.data && event.data.type === "QUERY_SLICE_FIELD") {
|
|
3853
|
+
// ARCH-1065 M3 — {entity, field} -> {currentValue, valueType,
|
|
3854
|
+
// distinctValues} read live off window.__slice, for the FE's typed
|
|
3855
|
+
// controls (D7). `rowId` is optional: when omitted, the CURRENTLY
|
|
3856
|
+
// SELECTED (falling back to hovered) element's nearest
|
|
3857
|
+
// data-agent-row supplies it — the common case is "the user just
|
|
3858
|
+
// clicked a bound cell and wants its type/vocabulary", where the
|
|
3859
|
+
// row is already implied by that click.
|
|
3860
|
+
var queryEntity = event.data.entity
|
|
3861
|
+
var queryField = event.data.field
|
|
3862
|
+
var queryRowId =
|
|
3863
|
+
typeof event.data.rowId === "string" && event.data.rowId !== ""
|
|
3864
|
+
? event.data.rowId
|
|
3865
|
+
: null
|
|
3866
|
+
|
|
3867
|
+
var queryResult = null
|
|
3868
|
+
if (typeof queryEntity === "string" && typeof queryField === "string") {
|
|
3869
|
+
var contextElement = queryRowId
|
|
3870
|
+
? null
|
|
3871
|
+
: getSelectedElement() || highlightedElement
|
|
3872
|
+
var effectiveRowId =
|
|
3873
|
+
queryRowId || (contextElement ? nearestRowId(contextElement) : null)
|
|
3874
|
+
queryResult = querySliceField(queryEntity, queryField, effectiveRowId)
|
|
3875
|
+
}
|
|
3876
|
+
|
|
3877
|
+
postMessageToParent({
|
|
3878
|
+
type: "SLICE_FIELD_RESULT",
|
|
3879
|
+
requestId: event.data.requestId,
|
|
3880
|
+
entity: queryEntity,
|
|
3881
|
+
field: queryField,
|
|
3882
|
+
result: queryResult,
|
|
3883
|
+
})
|
|
3659
3884
|
}
|
|
3660
3885
|
}
|
|
3661
3886
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@archie/devtools",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.28",
|
|
4
4
|
"description": "DevTools for Archie generated applications - Route synchronization and editor communication",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -24,6 +24,11 @@
|
|
|
24
24
|
"import": "./dist/client/client.mjs",
|
|
25
25
|
"require": "./dist/client/client.js"
|
|
26
26
|
},
|
|
27
|
+
"./collection-binding": {
|
|
28
|
+
"types": "./dist/collection-binding.d.ts",
|
|
29
|
+
"import": "./dist/collection-binding.mjs",
|
|
30
|
+
"require": "./dist/collection-binding.js"
|
|
31
|
+
},
|
|
27
32
|
"./inspector.standalone.js": "./dist/inspector.standalone.js"
|
|
28
33
|
},
|
|
29
34
|
"scripts": {
|