asciidoctor-rhrev 1.5.0 → 1.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e0d0f5e91fc8b4f30c8325d121249758b652632641f7216a32c76d30d7096676
4
- data.tar.gz: 0ea9ee18142768232c7b8a14bc2a656fed2b7cb2829bc4f0dcbb42c6e7a57d24
3
+ metadata.gz: 749dcca33dd6cedd4b545e1f7fe8ae07c25c662d1475268b105654241a40f4d3
4
+ data.tar.gz: b9f5eb774c855c427e7c891f6f6dc5623566fe04bd9b4ce62d1fb8c95817f697
5
5
  SHA512:
6
- metadata.gz: bd5f85f7135ac2b0ba735dc71f25747d8e8a44a1e0b59520cdb4e42317ad98fc56d7cfd3a8054cc8d801f7c4be42037d8e8fa03e960d9f3efd70d5ccfd92c26a
7
- data.tar.gz: 8432383a8b45809314e0db49f508ca842bb3662ed487f38f8228810694d308480da4ab581129176a3f21083ce2626a2f8ce203b450444e228c83788a713dd51d
6
+ metadata.gz: 6dce05ff64190cf02cff0fdf39af62d481c1b3e43d7c447673a41276c644d3668a6fa5bef77fb1d19bfcb31fc555a36ebab52985bac41e174a1fb565b0117797
7
+ data.tar.gz: eb056701ebd0a0289143fde96aef7dea2d5e16bae03cadcee183865a74e80623a6ffd088267bb071de31b69eeaae61fc3cb1ee78e3c431acfe701e1b1792fe6b
data/CHANGELOG.adoc CHANGED
@@ -1,14 +1,27 @@
1
1
  = Changelog
2
2
 
3
+ == 1.5.2 (2026-09-01)
4
+
5
+ * Fix revision-history and `pagerhref` page numbers being off by a fixed, per-document offset for every `page_numbering_start_at` mode other than `body` (PDF backend). `Converter#record_rhrev_body_start_page` always assumed a `body`-mode restart (wherever structural body content first renders), the only mode where that assumption holds; reported directly with real page numbers from a real document under `after-toc` (an 11-page discrepancy, exactly the front matter preceding the real restart point) and `cover` (a consistent 1-page discrepancy, exactly the cover page numbering there is contiguous with, not reset after). `Converter#compute_rhrev_page_numbering_start_page` now reads the document's own resolved mode directly, matching asciidoctor-pdf's own logic (`converter.rb`'s own `page_numbering_start_at` branches), and `Converter#correct_rhrev_page_numbering` (called once, after the whole document, table of contents included, has rendered) corrects every number `record_rhrev_body_start_page`'s own eager, body-mode-only capture recorded during traversal: `toc`/`after-toc`'s real restart point is not knowable any earlier, confirmed directly against asciidoctor-pdf's own source, since it only finalizes the table of contents' real page extent after inking it. `Catalog#recompute_display_pages` applies the correction from each entry's own already-stored real physical page number (`page_sortable`), never re-derived. An explicit integer `page_numbering_start_at` remains a known, undocumented-no-longer limitation: that mode's own formula is a genuinely different shape (the body's own first page is labeled the given integer, not necessarily displayed page "1"), not confirmed against a real build, so left unhandled rather than risk a second, differently-wrong number. Verified directly against real `asciidoctor-pdf` builds for `after-toc` and `cover` (not assumed from source reading alone): the revision-history table's own reported page cross-checked against the number actually printed in the footer of the real page a marked entry lands on, confirmed wrong before the fix and correct after, for both modes independently; `body` mode and the two existing pagination regression fixtures produce byte-identical rendered text before and after. New regression fixture, `tests/regression/rhrev-page-numbering-start-at.rb`
6
+ * Note: gem-only; the Antora extension (HTML output, no physical PDF page concept) is unaffected, npm still bumps concurrently per the standing 1.5.1 policy
7
+
8
+ == 1.5.1 (2026-08-28)
9
+
10
+ * Fix the Antora extension's table-cell change bars tagging only the marked cell's nested content instead of its own `<td>`/`<th>`, the deliberate difference noted in 1.5.0 below. The earlier attempt (a real Opal subclass of `Html5Converter`, registered via `ConverterFactory`) broke real Antora builds whenever a sibling package's own `@asciidoctor/core` install disagreed in version with the consuming site's; the fix instead patches `$convert_table` directly onto whichever converter class is already resolved for the current document (`doc.getConverter()`), never a separately-required or separately-registered class, so it cannot collide with Antora's own converter registration regardless of version drift elsewhere in the process. The cell's own `<td>`/`<th>` now carries the `rhrev-changed` role directly, matching the PDF backend's margin bar and Asciidoctor's native HTML5 backend (npm)
11
+ * Fix a manual-mode `pagerhref` table's marked cell drawing no change bar at all (PDF backend), a previously documented limitation. `Converter#convert_table` computes the marked-row data for a change bar and clears it again before returning, correct for an ordinary table, but a `pagerhref` table instead defers its real render to `Converter#ink_pagerhref_tables`, much later, by which point that data had already been cleared, or worse, held a different table's value entirely. `Converter#allocate_pagerhref_table_extent` now stashes each `pagerhref` table's own marked-row data alongside its reserved page extent, and `ink_pagerhref_tables` restores it immediately before that specific table's deferred render, so the existing cell-bar mechanism reaches it correctly (gem)
12
+ * Note: gem and npm release concurrently from this version on, one version number for both regardless of which side's code actually changed
13
+
3
14
  == 1.5.0 (2026-08-28)
