leptris 1.9.390.2 → 1.9.391.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: ec92f0e6c7b71b0a72db8e812b67de6799e78b21d733c3de029dea60e433460c
4
- data.tar.gz: 9d0c460ecb7b79e3be5ab56d619f030b0acd4c7b0bff68152029b5f39acec8af
3
+ metadata.gz: be01b6e8aa9f7b7c51f9be514123f2f81578e69fc7b2ad702e7831fc0aeb424d
4
+ data.tar.gz: 2cbb5d3363d09d83352007193e42216570968760b7639bca21d78b7800aa73e2
5
5
  SHA512:
6
- metadata.gz: 8ff194f06b122d588af50825b60d44b695fcf670a47e83ad84be5d0992b9eab9445e3a8a40c1df307e6d0a13f3a75836fd637cfc6d2ab79a33cf8f367592702e
7
- data.tar.gz: 769c589b00fbb8b21e791dedba03761a1af8527e595115c7821f268b9b7f9588f86d5365d35cfd2caaba222226510fc93727bf93bb3c4d4b596b1a9f5ccc11f9
6
+ metadata.gz: c1c64ca2f128df857f8bdd76dd0abfdc87194f47f690efb148aa5ab62e9745b95c220a45ad82fb766c0d89b76f0026ed110417723410820abd13627d77696da0
7
+ data.tar.gz: 377c0b0ae5058d4bf8ba93e78922044fb428eb0f9666ab5fb0d3cea685575765d7b048141d469c8dab1ea478b2e9afd2b8c5780dce3bd85ea0822c101bc3a5f0
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ### Fixed
4
+
5
+ - Rebuild the native object under the Ruby that performs final packaging.
6
+ Restoring the job Ruby after the per-minor release loop could reuse the
7
+ last minor's object and overwrite the job minor's bundle with a different
8
+ Ruby header ABI. The packaging regression now exercises the same workspace
9
+ under Ruby 3.4, then 4.0, then 3.3 and checks the actual packaged native/GC paths.
10
+
3
11
  ### Added — 1.9.390.2 (namespace snapshot face)
4
12
 
5
13
  - **Element#namespace_declarations_snapshot (leptris-ruby#565).**
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.390"
11
+ LIBLEPTRIS_VERSION = "1.9.391"
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
@@ -290,7 +290,9 @@ task :compile do
290
290
  elsif %w[ruby truffleruby].include?(RUBY_ENGINE)
291
291
  ext_dir = "ext/leptris/native"
292
292
  Dir.chdir(ext_dir) do
293
- sh "ruby extconf.rb"
293
+ # Packaging restores the job Ruby after the per-minor release loop.
294
+ # Rebuild even when native.o is newer: it may use another Ruby's headers.
295
+ sh RbConfig.ruby, "extconf.rb"
294
296
  if RUBY_PLATFORM =~ /darwin/
295
297
  # Link the bundle ourselves: mkmf snapshots LIBRUBYARG from
296
298
  # RbConfig at require time, so setup-ruby's shared-libruby
@@ -300,18 +302,18 @@ task :compile do
300
302
  # Makefile, link with pure -undefined dynamic_lookup (Ruby
301
303
  # symbols resolve from the loading interpreter) and a
302
304
  # conservative deployment target.
303
- sh "make native.o"
305
+ sh "make -B native.o"
304
306
  sh "cc -dynamic -bundle -undefined dynamic_lookup " \
305
307
  "-mmacosx-version-min=#{ENV['MACOSX_DEPLOYMENT_TARGET'] || '11.0'} " \
306
308
  "-o native.bundle native.o"
307
309
  else
308
310
  # #207: the darwin contract on Linux too — mkmf's `make`
309
311
  # linked libruby.so.3.3 (plus a runner runpath), which
310
- # failed to load on 3.4/4.0. Link WITHOUT libruby: one
311
- # .so serves every Ruby minor; rb_* resolve from the
312
- # loading interpreter at dlopen (static rubies export
312
+ # failed to load on 3.4/4.0. Link WITHOUT libruby while
313
+ # keeping the building Ruby's header ABI: rb_* resolve from
314
+ # the loading interpreter at dlopen (static rubies export
313
315
  # their symbols via -rdynamic, like any extension .so).
314
- sh "make native.o"
316
+ sh "make -B native.o"
315
317
  sh "#{RbConfig::CONFIG['CC']} -shared -fPIC -o native.so native.o"
316
318
  end
