v4.0.2
Summary
Release meta
Released on: 2026-07-06
Released by: github-actions[bot]
Published by: GitHub
Logs: full diff
Changelog
Improvements
- The HTML5 converter can now inline an SVG image whose target is a
data:URI (e.g.image::data:image/svg+xml;base64,…[opts=inline]).readSvgContentsdecodes both Base64 and percent-encodeddata:payloads instead of only reading from a file or remote URI, so a diagram or image embedded as a data-URI can be rendered as inline<svg>without writing a file or enablingallow-uri-read. The SVG format is inferred from theimage/svg+xmlmedia type, so an explicitformat=svgattribute is no longer required on adata:URI target
Bug Fixes
imageUrinow returns adata:URI image target as-is instead of attempting to read it as a file or fetch it via the Fetch API; previously, with bothdata-uriandallow-uri-readset, adata:URI target (e.g.data:image/png;base64,…) triggered a spurious "could not retrieve image data from URI" warning- Fix the built-in
asciidoctor-versionattribute reporting the hard-coded upstream Ruby version (3.0.0.dev) instead of the actual library version — it now resolves to the@asciidoctor/corepackage version (e.g.4.0.1), so references such as{asciidoctor-version}reflect the real release - Report
Asciidoctor.js(instead ofAsciidoctor) in the HTML5<meta name="generator">and manpageGenerator:metadata, so the generated output identifies the JavaScript library and its version (e.g.Asciidoctor.js 4.0.1) - Fix natural cross-references (e.g.
<<Some section title>>) not resolving inside list items, description list items and table cells — they rendered as<a href="#Some section title">[Some section title]</a>instead of linking to the section’s generated ID. Unlike paragraph text (substituted lazily during conversion, after the reftext→id map is built), list/cell/dlist text is pre-computed eagerly in_resolveAllTexts, which ran before the map existed; the synchronousresolveIdfallback then matched against the rawreftextattribute rather than the computedxreftext(a section’s title), so the lookup failed. Text pre-computation now runs in two passes — titles and reftexts first, then the reftext→id map is built, then list/cell/dlist content text — restoring Ruby’s invariant that all references are known before any content substitution resolves a natural cross-reference - Fix a registered converter’s flat string trait properties (convention
#2, e.g.converter.outfilesuffix = '.html') being silently overwritten with accessor functions after the first conversion — normalizing the converter applied theBackendTraitsmixin, which installed same-named accessor methods on the instance, clobbering the author’s strings. Code readingconverter.outfilesuffixthen got a function instead of.html(and only after normalization, so the value’s type changed mid-lifecycle).applyBackendTraitsno longer overwrites an existing same-named data property, andDocumentreads backend traits through_getBackendTraits()rather than the accessor methods, so flat string properties stay strings throughout - Fix JavaScript templates not being applied depending on their file extension and the project’s module format (#1841) — a
.jstemplate in a"type": "module"(ESM) project crashed withtemplate.render is not a function, and.mjstemplates were silently ignored (the extension was not even recognised). The template loader used a CommonJSrequire()for.js/.cjsfiles, which returned the ESM namespace object (not the render function) for ESM.jsfiles and did not handle.mjsat all..jsand.mjstemplates are now loaded with a dynamicimport()(which Node resolves as either ESM or CommonJS) and the render function is taken from the module’s default export, so all combinations of extension (.js,.cjs,.mjs) and module format (ESM or CommonJS) work. The same loading is applied to the optionalhelpersfile (helpers.js/helpers.cjs/helpers.mjs), which can now also be an ES module