leptris 1.9.374.0-aarch64-linux → 1.9.375.0-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: f1cfdde9b79dc733fd841f7c812984e03a3b26da42ec56232dc0847d840fe7f6
4
- data.tar.gz: a620bff9d9f386b970c6f7523119a5a7635e3d6d61b2d3d9170a8a1ac17ab6d4
3
+ metadata.gz: ced7790ba0349b52901cfe048ccaaee9c173b4b9b1de734c0d3fabd33a16cd8f
4
+ data.tar.gz: 67b2f8ad00b72be5df814d61a54beafd7d3aca4e1e11990eb82c6e4d2111d760
5
5
  SHA512:
6
- metadata.gz: 85e7d38d6393fd494646d20630b3bd31b8e35536c47b22b83c12277ecc6a431b82255e0cf191aeb3c87f5a5dd824fa064113d88a4e9c37989b9ee702f26676e5
7
- data.tar.gz: 1913d5728de2ae72375de606fb48ca5b09b9964775468d5cf2f6c273d8079f9b359c71e34fc99eb377307aa664abebd519716b9285a2230543e1bce1d5bf65eb
6
+ metadata.gz: 897ed4da545dd52d98e29024bd707e19f8de4f9339e2b3febfe315332595fa05e7fb3868960adcd7c3d867b359e8eb6e1ed5e9b85910e856601b33ef6f400f88
7
+ data.tar.gz: 4234b33c3e5b9a2c5a1bfb219ce73a8fcda24afe4a1415d89eaa930df5ac16776231d47db8300a39ebd1a580d398cbe941a02d4e35f4b0b8718981ed1644c9f7
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.374"
11
+ LIBLEPTRIS_VERSION = "1.9.375"
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Leptris
4
- VERSION = "1.9.374.0"
4
+ VERSION = "1.9.375.0"
5
5
  end
data/lib/libleptris.so CHANGED
Binary file
data/vendor-src/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  Sources vendored in this gem (recompile rights; the ruby
2
2
  variant builds them at install via extconf.rb):
3
3
 
4
- - libleptris v1.9.374
4
+ - libleptris v1.9.375
5
5
  - utf8proc v2.11.0
6
6
 
7
7
  Rebuild by hand:
@@ -1,5 +1,22 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.9.375] - 2026-10-20
4
+
5
+ ### Added
6
+
7
+ - **html: the #1771 verdict-parity emission slices (PRs #1788,
8
+ #1789, #1790, #1791) — parity 1394 to 1423 of 1555.** The EOF
9
+ closing-tag verdict now implements html5lib's InBody processEOF
10
+ allowed-set exactly (zero false positives — the lint's first
11
+ requirement); the in-select drop sites report
12
+ unexpected-start/end-tag-in-select and unexpected-select-in-
13
+ select; the foster branch reports foster-parenting-character/
14
+ -start-tag by node kind; unknown-doctype follows html5lib's
15
+ BeforeHtml processDoctype (name/public/system shape). Trees
16
+ byte-identical throughout (1555/1555); full suite green at
17
+ every step.
18
+
19
+
3
20
  ## [1.9.374] - 2026-10-19
4
21
 
5
22
  ### Fixed
@@ -3,7 +3,7 @@
3
3
  cmake_minimum_required(VERSION 3.20)
4
4
 
5
5
  project(leptris
6
- VERSION 1.9.374
6
+ VERSION 1.9.375
7
7
  DESCRIPTION "Fast XML parser and XPath evaluator in pure C"
8
8
  LANGUAGES C CXX
9
9
  )