317
319
  # Guard the linkage contract at the build chokepoint (#1739):
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Leptris
4
- VERSION = "1.9.390.2"
4
+ VERSION = "1.9.391.0"
5
5
  end
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.390
4
+ - libleptris v1.9.391
5
5
  - utf8proc v2.11.0
6
6
 
7
7
  Rebuild by hand:
@@ -1,5 +1,29 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.9.391] - 2026-10-30
4
+
5
+ ### Fixed
6
+
7
+ - **XSD: resolve attributeGroup ref rows the pre-pass captured
8
+ before its imports (leptris-ruby#569, PR #1906).** The #1880
9
+ attributeGroup pre-pass captures each unit's group defs *before*
10
+ that unit's imports are chased, so an `<xs:attribute ref="r:embed"/>`
11
+ row whose declaration lives in a later-imported unit found no
12
+ global attribute and was silently dropped. Types were left
13
+ hole-punched (whole-instance validation then rejected `a:blip
14
+ @r:embed` with "not declared (strict)" on the OOXML `wml.xsd`
15
+ chain — clean on 1.9.368.1, regressed by the 386-390 wave) or
16
+ attribute-less, which skipped the strict attribute walk entirely
17
+ and false-validated foreign attributes. Unresolved ref rows are
18
+ now kept pending — with the ref's own `use=` override recorded —
19
+ and re-resolved against the merged top-level attribute table once
20
+ the whole capture has run; row copies carry the flag so referencing
21
+ types heal too. Witness: the real uniword `wml.xsd` (1826
22
+ declarations) compiles clean and a docx-style document with
23
+ `a:blip r:embed` validates 1.
24
+
25
+
26
+
3
27
  ## [1.9.390] - 2026-10-29
4
28
 
5
29
  ### Fixed
@@ -3,7 +3,7 @@
3
3
  cmake_minimum_required(VERSION 3.20)
4
4
 
5
5
  project(leptris
6
- VERSION 1.9.390
6
+ VERSION 1.9.391
7
7
  DESCRIPTION "Fast XML parser and XPath evaluator in pure C"
8
8
  LANGUAGES C CXX
9
9
  )
@@ -100,6 +100,7 @@ static void xsd_capture_root(struct leptris_xsd_schema* s,
100
100
  LeptrisElement root);
101
101
  static char* xsd_read_file(const char* path, size_t* out_len);
102
102
  static XsdAttrDecl* xsd_copy_attr_rows(const XsdAttrDecl* src);
103
+ static void xsd_resolve_pending_attr_refs(struct leptris_xsd_schema* s);
103
104
  static void xsd_register_complex(struct leptris_xsd_schema* s,
104
105
  XsdCm* root, XsdAttrDecl* attrs,
105
106
  const char* name, char* any_attr_ns,
@@ -2021,6 +2022,7 @@ static LeptrisXsdSchema xsd_compile_impl(const char* xsd_text,
2021
2022
 
2022
2023
  xsd_capture_root(s, root);
2023
2024
  xsd_resolve_extension_bases(s);
2025
+ xsd_resolve_pending_attr_refs(s);
2024
2026
 
2025
2027
  leptris_document_free(doc);
2026
2028
  return s;
@@ -3109,6 +3111,7 @@ static XsdAttrDecl* xsd_copy_attr_rows(const XsdAttrDecl* src) {
3109
3111
  d->type = xsd_strdup(src->type);
3110
3112
  d->fixed = xsd_strdup(src->fixed);
3111
3113
  d->required = src->required;
3114
+ d->pending_ref = src->pending_ref;
3112
3115
  if (tail)
3113
3116
  tail->next = d;
3114
3117
  else
@@ -3118,6 +3121,51 @@ static XsdAttrDecl* xsd_copy_attr_rows(const XsdAttrDecl* src) {
3118
3121
  return head;
3119
3122
  }
3120
3123
 
3124
+ /* leptris-ruby#569: re-resolve the rows the #1880 attributeGroup
3125
+ * pre-pass captured before the import chase had registered the
3126
+ * referenced unit's top-level attributes. Idempotent; pending rows
3127
+ * that never resolve keep declaring their name (untyped) — the
3128
+ * compile-time ref check already rejects true danglers loudly. */
3129
+ #define XSD_PENDING_REF 1
3130
+ #define XSD_PENDING_USE 2
3131
+ static void xsd_resolve_pending_attr_refs(struct leptris_xsd_schema* s) {
3132
+ if (!s) return;
3133
+ int progressed = 1;
3134
+ while (progressed) {
3135
+ progressed = 0;
3136
+ for (XsdAttrGroupDef* g = s->attr_groups; g; g = g->next)
3137
+ for (XsdAttrDecl* a = g->attrs; a; a = a->next) {
3138
+ if (!(a->pending_ref & XSD_PENDING_REF) || !a->name)
3139
+ continue;
3140
+ const XsdAttrDecl* src = xsd_find_top_attr(s, a->name);
3141
+ if (!src) continue;
3142
+ free(a->type);
3143
+ free(a->fixed);
3144
+ a->type = xsd_strdup(src->type);
3145
+ a->fixed = xsd_strdup(src->fixed);
3146
+ if (!(a->pending_ref & XSD_PENDING_USE))
3147
+ a->required = src->required;
3148
+ a->pending_ref &= ~XSD_PENDING_REF;
3149
+ progressed = 1;
3150
+ }
3151
+ for (XsdTypeAttrs* t = s->type_attrs; t; t = t->next)
3152
+ for (XsdAttrDecl* a = t->attrs; a; a = a->next) {
3153
+ if (!(a->pending_ref & XSD_PENDING_REF) || !a->name)
3154
+ continue;
3155
+ const XsdAttrDecl* src = xsd_find_top_attr(s, a->name);
3156
+ if (!src) continue;
3157
+ free(a->type);
3158
+ free(a->fixed);
3159
+ a->type = xsd_strdup(src->type);
3160
+ a->fixed = xsd_strdup(src->fixed);
3161
+ if (!(a->pending_ref & XSD_PENDING_USE))
3162
+ a->required = src->required;
3163
+ a->pending_ref &= ~XSD_PENDING_REF;
3164
+ progressed = 1;
3165
+ }
3166
+ }
3167
+ }
3168
+
3121
3169
  /* Capture the attribute rows of a complexType or attributeGroup:
3122
3170
  * named rows, inline anonymous simpleTypes (synthesized slots),
3123
3171
  * refs to top-level attributes, and attributeGroup refs. */
@@ -3185,16 +3233,31 @@ static XsdAttrDecl* xsd_capture_attr_rows(struct leptris_xsd_schema* s,
3185
3233
  leptris_element_attribute(ae, "ref"));
3186
3234
  const XsdAttrDecl* src =
3187
3235
  ref ? xsd_find_top_attr(s, ref) : NULL;
3188
- if (!src) {
3236
+ if (!src && !ref) {
3189
3237
  free(d);
3190
3238
  continue;
3191
3239
  }
3192
- d->name = xsd_strdup(src->name);
3193
- d->type = xsd_strdup(src->type);
3194
- d->fixed = xsd_strdup(src->fixed);
3195
- d->required = use
3196
- ? (strcmp(use, "required") == 0)
3197
- : src->required;
3240
+ if (!src) {
3241
+ /* leptris-ruby#569: the #1880 pre-pass captures
3242
+ * attributeGroup defs BEFORE the import chase
3243
+ * registers the referenced unit's globals — an
3244
+ * unresolved ref used to be silently DROPPED
3245
+ * here, hole-punching the type's rows (a:blip
3246
+ * @r:embed "not declared (strict)") or leaving
3247
+ * the type attribute-less so the strict walk
3248
+ * never ran. Keep the row pending; the
3249
+ * post-capture fixup resolves it. */
3250
+ d->name = xsd_strdup(xsd_local_name(ref));
3251
+ d->pending_ref = use ? 3 : 1;
3252
+ d->required = (use && strcmp(use, "required") == 0);
3253
+ } else {
3254
+ d->name = xsd_strdup(src->name);
3255
+ d->type = xsd_strdup(src->type);
3256
+ d->fixed = xsd_strdup(src->fixed);
3257
+ d->required = use
3258
+ ? (strcmp(use, "required") == 0)
3259
+ : src->required;
3260
+ }
3198
3261
  }
3199
3262
  if (tail)
3200
3263
  tail->next = d;
@@ -3802,5 +3865,6 @@ LEPTRIS_API LeptrisXsdSchema leptris_xsd_compile_set(
3802
3865
  s->base_dir = saved;
3803
3866
  }
3804
3867
  xsd_resolve_extension_bases(s);
3868
+ xsd_resolve_pending_attr_refs(s);
3805
3869
  return s;
3806
3870
  }
@@ -197,6 +197,15 @@ typedef struct xsd_attr_decl {
197
197
  char* type; /* builtin ref or local simpleType name (NULL=anySimple) */
198
198
  char* fixed; /* #FIXED value: present values must string-equal it */
199
199
  int required;
200
+ /* leptris-ruby#569: the row came from <xs:attribute ref=.../>
201
+ * whose global declaration was not yet captured (the #1880
202
+ * attributeGroup pre-pass runs before the import chase). The
203
+ * row is kept — never silently dropped — and xsd_compile_impl
204
+ * re-resolves it once the full merged capture has run
205
+ * (xsd_resolve_pending_attr_refs). bit 0 = ref unresolved,
206
+ * bit 1 = the ref carried its own use= (it overrides the
207
+ * declaration's). */
208
+ int pending_ref;
200
209
  struct xsd_attr_decl* next;
201
210
  } XsdAttrDecl;
202
211
 
@@ -7,6 +7,7 @@
7
7
  #include <gtest/gtest.h>
8
8
 
9
9
  #include <cstdio>
10
+ #include <fstream>
10
11
  #include <cstring>
11
12
  #include <string>
12
13
  #include <algorithm>
@@ -3680,3 +3681,209 @@ TEST(XsdContent, Issue1894ReproStaysUnderCapAndCorrect) {
3680
3681
  EXPECT_EQ(leptris_xsd_error_count(s), 0u);
3681
3682
  leptris_xsd_free(s);
3682
3683
  }
3684
+
3685
+
3686
+ /* leptris-ruby#569 family: cross-namespace references into an
3687
+ * IMPORTED unit. The importing schema must declare xmlns="urn:a"
3688
+ * as the DEFAULT namespace — unprefixed ref QNames resolve to
3689
+ * no-namespace otherwise (spec behavior, the #1901 repro lesson). */
3690
+ TEST(XsdCrossNs, AttributeRefIntoImportedUnitResolves) {
3691
+ const char* rel =
3692
+ "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\""
3693
+ " targetNamespace=\"urn:r\" elementFormDefault=\"qualified\">"
3694
+ "<xs:simpleType name=\"ST_RelId\">"
3695
+ "<xs:restriction base=\"xs:string\"/></xs:simpleType>"
3696
+ "<xs:attribute name=\"embed\" type=\"ST_RelId\"/>"
3697
+ "</xs:schema>";
3698
+ const char* main =
3699
+ "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\""
3700
+ " xmlns:r=\"urn:r\" xmlns=\"urn:a\" targetNamespace=\"urn:a\""
3701
+ " elementFormDefault=\"qualified\">"
3702
+ "<xs:import namespace=\"urn:r\" schemaLocation=\"blip_repro_rel.xsd\"/>"
3703
+ "<xs:attributeGroup name=\"AG_Blob\">"
3704
+ "<xs:attribute ref=\"r:embed\" use=\"optional\"/>"
3705
+ "</xs:attributeGroup>"
3706
+ "<xs:complexType name=\"CT_Blip\">"
3707
+ "<xs:sequence><xs:element name=\"e\" type=\"xs:string\""
3708
+ " minOccurs=\"0\"/></xs:sequence>"
3709
+ "<xs:attributeGroup ref=\"AG_Blob\"/>"
3710
+ "</xs:complexType>"
3711
+ "<xs:element name=\"blip\" type=\"CT_Blip\"/>"
3712
+ "</xs:schema>";
3713
+
3714
+ const char* dir = std::getenv("TMPDIR");
3715
+ std::string base = dir ? dir : "/tmp";
3716
+ std::string rel_path = base + "/blip_repro_rel.xsd";
3717
+ std::string main_path = base + "/blip_repro_main.xsd";
3718
+ {
3719
+ std::ofstream f(rel_path);
3720
+ f << rel;
3721
+ }
3722
+ {
3723
+ std::ofstream f(main_path);
3724
+ f << main;
3725
+ }
3726
+ const char* paths[2] = {rel_path.c_str(), main_path.c_str()};
3727
+ LeptrisStatus st = LEPTRIS_OK;
3728
+ LeptrisXsdSchema s =
3729
+ leptris_xsd_compile_set(paths, 2, &st);
3730
+ if (st != LEPTRIS_OK || s == (LeptrisXsdSchema)0) {
3731
+ const char* err = s ? leptris_xsd_error(s) : "(no handle)";
3732
+ GTEST_FAIL() << "compile_set failed st=" << (int)st
3733
+ << " err=" << (err ? err : "(null)");
3734
+ }
3735
+
3736
+ EXPECT_EQ(validate_compiled(s,
3737
+ "<a:blip xmlns:a=\"urn:a\" xmlns:r=\"urn:r\""
3738
+ " r:embed=\"rId2\"><e>x</e></a:blip>"),
3739
+ 1)
3740
+ << "cross-unit attribute ref must resolve: "
3741
+ << leptris_xsd_error(s);
3742
+ std::remove(rel_path.c_str());
3743
+ std::remove(main_path.c_str());
3744
+ leptris_xsd_free(s);
3745
+ }
3746
+
3747
+ /* Same shape through the single-document import chase. */
3748
+ TEST(XsdCrossNs, SingleDocImportChaseResolves) {
3749
+ const char* rel =
3750
+ "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\""
3751
+ " targetNamespace=\"urn:r\" elementFormDefault=\"qualified\">"
3752
+ "<xs:simpleType name=\"ST_RelId\">"
3753
+ "<xs:restriction base=\"xs:string\"/></xs:simpleType>"
3754
+ "<xs:attribute name=\"embed\" type=\"ST_RelId\"/>"
3755
+ "</xs:schema>";
3756
+ const char* main =
3757
+ "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\""
3758
+ " xmlns:r=\"urn:r\" xmlns=\"urn:a\" targetNamespace=\"urn:a\""
3759
+ " elementFormDefault=\"qualified\">"
3760
+ "<xs:import namespace=\"urn:r\""
3761
+ " schemaLocation=\"blip_repro_rel.xsd\"/>"
3762
+ "<xs:attributeGroup name=\"AG_Blob\">"
3763
+ "<xs:attribute ref=\"r:embed\" use=\"optional\"/>"
3764
+ "</xs:attributeGroup>"
3765
+ "<xs:complexType name=\"CT_Blip\">"
3766
+ "<xs:sequence><xs:element name=\"e\" type=\"xs:string\""
3767
+ " minOccurs=\"0\"/></xs:sequence>"
3768
+ "<xs:attributeGroup ref=\"AG_Blob\"/>"
3769
+ "</xs:complexType>"
3770
+ "<xs:element name=\"blip\" type=\"CT_Blip\"/>"
3771
+ "</xs:schema>";
3772
+
3773
+ const char* dir = std::getenv("TMPDIR");
3774
+ std::string base = dir ? dir : "/tmp";
3775
+ std::string rel_path = base + "/blip_repro_rel.xsd";
3776
+ std::string main_path = base + "/blip_repro_main.xsd";
3777
+ {
3778
+ std::ofstream f(rel_path);
3779
+ f << rel;
3780
+ }
3781
+ {
3782
+ std::ofstream f(main_path);
3783
+ f << main;
3784
+ }
3785
+ LeptrisStatus st = LEPTRIS_OK;
3786
+ LeptrisXsdSchema s =
3787
+ leptris_xsd_compile_file(main_path.c_str(), &st);
3788
+ if (st != LEPTRIS_OK || s == (LeptrisXsdSchema)0) {
3789
+ const char* err = s ? leptris_xsd_error(s) : "(no handle)";
3790
+ GTEST_FAIL() << "single-doc compile failed st=" << (int)st
3791
+ << " err=" << (err ? err : "(null)");
3792
+ }
3793
+
3794
+ EXPECT_EQ(validate_compiled(s,
3795
+ "<a:blip xmlns:a=\"urn:a\" xmlns:r=\"urn:r\""
3796
+ " r:embed=\"rId2\"><e>x</e></a:blip>"),
3797
+ 1)
3798
+ << "import-chase attribute ref must resolve: "
3799
+ << leptris_xsd_error(s);
3800
+ std::remove(rel_path.c_str());
3801
+ std::remove(main_path.c_str());
3802
+ leptris_xsd_free(s);
3803
+ }
3804
+
3805
+ /* The #569 regression itself: the #1880 attributeGroup pre-pass
3806
+ * captured AG_Blob and resolved its <xs:attribute ref="r:embed"/>
3807
+ * row BEFORE the import chase registered the referenced unit's
3808
+ * r:embed — the row used to be silently dropped, so whole-instance
3809
+ * validation then rejected every a:blip @r:embed ("not declared
3810
+ * (strict)") on the real DrawingML chain. The row must survive as
3811
+ * pending and resolve once the full capture has run. */
3812
+ TEST(XsdCrossNs, AttrGroupRefRowResolvedAfterImportChase) {
3813
+ const char* rel =
3814
+ "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\""
3815
+ " targetNamespace=\"urn:r\" elementFormDefault=\"qualified\">"
3816
+ "<xs:attribute name=\"embed\" type=\"xs:string\"/>"
3817
+ "</xs:schema>";
3818
+ const char* main =
3819
+ "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\""
3820
+ " xmlns:r=\"urn:r\" xmlns=\"urn:a\" targetNamespace=\"urn:a\""
3821
+ " elementFormDefault=\"qualified\">"
3822
+ "<xs:import namespace=\"urn:r\" schemaLocation=\"ag569_rel.xsd\"/>"
3823
+ "<xs:attributeGroup name=\"AG_Blob\">"
3824
+ "<xs:attribute ref=\"r:embed\"/>"
3825
+ "</xs:attributeGroup>"
3826
+ "<xs:complexType name=\"CT_Blip\">"
3827
+ "<xs:sequence><xs:element name=\"e\" type=\"xs:string\""
3828
+ " minOccurs=\"0\"/></xs:sequence>"
3829
+ "<xs:attributeGroup ref=\"AG_Blob\"/>"
3830
+ "</xs:complexType>"
3831
+ "<xs:element name=\"blip\" type=\"CT_Blip\"/>"
3832
+ "</xs:schema>";
3833
+
3834
+ const char* dir = std::getenv("TMPDIR");
3835
+ std::string base = dir ? dir : "/tmp";
3836
+ std::string rel_path = base + "/ag569_rel.xsd";
3837
+ std::string main_path = base + "/ag569_main.xsd";
3838
+ {
3839
+ std::ofstream f(rel_path);
3840
+ f << rel;
3841
+ }
3842
+ {
3843
+ std::ofstream f(main_path);
3844
+ f << main;
3845
+ }
3846
+ LeptrisStatus st = LEPTRIS_OK;
3847
+ LeptrisXsdSchema s =
3848
+ leptris_xsd_compile_file(main_path.c_str(), &st);
3849
+ ASSERT_NE(s, (LeptrisXsdSchema)0);
3850
+ const char* err = leptris_xsd_error(s);
3851
+ ASSERT_EQ(st, LEPTRIS_OK)
3852
+ << "compile failed: " << (err ? err : "(null)");
3853
+
3854
+ EXPECT_EQ(validate_compiled(s,
3855
+ "<a:blip xmlns:a=\"urn:a\" xmlns:r=\"urn:r\""
3856
+ " r:embed=\"rId2\"><e>x</e></a:blip>"),
3857
+ 1)
3858
+ << "pre-pass ref row must resolve after the import chase: "
3859
+ << leptris_xsd_error(s);
3860
+ std::remove(rel_path.c_str());
3861
+ std::remove(main_path.c_str());
3862
+ leptris_xsd_free(s);
3863
+ }
3864
+
3865
+ /* leptris-ruby#569: compiling the REAL wml.xsd (ISO transitional,
3866
+ * 790 element decls, import chain to the drawing units) must yield
3867
+ * a cleanly compiled schema — a missing import file poisons the
3868
+ * graph (the '{mce}Ignorable' class), and the merged capture must
3869
+ * carry every unit. The schema set is bundled at $BLIP_CHAIN_DIR
3870
+ * in dev; CI skips when the fixture is absent so the suite stays
3871
+ * hermetic. */
3872
+ TEST(XsdCrossNs, RealWmlChainCompilesDeclarations) {
3873
+ const char* dir = std::getenv("BLIP_CHAIN_DIR");
3874
+ if (!dir || *dir == '\0') {
3875
+ GTEST_SKIP() << "BLIP_CHAIN_DIR not set";
3876
+ }
3877
+ std::string wml = std::string(dir) + "/wml.xsd";
3878
+ std::ifstream f(wml);
3879
+ ASSERT_TRUE(f.good()) << wml;
3880
+ LeptrisStatus st = LEPTRIS_OK;
3881
+ LeptrisXsdSchema s = leptris_xsd_compile_file(wml.c_str(), &st);
3882
+ ASSERT_NE(s, (LeptrisXsdSchema)0);
3883
+ const char* err = leptris_xsd_error(s);
3884
+ EXPECT_EQ(st, LEPTRIS_OK)
3885
+ << "compile status " << (int)st
3886
+ << " decls=" << leptris_xsd_declaration_count(s)
3887
+ << " err=" << (err ? err : "(clean)");
3888
+ leptris_xsd_free(s);
3889
+ }
@@ -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.390",
4
+ "version": "1.9.391",
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.390.2
4
+ version: 1.9.391.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-10-29 00:00:00.000000000 Z
11
+ date: 2026-10-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi