fix(html): reflect link and meta metadata attributes

Expose link.rev, link.type and meta.scheme through the existing native DOMString reflection infrastructure. Regression coverage includes live and windowless documents, owner-prototype descriptors, valid non-ASCII and astral Unicode, attribute mutations and receiver validation before value conversion.

Validation: all branch checks passed. Summary [ 191.579s] 18922 tests run: 18922 passed (3 slow), 16 skipped
This commit is contained in:
ldm0
2026-09-29 18:09:26 +08:00
committed by Donough Liu
parent 14cc9792ef
commit a7beb2e816
3 changed files with 92 additions and 0 deletions
@@ -212,11 +212,14 @@ pub(super) enum DomStringReflection {
LinkIntegrity,
LinkMedia,
LinkReferrerPolicy,
LinkRev,
LinkType,
LiType,
MarqueeBgColor,
MarqueeHeight,
MarqueeWidth,
MetaMedia,
MetaScheme,
ModDateTime,
ObjectArchive,
ObjectCode,
@@ -560,6 +563,24 @@ const DOM_STRING_REFLECTION_DESCRIPTORS: &[(DomStringReflection, DomStringReflec
"referrerPolicy",
),
),
(
DomStringReflection::LinkRev,
DomStringReflectionDescriptor::new_html_element(
"HTMLLinkElement",
"link",
"rev",
"rev",
),
),
(
DomStringReflection::LinkType,
DomStringReflectionDescriptor::new_html_element(
"HTMLLinkElement",
"link",
"type",
"type",
),
),
(
DomStringReflection::LiType,
DomStringReflectionDescriptor::new("HTMLLIElement", "type", "type"),
@@ -580,6 +601,15 @@ const DOM_STRING_REFLECTION_DESCRIPTORS: &[(DomStringReflection, DomStringReflec
DomStringReflection::MetaMedia,
DomStringReflectionDescriptor::new("HTMLMetaElement", "media", "media"),
),
(
DomStringReflection::MetaScheme,
DomStringReflectionDescriptor::new_html_element(
"HTMLMetaElement",
"meta",
"scheme",
"scheme",
),
),
(
DomStringReflection::ModDateTime,
DomStringReflectionDescriptor::new("HTMLModElement", "datetime", "dateTime"),
@@ -2190,6 +2190,20 @@ pub(super) struct HtmlLinkElementUrlPrototypeDeclaration {
data = DomStringReflection::LinkIntegrity
)]
integrity: (),
#[webapi(
accessor_property,
getter = dom_string_reflection_getter_function,
setter = dom_string_reflection_setter_function,
data = DomStringReflection::LinkRev
)]
rev: (),
#[webapi(
accessor_property,
getter = dom_string_reflection_getter_function,
setter = dom_string_reflection_setter_function,
data = DomStringReflection::LinkType
)]
r#type: (),
}
#[derive(WebApiFunctionTemplate)]
@@ -2423,6 +2437,13 @@ pub(super) struct HtmlMetaElementPrototypeDeclaration {
setter = meta_http_equiv_setter_function
)]
http_equiv: (),
#[webapi(
accessor_property,
getter = dom_string_reflection_getter_function,
setter = dom_string_reflection_setter_function,
data = DomStringReflection::MetaScheme
)]
scheme: (),
}
#[derive(WebApiFunctionTemplate)]
@@ -727,3 +727,44 @@ fn legacy_boolean_accessors_live_on_owner_prototypes() {
assert_eq!(result, "ok");
}
#[test]
fn link_and_meta_legacy_metadata_reflect_on_native_owner_prototypes() {
let mut vm = new_parsed_test_vm(
"https://metadata-reflection.test/",
"<!doctype html><html><head></head><body></body></html>",
);
let result = vm.eval(r#"
(() => {
const assert = (condition, message) => { if (!condition) throw new Error(message); };
for (const owner of [document, document.implementation.createHTMLDocument('')]) {
for (const [tag, property, prototype] of [
['link', 'rev', HTMLLinkElement.prototype],
['link', 'type', HTMLLinkElement.prototype],
['meta', 'scheme', HTMLMetaElement.prototype]
]) {
const element = owner.createElement(tag);
owner.head.appendChild(element);
const descriptor = Object.getOwnPropertyDescriptor(prototype, property);
assert(descriptor && descriptor.enumerable && descriptor.configurable, `${tag}.${property} descriptor`);
assert(typeof descriptor.get === 'function' && typeof descriptor.set === 'function', 'accessors');
assert(element[property] === '', 'missing value');
element[property] = 'MiXeD\u00E9\u{1F642}';
assert(element.getAttribute(property) === 'MiXeD\u00E9\u{1F642}', 'DOMString reflection');
element.setAttribute(property, 'updated');
assert(element[property] === 'updated', 'attribute mutation');
element.removeAttribute(property);
assert(element[property] === '', 'attribute removal');
let converted = false;
try {
descriptor.set.call({}, { toString() { converted = true; return 'forged'; } });
throw new Error('accepted forged receiver');
} catch (error) { assert(error instanceof TypeError, 'receiver brand'); }
assert(!converted, 'receiver validation precedes conversion');
}
}
return 'ok';
})()
"#).expect("link and meta metadata reflection probe should evaluate");
assert_eq!(result, "ok");
}