mirror of
https://github.com/lexmount/moli.git
synced 2026-11-13 08:08:10 +00:00
fix(script): keep currentScript in its execution Document
A running script can be adopted into another Document without changing the source Document's currentScript. Query the main execution stack for the main Document rather than filtering by the node's new ownerDocument; retain the existing per-child-Document stack and shadow visibility checks. Dynamic inline error reporting exposed this pre-existing bug as a WPT failure. A direct old-release probe also returns the wrong currentScript, so the old WPT pass was masking the exception rather than proving correct behavior. Cover adoption, the destination's null value and stack restoration.
This commit is contained in:
@@ -1052,36 +1052,18 @@ fn current_script_handle_for_document(
|
||||
// its node document or tree while its currentScript value stays set.
|
||||
return runtime.child_current_script_handle_for_document(document_handle);
|
||||
}
|
||||
if let Some(script) = runtime.current_inline_script_handle()
|
||||
&& current_script_belongs_to_document(runtime, script, document_handle)
|
||||
{
|
||||
return current_script_is_visible_for_document(runtime, script, document_handle)
|
||||
.then_some(script);
|
||||
if document_handle != runtime.dom_host().document_handle() {
|
||||
return None;
|
||||
}
|
||||
// The executing Document owns currentScript, even if the script is adopted
|
||||
// into another Document before its execution finishes.
|
||||
let dom = runtime.dom_host();
|
||||
runtime
|
||||
.current_script_handle()
|
||||
.filter(|script| current_script_is_visible_for_document(runtime, *script, document_handle))
|
||||
}
|
||||
|
||||
fn current_script_is_visible_for_document(
|
||||
runtime: &PageScriptHost,
|
||||
script: DomHandle,
|
||||
document_handle: DomHandle,
|
||||
) -> bool {
|
||||
let dom = runtime.dom_host();
|
||||
current_script_belongs_to_document(runtime, script, document_handle)
|
||||
&& (!dom.is_connected(script) || dom.containing_shadow_root(script).is_none())
|
||||
}
|
||||
|
||||
fn current_script_belongs_to_document(
|
||||
runtime: &PageScriptHost,
|
||||
script: DomHandle,
|
||||
document_handle: DomHandle,
|
||||
) -> bool {
|
||||
let dom = runtime.dom_host();
|
||||
dom.node(script)
|
||||
.and_then(Node::owner_document)
|
||||
.is_some_and(|owner_document| owner_document == document_handle)
|
||||
.current_inline_script_handle()
|
||||
.or_else(|| runtime.current_script_handle())
|
||||
.filter(|script| {
|
||||
!dom.is_connected(*script) || dom.containing_shadow_root(*script).is_none()
|
||||
})
|
||||
}
|
||||
|
||||
fn document_hidden_getter_function<'s>(
|
||||
|
||||
@@ -5,6 +5,39 @@ const DYNAMIC_INLINE_ERRORS: &str = include_str!(concat!(
|
||||
"/tests/fixtures/dynamic-inline-errors.js"
|
||||
));
|
||||
|
||||
#[test]
|
||||
fn current_script_stays_with_its_execution_document_after_adoption() {
|
||||
let mut vm = new_parsed_test_vm(
|
||||
"https://inline-adoption.test/page.html",
|
||||
"<!doctype html><body></body>",
|
||||
);
|
||||
let result = vm
|
||||
.eval(
|
||||
r#"
|
||||
globalThis.adoptionResults = [];
|
||||
globalThis.outer = document.createElement('script');
|
||||
outer.textContent = `
|
||||
globalThis.inner = document.createElement('script');
|
||||
inner.textContent = \`
|
||||
adoptionResults.push(document.currentScript === inner);
|
||||
globalThis.destination = document.implementation.createHTMLDocument();
|
||||
destination.body.appendChild(inner);
|
||||
adoptionResults.push(inner.ownerDocument === destination);
|
||||
adoptionResults.push(document.currentScript === inner);
|
||||
adoptionResults.push(destination.currentScript === null);
|
||||
\`;
|
||||
document.body.appendChild(inner);
|
||||
adoptionResults.push(document.currentScript === outer);
|
||||
`;
|
||||
document.body.appendChild(outer);
|
||||
adoptionResults.push(document.currentScript === null);
|
||||
JSON.stringify(adoptionResults)
|
||||
"#,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(result, "[true,true,true,true,true,true]");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn main_dynamic_inline_script_errors_are_synchronous_and_restore_current_script() {
|
||||
for borrow_child_insertion in [false, true] {
|
||||
|
||||
Reference in New Issue
Block a user