4
15
 
5
- * Add change bars and revision-history roll-up for paragraphs, ordered/unordered/description lists, admonitions, open blocks, quotes, verses, and sidebars: an `rhrevN-M` attribute on one of these blocks inks a change bar the same way a section or table does, but adds its change text as a bullet to the entry of its nearest enclosing section, since it has no title or section number for a row of its own. A block with no enclosing section adds its change text to the document-level `all` entry instead. Available in both the PDF backend and Asciidoctor's HTML5 backend
6
- * Add table-cell change bars: an individual table cell needs the AsciiDoc-style cell syntax (`a|`) to carry an `rhrevN-M` attribute at all, since a plain cell never parses its content as blocks. In the PDF backend the bar draws in the page margin at the cell's real rendered row height, correct for a wrapped, multi-line cell. In the HTML backend the changed cell's `<td>`/`<th>` carries the `rhrev-changed` role directly. The cell's change text rolls onto its enclosing table's entry, or the table's nearest enclosing section if the table has no id of its own, or the document-level `all` entry if neither exists
16
+ * Add change bars and revision-history roll-up for paragraphs, ordered/unordered/description lists, admonitions, open blocks, quotes, verses, and sidebars: an `rhrevN-M` attribute on one of these blocks inks a change bar the same way a section or table does, but adds its change text as a bullet to the entry of its nearest enclosing section, since it has no title or section number for a row of its own. A block with no enclosing section adds its change text to the document-level `all` entry instead. Available in the PDF backend, Asciidoctor's HTML5 backend, and the Antora extension
17
+ * Add table-cell change bars: an individual table cell needs the AsciiDoc-style cell syntax (`a|`) to carry an `rhrevN-M` attribute at all, since a plain cell never parses its content as blocks. In the PDF backend the bar draws in the page margin at the cell's real rendered row height, correct for a wrapped, multi-line cell. In Asciidoctor's HTML5 backend the changed cell's `<td>`/`<th>` carries the `rhrev-changed` role directly. In the Antora extension the cell's marked nested content carries the role instead, a deliberate difference: no converter-level override exists there for tagging a `<td>`/`<th>` directly without risking conflicts with Antora's own HTML5 converter customization, and the unmodified converter already supports a role on ordinary content. In every backend, the cell's change text rolls onto its enclosing table's entry, or the table's nearest enclosing section if the table has no id of its own, or the document-level `all` entry if neither exists
7
18
  * Fix `convert_section` reading `page_number` before the chapter-opening page break instead of after (PDF backend): a chapter-opening section's revision-history entry and anchor destination recorded the page before the break, one page too low
