leptris 1.9.174.10 → 1.9.178.0

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: f0e347192431e6ed3ff15bed0fca55fb103ba7307a33d889014e72c3ece0dba8
4
- data.tar.gz: f7edb28afa62063bbc1f0ab2cfcc349619a8944249f69f41b40e054e016b5b45
3
+ metadata.gz: 6ba4c2ede4f3a1c625693e1daca604ba31bdaf23d830a9d9a544c5b7aa20e53a
4
+ data.tar.gz: 695077502147180c80396c2bfa2e153f91819efc73148f1cf6d815632d241af6
5
5
  SHA512:
6
- metadata.gz: 660309e07c7ce84a4a68bdca9c46a1970f0af6a1bd2e316acca600de60cf54cbd445cd0814232593dd1752f59965d7df8ede74c14da977005b48cbec4ec276fd
7
- data.tar.gz: ffe8c0e4f6fc98f4bda50187b3c740e278aae6c82ec384f1ac6843673276b916910a1ab72a4c740a69e0006992418c83eb92280a619b18fac69c8568f5b7639e
6
+ metadata.gz: e4a68c3001aac1ddabc0e767cae7adb968093d20b0795cc520cd7f84d1b968d67d9b5dcffa7bf443a788ce92cfc9ec65315ff047f9dff820c712b35534b46f4c
7
+ data.tar.gz: 941f104c501e25036fcfb7dfb391afff39424f04694492ca957b79c019c7f11710717d1dda6426ca53f1869cfbad68ced97515de82fc0504e9277c17ed567a19
data/CHANGELOG.md CHANGED
@@ -5,6 +5,59 @@ 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.178.0] - 2026-09-16
9
+
10
+ ### Changed — libleptris 1.9.177 → 1.9.178 (lockstep)
11
+
12
+ - **#1113**: descriptor plan walk — collection wrappers now carry
13
+ the producing row's wire_name/type_tag (spec-pinned).
14
+ - **#1115 / #1118**: descriptor plan surfaces — ChildPlan gains
15
+ rule-level `ns_form` (+ `ns_uri`) for mixed-qualification
16
+ schemas (additive to the frozen v1 ABI; the binding accepts
17
+ `:ns` on child rows and the trailing struct fields are
18
+ populated by `pack_plans`), and every value kind carries the
19
+ source node's byte offset (the accessor's contract widened;
20
+ readers respond with the engine's position).
21
+ - **#1117**: C14N 1.1 ground truth — whitespace-only PI data and
22
+ document-level separators (lutaml-model parity corpus).
23
+ - **#1111 / #659 / #1107**: xpath user_data, HTML corpus slices
24
+ (NUL/foreign-rules + frameset-ok + frameset-conversion +
25
+ scanner quote-parity), and CLI specs in out-of-tree builds.
26
+
27
+ ### Added
28
+
29
+ - The trailing `ns_form` + `pad0` + `ns_uri` fields on
30
+ `Leptris::XML::FFI::ChildPlan` (the lockstep extension).
31
+
32
+ ## [1.9.177.0] - 2026-09-16
33
+
34
+ ### Changed — libleptris 1.9.174 → 1.9.177 (lockstep)
35
+
36
+ - **Node-surface parity (upstream #1094, #212 — the big one)**:
37
+ entity references (`&name;` stays a first-class
38
+ `EntityReference` node under the new
39
+ `ParseOptions.keep_entity_refs` flag — text splits around them,
40
+ character references still expand, serialization is verbatim;
41
+ `Document#create_entity_reference`), the XML declaration
42
+ (`xml_version`/`xml_encoding`/`xml_standalone` readers and
43
+ writers — `#version` stays the mutation counter), programmatic
44
+ DOCTYPE (`Document#set_doctype` with PUBLIC/SYSTEM ids,
45
+ serializing in document position), and document-PI parity
46
+ (`add_pi` returns the PI node with identity and epilog
47
+ anchoring; `Document#remove_child` removes PIs/comments). The
48
+ ext's kind dispatch knows the new node kind.
49
+ - **C14N: redundant namespace redeclarations omitted** (upstream
50
+ #1096) — spec-pinned.
51
+ - **Document lifecycle** (upstream #1093): pool destroy parks the
52
+ arenas — the fresh-doc build row's teardown share should drop;
53
+ clean-host battery pending.
54
+ - XSLT/XPath/HTML perf + conformance run (1.9.175-177).
55
+
56
+ ### Added
57
+
58
+ - `Leptris::XML::EntityReference`, the ten new FFI faces, the
59
+ `KEEP_ENTITY_REFS` parse flag.
60
+
8
61
  ## [1.9.174.10] - 2026-09-16
9
62
 
10
63
  ### Changed
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.174"
11
+ LIBLEPTRIS_VERSION = "1.9.178"
12
12
  # Vendored alongside libleptris for fn:normalize-unicode (TODO
13
13
  # .restructure/20): built per platform with a RELOCATABLE @rpath
14
14
  # install name, loaded by ffi.rb before libleptris so the
@@ -1212,7 +1212,8 @@ static VALUE nn_address(VALUE self)
1212
1212
  * Init; the per-node Ruby frames (wrap/construct/memo/alive)
1213
1213
  * disappear. */
1214
1214
  static VALUE c_b_element = Qundef, c_b_text, c_b_comment, c_b_cdata,
1215
- c_b_pi, c_b_node, c_b_result_text, c_b_result_attr,
1215
+ c_b_pi, c_b_entity_ref, c_b_node, c_b_result_text,
1216
+ c_b_result_attr,
1216
1217
  c_b_attr, c_ffi_pointer, c_b_document, c_b_freed;
1217
1218
  static VALUE c_iteration_scope;
1218
1219
  static ID id_ptr_new;
@@ -1229,6 +1230,7 @@ static void resolve_binding_classes(void)
1229
1230
  c_b_comment = rb_path2class("Leptris::XML::Comment");
1230
1231
  c_b_cdata = rb_path2class("Leptris::XML::CDATA");
1231
1232
  c_b_pi = rb_path2class("Leptris::XML::ProcessingInstruction");
1233
+ c_b_entity_ref = rb_path2class("Leptris::XML::EntityReference");
1232
1234
  c_b_node = rb_path2class("Leptris::XML::Node");
1233
1235
  c_b_result_text = rb_path2class("Leptris::XML::ResultText");
1234
1236
  c_b_result_attr = rb_path2class("Leptris::XML::ResultAttr");
@@ -1244,6 +1246,7 @@ static void resolve_binding_classes(void)
1244
1246
  rb_gc_register_mark_object(c_b_comment);
1245
1247
  rb_gc_register_mark_object(c_b_cdata);
1246
1248
  rb_gc_register_mark_object(c_b_pi);
1249
+ rb_gc_register_mark_object(c_b_entity_ref);
1247
1250
  rb_gc_register_mark_object(c_b_node);
1248
1251
  rb_gc_register_mark_object(c_b_result_text);
1249
1252
  rb_gc_register_mark_object(c_b_result_attr);
@@ -1263,6 +1266,7 @@ static VALUE binding_klass_for(int kind)
1263
1266
  case 2: return c_b_comment;
1264
1267
  case 3: return c_b_cdata;
1265
1268
  case 4: return c_b_pi;
1269
+ case 10: return c_b_entity_ref; /* #212 / upstream #1094 */
1266
1270
  default: return c_b_node;
1267
1271
  }
1268
1272
  }
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Leptris
4
- VERSION = "1.9.174.10"
4
+ VERSION = "1.9.178.0"
5
5
  end
@@ -150,6 +150,18 @@ class Leptris::XML::Descriptor
150
150
  cp[:kind] = kind_code(row[:kind] || :scalar)
151
151
  cp[:type_tag] = row[:type_tag] || 0
152
152
  cp[:child_plan_index] = row[:child_plan_index] || -1
153
+ # Rule-level ns form (libleptris 1.9.178, #1115): siblings
154
+ # under one parent can require different URIs when set;
155
+ # defaults to NONE for backward compatibility.
156
+ cp[:ns_form] =
157
+ case row[:ns]
158
+ when :any then Leptris::XML::FFI::PLAN_NS_ANY
159
+ when Hash then Leptris::XML::FFI::PLAN_NS_EXACT
160
+ else Leptris::XML::FFI::PLAN_NS_NONE
161
+ end
162
+ cp[:ns_uri] =
163
+ row[:ns].is_a?(Hash) ?
164
+ anchor_string(anchors, row[:ns].fetch(:exact)) : nil
153
165
  end
154
166
  ep[:child_count] = children.size
155
167
  ep[:child_plans] = child_memory
@@ -505,15 +505,82 @@ class Leptris::XML::Document
505
505
  Leptris::XML::Node.wrap(ptr, self)
506
506
  end
507
507
 
508
- # Append a document-level processing instruction. Returns self.
508
+ # Append a document-level processing instruction. Returns the PI
509
+ # node (epilog anchor — after the root; identity via
510
+ # leptris_document_append_pi, libleptris 1.9.176 / #212).
509
511
  def add_pi(target, data = "")
510
- witness = Leptris::XML::FFI.leptris_document_add_pi(
512
+ witness = Leptris::XML::FFI.leptris_document_append_pi(
511
513
  c_ptr, target.to_s, data.to_s)
512
- raise Leptris::XML::Error, "leptris_document_add_pi failed" if witness.null?
514
+ raise Leptris::XML::Error, "leptris_document_append_pi failed" if witness.null?
515
+ @version += 1
516
+ Leptris::XML::Node.wrap(witness, self)
517
+ end
518
+
519
+ # Remove a document-level PI or comment from the document
520
+ # children chain (libleptris 1.9.176 / #212). The node stays
521
+ # document-owned. Raises when the node is not in the chain.
522
+ def remove_child(node)
523
+ Leptris::XML::FFI.check_status(
524
+ Leptris::XML::FFI.leptris_document_remove_child(c_ptr, node.c_ptr))
513
525
  @version += 1
514
526
  self
515
527
  end
516
528
 
529
+ # Create an &name; entity reference node (libleptris 1.9.176 /
530
+ # #212): serializes back verbatim once attached.
531
+ def create_entity_reference(name)
532
+ ptr = Leptris::XML::FFI.leptris_entity_ref_node_create(
533
+ c_ptr, name.to_s)
534
+ raise Leptris::XML::Error, "leptris_entity_ref_node_create failed" if ptr.null?
535
+ Leptris::XML::Node.wrap_fresh(ptr, self, Leptris::XML::FFI::NODE_ENTITY_REF)
536
+ end
537
+
538
+ # The XML declaration (libleptris 1.9.176 / #212). `#version`
539
+ # stays the mutation counter — the declaration reads are
540
+ # xml_-prefixed.
541
+ def xml_version
542
+ Leptris::XML::FFI.leptris_document_version(c_ptr)
543
+ end
544
+
545
+ def xml_standalone
546
+ v = Leptris::XML::FFI.leptris_document_standalone(c_ptr)
547
+ v < 0 ? nil : (v == 1)
548
+ end
549
+
550
+ def xml_encoding
551
+ Leptris::XML::FFI.leptris_document_encoding(c_ptr)
552
+ end
553
+
554
+ def xml_version=(value)
555
+ Leptris::XML::FFI.check_status(
556
+ Leptris::XML::FFI.leptris_document_set_version(c_ptr, value.to_s))
557
+ value
558
+ end
559
+
560
+ def xml_encoding=(value)
561
+ Leptris::XML::FFI.check_status(
562
+ Leptris::XML::FFI.leptris_document_set_encoding(c_ptr, value.to_s))
563
+ value
564
+ end
565
+
566
+ def xml_standalone=(value)
567
+ Leptris::XML::FFI.check_status(
568
+ Leptris::XML::FFI.leptris_document_set_standalone(c_ptr,
569
+ value.nil? ? -1 : (value ? 1 : 0)))
570
+ value
571
+ end
572
+
573
+ # Programmatic DOCTYPE (libleptris 1.9.176 / #212): create and
574
+ # set the document's DOCTYPE (root name + optional PUBLIC/SYSTEM
575
+ # ids); serializes in document position. Returns the DocType.
576
+ def set_doctype(name, public_id: nil, system_id: nil)
577
+ dt = Leptris::XML::FFI.leptris_document_set_doctype(
578
+ c_ptr, name.to_s, public_id, system_id)
579
+ raise Leptris::XML::Error, "leptris_document_set_doctype failed" if dt.null?
580
+ @version += 1
581
+ Leptris::XML::DocType.new(dt, self)
582
+ end
583
+
517
584
  # Append a document-level comment (epilog position, after the
518
585
  # root element) — the add_pi twin (libleptris 1.9.160, #1032;
519
586
  # parsed document-level comments round-tripped since 1.9.3/#578,
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ # An unexpanded &name; entity reference — a first-class node when
4
+ # parsing with ParseOptions.keep_entity_refs (libleptris 1.9.176,
5
+ # upstream #1094 / leptris-ruby#212), or created via
6
+ # Document#create_entity_reference. Serializes back verbatim as
7
+ # &name;; text runs around it split into their own Text siblings.
8
+ class Leptris::XML::EntityReference < Leptris::XML::Node
9
+ def name
10
+ Leptris::XML::FFI.leptris_entity_ref_node_name(c_ptr)
11
+ end
12
+ alias_method :node_name, :name
13
+ end
@@ -209,7 +209,12 @@ module Leptris
209
209
  layout :wire_name, :pointer,
210
210
  :kind, :uint8,
211
211
  :type_tag, :uint8,
212
- :child_plan_index, :int32
212
+ :child_plan_index, :int32,
213
+ # libleptris 1.9.178 (#1114/#1115): rule-level ns
214
+ # forms on ChildPlan (additive to the frozen v1 ABI).
215
+ :ns_form, :uint8,
216
+ :pad0, :uint8,
217
+ :ns_uri, :pointer
213
218
  end
214
219
  class ElementPlan < ::FFI::Struct
215
220
  layout :element_name, :pointer,
@@ -337,6 +342,29 @@ attach_function :leptris_parse_string,
337
342
  # node_first_child without the intermediate handle).
338
343
  attach_function :leptris_document_first_child,
339
344
  [:leptris_document], :leptris_node_ref
345
+ # Node-surface parity (libleptris 1.9.176, upstream #1094,
346
+ # leptris-ruby#212): entity references, the XML declaration,
347
+ # programmatic DOCTYPE, and document-PI identity/removal.
348
+ attach_function :leptris_entity_ref_node_create,
349
+ [:leptris_document, :string], :leptris_node_ref
350
+ attach_function :leptris_entity_ref_node_name,
351
+ [:leptris_node_ref], :string
352
+ attach_function :leptris_document_version,
353
+ [:leptris_document], :string
354
+ attach_function :leptris_document_standalone,
355
+ [:leptris_document], :int
356
+ attach_function :leptris_document_set_version,
357
+ [:leptris_document, :string], :leptris_status
358
+ attach_function :leptris_document_set_encoding,
359
+ [:leptris_document, :string], :leptris_status
360
+ attach_function :leptris_document_set_standalone,
361
+ [:leptris_document, :int], :leptris_status
362
+ attach_function :leptris_document_set_doctype,
363
+ [:leptris_document, :string, :string, :string], :leptris_doctype
364
+ attach_function :leptris_document_append_pi,
365
+ [:leptris_document, :string, :string], :leptris_node_ref
366
+ attach_function :leptris_document_remove_child,
367
+ [:leptris_document, :leptris_node_ref], :leptris_status
340
368
  # Wrap-free subtree visitation (1.9.20, upstream #645a):
341
369
  # enter/leave pairs for elements, depth from the walk's root,
342
370
  # one C call — no NodeSet/Array churn per level. The document
@@ -1070,11 +1098,15 @@ attach_function :leptris_parse_string,
1070
1098
  NODE_COMMENT = 2
1071
1099
  NODE_CDATA = 3
1072
1100
  NODE_PI = 4
1101
+ NODE_ENTITY_REF = 10
1073
1102
  # Internal XPath-synthetic text node (leptris/types.h): the
1074
1103
  # carrier for sequence/map/array items in result nodesets —
1075
1104
  # readable only through the result handle, so the binding
1076
1105
  # captures the value at materialization (ResultText).
1077
1106
  NODE_SYNTHETIC_TEXT = 8
1107
+ # #1094: &name; references stay unexpanded first-class nodes
1108
+ # when this flag parses (character references still expand).
1109
+ LEPTRIS_PARSE_KEEP_ENTITY_REFS = 4
1078
1110
  NODE_DOCTYPE = 5
1079
1111
  NODE_ATTRIBUTE = 6
1080
1112
 
@@ -132,6 +132,8 @@ class Leptris::XML::Node
132
132
  Leptris::XML::CDATA.new(c_ptr, document, parent: parent, node_type: node_type)
133
133
  when Leptris::XML::FFI::NODE_PI
134
134
  Leptris::XML::ProcessingInstruction.new(c_ptr, document, parent: parent, node_type: node_type)
135
+ when Leptris::XML::FFI::NODE_ENTITY_REF
136
+ Leptris::XML::EntityReference.new(c_ptr, document, parent: parent, node_type: node_type)
135
137
  else
136
138
  new(c_ptr, document, parent: parent, node_type: node_type)
137
139
  end
@@ -17,6 +17,13 @@ class Leptris::XML::ParseOptions
17
17
  # defaulted attributes.
18
18
  DTDATTR = Leptris::XML::FFI::LEPTRIS_PARSE_DTDATTR
19
19
 
20
+ # Keep &name; entity references unexpanded as first-class
21
+ # EntityReference nodes (libleptris 1.9.176, upstream #1094 /
22
+ # leptris-ruby#212): text runs split around them, character
23
+ # references still expand, and the references serialize back
24
+ # verbatim.
25
+ KEEP_ENTITY_REFS = Leptris::XML::FFI::LEPTRIS_PARSE_KEEP_ENTITY_REFS
26
+
20
27
  attr_reader :flags
21
28
 
22
29
  # Recover (libleptris 1.9.0, #547): a parse failure returns an
@@ -32,6 +39,10 @@ class Leptris::XML::ParseOptions
32
39
  @recover = recover ? true : false
33
40
  end
34
41
 
42
+ def self.keep_entity_refs
43
+ new(KEEP_ENTITY_REFS)
44
+ end
45
+
35
46
  def self.noblanks
36
47
  new(NOBLANKS)
37
48
  end
@@ -52,6 +63,10 @@ class Leptris::XML::ParseOptions
52
63
  @flags & DTDATTR != 0
53
64
  end
54
65
 
66
+ def keep_entity_refs?
67
+ @flags & KEEP_ENTITY_REFS != 0
68
+ end
69
+
55
70
  def dtdattr=(value)
56
71
  if value then @flags |= DTDATTR else @flags &= ~DTDATTR end
57
72
  end
data/lib/leptris/xml.rb CHANGED
@@ -9,6 +9,7 @@ module Leptris
9
9
  autoload :Comment, "leptris/xml/comment"
10
10
  autoload :CDATA, "leptris/xml/cdata"
11
11
  autoload :ProcessingInstruction, "leptris/xml/processing_instruction"
12
+ autoload :EntityReference, "leptris/xml/entity_reference"
12
13
  autoload :Attr, "leptris/xml/attr"
13
14
  autoload :Namespace, "leptris/xml/namespace"
14
15
  autoload :Document, "leptris/xml/document"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: leptris
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.174.10
4
+ version: 1.9.178.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
@@ -164,6 +164,7 @@ files:
164
164
  - lib/leptris/xml/document.rb
165
165
  - lib/leptris/xml/document_fragment.rb
166
166
  - lib/leptris/xml/element.rb
167
+ - lib/leptris/xml/entity_reference.rb
167
168
  - lib/leptris/xml/evaluation_context.rb
168
169
  - lib/leptris/xml/ffi.rb
169
170
  - lib/leptris/xml/iteration_scope.rb