leptris 1.9.399.0-arm-linux → 1.9.401.0-arm-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: 85e3d9f5b990ac287799605ca5cd9054c9e7dd682d482af346ac1db782a26e1b
4
- data.tar.gz: 8895a0750efb957fe2de60a932095e53345860eb448da621199a922fb38ab372
3
+ metadata.gz: c107bf6982053d9a85a433e49e16436cf38c93ef390fcb11069642bd507255cb
4
+ data.tar.gz: '0349bd09652826c6ac93638d751b743c60d687dd20679aeebf6e12dca0477edc'
5
5
  SHA512:
6
- metadata.gz: 333f9d60f1197ea4db616adbbfc9db96abdf6cca1a8e17abf1d6afbc7d798d0a69b7cf504bbecb2e22cd44e1c72de00cf9a50c38e50bab032ea1356526d22126
7
- data.tar.gz: 608657836bc76cb63eb79466b06d9e6f93862dd63c44b3e5bc19a77fcbb6b51f81c4f2594f4e98607353342dd064da56cf78d96335a5b9bc690eed9f15bc8374
6
+ metadata.gz: c3de4ef23793319525120a22edd38087087bc726579eff905dcb63cc3a75fd05a214b94dd80fb7bcae66186fe27e9b09db1aa33da79a1c05d4f5b37a4d8206e9
7
+ data.tar.gz: c8b03b880fc5bc05fece37578f53d265cf3c3c7ec041c88dc46180d67c3462bea01f46d460210340784eeb116464933dc0f6fe82c24e4d426bf1220d316f9eea
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.399"
11
+ LIBLEPTRIS_VERSION = "1.9.401"
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.399.0"
4
+ VERSION = "1.9.401.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.399
4
+ - libleptris v1.9.401
5
5
  - utf8proc v2.11.0
6
6
 
7
7
  Rebuild by hand:
