import htmlData from "@wzlin/html-data"; import { writeFileSync } from "fs"; import { join } from "path"; import { RUST_OUT_DIR } from "./_common"; const rsTagAttr = ({ boolean = false, caseInsensitive = false, collapse = false, defaultValue, redundantIfEmpty = false, trim = false, }: { boolean?: boolean; caseInsensitive?: boolean; collapse?: boolean; defaultValue?: string; redundantIfEmpty?: boolean; trim?: boolean; }) => ` AttributeMinification { boolean: ${boolean}, case_insensitive: ${caseInsensitive}, collapse: ${collapse}, default_value: ${ defaultValue == undefined ? "None" : `Some(b"${defaultValue}")` }, redundant_if_empty: ${redundantIfEmpty}, trim: ${trim}, } `; let code = ` use lazy_static::lazy_static; use rustc_hash::FxHashMap; use crate::common::spec::tag::ns::Namespace; pub struct AttributeMinification { pub boolean: bool, pub case_insensitive: bool, pub collapse: bool, pub default_value: Option<&'static [u8]>, pub redundant_if_empty: bool, pub trim: bool, } pub enum AttrMapEntry { AllNamespaceElements(AttributeMinification), SpecificNamespaceElements(FxHashMap<&'static [u8], AttributeMinification>), } pub struct ByNamespace { // Make pub so this struct can be statically created in gen/attrs.rs. pub html: Option, pub svg: Option, } impl ByNamespace { fn get(&self, ns: Namespace) -> Option<&AttrMapEntry> { match ns { Namespace::Html => self.html.as_ref(), Namespace::Svg => self.svg.as_ref(), } } } pub struct AttrMap(FxHashMap<&'static [u8], ByNamespace>); impl AttrMap { pub const fn new(map: FxHashMap<&'static [u8], ByNamespace>) -> AttrMap { AttrMap(map) } pub fn get(&self, ns: Namespace, tag: &[u8], attr: &[u8]) -> Option<&AttributeMinification> { self.0.get(attr).and_then(|namespaces| namespaces.get(ns)).and_then(|entry| match entry { AttrMapEntry::AllNamespaceElements(min) => Some(min), AttrMapEntry::SpecificNamespaceElements(map) => map.get(tag), }) } } `; code += ` lazy_static! { pub static ref ATTRS: AttrMap = { let mut m = FxHashMap::<&'static [u8], ByNamespace>::default(); ${[...Object.entries(htmlData.attributes)] .map( ([attr_name, namespaces]) => ` m.insert(b\"${attr_name}\", ByNamespace { ${(["html", "svg"] as const) .map( (ns) => ` ${ns}: ` + (() => { const tagsMap = namespaces[ns]; if (!tagsMap) { return "None"; } const globalAttr = tagsMap["*"]; if (globalAttr) { return `Some(AttrMapEntry::AllNamespaceElements(${rsTagAttr( globalAttr )}))`; } const entries = Object.entries(tagsMap); return `Some({ let ${ entries.length ? "mut" : "" } m = FxHashMap::<&'static [u8], AttributeMinification>::default(); ${entries .map( ([tagName, tagAttr]) => ` m.insert(b\"${tagName}\", ${rsTagAttr(tagAttr)});` ) .join("\n")} AttrMapEntry::SpecificNamespaceElements(m) })`; })() + "," ) .join("\n")} }); ` ) .join("")} AttrMap::new(m) }; }`; writeFileSync(join(RUST_OUT_DIR, "attrs.rs"), code);