Repository: typst/typst
File: crates/typst-html/src/lib.rs (Rust)

Code before:
                .into(),
        );
    }

    if let Some(description) = &info.description {
        children.push(
            HtmlElement::new(tag::meta)
                .with_attr(attr::name, "description")
                .with_attr(attr::content, description.clone())
                .into(),
        );
    }

    if !info.author.is_empty() {
        children.push(
            HtmlElement::new(tag::meta)
                .with_attr(attr::name, "authors")
                .with_attr(attr::content, info.author.join(", "))
                .into(),
        )
    }

    if !info.keywords.is_empty() {
        children.push(
            HtmlElement::new(tag::meta)
                .with_attr(attr::name, "keywords")
                .with_attr(attr::content, info.keywords.join(", "))
                .into(),
        )
    }

    HtmlElement::new(tag::head).with_children(children)
}

/// Determine which kind of output the user generated.
fn classify_output(mut output: Vec<HtmlNode>) -> SourceResult<OutputKind> {
    let count = output.iter().filter(|node| !matches!(node, HtmlNode::Tag(_))).count();
    for node in &mut output {
        let HtmlNode::Element(elem) = node else { continue };
        let tag = elem.tag;
        let mut take = || std::mem::replace(elem, HtmlElement::new(tag::html));
        match (tag, count) {
            (tag::html, 1) => return Ok(OutputKind::Html(take())),
            (tag::body, 1) => return Ok(OutputKind::Body(take())),
            (tag::html | tag::body, _) => bail!(
                elem.span,
                "`{}` element must be the only element in the document",
                elem.tag,
            ),
            _ => {}
        }

Review comment (bug):
Do we know if they should be separated by commas and spaces instead of just commas? MDN[^1] only claims they are "separated by commas", so maybe no spaces is "more correct" (even if less readable by humans)? Though I'm finding examples of both usages around[^2], so maybe it doesn't matter...

[^1]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta/name
[^2]: https://stackoverflow.com/a/63637855

Code after:
        );
    }

    if let Some(description) = &info.description {
        children.push(
            HtmlElement::new(tag::meta)
                .with_attr(attr::name, "description")
                .with_attr(attr::content, description.clone())
                .into(),
        );
    }

    if !info.author.is_empty() {
        children.push(
            HtmlElement::new(tag::meta)
                .with_attr(attr::name, "authors")
                .with_attr(attr::content, info.author.join(", "))
                .into(),
        )
    }

    if !info.keywords.is_empty() {
        children.push(
            HtmlElement::new(tag::meta)
                .with_attr(attr::name, "keywords")
                .with_attr(attr::content, info.keywords.join(", "))
                .into(),
        )
    }

    HtmlElement::new(tag::head).with_children(children)
}

/// Determine which kind of output the user generated.
fn classify_output(mut output: Vec<HtmlNode>) -> SourceResult<OutputKind> {
    let count = output.iter().filter(|node| !matches!(node, HtmlNode::Tag(_))).count();
    for node in &mut output {
        let HtmlNode::Element(elem) = node else { continue };
        let tag = elem.tag;
        let mut take = || std::mem::replace(elem, HtmlElement::new(tag::html));
        match (tag, count) {
            (tag::html, 1) => return Ok(OutputKind::Html(take())),
            (tag::body, 1) => return Ok(OutputKind::Body(take())),
            (tag::html | tag::body, _) => bail!(
                elem.span,
                "`{}` element must be the only element in the document",
                elem.tag,
            ),
            _ => {}
        }
    }