TyXML 5.0.0: the HTML living standard and SVG 2
TyXML 5.0.0 is out, and it is a major release. The library now follows the current specifications: the WHATWG living standard for HTML, and SVG 2 with the Filter Effects module for SVG, whose support had not moved since SVG 1.1. On the way it fixes a long list of elements and attributes that could not be used at all, and the PPX and JSX syntaxes now accept the camel case SVG attributes, so that an indented <svg viewBox="0 0 100 100"> both parses and typechecks.
TyXML builds HTML and SVG documents whose validity is checked by the OCaml type system: an element that the specification does not allow in a given position does not typecheck, and neither does an attribute on an element that does not carry it. It works with the textual representation shipped in the package, with DOM trees (js_of_ocaml-tyxml), and with the reactive and replicated trees of Eliom; you can plug your own representation through the functorial interface. Markup can be written with the combinators, with the HTML syntax through the PPX, or with JSX.
HTML: catching up with the living standard
New elements: s, bdi, search, data, slot, and track with its kind, srclang and default attributes, which audio and video take through a new ?tracks argument.
New attributes, by family:
- popover (
popover,popovertarget,popovertargetaction) and the invoker commandscommandandcommandforon buttons; - microdata:
itemscope,itemtype,itemid,itempropanditemref, plusmeta_itemprop, the form ofmetathat the specification allows wherever phrasing content is expected and not only in the head; - declarative shadow DOM on templates (
shadowrootmode,shadowrootdelegatesfocus,shadowrootclonable,shadowrootserializable) and the CSS shadow partspartandexportparts; - loading and fetching:
loading,decodingandfetchpriorityon images,as,imagesrcsetandimagesizeson preload links,blockingon links, scripts and styles,nomoduleon scripts,nonceanywhere; - forms and dialogs:
closedbyon dialogs,dirnameon inputs and textareas,captureon file inputs, thedialogvalue ofmethodandformmethod,autocompleteon selects and textareas; - global:
inert,enterkeyhint,autocapitalize,autocorrect,writingsuggestions,slot,is, and the`Autovalue ofdir.
The event handler attributes that were missing are in as well: the whole pointer event family, onwheel, onauxclick, the clipboard handlers, and onbeforeinput, onbeforematch, onbeforetoggle, oncancel, oncuechange, onscrollend, onsecuritypolicyviolation, onslotchange and ontoggle, among others.
Content models were brought in line with the specification: div groups dt and dd inside dl, the script-supporting elements are accepted in dl, ol, ul, menu, table and its row groups, tr, select and optgroup, hgroup accepts p, and select accepts hr.
SVG: from 1.1 to 2
The SVG side is where the release is largest, since it had not moved since SVG 1.1. Three elements were added, and two of them were more than an omission:
maskwas declared inSvg_typesbut the element itself was missing;feMergecould be given no child at all, becausefeMergeNodedid not exist;feDropShadowis new in Filter Effects 1.
About thirty presentation attributes had their type tag declared but no function to produce them, so they were simply unreachable: baseline-shift, clip-rule, color, color-interpolation, cursor, display, fill-opacity, filter, flood-color, letter-spacing, marker-end, mask, opacity, overflow, pointer-events, visibility, word-spacing, writing-mode and more. The ones new in SVG 2 are there too: paint-order, text-overflow, transform-origin, vector-effect and white-space.
Also new: ARIA support (a_role and a_aria) on both the HTML and the SVG side, the tabindex and autofocus global attributes, lang becoming global, the SVG 2 link attributes on the a element (download, hreflang, ping, referrerpolicy, rel and type), the geometry attributes on symbol, fr on radial gradients, side and path on textPath, and the HTML event handler attributes that SVG 2 reuses on every element.
Content models were widened to SVG 2: shapes accept paint servers, clipPath, marker, mask, script and style; text elements accept paint servers; filter primitives accept descriptive elements and animation. What SVG 2 removed is now deprecated rather than absent, and a_onload is undeprecated, since the load event is still fired.
Two changes affect the output. The animation attributes values, keyTimes and keySplines are separated with semicolons, as SMIL requires, where they used to be split on spaces. And a printed document no longer carries the SVG 1.1 doctype: Svg.Info declared SVG 1.1, so every document went out with a DTD that forbids the SVG 2 elements and attributes TyXML emits, and SVG 2 defines no DTD at all.
Things that did not work at all
Part of this release is a list of constructs that the types allowed on paper but that no program could actually use:
- the
areaelement had nohrefattribute, and its type tag was in no content model, so amapcontaining areas fitted nowhere; symbolaccepted neither the core attributes, so noidand therefore no way to reference it, nor the presentation and event attributes, nor shape children;- the
lichildren ofmenucould not be built: the branch required anliwhose attributes were a subset of the common ones, which excludes thevalueattribute thatlialways allows; - the
xml:base,xml:langandxml:spaceattributes and the touch event handlers of SVG had type tags listed in no attribute category, which made them unusable on every element; - nine attribute functions produced a tag that did not match them, among them
a_edgeMode, which produced the tag oftargetY, anda_low, which produced the tag ofa_high; feFuncR,feFuncGandfeFuncBwere all defined as the tag offeFuncA.
Several names were also emitted misspelled, which is worse than a compile error because the output looks fine: reversed went out as reserved, the allow-scripts sandbox token as allow-script, and in SVG target as xlink:target, glyph-name as glyphname, requiredExtensions, zoomAndPan, filterRes and edgeMode under wrong names. Some attribute values were affected as well. Finally Xml_print.compose_decl emitted a literal backslash-n instead of a newline, which made the XML declaration invalid.
The PPX and the JSX syntax
The headline fix: no camel case SVG attribute was recognised. viewBox, maskUnits, stdDeviation, gradientTransform, preserveAspectRatio, refX, markerWidth and many others were rejected, because the markup parser lowercases attribute names and the SVG case adjustments of the HTML standard were not applied. Which means most real SVG could not be written with the PPX or with JSX at all.
Whitespace between SVG tags is now ignored for the elements whose content model does not accept text, so indented SVG, as the specification itself writes it, typechecks:
let icon =
[%svg "<g transform='translate(1,2) rotate(45)'>
<circle cx='5' cy='5' r='4'/>
</g>"]Both of those failed before: the indentation for the first reason, and the transform attribute because its arguments were comma separated. Any whitespace, and not only the space character, is now accepted around the separators of list-valued attributes. An empty option is accepted too, as for script and textarea, which is the usual form inside a datalist.
Breaking changes
The interesting ones for existing code:
hiddentakes an enumerated argument instead of no argument, andcontenteditablean enumerated argument instead of a boolean, so that the until-found and plaintext-only states can be expressed;- the attributes whose value is a URL go through
Xml.uri:a_itemtypeanda_pingon the HTML side, anda_href,a_xlink_hrefanda_pingon the SVG side.Tyxml.HtmlandTyxml.Svgare unaffected, theirXml.uriisstring; the gain is for the implementations whoseuritype is abstract; - SVG documents are printed without a doctype, as above;
- the
Wrapped_functionsmodule type has four new functions, which the implementations of the functorial interface must provide; - the build now requires OCaml 4.08, dune 3.18 and ppxlib 0.36.
The changelog has the full list, including the misspelled names that were corrected.
Documentation
The manual moved from wikicreole to odoc, the API references in the interfaces are native odoc references, and the themed site is built by wodoc, like the rest of ocsigen.org. It is at ocsigen.org/tyxml.
Getting it
opam install tyxmlwith tyxml-ppx or tyxml-jsx for the syntaxes. The release notes carry the same changelog.
Eliom already has the matching changes in its development branches. The released version still requires TyXML 4.6, so it will pick 5.0.0 up in its next release; js_of_ocaml-tyxml and the odoc family needed no change at all.
Thanks
This release owes a lot to its contributors: Hugo Heuzard, who found and fixed most of the mismatched type tags and misspelled names, Martin Bodin for the SVG whitespace handling, the transform separators, clip-path and the XML declaration, toastal for the microdata attributes, the content models and a round of orthographic fixes, Sylvain Boilard for popover and the name attribute of details, rand00 for the semicolon-separated animation attributes, Sora Morimoto for the build modernisation, and Patrick Ferris for the OCaml 5.2 AST.
Bug reports and pull requests are welcome on GitHub.