8
19
  * Fix revision-history and `pagerhref` page numbers showing the physical PDF page index instead of the reader-visible page, when `page_numbering_start_at: body` (the default) and the document has real preamble content before the body starts (PDF backend)
9
20
  * Fix the HTML backend's revision-history table not rendering at all when the only revision-history content was a document-level `all` entry and no block had its own entry
10
21
  * Fix `rhrev-table-extra-blank-row` being silently ignored for an initial-release document (`revnumber` `1.0`/`1`): the initial-release table is built through a separate code path from the regular revision-history table and never checked the attribute
11
- * Note: this release is gem-only. The Antora extension's revision-history logic (`antora-extension/antora-rhrev-html.js`) is a separate, independently maintained implementation from the gem's Ruby code and does not yet include the paragraph/list/table-cell coverage above; the npm package skips 1.5.0
22
+ * Fix the Antora extension's cross-page catalog builder (`antora-rhrev-html.js`): rewritten from a regex/heuristic-anchor-guessing scan to real per-page parsing, needed for any block type beyond the original six (section, floating title, example, listing, table, image) to reach a real Antora-built site at all
23
+ * Fix `Block#setContent is not a function` in the Antora extension on a modern `@asciidoctor/core`, found while verifying the above
24
+ * Note: the gem published first; the Antora extension's parity work landed in a separate, later commit under the same version number
12
25
 
13
26
  == 1.4.0 (2026-08-14)
14
27
 
@@ -59,20 +59,56 @@ module Asciidoctor
59
59
  @entries.each do |revision, entry_list|
60
60
  entry_list.each do |entry|
61
61
  next unless entry[:anchor] == anchor
62
-
63
- virtual_page_number = physical_page_number - (start_page_number - 1)
62
+
64
63
  entry[:dest] = {
65
64
  anchor: anchor,
66
- page: (virtual_page_number < 1 ?
67
- (Asciidoctor::PDF::RomanNumeral.new physical_page_number, :lower) :
68
- virtual_page_number).to_s,
65
+ page: (displayed_page_for physical_page_number, start_page_number).to_s,
69
66
  page_sortable: physical_page_number,
70
67
  y: y
71
68
  }
72
69
  end
73
70
  end
74
71
  end
75
-
72
+
73
+ # The reader-visible page number for one physical page, given the
74
+ # physical page that displays as "1" (start_page_number) - a plain
75
+ # page number once numbering has started there, a lowercase roman
76
+ # numeral for anything still before it. Shared by link_dest_to_page
77
+ # (the eager, first-pass conversion, correct as-is for
78
+ # page-numbering-start-at: body, the common case) and
79
+ # recompute_display_pages (the deferred, corrected conversion for
80
+ # every other mode, see that method's own docblock).
81
+ def displayed_page_for physical_page_number, start_page_number
82
+ virtual_page_number = physical_page_number - (start_page_number - 1)
83
+ virtual_page_number < 1 ? (Asciidoctor::PDF::RomanNumeral.new physical_page_number, :lower) : virtual_page_number
84
+ end
85
+
86
+ # Recomputes every entry's own :dest][:page] from its already-stored
87
+ # :page_sortable (the real physical page number, unconditionally
88
+ # correct, set by link_dest_to_page above regardless of mode) and
89
+ # the given, now-final start_page_number.
90
+ #
91
+ # Needed because link_dest_to_page's own formula, applied eagerly
92
+ # during document traversal, is only ever correct for page-
93
+ # numbering-start-at: body: for toc/after-toc/cover/an explicit
94
+ # integer, the real physical page that displays as "1" is not
95
+ # knowable that early (asciidoctor-pdf itself only finalizes it
96
+ # after inking the table of contents, confirmed directly against
97
+ # its own source, converter.rb's convert_document). The converter
98
+ # calls this once, after the whole document (table of contents
99
+ # included) has rendered, with the real, corrected start_page_number
100
+ # its own compute_rhrev_page_numbering_start_page works out; entries
101
+ # already correct (body mode) are simply recomputed to the same
102
+ # value they already held, a harmless no-op.
103
+ def recompute_display_pages start_page_number
104
+ @entries.each_value do |entry_list|
105
+ entry_list.each do |entry|
106
+ next unless (dest = entry[:dest]) && dest[:page_sortable]
107
+ dest[:page] = (displayed_page_for dest[:page_sortable], start_page_number).to_s
108
+ end
109
+ end
110
+ end
111
+
76
112
  def sorted_revisions