@@ -1,5 +1,41 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.9.401] - 2026-11-01
4
+
5
+ ### Fixed
6
+
7
+ - **List value spaces collapse whitespace before the facets
8
+ (leptris#1936 stG010/stH005, PR #1945).** Caught by running the
9
+ REAL W3C suite documents (vendored in lutaml-xsd) through the
10
+ xmllint-arbiter harness: a list-derived restriction's
11
+ enumeration facet compared the RAW element content — stG010's
12
+ value arrives as newline-tab-CA-newline-spaces and never matched
13
+ enum "CA" — and a whole-list pattern had the same hole (stH005).
14
+ List value spaces are whitespace=collapse (Part 2): the value is
15
+ normalized before the pattern/enumeration/length family runs.
16
+ Suite 142/142; both documents validate. (xsd)
17
+
18
+
19
+
20
+ ## [1.9.400] - 2026-11-01
21
+
22
+ ### Fixed
23
+
24
+ - **A restriction's inline anonymous base drives validation
25
+ (leptris#1936 stG/stH, PR #1943).** An `xs:restriction` whose
26
+ base is an inline anonymous `<xs:simpleType>` — the W3C suite's
27
+ stG/stH style — never captured that base: values were
28
+ facet-checked with nothing underneath, so `length` counted
29
+ characters of the whole lexical instead of list items. The base
30
+ now rides the capture (`base_def`, mirroring `item_def`/
31
+ `member_defs`), the value passes through the base's own
32
+ derivation before the restriction's facets, and the list-chain
33
+ detector descends the anonymous path. RED-first spec; the
34
+ xmllint-arbiter harness agrees on all 8 collected
35
+ schema/instance pairs. (xsd)
36
+
37
+
38
+
3
39
  ## [1.9.399] - 2026-10-31
4
40
 
5
41
  ### Fixed
@@ -169,3 +169,19 @@ calculates the next version, and updates three files:
169
169
  - `CHANGELOG.md` (version header)
170
170
 
171
171
  The bump-version.sh script handles all three in one shot.
172
+
173
+ ### Runtime coverage law: publish ALL runtimes every release
174
+
175
+ An engine release is NOT done when the GitHub Release publishes — it is
176
+ done when every runtime package riding it is published and VERIFIED on
177
+ its registry, same day: **ruby** (rubygems, leptris-ruby: bump Rakefile
178
+ `LIBLEPTRIS_VERSION` + `lib/leptris/version.rb`; merge = publish), **py**
179
+ (PyPI, leptris-py: bump `libleptris-version.txt` + `pyproject.toml` +
180
+ `leptris/__init__.py`; merge = publish), **rs** (crates.io, leptris-rs:
181
+ conventional commits -> merge release-plz's release PR = publish), **ts**
182
+ (npm package `leptris`, leptris-ts: bump pin + `package.json`; the
183
+ `v<pkg>` tag push publishes). Verify on the registry itself — a merged
184
+ PR with a stuck workflow is not a release (2026-10-29: ruby sat two
185
+ engine releases behind with the pin already advanced; py seven behind;
186
+ rs's release workflow had never succeeded — missing `id-token: write`;
187
+ ts 0.1.24 never tagged).
@@ -3,7 +3,7 @@
3
3
  cmake_minimum_required(VERSION 3.20)
4
4
 
5
5
  project(leptris
6
- VERSION 1.9.399
6
+ VERSION 1.9.401
7
7
  DESCRIPTION "Fast XML parser and XPath evaluator in pure C"
8
8
  LANGUAGES C CXX
9
9
  )
@@ -1172,6 +1172,53 @@ No runtime dependencies when built without utf8proc/iconv.
1172
1172
  |libFuzzer for 5 minutes; report any crashes.
1173
1173
  |===
1174
1174
 
1175
+ == Releasing and the runtime packages
1176
+
1177
+ The engine releases via the automated workflow
1178
+ (`gh workflow run release.yml -f next_version=patch` — the workflow
1179
+ bumps the version, opens the release PR, and tags + publishes the
1180
+ GitHub Release when it merges). Never tag or release by hand.
1181
+
1182
+ **Every engine release ships ALL runtime packages the same day** —
1183
+ an engine release is not done until each binding that rides it is
1184
+ published and verified on its registry:
1185
+
1186
+ [cols="1,2,3",options="header"]
1187
+ |===
1188
+ |Runtime |Registry |Ride
1189
+
1190
+ |Ruby
1191
+ |rubygems (`leptris`, `{engine-semver}.{binding-patch}`)
1192
+ |bump `Rakefile` `LIBLEPTRIS_VERSION` + `lib/leptris/version.rb` in
1193
+ link:https://github.com/leptris/leptris-ruby[leptris-ruby]; merging
1194
+ the bump PR is the release decision (auto-publish).
1195
+
1196
+ |Python
1197
+ |PyPI (`leptris`)
1198
+ |bump `libleptris-version.txt` + `pyproject.toml` +
1199
+ `leptris/__init__.py` in
1200
+ link:https://github.com/leptris/leptris-py[leptris-py]; merging the
1201
+ bump PR publishes via trusted publishing.
1202
+
1203
+ |Rust
1204
+ |crates.io (`leptris`)
1205
+ |conventional commits on
1206
+ link:https://github.com/leptris/leptris-rs[leptris-rs] main; the
1207
+ release-plz PR carries the version bump, and merging IT publishes
1208
+ (crates.io trusted publishing).
1209
+
1210
+ |TypeScript / WASM
1211
+ |npm (`leptris`)
1212
+ |bump the engine pin + `package.json` version in
1213
+ link:https://github.com/leptris/leptris-ts[leptris-ts]; the
1214
+ tag-gated `v<pkg-version>` push publishes via npm trusted
1215
+ publishing.
1216
+ |===
1217
+
1218
+ Verify each publication on the registry itself (`gem list -r`,
1219
+ `pip index versions`, the crates.io/npm APIs) — a merged PR with a
1220
+ stuck workflow is NOT a release.
1221
+
1175
1222
  == Project layout
1176
1223
 
1177
1224
  [source,text]
@@ -428,6 +428,22 @@ static XsdSimple* xsd_capture_simple(LeptrisElement st) {
428
428
  } else if (strcmp(local, "restriction") == 0) {
429
429
  simple->base = xsd_strdup(xsd_local_name(
430
430
  leptris_element_attribute(e, "base")));
431
+ /* #1936 (stG/stH): an inline anonymous BASE rides this
432
+ * capture — without it the restriction's facets apply
433
+ * with no base (length counted characters, list
434
+ * semantics vanished). Mirrors the union member_defs. */
435
+ for (LeptrisNodeRef b = leptris_node_first_child(
436
+ leptris_element_as_node(e));
437
+ b && !simple->base_def;
438
+ b = leptris_node_next_sibling(b)) {
439
+ if (leptris_node_get_type(b) != LEPTRIS_NODE_TYPE_ELEMENT)
440
+ continue;
441
+ LeptrisElement be = (LeptrisElement)b;
442
+ const char* bl = NULL;
443
+ leptris_element_expanded_name(be, &bl, NULL, NULL);
444
+ if (bl && strcmp(bl, "simpleType") == 0)
445
+ simple->base_def = xsd_capture_simple(be);
446
+ }
431
447
  for (LeptrisNodeRef f = leptris_node_first_child(
432
448
  leptris_element_as_node(e));
433
449
  f; f = leptris_node_next_sibling(f)) {
@@ -584,7 +600,13 @@ static int xsd_chain_is_list(struct leptris_xsd_schema* s,
584
600
  int depth = 0;
585
601
  while (t && depth < 32) {
586
602
  if (t->deriv == XSD_SIMPLE_LIST) return 1;
587
- if (!t->base) return 0;
603
+ if (!t->base) {
604
+ /* #1936: an anonymous inline base continues the chain —
605
+ * a restriction of an inline list keeps list semantics
606
+ * (the length family counts items). */
607
+ if (t->base_def) { t = t->base_def; depth++; continue; }
608
+ return 0;
609
+ }
588
610
  if (strncmp(t->base, "xs:", 3) == 0)
589
611
  return strcmp(t->base, "xs:IDREFS") == 0 ||
590
612
  strcmp(t->base, "xs:NMTOKENS") == 0 ||
@@ -651,6 +673,11 @@ static int xsd_deriv_valid(struct leptris_xsd_schema* s,
651
673
  return 1;
652
674
  return 0;
653
675
  }
676
+ /* #1936: the value satisfies the inline base (its own
677
+ * derivation — list item walks, union members — first), then
678
+ * this level's facets. */
679
+ if (t->base_def && !xsd_deriv_valid(s, t->base_def, v, depth + 1))
680
+ return 0;
654
681
  return xsd_simple_valid(t, v, xsd_chain_terminal(s, t), 0);
655
682
  }
656
683
 
@@ -663,6 +690,11 @@ static int xsd_valid_chain(struct leptris_xsd_schema* s,
663
690
  }
664
691
  if (t->deriv != XSD_SIMPLE_RESTRICT)
665
692
  return xsd_deriv_valid(s, t, v, depth);
693
+ /* #1936: the inline anonymous base drives the value first
694
+ * (its own derivation — list item walks, union members),
695
+ * then this restriction's facets. */
696
+ if (t->base_def && !xsd_deriv_valid(s, t->base_def, v, depth + 1))
697
+ return 0;
666
698
  return xsd_simple_valid(t, v, xsd_chain_terminal(s, t),
667
699
  xsd_chain_is_list(s, t));
668
700
  }
@@ -2551,6 +2583,7 @@ static void xsd_free_simple_one(XsdSimple* t) {
2551
2583
  free(t->assertion);
2552
2584
  free(t->item_type);
2553
2585
  xsd_free_simple_one(t->item_def);
2586
+ xsd_free_simple_one(t->base_def);
2554
2587
  for (size_t i = 0; i < t->member_count; i++) free(t->members[i]);
2555
2588
  free(t->members);
2556
2589
  for (size_t i = 0; i < t->member_def_count; i++)
@@ -510,7 +510,41 @@ static int facet_check_body(const XsdSimple* s, const char* v,
510
510
  const char* terminal_base, int chain_is_list);
511
511
  static int facet_check(const XsdSimple* s, const char* v,
512
512
  const char* terminal_base, int chain_is_list) {
513
- int rc = facet_check_body(s, v, terminal_base, chain_is_list);
513
+ /* #1936 (stG010): a LIST value space is whitespace=collapse —
514
+ * element content arrives as "\n\tCA\n " and the enumeration
515
+ * /pattern facets must see the collapsed form ("CA"), not the
516
+ * raw text. */
517
+ int list_valued = chain_is_list || s->deriv == XSD_SIMPLE_LIST ||
518
+ (terminal_base &&
519
+ (strcmp(terminal_base, "xs:IDREFS") == 0 ||
520
+ strcmp(terminal_base, "xs:NMTOKENS") == 0 ||
521
+ strcmp(terminal_base, "xs:ENTITIES") == 0));
522
+ if (!list_valued)
523
+ return facet_check_body(s, v, terminal_base, chain_is_list);
524
+ while (*v == ' ' || *v == '\t' || *v == '\n' || *v == '\r') v++;
525
+ size_t n = strlen(v);
526
+ while (n > 0 && (v[n-1] == ' ' || v[n-1] == '\t' ||
527
+ v[n-1] == '\n' || v[n-1] == '\r'))
528
+ n--;
529
+ char* collapsed = (char*)malloc(n + 1);
530
+ if (!collapsed)
531
+ return facet_check_body(s, v, terminal_base, chain_is_list);
532
+ size_t o = 0;
533
+ int in_ws = 0;
534
+ for (size_t i = 0; i < n; i++) {
535
+ char ch = v[i];
536
+ if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r') {
537
+ if (!in_ws && o) collapsed[o++] = ' ';
538
+ in_ws = 1;
539
+ } else {
540
+ collapsed[o++] = ch;
541
+ in_ws = 0;
542
+ }
543
+ }
544
+ if (o && collapsed[o-1] == ' ') o--;
545
+ collapsed[o] = 0;
546
+ int rc = facet_check_body(s, collapsed, terminal_base, chain_is_list);
547
+ free(collapsed);
514
548
  return rc;
515
549
  }
516
550
  static int facet_check_body(const XsdSimple* s, const char* v,
@@ -40,6 +40,7 @@ typedef struct xsd_simple {
40
40
  char* name;
41
41
  char* ns; /* leptris-ruby#440: declaring schema's targetNamespace */
42
42
  char* base;
43
+ struct xsd_simple* base_def; /* RESTRICTION: inline anonymous base */
43
44
  XsdSimpleDeriv deriv;
44
45
  char* item_type; /* LIST: builtin or local type name */
45
46
  struct xsd_simple* item_def; /* LIST: inline anonymous item type */
@@ -390,6 +390,53 @@ TEST(XsdDatatypes, LengthFacetCountsOctetsForHexBinary) {
390
390
  // byte world and character-class SUBTRACTION — the OPC
391
391
  // ST_ContentType shape. A pattern that fails to parse rejects
392
392
  // everything, so media types failed wholesale.
393
+ // leptris#1936 (stG/stH oracle pair): a restriction whose base is
394
+ // an ANONYMOUS inline simpleType must validate the value against
395
+ // that base before its own facets — length on a list-with-length-2
396
+ // counts items, not characters of the whole lexical.
397
+ // leptris#1936 (stG010/stH005, the REAL suite documents): a list
398
+ // value space is whitespace=collapse — element content "\n\tCA\n "
399
+ // normalizes to "CA" before the enumeration/pattern facets run.
400
+ TEST(XsdDatatypes, ListValueSpaceCollapsesBeforeFacets) {
401
+ const char xsd[] =
402
+ "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">"
403
+ "<xs:simpleType name=\"myToken\"><xs:list itemType=\"xs:NMTOKEN\"/>"
404
+ "</xs:simpleType>"
405
+ "<xs:simpleType name=\"fooType\"><xs:restriction base=\"myToken\">"
406
+ "<xs:enumeration value=\"CA\"/><xs:enumeration value=\"OR\"/>"
407
+ "</xs:restriction></xs:simpleType>"
408
+ "<xs:element name=\"r\" type=\"fooType\"/></xs:schema>";
409
+ LeptrisStatus st = LEPTRIS_OK;
410
+ LeptrisXsdSchema s = leptris_xsd_compile(xsd, strlen(xsd), &st);
411
+ ASSERT_EQ(st, LEPTRIS_OK);
412
+ ASSERT_NE(s, (LeptrisXsdSchema)0);
413
+ EXPECT_EQ(leptris_xsd_simple_valid(s, "fooType", "\n\tCA\n "), 1);
414
+ EXPECT_EQ(leptris_xsd_simple_valid(s, "fooType", "CA"), 1);
415
+ EXPECT_EQ(leptris_xsd_simple_valid(s, "fooType", " OR "), 1);
416
+ EXPECT_EQ(leptris_xsd_simple_valid(s, "fooType", "CA OR"), 0);
417
+ leptris_xsd_free(s);
418
+ }
419
+
420
+ TEST(XsdDatatypes, RestrictionInlineBaseDrivesFacets) {
421
+ const char xsd[] =
422
+ "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">"
423
+ "<xs:simpleType name=\"twoInts\"><xs:restriction>"
424
+ "<xs:simpleType><xs:list itemType=\"xs:int\"/></xs:simpleType>"
425
+ "<xs:length value=\"2\"/></xs:restriction></xs:simpleType>"
426
+ "<xs:element name=\"r\" type=\"twoInts\"/></xs:schema>";
427
+ LeptrisStatus st = LEPTRIS_OK;
428
+ LeptrisXsdSchema s = leptris_xsd_compile(xsd, strlen(xsd), &st);
429
+ ASSERT_EQ(st, LEPTRIS_OK);
430
+ ASSERT_NE(s, (LeptrisXsdSchema)0);
431
+ // 2 items: valid per xmllint (the engine used to count chars)
432
+ EXPECT_EQ(leptris_xsd_simple_valid(s, "twoInts", "1 2"), 1);
433
+ // 3 items: over the length facet
434
+ EXPECT_EQ(leptris_xsd_simple_valid(s, "twoInts", "1 2 3"), 0);
435
+ // a member fails the item type
436
+ EXPECT_EQ(leptris_xsd_simple_valid(s, "twoInts", "1 x"), 0);
437
+ leptris_xsd_free(s);
438
+ }
439
+
393
440
  // leptris#1936 (reS38/reT51): XSD 1.0 cites Unicode 3.1, where
394
441
  // U+1369-1371 (Ethiopic digits one-nine) were Nd — \\d matches
395
442
  // &#x1371; and \\D rejects it even though the host tables (4.0.1+)
@@ -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.399",
4
+ "version": "1.9.401",
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,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: leptris
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.399.0
4
+ version: 1.9.401.0
5
5
  platform: arm-linux
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-10-31 00:00:00.000000000 Z
11
+ date: 2026-11-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi