Skip to content

v4.0.1

Choose a tag to compare

@github-actions github-actions released this 01 Jul 15:50

Summary

Release meta

Released on: 2026-07-01
Released by: github-actions[bot]
Published by: GitHub

Logs: full diff

Changelog

Bug Fixes

  • Fix reassigned document-body attributes all resolving to their final value — a custom attribute redefined in the body (e.g. :reassigned: one:reassigned: two) must resolve to the value in scope at each reference (Ruby renders one then two), but every reference rendered the last value when any content preceded the entries (including a document header). The parser reset the shared block-attributes object between blocks with Object.keys(...), which skips the Symbol-keyed ATTR_ENTRIES_KEY, so the array of AttributeEntry objects leaked and accumulated across blocks; each block’s attribute-entry playback then replayed every assignment. The reset now uses Reflect.ownKeys(...) so the entries are cleared too
  • Fix reassigned attributes not resolving correctly when referenced from list item or table cell text (e.g. :x: 1* item {x}:x: 2* item {x}) — unlike paragraph content (resolved lazily during conversion with attribute-entry playback), list item and table cell text is pre-computed eagerly after restoreAttributes() reverted the document to its header state, so body-level attributes were out of scope and rendered as unresolved ({x}) or with the wrong value. _resolveAllTexts now replays each block’s attribute entries in document order (mirroring AbstractBlock#convert) while pre-computing, then restores the header state. In addition, a block carrying only Symbol-keyed attribute entries (an :attr: entry immediately preceding a list or table) now still receives them — the parser’s transfer guard used Object.keys(...).length (0 for entry-only attributes) instead of Reflect.ownKeys(...).length, matching Ruby’s attributes.empty? where :attribute_entries is counted
  • Fix loss of the structured source_location on log messages emitted through the reader/preprocessor path (e.g. include file not found, unterminated <type> block, unterminated preprocessor conditionals) — these were logged as a plain string with the cursor baked into the text as a "<path>: line <N>: " prefix, so message.getSourceLocation() returned null (regression from 2.x). The reader now logs an auto-formatting message that keeps the cursor as a structured source_location, so getSourceLocation() (getFile()/getLineNumber()) is populated again and getText() stays clean; the stderr Logger still renders the "<path>: line <N>: " prefix. This restores line-anchored diagnostics for downstream tooling (IDE integrations, linters, CI annotations)
  • Fix allow-uri-read not being recognised when declared with an empty value (e.g. allow-uri-read= or attributes: { 'allow-uri-read': '' }) — include resolution checked the attribute’s truthiness via getAttribute, but ’'is falsy in JavaScript while Asciidoctor treats the mere presence of an attribute as enabled; the include reader (Node and browser modes) now checks presence viahasAttribute, matching Ruby’s attr?` semantics
  • Fix incorrect generated type declarations for async substitutor methods — applySubs, subQuotes, subMacros, subPostReplacements, subSource, subCallouts, highlightSource, restorePassthroughs and parseAttributes are all async but their JSDoc @returns declared the unwrapped type (e.g. string), so the emitted .d.ts advertised string instead of Promise<string>; callers following the types could concatenate the returned Promise and produce [object Promise]. The JSDoc now declares Promise<…> and the .d.ts was regenerated

Improvements

  • Improve typing of MemoryLogger#getMessages() — it previously returned any[]; the LogMessage wrapper class is now exported and getMessages() is declared to return LogMessage[], so consumers get typed getSeverity() (string), getText() (string) and getSourceLocation() (Cursor | undefined) accessors. The wrapper’s internal _text/_sourceLocation fields were renamed to public text/sourceLocation properties (consistent with severity), providing dual property/getter access