77
113
  # Collect all unique revisions from entries, all_entries, and cover_entries
78
114
  all_revisions = (@entries.keys + @all_entries.keys + @cover_entries.keys).uniq
@@ -48,13 +48,14 @@ module Asciidoctor
48
48
  # `body_offset = (body_start_page_number = page_number) - 1` line).
49
49
  # Captured once, from whichever of convert_preamble/convert_section
50
50
  # runs first; every later call is a no-op via the memoized ivar.
51
- # Used as the start_page_number fed to Catalog#link_dest_to_page, so
52
- # entries display the reader-visible page (matching page_numbering_
53
- # start_at: body, the default), not a raw physical index that runs
54
- # ahead by however many roman-numeral-numbered front-matter pages a
55
- # title page, TOC, or preamble content added before the body starts.
56
- # Other page_numbering_start_at modes (toc, after-toc, cover, an
57
- # explicit integer) are not accounted for and stay a known limitation.
51
+ #
52
+ # Correct as the FINAL value only for page-numbering-start-at: body
53
+ # (the default): every entry recorded against it during traversal
54
+ # (Catalog#link_dest_to_page, @anchor_catalog below) is provisional
55
+ # for any other mode, corrected once, after the whole document has
56
+ # rendered, by correct_rhrev_page_numbering (convert_document, see
57
+ # its own docblock for why the correction cannot happen any
58
+ # earlier for toc/after-toc specifically).
58
59
  def record_rhrev_body_start_page
59
60
  @rhrev_body_start_page ||= page_number unless scratch?
60
61
  end
@@ -70,7 +71,80 @@ module Asciidoctor
70
71
  virtual = physical_page_number - (start_at - 1)
71
72
  (virtual < 1 ? (RomanNumeral.new physical_page_number, :lower) : virtual).to_s
72
73
  end
