Move codegen and data to typst-assets

This commit is contained in:
Laurenz 2025-06-21 10:43:00 +02:00
parent 2fd7d6facd
commit f3907c7d1b
9 changed files with 618 additions and 2352 deletions

227
Cargo.lock generated
View File

@ -545,29 +545,6 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929"
[[package]]
name = "cssparser"
version = "0.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7c66d1cd8ed61bf80b38432613a7a2f09401ab8d0501110655f8b341484a3e3"
dependencies = [
"cssparser-macros",
"dtoa-short",
"itoa",
"phf",
"smallvec",
]
[[package]]
name = "cssparser-macros"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
dependencies = [
"quote",
"syn",
]
[[package]]
name = "csv"
version = "1.3.1"
@ -615,17 +592,6 @@ dependencies = [
"syn",
]
[[package]]
name = "derive_more"
version = "0.99.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "dirs"
version = "6.0.0"
@ -664,21 +630,6 @@ version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
[[package]]
name = "dtoa"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04"
[[package]]
name = "dtoa-short"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87"
dependencies = [
"dtoa",
]
[[package]]
name = "ecow"
version = "0.2.3"
@ -688,12 +639,6 @@ dependencies = [
"serde",
]
[[package]]
name = "ego-tree"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2972feb8dffe7bc8c5463b1dacda1b0dfbed3710e50f977d965429692d74cd8"
[[package]]
name = "either"
version = "1.13.0"
@ -916,16 +861,6 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
[[package]]
name = "futf"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843"
dependencies = [
"mac",
"new_debug_unreachable",
]
[[package]]
name = "fxhash"
version = "0.2.1"
@ -1035,18 +970,6 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "html5ever"
version = "0.29.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b7410cae13cbc75623c98ac4cbfd1f0bedddf3227afc24f370cf0f50a44a11c"
dependencies = [
"log",
"mac",
"markup5ever",
"match_token",
]
[[package]]
name = "httpdate"
version = "1.0.3"
@ -1619,37 +1542,6 @@ dependencies = [
"pkg-config",
]
[[package]]
name = "mac"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
[[package]]
name = "markup5ever"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7a7213d12e1864c0f002f52c2923d4556935a43dec5e71355c2760e0f6e7a18"
dependencies = [
"log",
"phf",
"phf_codegen",
"string_cache",
"string_cache_codegen",
"tendril",
]
[[package]]
name = "match_token"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "memchr"
version = "2.7.4"
@ -1722,12 +1614,6 @@ dependencies = [
"tempfile",
]
[[package]]
name = "new_debug_unreachable"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
[[package]]
name = "nom"
version = "7.1.3"
@ -1985,16 +1871,6 @@ dependencies = [
"phf_shared",
]
[[package]]
name = "phf_codegen"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a"
dependencies = [
"phf_generator",
"phf_shared",
]
[[package]]
name = "phf_generator"
version = "0.11.3"
@ -2107,12 +1983,6 @@ dependencies = [
"zerocopy",
]
[[package]]
name = "precomputed-hash"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
[[package]]
name = "proc-macro2"
version = "1.0.93"
@ -2414,21 +2284,6 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "scraper"
version = "0.23.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "527e65d9d888567588db4c12da1087598d0f6f8b346cc2c5abc91f05fc2dffe2"
dependencies = [
"cssparser",
"ego-tree",
"getopts",
"html5ever",
"precomputed-hash",
"selectors",
"tendril",
]
[[package]]
name = "security-framework"
version = "2.11.1"
@ -2452,25 +2307,6 @@ dependencies = [
"libc",
]
[[package]]
name = "selectors"
version = "0.26.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd568a4c9bb598e291a08244a5c1f5a8a6650bee243b5b0f8dbb3d9cc1d87fe8"
dependencies = [
"bitflags 2.8.0",
"cssparser",
"derive_more",
"fxhash",
"log",
"new_debug_unreachable",
"phf",
"phf_codegen",
"precomputed-hash",
"servo_arc",
"smallvec",
]
[[package]]
name = "self-replace"
version = "1.5.0"
@ -2554,15 +2390,6 @@ dependencies = [
"unsafe-libyaml",
]
[[package]]
name = "servo_arc"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae65c4249478a2647db249fb43e23cec56a2c8974a427e7bd8cb5a1d0964921a"
dependencies = [
"stable_deref_trait",
]
[[package]]
name = "shell-escape"
version = "0.1.5"
@ -2674,31 +2501,6 @@ dependencies = [
"serde",
]
[[package]]
name = "string_cache"
version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f"
dependencies = [
"new_debug_unreachable",
"parking_lot",
"phf_shared",
"precomputed-hash",
"serde",
]
[[package]]
name = "string_cache_codegen"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0"
dependencies = [
"phf_generator",
"phf_shared",
"proc-macro2",
"quote",
]
[[package]]
name = "strsim"
version = "0.11.1"
@ -2821,17 +2623,6 @@ dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "tendril"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0"
dependencies = [
"futf",
"mac",
"utf-8",
]
[[package]]
name = "termcolor"
version = "1.4.1"
@ -3072,7 +2863,7 @@ dependencies = [
[[package]]
name = "typst-assets"
version = "0.13.1"
source = "git+https://github.com/typst/typst-assets?rev=c74e539#c74e539b090070a0c66fd007c550f5b6d3b724bd"
source = "git+https://github.com/typst/typst-assets?rev=a70ec89#a70ec8995e8ea59b66a6d3351ffaea2f16441872"
[[package]]
name = "typst-cli"
@ -3119,16 +2910,6 @@ dependencies = [
"zip",
]
[[package]]
name = "typst-codegen"
version = "0.13.1"
dependencies = [
"native-tls",
"regex",
"scraper",
"ureq",
]
[[package]]
name = "typst-dev-assets"
version = "0.13.1"
@ -3642,12 +3423,6 @@ dependencies = [
"xmlwriter",
]
[[package]]
name = "utf-8"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
[[package]]
name = "utf16_iter"
version = "1.0.5"

View File

@ -1,5 +1,5 @@
[workspace]
members = ["crates/*", "docs", "tests", "tests/fuzz", "tools/codegen"]
members = ["crates/*", "docs", "tests", "tests/fuzz"]
default-members = ["crates/typst-cli"]
resolver = "2"
@ -32,7 +32,7 @@ typst-svg = { path = "crates/typst-svg", version = "0.13.1" }
typst-syntax = { path = "crates/typst-syntax", version = "0.13.1" }
typst-timing = { path = "crates/typst-timing", version = "0.13.1" }
typst-utils = { path = "crates/typst-utils", version = "0.13.1" }
typst-assets = { git = "https://github.com/typst/typst-assets", rev = "c74e539" }
typst-assets = { git = "https://github.com/typst/typst-assets", rev = "a70ec89" }
typst-dev-assets = { git = "https://github.com/typst/typst-dev-assets", rev = "fddbf8b" }
arrayvec = "0.7.4"
az = "1.2"
@ -104,7 +104,6 @@ roxmltree = "0.20"
rust_decimal = { version = "1.36.0", default-features = false, features = ["maths"] }
rustybuzz = "0.20"
same-file = "1"
scraper = "0.23"
self-replace = "1.3.7"
semver = "1"
serde = { version = "1.0.184", features = ["derive"] }

View File

@ -347,10 +347,122 @@ pub mod charsets {
}
/// Predefined constants for HTML tags.
#[allow(non_upper_case_globals)]
pub mod tag {
use super::HtmlTag;
pub use crate::html::generated::tag::*;
pub const a: HtmlTag = HtmlTag::constant("a");
pub const abbr: HtmlTag = HtmlTag::constant("abbr");
pub const address: HtmlTag = HtmlTag::constant("address");
pub const area: HtmlTag = HtmlTag::constant("area");
pub const article: HtmlTag = HtmlTag::constant("article");
pub const aside: HtmlTag = HtmlTag::constant("aside");
pub const audio: HtmlTag = HtmlTag::constant("audio");
pub const b: HtmlTag = HtmlTag::constant("b");
pub const base: HtmlTag = HtmlTag::constant("base");
pub const bdi: HtmlTag = HtmlTag::constant("bdi");
pub const bdo: HtmlTag = HtmlTag::constant("bdo");
pub const blockquote: HtmlTag = HtmlTag::constant("blockquote");
pub const body: HtmlTag = HtmlTag::constant("body");
pub const br: HtmlTag = HtmlTag::constant("br");
pub const button: HtmlTag = HtmlTag::constant("button");
pub const canvas: HtmlTag = HtmlTag::constant("canvas");
pub const caption: HtmlTag = HtmlTag::constant("caption");
pub const cite: HtmlTag = HtmlTag::constant("cite");
pub const code: HtmlTag = HtmlTag::constant("code");
pub const col: HtmlTag = HtmlTag::constant("col");
pub const colgroup: HtmlTag = HtmlTag::constant("colgroup");
pub const data: HtmlTag = HtmlTag::constant("data");
pub const datalist: HtmlTag = HtmlTag::constant("datalist");
pub const dd: HtmlTag = HtmlTag::constant("dd");
pub const del: HtmlTag = HtmlTag::constant("del");
pub const details: HtmlTag = HtmlTag::constant("details");
pub const dfn: HtmlTag = HtmlTag::constant("dfn");
pub const dialog: HtmlTag = HtmlTag::constant("dialog");
pub const div: HtmlTag = HtmlTag::constant("div");
pub const dl: HtmlTag = HtmlTag::constant("dl");
pub const dt: HtmlTag = HtmlTag::constant("dt");
pub const em: HtmlTag = HtmlTag::constant("em");
pub const embed: HtmlTag = HtmlTag::constant("embed");
pub const fieldset: HtmlTag = HtmlTag::constant("fieldset");
pub const figcaption: HtmlTag = HtmlTag::constant("figcaption");
pub const figure: HtmlTag = HtmlTag::constant("figure");
pub const footer: HtmlTag = HtmlTag::constant("footer");
pub const form: HtmlTag = HtmlTag::constant("form");
pub const h1: HtmlTag = HtmlTag::constant("h1");
pub const h2: HtmlTag = HtmlTag::constant("h2");
pub const h3: HtmlTag = HtmlTag::constant("h3");
pub const h4: HtmlTag = HtmlTag::constant("h4");
pub const h5: HtmlTag = HtmlTag::constant("h5");
pub const h6: HtmlTag = HtmlTag::constant("h6");
pub const head: HtmlTag = HtmlTag::constant("head");
pub const header: HtmlTag = HtmlTag::constant("header");
pub const hgroup: HtmlTag = HtmlTag::constant("hgroup");
pub const hr: HtmlTag = HtmlTag::constant("hr");
pub const html: HtmlTag = HtmlTag::constant("html");
pub const i: HtmlTag = HtmlTag::constant("i");
pub const iframe: HtmlTag = HtmlTag::constant("iframe");
pub const img: HtmlTag = HtmlTag::constant("img");
pub const input: HtmlTag = HtmlTag::constant("input");
pub const ins: HtmlTag = HtmlTag::constant("ins");
pub const kbd: HtmlTag = HtmlTag::constant("kbd");
pub const label: HtmlTag = HtmlTag::constant("label");
pub const legend: HtmlTag = HtmlTag::constant("legend");
pub const li: HtmlTag = HtmlTag::constant("li");
pub const link: HtmlTag = HtmlTag::constant("link");
pub const main: HtmlTag = HtmlTag::constant("main");
pub const map: HtmlTag = HtmlTag::constant("map");
pub const mark: HtmlTag = HtmlTag::constant("mark");
pub const menu: HtmlTag = HtmlTag::constant("menu");
pub const meta: HtmlTag = HtmlTag::constant("meta");
pub const meter: HtmlTag = HtmlTag::constant("meter");
pub const nav: HtmlTag = HtmlTag::constant("nav");
pub const noscript: HtmlTag = HtmlTag::constant("noscript");
pub const object: HtmlTag = HtmlTag::constant("object");
pub const ol: HtmlTag = HtmlTag::constant("ol");
pub const optgroup: HtmlTag = HtmlTag::constant("optgroup");
pub const option: HtmlTag = HtmlTag::constant("option");
pub const output: HtmlTag = HtmlTag::constant("output");
pub const p: HtmlTag = HtmlTag::constant("p");
pub const picture: HtmlTag = HtmlTag::constant("picture");
pub const pre: HtmlTag = HtmlTag::constant("pre");
pub const progress: HtmlTag = HtmlTag::constant("progress");
pub const q: HtmlTag = HtmlTag::constant("q");
pub const rp: HtmlTag = HtmlTag::constant("rp");
pub const rt: HtmlTag = HtmlTag::constant("rt");
pub const ruby: HtmlTag = HtmlTag::constant("ruby");
pub const s: HtmlTag = HtmlTag::constant("s");
pub const samp: HtmlTag = HtmlTag::constant("samp");
pub const script: HtmlTag = HtmlTag::constant("script");
pub const search: HtmlTag = HtmlTag::constant("search");
pub const section: HtmlTag = HtmlTag::constant("section");
pub const select: HtmlTag = HtmlTag::constant("select");
pub const slot: HtmlTag = HtmlTag::constant("slot");
pub const small: HtmlTag = HtmlTag::constant("small");
pub const source: HtmlTag = HtmlTag::constant("source");
pub const span: HtmlTag = HtmlTag::constant("span");
pub const strong: HtmlTag = HtmlTag::constant("strong");
pub const style: HtmlTag = HtmlTag::constant("style");
pub const sub: HtmlTag = HtmlTag::constant("sub");
pub const summary: HtmlTag = HtmlTag::constant("summary");
pub const sup: HtmlTag = HtmlTag::constant("sup");
pub const table: HtmlTag = HtmlTag::constant("table");
pub const tbody: HtmlTag = HtmlTag::constant("tbody");
pub const td: HtmlTag = HtmlTag::constant("td");
pub const template: HtmlTag = HtmlTag::constant("template");
pub const textarea: HtmlTag = HtmlTag::constant("textarea");
pub const tfoot: HtmlTag = HtmlTag::constant("tfoot");
pub const th: HtmlTag = HtmlTag::constant("th");
pub const thead: HtmlTag = HtmlTag::constant("thead");
pub const time: HtmlTag = HtmlTag::constant("time");
pub const title: HtmlTag = HtmlTag::constant("title");
pub const tr: HtmlTag = HtmlTag::constant("tr");
pub const track: HtmlTag = HtmlTag::constant("track");
pub const u: HtmlTag = HtmlTag::constant("u");
pub const ul: HtmlTag = HtmlTag::constant("ul");
pub const var: HtmlTag = HtmlTag::constant("var");
pub const video: HtmlTag = HtmlTag::constant("video");
pub const wbr: HtmlTag = HtmlTag::constant("wbr");
/// Whether this is a void tag whose associated element may not have
/// children.
@ -505,4 +617,196 @@ pub mod tag {
}
}
pub use crate::html::generated::attr;
#[allow(non_upper_case_globals)]
#[rustfmt::skip]
pub mod attr {
use crate::html::HtmlAttr;
pub const abbr: HtmlAttr = HtmlAttr::constant("abbr");
pub const accept: HtmlAttr = HtmlAttr::constant("accept");
pub const accept_charset: HtmlAttr = HtmlAttr::constant("accept-charset");
pub const accesskey: HtmlAttr = HtmlAttr::constant("accesskey");
pub const action: HtmlAttr = HtmlAttr::constant("action");
pub const allow: HtmlAttr = HtmlAttr::constant("allow");
pub const allowfullscreen: HtmlAttr = HtmlAttr::constant("allowfullscreen");
pub const alpha: HtmlAttr = HtmlAttr::constant("alpha");
pub const alt: HtmlAttr = HtmlAttr::constant("alt");
pub const aria_activedescendant: HtmlAttr = HtmlAttr::constant("aria-activedescendant");
pub const aria_atomic: HtmlAttr = HtmlAttr::constant("aria-atomic");
pub const aria_autocomplete: HtmlAttr = HtmlAttr::constant("aria-autocomplete");
pub const aria_busy: HtmlAttr = HtmlAttr::constant("aria-busy");
pub const aria_checked: HtmlAttr = HtmlAttr::constant("aria-checked");
pub const aria_colcount: HtmlAttr = HtmlAttr::constant("aria-colcount");
pub const aria_colindex: HtmlAttr = HtmlAttr::constant("aria-colindex");
pub const aria_colspan: HtmlAttr = HtmlAttr::constant("aria-colspan");
pub const aria_controls: HtmlAttr = HtmlAttr::constant("aria-controls");
pub const aria_current: HtmlAttr = HtmlAttr::constant("aria-current");
pub const aria_describedby: HtmlAttr = HtmlAttr::constant("aria-describedby");
pub const aria_details: HtmlAttr = HtmlAttr::constant("aria-details");
pub const aria_disabled: HtmlAttr = HtmlAttr::constant("aria-disabled");
pub const aria_errormessage: HtmlAttr = HtmlAttr::constant("aria-errormessage");
pub const aria_expanded: HtmlAttr = HtmlAttr::constant("aria-expanded");
pub const aria_flowto: HtmlAttr = HtmlAttr::constant("aria-flowto");
pub const aria_haspopup: HtmlAttr = HtmlAttr::constant("aria-haspopup");
pub const aria_hidden: HtmlAttr = HtmlAttr::constant("aria-hidden");
pub const aria_invalid: HtmlAttr = HtmlAttr::constant("aria-invalid");
pub const aria_keyshortcuts: HtmlAttr = HtmlAttr::constant("aria-keyshortcuts");
pub const aria_label: HtmlAttr = HtmlAttr::constant("aria-label");
pub const aria_labelledby: HtmlAttr = HtmlAttr::constant("aria-labelledby");
pub const aria_level: HtmlAttr = HtmlAttr::constant("aria-level");
pub const aria_live: HtmlAttr = HtmlAttr::constant("aria-live");
pub const aria_modal: HtmlAttr = HtmlAttr::constant("aria-modal");
pub const aria_multiline: HtmlAttr = HtmlAttr::constant("aria-multiline");
pub const aria_multiselectable: HtmlAttr = HtmlAttr::constant("aria-multiselectable");
pub const aria_orientation: HtmlAttr = HtmlAttr::constant("aria-orientation");
pub const aria_owns: HtmlAttr = HtmlAttr::constant("aria-owns");
pub const aria_placeholder: HtmlAttr = HtmlAttr::constant("aria-placeholder");
pub const aria_posinset: HtmlAttr = HtmlAttr::constant("aria-posinset");
pub const aria_pressed: HtmlAttr = HtmlAttr::constant("aria-pressed");
pub const aria_readonly: HtmlAttr = HtmlAttr::constant("aria-readonly");
pub const aria_relevant: HtmlAttr = HtmlAttr::constant("aria-relevant");
pub const aria_required: HtmlAttr = HtmlAttr::constant("aria-required");
pub const aria_roledescription: HtmlAttr = HtmlAttr::constant("aria-roledescription");
pub const aria_rowcount: HtmlAttr = HtmlAttr::constant("aria-rowcount");
pub const aria_rowindex: HtmlAttr = HtmlAttr::constant("aria-rowindex");
pub const aria_rowspan: HtmlAttr = HtmlAttr::constant("aria-rowspan");
pub const aria_selected: HtmlAttr = HtmlAttr::constant("aria-selected");
pub const aria_setsize: HtmlAttr = HtmlAttr::constant("aria-setsize");
pub const aria_sort: HtmlAttr = HtmlAttr::constant("aria-sort");
pub const aria_valuemax: HtmlAttr = HtmlAttr::constant("aria-valuemax");
pub const aria_valuemin: HtmlAttr = HtmlAttr::constant("aria-valuemin");
pub const aria_valuenow: HtmlAttr = HtmlAttr::constant("aria-valuenow");
pub const aria_valuetext: HtmlAttr = HtmlAttr::constant("aria-valuetext");
pub const r#as: HtmlAttr = HtmlAttr::constant("as");
pub const r#async: HtmlAttr = HtmlAttr::constant("async");
pub const autocapitalize: HtmlAttr = HtmlAttr::constant("autocapitalize");
pub const autocomplete: HtmlAttr = HtmlAttr::constant("autocomplete");
pub const autocorrect: HtmlAttr = HtmlAttr::constant("autocorrect");
pub const autofocus: HtmlAttr = HtmlAttr::constant("autofocus");
pub const autoplay: HtmlAttr = HtmlAttr::constant("autoplay");
pub const blocking: HtmlAttr = HtmlAttr::constant("blocking");
pub const charset: HtmlAttr = HtmlAttr::constant("charset");
pub const checked: HtmlAttr = HtmlAttr::constant("checked");
pub const cite: HtmlAttr = HtmlAttr::constant("cite");
pub const class: HtmlAttr = HtmlAttr::constant("class");
pub const closedby: HtmlAttr = HtmlAttr::constant("closedby");
pub const color: HtmlAttr = HtmlAttr::constant("color");
pub const colorspace: HtmlAttr = HtmlAttr::constant("colorspace");
pub const cols: HtmlAttr = HtmlAttr::constant("cols");
pub const colspan: HtmlAttr = HtmlAttr::constant("colspan");
pub const command: HtmlAttr = HtmlAttr::constant("command");
pub const commandfor: HtmlAttr = HtmlAttr::constant("commandfor");
pub const content: HtmlAttr = HtmlAttr::constant("content");
pub const contenteditable: HtmlAttr = HtmlAttr::constant("contenteditable");
pub const controls: HtmlAttr = HtmlAttr::constant("controls");
pub const coords: HtmlAttr = HtmlAttr::constant("coords");
pub const crossorigin: HtmlAttr = HtmlAttr::constant("crossorigin");
pub const data: HtmlAttr = HtmlAttr::constant("data");
pub const datetime: HtmlAttr = HtmlAttr::constant("datetime");
pub const decoding: HtmlAttr = HtmlAttr::constant("decoding");
pub const default: HtmlAttr = HtmlAttr::constant("default");
pub const defer: HtmlAttr = HtmlAttr::constant("defer");
pub const dir: HtmlAttr = HtmlAttr::constant("dir");
pub const dirname: HtmlAttr = HtmlAttr::constant("dirname");
pub const disabled: HtmlAttr = HtmlAttr::constant("disabled");
pub const download: HtmlAttr = HtmlAttr::constant("download");
pub const draggable: HtmlAttr = HtmlAttr::constant("draggable");
pub const enctype: HtmlAttr = HtmlAttr::constant("enctype");
pub const enterkeyhint: HtmlAttr = HtmlAttr::constant("enterkeyhint");
pub const fetchpriority: HtmlAttr = HtmlAttr::constant("fetchpriority");
pub const r#for: HtmlAttr = HtmlAttr::constant("for");
pub const form: HtmlAttr = HtmlAttr::constant("form");
pub const formaction: HtmlAttr = HtmlAttr::constant("formaction");
pub const formenctype: HtmlAttr = HtmlAttr::constant("formenctype");
pub const formmethod: HtmlAttr = HtmlAttr::constant("formmethod");
pub const formnovalidate: HtmlAttr = HtmlAttr::constant("formnovalidate");
pub const formtarget: HtmlAttr = HtmlAttr::constant("formtarget");
pub const headers: HtmlAttr = HtmlAttr::constant("headers");
pub const height: HtmlAttr = HtmlAttr::constant("height");
pub const hidden: HtmlAttr = HtmlAttr::constant("hidden");
pub const high: HtmlAttr = HtmlAttr::constant("high");
pub const href: HtmlAttr = HtmlAttr::constant("href");
pub const hreflang: HtmlAttr = HtmlAttr::constant("hreflang");
pub const http_equiv: HtmlAttr = HtmlAttr::constant("http-equiv");
pub const id: HtmlAttr = HtmlAttr::constant("id");
pub const imagesizes: HtmlAttr = HtmlAttr::constant("imagesizes");
pub const imagesrcset: HtmlAttr = HtmlAttr::constant("imagesrcset");
pub const inert: HtmlAttr = HtmlAttr::constant("inert");
pub const inputmode: HtmlAttr = HtmlAttr::constant("inputmode");
pub const integrity: HtmlAttr = HtmlAttr::constant("integrity");
pub const is: HtmlAttr = HtmlAttr::constant("is");
pub const ismap: HtmlAttr = HtmlAttr::constant("ismap");
pub const itemid: HtmlAttr = HtmlAttr::constant("itemid");
pub const itemprop: HtmlAttr = HtmlAttr::constant("itemprop");
pub const itemref: HtmlAttr = HtmlAttr::constant("itemref");
pub const itemscope: HtmlAttr = HtmlAttr::constant("itemscope");
pub const itemtype: HtmlAttr = HtmlAttr::constant("itemtype");
pub const kind: HtmlAttr = HtmlAttr::constant("kind");
pub const label: HtmlAttr = HtmlAttr::constant("label");
pub const lang: HtmlAttr = HtmlAttr::constant("lang");
pub const list: HtmlAttr = HtmlAttr::constant("list");
pub const loading: HtmlAttr = HtmlAttr::constant("loading");
pub const r#loop: HtmlAttr = HtmlAttr::constant("loop");
pub const low: HtmlAttr = HtmlAttr::constant("low");
pub const max: HtmlAttr = HtmlAttr::constant("max");
pub const maxlength: HtmlAttr = HtmlAttr::constant("maxlength");
pub const media: HtmlAttr = HtmlAttr::constant("media");
pub const method: HtmlAttr = HtmlAttr::constant("method");
pub const min: HtmlAttr = HtmlAttr::constant("min");
pub const minlength: HtmlAttr = HtmlAttr::constant("minlength");
pub const multiple: HtmlAttr = HtmlAttr::constant("multiple");
pub const muted: HtmlAttr = HtmlAttr::constant("muted");
pub const name: HtmlAttr = HtmlAttr::constant("name");
pub const nomodule: HtmlAttr = HtmlAttr::constant("nomodule");
pub const nonce: HtmlAttr = HtmlAttr::constant("nonce");
pub const novalidate: HtmlAttr = HtmlAttr::constant("novalidate");
pub const open: HtmlAttr = HtmlAttr::constant("open");
pub const optimum: HtmlAttr = HtmlAttr::constant("optimum");
pub const pattern: HtmlAttr = HtmlAttr::constant("pattern");
pub const ping: HtmlAttr = HtmlAttr::constant("ping");
pub const placeholder: HtmlAttr = HtmlAttr::constant("placeholder");
pub const playsinline: HtmlAttr = HtmlAttr::constant("playsinline");
pub const popover: HtmlAttr = HtmlAttr::constant("popover");
pub const popovertarget: HtmlAttr = HtmlAttr::constant("popovertarget");
pub const popovertargetaction: HtmlAttr = HtmlAttr::constant("popovertargetaction");
pub const poster: HtmlAttr = HtmlAttr::constant("poster");
pub const preload: HtmlAttr = HtmlAttr::constant("preload");
pub const readonly: HtmlAttr = HtmlAttr::constant("readonly");
pub const referrerpolicy: HtmlAttr = HtmlAttr::constant("referrerpolicy");
pub const rel: HtmlAttr = HtmlAttr::constant("rel");
pub const required: HtmlAttr = HtmlAttr::constant("required");
pub const reversed: HtmlAttr = HtmlAttr::constant("reversed");
pub const role: HtmlAttr = HtmlAttr::constant("role");
pub const rows: HtmlAttr = HtmlAttr::constant("rows");
pub const rowspan: HtmlAttr = HtmlAttr::constant("rowspan");
pub const sandbox: HtmlAttr = HtmlAttr::constant("sandbox");
pub const scope: HtmlAttr = HtmlAttr::constant("scope");
pub const selected: HtmlAttr = HtmlAttr::constant("selected");
pub const shadowrootclonable: HtmlAttr = HtmlAttr::constant("shadowrootclonable");
pub const shadowrootcustomelementregistry: HtmlAttr = HtmlAttr::constant("shadowrootcustomelementregistry");
pub const shadowrootdelegatesfocus: HtmlAttr = HtmlAttr::constant("shadowrootdelegatesfocus");
pub const shadowrootmode: HtmlAttr = HtmlAttr::constant("shadowrootmode");
pub const shadowrootserializable: HtmlAttr = HtmlAttr::constant("shadowrootserializable");
pub const shape: HtmlAttr = HtmlAttr::constant("shape");
pub const size: HtmlAttr = HtmlAttr::constant("size");
pub const sizes: HtmlAttr = HtmlAttr::constant("sizes");
pub const slot: HtmlAttr = HtmlAttr::constant("slot");
pub const span: HtmlAttr = HtmlAttr::constant("span");
pub const spellcheck: HtmlAttr = HtmlAttr::constant("spellcheck");
pub const src: HtmlAttr = HtmlAttr::constant("src");
pub const srcdoc: HtmlAttr = HtmlAttr::constant("srcdoc");
pub const srclang: HtmlAttr = HtmlAttr::constant("srclang");
pub const srcset: HtmlAttr = HtmlAttr::constant("srcset");
pub const start: HtmlAttr = HtmlAttr::constant("start");
pub const step: HtmlAttr = HtmlAttr::constant("step");
pub const style: HtmlAttr = HtmlAttr::constant("style");
pub const tabindex: HtmlAttr = HtmlAttr::constant("tabindex");
pub const target: HtmlAttr = HtmlAttr::constant("target");
pub const title: HtmlAttr = HtmlAttr::constant("title");
pub const translate: HtmlAttr = HtmlAttr::constant("translate");
pub const r#type: HtmlAttr = HtmlAttr::constant("type");
pub const usemap: HtmlAttr = HtmlAttr::constant("usemap");
pub const value: HtmlAttr = HtmlAttr::constant("value");
pub const width: HtmlAttr = HtmlAttr::constant("width");
pub const wrap: HtmlAttr = HtmlAttr::constant("wrap");
pub const writingsuggestions: HtmlAttr = HtmlAttr::constant("writingsuggestions");
}

View File

@ -1,952 +0,0 @@
// This file is generated by `tools/codegen/src/html.rs`.
// Do not edit by hand.
#![cfg_attr(rustfmt, rustfmt_skip)]
use std::num::NonZeroU64;
use crate::foundations::{Datetime, Duration, PositiveF64, Smart, Str};
use crate::html::typed::*;
use crate::visualize::Color;
#[allow(non_upper_case_globals)]
pub mod tag {
use crate::html::HtmlTag;
pub const a: HtmlTag = HtmlTag::constant("a");
pub const abbr: HtmlTag = HtmlTag::constant("abbr");
pub const address: HtmlTag = HtmlTag::constant("address");
pub const area: HtmlTag = HtmlTag::constant("area");
pub const article: HtmlTag = HtmlTag::constant("article");
pub const aside: HtmlTag = HtmlTag::constant("aside");
pub const audio: HtmlTag = HtmlTag::constant("audio");
pub const b: HtmlTag = HtmlTag::constant("b");
pub const base: HtmlTag = HtmlTag::constant("base");
pub const bdi: HtmlTag = HtmlTag::constant("bdi");
pub const bdo: HtmlTag = HtmlTag::constant("bdo");
pub const blockquote: HtmlTag = HtmlTag::constant("blockquote");
pub const body: HtmlTag = HtmlTag::constant("body");
pub const br: HtmlTag = HtmlTag::constant("br");
pub const button: HtmlTag = HtmlTag::constant("button");
pub const canvas: HtmlTag = HtmlTag::constant("canvas");
pub const caption: HtmlTag = HtmlTag::constant("caption");
pub const cite: HtmlTag = HtmlTag::constant("cite");
pub const code: HtmlTag = HtmlTag::constant("code");
pub const col: HtmlTag = HtmlTag::constant("col");
pub const colgroup: HtmlTag = HtmlTag::constant("colgroup");
pub const data: HtmlTag = HtmlTag::constant("data");
pub const datalist: HtmlTag = HtmlTag::constant("datalist");
pub const dd: HtmlTag = HtmlTag::constant("dd");
pub const del: HtmlTag = HtmlTag::constant("del");
pub const details: HtmlTag = HtmlTag::constant("details");
pub const dfn: HtmlTag = HtmlTag::constant("dfn");
pub const dialog: HtmlTag = HtmlTag::constant("dialog");
pub const div: HtmlTag = HtmlTag::constant("div");
pub const dl: HtmlTag = HtmlTag::constant("dl");
pub const dt: HtmlTag = HtmlTag::constant("dt");
pub const em: HtmlTag = HtmlTag::constant("em");
pub const embed: HtmlTag = HtmlTag::constant("embed");
pub const fieldset: HtmlTag = HtmlTag::constant("fieldset");
pub const figcaption: HtmlTag = HtmlTag::constant("figcaption");
pub const figure: HtmlTag = HtmlTag::constant("figure");
pub const footer: HtmlTag = HtmlTag::constant("footer");
pub const form: HtmlTag = HtmlTag::constant("form");
pub const h1: HtmlTag = HtmlTag::constant("h1");
pub const h2: HtmlTag = HtmlTag::constant("h2");
pub const h3: HtmlTag = HtmlTag::constant("h3");
pub const h4: HtmlTag = HtmlTag::constant("h4");
pub const h5: HtmlTag = HtmlTag::constant("h5");
pub const h6: HtmlTag = HtmlTag::constant("h6");
pub const head: HtmlTag = HtmlTag::constant("head");
pub const header: HtmlTag = HtmlTag::constant("header");
pub const hgroup: HtmlTag = HtmlTag::constant("hgroup");
pub const hr: HtmlTag = HtmlTag::constant("hr");
pub const html: HtmlTag = HtmlTag::constant("html");
pub const i: HtmlTag = HtmlTag::constant("i");
pub const iframe: HtmlTag = HtmlTag::constant("iframe");
pub const img: HtmlTag = HtmlTag::constant("img");
pub const input: HtmlTag = HtmlTag::constant("input");
pub const ins: HtmlTag = HtmlTag::constant("ins");
pub const kbd: HtmlTag = HtmlTag::constant("kbd");
pub const label: HtmlTag = HtmlTag::constant("label");
pub const legend: HtmlTag = HtmlTag::constant("legend");
pub const li: HtmlTag = HtmlTag::constant("li");
pub const link: HtmlTag = HtmlTag::constant("link");
pub const main: HtmlTag = HtmlTag::constant("main");
pub const map: HtmlTag = HtmlTag::constant("map");
pub const mark: HtmlTag = HtmlTag::constant("mark");
pub const menu: HtmlTag = HtmlTag::constant("menu");
pub const meta: HtmlTag = HtmlTag::constant("meta");
pub const meter: HtmlTag = HtmlTag::constant("meter");
pub const nav: HtmlTag = HtmlTag::constant("nav");
pub const noscript: HtmlTag = HtmlTag::constant("noscript");
pub const object: HtmlTag = HtmlTag::constant("object");
pub const ol: HtmlTag = HtmlTag::constant("ol");
pub const optgroup: HtmlTag = HtmlTag::constant("optgroup");
pub const option: HtmlTag = HtmlTag::constant("option");
pub const output: HtmlTag = HtmlTag::constant("output");
pub const p: HtmlTag = HtmlTag::constant("p");
pub const picture: HtmlTag = HtmlTag::constant("picture");
pub const pre: HtmlTag = HtmlTag::constant("pre");
pub const progress: HtmlTag = HtmlTag::constant("progress");
pub const q: HtmlTag = HtmlTag::constant("q");
pub const rp: HtmlTag = HtmlTag::constant("rp");
pub const rt: HtmlTag = HtmlTag::constant("rt");
pub const ruby: HtmlTag = HtmlTag::constant("ruby");
pub const s: HtmlTag = HtmlTag::constant("s");
pub const samp: HtmlTag = HtmlTag::constant("samp");
pub const script: HtmlTag = HtmlTag::constant("script");
pub const search: HtmlTag = HtmlTag::constant("search");
pub const section: HtmlTag = HtmlTag::constant("section");
pub const select: HtmlTag = HtmlTag::constant("select");
pub const slot: HtmlTag = HtmlTag::constant("slot");
pub const small: HtmlTag = HtmlTag::constant("small");
pub const source: HtmlTag = HtmlTag::constant("source");
pub const span: HtmlTag = HtmlTag::constant("span");
pub const strong: HtmlTag = HtmlTag::constant("strong");
pub const style: HtmlTag = HtmlTag::constant("style");
pub const sub: HtmlTag = HtmlTag::constant("sub");
pub const summary: HtmlTag = HtmlTag::constant("summary");
pub const sup: HtmlTag = HtmlTag::constant("sup");
pub const table: HtmlTag = HtmlTag::constant("table");
pub const tbody: HtmlTag = HtmlTag::constant("tbody");
pub const td: HtmlTag = HtmlTag::constant("td");
pub const template: HtmlTag = HtmlTag::constant("template");
pub const textarea: HtmlTag = HtmlTag::constant("textarea");
pub const tfoot: HtmlTag = HtmlTag::constant("tfoot");
pub const th: HtmlTag = HtmlTag::constant("th");
pub const thead: HtmlTag = HtmlTag::constant("thead");
pub const time: HtmlTag = HtmlTag::constant("time");
pub const title: HtmlTag = HtmlTag::constant("title");
pub const tr: HtmlTag = HtmlTag::constant("tr");
pub const track: HtmlTag = HtmlTag::constant("track");
pub const u: HtmlTag = HtmlTag::constant("u");
pub const ul: HtmlTag = HtmlTag::constant("ul");
pub const var: HtmlTag = HtmlTag::constant("var");
pub const video: HtmlTag = HtmlTag::constant("video");
pub const wbr: HtmlTag = HtmlTag::constant("wbr");
}
#[allow(non_upper_case_globals)]
pub mod attr {
use crate::html::HtmlAttr;
pub const abbr: HtmlAttr = HtmlAttr::constant("abbr");
pub const accept: HtmlAttr = HtmlAttr::constant("accept");
pub const accept_charset: HtmlAttr = HtmlAttr::constant("accept-charset");
pub const accesskey: HtmlAttr = HtmlAttr::constant("accesskey");
pub const action: HtmlAttr = HtmlAttr::constant("action");
pub const allow: HtmlAttr = HtmlAttr::constant("allow");
pub const allowfullscreen: HtmlAttr = HtmlAttr::constant("allowfullscreen");
pub const alpha: HtmlAttr = HtmlAttr::constant("alpha");
pub const alt: HtmlAttr = HtmlAttr::constant("alt");
pub const aria_activedescendant: HtmlAttr = HtmlAttr::constant("aria-activedescendant");
pub const aria_atomic: HtmlAttr = HtmlAttr::constant("aria-atomic");
pub const aria_autocomplete: HtmlAttr = HtmlAttr::constant("aria-autocomplete");
pub const aria_busy: HtmlAttr = HtmlAttr::constant("aria-busy");
pub const aria_checked: HtmlAttr = HtmlAttr::constant("aria-checked");
pub const aria_colcount: HtmlAttr = HtmlAttr::constant("aria-colcount");
pub const aria_colindex: HtmlAttr = HtmlAttr::constant("aria-colindex");
pub const aria_colspan: HtmlAttr = HtmlAttr::constant("aria-colspan");
pub const aria_controls: HtmlAttr = HtmlAttr::constant("aria-controls");
pub const aria_current: HtmlAttr = HtmlAttr::constant("aria-current");
pub const aria_describedby: HtmlAttr = HtmlAttr::constant("aria-describedby");
pub const aria_details: HtmlAttr = HtmlAttr::constant("aria-details");
pub const aria_disabled: HtmlAttr = HtmlAttr::constant("aria-disabled");
pub const aria_errormessage: HtmlAttr = HtmlAttr::constant("aria-errormessage");
pub const aria_expanded: HtmlAttr = HtmlAttr::constant("aria-expanded");
pub const aria_flowto: HtmlAttr = HtmlAttr::constant("aria-flowto");
pub const aria_haspopup: HtmlAttr = HtmlAttr::constant("aria-haspopup");
pub const aria_hidden: HtmlAttr = HtmlAttr::constant("aria-hidden");
pub const aria_invalid: HtmlAttr = HtmlAttr::constant("aria-invalid");
pub const aria_keyshortcuts: HtmlAttr = HtmlAttr::constant("aria-keyshortcuts");
pub const aria_label: HtmlAttr = HtmlAttr::constant("aria-label");
pub const aria_labelledby: HtmlAttr = HtmlAttr::constant("aria-labelledby");
pub const aria_level: HtmlAttr = HtmlAttr::constant("aria-level");
pub const aria_live: HtmlAttr = HtmlAttr::constant("aria-live");
pub const aria_modal: HtmlAttr = HtmlAttr::constant("aria-modal");
pub const aria_multiline: HtmlAttr = HtmlAttr::constant("aria-multiline");
pub const aria_multiselectable: HtmlAttr = HtmlAttr::constant("aria-multiselectable");
pub const aria_orientation: HtmlAttr = HtmlAttr::constant("aria-orientation");
pub const aria_owns: HtmlAttr = HtmlAttr::constant("aria-owns");
pub const aria_placeholder: HtmlAttr = HtmlAttr::constant("aria-placeholder");
pub const aria_posinset: HtmlAttr = HtmlAttr::constant("aria-posinset");
pub const aria_pressed: HtmlAttr = HtmlAttr::constant("aria-pressed");
pub const aria_readonly: HtmlAttr = HtmlAttr::constant("aria-readonly");
pub const aria_relevant: HtmlAttr = HtmlAttr::constant("aria-relevant");
pub const aria_required: HtmlAttr = HtmlAttr::constant("aria-required");
pub const aria_roledescription: HtmlAttr = HtmlAttr::constant("aria-roledescription");
pub const aria_rowcount: HtmlAttr = HtmlAttr::constant("aria-rowcount");
pub const aria_rowindex: HtmlAttr = HtmlAttr::constant("aria-rowindex");
pub const aria_rowspan: HtmlAttr = HtmlAttr::constant("aria-rowspan");
pub const aria_selected: HtmlAttr = HtmlAttr::constant("aria-selected");
pub const aria_setsize: HtmlAttr = HtmlAttr::constant("aria-setsize");
pub const aria_sort: HtmlAttr = HtmlAttr::constant("aria-sort");
pub const aria_valuemax: HtmlAttr = HtmlAttr::constant("aria-valuemax");
pub const aria_valuemin: HtmlAttr = HtmlAttr::constant("aria-valuemin");
pub const aria_valuenow: HtmlAttr = HtmlAttr::constant("aria-valuenow");
pub const aria_valuetext: HtmlAttr = HtmlAttr::constant("aria-valuetext");
pub const r#as: HtmlAttr = HtmlAttr::constant("as");
pub const r#async: HtmlAttr = HtmlAttr::constant("async");
pub const autocapitalize: HtmlAttr = HtmlAttr::constant("autocapitalize");
pub const autocomplete: HtmlAttr = HtmlAttr::constant("autocomplete");
pub const autocorrect: HtmlAttr = HtmlAttr::constant("autocorrect");
pub const autofocus: HtmlAttr = HtmlAttr::constant("autofocus");
pub const autoplay: HtmlAttr = HtmlAttr::constant("autoplay");
pub const blocking: HtmlAttr = HtmlAttr::constant("blocking");
pub const charset: HtmlAttr = HtmlAttr::constant("charset");
pub const checked: HtmlAttr = HtmlAttr::constant("checked");
pub const cite: HtmlAttr = HtmlAttr::constant("cite");
pub const class: HtmlAttr = HtmlAttr::constant("class");
pub const closedby: HtmlAttr = HtmlAttr::constant("closedby");
pub const color: HtmlAttr = HtmlAttr::constant("color");
pub const colorspace: HtmlAttr = HtmlAttr::constant("colorspace");
pub const cols: HtmlAttr = HtmlAttr::constant("cols");
pub const colspan: HtmlAttr = HtmlAttr::constant("colspan");
pub const command: HtmlAttr = HtmlAttr::constant("command");
pub const commandfor: HtmlAttr = HtmlAttr::constant("commandfor");
pub const content: HtmlAttr = HtmlAttr::constant("content");
pub const contenteditable: HtmlAttr = HtmlAttr::constant("contenteditable");
pub const controls: HtmlAttr = HtmlAttr::constant("controls");
pub const coords: HtmlAttr = HtmlAttr::constant("coords");
pub const crossorigin: HtmlAttr = HtmlAttr::constant("crossorigin");
pub const data: HtmlAttr = HtmlAttr::constant("data");
pub const datetime: HtmlAttr = HtmlAttr::constant("datetime");
pub const decoding: HtmlAttr = HtmlAttr::constant("decoding");
pub const default: HtmlAttr = HtmlAttr::constant("default");
pub const defer: HtmlAttr = HtmlAttr::constant("defer");
pub const dir: HtmlAttr = HtmlAttr::constant("dir");
pub const dirname: HtmlAttr = HtmlAttr::constant("dirname");
pub const disabled: HtmlAttr = HtmlAttr::constant("disabled");
pub const download: HtmlAttr = HtmlAttr::constant("download");
pub const draggable: HtmlAttr = HtmlAttr::constant("draggable");
pub const enctype: HtmlAttr = HtmlAttr::constant("enctype");
pub const enterkeyhint: HtmlAttr = HtmlAttr::constant("enterkeyhint");
pub const fetchpriority: HtmlAttr = HtmlAttr::constant("fetchpriority");
pub const r#for: HtmlAttr = HtmlAttr::constant("for");
pub const form: HtmlAttr = HtmlAttr::constant("form");
pub const formaction: HtmlAttr = HtmlAttr::constant("formaction");
pub const formenctype: HtmlAttr = HtmlAttr::constant("formenctype");
pub const formmethod: HtmlAttr = HtmlAttr::constant("formmethod");
pub const formnovalidate: HtmlAttr = HtmlAttr::constant("formnovalidate");
pub const formtarget: HtmlAttr = HtmlAttr::constant("formtarget");
pub const headers: HtmlAttr = HtmlAttr::constant("headers");
pub const height: HtmlAttr = HtmlAttr::constant("height");
pub const hidden: HtmlAttr = HtmlAttr::constant("hidden");
pub const high: HtmlAttr = HtmlAttr::constant("high");
pub const href: HtmlAttr = HtmlAttr::constant("href");
pub const hreflang: HtmlAttr = HtmlAttr::constant("hreflang");
pub const http_equiv: HtmlAttr = HtmlAttr::constant("http-equiv");
pub const id: HtmlAttr = HtmlAttr::constant("id");
pub const imagesizes: HtmlAttr = HtmlAttr::constant("imagesizes");
pub const imagesrcset: HtmlAttr = HtmlAttr::constant("imagesrcset");
pub const inert: HtmlAttr = HtmlAttr::constant("inert");
pub const inputmode: HtmlAttr = HtmlAttr::constant("inputmode");
pub const integrity: HtmlAttr = HtmlAttr::constant("integrity");
pub const is: HtmlAttr = HtmlAttr::constant("is");
pub const ismap: HtmlAttr = HtmlAttr::constant("ismap");
pub const itemid: HtmlAttr = HtmlAttr::constant("itemid");
pub const itemprop: HtmlAttr = HtmlAttr::constant("itemprop");
pub const itemref: HtmlAttr = HtmlAttr::constant("itemref");
pub const itemscope: HtmlAttr = HtmlAttr::constant("itemscope");
pub const itemtype: HtmlAttr = HtmlAttr::constant("itemtype");
pub const kind: HtmlAttr = HtmlAttr::constant("kind");
pub const label: HtmlAttr = HtmlAttr::constant("label");
pub const lang: HtmlAttr = HtmlAttr::constant("lang");
pub const list: HtmlAttr = HtmlAttr::constant("list");
pub const loading: HtmlAttr = HtmlAttr::constant("loading");
pub const r#loop: HtmlAttr = HtmlAttr::constant("loop");
pub const low: HtmlAttr = HtmlAttr::constant("low");
pub const max: HtmlAttr = HtmlAttr::constant("max");
pub const maxlength: HtmlAttr = HtmlAttr::constant("maxlength");
pub const media: HtmlAttr = HtmlAttr::constant("media");
pub const method: HtmlAttr = HtmlAttr::constant("method");
pub const min: HtmlAttr = HtmlAttr::constant("min");
pub const minlength: HtmlAttr = HtmlAttr::constant("minlength");
pub const multiple: HtmlAttr = HtmlAttr::constant("multiple");
pub const muted: HtmlAttr = HtmlAttr::constant("muted");
pub const name: HtmlAttr = HtmlAttr::constant("name");
pub const nomodule: HtmlAttr = HtmlAttr::constant("nomodule");
pub const nonce: HtmlAttr = HtmlAttr::constant("nonce");
pub const novalidate: HtmlAttr = HtmlAttr::constant("novalidate");
pub const open: HtmlAttr = HtmlAttr::constant("open");
pub const optimum: HtmlAttr = HtmlAttr::constant("optimum");
pub const pattern: HtmlAttr = HtmlAttr::constant("pattern");
pub const ping: HtmlAttr = HtmlAttr::constant("ping");
pub const placeholder: HtmlAttr = HtmlAttr::constant("placeholder");
pub const playsinline: HtmlAttr = HtmlAttr::constant("playsinline");
pub const popover: HtmlAttr = HtmlAttr::constant("popover");
pub const popovertarget: HtmlAttr = HtmlAttr::constant("popovertarget");
pub const popovertargetaction: HtmlAttr = HtmlAttr::constant("popovertargetaction");
pub const poster: HtmlAttr = HtmlAttr::constant("poster");
pub const preload: HtmlAttr = HtmlAttr::constant("preload");
pub const readonly: HtmlAttr = HtmlAttr::constant("readonly");
pub const referrerpolicy: HtmlAttr = HtmlAttr::constant("referrerpolicy");
pub const rel: HtmlAttr = HtmlAttr::constant("rel");
pub const required: HtmlAttr = HtmlAttr::constant("required");
pub const reversed: HtmlAttr = HtmlAttr::constant("reversed");
pub const role: HtmlAttr = HtmlAttr::constant("role");
pub const rows: HtmlAttr = HtmlAttr::constant("rows");
pub const rowspan: HtmlAttr = HtmlAttr::constant("rowspan");
pub const sandbox: HtmlAttr = HtmlAttr::constant("sandbox");
pub const scope: HtmlAttr = HtmlAttr::constant("scope");
pub const selected: HtmlAttr = HtmlAttr::constant("selected");
pub const shadowrootclonable: HtmlAttr = HtmlAttr::constant("shadowrootclonable");
pub const shadowrootcustomelementregistry: HtmlAttr = HtmlAttr::constant("shadowrootcustomelementregistry");
pub const shadowrootdelegatesfocus: HtmlAttr = HtmlAttr::constant("shadowrootdelegatesfocus");
pub const shadowrootmode: HtmlAttr = HtmlAttr::constant("shadowrootmode");
pub const shadowrootserializable: HtmlAttr = HtmlAttr::constant("shadowrootserializable");
pub const shape: HtmlAttr = HtmlAttr::constant("shape");
pub const size: HtmlAttr = HtmlAttr::constant("size");
pub const sizes: HtmlAttr = HtmlAttr::constant("sizes");
pub const slot: HtmlAttr = HtmlAttr::constant("slot");
pub const span: HtmlAttr = HtmlAttr::constant("span");
pub const spellcheck: HtmlAttr = HtmlAttr::constant("spellcheck");
pub const src: HtmlAttr = HtmlAttr::constant("src");
pub const srcdoc: HtmlAttr = HtmlAttr::constant("srcdoc");
pub const srclang: HtmlAttr = HtmlAttr::constant("srclang");
pub const srcset: HtmlAttr = HtmlAttr::constant("srcset");
pub const start: HtmlAttr = HtmlAttr::constant("start");
pub const step: HtmlAttr = HtmlAttr::constant("step");
pub const style: HtmlAttr = HtmlAttr::constant("style");
pub const tabindex: HtmlAttr = HtmlAttr::constant("tabindex");
pub const target: HtmlAttr = HtmlAttr::constant("target");
pub const title: HtmlAttr = HtmlAttr::constant("title");
pub const translate: HtmlAttr = HtmlAttr::constant("translate");
pub const r#type: HtmlAttr = HtmlAttr::constant("type");
pub const usemap: HtmlAttr = HtmlAttr::constant("usemap");
pub const value: HtmlAttr = HtmlAttr::constant("value");
pub const width: HtmlAttr = HtmlAttr::constant("width");
pub const wrap: HtmlAttr = HtmlAttr::constant("wrap");
pub const writingsuggestions: HtmlAttr = HtmlAttr::constant("writingsuggestions");
}
pub const ELEMENTS: &[ElementInfo] = &[
ElementInfo::new("a", "Hyperlink.", &[115, 129, 132, 167, 176, 177, 203, 210]),
ElementInfo::new("abbr", "Abbreviation.", &[]),
ElementInfo::new("address", "Contact information for a page or article element.", &[]),
ElementInfo::new("area", "Hyperlink or dead area on an image map.", &[83, 102, 115, 129, 167, 176, 177, 192, 203]),
ElementInfo::new("article", "Self-contained syndicatable or reusable composition.", &[]),
ElementInfo::new("aside", "Sidebar for tangentially related content.", &[]),
ElementInfo::new("audio", "Audio player.", &[88, 101, 103, 142, 153, 173, 197]),
ElementInfo::new("b", "Keywords.", &[]),
ElementInfo::new("base", "Base URL and default target navigable for hyperlinks and forms.", &[131, 204]),
ElementInfo::new("bdi", "Text directionality isolation.", &[]),
ElementInfo::new("bdo", "Text directionality formatting.", &[]),
ElementInfo::new("blockquote", "A section quoted from another source.", &[92]),
ElementInfo::new("body", "Document body.", &[]),
ElementInfo::new("br", "Line break, e.g. in poem or postal address.", &[]),
ElementInfo::new("button", "Button control.", &[98, 99, 112, 120, 121, 122, 123, 124, 125, 154, 170, 171, 211, 217]),
ElementInfo::new("canvas", "Scriptable bitmap canvas.", &[127, 222]),
ElementInfo::new("caption", "Table caption.", &[]),
ElementInfo::new("cite", "Title of a work.", &[]),
ElementInfo::new("code", "Computer code.", &[]),
ElementInfo::new("col", "Table column.", &[196]),
ElementInfo::new("colgroup", "Group of columns in a table.", &[196]),
ElementInfo::new("data", "Machine-readable equivalent.", &[218]),
ElementInfo::new("datalist", "Container for options for combo box control.", &[]),
ElementInfo::new("dd", "Content for corresponding dt element(s).", &[]),
ElementInfo::new("del", "A removal from the document.", &[92, 105]),
ElementInfo::new("details", "Disclosure control for hiding details.", &[155, 163]),
ElementInfo::new("dfn", "Defining instance.", &[]),
ElementInfo::new("dialog", "Dialog box or window.", &[164]),
ElementInfo::new("div", "Generic flow container, or container for name-value groups in dl elements.", &[]),
ElementInfo::new("dl", "Association list consisting of zero or more name-value groups.", &[]),
ElementInfo::new("dt", "Legend for corresponding dd element(s).", &[]),
ElementInfo::new("em", "Stress emphasis.", &[]),
ElementInfo::new("embed", "Plugin.", &[127, 197, 212, 222]),
ElementInfo::new("fieldset", "Group of form controls.", &[113, 120, 154]),
ElementInfo::new("figcaption", "Caption for figure.", &[]),
ElementInfo::new("figure", "Figure with optional caption.", &[]),
ElementInfo::new("footer", "Footer for a page or section.", &[]),
ElementInfo::new("form", "User-submittable form.", &[78, 79, 86, 116, 148, 156, 162, 179, 205]),
ElementInfo::new("h1", "Heading.", &[]),
ElementInfo::new("h2", "Heading.", &[]),
ElementInfo::new("h3", "Heading.", &[]),
ElementInfo::new("h4", "Heading.", &[]),
ElementInfo::new("h5", "Heading.", &[]),
ElementInfo::new("h6", "Heading.", &[]),
ElementInfo::new("head", "Container for document metadata.", &[]),
ElementInfo::new("header", "Introductory or navigational aids for a page or section.", &[]),
ElementInfo::new("hgroup", "Heading container.", &[]),
ElementInfo::new("hr", "Thematic break.", &[]),
ElementInfo::new("html", "Root element.", &[]),
ElementInfo::new("i", "Alternate voice.", &[]),
ElementInfo::new("iframe", "Child navigable.", &[80, 81, 127, 141, 157, 176, 184, 197, 198, 222]),
ElementInfo::new("img", "Image.", &[83, 103, 107, 117, 127, 137, 141, 176, 195, 197, 200, 216, 222]),
ElementInfo::new("input", "Form control.", &[77, 82, 83, 87, 91, 95, 111, 112, 120, 121, 122, 123, 124, 125, 127, 140, 144, 146, 149, 151, 152, 154, 166, 168, 170, 171, 174, 180, 193, 197, 202, 213, 219, 222]),
ElementInfo::new("ins", "An addition to the document.", &[92, 105]),
ElementInfo::new("kbd", "User input.", &[]),
ElementInfo::new("label", "Caption for a form control.", &[118]),
ElementInfo::new("legend", "Caption for fieldset.", &[]),
ElementInfo::new("li", "List item.", &[220]),
ElementInfo::new("link", "Link metadata.", &[84, 89, 94, 103, 114, 117, 130, 132, 134, 135, 136, 147, 176, 178, 194, 210]),
ElementInfo::new("main", "Container for the dominant contents of the document.", &[]),
ElementInfo::new("map", "Image map.", &[158]),
ElementInfo::new("mark", "Highlight.", &[]),
ElementInfo::new("menu", "Menu of commands.", &[]),
ElementInfo::new("meta", "Text metadata.", &[90, 100, 133, 147, 159]),
ElementInfo::new("meter", "Gauge.", &[128, 143, 145, 150, 165, 221]),
ElementInfo::new("nav", "Section with navigational links.", &[]),
ElementInfo::new("noscript", "Fallback content for script.", &[]),
ElementInfo::new("object", "Image, child navigable, or plugin.", &[104, 120, 127, 157, 212, 222]),
ElementInfo::new("ol", "Ordered list.", &[181, 201, 214]),
ElementInfo::new("optgroup", "Group of options in a list box.", &[112, 139]),
ElementInfo::new("option", "Option in a list box or combo box control.", &[112, 139, 186, 217]),
ElementInfo::new("output", "Calculated output value.", &[119, 120, 154]),
ElementInfo::new("p", "Paragraph.", &[]),
ElementInfo::new("picture", "Image.", &[]),
ElementInfo::new("pre", "Block of preformatted text.", &[]),
ElementInfo::new("progress", "Progress bar.", &[145, 221]),
ElementInfo::new("q", "Quotation.", &[92]),
ElementInfo::new("rp", "Parenthesis for ruby annotation text.", &[]),
ElementInfo::new("rt", "Ruby annotation text.", &[]),
ElementInfo::new("ruby", "Ruby annotation(s).", &[]),
ElementInfo::new("s", "Inaccurate text.", &[]),
ElementInfo::new("samp", "Computer output.", &[]),
ElementInfo::new("script", "Embedded script.", &[85, 89, 103, 109, 117, 136, 161, 176, 197, 215]),
ElementInfo::new("search", "Container for search controls.", &[]),
ElementInfo::new("section", "Generic document or application section.", &[]),
ElementInfo::new("select", "List box control.", &[87, 112, 120, 152, 154, 180, 193]),
ElementInfo::new("slot", "Shadow tree slot.", &[160]),
ElementInfo::new("small", "Side comment.", &[]),
ElementInfo::new("source", "Image source for img or media source for video or audio.", &[127, 147, 195, 197, 200, 212, 222]),
ElementInfo::new("span", "Generic phrasing container.", &[]),
ElementInfo::new("strong", "Importance.", &[]),
ElementInfo::new("style", "Embedded styling information.", &[89, 147]),
ElementInfo::new("sub", "Subscript.", &[]),
ElementInfo::new("summary", "Caption for details.", &[]),
ElementInfo::new("sup", "Superscript.", &[]),
ElementInfo::new("table", "Table.", &[]),
ElementInfo::new("tbody", "Group of rows in a table.", &[]),
ElementInfo::new("td", "Table cell.", &[97, 126, 183]),
ElementInfo::new("template", "Template.", &[187, 188, 189, 190, 191]),
ElementInfo::new("textarea", "Multiline text controls.", &[87, 96, 111, 112, 120, 146, 151, 154, 168, 174, 180, 182, 223]),
ElementInfo::new("tfoot", "Group of footer rows in a table.", &[]),
ElementInfo::new("th", "Table header cell.", &[76, 97, 126, 183, 185]),
ElementInfo::new("thead", "Group of heading rows in a table.", &[]),
ElementInfo::new("time", "Machine-readable equivalent of date- or time-related data.", &[106]),
ElementInfo::new("title", "Document title.", &[]),
ElementInfo::new("tr", "Table row.", &[]),
ElementInfo::new("track", "Timed text track.", &[108, 138, 139, 197, 199]),
ElementInfo::new("u", "Unarticulated annotation.", &[]),
ElementInfo::new("ul", "List.", &[]),
ElementInfo::new("var", "Variable.", &[]),
ElementInfo::new("video", "Video player.", &[88, 101, 103, 127, 142, 153, 169, 172, 173, 197, 222]),
ElementInfo::new("wbr", "Line breaking opportunity.", &[]),
];
pub const ATTRS: &[AttrInfo] = &[
AttrInfo::new::<TokenList<char, ','>>("accesskey", "Keyboard shortcut to activate or focus element. Expects a single-codepoint string or an array thereof."),
AttrInfo::new::<Str>("aria-activedescendant", "Identifies the currently active element when DOM focus is on a composite widget, textbox, group, or application."),
AttrInfo::new::<StrBool>("aria-atomic", "Indicates whether assistive technologies will present all, or only parts of, the changed region based on the change notifications defined by the aria-relevant attribute."),
AttrInfo::new::<StrOptionNone<StrEnum<255, 258>>>("aria-autocomplete", "Indicates whether inputting text could trigger display of one or more predictions of the user's intended value for an input and specifies how predictions would be presented if they are made."),
AttrInfo::new::<StrBool>("aria-busy", "Indicates an element is being modified and that assistive technologies MAY want to wait until the modifications are complete before exposing them to the user."),
AttrInfo::new::<Or<StrBool, StrEnum<258, 259>>>("aria-checked", "Indicates the current \"checked\" state of checkboxes, radio buttons, and other widgets. See related aria-pressed and aria-selected."),
AttrInfo::new::<i64>("aria-colcount", "Defines the total number of columns in a table, grid, or treegrid. See related aria-colindex."),
AttrInfo::new::<i64>("aria-colindex", "Defines an element's column index or position with respect to the total number of columns within a table, grid, or treegrid. See related aria-colcount and aria-colspan."),
AttrInfo::new::<i64>("aria-colspan", "Defines the number of columns spanned by a cell or gridcell within a table, grid, or treegrid. See related aria-colindex and aria-rowspan."),
AttrInfo::new::<TokenList<Str, ' '>>("aria-controls", "Identifies the element (or elements) whose contents or presence are controlled by the current element. See related aria-owns."),
AttrInfo::new::<Or<StrBool, StrEnum<259, 264>>>("aria-current", "Indicates the element that represents the current item within a container or set of related elements."),
AttrInfo::new::<TokenList<Str, ' '>>("aria-describedby", "Identifies the element (or elements) that describes the object. See related aria-labelledby."),
AttrInfo::new::<Str>("aria-details", "Identifies the element that provides a detailed, extended description for the object. See related aria-describedby."),
AttrInfo::new::<StrBool>("aria-disabled", "Indicates that the element is perceivable but disabled, so it is not editable or otherwise operable. See related aria-hidden and aria-readonly."),
AttrInfo::new::<Str>("aria-errormessage", "Identifies the element that provides an error message for the object. See related aria-invalid and aria-describedby."),
AttrInfo::new::<StrOptionUndefined<StrBool>>("aria-expanded", "Indicates whether the element, or another grouping element it controls, is currently expanded or collapsed."),
AttrInfo::new::<TokenList<Str, ' '>>("aria-flowto", "Identifies the next element (or elements) in an alternate reading order of content which, at the user's discretion, allows assistive technology to override the general default of reading in document source order."),
AttrInfo::new::<Or<StrBool, StrEnum<264, 269>>>("aria-haspopup", "Indicates the availability and type of interactive popup element, such as menu or dialog, that can be triggered by an element."),
AttrInfo::new::<StrOptionUndefined<StrBool>>("aria-hidden", "Indicates whether the element is exposed to an accessibility API. See related aria-disabled."),
AttrInfo::new::<Or<StrBool, StrEnum<269, 271>>>("aria-invalid", "Indicates the entered value does not conform to the format expected by the application. See related aria-errormessage."),
AttrInfo::new::<Str>("aria-keyshortcuts", "Indicates keyboard shortcuts that an author has implemented to activate or give focus to an element."),
AttrInfo::new::<Str>("aria-label", "Defines a string value that labels the current element. See related aria-labelledby."),
AttrInfo::new::<TokenList<Str, ' '>>("aria-labelledby", "Identifies the element (or elements) that labels the current element. See related aria-describedby."),
AttrInfo::new::<i64>("aria-level", "Defines the hierarchical level of an element within a structure."),
AttrInfo::new::<StrEnum<271, 274>>("aria-live", "Indicates that an element will be updated, and describes the types of updates the user agents, assistive technologies, and user can expect from the live region."),
AttrInfo::new::<StrBool>("aria-modal", "Indicates whether an element is modal when displayed."),
AttrInfo::new::<StrBool>("aria-multiline", "Indicates whether a text box accepts multiple lines of input or only a single line."),
AttrInfo::new::<StrBool>("aria-multiselectable", "Indicates that the user may select more than one item from the current selectable descendants."),
AttrInfo::new::<StrEnum<274, 277>>("aria-orientation", "Indicates whether the element's orientation is horizontal, vertical, or unknown/ambiguous."),
AttrInfo::new::<TokenList<Str, ' '>>("aria-owns", "Identifies an element (or elements) in order to define a visual, functional, or contextual parent/child relationship between DOM elements where the DOM hierarchy cannot be used to represent the relationship. See related aria-controls."),
AttrInfo::new::<Str>("aria-placeholder", "Defines a short hint (a word or short phrase) intended to aid the user with data entry when the control has no value. A hint could be a sample value or a brief description of the expected format."),
AttrInfo::new::<i64>("aria-posinset", "Defines an element's number or position in the current set of listitems or treeitems. Not required if all elements in the set are present in the DOM. See related aria-setsize."),
AttrInfo::new::<Or<StrBool, StrEnum<258, 259>>>("aria-pressed", "Indicates the current \"pressed\" state of toggle buttons. See related aria-checked and aria-selected."),
AttrInfo::new::<StrBool>("aria-readonly", "Indicates that the element is not editable, but is otherwise operable. See related aria-disabled."),
AttrInfo::new::<TokenList<StrEnum<277, 282>, ' '>>("aria-relevant", "Indicates what notifications the user agent will trigger when the accessibility tree within a live region is modified. See related aria-atomic."),
AttrInfo::new::<StrBool>("aria-required", "Indicates that user input is required on the element before a form may be submitted."),
AttrInfo::new::<Str>("aria-roledescription", "Defines a human-readable, author-localized description for the role of an element."),
AttrInfo::new::<i64>("aria-rowcount", "Defines the total number of rows in a table, grid, or treegrid. See related aria-rowindex."),
AttrInfo::new::<i64>("aria-rowindex", "Defines an element's row index or position with respect to the total number of rows within a table, grid, or treegrid. See related aria-rowcount and aria-rowspan."),
AttrInfo::new::<i64>("aria-rowspan", "Defines the number of rows spanned by a cell or gridcell within a table, grid, or treegrid. See related aria-rowindex and aria-colspan."),
AttrInfo::new::<StrOptionUndefined<StrBool>>("aria-selected", "Indicates the current \"selected\" state of various widgets. See related aria-checked and aria-pressed."),
AttrInfo::new::<i64>("aria-setsize", "Defines the number of items in the current set of listitems or treeitems. Not required if all elements in the set are present in the DOM. See related aria-posinset."),
AttrInfo::new::<StrOptionNone<StrEnum<282, 285>>>("aria-sort", "Indicates if items in a table or grid are sorted in ascending or descending order."),
AttrInfo::new::<f64>("aria-valuemax", "Defines the maximum allowed value for a range widget."),
AttrInfo::new::<f64>("aria-valuemin", "Defines the minimum allowed value for a range widget."),
AttrInfo::new::<f64>("aria-valuenow", "Defines the current value for a range widget. See related aria-valuetext."),
AttrInfo::new::<Str>("aria-valuetext", "Defines the human readable text alternative of aria-valuenow for a range widget."),
AttrInfo::new::<StrOptionNone<Or<OnOffBool, StrEnum<23, 26>>>>("autocapitalize", "Recommended autocapitalization behavior (for supported input methods)."),
AttrInfo::new::<OnOffBool>("autocorrect", "Recommended autocorrection behavior (for supported input methods)."),
AttrInfo::new::<NamedBool>("autofocus", "Automatically focus the element when the page is loaded."),
AttrInfo::new::<TokenList<Str, ' '>>("class", "Classes to which the element belongs."),
AttrInfo::new::<Or<StrBool, StrEnum<36, 37>>>("contenteditable", "Whether the element is editable."),
AttrInfo::new::<Smart<HorizontalDir>>("dir", "The text directionality of the element."),
AttrInfo::new::<StrBool>("draggable", "Whether the element is draggable."),
AttrInfo::new::<StrEnum<44, 51>>("enterkeyhint", "Hint for selecting an enter key action."),
AttrInfo::new::<Or<NamedBool, StrEnum<60, 61>>>("hidden", "Whether the element is relevant."),
AttrInfo::new::<Str>("id", "The element's ID."),
AttrInfo::new::<NamedBool>("inert", "Whether the element is inert."),
AttrInfo::new::<StrOptionNone<StrEnum<66, 73>>>("inputmode", "Hint for selecting an input modality."),
AttrInfo::new::<Str>("is", "Creates a customized built-in element."),
AttrInfo::new::<Str>("itemid", "Global identifier for a microdata item."),
AttrInfo::new::<TokenList<Str, ' '>>("itemprop", "Property names of a microdata item."),
AttrInfo::new::<TokenList<Str, ' '>>("itemref", "Referenced elements."),
AttrInfo::new::<NamedBool>("itemscope", "Introduces a microdata item."),
AttrInfo::new::<TokenList<Str, ' '>>("itemtype", "Item types of a microdata item."),
AttrInfo::new::<StrOptionEmpty<Str>>("lang", "Language of the element."),
AttrInfo::new::<Str>("nonce", "Cryptographic nonce used in Content Security Policy checks."),
AttrInfo::new::<Smart<StrEnum<80, 81>>>("popover", "Makes the element a popover element."),
AttrInfo::new::<StrOptionNone<StrEnum<175, 255>>>("role", "An ARIA role."),
AttrInfo::new::<Str>("slot", "The element's desired slot."),
AttrInfo::new::<NamedBool>("spellcheck", "Whether the element is to have its spelling and grammar checked."),
AttrInfo::new::<Str>("style", "Presentational and formatting instructions."),
AttrInfo::new::<i64>("tabindex", "Whether the element is focusable and sequentially focusable, and the relative order of the element for the purposes of sequential focus navigation."),
AttrInfo::new::<Str>("title", "Advisory information for the element."),
AttrInfo::new::<YesNoBool>("translate", "Whether the element is to be translated when the page is localized."),
AttrInfo::new::<NamedBool>("writingsuggestions", "Whether the element can offer writing suggestions or not."),
AttrInfo::new::<Str>("abbr", "Alternative label to use for the header cell when referencing the cell in other contexts."),
AttrInfo::new::<TokenList<Str, ','>>("accept", "Hint for expected file type in file upload controls."),
AttrInfo::new::<StrEnum<0, 1>>("accept-charset", "Character encodings to use for form submission."),
AttrInfo::new::<Str>("action", "URL to use for form submission."),
AttrInfo::new::<Str>("allow", "Permissions policy to be applied to the iframe's contents."),
AttrInfo::new::<NamedBool>("allowfullscreen", "Whether to allow the iframe's contents to use requestFullscreen()."),
AttrInfo::new::<NamedBool>("alpha", "Allow the color's alpha component to be set."),
AttrInfo::new::<Str>("alt", "Replacement text for use when images are not available."),
AttrInfo::new::<StrEnum<1, 23>>("as", "Potential destination for a preload request (for rel=\"preload\" and rel=\"modulepreload\")."),
AttrInfo::new::<NamedBool>("async", "Execute script when available, without blocking while fetching."),
AttrInfo::new::<OnOffBool>("autocomplete", "Default setting for autofill feature for controls in the form."),
AttrInfo::new::<Str>("autocomplete", "Hint for form autofill feature."),
AttrInfo::new::<NamedBool>("autoplay", "Hint that the media resource can be started automatically when the page is loaded."),
AttrInfo::new::<TokenList<Str, ' '>>("blocking", "Whether the element is potentially render-blocking."),
AttrInfo::new::<StrEnum<0, 1>>("charset", "Character encoding declaration."),
AttrInfo::new::<NamedBool>("checked", "Whether the control is checked."),
AttrInfo::new::<Str>("cite", "Link to the source of the quotation or more information about the edit."),
AttrInfo::new::<StrOptionNone<StrEnum<26, 28>>>("closedby", "Which user actions will close the dialog."),
AttrInfo::new::<Color>("color", "Color to use when customizing a site's icon (for rel=\"mask-icon\")."),
AttrInfo::new::<StrEnum<28, 30>>("colorspace", "The color space of the serialized color."),
AttrInfo::new::<NonZeroU64>("cols", "Maximum number of characters per line."),
AttrInfo::new::<NonZeroU64>("colspan", "Number of columns that the cell is to span."),
AttrInfo::new::<Or<StrEnum<30, 36>, Str>>("command", "Indicates to the targeted element which action to take."),
AttrInfo::new::<Str>("commandfor", "Targets another element to be invoked."),
AttrInfo::new::<Str>("content", "Value of the element."),
AttrInfo::new::<NamedBool>("controls", "Show user agent controls."),
AttrInfo::new::<TokenList<f64, ',', false>>("coords", "Coordinates for the shape to be created in an image map. Expects an array of floating point numbers."),
AttrInfo::new::<StrEnum<37, 39>>("crossorigin", "How the element handles crossorigin requests."),
AttrInfo::new::<Str>("data", "Address of the resource."),
AttrInfo::new::<Datetime>("datetime", "Date and (optionally) time of the change."),
AttrInfo::new::<Or<Datetime, Duration>>("datetime", "Machine-readable value."),
AttrInfo::new::<Smart<StrEnum<39, 41>>>("decoding", "Decoding hint to use when processing this image for presentation."),
AttrInfo::new::<NamedBool>("default", "Enable the track if no other text track is more suitable."),
AttrInfo::new::<NamedBool>("defer", "Defer script execution."),
AttrInfo::new::<HorizontalDir>("dir", "The text directionality of the element."),
AttrInfo::new::<Str>("dirname", "Name of form control to use for sending the element's directionality in form submission."),
AttrInfo::new::<NamedBool>("disabled", "Whether the form control is disabled."),
AttrInfo::new::<NamedBool>("disabled", "Whether the descendant form controls, except any inside legend, are disabled."),
AttrInfo::new::<NamedBool>("disabled", "Whether the link is disabled."),
AttrInfo::new::<Str>("download", "Whether to download the resource instead of navigating to it, and its filename if so."),
AttrInfo::new::<StrEnum<41, 44>>("enctype", "Entry list encoding type to use for form submission."),
AttrInfo::new::<Smart<StrEnum<51, 53>>>("fetchpriority", "Sets the priority for fetches initiated by the element."),
AttrInfo::new::<Str>("for", "Associate the label with form control."),
AttrInfo::new::<TokenList<Str, ' '>>("for", "Specifies controls from which the output was calculated."),
AttrInfo::new::<Str>("form", "Associates the element with a form element."),
AttrInfo::new::<Str>("formaction", "URL to use for form submission."),
AttrInfo::new::<StrEnum<41, 44>>("formenctype", "Entry list encoding type to use for form submission."),
AttrInfo::new::<StrEnum<53, 56>>("formmethod", "Variant to use for form submission."),
AttrInfo::new::<NamedBool>("formnovalidate", "Bypass form control validation for form submission."),
AttrInfo::new::<Or<StrEnum<56, 60>, Str>>("formtarget", "Navigable for form submission."),
AttrInfo::new::<TokenList<Str, ' '>>("headers", "The header cells for this cell."),
AttrInfo::new::<u64>("height", "Vertical dimension."),
AttrInfo::new::<f64>("high", "Low limit of high range."),
AttrInfo::new::<Str>("href", "Address of the hyperlink."),
AttrInfo::new::<Str>("href", "Address of the hyperlink."),
AttrInfo::new::<Str>("href", "Document base URL."),
AttrInfo::new::<Str>("hreflang", "Language of the linked resource."),
AttrInfo::new::<StrEnum<61, 66>>("http-equiv", "Pragma directive."),
AttrInfo::new::<TokenList<SourceSize, ',', false>>("imagesizes", "Image sizes for different page layouts (for rel=\"preload\"). Expects an array of dictionaries with the keys `condition` (string) and `size` (length)."),
AttrInfo::new::<TokenList<ImageCandidate, ',', false>>("imagesrcset", "Images to use in different situations, e.g., high-resolution displays, small monitors, etc. (for rel=\"preload\"). Expects an array of dictionaries with the keys `src` (string) and `width` (integer) or `density` (float)."),
AttrInfo::new::<Str>("integrity", "Integrity metadata used in Subresource Integrity checks."),
AttrInfo::new::<NamedBool>("ismap", "Whether the image is a server-side image map."),
AttrInfo::new::<StrEnum<73, 78>>("kind", "The type of text track."),
AttrInfo::new::<Str>("label", "User-visible label."),
AttrInfo::new::<Str>("list", "List of autocomplete options."),
AttrInfo::new::<StrEnum<78, 80>>("loading", "Used when determining loading deferral."),
AttrInfo::new::<NamedBool>("loop", "Whether to loop the media resource."),
AttrInfo::new::<f64>("low", "High limit of low range."),
AttrInfo::new::<InputBound>("max", "Maximum value."),
AttrInfo::new::<f64>("max", "Upper bound of range."),
AttrInfo::new::<u64>("maxlength", "Maximum length of value."),
AttrInfo::new::<Str>("media", "Applicable media."),
AttrInfo::new::<StrEnum<53, 56>>("method", "Variant to use for form submission."),
AttrInfo::new::<InputBound>("min", "Minimum value."),
AttrInfo::new::<f64>("min", "Lower bound of range."),
AttrInfo::new::<u64>("minlength", "Minimum length of value."),
AttrInfo::new::<NamedBool>("multiple", "Whether to allow multiple values."),
AttrInfo::new::<NamedBool>("muted", "Whether to mute the media resource by default."),
AttrInfo::new::<Str>("name", "Name of the element to use for form submission and in the form.elements API."),
AttrInfo::new::<Str>("name", "Name of group of mutually-exclusive details elements."),
AttrInfo::new::<Str>("name", "Name of form to use in the document.forms API."),
AttrInfo::new::<Or<StrEnum<56, 60>, Str>>("name", "Name of content navigable."),
AttrInfo::new::<Str>("name", "Name of image map to reference from the usemap attribute."),
AttrInfo::new::<Str>("name", "Metadata name."),
AttrInfo::new::<Str>("name", "Name of shadow tree slot."),
AttrInfo::new::<NamedBool>("nomodule", "Prevents execution in user agents that support module scripts."),
AttrInfo::new::<NamedBool>("novalidate", "Bypass form control validation for form submission."),
AttrInfo::new::<NamedBool>("open", "Whether the details are visible."),
AttrInfo::new::<NamedBool>("open", "Whether the dialog box is showing."),
AttrInfo::new::<f64>("optimum", "Optimum value in gauge."),
AttrInfo::new::<Str>("pattern", "Pattern to be matched by the form control's value."),
AttrInfo::new::<TokenList<Str, ' '>>("ping", "URLs to ping."),
AttrInfo::new::<Str>("placeholder", "User-visible label to be placed within the form control."),
AttrInfo::new::<NamedBool>("playsinline", "Encourage the user agent to display video content within the element's playback area."),
AttrInfo::new::<Str>("popovertarget", "Targets a popover element to toggle, show, or hide."),
AttrInfo::new::<StrEnum<81, 84>>("popovertargetaction", "Indicates whether a targeted popover element is to be toggled, shown, or hidden."),
AttrInfo::new::<Str>("poster", "Poster frame to show prior to video playback."),
AttrInfo::new::<Smart<StrOptionNone<StrEnum<77, 78>>>>("preload", "Hints how much buffering the media resource will likely need."),
AttrInfo::new::<NamedBool>("readonly", "Whether to allow the value to be edited by the user."),
AttrInfo::new::<NamedBool>("readonly", "Affects willValidate, plus any behavior added by the custom element author."),
AttrInfo::new::<StrOptionEmpty<StrEnum<84, 92>>>("referrerpolicy", "Referrer policy for fetches initiated by the element."),
AttrInfo::new::<TokenList<StrEnum<92, 119>, ' '>>("rel", "Relationship between the location in the document containing the hyperlink and the destination resource."),
AttrInfo::new::<TokenList<StrEnum<92, 119>, ' '>>("rel", "Relationship between the document containing the hyperlink and the destination resource."),
AttrInfo::new::<TokenList<StrEnum<92, 119>, ' '>>("rel", "Relationship between the document containing the form and its action destination"),
AttrInfo::new::<NamedBool>("required", "Whether the control is required for form submission."),
AttrInfo::new::<NamedBool>("reversed", "Number the list backwards."),
AttrInfo::new::<NonZeroU64>("rows", "Number of lines to show."),
AttrInfo::new::<u64>("rowspan", "Number of rows that the cell is to span."),
AttrInfo::new::<TokenList<StrEnum<119, 132>, ' '>>("sandbox", "Security rules for nested content."),
AttrInfo::new::<StrEnum<132, 136>>("scope", "Specifies which cells the header cell applies to."),
AttrInfo::new::<NamedBool>("selected", "Whether the option is selected by default."),
AttrInfo::new::<NamedBool>("shadowrootclonable", "Sets clonable on a declarative shadow root."),
AttrInfo::new::<NamedBool>("shadowrootcustomelementregistry", "Enables declarative shadow roots to indicate they will use a custom element registry."),
AttrInfo::new::<NamedBool>("shadowrootdelegatesfocus", "Sets delegates focus on a declarative shadow root."),
AttrInfo::new::<StrEnum<136, 138>>("shadowrootmode", "Enables streaming declarative shadow roots."),
AttrInfo::new::<NamedBool>("shadowrootserializable", "Sets serializable on a declarative shadow root."),
AttrInfo::new::<StrEnum<138, 142>>("shape", "The kind of shape to be created in an image map."),
AttrInfo::new::<NonZeroU64>("size", "Size of the control."),
AttrInfo::new::<TokenList<IconSize, ' ', false>>("sizes", "Sizes of the icons (for rel=\"icon\"). Expects an array of sizes. Each size is specified as an array of two integers (width and height)."),
AttrInfo::new::<TokenList<SourceSize, ',', false>>("sizes", "Image sizes for different page layouts. Expects an array of dictionaries with the keys `condition` (string) and `size` (length)."),
AttrInfo::new::<NonZeroU64>("span", "Number of columns spanned by the element."),
AttrInfo::new::<Str>("src", "Address of the resource."),
AttrInfo::new::<Str>("srcdoc", "A document to render in the iframe."),
AttrInfo::new::<Str>("srclang", "Language of the text track."),
AttrInfo::new::<TokenList<ImageCandidate, ',', false>>("srcset", "Images to use in different situations, e.g., high-resolution displays, small monitors, etc. Expects an array of dictionaries with the keys `src` (string) and `width` (integer) or `density` (float)."),
AttrInfo::new::<i64>("start", "Starting value of the list."),
AttrInfo::new::<Or<PositiveF64, StrEnum<26, 27>>>("step", "Granularity to be matched by the form control's value."),
AttrInfo::new::<Or<StrEnum<56, 60>, Str>>("target", "Navigable for hyperlink navigation."),
AttrInfo::new::<Or<StrEnum<56, 60>, Str>>("target", "Default navigable for hyperlink navigation and form submission."),
AttrInfo::new::<Or<StrEnum<56, 60>, Str>>("target", "Navigable for form submission."),
AttrInfo::new::<Str>("title", "Full term or expansion of abbreviation."),
AttrInfo::new::<Str>("title", "Description of pattern (when used with pattern attribute)."),
AttrInfo::new::<Str>("title", "Title of the link."),
AttrInfo::new::<Str>("title", "CSS style sheet set name."),
AttrInfo::new::<Str>("type", "Hint for the type of the referenced resource."),
AttrInfo::new::<StrEnum<142, 145>>("type", "Type of button."),
AttrInfo::new::<Str>("type", "Type of embedded resource."),
AttrInfo::new::<StrEnum<145, 167>>("type", "Type of form control."),
AttrInfo::new::<StrEnum<167, 172>>("type", "Kind of list marker."),
AttrInfo::new::<Or<StrEnum<172, 173>, Str>>("type", "Type of script."),
AttrInfo::new::<Str>("usemap", "Name of image map to use."),
AttrInfo::new::<Str>("value", "Value to be used for form submission."),
AttrInfo::new::<Str>("value", "Machine-readable value."),
AttrInfo::new::<InputValue>("value", "Value of the form control."),
AttrInfo::new::<i64>("value", "Ordinal value of the list item."),
AttrInfo::new::<f64>("value", "Current value of the element."),
AttrInfo::new::<u64>("width", "Horizontal dimension."),
AttrInfo::new::<StrEnum<173, 175>>("wrap", "How the value of the form control is to be wrapped for form submission."),
];
pub const ATTRS_GLOBAL: usize = 76;
pub const ATTR_STRINGS: &[(&str, &str)] = &[
("utf-8", ""),
("audio", ""),
("audioworklet", ""),
("document", ""),
("embed", ""),
("font", ""),
("frame", ""),
("iframe", ""),
("image", ""),
("json", ""),
("manifest", ""),
("object", ""),
("paintworklet", ""),
("report", ""),
("script", ""),
("serviceworker", ""),
("sharedworker", ""),
("style", ""),
("track", ""),
("video", ""),
("webidentity", ""),
("worker", ""),
("xslt", ""),
("sentences", ""),
("words", ""),
("characters", ""),
("any", ""),
("closerequest", ""),
("limited-srgb", ""),
("display-p3", ""),
("toggle-popover", ""),
("show-popover", ""),
("hide-popover", ""),
("close", ""),
("request-close", ""),
("show-modal", ""),
("plaintext-only", ""),
("anonymous", ""),
("use-credentials", ""),
("sync", ""),
("async", ""),
("application/x-www-form-urlencoded", ""),
("multipart/form-data", ""),
("text/plain", ""),
("enter", ""),
("done", ""),
("go", ""),
("next", ""),
("previous", ""),
("search", ""),
("send", ""),
("high", ""),
("low", ""),
("GET", ""),
("POST", ""),
("dialog", ""),
("_blank", ""),
("_self", ""),
("_parent", ""),
("_top", ""),
("until-found", ""),
("content-type", ""),
("default-style", ""),
("refresh", ""),
("x-ua-compatible", ""),
("content-security-policy", ""),
("text", ""),
("tel", ""),
("email", ""),
("url", ""),
("numeric", ""),
("decimal", ""),
("search", ""),
("subtitles", ""),
("captions", ""),
("descriptions", ""),
("chapters", ""),
("metadata", ""),
("lazy", ""),
("eager", ""),
("manual", ""),
("toggle", ""),
("show", ""),
("hide", ""),
("no-referrer", ""),
("no-referrer-when-downgrade", ""),
("same-origin", ""),
("origin", ""),
("strict-origin", ""),
("origin-when-cross-origin", ""),
("strict-origin-when-cross-origin", ""),
("unsafe-url", ""),
("alternate", ""),
("canonical", ""),
("author", ""),
("bookmark", ""),
("dns-prefetch", ""),
("expect", ""),
("external", ""),
("help", ""),
("icon", ""),
("manifest", ""),
("modulepreload", ""),
("license", ""),
("next", ""),
("nofollow", ""),
("noopener", ""),
("noreferrer", ""),
("opener", ""),
("pingback", ""),
("preconnect", ""),
("prefetch", ""),
("preload", ""),
("prev", ""),
("privacy-policy", ""),
("search", ""),
("stylesheet", ""),
("tag", ""),
("terms-of-service", ""),
("allow-downloads", ""),
("allow-forms", ""),
("allow-modals", ""),
("allow-orientation-lock", ""),
("allow-pointer-lock", ""),
("allow-popups", ""),
("allow-popups-to-escape-sandbox", ""),
("allow-presentation", ""),
("allow-same-origin", ""),
("allow-scripts", ""),
("allow-top-navigation", ""),
("allow-top-navigation-by-user-activation", ""),
("allow-top-navigation-to-custom-protocols", ""),
("row", ""),
("col", ""),
("rowgroup", ""),
("colgroup", ""),
("open", ""),
("closed", ""),
("circle", ""),
("default", ""),
("poly", ""),
("rect", ""),
("submit", ""),
("reset", ""),
("button", ""),
("hidden", ""),
("text", ""),
("search", ""),
("tel", ""),
("url", ""),
("email", ""),
("password", ""),
("date", ""),
("month", ""),
("week", ""),
("time", ""),
("datetime-local", ""),
("number", ""),
("range", ""),
("color", ""),
("checkbox", ""),
("radio", ""),
("file", ""),
("submit", ""),
("image", ""),
("reset", ""),
("button", ""),
("1", ""),
("a", ""),
("A", ""),
("i", ""),
("I", ""),
("module", ""),
("soft", ""),
("hard", ""),
("alert", "A type of live region with important, and usually time-sensitive, information. See related alertdialog and status."),
("alertdialog", "A type of dialog that contains an alert message, where initial focus goes to an element within the dialog. See related alert and dialog."),
("application", "A structure containing one or more focusable elements requiring user input, such as keyboard or gesture events, that do not follow a standard interaction pattern supported by a widget role."),
("article", "A section of a page that consists of a composition that forms an independent part of a document, page, or site."),
("banner", "A region that contains mostly site-oriented content, rather than page-specific content."),
("button", "An input that allows for user-triggered actions when clicked or pressed. See related link."),
("cell", "A cell in a tabular container. See related gridcell."),
("checkbox", "A checkable input that has three possible values: true, false, or mixed."),
("columnheader", "A cell containing header information for a column."),
("combobox", "A composite widget containing a single-line textbox and another element, such as a listbox or grid, that can dynamically pop up to help the user set the value of the textbox."),
("command", "A form of widget that performs an action but does not receive input data."),
("complementary", "A supporting section of the document, designed to be complementary to the main content at a similar level in the DOM hierarchy, but remains meaningful when separated from the main content."),
("composite", "A widget that may contain navigable descendants or owned children."),
("contentinfo", "A large perceivable region that contains information about the parent document."),
("definition", "A definition of a term or concept. See related term."),
("dialog", "A dialog is a descendant window of the primary window of a web application. For HTML pages, the primary application window is the entire web document, i.e., the body element."),
("directory", "A list of references to members of a group, such as a static table of contents."),
("document", "An element containing content that assistive technology users may want to browse in a reading mode."),
("feed", "A scrollable list of articles where scrolling may cause articles to be added to or removed from either end of the list."),
("figure", "A perceivable section of content that typically contains a graphical document, images, code snippets, or example text. The parts of a figure MAY be user-navigable."),
("form", "A landmark region that contains a collection of items and objects that, as a whole, combine to create a form. See related search."),
("grid", "A composite widget containing a collection of one or more rows with one or more cells where some or all cells in the grid are focusable by using methods of two-dimensional navigation, such as directional arrow keys."),
("gridcell", "A cell in a grid or treegrid."),
("group", "A set of user interface objects which are not intended to be included in a page summary or table of contents by assistive technologies."),
("heading", "A heading for a section of the page."),
("img", "A container for a collection of elements that form an image."),
("input", "A generic type of widget that allows user input."),
("landmark", "A perceivable section containing content that is relevant to a specific, author-specified purpose and sufficiently important that users will likely want to be able to navigate to the section easily and to have it listed in a summary of the page. Such a page summary could be generated dynamically by a user agent or assistive technology."),
("link", "An interactive reference to an internal or external resource that, when activated, causes the user agent to navigate to that resource. See related button."),
("list", "A section containing listitem elements. See related listbox."),
("listbox", "A widget that allows the user to select one or more items from a list of choices. See related combobox and list."),
("listitem", "A single item in a list or directory."),
("log", "A type of live region where new information is added in meaningful order and old information may disappear. See related marquee."),
("main", "The main content of a document."),
("marquee", "A type of live region where non-essential information changes frequently. See related log."),
("math", "Content that represents a mathematical expression."),
("menu", "A type of widget that offers a list of choices to the user."),
("menubar", "A presentation of menu that usually remains visible and is usually presented horizontally."),
("menuitem", "An option in a set of choices contained by a menu or menubar."),
("menuitemcheckbox", "A menuitem with a checkable state whose possible values are true, false, or mixed."),
("menuitemradio", "A checkable menuitem in a set of elements with the same role, only one of which can be checked at a time."),
("navigation", "A collection of navigational elements (usually links) for navigating the document or related documents."),
("note", "A section whose content is parenthetic or ancillary to the main content of the resource."),
("option", "A selectable item in a select list."),
("presentation", "An element whose implicit native role semantics will not be mapped to the accessibility API. See synonym none."),
("progressbar", "An element that displays the progress status for tasks that take a long time."),
("radio", "A checkable input in a group of elements with the same role, only one of which can be checked at a time."),
("radiogroup", "A group of radio buttons."),
("range", "An input representing a range of values that can be set by the user."),
("region", "A perceivable section containing content that is relevant to a specific, author-specified purpose and sufficiently important that users will likely want to be able to navigate to the section easily and to have it listed in a summary of the page. Such a page summary could be generated dynamically by a user agent or assistive technology."),
("roletype", "The base role from which all other roles in this taxonomy inherit."),
("row", "A row of cells in a tabular container."),
("rowgroup", "A structure containing one or more row elements in a tabular container."),
("rowheader", "A cell containing header information for a row in a grid."),
("scrollbar", "A graphical object that controls the scrolling of content within a viewing area, regardless of whether the content is fully displayed within the viewing area."),
("search", "A landmark region that contains a collection of items and objects that, as a whole, combine to create a search facility. See related form and searchbox."),
("searchbox", "A type of textbox intended for specifying search criteria. See related textbox and search."),
("section", "A renderable structural containment unit in a document or application."),
("sectionhead", "A structure that labels or summarizes the topic of its related section."),
("select", "A form widget that allows the user to make selections from a set of choices."),
("separator", "A divider that separates and distinguishes sections of content or groups of menuitems."),
("slider", "A user input where the user selects a value from within a given range."),
("spinbutton", "A form of range that expects the user to select from among discrete choices."),
("status", "A type of live region whose content is advisory information for the user but is not important enough to justify an alert, often but not necessarily presented as a status bar."),
("structure", "A document structural element."),
("switch", "A type of checkbox that represents on/off values, as opposed to checked/unchecked values. See related checkbox."),
("tab", "A grouping label providing a mechanism for selecting the tab content that is to be rendered to the user."),
("table", "A section containing data arranged in rows and columns. See related grid."),
("tablist", "A list of tab elements, which are references to tabpanel elements."),
("tabpanel", "A container for the resources associated with a tab, where each tab is contained in a tablist."),
("term", "A word or phrase with a corresponding definition. See related definition."),
("textbox", "A type of input that allows free-form text as its value."),
("timer", "A type of live region containing a numerical counter which indicates an amount of elapsed time from a start point, or the time remaining until an end point."),
("toolbar", "A collection of commonly used function buttons or controls represented in compact visual form."),
("tooltip", "A contextual popup that displays a description for an element."),
("tree", "A type of list that may contain sub-level nested groups that can be collapsed and expanded."),
("treegrid", "A grid whose rows can be expanded and collapsed in the same manner as for a tree."),
("treeitem", "An option item of a tree. This is an element within a tree that may be expanded or collapsed if it contains a sub-level group of tree item elements."),
("widget", "An interactive component of a graphical user interface (GUI)."),
("window", "A browser or application window."),
("inline", "When a user is providing input, text suggesting one way to complete the provided input may be dynamically inserted after the caret."),
("list", "When a user is providing input, an element containing a collection of values that could complete the provided input may be displayed."),
("both", "When a user is providing input, an element containing a collection of values that could complete the provided input may be displayed. If displayed, one value in the collection is automatically selected, and the text needed to complete the automatically selected value appears after the caret in the input."),
("mixed", "An intermediate value between true and false."),
("page", "Represents the current page within a set of pages."),
("step", "Represents the current step within a process."),
("location", "Represents the current location within an environment or context."),
("date", "Represents the current date within a collection of dates."),
("time", "Represents the current time within a set of times."),
("menu", "Indicates the popup is a menu."),
("listbox", "Indicates the popup is a listbox."),
("tree", "Indicates the popup is a tree."),
("grid", "Indicates the popup is a grid."),
("dialog", "Indicates the popup is a dialog."),
("grammar", "A grammatical error was detected."),
("spelling", "A spelling error was detected."),
("assertive", "Indicates that updates to the region have the highest priority and should be presented the user immediately."),
("off", "Indicates that updates to the region should not be presented to the user unless the used is currently focused on that region."),
("polite", "Indicates that updates to the region should be presented at the next graceful opportunity, such as at the end of speaking the current sentence or when the user pauses typing."),
("horizontal", "The element is oriented horizontally."),
("undefined", "The element's orientation is unknown/ambiguous."),
("vertical", "The element is oriented vertically."),
("additions", "Element nodes are added to the accessibility tree within the live region."),
("additions text", "Equivalent to the combination of values, \"additions text\"."),
("all", "Equivalent to the combination of all values, \"additions removals text\"."),
("removals", "Text content, a text alternative, or an element node within the live region is removed from the accessibility tree."),
("text", "Text content or a text alternative is added to any descendant in the accessibility tree of the live region."),
("ascending", "Items are sorted in ascending order by this column."),
("descending", "Items are sorted in descending order by this column."),
("other", "A sort algorithm other than ascending or descending has been applied."),
];

View File

@ -1,7 +1,6 @@
//! HTML output.
mod dom;
mod generated;
mod typed;
pub use self::dom::*;

View File

@ -4,23 +4,23 @@
//! specification. See [generated] and `tools/codegen`.
use std::fmt::Write;
use std::marker::PhantomData;
use std::num::{NonZeroI64, NonZeroU64};
use std::sync::LazyLock;
use bumpalo::Bump;
use comemo::Tracked;
use ecow::{eco_format, eco_vec, EcoString};
use typst_assets::html as data;
use typst_macros::cast;
use crate::diag::{bail, At, Hint, HintedStrResult, SourceResult};
use crate::engine::Engine;
use crate::foundations::{
Args, Array, CastInfo, Content, Context, Datetime, Dict, Duration, FromValue,
IntoValue, NativeFuncData, NativeFuncPtr, ParamInfo, PositiveF64, Reflect, Scope,
Smart, Str, Type, Value,
Args, Array, AutoValue, CastInfo, Content, Context, Datetime, Dict, Duration,
FromValue, IntoValue, NativeFuncData, NativeFuncPtr, NoneValue, ParamInfo,
PositiveF64, Reflect, Scope, Str, Type, Value,
};
use crate::html::{generated, tag};
use crate::html::tag;
use crate::html::{HtmlAttr, HtmlAttrs, HtmlElem, HtmlTag};
use crate::layout::{Axes, Axis, Dir, Length};
use crate::visualize::Color;
@ -33,21 +33,16 @@ pub(super) fn define(html: &mut Scope) {
}
/// Lazily created functions for all typed HTML constructors.
static FUNCS: LazyLock<&'static [NativeFuncData]> = LazyLock::new(|| {
static FUNCS: LazyLock<Vec<NativeFuncData>> = LazyLock::new(|| {
// Leaking is okay here. It's not meaningfully different from having
// memory-managed values as `FUNCS` is a static.
let bump = Box::leak(Box::new(Bump::new()));
Vec::leak(
generated::ELEMENTS
.iter()
.map(|info| create_func_data(info, bump))
.collect(),
)
data::ELEMS.iter().map(|info| create_func_data(info, bump)).collect()
});
/// Creates metadata for a native HTML element constructor function.
fn create_func_data(
element: &'static ElementInfo,
element: &'static data::ElemInfo,
bump: &'static Bump,
) -> NativeFuncData {
NativeFuncData {
@ -72,13 +67,13 @@ fn create_func_data(
}
/// Creates parameter signature metadata for an element.
fn create_param_info(element: &'static ElementInfo) -> Vec<ParamInfo> {
fn create_param_info(element: &'static data::ElemInfo) -> Vec<ParamInfo> {
let mut params = vec![];
for attr in element.attributes() {
params.push(ParamInfo {
name: attr.name,
docs: attr.docs,
input: (attr.ty.input)(),
input: AttrType::convert(attr.ty).input(),
default: None,
positional: false,
named: true,
@ -87,7 +82,8 @@ fn create_param_info(element: &'static ElementInfo) -> Vec<ParamInfo> {
settable: false,
});
}
if !tag::is_void(element.tag) {
let tag = HtmlTag::constant(element.name);
if !tag::is_void(tag) {
params.push(ParamInfo {
name: "body",
docs: "The contents of the HTML element.",
@ -104,7 +100,7 @@ fn create_param_info(element: &'static ElementInfo) -> Vec<ParamInfo> {
}
/// The native constructor function shared by all HTML elements.
fn construct(element: &'static ElementInfo, args: &mut Args) -> SourceResult<Value> {
fn construct(element: &'static data::ElemInfo, args: &mut Args) -> SourceResult<Value> {
let mut attrs = HtmlAttrs::default();
let mut errors = eco_vec![];
@ -114,8 +110,9 @@ fn construct(element: &'static ElementInfo, args: &mut Args) -> SourceResult<Val
let span = item.value.span;
let value = std::mem::take(&mut item.value.v);
match (attr.ty.cast)(value).at(span) {
Ok(Some(string)) => attrs.push(attr.attr, string),
let ty = AttrType::convert(attr.ty);
match ty.cast(value).at(span) {
Ok(Some(string)) => attrs.push(HtmlAttr::constant(attr.name), string),
Ok(None) => {}
Err(diags) => errors.extend(diags),
}
@ -127,12 +124,13 @@ fn construct(element: &'static ElementInfo, args: &mut Args) -> SourceResult<Val
return Err(errors);
}
let mut elem = HtmlElem::new(element.tag);
let tag = HtmlTag::constant(element.name);
let mut elem = HtmlElem::new(tag);
if !attrs.0.is_empty() {
elem.push_attrs(attrs);
}
if !tag::is_void(element.tag) {
if !tag::is_void(tag) {
let body = args.eat::<Content>()?;
elem.push_body(body);
}
@ -140,146 +138,251 @@ fn construct(element: &'static ElementInfo, args: &mut Args) -> SourceResult<Val
Ok(elem.into_value())
}
/// Details about an HTML element.
pub struct ElementInfo {
/// The element's tag.
tag: HtmlTag,
/// The element's name, same as `tag`, but different representation.
name: &'static str,
/// A description for the element.
docs: &'static str,
/// Indices of the element's attributes in `ATTRS`.
attrs: &'static [u8],
}
impl ElementInfo {
/// Creates element information from its parts.
///
/// The `attrs` slice consists of indices pointing into `generated::ATTRS`.
/// It must be sorted by index (and, by extension, also by name of the
/// pointed-to attributes because the attributes themselves are sorted).
pub const fn new(
name: &'static str,
docs: &'static str,
attrs: &'static [u8],
) -> ElementInfo {
ElementInfo { tag: HtmlTag::constant(name), name, docs, attrs }
}
/// Iterates over all attributes an element of this type can have
/// (both specific and global).
fn attributes(&self) -> impl Iterator<Item = &'static AttrInfo> {
self.attrs
.iter()
.map(|&i| &generated::ATTRS[usize::from(i)])
.chain(&generated::ATTRS[..generated::ATTRS_GLOBAL])
}
/// Provides metadata for an attribute with the given name if it exists for
/// this element. The attribute may be specific or global.
fn get_attr(&self, name: &str) -> Option<&'static AttrInfo> {
self.get_specific_attr(name)
.or_else(|| self.get_global_attr(name))
.map(|i| &generated::ATTRS[i])
}
/// Tries to locate the index of a specific attribute in `ATTRS`.
fn get_specific_attr(&self, name: &str) -> Option<usize> {
self.attrs
.binary_search_by_key(&name, |&i| generated::ATTRS[usize::from(i)].name)
.map(|k| usize::from(self.attrs[k]))
.ok()
}
/// Tries to locate the index of a global attribute in `ATTRS`.
fn get_global_attr(&self, name: &str) -> Option<usize> {
generated::ATTRS[..generated::ATTRS_GLOBAL]
.binary_search_by_key(&name, |attr| attr.name)
.ok()
}
}
/// Details about an HTML attribute.
pub struct AttrInfo {
/// The attribute itself.
attr: HtmlAttr,
/// The attribute's name, same as `attr`, but different representation.
name: &'static str,
/// A description for the attribute.
docs: &'static str,
/// Type information for the attribute.
ty: AttrType,
}
impl AttrInfo {
/// Creates attribute information from its parts.
pub const fn new<T: IntoOptionalAttr>(
name: &'static str,
docs: &'static str,
) -> AttrInfo {
AttrInfo {
attr: HtmlAttr::constant(name),
name,
docs,
ty: AttrType::of::<T>(),
}
}
}
/// A dynamic representation of an attribute's type.
struct AttrType {
/// Describes the attribute's schema.
input: fn() -> CastInfo,
/// Tries to cast a value into this attribute's value given the attribute
/// name. If `None`, this is a boolean presence-based attribute.
cast: fn(value: Value) -> HintedStrResult<Option<EcoString>>,
///
/// See the documentation of [`data::Type`] for more details on variants.
enum AttrType {
Presence,
Native(NativeType),
Strings(StringsType),
Union(UnionType),
List(ListType),
}
impl AttrType {
const fn of<T: IntoOptionalAttr>() -> Self {
Self {
cast: |value| {
let this = value.cast::<T>()?;
Ok(this.into_optional_attr())
},
input: T::input,
/// Converts the type definition into a representation suitable for casting
/// and reflection.
const fn convert(ty: data::Type) -> AttrType {
use data::Type;
match ty {
Type::Presence => Self::Presence,
Type::None => Self::of::<NoneValue>(),
Type::NoneEmpty => Self::of::<NoneEmpty>(),
Type::NoneUndefined => Self::of::<NoneUndefined>(),
Type::Auto => Self::of::<AutoValue>(),
Type::TrueFalse => Self::of::<TrueFalseBool>(),
Type::YesNo => Self::of::<YesNoBool>(),
Type::OnOff => Self::of::<OnOffBool>(),
Type::Int => Self::of::<i64>(),
Type::NonNegativeInt => Self::of::<u64>(),
Type::PositiveInt => Self::of::<NonZeroU64>(),
Type::Float => Self::of::<f64>(),
Type::PositiveFloat => Self::of::<PositiveF64>(),
Type::Str => Self::of::<Str>(),
Type::Char => Self::of::<char>(),
Type::Datetime => Self::of::<Datetime>(),
Type::Duration => Self::of::<Duration>(),
Type::Color => Self::of::<Color>(),
Type::HorizontalDir => Self::of::<HorizontalDir>(),
Type::IconSize => Self::of::<IconSize>(),
Type::ImageCandidate => Self::of::<ImageCandidate>(),
Type::SourceSize => Self::of::<SourceSize>(),
Type::Strings(start, end) => Self::Strings(StringsType { start, end }),
Type::Union(variants) => Self::Union(UnionType(variants)),
Type::List(inner, separator, shorthand) => {
Self::List(ListType { inner, separator, shorthand })
}
}
}
/// Produces the dynamic representation of an attribute type backed by a
/// native Rust type.
const fn of<T: IntoAttr>() -> Self {
Self::Native(NativeType::of::<T>())
}
/// See [`Reflect::input`].
fn input(&self) -> CastInfo {
match self {
Self::Presence => bool::input(),
Self::Native(ty) => (ty.input)(),
Self::Union(ty) => ty.input(),
Self::Strings(ty) => ty.input(),
Self::List(ty) => ty.input(),
}
}
/// See [`Reflect::castable`].
fn castable(&self, value: &Value) -> bool {
match self {
Self::Presence => bool::castable(value),
Self::Native(ty) => (ty.castable)(value),
Self::Union(ty) => ty.castable(value),
Self::Strings(ty) => ty.castable(value),
Self::List(ty) => ty.castable(value),
}
}
/// Tries to cast the value into this attribute's type and serialize it into
/// an HTML attribute string.
fn cast(&self, value: Value) -> HintedStrResult<Option<EcoString>> {
match self {
Self::Presence => value.cast::<bool>().map(|b| b.then(EcoString::new)),
Self::Native(ty) => (ty.cast)(value),
Self::Union(ty) => ty.cast(value),
Self::Strings(ty) => ty.cast(value),
Self::List(ty) => ty.cast(value),
}
}
}
/// Casts a type into an optional HTML attribute.
/// An enumeration with generated string variants.
///
/// If `into_optional_attr`, no attribute is written.
pub trait IntoOptionalAttr: FromValue {
/// Turn the value into an attribute string or indicate the absence of an
/// attribute via `None`.
fn into_optional_attr(self) -> Option<EcoString>;
/// `start` and `end` are used to index into `data::ATTR_STRINGS`.
struct StringsType {
start: usize,
end: usize,
}
impl<T: IntoAttr> IntoOptionalAttr for T {
fn into_optional_attr(self) -> Option<EcoString> {
Some(self.into_attr())
impl StringsType {
fn input(&self) -> CastInfo {
CastInfo::Union(
self.strings()
.iter()
.map(|(val, desc)| CastInfo::Value(val.into_value(), desc))
.collect(),
)
}
fn castable(&self, value: &Value) -> bool {
match value {
Value::Str(s) => self.strings().iter().any(|&(v, _)| v == s.as_str()),
_ => false,
}
}
fn cast(&self, value: Value) -> HintedStrResult<Option<EcoString>> {
if self.castable(&value) {
value.cast().map(Some)
} else {
Err(self.input().error(&value))
}
}
fn strings(&self) -> &'static [(&'static str, &'static str)] {
&data::ATTR_STRINGS[self.start..self.end]
}
}
/// A boolean that is encoded by presence of the attribute:
/// - `false` is encoded by an absent attribute.
/// - `true` is encoded by the empty string:
/// `<input checked="">` which collapses into `<input checked>`
pub struct NamedBool(pub bool);
/// A type that accepts any of the contained types.
struct UnionType(&'static [data::Type]);
cast! {
NamedBool,
v: bool => Self(v),
}
impl UnionType {
fn input(&self) -> CastInfo {
CastInfo::Union(self.iter().map(|ty| ty.input()).collect())
}
impl IntoOptionalAttr for NamedBool {
fn into_optional_attr(self) -> Option<EcoString> {
self.0.then(EcoString::new)
fn castable(&self, value: &Value) -> bool {
self.iter().any(|ty| ty.castable(value))
}
fn cast(&self, value: Value) -> HintedStrResult<Option<EcoString>> {
for item in self.iter() {
if item.castable(&value) {
return item.cast(value);
}
}
Err(self.input().error(&value))
}
fn iter(&self) -> impl Iterator<Item = AttrType> {
self.0.iter().map(|&ty| AttrType::convert(ty))
}
}
/// Casts a type into an HTML attribute.
/// A list of items separated by a specific separator char.
///
/// - https://html.spec.whatwg.org/#space-separated-tokens>
/// - https://html.spec.whatwg.org/#comma-separated-tokens>
struct ListType {
inner: &'static data::Type,
separator: char,
shorthand: bool,
}
impl ListType {
fn input(&self) -> CastInfo {
if self.shorthand {
Array::input() + self.inner().input()
} else {
Array::input()
}
}
fn castable(&self, value: &Value) -> bool {
Array::castable(value) || (self.shorthand && self.inner().castable(value))
}
fn cast(&self, value: Value) -> HintedStrResult<Option<EcoString>> {
let ty = self.inner();
if Array::castable(&value) {
let array = value.cast::<Array>()?;
let mut out = EcoString::new();
for (i, item) in array.into_iter().enumerate() {
let item = ty.cast(item)?.unwrap();
if item.as_str().contains(self.separator) {
let buf;
let name = match self.separator {
' ' => "space",
',' => "comma",
_ => {
buf = eco_format!("'{}'", self.separator);
buf.as_str()
}
};
bail!(
"array item may not contain a {name}";
hint: "the array attribute will be encoded as a \
{name}-separated string"
);
}
if i > 0 {
out.push(self.separator);
if self.separator == ',' {
out.push(' ');
}
}
out.push_str(&item);
}
Ok(Some(out))
} else if self.shorthand && ty.castable(&value) {
let item = ty.cast(value)?.unwrap();
Ok(Some(item))
} else {
Err(self.input().error(&value))
}
}
fn inner(&self) -> AttrType {
AttrType::convert(*self.inner)
}
}
/// A dynamic representation of attribute backed by a native type implementing
/// - the standard `Reflect` and `FromValue` traits for casting from a value,
/// - the special `IntoAttr` trait for conversion into an attribute string.
#[derive(Copy, Clone)]
struct NativeType {
input: fn() -> CastInfo,
cast: fn(Value) -> HintedStrResult<Option<EcoString>>,
castable: fn(&Value) -> bool,
}
impl NativeType {
/// Creates a dynamic native type from a native Rust type.
const fn of<T: IntoAttr>() -> Self {
Self {
cast: |value| {
let this = value.cast::<T>()?;
Ok(Some(this.into_attr()))
},
input: T::input,
castable: T::castable,
}
}
}
/// Casts a native type into an HTML attribute.
pub trait IntoAttr: FromValue {
/// Turn the value into an attribute string.
fn into_attr(self) -> EcoString;
@ -294,14 +397,14 @@ impl IntoAttr for Str {
/// A boolean that is encoded as a string:
/// - `false` is encoded as `"false"`
/// - `true` is encoded as `"true"`
pub struct StrBool(pub bool);
pub struct TrueFalseBool(pub bool);
cast! {
StrBool,
TrueFalseBool,
v: bool => Self(v),
}
impl IntoAttr for StrBool {
impl IntoAttr for TrueFalseBool {
fn into_attr(self) -> EcoString {
if self.0 { "true" } else { "false" }.into()
}
@ -339,6 +442,46 @@ impl IntoAttr for OnOffBool {
}
}
impl IntoAttr for AutoValue {
fn into_attr(self) -> EcoString {
"auto".into()
}
}
impl IntoAttr for NoneValue {
fn into_attr(self) -> EcoString {
"none".into()
}
}
/// A `none` value that turns into an empty string attribute.
struct NoneEmpty;
cast! {
NoneEmpty,
_: NoneValue => NoneEmpty,
}
impl IntoAttr for NoneEmpty {
fn into_attr(self) -> EcoString {
"".into()
}
}
/// A `none` value that turns into the string `"undefined"`.
struct NoneUndefined;
cast! {
NoneUndefined,
_: NoneValue => NoneUndefined,
}
impl IntoAttr for NoneUndefined {
fn into_attr(self) -> EcoString {
"undefined".into()
}
}
impl IntoAttr for char {
fn into_attr(self) -> EcoString {
eco_format!("{self}")
@ -489,254 +632,17 @@ impl IntoAttr for Dir {
}
}
/// An optional value that represents `None` with one of three strings.
pub struct StrOption<T, const INDEX: usize>(Option<T>);
pub type StrOptionEmpty<T> = StrOption<T, 0>;
pub type StrOptionNone<T> = StrOption<T, 1>;
pub type StrOptionUndefined<T> = StrOption<T, 2>;
const NONE_STRS: &[&str] = &["", "none", "undefined"];
impl<T: Reflect, const INDEX: usize> Reflect for StrOption<T, INDEX> {
fn input() -> CastInfo {
Option::<T>::input()
}
fn output() -> CastInfo {
Option::<T>::output()
}
fn castable(value: &Value) -> bool {
Option::<T>::castable(value)
}
}
impl<T: FromValue, const INDEX: usize> FromValue for StrOption<T, INDEX> {
fn from_value(value: Value) -> HintedStrResult<Self> {
value.cast().map(Self)
}
}
impl<T: IntoOptionalAttr, const INDEX: usize> IntoOptionalAttr for StrOption<T, INDEX> {
fn into_optional_attr(self) -> Option<EcoString> {
match self.0 {
None => Some(NONE_STRS[INDEX].into()),
Some(v) => v.into_optional_attr(),
}
}
}
impl<T: IntoOptionalAttr> IntoOptionalAttr for Smart<T> {
fn into_optional_attr(self) -> Option<EcoString> {
match self {
Smart::Auto => Some("auto".into()),
Smart::Custom(v) => v.into_optional_attr(),
}
}
}
/// A list of items separated by a specific separator char.
///
/// - https://html.spec.whatwg.org/#space-separated-tokens>
/// - https://html.spec.whatwg.org/#comma-separated-tokens>
pub struct TokenList<T, const SEP: char, const SHORTHAND: bool = true>(
EcoString,
PhantomData<T>,
);
impl<T: Reflect, const SEP: char, const SHORTHAND: bool> Reflect
for TokenList<T, SEP, SHORTHAND>
{
fn input() -> CastInfo {
if SHORTHAND {
Array::input() + T::input()
} else {
Array::input()
}
}
fn output() -> CastInfo {
if SHORTHAND {
Array::output() + T::input()
} else {
Array::output()
}
}
fn castable(value: &Value) -> bool {
Array::castable(value) || (SHORTHAND && T::castable(value))
}
}
impl<T: FromValue + IntoAttr, const SEP: char, const SHORTHAND: bool> FromValue
for TokenList<T, SEP, SHORTHAND>
{
fn from_value(value: Value) -> HintedStrResult<Self> {
if Array::castable(&value) {
let array = value.cast::<Array>()?;
let mut out = EcoString::new();
for (i, item) in array.into_iter().enumerate() {
let item = item.cast::<T>()?.into_attr();
if item.as_str().contains(SEP) {
let buf;
let name = match SEP {
' ' => "space",
',' => "comma",
_ => {
buf = eco_format!("'{SEP}'");
buf.as_str()
}
};
bail!(
"array item may not contain a {name}";
hint: "the array attribute will be encoded as a \
{name}-separated string"
);
}
if i > 0 {
out.push(SEP);
if SEP == ',' {
out.push(' ');
}
}
out.push_str(&item);
}
Ok(Self(out, PhantomData))
} else if SHORTHAND && T::castable(&value) {
let item = value.cast::<T>()?.into_attr();
Ok(Self(item, PhantomData))
} else {
Err(<Self as Reflect>::error(&value))
}
}
}
impl<T: FromValue + IntoAttr, const SEP: char, const SHORTHAND: bool> IntoAttr
for TokenList<T, SEP, SHORTHAND>
{
fn into_attr(self) -> EcoString {
self.0
}
}
/// An enumeration with generated string variants.
///
/// `START` and `END` are used to index into `generated::ATTR_STRINGS`.
pub struct StrEnum<const START: usize, const END: usize>(Str);
impl<const START: usize, const END: usize> Reflect for StrEnum<START, END> {
fn input() -> CastInfo {
CastInfo::Union(
generated::ATTR_STRINGS[START..END]
.iter()
.map(|&(string, docs)| CastInfo::Value(string.into_value(), docs))
.collect(),
)
}
fn output() -> CastInfo {
Self::input()
}
fn castable(value: &Value) -> bool {
match value {
Value::Str(s) => generated::ATTR_STRINGS[START..END]
.iter()
.any(|&(v, _)| v == s.as_str()),
_ => false,
}
}
}
impl<const START: usize, const END: usize> FromValue for StrEnum<START, END> {
fn from_value(value: Value) -> HintedStrResult<Self> {
if Self::castable(&value) {
Ok(Self(value.cast()?))
} else {
Err(<Self as Reflect>::error(&value))
}
}
}
impl<const START: usize, const END: usize> IntoAttr for StrEnum<START, END> {
fn into_attr(self) -> EcoString {
self.0.into()
}
}
/// One attribute type or another.
pub enum Or<A, B> {
A(A),
B(B),
}
impl<A: Reflect, B: Reflect> Reflect for Or<A, B> {
fn input() -> CastInfo {
A::input() + B::input()
}
fn output() -> CastInfo {
A::output() + B::output()
}
fn castable(value: &Value) -> bool {
A::castable(value) || B::castable(value)
}
}
impl<A: FromValue, B: FromValue> FromValue for Or<A, B> {
fn from_value(value: Value) -> HintedStrResult<Self> {
if A::castable(&value) {
A::from_value(value).map(Self::A)
} else if B::castable(&value) {
B::from_value(value).map(Self::B)
} else {
Err(<Self as Reflect>::error(&value))
}
}
}
impl<A: IntoOptionalAttr, B: IntoOptionalAttr> IntoOptionalAttr for Or<A, B> {
fn into_optional_attr(self) -> Option<EcoString> {
match self {
Self::A(v) => v.into_optional_attr(),
Self::B(v) => v.into_optional_attr(),
}
}
}
/// A value of an `<input>` element.
pub struct InputValue(EcoString);
/// A width/height pair for `<link rel="icon" sizes="..." />`.
pub struct IconSize(Axes<u64>);
cast! {
InputValue,
v: Str => Self(v.into_attr()),
v: f64 => Self(v.into_attr()),
v: Datetime => Self(v.into_attr()),
v: Color => Self(v.into_attr()),
v: TokenList<Str, ','> => Self(v.into_attr()),
IconSize,
v: Axes<u64> => Self(v),
}
impl IntoAttr for InputValue {
impl IntoAttr for IconSize {
fn into_attr(self) -> EcoString {
self.0
}
}
/// A min/max bound of an `<input>` element.
pub struct InputBound(EcoString);
cast! {
InputBound,
v: Str => Self(v.into_attr()),
v: f64 => Self(v.into_attr()),
v: Datetime => Self(v.into_attr()),
}
impl IntoAttr for InputBound {
fn into_attr(self) -> EcoString {
self.0
eco_format!("{}x{}", self.0.x, self.0.y)
}
}
@ -799,20 +705,6 @@ impl IntoAttr for SourceSize {
}
}
/// A width/height pair for `<link rel="icon" sizes="..." />`.
pub struct IconSize(Axes<u64>);
cast! {
IconSize,
v: Axes<u64> => Self(v),
}
impl IntoAttr for IconSize {
fn into_attr(self) -> EcoString {
eco_format!("{}x{}", self.0.x, self.0.y)
}
}
/// Conversion from Typst data types into CSS data types.
///
/// This can be moved elsewhere once we start supporting more CSS stuff.
@ -959,3 +851,18 @@ mod css {
(a - b).abs() < EPS
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_tags_and_attr_const_internible() {
for elem in data::ELEMS {
let _ = HtmlTag::constant(elem.name);
}
for attr in data::ATTRS {
let _ = HtmlAttr::constant(attr.name);
}
}
}

View File

@ -1,16 +0,0 @@
[package]
name = "typst-codegen"
version = { workspace = true }
rust-version = { workspace = true }
authors = { workspace = true }
edition = { workspace = true }
publish = false
[dependencies]
native-tls = { workspace = true }
regex = { workspace = true }
scraper = { workspace = true }
ureq = { workspace = true }
[lints]
workspace = true

View File

@ -1,719 +0,0 @@
//! Usage: `cargo run -p typst-codegen -- html path/to/spec/dir`
//!
//! The spec dir will automatically be populated with the necessary
//! specifications if one is missing.
use std::borrow::Cow;
use std::collections::BTreeSet;
use std::fmt::{Display, Write};
use std::path::PathBuf;
use regex::Regex;
use scraper::{ElementRef, Html, Selector};
pub fn main() {
// Directory where specs will be read from / downloaded into.
let dir = std::env::args_os().nth(2).map(PathBuf::from);
let mut ctx = Context {
html: load_spec(&dir, "html", "https://html.spec.whatwg.org/"),
fetch: load_spec(&dir, "fetch", "https://fetch.spec.whatwg.org/"),
referrer: load_spec(
&dir,
"referrer",
"https://w3c.github.io/webappsec-referrer-policy/",
),
aria: load_spec(&dir, "aria", "https://www.w3.org/TR/wai-aria-1.1/"),
strings: vec![],
};
let attr_infos = collect_attributes(&mut ctx);
let element_infos = collect_elements(&ctx, &attr_infos);
let output = Output {
tags: element_infos.iter().map(|info| info.name.clone()).collect(),
attrs: attr_infos.iter().map(|info| info.name.clone()).collect(),
attr_global_count: attr_infos
.iter()
.filter(|info| matches!(info.applies_to, Applicable::Globally))
.count(),
element_infos,
attr_infos,
attr_strings: ctx.strings,
};
let path = "crates/typst-library/src/html/generated.rs";
let code = codegen(&output);
std::fs::write(path, code).unwrap();
println!("Success!");
}
/// Reads a spec from the directory or, if it does not exist, fetches and stores it.
fn load_spec(spec_dir: &Option<PathBuf>, name: &str, url: &str) -> ElementRef<'static> {
let text = if let Some(dir) = spec_dir {
let path = dir.join(name).with_extension("html");
if path.exists() {
println!("Reading from {}", path.display());
std::fs::read_to_string(&path).unwrap()
} else {
let text = crate::fetch(url);
println!("Writing to {}", path.display());
std::fs::create_dir_all(dir).unwrap();
std::fs::write(&path, &text).unwrap();
text
}
} else {
crate::fetch(url)
};
Box::leak(Box::new(Html::parse_document(&text))).root_element()
}
struct Context<'a> {
html: ElementRef<'a>,
fetch: ElementRef<'a>,
referrer: ElementRef<'a>,
aria: ElementRef<'a>,
strings: Vec<(String, String)>,
}
struct Output {
tags: BTreeSet<String>,
attrs: BTreeSet<String>,
attr_global_count: usize,
element_infos: Vec<ElementInfo>,
attr_infos: Vec<AttrInfo>,
attr_strings: Vec<(String, String)>,
}
struct ElementInfo {
name: String,
docs: String,
attributes: Vec<usize>,
}
struct AttrInfo {
name: String,
docs: String,
ty: String,
applies_to: Applicable,
}
enum Applicable {
Globally,
Elements(Vec<String>),
}
impl Applicable {
fn applies_specifically_to(&self, tag: &str) -> bool {
match self {
Self::Globally => false,
Self::Elements(elements) => elements.iter().any(|s| s == tag),
}
}
}
/// Creates a lazily initialized static value.
macro_rules! lazy {
($ty:ty = $init:expr) => {{
static VAL: ::std::sync::LazyLock<$ty> = ::std::sync::LazyLock::new(|| $init);
&*VAL
}};
}
/// Creates a static CSS selector.
macro_rules! s {
($s:literal) => {
lazy!(Selector = Selector::parse($s).unwrap())
};
}
/// Creates a lazily initialized regular expression.
macro_rules! re {
($s:expr) => {
lazy!(Regex = Regex::new($s).unwrap())
};
}
/// Like `match`, but with regular expressions!
macro_rules! regex_match {
($text:expr, {
$($re:literal $(if $guard:expr)? => $out:expr,)*
_ => $final:expr $(,)?
}) => {{
let __text = $text;
match () {
$(_ if re!(&concat!("(?i)^", $re, "$")).is_match(__text)
$(&& $guard)? => $out,)*
_ => $final
}
}};
}
/// Collects all attributes with documentation and descriptions.
fn collect_attributes(ctx: &mut Context) -> Vec<AttrInfo> {
let mut infos = vec![];
collect_html_attributes(ctx, &mut infos);
collect_aria_attributes(ctx, &mut infos);
infos.sort_by(|a, b| sort_key(a).cmp(&sort_key(b)));
infos
}
/// Global attributes should come first and attributes be binary-searchable.
fn sort_key(attr: &AttrInfo) -> impl Ord + '_ {
(matches!(attr.applies_to, Applicable::Elements(_)), &attr.name)
}
/// Collects attributes from the HTML spec.
fn collect_html_attributes(ctx: &mut Context, infos: &mut Vec<AttrInfo>) {
for tr in ctx.html.select_first(s!("#attributes-1")).select(s!("tbody > tr")) {
let name = tr.select_text(s!("th code"));
let elements = tr.select_first(s!("td:nth-of-type(1)"));
let mut docs = docs(&tr.select_text(s!("td:nth-of-type(2)")));
let applies_to = if elements.inner_text().trim() == "HTML elements" {
Applicable::Globally
} else {
Applicable::Elements(
elements.select(s!("code")).map(|elem| elem.inner_text()).collect(),
)
};
let ty_cell = tr.select_first(s!("td:nth-of-type(3)"));
let ty = determine_type(ctx, &name, ty_cell, &mut docs);
infos.push(AttrInfo { name, docs, ty, applies_to });
}
// HTML spec is missing this.
infos.push(AttrInfo {
name: "rel".into(),
docs: "Relationship between the document containing \
the form and its action destination"
.into(),
ty: rel_type(ctx),
applies_to: Applicable::Elements(vec!["form".into()]),
});
}
/// Collects attributes from the ARIA spec.
fn collect_aria_attributes(ctx: &mut Context, infos: &mut Vec<AttrInfo>) {
// Collect ARIA roles.
let role_dl = ctx.aria.select_first(s!("#index_role"));
infos.push(AttrInfo {
name: "role".into(),
docs: "An ARIA role.".into(),
ty: create_str_enum(
ctx,
role_dl
.select(s!("dt code"))
.zip(role_dl.select(s!("dd")))
.map(|(code, dd)| (code.inner_text(), dd.inner_text())),
),
applies_to: Applicable::Globally,
});
// Collect ARIA property and state attributes.
let attrs_dl = ctx.aria.select_first(s!("#index_state_prop"));
for (dt, dd) in attrs_dl.select(s!("dt")).zip(attrs_dl.select(s!("dd"))) {
let docs = docs(&dd.inner_text());
if docs.contains("Deprecated") {
continue;
}
let name = dt.inner_text();
let ty = determine_aria_type(ctx, &name);
infos.push(AttrInfo { name, docs, ty, applies_to: Applicable::Globally });
}
}
/// Collects all HTML elements.
fn collect_elements(ctx: &Context, attrs: &[AttrInfo]) -> Vec<ElementInfo> {
let mut infos = vec![];
for tr in ctx
.html
.select_first(s!("#elements-3 ~ table"))
.select(s!("tbody > tr"))
{
for code in tr.select(s!("th code")) {
let name = code.inner_text();
// These are special and not normal HTML elements.
if matches!(name.as_str(), "svg" | "math") {
continue;
}
let docs = docs(&tr.select_text(s!("td:first-of-type")));
let attributes = collect_attr_indices(tr, &name, attrs);
infos.push(ElementInfo { name, docs, attributes });
}
}
infos
}
/// Collects the indices of the attribute infos for an element's attributes.
fn collect_attr_indices(tr: ElementRef, tag: &str, attrs: &[AttrInfo]) -> Vec<usize> {
let mut indices = vec![];
for elem in tr.select(s!("td:nth-of-type(5) code")) {
let name = elem.inner_text();
// Ignore the event handle attributes on the body element that are
// for some reason documented (unlike other event handle attributes).
if tag == "body" && name.starts_with("on") {
continue;
}
let index = attrs
.iter()
.position(|attr| {
attr.name == name && attr.applies_to.applies_specifically_to(tag)
})
.unwrap_or_else(|| panic!("failed to find attribute {name} for {tag}"));
indices.push(index)
}
indices.sort();
assert!(indices.is_sorted_by_key(|&i| &attrs[i].name));
indices
}
/// Determines the Rust type for an HTML attribute.
fn determine_type(
ctx: &mut Context,
attr: &str,
cell: ElementRef,
docs: &mut String,
) -> String {
let textual_ty = cell.inner_text().trim().trim_end_matches("*").replace("\n", " ");
if let Some(ty) = try_parse_alternation(ctx, &textual_ty) {
return ty;
}
regex_match!(textual_ty.as_str(), {
"autofill field name.*" => "Str".into(),
"css declarations" => "Str".into(),
"id" => "Str".into(),
"regular expression.*" => "Str".into(),
"serialized permissions policy" => "Str".into(),
"text" => "Str".into(),
"the source of an iframe srcdoc document" => "Str".into(),
"valid (non-empty )?url.*" => "Str".into(),
"valid bcp 47 language tag" => "Str".into(),
"valid custom element name.*" => "Str".into(),
"valid hash-name reference" => "Str".into(),
"valid mime type string" => "Str".into(),
"valid integer" => "i64".into(),
"valid non-negative integer" => "u64".into(),
"valid non-negative integer greater than zero" => "NonZeroU64".into(),
"valid floating-point number" => "f64".into(),
"valid float.* greater than zero, or \"any\"" => {
format!("Or<PositiveF64, {}>", create_str_literal(ctx, "any"))
},
"css <color>" => "Color".into(),
"valid date string with optional time" => "Datetime".into(),
"valid month string.*valid duration string" => "Or<Datetime, Duration>".into(),
"boolean attribute" => "NamedBool".into(),
"valid bcp 47 language tag or the empty string" => "StrOptionEmpty<Str>".into(),
".*until-found.*" if attr == "hidden" => {
format!("Or<NamedBool, {}>", create_str_literal(ctx, "until-found"))
},
".*true.*empty string.*" if matches!(attr, "spellcheck" | "writingsuggestions") => "NamedBool".into(),
"valid list of floating-point numbers" => {
write!(docs, " Expects an array of floating point numbers.").unwrap();
"TokenList<f64, ',', false>".into()
},
".*space-separated tokens.*" if attr == "rel" => rel_type(ctx),
".*space-separated tokens.*" if attr == "sandbox" => {
let variants = cell
.select(s!("code"))
.map(|elem| elem.inner_text());
let ty = create_str_enum(ctx, variants);
format!("TokenList<{ty}, ' '>")
},
".*space-separated tokens.*consisting of one code point.*" => {
write!(docs, " Expects a single-codepoint string or an array thereof.").unwrap();
"TokenList<char, ','>".into()
},
".*space-separated tokens.*consisting of sizes" => {
write!(
docs,
" Expects an array of sizes. Each size is specified as an \
array of two integers (width and height).",
).unwrap();
"TokenList<IconSize, ' ', false>".into()
},
".*space-separated tokens.*" => "TokenList<Str, ' '>".into(),
".*comma-separated tokens.*" => "TokenList<Str, ','>".into(),
"valid media query list" => "Str".into(),
"ascii case-insensitive match for \"utf-8\"" => create_str_literal(ctx, "utf-8"),
"varies" if matches!(attr, "min" | "max") => "InputBound".into(),
"varies" if attr == "value" => "InputValue".into(),
"comma-separated list of image candidate strings" => {
write!(
docs,
" Expects an array of dictionaries with the keys \
`src` (string) and `width` (integer) or `density` (float).",
).unwrap();
"TokenList<ImageCandidate, ',', false>".into()
},
"valid source size list" => {
write!(
docs,
" Expects an array of dictionaries with the keys \
`condition` (string) and `size` (length).",
).unwrap();
"TokenList<SourceSize, ',', false>".into()
},
"input type keyword" => {
let variants = ctx
.html
.select(s!(
"table#attr-input-type-keywords > tbody > tr > td:first-child code"
))
.map(|elem| elem.inner_text());
create_str_enum(ctx, variants)
},
"referrer policy" => {
let variants = ctx
.referrer
.select_first(s!("h2#referrer-policies ~ p"))
.select(s!("code"))
.map(|elem| elem.inner_text());
let ty = create_str_enum(ctx, variants);
format!("StrOptionEmpty<{ty}>")
},
"potential destination.*" => {
let variants = ctx
.fetch
.select_first(s!("p:has(#destination-type)"))
.select(s!("code"))
.map(|elem| elem.inner_text());
create_str_enum(ctx, variants)
},
"valid navigable target name or keyword" => {
let variants = ctx
.html
.select(s!("#valid-browsing-context-name-or-keyword code"))
.map(|elem| elem.inner_text());
format!("Or<{}, Str>", create_str_enum(ctx, variants))
},
_ => panic!("not handled: {textual_ty} for {attr}"),
})
}
fn rel_type(ctx: &mut Context) -> String {
let variants = ctx
.html
.select_first(s!("#table-link-relations"))
.select(s!("tbody tr td:first-of-type code"))
.map(|elem| elem.inner_text());
let ty = create_str_enum(ctx, variants);
format!("TokenList<{ty}, ' '>")
}
/// Tries to parse an attribute's textual as a semicolon-separate list of
/// strings.
fn try_parse_alternation(ctx: &mut Context, textual_ty: &str) -> Option<String> {
let mut fallback = false;
let mut variants = vec![];
for piece in textual_ty.split(";") {
let piece = piece.trim();
if piece.starts_with('"') && piece.ends_with('"') {
variants.push(piece[1..piece.len() - 1].to_owned());
continue;
}
match piece {
"a custom command keyword" => fallback = true,
s if s.starts_with("a valid MIME type string") => fallback = true,
_ if !piece.is_empty() => return None,
_ => {}
}
}
let mut ty = create_str_enum(ctx, variants);
if fallback {
ty = format!("Or<{ty}, Str>");
}
Some(ty)
}
/// Determines the Rust type for an ARIA attribute.
fn determine_aria_type(ctx: &mut Context, attr: &str) -> String {
let table_sel = format!("h4[id^=\"{attr}\"] ~ table[class$=\"-features\"]");
let ty_cell = ctx
.aria
.select_first(&Selector::parse(&table_sel).unwrap())
.select_first(s!("td[class$=\"-value\"]"));
match ty_cell.inner_text().as_str() {
"ID reference" => "Str".into(),
"ID reference list" => "TokenList<Str, ' '>".into(),
"integer" => "i64".into(),
"number" => "f64".into(),
"string" => "Str".into(),
"token" => determine_aria_values(ctx, attr),
"token list" => {
let ty = determine_aria_values(ctx, attr);
format!("TokenList<{ty}, ' '>")
}
"tristate" => {
format!(
"Or<StrBool, {}>",
create_str_literal(
ctx,
(
"mixed".into(),
"An intermediate value between true and false.".into()
)
)
)
}
"true/false" => "StrBool".into(),
"true/false/undefined" => "StrOptionUndefined<StrBool>".into(),
text => panic!("aria not handled: {text} for {attr}"),
}
}
/// Determines the Rust type for an ARIA string enumeration.
fn determine_aria_values(ctx: &mut Context, attr: &str) -> String {
let table_sel = format!("h4[id^=\"{attr}\"] ~ table.value-descriptions");
let variants = ctx
.aria
.select_first(&Selector::parse(&table_sel).unwrap())
.select(s!("tbody tr"))
.map(|tr| {
(
tr.select_text(s!(".value-name"))
.trim_end_matches(" (default)")
.to_owned(),
tr.select_text(s!(".value-description")),
)
});
create_str_enum(ctx, variants)
}
/// Allocate a string literal type in the output.
fn create_str_literal(ctx: &mut Context, variant: impl EnumVariant) -> String {
create_str_enum(ctx, vec![variant])
}
/// Allocates a string enum type in the output.
fn create_str_enum<V: EnumVariant>(
ctx: &mut Context,
variants: impl IntoIterator<Item = V>,
) -> String {
let mut variants: Vec<_> = variants.into_iter().map(V::with_docs).collect();
let mut extract = |list: &[&str]| {
let has = list.iter().all(|item| variants.iter().any(|(v, _)| v == item));
if has {
variants.retain(|(v, _)| !list.contains(&v.as_str()));
}
has
};
let mut ty = "()".to_owned();
if extract(&["true", "false"]) {
ty = format!("Or<StrBool, {ty}>");
} else if extract(&["yes", "no"]) {
ty = format!("Or<YesNoBool, {ty}>");
} else if extract(&["on", "off"]) {
ty = format!("Or<OnOffBool, {ty}>");
}
if extract(&["ltr", "rtl"]) {
ty = format!("Or<HorizontalDir, {ty}>");
}
if extract(&["none"]) {
ty = format!("StrOptionNone<{ty}>");
}
if extract(&["auto"]) {
ty = format!("Smart<{ty}>");
}
if variants.is_empty() {
return re!("Or<(\\w+), \\(\\)>")
.replace(&ty, |m: &regex::Captures| m[1].to_owned())
.into_owned();
}
let len = variants.len();
let start = (0..ctx.strings.len())
.find(|&i| ctx.strings.get(i..i + len) == Some(variants.as_slice()))
.unwrap_or_else(|| {
let i = ctx.strings.len();
ctx.strings.extend(variants);
i
});
let end = start + len;
ty.replace("()", &format!("StrEnum<{start}, {end}>"))
}
/// A variant in a stringy enum.
trait EnumVariant {
fn with_docs(self) -> (String, String);
}
impl EnumVariant for &str {
fn with_docs(self) -> (String, String) {
(self.into(), String::new())
}
}
impl EnumVariant for String {
fn with_docs(self) -> (String, String) {
(self, String::new())
}
}
impl EnumVariant for (String, String) {
fn with_docs(self) -> (String, String) {
self
}
}
/// Generates the output file.
fn codegen(output: &Output) -> String {
let tags = output.tags.iter().map(|tag| {
format!(" pub const {}: HtmlTag = HtmlTag::constant({tag:?});", ident(tag))
});
let attrs = output.attrs.iter().map(|attr| {
format!(" pub const {}: HtmlAttr = HtmlAttr::constant({attr:?});", ident(attr))
});
let element_infos = output.element_infos.iter().map(|info| {
let ElementInfo { name, docs, attributes } = info;
format!(
" ElementInfo::new({name:?}, {docs:?}, &[{}]),",
attributes
.iter()
.map(|v| v.to_string())
.collect::<Vec<_>>()
.join(", ")
)
});
let attr_infos = output.attr_infos.iter().map(|info| {
let AttrInfo { name, docs, ty, .. } = info;
format!(" AttrInfo::new::<{ty}>({name:?}, {docs:?}),")
});
let attr_strings = output.attr_strings.iter().map(|pair| format!(" {pair:?},"));
let mut out = String::new();
macro_rules! w {
($($tts:tt)*) => {
writeln!(out, $($tts)*).unwrap();
}
}
w!("// This file is generated by `{}`.", file!());
w!("// Do not edit by hand.");
w!();
w!("#![cfg_attr(rustfmt, rustfmt_skip)]");
w!();
w!("use std::num::NonZeroU64;");
w!();
w!("use crate::foundations::{{Datetime, Duration, PositiveF64, Smart, Str}};");
w!("use crate::html::typed::*;");
w!("use crate::visualize::Color;");
w!();
w!("#[allow(non_upper_case_globals)]");
w!("pub mod tag {{");
w!(" use crate::html::HtmlTag;");
w!("{}", tags.join("\n"));
w!("}}");
w!();
w!("#[allow(non_upper_case_globals)]");
w!("pub mod attr {{");
w!(" use crate::html::HtmlAttr;");
w!("{}", attrs.join("\n"));
w!("}}");
w!();
w!("pub const ELEMENTS: &[ElementInfo] = &[");
w!("{}", element_infos.join("\n"));
w!("];");
w!();
w!("pub const ATTRS: &[AttrInfo] = &[");
w!("{}", attr_infos.join("\n"));
w!("];");
w!();
w!("pub const ATTRS_GLOBAL: usize = {};", output.attr_global_count);
w!();
w!("pub const ATTR_STRINGS: &[(&str, &str)] = &[");
w!("{}", attr_strings.join("\n"));
w!("];");
out
}
/// Postprocesses documentation.
fn docs(text: &str) -> String {
text.replace("\n", " ")
.replace_regex(re!("\\[[A-Z]+\\]"), "")
.replace_regex(re!("\\s+"), " ")
.trim()
.trim_end_matches('.')
.to_owned()
+ "."
}
/// Turns a tag or attribute name into a valid Rust identifier.
fn ident(name: &str) -> String {
let string = name.replace("-", "_");
if matches!(string.as_str(), "as" | "async" | "for" | "loop" | "type") {
format!("r#{string}")
} else {
string
}
}
/// Helpers methods on [`ElementRef`].
trait ElementRefExt<'a> {
fn inner_text(&self) -> String;
fn select_text(&self, selector: &Selector) -> String;
fn select_first(&self, selector: &Selector) -> ElementRef<'a>;
}
impl<'a> ElementRefExt<'a> for ElementRef<'a> {
fn inner_text(&self) -> String {
self.text().collect()
}
fn select_text(&self, selector: &Selector) -> String {
self.select(selector).flat_map(|elem| elem.text()).collect()
}
#[track_caller]
fn select_first(&self, selector: &Selector) -> ElementRef<'a> {
self.select(selector).next().expect("found no matching element")
}
}
trait Join {
fn join(self, separator: &str) -> String;
}
impl<I, T> Join for I
where
I: Iterator<Item = T>,
T: Display,
{
fn join(self, separator: &str) -> String {
self.map(|v| v.to_string()).collect::<Vec<_>>().join(separator)
}
}
trait StrExt {
fn replace_regex(&self, re: &Regex, replacement: &str) -> Cow<str>;
}
impl StrExt for str {
fn replace_regex(&self, re: &Regex, replacement: &str) -> Cow<str> {
re.replace_all(self, replacement)
}
}

View File

@ -1,31 +0,0 @@
//! Usage: `cargo run -p typst-codegen -- <job>`
//!
//! See other files for more details.
use std::sync::Arc;
mod html;
fn main() {
match std::env::args().nth(1).as_deref() {
Some("html") => html::main(),
Some(job) => panic!("unknown codegen job: {job}"),
None => panic!("no codegen job provided"),
}
}
fn fetch(url: &str) -> String {
println!("Fetching {url}");
// Can't use `Response::into_string` because it has a 10MB limit.
let mut buf = String::new();
ureq::AgentBuilder::new()
.tls_connector(Arc::new(native_tls::TlsConnector::new().unwrap()))
.build()
.get(url)
.call()
.unwrap()
.into_reader()
.read_to_string(&mut buf)
.unwrap();
buf
}