Which is really sad. This is the actual reason why I preferred C over Python[*] for that project, so I could use my own library for HTML generation, which does exactly that. It also ameliorates the `goto cleanup;` thing, since now you can just tell the library to throw subtrees away. And the best thing is, that you can MOVE, and COPY them, which means you can generate code once and then fill it with the data and still later modify it. This means you can also refer to earlier generated values to generate something else, without needing to store everything twice or reparse your own output.
[*] I mean yeah, I could have written a wrapper, but that would have taken far more time.
My point is that treating it as the tree it is, is the only way to really make it impossible to produce invalid HTML. You could also actually validate not just syntax, but also semantic.
> Not a lot of tree oriented output as you make it libraries.
That was actually the point of my library, although I must admit, I haven't implemented actually streaming the HTML output out, before having composed the whole tree. It isn't actually that complicated, what I would need to implement would be to make part of the tree immutable, so that the HTML for it can already be generated.
There was a system with dependent types that ruled out invalid html at compile time, even dynamically generated html (rather than a runtime error, you would get a compile error if your code did something wrong)
Needless to say it wasn't very practical. But there was one commercial site written in it https://github.com/bazqux/bazqux-urweb (the site still exists but not sure if it's still written in ur/web)
It's still written in Ur/Web. And the type-safety of Ur/Web is the reason I started writing it -- I couldn't imagine myself using untyped JavaScript.
Ur/Web is not very practical for reasons other than type safety: the lack of libraries and slow compilation when the project gets big. The language itself is good, though.
Nowadays, I would probably choose OCaml. It doesn't have Ur/Web's high-level features, but it's typed and compiles quckly.
Yet 30 years later it feels like string interpolation is the most common tool. It probably isn't, but still surprisingly common.