fix(js): remove runtime selector traversal

Replace runtime querySelector/closest/matches traversal with explicit element walks and generated-id predicates, preserving existing runtime convention coverage.

req: runtime/001

req: target_policy/001

req: target_policy/002
This commit is contained in:
slhx agent
2026-05-26 01:18:21 +02:00
parent a8bd7dfdf7
commit d3fc1a745a
2 changed files with 137 additions and 46 deletions
+18 -11
View File
@@ -26,9 +26,11 @@ fn runtime_targets_generated_resources_not_response_selectors() {
let source = slhx_js::RUNTIME_JS;
assert!(source.contains("function targetFor(scope, ref)"));
assert!(source.contains("return scope.querySelector(`[data-sid=\"${ref.resource.id}\"], [data-slot-id=\"${ref.resource.id}\"]`)"));
assert!(source.contains("return scope.querySelector(`[data-sid=\"${id}\"][data-key=\"${escapedKey}\"], [data-sid=\"${id}\"] [data-key=\"${escapedKey}\"], [data-slot-id=\"${id}\"][data-key=\"${escapedKey}\"], [data-slot-id=\"${id}\"] [data-key=\"${escapedKey}\"]`)"));
assert!(source.contains("doc.querySelectorAll(\"[data-sid], [data-slot-id]\")"));
assert!(source.contains("return generatedTarget(scope, ref.resource.id)"));
assert!(source.contains("function firstElement(scope, predicate)"));
assert!(source.contains("function generatedResource(el, id)"));
assert!(source.contains("return firstElement(scope, (el) => attrEquals(el, \"data-key\", key) && withinGeneratedResource(el, scope, id))"));
assert!(source.contains("const target = generatedTarget(scope, id)"));
assert!(source.contains("if (!target) return missing(scope, op.target)"));
assert!(!source.contains("data-slhx-target"));
assert!(!source.contains("data-slhx-select"));
@@ -39,8 +41,9 @@ fn runtime_interval_dispatch_avoids_duplicate_timers() {
// req: convention/005
let source = slhx_js::RUNTIME_JS;
assert!(source.contains("root.querySelectorAll(\"[data-slhx-every]\")"));
assert!(source.contains("if (timers.has(el)) return"));
assert!(source.contains("forEachElement(root, (el) =>"));
assert!(source.contains("!el.hasAttribute(\"data-slhx-every\") || timers.has(el)"));
assert!(source.contains("if (!el.hasAttribute(\"data-slhx-every\") || timers.has(el)) return"));
assert!(source.contains("setInterval(() => document.contains(el) ? send(el, \"every\")"));
assert!(source.contains("clearInterval(timers.get(el))"));
}
@@ -53,9 +56,11 @@ fn runtime_toggles_pending_conventions_around_requests() {
assert!(source.contains("function showPending(el, on)"));
assert!(source.contains("el.getAttribute(\"data-slhx-pending-class\")"));
assert!(source.contains("el.classList.toggle(klass, on)"));
assert!(source.contains("root.querySelectorAll(\"[data-slhx-indicator]\")"));
assert!(source.contains("forEachElement(root, (i) => { if (i.hasAttribute(\"data-slhx-indicator\")) i.hidden = !on; })"));
assert!(source.contains("i.hidden = !on"));
assert!(source.contains("el.hasAttribute(\"data-slhx-disable-while-pending\")"));
assert!(source.contains("if (isDisableControl(el)) controls.push(el)"));
assert!(source.contains("forEachElement(el, (child) => { if (isDisableControl(child)) controls.push(child); })"));
assert!(source.contains("c.disabled = on"));
assert!(source.contains("showPending(target, true)"));
assert!(source.contains("showPending(target, false)"));
@@ -95,8 +100,9 @@ fn runtime_clicking_submitter_schedules_form_submit() {
assert!(source.contains("function formOwner(el)"));
assert!(source.contains("function formHandleId(form)"));
assert!(source.contains("document.getElementById(el.getAttribute(\"form\"))"));
assert!(source.contains("const direct = closestInRoot(event.target, root, `[${HID}]`)"));
assert!(source.contains("button[type=submit], input[type=submit], button:not([type])"));
assert!(source.contains("const direct = closestInRoot(event.target, root, (el) => el.hasAttribute(HID))"));
assert!(source.contains("const submitter = closestInRoot(event.target, root, (el) =>"));
assert!(source.contains("el.tagName === \"BUTTON\" && (!el.hasAttribute(\"type\") || el.getAttribute(\"type\") === \"submit\")"));
assert!(source.contains("form.reportValidity && !form.reportValidity()"));
assert!(source.contains("schedule(form, \"submit\")"));
}
@@ -187,7 +193,8 @@ fn runtime_page_swaps_lowered_slot_ids() {
let source = slhx_js::RUNTIME_JS;
assert!(source.contains("function replaceLoweredSlots(scope, doc)"));
assert!(source.contains("doc.querySelectorAll(\"[data-sid], [data-slot-id]\")"));
assert!(source.contains("forEachElement(doc.body || doc, (source)"));
assert!(source.contains("const target = generatedTarget(scope, id)"));
assert!(source.contains("target.innerHTML = source.innerHTML"));
}
@@ -196,9 +203,9 @@ fn runtime_keeps_form_field_targets_separate_from_error_targets() {
let source = slhx_js::RUNTIME_JS;
assert!(source.contains("function fieldTarget(scope, id, field)"));
assert!(source.contains("[data-fid=\"${id}\"] [name=\"${escapedField}\"]"));
assert!(source.contains("attrEquals(el, \"name\", field) && withinGeneratedForm(el, scope, id)"));
assert!(source.contains("function formErrorTarget(scope, id, field)"));
assert!(source.contains("[data-slhx-error-for=\"${escapedField}\"]"));
assert!(source.contains("attrEquals(el, \"data-slhx-error-for\", field) && withinGeneratedForm(el, scope, id)"));
}
#[test]