73
-
74
+
75
+ # The physical PDF page that displays as reader-visible page "1",
76
+ # computed the same way asciidoctor-pdf itself does (converter.rb's
77
+ # own convert_document), reading the document's own resolved
78
+ # page-numbering-start-at mode, rather than assuming a body-mode
79
+ # restart the way record_rhrev_body_start_page's own capture always
80
+ # has.
81
+ #
82
+ # Called once, from convert_document, AFTER the whole document
83
+ # (table of contents included) has rendered: toc/after-toc
84
+ # genuinely cannot be answered any earlier. Confirmed directly
85
+ # against asciidoctor-pdf's own source: for the standard case (an
86
+ # automatic, top-of-document toc, not an explicit toc::[] macro),
87
+ # its real page extent, and therefore the toc/after-toc offset, is
88
+ # already known before traverse even starts (allocate_toc's own
89
+ # dry run measures it up front) - but for a toc::[] macro placed
90
+ # inside a preamble or elsewhere, that extent is only known once
91
+ # traverse actually reaches and inks it, and asciidoctor-pdf's own
92
+ # correction for that case runs only after traverse doc returns
93
+ # (the num_front_matter_pages[1] = toc_extent.to.page adjustment,
94
+ # gated on title_as_page && !toc_at_top). Reading @toc_extent once,
95
+ # after super has fully returned, gives the correct, final value
96
+ # either way, without this method needing to know which of the two
97
+ # internal paths asciidoctor-pdf actually took.
98
+ #
99
+ # Deliberately does not handle an explicit integer
100
+ # page-numbering-start-at: that mode's own body page is LABELED the
101
+ # given integer, not necessarily displayed page "1" at all (a
102
+ # genuinely different formula shape, physical - anchor + label,
103
+ # not physical - anchor + 1), and is left as the same known
104
+ # limitation record_rhrev_body_start_page's own prior docblock
105
+ # already named, rather than risk a second, differently-wrong
106
+ # formula for a mode not confirmed against a real build.
107
+ def compute_rhrev_page_numbering_start_page node
108
+ body_start = @rhrev_body_start_page || 1
109
+ case (mode = @theme.page_numbering_start_at || 'body')
110
+ when 'cover'
111
+ front_cover_path, = resolve_background_image node.document, @theme, 'front-cover-image', theme_key: :cover_front_image
112
+ front_cover_path ? 1 : body_start
113
+ when 'toc'
114
+ (extent = @toc_extent) ? extent.from.page : body_start
115
+ when 'after-toc'
116
+ if (extent = @toc_extent)
117
+ after_toc_page = extent.to.page
118
+ after_toc_page += 1 if @ppbook && (recto_page? after_toc_page)
119
+ after_toc_page + 1
120
+ else
121
+ body_start
122
+ end
123
+ else
124
+ body_start
125
+ end
126
+ end
127
+
128
+ # Applies compute_rhrev_page_numbering_start_page's own real,
129
+ # mode-aware result, correcting every page number recorded during
130
+ # traversal under the wrong, body-mode-only assumption. A no-op,
131
+ # deliberately, when the corrected value matches what
132
+ # record_rhrev_body_start_page already captured (page-numbering-
133
+ # start-at: body, the common case, and any other mode this method
134
+ # could not confidently resolve): no entry is touched twice for
135
+ # nothing.
136
+ def correct_rhrev_page_numbering node
137
+ return unless @catalog
138
+ corrected = compute_rhrev_page_numbering_start_page node
139
+ return if corrected == @rhrev_body_start_page
140
+ @rhrev_body_start_page = corrected
141
+ @catalog.recompute_display_pages corrected
142
+ @anchor_catalog&.each_value do |entry|
143
+ next unless (dest = entry[:dest]) && dest[:physical_page]
144
+ dest[:page] = rhrev_display_page dest[:physical_page]
145
+ end
146
+ end
147
+
74
148
  def convert_document node
75
149
  @revision_prefix = node.attr 'revhistoryprefix', 'rhrev'
76
150
  init_change_bars node
@@ -87,7 +161,15 @@ module Asciidoctor
87
161
 
88
162
  # Render document (this will visit all nodes and update entry metadata)
89
163
  result = super
90
-
164
+
165
+ # Correct every page number recorded during traversal under the
166
+ # body-mode-only assumption record_rhrev_body_start_page always
167
+ # makes: the real mode-aware value is only knowable now, after
168
+ # the whole document (table of contents included) has rendered.
169
+ # Must run before ink_revision_history/ink_pagerhref_tables below,
170
+ # both real consumers of the numbers this corrects.
171
+ correct_rhrev_page_numbering node
172
+
91
173
  # Ink revision history if allocated
92
174
  if @revision_history_extent && @catalog
93
175
  ink_revision_history node, @revision_history_extent
@@ -141,7 +223,7 @@ module Asciidoctor
141
223
  context: node.context,
142
224
  level: node.level
143
225
  }
144
- @anchor_catalog[node.id][:dest] = { page: (rhrev_display_page page_num), y: cursor }
226
+ @anchor_catalog[node.id][:dest] = { page: (rhrev_display_page page_num), physical_page: page_num, y: cursor }
145
227
 
146
228
  # Link destination to page for revision history
147
229
  revision_history.link_dest_to_page node.id, page_num, (@rhrev_body_start_page || 1), y: cursor
