///|
fn is_dom_bool_property(attr_name : String) -> Bool {
attr_name
is ("checked"
| "disabled"
| "hidden"
| "selected"
| "multiple"
| "autofocus"
| "required"
| "readonly"
| "open"
| "async"
| "defer"
| "loop"
| "muted"
| "controls"
| "autoplay"
| "allowfullscreen"
| "playsinline"
| "inert"
| "novalidate"
| "formnovalidate"
| "ismap"
| "default")
}
///|
fn is_dom_string_property(attr_name : String) -> Bool {
attr_name is ("value" | "href" | "textContent")
}
///|
priv enum AttrParamType {
AttrString
AttrBool
AttrInt
}
///|
priv struct AttrMethodInfo {
method_name : String
param_type : AttrParamType
}
///|
let attrs_method_registry : Map[String, AttrMethodInfo] = {
"accept": { method_name: "accept", param_type: AttrString },
"accept-charset": { method_name: "accept_charset", param_type: AttrString },
"accesskey": { method_name: "accesskey", param_type: AttrString },
"action": { method_name: "action", param_type: AttrString },
"align": { method_name: "align", param_type: AttrString },
"allow": { method_name: "allow", param_type: AttrString },
"alt": { method_name: "alt", param_type: AttrString },
"async": { method_name: "async_", param_type: AttrBool },
"autocapitalize": { method_name: "autocapitalize", param_type: AttrString },
"autocomplete": { method_name: "autocomplete", param_type: AttrString },
"autofocus": { method_name: "autofocus", param_type: AttrBool },
"autoplay": { method_name: "autoplay", param_type: AttrBool },
"bgcolor": { method_name: "bgcolor", param_type: AttrString },
"border": { method_name: "border", param_type: AttrInt },
"charset": { method_name: "charset", param_type: AttrString },
"checked": { method_name: "checked", param_type: AttrBool },
"cite": { method_name: "cite", param_type: AttrString },
"class": { method_name: "class", param_type: AttrString },
"color": { method_name: "color", param_type: AttrString },
"cols": { method_name: "cols", param_type: AttrInt },
"colspan": { method_name: "colspan", param_type: AttrInt },
"content": { method_name: "content", param_type: AttrString },
"contenteditable": { method_name: "contenteditable", param_type: AttrString },
"controls": { method_name: "controls", param_type: AttrBool },
"coords": { method_name: "coords", param_type: AttrString },
"crossorigin": { method_name: "crossorigin", param_type: AttrString },
"data": { method_name: "data", param_type: AttrString },
"datetime": { method_name: "datetime", param_type: AttrString },
"decoding": { method_name: "decoding", param_type: AttrString },
"default": { method_name: "default", param_type: AttrBool },
"defer": { method_name: "defer_", param_type: AttrBool },
"dir": { method_name: "dir", param_type: AttrString },
"dirname": { method_name: "dirname", param_type: AttrString },
"disabled": { method_name: "disabled", param_type: AttrBool },
"download": { method_name: "download", param_type: AttrString },
"draggable": { method_name: "draggable", param_type: AttrString },
"enctype": { method_name: "enctype", param_type: AttrString },
"for": { method_name: "for_", param_type: AttrString },
"form": { method_name: "form", param_type: AttrString },
"formaction": { method_name: "formaction", param_type: AttrString },
"formenctype": { method_name: "formenctype", param_type: AttrString },
"formmethod": { method_name: "formmethod", param_type: AttrString },
"formnovalidate": { method_name: "formnovalidate", param_type: AttrBool },
"formtarget": { method_name: "formtarget", param_type: AttrString },
"headers": { method_name: "headers", param_type: AttrString },
"height": { method_name: "height", param_type: AttrInt },
"hidden": { method_name: "hidden", param_type: AttrBool },
"high": { method_name: "high", param_type: AttrInt },
"href": { method_name: "href", param_type: AttrString },
"hreflang": { method_name: "hreflang", param_type: AttrString },
"http-equiv": { method_name: "http_equiv", param_type: AttrString },
"id": { method_name: "id", param_type: AttrString },
"inert": { method_name: "inert", param_type: AttrBool },
"inputmode": { method_name: "inputmode", param_type: AttrString },
"ismap": { method_name: "ismap", param_type: AttrBool },
"kind": { method_name: "kind", param_type: AttrString },
"label": { method_name: "label", param_type: AttrString },
"lang": { method_name: "lang", param_type: AttrString },
"loading": { method_name: "loading", param_type: AttrString },
"list": { method_name: "list", param_type: AttrString },
"loop": { method_name: "loop_", param_type: AttrBool },
"low": { method_name: "low", param_type: AttrInt },
"max": { method_name: "max", param_type: AttrInt },
"maxlength": { method_name: "maxlength", param_type: AttrInt },
"media": { method_name: "media", param_type: AttrString },
"method": { method_name: "method_", param_type: AttrString },
"min": { method_name: "min", param_type: AttrInt },
"minlength": { method_name: "minlength", param_type: AttrInt },
"multiple": { method_name: "multiple", param_type: AttrBool },
"muted": { method_name: "muted", param_type: AttrBool },
"name": { method_name: "name", param_type: AttrString },
"novalidate": { method_name: "novalidate", param_type: AttrBool },
"open": { method_name: "open", param_type: AttrBool },
"optimum": { method_name: "optimum", param_type: AttrInt },
"pattern": { method_name: "pattern", param_type: AttrString },
"placeholder": { method_name: "placeholder", param_type: AttrString },
"playsinline": { method_name: "playsinline", param_type: AttrBool },
"poster": { method_name: "poster", param_type: AttrString },
"preload": { method_name: "preload", param_type: AttrString },
"readonly": { method_name: "readonly_", param_type: AttrBool },
"rel": { method_name: "rel", param_type: AttrString },
"required": { method_name: "required", param_type: AttrBool },
"reversed": { method_name: "reversed", param_type: AttrBool },
"role": { method_name: "role", param_type: AttrString },
"rows": { method_name: "rows", param_type: AttrInt },
"rowspan": { method_name: "rowspan", param_type: AttrInt },
"sandbox": { method_name: "sandbox", param_type: AttrString },
"shape": { method_name: "shape", param_type: AttrString },
"size": { method_name: "size", param_type: AttrInt },
"sizes": { method_name: "sizes", param_type: AttrString },
"span": { method_name: "span", param_type: AttrInt },
"src": { method_name: "src", param_type: AttrString },
"srcdoc": { method_name: "srcdoc", param_type: AttrString },
"srclang": { method_name: "srclang", param_type: AttrString },
"srcset": { method_name: "srcset", param_type: AttrString },
"start": { method_name: "start", param_type: AttrInt },
"step": { method_name: "step", param_type: AttrInt },
"style": { method_name: "style_attr", param_type: AttrString },
"tabindex": { method_name: "tabindex", param_type: AttrInt },
"target": { method_name: "target", param_type: AttrString },
"title": { method_name: "title", param_type: AttrString },
"type": { method_name: "type_", param_type: AttrString },
"value": { method_name: "value", param_type: AttrString },
"width": { method_name: "width", param_type: AttrInt },
"wrap": { method_name: "wrap", param_type: AttrString },
"allowfullscreen": { method_name: "allowfullscreen", param_type: AttrBool },
"colspan": { method_name: "colspan", param_type: AttrInt },
"selected": { method_name: "selected", param_type: AttrBool },
}
///|
fn get_attr_method(attr_name : String) -> AttrMethodInfo? {
attrs_method_registry.get(attr_name)
}
///|
priv struct StyleDecl {
prop : String
value : String
}
///|
fn parse_style(style_str : String) -> Array[StyleDecl] {
style_str
.split(";")
.filter_map(part => {
let trimmed = part.trim()
if trimmed.is_empty() {
return None
}
trimmed
.split_once(":")
.bind(pair => {
let (prop, value) = pair
if prop.is_empty() {
None
} else {
Some({ prop: prop.to_string(), value: value.trim().to_string() })
}
})
})
.collect()
}
///|
priv enum AttrKind {
CommonNamedParam(String)
TagSpecificNamedParam(String)
DomBoolProperty
DomStringProperty
StyleAttr
FallbackAttribute
EventHandler
}
///|
fn classify_attr(
attr_name : String,
tag : String,
tag_params : Map[String, String],
) -> AttrKind {
ignore(tag)
if attr_name == "style" {
return StyleAttr
}
if tag_params.contains(attr_name) {
return TagSpecificNamedParam(tag_params[attr_name])
}
match attr_name {
"id" => CommonNamedParam("id")
"class" => CommonNamedParam("class")
"title" => CommonNamedParam("title")
"hidden" => CommonNamedParam("hidden")
_ =>
if is_dom_bool_property(attr_name) {
DomBoolProperty
} else if is_dom_string_property(attr_name) {
DomStringProperty
} else if attr_name.has_prefix("on") {
EventHandler
} else {
FallbackAttribute
}
}
}