@@ -0,0 +1,154 @@
1
+ # TODO.SOTA — the vision of done
2
+
3
+ The audit underneath this board: an XML stack is an **epistemic
4
+ instrument** — it decides what a document means. Its purpose is
5
+ trustworthy interpretation, made affordable everywhere. SOTA is
6
+ therefore not a feeling but four provable claims, each with a
7
+ measurement command whose output is the verdict:
8
+
9
+ 1. **Conformance** — we interpret every document the way the
10
+ specifications (and the reference suites) say. *Proof: zero reds
11
+ on every adopted suite.*
12
+ 2. **Performance** — correctness is free; we are faster than every
13
+ incumbent on every published shape. *Proof: ≥1.00x on every row,
14
+ interleaved medians.*
15
+ 3. **Safety** — trust is auditable: memory-safe under sanitizers,
16
+ fuzz-clean, reproducibly built. *Proof: clean lanes + per-release
17
+ build manifests.*
18
+ 4. **Universality** — the same semantics in every language; a
19
+ document means the same thing through every runtime. *Proof: a
20
+ cross-runtime differential corpus, byte-identical.*
21
+
22
+ Everything below is the task board for those four proofs. Every row
23
+ ends with a dated measurement; the scoreboard lives in
24
+ docs/MISSION-PLAN.md and is updated at every release.
25
+
26
+ ---
27
+
28
+ ## Gate A — Conformance: zero reds everywhere
29
+
30
+ ### A1 WHATWG verdict parity: 1394/1555 → 1555/1555
31
+ The remaining 161 verdict cases + ~270 code-set divergences
32
+ (html5lib-verdict-redlist.txt). Ground every slice in html5lib's
33
+ actual source (~/src/external/html5lib):
34
+ - [ ] escaped-state EOF codes (`unexpected-eof-in-text-mode`,
35
+ `eof-in-script-in-script`) — the script-data state machine's
36
+ EOF classification
37
+ - [ ] the after-body EOF phase rule (tests1:34 class; the exact
38
+ phaseAtBody.eof semantics)
39
+ - [ ] in-body `unexpected-start-tag` family (body/frameset/form
40
+ starts; the startTagBody/Forms/Frameset error sites)
41
+ - [ ] `unexpected-end-tag` family (p-in-button-scope synthesis,
42
+ form pointer, li/dd/dt scope, endTagOther walk)
43
+ - [ ] foster-parenting sites (start-tag/character/character-in-table)
44
+ - [ ] adoption-agency codes (`adoption-agency-1.3` et al.)
45
+ - [ ] in-table voodoo (`*-implies-table-voodoo`, cells, eof-in-table)
46
+ - [ ] unknown-doctype / unexpected-char-in-doctype (doctype
47
+ tokenization §13.2.5.28+)
48
+ - [ ] non-html-root, select-mode codes, heading/edge shapes
49
+
50
+ ### A2 QT3 / XQuery 3.1: zero unexplained pins
51
+ - [ ] re-pin fresh (the ~41–99 slice figures are dated)
52
+ - [ ] every remaining pin gets a disposition file or a fix
53
+ - [ ] ctor node-yield family: owned_docs transfer completion
54
+
55
+ ### A3 XSD conformance lane: suite-complete
56
+ - [ ] the lane's own queue (769→795 → its ceiling) to zero
57
+
58
+ ### A4 DTD phase 8 (TODO 91)
59
+ - [ ] ENTITY/ENTITIES attribute resolution
60
+ - [ ] parameter entities, choice-model backtracking
61
+
62
+ ### A5 XInclude completeness (TODO 92)
63
+ - [ ] `parse="xml"` (ownership-transfer splice exists — wire it)
64
+ - [ ] xpointer
65
+
66
+ ### A6 The universality proof (differential corpus)
67
+ - [ ] one curated corpus (the html5lib + QT3-winner + metanorma
68
+ sample set) run through ruby/py/ts/rs bindings
69
+ - [ ] byte-identical outputs asserted in CI (the "one engine, same
70
+ numbers everywhere" proof)
71
+
72
+ ### A7 Maintain (already green; keep gated)
73
+ - [ ] XML 1.0, XPath 438/438, libxslt 205/205, XsltFull,
74
+ C14N, RelaxNG, SAX records lane
75
+
76
+ ## Gate B — Performance: every published row ≥1.00x
77
+
78
+ ### B1 build row: ~2.9x → ≤1.0x (the #242 campaign)
79
+ Harness: wt/460-harness/build_bench.rb. Decomposition on record.
80
+ - [ ] per-element object budget: one Ruby object per created node
81
+ (drop the shell entirely post-create-priming; the mint cache
82
+ insert policy; the context registration)
83
+ - [ ] the root `to_binding` bridge (set_root path)
84
+ - [ ] `[]=` / `text=` write faces (nn_set_attribute pattern applied
85
+ to text writes; one C frame per write)
86
+
87
+ ### B2 walk row: 0.88x → much faster
88
+ Per-face reads already 3–5x ahead; the harness floor is shared
89
+ scaffolding. Memo law holds (dropping @children memo = 2x GC).
90
+ - [ ] hot-path audit of NodeSet#each / block dispatch
91
+ - [ ] publish the per-face table (the honest much-faster story)
92
+
93
+ ### B3 whole-pipeline rows (new, published)
94
+ - [ ] parse→query→serialize pipeline row vs nokogiri/libxml2
95
+ - [ ] build→transform (XSLT) pipeline row
96
+ - [ ] both to serialbench as the public scoreboard
97
+
98
+ ### B4 durability
99
+ - [ ] CI perf regression gates on the chokepoints (parse, walk,
100
+ build, serialize medians, fail on >5% regression)
101
+
102
+ ### B5 remaining red rows
103
+ - [ ] pugixml lane-18 append/attr-parse (2.0x/5.9x; hash prefilter)
104
+ - [ ] zero-copy text lever (#1218) — adopt if it wins any row
105
+
106
+ ## Gate C — Safety: trust is auditable
107
+
108
+ - [ ] C1 structure-aware fuzzing: grammar-aware corpora for
109
+ XML/XPath/XSLT/HTML (grow beyond the three libFuzzer harnesses;
110
+ corpus commit + crash-triage SLA)
111
+ - [ ] C2 sanitizer lanes over the risk families: records-drain,
112
+ borrowed-slice + pool-recycle (the #506 class), iterparse
113
+ keepalive — ASAN/UBSAN now, add TSAN (batch/worker surfaces)
114
+ - [ ] C3 reproducible builds everywhere: darwin toolchain pin done
115
+ (ruby#512) — extend to linux/windows legs; publish a per-
116
+ release build manifest (engine + binding hashes per platform)
117
+ - [ ] C4 security.md: advisory channel, CVE-response process,
118
+ dependency-free attestation
119
+ - [ ] C5 the memory story documented: pool arena model, leak gates,
120
+ the borrowed-slice lifetime contract
121
+
122
+ ## Gate D — Universality: same semantics everywhere
123
+
124
+ - [ ] D1 leptris-descriptor published (crates.io; feat/294 branch
125
+ lands), rides lockstep
126
+ - [ ] D2 system packaging: homebrew, conan, deb (apt repo)
127
+ - [ ] D3 cross-runtime differential CI (= A6, wired)
128
+ - [ ] D4 libxml2→libleptris migration guide (docs/guide/) + the
129
+ nokogiri-compat surface documented
130
+
131
+ ## Gate E — 1.0 (the seal)
132
+
133
+ - [ ] E1 Gate A + B report zero reds (dated scoreboard)
134
+ - [ ] E2 semver freeze, ABI stability policy, platform matrix doc
135
+ - [ ] E3 v1.0.0 through the release workflow — never tagged by hand
136
+
137
+ ---
138
+
139
+ ## Invariants (the laws the board executes inside)
140
+
141
+ - Falsifiability: red-first specs; both-directions measurement.
142
+ - Lockstep + TAG-RACE; the release workflow owns versions and tags.
143
+ - One branch/PR per item; worktrees at wt/; never commit on main;
144
+ never `git add -A`; verify the branch before every commit.
145
+ - Aliases before shims: unshadowed C faces upstream; consumers
146
+ face-probe and plain-dispatch.
147
+ - Suites over opinions; the corpus is the reference.
148
+
149
+ ## Definition of done
150
+
151
+ Every checkbox above carries a dated measurement command and its
152
+ recorded result; docs/MISSION-PLAN.md's scoreboard shows Gate A and
153
+ Gate B at zero reds; v1.0.0 is tagged. That day, the libxml2 era is
154
+ over wherever this engine ships.
@@ -4136,6 +4136,16 @@ static void h_append(HBuilder* b, LeptrisNodeRef n) {
4136
4136
  /* #659 foster (WHATWG only): text/elements in table context
4137
4137
  * go before the nearest open table in ITS parent. */
4138
4138
  if (b->whatwg_foster && tbl_ctx && h_fosterable(b, n)) {
4139
+ /* #1771: the corpus verdicts name the foster by node
4140
+ * kind (foster-parenting-character / -start-tag). The
4141
+ * position rides the line memo — h_append has no token
4142
+ * offset, and the verdict gate compares codes only. */
4143
+ h_diag(b,
4144
+ leptris_node_get_type(n) == LEPTRIS_NODE_TYPE_TEXT
4145
+ ? "foster-parenting-character"
4146
+ : "foster-parenting-start-tag",
4147
+ b->err_line_memo_off,
4148
+ "node fostered out of the table context");
4139
4149
  int ti = (int)b->depth - 1;
4140
4150
  while (ti >= 0 && !h_ieq_raw(
4141
4151
  leptris_element_name(b->open[ti]), "table"))
@@ -5903,6 +5913,21 @@ static LeptrisDocument html_parse_shared(
5903
5913
  * doctype - with an EMPTY name (13.2.5 "missing-
5904
5914
  * doctype-name", doctype01.dat:4/5). WHATWG
5905
5915
  * mode only; html4 keeps the drop. */
5916
+ /* #1771: html5lib's BeforeHtml processDoctype —
5917
+ * name != html, a public id, or a system id other
5918
+ * than about:legacy-compat is unknown-doctype. */
5919
+ if (b.whatwg) {
5920
+ size_t ln = nlen;
5921
+ int name_html = (ln == 4);
5922
+ for (int i = 0; name_html && i < 4; i++)
5923
+ if (h_lower(nstart[i]) != "html"[i])
5924
+ name_html = 0;
5925
+ if (!name_html || pub[0] ||
5926
+ (sys[0] && strcmp(sys, "about:legacy-compat") != 0))
5927
+ h_diag(&b, "unknown-doctype",
5928
+ (size_t)(nstart - b.input_base),
5929
+ "unknown DOCTYPE shape");
5930
+ }
5906
5931
  if (nlen || b.whatwg) {
5907
5932
  /* WHATWG lowercases the doctype name;
5908
5933
  * libxml2 (the html4/parity mode) preserves
@@ -6357,6 +6382,13 @@ static LeptrisDocument html_parse_shared(
6357
6382
  strcmp(lname, "select") != 0 &&
6358
6383
 
6359
6384
  strcmp(lname, "template") != 0) {
6385
+ /* #1771: html5lib's InSelect endTagOther
6386
+ * reports the drop (unexpected-end-tag-
6387
+ * in-select). */
6388
+ h_diag(&b, "unexpected-end-tag-in-select",
6389
+ (size_t)(p - b.input_base),
6390
+ "</%s> ignored inside <select>",
6391
+ lname);
6360
6392
  p = q;
6361
6393
  text = p;
6362
6394
  continue;
@@ -7215,7 +7247,11 @@ static LeptrisDocument html_parse_shared(
7215
7247
  if (b.whatwg && h_in_select(&b) &&
7216
7248
  strcmp(name, "select") == 0) {
7217
7249
  /* 13.2.6.4.11: a <select> start tag inside a select
7218
- * ACTS AS its end tag — no nesting (tests1:30). */
7250
+ * ACTS AS its end tag — no nesting (tests1:30).
7251
+ * #1771: html5lib reports unexpected-select-in-select. */
7252
+ h_diag(&b, "unexpected-select-in-select",
7253
+ (size_t)(p - b.input_base),
7254
+ "<select> inside <select> acts as an end tag");
7219
7255
  for (size_t d2 = b.depth; d2 > 0; d2--)
7220
7256
  if (strcmp(leptris_element_name(b.open[d2 - 1]),
7221
7257
  "select") == 0) {
@@ -7274,6 +7310,11 @@ static LeptrisDocument html_parse_shared(
7274
7310
  b.depth = (size_t)sel_idx; /* pop the select;
7275
7311
  * reprocess below */
7276
7312
  } else {
7313
+ /* #1771: html5lib's InSelect startTagOther reports
7314
+ * the drop (unexpected-start-tag-in-select). */
7315
+ h_diag(&b, "unexpected-start-tag-in-select",
7316
+ (size_t)(p - b.input_base),
7317
+ "<%s> ignored inside <select>", name);
7277
7318
  while (q < end && *q != '>') q++;
7278
7319
  p = (q < end) ? q + 1 : end;
7279
7320
  text = p;
@@ -8323,29 +8364,43 @@ done:
8323
8364
  /* Nothing appended (empty input, stray end tags only, doctype
8324
8365
  * only) is NOT an error in lenient HTML mode: the wrapper
8325
8366
  * synthesis below yields the empty Nokogiri shape. */
8326
- /* #1771: elements still open at EOF are
8327
- * expected-closing-tag-but-got-eof (html5lib's verdict; the
8328
- * implied html shell does not count). Judged BEFORE the
8329
- * wrapper synthesis, which tears the open stack down. Our
8330
- * stack carries no implied html/body, so the html5lib
8331
- * top-of-stack rule maps to: any real element open, gated on
8332
- * </body>/</html> never having been seen — after-body EOF is
8333
- * clean whatever remains (tests1:34). A raw-text container
8334
- * got its own variant at the raw branch already (that branch
8335
- * pops the element, so the top here is whatever wraps it). */
8367
+ /* #1771: html5lib's InBody processEOF (html5parser.py:958):
8368
+ * ONE expected-closing-tag-but-got-eof iff ANY open element is
8369
+ * outside the allowed set {dd,dt,li,p,tbody,td,tfoot,th,thead,
8370
+ * tr,body,html} — li/p/table scaffolding does not count
8371
+ * (tests1:34), address/applet/div do (blocks.dat:1,
8372
+ * tests20:96-class). AfterBody's processEOF is silent
8373
+ * (html5parser.py:2533) and its non-wsCharacters rule flips the
8374
+ * phase back to in-body — the builder's after_body/after_body_done
8375
+ * pair is exactly that state. A raw-text container got its own
8376
+ * variant at the raw branch already (that branch pops the
8377
+ * element). Judged BEFORE the wrapper synthesis tears the open
8378
+ * stack down. */
8336
8379
  if (b.whatwg && b.depth > 0) {
8337
- uint8_t top = b.open_id[b.depth - 1];
8338
- if (top != h_id_html && top != h_id_head &&
8339
- top != h_id_body)
8340
- h_diag(&b,
8341
- (top == h_id_script || top == h_id_style ||
8342
- top == h_id_listing || top == h_id_plaintext ||
8343
- top == h_id_textarea || top == h_id_title ||
8344
- top == h_id_xmp || top == h_id_iframe ||
8345
- top == h_id_noembed || top == h_id_noframes)
8346
- ? "expected-named-closing-tag-but-got-eof"
8347
- : "expected-closing-tag-but-got-eof",
8348
- b.input_len, "elements left open at end of input");
8380
+ static uint8_t k_allowed[256];
8381
+ static int allowed_init;
8382
+ if (!allowed_init) {
8383
+ /* id tables are lazily initialized once; these ids are
8384
+ * stable for the process lifetime */
8385
+ uint8_t ids[] = {h_id_p, h_id_li, h_id_dd, h_id_dt,
8386
+ h_id_tbody, h_id_td, h_id_tfoot,
8387
+ h_id_th, h_id_thead, h_id_tr,
8388
+ h_id_body, h_id_html};
8389
+ for (size_t k = 0; k < sizeof(ids) / sizeof(ids[0]); k++)
8390
+ k_allowed[ids[k]] = 1;
8391
+ allowed_init = 1;
8392
+ }
8393
+ for (size_t k = 0; k < b.depth; k++) {
8394
+ uint8_t id = b.open_id[k];
8395
+ if (id == h_id_html || id == h_id_head || id == h_id_body)
8396
+ continue;
8397
+ if (!k_allowed[id]) {
8398
+ h_diag(&b, "expected-closing-tag-but-got-eof",
8399
+ b.input_len,
8400
+ "elements left open at end of input");
8401
+ break;
8402
+ }
8403
+ }
8349
8404
  }
8350
8405
  /* Nokogiri document shape (#659): with no explicit <html>,
8351
8406
  * synthesize <html><head></head><body>content</body></html> —
@@ -978,8 +978,8 @@ TEST(Html5LibCorpus, ErrorVerdictParity) {
978
978
  printf(" VERDICT %s\n", failures[i].c_str());
979
979
  EXPECT_GT(total, (size_t)1500);
980
980
  /* Verdict-parity floor — set at the slice-2 baseline
981
- * (1394/1555; was 190 before the #1771 emission slices —
981
+ * (1409/1555; was 190 before the #1771 emission slices —
982
982
  * the doctype-less initial-mode family, trailing chars, EOF with
983
983
  * open elements; slice 3 adds the raw-text EOF variants). Only raises. */
984
- EXPECT_GE(parity, (size_t)1394);
984
+ EXPECT_GE(parity, (size_t)1409);
985
985
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg/master/scripts/vcpkg.schema.json",
3
3
  "name": "leptris",
4
- "version": "1.9.374",
4
+ "version": "1.9.375",
5
5
  "description": "High-performance XML parser and XPath 1.0 engine in C (libleptris)",
6
6
  "homepage": "https://github.com/leptris/leptris",
7
7
  "license": "MIT",
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.374.0
4
+ version: 1.9.375.0
5
5
  platform: aarch64-linux
6
6
  authors:
7
7
  - Ribose Inc.
@@ -206,6 +206,7 @@ files:
206
206
  - vendor-src/libleptris/CONTEXT.md
207
207
  - vendor-src/libleptris/LICENSE.md
208
208
  - vendor-src/libleptris/README.adoc
209
+ - vendor-src/libleptris/TODO.SOTA.md
209
210
  - vendor-src/libleptris/TODO.assemble/README.md
210
211
  - vendor-src/libleptris/TODO.bindings/01-mutation-construction.md
211
212
  - vendor-src/libleptris/TODO.bindings/02-incremental-iterparse.md