leptris 1.9.43-aarch64-linux → 1.9.45-aarch64-linux

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: 3585b1f38f17d8a06b370034756a6eeccc78605843c1133f36bed7ff07d92f6f
4
- data.tar.gz: 1170564a2c9bd8f49d6828491dae7bd9f803b477cab13bf665e2bc46708e4fa2
3
+ metadata.gz: bb8f4818b7cf8e077979539e52e40db4bec3463f19366502d810ad326f3e587b
4
+ data.tar.gz: 06d30447b248bcc443c89897d1b142c3139f92211ee1983eb847f63fb178268a
5
5
  SHA512:
6
- metadata.gz: 8d1a742167a13771fe76e8c46f3b36b9eb7bc9c02e639f548888e19de588f57e00a727ad4fb645daab0dadba444ec22144e4829ff496a82707efb0c76e30e19e
7
- data.tar.gz: ac245cc32da208680784662259db2a625b5f5a9d2ed252b1884fe5f20c31d8e861c6b68bb5d247c9ad7052ed28dd2b10f77bbae354f3007f4114d61d90eaa618
6
+ metadata.gz: 32c7eef741a89b3fe823b39abe19e6046354a2a63f2e691c6deb4077629330ab84b7e9a449878c099181ffff785283ad5c71843ce5714667109855a8f67bb528
7
+ data.tar.gz: 361c6ae7a3866cd168924d6898ddadc1e8ec207fcc3a542c0f9b462eff3f96ec4d5e6a4abfc22a2995d6f88d4d95625a276d2c11c5ed5ba0dc1e69bdec7efb54
data/CHANGELOG.md CHANGED
@@ -5,6 +5,64 @@ All notable changes to Leptris will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.9.45] - 2026-08-31
9
+
10
+ ### Added
11
+
12
+ - **Element-face indent unit (leptris-ruby#109 residual 2)**:
13
+ `Element#to_xml(indent: 2, indent_text: "\t")` — the unit with
14
+ Nokogiri's element semantics, byte-identical to Nokogiri's
15
+ `Element#to_xml` on the same input. No element-level
16
+ ext-serialize entry exists yet, so the path copies the element
17
+ C-side into a fresh document (one pool allocation) and
18
+ serializes through the document ext entry without a declaration.
19
+ `indent_text: true` raises ArgumentError on elements — the
20
+ display form stays document-level. The element default is
21
+ unchanged.
22
+ - **libleptris 1.9.23 lockstep**: XPath 2.0+ expression core
23
+ upstream (if/then/else, for-return, `to` ranges); audit 255/255,
24
+ no new C surface.
25
+
26
+ ### Known issue
27
+
28
+ - **#109 residual 1 (text-bearing leaves lose the unit) is
29
+ engine-side and filed as leptris/leptris#658**: the fused-leaf
30
+ fast path (serialize.c ~1193) computes `indent * indent_spaces`
31
+ directly, bypassing `buffer_append_indent`'s unit branch — every
32
+ mixed-content leaf's line indent falls back to spaces while
33
+ element-only subtrees get the unit. Two-line C fix (route the
34
+ fused lead through the unit); the binding adopts it in the next
35
+ lockstep.
36
+
37
+ ## [1.9.44] - 2026-08-31
38
+
39
+ ### Added
40
+
41
+ - **libleptris 1.9.19–1.9.22 lockstep** (audit 255/255, three new
42
+ symbols): the #653 hold is lifted — the reported parse
43
+ "regression" was an ill-formed fixture (stray `</y>`) plus a
44
+ stale-build bisect artifact; forced-clean rebuilds show 1.9.18
45
+ and 1.9.21+ identical on every well-formed shape (verified and
46
+ withdrawn on the issue).
47
+ - **`Node#visit`** (upstream #645a, `leptris_node_visit`): one C
48
+ call over the subtree — elements yield `(node, true/false,
49
+ depth)` enter/leave pairs, other kinds once, depth from the
50
+ receiver; the document node walks the document chain. No
51
+ NodeSet, pointer array, or children memo per level — the leanest
52
+ full-subtree iteration the binding offers (#645a's walk lever;
53
+ consumers can now beat the children-recursion allocation floor).
54
+ - **Indent unit with Nokogiri semantics (leptris-ruby#109,
55
+ upstream #633)**: `to_xml(indent: 2, indent_text: "\t")` — the
56
+ unit string replaces the default spaces, repeated `indent`
57
+ times per depth level, standard layout otherwise
58
+ (byte-identical to Nokogiri's output modulo their trailing
59
+ newline, which moxml normalizes). `indent_text: true` keeps the
60
+ display form; `false` the default. Wired through the sized
61
+ ext-serialize entry (PR #107's substance — the audit requires it
62
+ attached with the lockstep, so it rides here; the engine emits
63
+ one unit copy per level and the binding multiplies unit x indent
64
+ to reach Nokogiri's repeat count).
65
+
8
66
  ## [1.9.43] - 2026-08-31
9
67
 
10
68
  ### Fixed
data/Rakefile CHANGED
@@ -8,7 +8,7 @@ RSpec::Core::RakeTask.new(:spec)
8
8
  # Pin for `rake compile` and the platform-gem builds. Keep in lockstep
9
9
  # with .github/workflows/build.yml (which calls `rake compile`) and the
10
10
  # CHANGELOG when libleptris releases.
11
- LIBLEPTRIS_VERSION = "1.9.18"
11
+ LIBLEPTRIS_VERSION = "1.9.23"
12
12
 
13
13
  CMAKE_FLAGS = %w[
14
14
  -DCMAKE_BUILD_TYPE=Release
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Leptris
4
- VERSION = "1.9.43"
4
+ VERSION = "1.9.45"
5
5
  end
@@ -266,13 +266,21 @@ class Leptris::XML::Document
266
266
  end
267
267
  alias_method :internal_subset, :doctype
268
268
 
269
- # indent_text: true selects the display form (libleptris 1.9.9,
270
- # #129): text and mixed content indent too — the output is
271
- # display-oriented and not round-trip-guaranteed.
269
+ # indent_text selects the ext-serializer knob (libleptris 1.9.22):
270
+ # a STRING is the indent unit with Nokogiri's semantics — the unit
271
+ # replaces the default spaces, one copy per depth level, standard
272
+ # layout (requires indent > 0); true selects the display form
273
+ # (1.9.9 #129 — text and mixed content indent too; output is
274
+ # display-oriented and not round-trip-guaranteed).
272
275
  def to_xml(indent: 0, no_decl: false, encoding: nil, indent_text: false)
273
276
  raise Leptris::XML::UseAfterFreeError if @freed.state == :freed
274
277
  return "" if @c_ptr.nil?
275
- if indent_text
278
+ case indent_text
279
+ when String
280
+ return Leptris::XML::Serialization.to_xml_indent_unit(
281
+ @c_ptr, indent_text, indent: indent, no_decl: no_decl,
282
+ encoding: encoding)
283
+ when true
276
284
  return Leptris::XML::Serialization.to_xml_display(
277
285
  @c_ptr, indent: indent, no_decl: no_decl, encoding: encoding)
278
286
  end
@@ -358,7 +358,18 @@ class Leptris::XML::Element < Leptris::XML::Node
358
358
  end.join
359
359
  end
360
360
 
361
- def to_xml(indent: 0, no_decl: false, encoding: nil)
361
+ # indent_text: a STRING is the indent unit with Nokogiri's
362
+ # semantics (leptris-ruby#109; via a C-side copy into a fresh
363
+ # document — no element-level ext entry exists yet). true is NOT
364
+ # supported here: the display form is document-level.
365
+ def to_xml(indent: 0, no_decl: false, encoding: nil, indent_text: false)
366
+ if indent_text == true
367
+ raise ArgumentError,
368
+ "indent_text: true (display form) is document-level — " \
369
+ "pass the unit string for elements"
370
+ end
371
+ return Leptris::XML::Serialization.to_xml_element_unit(
372
+ self, indent_text, indent: indent) if indent_text.is_a?(String)
362
373
  Leptris::XML::Serialization.to_xml(
363
374
  Leptris::XML::FFI.method(:leptris_element_serialize_into), @c_ptr,
364
375
  indent: indent, no_decl: no_decl, encoding: encoding)
@@ -72,10 +72,13 @@ module Leptris
72
72
  :encoding, :pointer
73
73
  end
74
74
 
75
- # LeptrisSerializeExtOptions (1.9.9, #129): display-form
76
- # serialization knobs beyond the ABI-frozen options struct.
75
+ # LeptrisSerializeExtOptions (1.9.9 #129 display form; 1.9.22
76
+ # #633/#109 indent unit): knobs beyond the ABI-frozen options
77
+ # struct. MAY grow — always pass its size through the sized
78
+ # entry.
77
79
  class SerializeExtStruct < ::FFI::Struct
78
- layout :indent_text, :int
80
+ layout :indent_text, :int,
81
+ :indent_unit, :pointer
79
82
  end
80
83
 
81
84
  # Mirrors LeptrisParseOptions (libleptris >= 1.9.0 carries the
@@ -154,6 +157,12 @@ module Leptris
154
157
  # 1.9.7, upstream #580; the libxml2 model).
155
158
  attach_function :leptris_document_node,
156
159
  [:leptris_document], :leptris_node_ref
160
+ # Wrap-free subtree visitation (1.9.20, upstream #645a):
161
+ # enter/leave pairs for elements, depth from the walk's root,
162
+ # one C call — no NodeSet/Array churn per level. The document
163
+ # node walks the document child chain.
164
+ attach_function :leptris_node_visit,
165
+ [:leptris_node_ref, :pointer, :pointer], :void
157
166
  # Document-level PIs (v1.6.0): not tree nodes — enumerate via
158
167
  # these accessors only.
159
168
  attach_function :leptris_document_pi_count,
@@ -646,6 +655,11 @@ module Leptris
646
655
  # read_owned_string (the seam frees it).
647
656
  attach_function :leptris_document_serialize_ext,
648
657
  [:leptris_document, :pointer, :pointer], :pointer
658
+ # Sized variant (1.9.19, upstream #644 — leptris-ruby PR #107):
659
+ # passing our ext-struct size keeps the engine from reading
660
+ # past this binding's allocation (the MSVC segfault).
661
+ attach_function :leptris_document_serialize_ext_sized,
662
+ [:leptris_document, :pointer, :pointer, :size_t], :pointer
649
663
  attach_function :leptris_document_serialize_into,
650
664
  [:leptris_document, :pointer, :size_t, :pointer, :pointer], :size_t
651
665
  attach_function :leptris_document_get_dtd,
@@ -273,6 +273,31 @@ class Leptris::XML::Node
273
273
  end
274
274
  alias_method :remove, :unlink
275
275
 
276
+ # Visits the subtree with ONE C call (leptris_node_visit,
277
+ # libleptris 1.9.20 — upstream #645a): elements yield twice —
278
+ # (node, true, depth) before their children, (node, false, depth)
279
+ # after the subtree completes — every other kind once with
280
+ # entering=true; depth counts element levels from the receiver.
281
+ # No NodeSet, pointer array, or children memo per level: the
282
+ # leanest full-subtree iteration the binding offers (a document
283
+ # receiver walks the document child chain). The walk is read-only
284
+ # — mutate only between visits.
285
+ #
286
+ # root.visit { |node, entering, depth| ... }
287
+ def visit(&block)
288
+ return enum_for(:visit) unless block
289
+ ensure_alive!
290
+ document = @document
291
+ visitor = ::FFI::Function.new(
292
+ :void, [:pointer, :pointer, :int, :int], blocking: true) do |_, node_ptr, entering, depth|
293
+ block.call(
294
+ Leptris::XML::Node.wrap(node_ptr, document),
295
+ entering == 1, depth)
296
+ end
297
+ Leptris::XML::FFI.leptris_node_visit(@c_ptr, visitor, nil)
298
+ self
299
+ end
300
+
276
301
  # Walks the subtree in post-order DFS (matches Nokogiri's
277
302
  # semantics): the receiver, its descendants, nothing else.
278
303
  #
@@ -47,8 +47,28 @@ module Leptris::XML::Serialization
47
47
  def self.to_xml_display(c_ptr, indent: 0, no_decl: false, encoding: nil)
48
48
  opts, encoding_anchor = build_options(
49
49
  indent: indent, no_decl: no_decl, encoding: encoding)
50
- str_ptr = Leptris::XML::FFI.leptris_document_serialize_ext(
51
- c_ptr, opts.pointer, INDENT_TEXT_EXT.pointer)
50
+ str_ptr = Leptris::XML::FFI.leptris_document_serialize_ext_sized(
51
+ c_ptr, opts.pointer, INDENT_TEXT_EXT.pointer, INDENT_TEXT_EXT.size)
52
+ Leptris::XML::FFI.read_owned_string(str_ptr)
53
+ end
54
+
55
+ # Indent-unit serialization (libleptris 1.9.22, #633 —
56
+ # leptris-ruby#109): Nokogiri's indent_text semantics — the unit
57
+ # string replaces the default spaces, repeated `indent` times per
58
+ # depth level, standard layout otherwise. The engine emits ONE
59
+ # copy of the unit string per level (options->indent is ignored
60
+ # when a unit is set), so the binding multiplies unit x indent to
61
+ # reach Nokogiri's repeat count.
62
+ def self.to_xml_indent_unit(c_ptr, unit, indent: 0, no_decl: false,
63
+ encoding: nil)
64
+ opts, encoding_anchor = build_options(
65
+ indent: indent, no_decl: no_decl, encoding: encoding)
66
+ ext = Leptris::XML::FFI::SerializeExtStruct.new
67
+ unit_anchor = ::FFI::MemoryPointer.from_string(
68
+ indent.positive? ? unit.to_s * indent : unit.to_s)
69
+ ext[:indent_unit] = unit_anchor
70
+ str_ptr = Leptris::XML::FFI.leptris_document_serialize_ext_sized(
71
+ c_ptr, opts.pointer, ext.pointer, ext.size)
52
72
  Leptris::XML::FFI.read_owned_string(str_ptr)
53
73
  end
54
74
 
@@ -75,6 +95,28 @@ module Leptris::XML::Serialization
75
95
  string.gsub(ESCAPE_TEXT_RE, ESCAPE_TEXT)
76
96
  end
77
97
 
98
+ # Element-face indent unit (leptris-ruby#109 residual 2): no
99
+ # element-level ext-serialize entry exists yet, so the unit path
100
+ # copies the element into a fresh document (C-side copy, one
101
+ # pool allocation), serializes that document without a
102
+ # declaration, and returns the subtree — identical output to the
103
+ # element serializer for the standard layout, with the unit.
104
+ def self.to_xml_element_unit(element, unit, indent: 0)
105
+ document = Leptris::XML::Document.create
106
+ begin
107
+ copy_ptr = Leptris::XML::FFI.leptris_element_copy(
108
+ element.c_ptr, document.c_ptr)
109
+ if copy_ptr.null?
110
+ raise Leptris::XML::Error, "leptris_element_copy failed"
111
+ end
112
+ document.root = Leptris::XML::Node.wrap(copy_ptr, document)
113
+ to_xml_indent_unit(document.c_ptr, unit,
114
+ indent: indent, no_decl: true)
115
+ ensure
116
+ document.free
117
+ end
118
+ end
119
+
78
120
  # Builds a SerializeOptions struct. Returns [opts, encoding_anchor];
79
121
  # the anchor must stay referenced while opts is in an FFI call.
80
122
  def self.build_options(indent: 0, no_decl: false, encoding: nil)
data/lib/libleptris.so CHANGED
Binary file
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: leptris
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.43
4
+ version: 1.9.45
5
5
  platform: aarch64-linux
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-08-30 00:00:00.000000000 Z
11
+ date: 2026-08-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi