leptris 1.9.193.3 → 1.9.197.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: 49ef91f7ec6c9a0642a8a7663226bb98d5a1922adbb026354b9af783ab5f2821
4
- data.tar.gz: 114f27006c38eb0949f7754b39b4428da84f6c9e5dcc67886d147ac9ac04ebfb
3
+ metadata.gz: 1fe0d9ad19af1ea0312a5a04daf2f3fededf7c630490ebcf337bd231c5e86f76
4
+ data.tar.gz: 69ba7d9ba6b929220068d310d98e06e42480764828f023ed981b4f6625adb193
5
5
  SHA512:
6
- metadata.gz: 7ca23bf845f255e976988659785f79292fd131502b4ae04c0baaf95f813c06c22d1d57b76412ec52040e4a855cfffc3e122b82f3165a8244ae9c59e8cd1e527a
7
- data.tar.gz: 914210f2e059b27479bad365a3f8beef6121109638dced1db909ad49869db27cceb45426630024301d1542841540c6b63db1fe703baaee56c0c7f79d78bdf7f5
6
+ metadata.gz: 4eb77398a80e630172e14fe9d4ae3cbed2dc0416d3b6f6ed5d2343b394eb24477e9b824d8cfa5d18cdcc61cc2788d812de9b9ea533bf15a34f7478c51882aee7
7
+ data.tar.gz: 2a10f88e73dceb1ae6b48bb3aeacd8f5f696d54cbb5906acece5d2dac19c81925742b575f42a51a5a5eab750981fa4e9691570359cfa7dafd97c617b5adefff8
data/CHANGELOG.md CHANGED
@@ -5,6 +5,123 @@ 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.197.0] - 2026-09-18
9
+
10
+ ### Changed — libleptris 1.9.194 → 1.9.197 (lockstep)
11
+
12
+ - **HTML: the html5lib corpus is at ZERO reds upstream** — #659's
13
+ closing state reached in v1.9.196 (tricky01:8 table scope +
14
+ marker prune was the last), with table-foreign-scope bursts,
15
+ after-body/after-after-body comment routing, plaintext
16
+ raw-to-EOF, nested-table-in-cell, and the document-epilog
17
+ comment rule. v1.9.197 adds a memchr text-run skip in the
18
+ tokenizer main loop. The binding's WHATWG battery grows two
19
+ pins from the zero-reds set: comments past `</html>` become
20
+ document-level epilog nodes, and a nested table inside a cell
21
+ nests instead of foster-parenting.
22
+ - **HTML: WHATWG mode is feature-complete upstream (#659 closed)** —
23
+ the binding now pins the shipped behavior classes in
24
+ `spec/xml/html_whatwg_full_spec.rb`: active-formatting
25
+ reconstruction across paragraphs, the adoption agency (misnested
26
+ formatting reopens inside `<p>`), the Noah's Ark three-element
27
+ cap, template content outside the live table machinery,
28
+ RCDATA/rawtext (title/textarea/iframe/noembed/xmp/style),
29
+ in-table stray-text foster parenting, frameset-mode content
30
+ drop, foreign integration points, after-body restore, and the
31
+ script-data escape states. The `:html4` default lane is
32
+ unchanged.
33
+ - **RNG: required attributes behind `<ref>` are enforced**
34
+ (#1164). Spec-pinned.
35
+ - **RNG: stray character data under element-only content is
36
+ rejected (#1153)** — the anyName-wildcard laxness we filed from
37
+ the v188 pins. Spec-pinned at the verdict level; follow-up filed
38
+ upstream: the rejection does not yet record an error row
39
+ (report/legacy channels empty for this case).
40
+ - Engine 1.9.195 also fixes public-API symbols kept through
41
+ ThinLTO (#1154) — the macOS dylib now exports all 323 declared
42
+ symbols.
43
+
44
+ ### Added
45
+
46
+ - **gem-smoke workflow** (the teptris-ruby template, 9 legs): after
47
+ every release, install the PUBLISHED gem from rubygems on
48
+ ubuntu/arm64-ubuntu/macos-intel/macos-arm and Windows ucrt
49
+ (x64 3.3/3.4/4.0, arm64 3.4/4.0), then round-trip
50
+ parse/xpath/mutate/serialize/RelaxNG against the installed copy —
51
+ with an explicit guard that the NODE_* constants ship in the
52
+ Ruby layer (the sibling project's #318 class: a packaging skew
53
+ surfaced as NameErrors in host apps). `scripts/gem_smoke.rb`.
54
+ - **Ruby-source parity gate in the publish job**: every platform
55
+ variant's `lib/**/*.rb` must be byte-identical before anything
56
+ is pushed — a skew (one cell packaging from a different source
57
+ state) aborts the release.
58
+
59
+ ### Changed
60
+
61
+ - The armv7 platform legs (`arm-linux`, `arm-linux-musl`) are
62
+ **experimental** (continue-on-error) until upstream ports the
63
+ 64-bit-pinned layouts: the engine's round-19 ABI asserts
64
+ correctly abort on 32-bit (`sizeof(leptris_element) == 72`
65
+ requires 8-byte pointers) — filed as leptris/leptris#1174 with
66
+ both logs. aarch64-linux (qemu bookworm, glibc floor 2.36)
67
+ stays strict. The 1.9.194.0 release run correctly refused to
68
+ publish on their failure; .1/.2 were the parallel hot-read
69
+ aliases.
70
+
71
+ ## [1.9.194.0] - 2026-09-18
72
+
73
+ ### Changed — libleptris 1.9.193 → 1.9.194 (lockstep)
74
+
75
+ - **RELAX NG: define bodies are sibling lists** — a `<ref>` to a
76
+ multi-member define matches the WHOLE body (an implicit group);
77
+ previously only the body's head pattern was matched, so the
78
+ metanorma `DocumentBody` shape (optional preface + required
79
+ sections) never matched its tail. Spec-pinned.
80
+ - **RELAX NG: choice starvation fix** — inside a CHOICE,
81
+ alternatives that consume a child win over the zero-width
82
+ `<text/>`/empty branch (inline TextElement models stopped
83
+ failing). Spec-pinned.
84
+ - **RELAX NG diagnostics: Jing `PatternMatcher` semantics** — refs
85
+ splice body members into the walk, the invalid-attribute-value
86
+ message enumerates every reachable VALUE leaf through refs,
87
+ `incomplete` reports the leftmost required position, and missing
88
+ required attributes collapse to one message. The metanorma
89
+ standoc corpus is now byte-identical to Jing. Spec-pinned (the
90
+ attribution survives ref splicing).
91
+ - Engine 1.9.193.x fixes ride along (no public-symbol changes:
92
+ audit 323/323). The 1.9.193.2/.3 binding patches shipped without
93
+ changelog entries.
94
+
95
+ ### Added
96
+
97
+ - **32-bit ARM platform gems: `arm-linux` and `arm-linux-musl`** —
98
+ no GitHub-hosted armv7 runner exists, so the release builds them
99
+ under qemu binfmt emulation (ruby:3.3-bookworm / ruby:3.3-alpine,
100
+ `--platform linux/arm/v7`); `LEPTRIS_PGO=0` on the emulated legs
101
+ (the two-stage trainer under qemu costs 10-20x for the same
102
+ library). The ruby variant vendors both, and the ffi vendor map
103
+ resolves `armv7l-linux`-style platforms — zero-setup
104
+ TruffleRuby/JRuby on armv7. Completes platform parity with the
105
+ sibling project's table.
106
+
107
+ ### Fixed
108
+
109
+ - **macOS floor of the vendored dylibs (was: macOS 26 only)**: the
110
+ published darwin gems' `libleptris.dylib` carried
111
+ `LC_BUILD_VERSION minos 26.0` — the CI runner's SDK default —
112
+ and refused to load on any older macOS. The compile task now
113
+ sets `MACOSX_DEPLOYMENT_TARGET=11.0` for cmake (a plain
114
+ `-DCMAKE_OSX_DEPLOYMENT_TARGET` lands UNINITIALIZED and is
115
+ ignored); verified `minos 11.0` locally. The extconf.rb pin had
116
+ only ever covered the native bundle.
117
+ - **glibc floor of the linux gems (was: glibc ≥ 2.38)**: the
118
+ x86_64 gem was built on a 24.04 runner and leaked GLIBC_2.38
119
+ symbol requirements — Debian 12 / Ubuntu 22.04 hosts could not
120
+ load it (the aarch64 gem likewise via the 24.04-arm runner).
121
+ The x86_64 leg now builds natively on ubuntu-22.04 (floor
122
+ 2.35) and the aarch64 leg builds in a qemu linux/arm64
123
+ bookworm container (floor 2.36).
124
+
8
125
  ## [1.9.193.0] - 2026-09-17
9
126
 
10
127
  ### Changed — libleptris 1.9.192 -> 1.9.193 (lockstep)
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.193"
11
+ LIBLEPTRIS_VERSION = "1.9.197"
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
@@ -77,6 +77,14 @@ task :compile do
77
77
  fetch_tarball.call(
78
78
  "https://api.github.com/repos/leptris/leptris/tarball/v#{version}", build)
79
79
 
80
+ # NOTE: 32-bit ARM (armv7) is an ENGINE port task — the round-19
81
+ # ABI asserts pin layouts to 8-byte-pointer sizes and correctly
82
+ # abort the build on 32-bit. Filed upstream as leptris/leptris
83
+ # #1174; the release legs stay experimental (continue-on-error)
84
+ # and flip green automatically when the port ships. We patch
85
+ # nothing here — the emulated-leg smoke validates whatever the
86
+ # engine provides.
87
+
80
88
  # utf8proc: shared build only, @rpath install name, local prefix.
81
89
  u8_dir = File.expand_path("tmp/utf8proc-#{UTF8PROC_VERSION}", __dir__)
82
90
  u8_prefix = File.join(u8_dir, "prefix")
@@ -98,6 +106,16 @@ task :compile do
98
106
  # literal on Windows shells (they broke the MSVC build).
99
107
  # GCC-family only — MSVC's cl rejects the flag outright (D8021).
100
108
  cflags = Gem.win_platform? ? "" : "-Wno-error=incompatible-pointer-types"
109
+ # macOS floor for the VENDORED dylibs: without this, cmake uses
110
+ # the building machine's SDK default (a macos-latest runner
111
+ # shipped minos 26.0) and the dylib refuses to load on user
112
+ # machines older than the runner — the extconf.rb 11.0 pin only
113
+ # ever covered the native bundle. CMake initializes
114
+ # CMAKE_OSX_DEPLOYMENT_TARGET from this env var at first
115
+ # configure (a plain -D lands UNINITIALIZED and is ignored).
116
+ # 11.0 = the oldest macOS GitHub still hosts runners for;
117
+ # matches extconf.rb.
118
+ ENV["MACOSX_DEPLOYMENT_TARGET"] ||= "11.0" if RUBY_PLATFORM =~ /darwin/
101
119
  cmake_base =
102
120
  "#{CMAKE_FLAGS.join(' ').sub('-DLEPTRIS_ENABLE_UTF8PROC=OFF', '-DLEPTRIS_ENABLE_UTF8PROC=ON')} " \
103
121
  "-DCMAKE_PREFIX_PATH=#{u8_prefix} #{cflags.empty? ? '' : "-DCMAKE_C_FLAGS=#{cflags}"}"
@@ -328,6 +346,10 @@ platforms = [
328
346
  "aarch64-linux-musl",
329
347
  "x86_64-darwin",
330
348
  "arm64-darwin",
349
+ "arm-linux",
350
+ "arm-linux-musl",
351
+ "ppc64le-linux",
352
+ "s390x-linux-musl",
331
353
  ]
332
354
 
333
355
  platforms.each do |platform|
@@ -1880,6 +1880,67 @@ static VALUE nf_snapshot_subtree(VALUE self, VALUE document, VALUE addr)
1880
1880
  return out;
1881
1881
  }
1882
1882
 
1883
+ /* ---- Lean plan rows (lutaml/moxml#249 plan layer) ----------------
1884
+ * Elements only, one 4-tuple per element: [name, attrs_flat, text,
1885
+ * depth] — no Hash per row, no text/comment rows, attr and element
1886
+ * NAMES interned (shared frozen fstrings: names repeat across the
1887
+ * document, so repeat reads allocate zero). Pre-order, depth 0 at
1888
+ * the addressed node. */
1889
+ static void walk_rows_impl(void *node, int depth, VALUE out)
1890
+ {
1891
+ if (f_node_type(node) == WS_NODE_ELEMENT) {
1892
+ VALUE row = rb_ary_new_capa(4);
1893
+ VALUE attrs;
1894
+ const char *name = f_elem_name(node);
1895
+ const char *an;
1896
+ const char *av;
1897
+ void *a;
1898
+ void *c;
1899
+
1900
+ rb_ary_store(row, 0, name ? rb_enc_interned_str(name, strlen(name),
1901
+ rb_utf8_encoding())
1902
+ : Qnil);
1903
+ attrs = rb_ary_new();
1904
+ for (a = f_attr_first(node); a; a = f_attr_next(a)) {
1905
+ an = f_attr_name(a);
1906
+ av = f_attr_value(node, a);
1907
+ rb_ary_push(attrs, an ? rb_enc_interned_str(an, strlen(an),
1908
+ rb_utf8_encoding())
1909
+ : Qnil);
1910
+ rb_ary_push(attrs, av ? rb_utf8_str_new_cstr(av) : Qnil);
1911
+ }
1912
+ rb_ary_store(row, 1, attrs);
1913
+ for (c = f_first_child(node); c; c = f_next_sibling(c)) {
1914
+ if (f_node_type(c) == WS_NODE_TEXT) {
1915
+ const char *t = f_text_content(c);
1916
+ rb_ary_store(row, 2, t ? rb_utf8_str_new_cstr(t) : Qnil);
1917
+ break;
1918
+ }
1919
+ }
1920
+ rb_ary_store(row, 3, INT2NUM(depth));
1921
+ rb_ary_push(out, row);
1922
+
1923
+ for (c = f_first_child(node); c; c = f_next_sibling(c)) {
1924
+ walk_rows_impl(c, depth + 1, out);
1925
+ }
1926
+ } else if (f_node_type(node) == WS_NODE_DOCTYPE || f_node_type(node) == 9) {
1927
+ void *dc = f_first_child(node);
1928
+ while (dc) {
1929
+ walk_rows_impl(dc, depth, out);
1930
+ dc = f_next_sibling(dc);
1931
+ }
1932
+ }
1933
+ }
1934
+
1935
+ static VALUE nf_snapshot_rows(VALUE self, VALUE document, VALUE addr)
1936
+ {
1937
+ (void)self;
1938
+ (void)document;
1939
+ VALUE out = rb_ary_new();
1940
+ walk_rows_impl((void *)(uintptr_t)NUM2ULL(addr), 0, out);
1941
+ return out;
1942
+ }
1943
+
1883
1944
  /* ---- inner_html in one C pass (TODO.perf/18) --------------------
1884
1945
  * Serializes the receiver's children into one growable buffer:
1885
1946
  * elements via leptris_element_serialize_into (the same opts the
@@ -2356,6 +2417,11 @@ void Init_native(void)
2356
2417
  rb_define_method(c_native_node, "content", nn_content, 0);
2357
2418
  rb_define_method(c_native_node, "attribute", nn_attribute, 1);
2358
2419
  rb_define_alias(c_native_node, "[]", "attribute");
2420
+ /* Unshadowed aliases for consumers whose contract modules shadow
2421
+ * attribute/content: a plain call resolves to these at normal
2422
+ * method-cache cost instead of UnboundMethod#bind_call. */
2423
+ rb_define_alias(c_native_node, "attr_read", "attribute");
2424
+ rb_define_alias(c_native_node, "text_read", "content");
2359
2425
  rb_define_method(c_native_node, "children", nn_children, 0);
2360
2426
  rb_define_method(c_native_node, "element_children", nn_element_children, 0);
2361
2427
  rb_define_method(c_native_node, "next_sibling", nn_next_sibling, 0);
@@ -2422,6 +2488,8 @@ void Init_native(void)
2422
2488
  nf_fast_inner_xml, 1);
2423
2489
  rb_define_module_function(m_native, "snapshot_subtree",
2424
2490
  nf_snapshot_subtree, 2);
2491
+ rb_define_module_function(m_native, "snapshot_rows",
2492
+ nf_snapshot_rows, 2);
2425
2493
  rb_define_module_function(m_native, "doc_handle_attach",
2426
2494
  nf_doc_handle_attach, 1);
2427
2495
  rb_define_module_function(m_native, "doc_handle_release",
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Leptris
4
- VERSION = "1.9.193.3"
4
+ VERSION = "1.9.197.0"
5
5
  end
@@ -21,6 +21,13 @@ module Leptris
21
21
  when /x86_64.*darwin/ then %w[x86_64-darwin]
22
22
  when /aarch64.*linux/ then %w[aarch64-linux aarch64-linux-musl]
23
23
  when /x86_64.*linux/ then %w[x86_64-linux x86_64-linux-musl]
24
+ # 32-bit ARM (armv[567l]: "arm-linux", "armv7l-linux",
25
+ # "armeb-linux", ...). Never matches aarch64 ("aarch" has
26
+ # no "arm" substring).
27
+ when /arm.*linux/ then %w[arm-linux arm-linux-musl]
28
+ # POWER8+ little-endian and IBM Z (qemu-built platform gems)
29
+ when /ppc64le.*linux/ then %w[ppc64le-linux]
30
+ when /s390x.*linux/ then %w[s390x-linux s390x-linux-musl]
24
31
  else []
25
32
  end
26
33
  end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Post-publish smoke (the teptris-ruby gem-smoke template): the
4
+ # INSTALLED gem from rubygems — not the checkout — must parse,
5
+ # query, mutate, serialize, and validate, with the native layer
6
+ # when the platform ships it. Also guards the #318 class: the
7
+ # NODE_* constants must exist in the shipped layer (a packaging
8
+ # skew surfaces as a NameError on first use, not at require).
9
+ require "leptris"
10
+
11
+ abort "SMOKE FAIL: leptris did not define Leptris::VERSION" unless defined?(Leptris::VERSION)
12
+ puts "leptris #{Leptris::VERSION} on #{RUBY_PLATFORM} (ruby #{RUBY_VERSION})"
13
+
14
+ doc = Leptris::XML.parse("<r id='1'><a x='2'>t1</a><a>t2</a></r>")
15
+ raise "parse: root" unless doc.root.name == "r"
16
+ raise "xpath: children" unless doc.root.xpath("a").size == 2
17
+ raise "attr read" unless doc.at_xpath("a")["x"] == "2"
18
+
19
+ doc.at_xpath("a").content = "z"
20
+ raise "mutate" unless doc.at_xpath("a").content == "z"
21
+ raise "serialize" unless doc.to_xml.include?('<a x="2">z</a>')
22
+
23
+ rng = Leptris::XML::RelaxNG.parse(
24
+ '<element name="r" xmlns="http://relaxng.org/ns/structure/1.0">' \
25
+ "<attribute name=\"id\"/></element>")
26
+ rng_doc = Leptris::XML::Document.parse(%q{<r id='1'/>})
27
+ raise "rng verdict" unless rng.valid?(rng_doc)
28
+ raise "rng errors shape" unless rng.validate_errors(rng_doc).is_a?(Array)
29
+ raise "rng report shape" unless rng.validate_report(rng_doc).is_a?(Array)
30
+
31
+ # The #318 class: node-kind constants must live in the shipped
32
+ # Ruby layer (plain constants cannot go missing with the lib).
33
+ raise "NODE constants" unless Leptris::XML::FFI::NODE_ELEMENT
34
+
35
+ layer = defined?(Leptris::XML::NATIVE_FAST) ? "native" : "ffi"
36
+ puts "SMOKE OK (#{layer} layer)"
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.193.3
4
+ version: 1.9.197.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-09-17 00:00:00.000000000 Z
11
+ date: 2026-09-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
@@ -146,6 +146,8 @@ files:
146
146
  - lib/leptris/vendor/aarch64-linux/libutf8proc.so.3
147
147
  - lib/leptris/vendor/arm64-darwin/libleptris.dylib
148
148
  - lib/leptris/vendor/arm64-darwin/libutf8proc.3.dylib
149
+ - lib/leptris/vendor/ppc64le-linux/libleptris.so
150
+ - lib/leptris/vendor/ppc64le-linux/libutf8proc.so.3
149
151
  - lib/leptris/vendor/x86_64-darwin/libleptris.dylib
150
152
  - lib/leptris/vendor/x86_64-darwin/libutf8proc.3.dylib
151
153
  - lib/leptris/vendor/x86_64-linux-musl/libleptris.so
@@ -193,6 +195,7 @@ files:
193
195
  - lib/leptris/xml/xpath.rb
194
196
  - lib/leptris/xml/xquery.rb
195
197
  - lib/leptris/xml/xslt.rb
198
+ - scripts/gem_smoke.rb
196
199
  homepage: https://github.com/leptris/leptris-ruby
197
200
  licenses:
198
201
  - MIT