@@ -191,10 +273,15 @@ module Asciidoctor
191
273
  # margin bar at draw time (table_cell_change_bar_patch.rb reads this
192
274
  # ivar back via Prawn::Table::Cell#row), independent of whether the
193
275
  # table itself is marked. See marked_table_cell_bar_rows for why
194
- # this matches by row index alone. Known gap: for a manual-mode
195
- # pagerhref table, this ivar is stale by the time
196
- # ink_pagerhref_tables performs the deferred real ink pass later,
197
- # so cell-level bars do not reach that combination.
276
+ # this matches by row index alone. For a manual-mode pagerhref
277
+ # table, this value is stashed onto @pagerhref_tables in
278
+ # allocate_pagerhref_table_extent below and restored by
279
+ # ink_pagerhref_tables right before that table's real, deferred
280
+ # render: this ivar itself would otherwise already be nil (or
281
+ # worse, another table's stale value) by the time that later pass
282
+ # runs, since every ordinary convert_table call clears it in its
283
+ # own ensure block below, long before ink_pagerhref_tables ever
284
+ # starts.
198
285
  @rhrev_table_cell_bar_rows = marked_table_cell_bar_rows(node) if @change_bar_attr && !scratch?
199
286
 
200
287
  if !has_id && !has_rhrev && !has_pagerhref
@@ -708,7 +795,7 @@ module Asciidoctor
708
795
  context: node.context
709
796
  }
710
797
  page_num = page_number
711
- @anchor_catalog[node.id][:dest] = { page: (rhrev_display_page page_num), y: cursor }
798
+ @anchor_catalog[node.id][:dest] = { page: (rhrev_display_page page_num), physical_page: page_num, y: cursor }
712
799
 
713
800
  revision_history.link_dest_to_page node.id, page_num, (@rhrev_body_start_page || 1), y: cursor
714
801
  end
@@ -770,10 +857,16 @@ module Asciidoctor
770
857
  extent.each_page { |first_page| start_new_page unless first_page }
771
858
  move_cursor_to extent.to.cursor
772
859
 
773
- # Store for later re-rendering with actual page numbers
860
+ # Store for later re-rendering with actual page numbers.
861
+ # bar_rows is @rhrev_table_cell_bar_rows as convert_table computed
862
+ # it for THIS node, a few lines before this method was called;
863
+ # stashed here since the ivar itself will not survive to
864
+ # ink_pagerhref_tables's own later pass, see that ivar's own
865
+ # comment in convert_table for why.
774
866
  @pagerhref_tables << {
775
867
  node: node,
776
- extent: extent
868
+ extent: extent,
869
+ bar_rows: @rhrev_table_cell_bar_rows
777
870
  }
778
871
  end
779
872
 
@@ -790,15 +883,25 @@ module Asciidoctor
790
883
  @pagerhref_tables.each do |table_info|
791
884
  extent = table_info[:extent]
792
885
  node = table_info[:node]
793
-
886
+
794
887
  # Go back to the allocated space
795
888
  go_to_page extent.from.page
796
889
  move_cursor_to extent.from.cursor
797
-
890
+
891
+ # Restore THIS table's own bar-row data for
892
+ # table_cell_change_bar_patch.rb to read during the real render
893
+ # below, the fix for the gap convert_table's own ivar comment
894
+ # describes: without this, the ivar is either nil or another
895
+ # table's stale value by this point, since every ordinary
896
+ # convert_table call already cleared it right after computing
897
+ # it, long before this loop ever runs.
898
+ @rhrev_table_cell_bar_rows = table_info[:bar_rows]
899
+
798
900
  # Re-render the table with flag set to prevent recursion
799
901
  @rendering_deferred_table = true
800
902
  super_convert_table node
801
903
  @rendering_deferred_table = false
904
+ @rhrev_table_cell_bar_rows = nil
802
905
  end
803
906
  end
804
907
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: asciidoctor-rhrev
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.0
4
+ version: 1.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - 白一百 baiyibai