lutaml-model 0.8.17 → 0.8.19
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 +4 -4
- data/.github/workflows/downstream-performance.yml +27 -1
- data/.github/workflows/js-pr-check.yml +102 -0
- data/.github/workflows/js-sync.yml +51 -0
- data/.github/workflows/opal.yml +26 -6
- data/.github/workflows/performance.yml +32 -7
- data/.github/workflows/rake.yml +78 -32
- data/.gitmodules +6 -0
- data/.rubocop_todo.yml +8 -0
- data/Gemfile +16 -1
- data/README.adoc +267 -0
- data/Rakefile +166 -4
- data/docs/_guides/builder-dsl.adoc +127 -0
- data/docs/_guides/schema-import.adoc +42 -0
- data/docs/_guides/xml-mapping.adoc +21 -0
- data/docs/_pages/validation.adoc +65 -0
- data/lib/compat/opal/generate_boot.rb +123 -0
- data/lib/compat/opal/js_bundle_entry.rb +42 -0
- data/lib/compat/opal/lutaml_model_boot.rb +497 -0
- data/lib/compat/opal/moxml_boot.rb +68 -0
- data/lib/compat/opal/yaml_compat.rb +32 -0
- data/lib/lutaml/json.rb +1 -1
- data/lib/lutaml/key_value/transform.rb +3 -8
- data/lib/lutaml/key_value/transformation/value_serializer.rb +14 -1
- data/lib/lutaml/key_value/transformation.rb +17 -5
- data/lib/lutaml/model/adapter_resolver.rb +2 -2
- data/lib/lutaml/model/attribute.rb +88 -11
- data/lib/lutaml/model/cached_type_resolver.rb +1 -1
- data/lib/lutaml/model/error/union_schema_unsupported_error.rb +11 -0
- data/lib/lutaml/model/global_context.rb +11 -8
- data/lib/lutaml/model/instrumentation.rb +2 -2
- data/lib/lutaml/model/mapping/mapping_rule.rb +0 -6
- data/lib/lutaml/model/register.rb +2 -2
- data/lib/lutaml/model/runtime_compatibility.rb +50 -0
- data/lib/lutaml/model/schema/class_loader.rb +58 -0
- data/lib/lutaml/model/schema/compiled_output.rb +83 -0
- data/lib/lutaml/model/schema/definitions/attribute.rb +32 -0
- data/lib/lutaml/model/schema/definitions/choice.rb +20 -0
- data/lib/lutaml/model/schema/definitions/facet.rb +40 -0
- data/lib/lutaml/model/schema/definitions/group_import.rb +22 -0
- data/lib/lutaml/model/schema/definitions/member_walk.rb +33 -0
- data/lib/lutaml/model/schema/definitions/model.rb +40 -0
- data/lib/lutaml/model/schema/definitions/namespace.rb +23 -0
- data/lib/lutaml/model/schema/definitions/restricted_type.rb +30 -0
- data/lib/lutaml/model/schema/definitions/sequence.rb +19 -0
- data/lib/lutaml/model/schema/definitions/simple_content.rb +22 -0
- data/lib/lutaml/model/schema/definitions/transform_facet.rb +21 -0
- data/lib/lutaml/model/schema/definitions/type_ref.rb +20 -0
- data/lib/lutaml/model/schema/definitions/union_type.rb +28 -0
- data/lib/lutaml/model/schema/definitions/xml_root.rb +20 -0
- data/lib/lutaml/model/schema/definitions.rb +24 -0
- data/lib/lutaml/model/schema/file_writer.rb +70 -0
- data/lib/lutaml/model/schema/generator/definitions_collection.rb +16 -2
- data/lib/lutaml/model/schema/generator/property.rb +21 -4
- data/lib/lutaml/model/schema/module_nesting.rb +31 -0
- data/lib/lutaml/model/schema/namespace_naming.rb +46 -0
- data/lib/lutaml/model/schema/registry_generator.rb +115 -0
- data/lib/lutaml/model/schema/renderers/base.rb +40 -0
- data/lib/lutaml/model/schema/renderers/mappings.rb +72 -0
- data/lib/lutaml/model/schema/renderers/member_decls.rb +115 -0
- data/lib/lutaml/model/schema/renderers/model.rb +121 -0
- data/lib/lutaml/model/schema/renderers/namespace.rb +30 -0
- data/lib/lutaml/model/schema/renderers/registration.rb +64 -0
- data/lib/lutaml/model/schema/renderers/required_files_calculator.rb +93 -0
- data/lib/lutaml/model/schema/renderers/restricted_type.rb +88 -0
- data/lib/lutaml/model/schema/renderers/union.rb +83 -0
- data/lib/lutaml/model/schema/renderers.rb +19 -0
- data/lib/lutaml/model/schema/rnc_compiler/source_resolver.rb +47 -0
- data/lib/lutaml/model/schema/rnc_compiler.rb +62 -0
- data/lib/lutaml/model/schema/rng_compiler/define_classifier.rb +91 -0
- data/lib/lutaml/model/schema/rng_compiler/element_visitor.rb +392 -0
- data/lib/lutaml/model/schema/rng_compiler/member_collector.rb +30 -0
- data/lib/lutaml/model/schema/rng_compiler/rng_helpers.rb +152 -0
- data/lib/lutaml/model/schema/rng_compiler/value_type_resolver.rb +125 -0
- data/lib/lutaml/model/schema/rng_compiler.rb +220 -0
- data/lib/lutaml/model/schema/templates.rb +162 -0
- data/lib/lutaml/model/schema/xml_compiler/element_order.rb +41 -0
- data/lib/lutaml/model/schema/xml_compiler/registry_generator.rb +31 -107
- data/lib/lutaml/model/schema/xml_compiler/spec_builder/complex_types.rb +191 -0
- data/lib/lutaml/model/schema/xml_compiler/spec_builder/members.rb +216 -0
- data/lib/lutaml/model/schema/xml_compiler/spec_builder/simple_types.rb +153 -0
- data/lib/lutaml/model/schema/xml_compiler/spec_builder.rb +167 -0
- data/lib/lutaml/model/schema/xml_compiler/supported_data_types.rb +87 -0
- data/lib/lutaml/model/schema/xml_compiler.rb +38 -517
- data/lib/lutaml/model/schema.rb +19 -0
- data/lib/lutaml/model/serialize/attribute_definition.rb +23 -11
- data/lib/lutaml/model/serialize/builder.rb +70 -2
- data/lib/lutaml/model/serialize/initialization.rb +3 -2
- data/lib/lutaml/model/serialize/value_mapping.rb +9 -57
- data/lib/lutaml/model/serialize.rb +6 -9
- data/lib/lutaml/model/services/rule_value_extractor.rb +2 -3
- data/lib/lutaml/model/services.rb +0 -2
- data/lib/lutaml/model/store.rb +2 -1
- data/lib/lutaml/model/toml.rb +1 -1
- data/lib/lutaml/model/transform.rb +17 -39
- data/lib/lutaml/model/transformation_registry.rb +1 -1
- data/lib/lutaml/model/type.rb +1 -0
- data/lib/lutaml/model/union.rb +320 -0
- data/lib/lutaml/model/utils.rb +6 -0
- data/lib/lutaml/model/validation.rb +1 -4
- data/lib/lutaml/model/version.rb +1 -1
- data/lib/lutaml/model.rb +18 -0
- data/lib/lutaml/toml.rb +1 -1
- data/lib/lutaml/xml/adapter.rb +1 -1
- data/lib/lutaml/xml/adapter_loader.rb +1 -1
- data/lib/lutaml/xml/builder/base.rb +1 -1
- data/lib/lutaml/xml/builder.rb +1 -1
- data/lib/lutaml/xml/error/schema_validation_error.rb +25 -0
- data/lib/lutaml/xml/model_transform.rb +5 -1
- data/lib/lutaml/xml/schema/relaxng_schema.rb +5 -0
- data/lib/lutaml/xml/schema/xsd_schema.rb +4 -0
- data/lib/lutaml/xml/serialization/format_conversion.rb +48 -0
- data/lib/lutaml/xml/serialization/instance_methods.rb +13 -0
- data/lib/lutaml/xml/transformation/element_builder.rb +21 -8
- data/lib/lutaml/xml/transformation/ordered_applier.rb +104 -4
- data/lib/lutaml/xml/xsd_validator.rb +66 -0
- data/lib/lutaml/xml.rb +53 -12
- data/lutaml-model.gemspec +4 -2
- data/spec/fixtures/xml/schema/rnc/address_book.rnc +15 -0
- data/spec/fixtures/xml/schema/rnc/book_features.rnc +18 -0
- data/spec/fixtures/xml/schema/rnc/includes/book.rnc +6 -0
- data/spec/fixtures/xml/schema/rnc/includes/circular_a.rnc +8 -0
- data/spec/fixtures/xml/schema/rnc/includes/circular_b.rnc +8 -0
- data/spec/fixtures/xml/schema/rnc/includes/library.rnc +8 -0
- data/spec/fixtures/xml/schema/rng/address_book.rng +16 -0
- data/spec/fixtures/xml/schema/rng/book.rng +27 -0
- data/spec/fixtures/xml/schema/rng/fixed_value.rng +11 -0
- data/spec/fixtures/xml/schema/rng/fragment_in_choice.rng +30 -0
- data/spec/fixtures/xml/schema/rng/full_name.rng +39 -0
- data/spec/fixtures/xml/schema/rng/integer_range.rng +32 -0
- data/spec/fixtures/xml/schema/rng/list_type.rng +12 -0
- data/spec/fixtures/xml/schema/rng/namespaced.rng +9 -0
- data/spec/fixtures/xml/schema/rng/paragraph.rng +13 -0
- data/spec/fixtures/xml/schema/rng/person.rng +23 -0
- data/spec/fixtures/xml/schema/rng/union.rng +14 -0
- data/spec/fixtures/xml/validate_xml_with_address.xsd +13 -0
- data/spec/fixtures/xml/validate_xml_with_contact.xsd +11 -0
- data/spec/fixtures/xml/validate_xml_with_person.xsd +11 -0
- data/spec/fixtures/xml/validate_xml_with_person_strict.xsd +17 -0
- data/spec/fixtures/xml/validate_xml_with_product.xsd +37 -0
- data/spec/lutaml/model/attribute_apply_value_map_spec.rb +134 -0
- data/spec/lutaml/model/attribute_spec.rb +169 -12
- data/spec/lutaml/model/boot_manifest_spec.rb +30 -0
- data/spec/lutaml/model/collection_spec.rb +18 -0
- data/spec/lutaml/model/mixed_content_spec.rb +171 -0
- data/spec/lutaml/model/opal_smoke_spec.rb +67 -2
- data/spec/lutaml/model/ordered_content_spec.rb +41 -0
- data/spec/lutaml/model/raw_element_spec.rb +125 -0
- data/spec/lutaml/model/rule_value_extractor_spec.rb +7 -14
- data/spec/lutaml/model/runtime_compatibility_spec.rb +25 -0
- data/spec/lutaml/model/schema/renderers/model_spec.rb +149 -0
- data/spec/lutaml/model/schema/renderers/namespace_spec.rb +36 -0
- data/spec/lutaml/model/schema/renderers/restricted_type_spec.rb +75 -0
- data/spec/lutaml/model/schema/renderers/union_spec.rb +58 -0
- data/spec/lutaml/model/serialize/builder_spec.rb +358 -0
- data/spec/lutaml/model/transform_apply_value_map_spec.rb +64 -0
- data/spec/lutaml/model/union_attribute_spec.rb +658 -0
- data/spec/lutaml/model/union_spec.rb +257 -0
- data/spec/lutaml/model/utils_spec.rb +14 -0
- data/spec/lutaml/xml/opal_xml_spec.rb +22 -20
- data/spec/lutaml/xml/schema/compiler_spec.rb +21 -4
- data/spec/lutaml/xml/schema/rnc_compiler_spec.rb +404 -0
- data/spec/lutaml/xml/schema/rng_compiler_spec.rb +893 -0
- data/spec/lutaml/xml/validate_xml_with_constructs_spec.rb +222 -0
- data/spec/lutaml/xml/validate_xml_with_spec.rb +186 -0
- data/spec/spec_helper.rb +28 -11
- data/spec/support/opal.rb +5 -2
- metadata +99 -31
- data/lib/lutaml/model/schema/xml_compiler/attribute.rb +0 -106
- data/lib/lutaml/model/schema/xml_compiler/attribute_group.rb +0 -47
- data/lib/lutaml/model/schema/xml_compiler/choice.rb +0 -67
- data/lib/lutaml/model/schema/xml_compiler/complex_content.rb +0 -27
- data/lib/lutaml/model/schema/xml_compiler/complex_content_restriction.rb +0 -34
- data/lib/lutaml/model/schema/xml_compiler/complex_type.rb +0 -173
- data/lib/lutaml/model/schema/xml_compiler/element.rb +0 -121
- data/lib/lutaml/model/schema/xml_compiler/group.rb +0 -113
- data/lib/lutaml/model/schema/xml_compiler/restriction.rb +0 -104
- data/lib/lutaml/model/schema/xml_compiler/sequence.rb +0 -52
- data/lib/lutaml/model/schema/xml_compiler/simple_content.rb +0 -40
- data/lib/lutaml/model/schema/xml_compiler/simple_type.rb +0 -265
- data/lib/lutaml/model/schema/xml_compiler/xml_namespace_class.rb +0 -110
- data/lib/lutaml/model/services/default_value_resolver.rb +0 -60
- data/spec/lutaml/model/services/default_value_resolver_spec.rb +0 -162
- data/spec/lutaml/xml/schema/compiler/attribute_group_spec.rb +0 -71
- data/spec/lutaml/xml/schema/compiler/attribute_spec.rb +0 -67
- data/spec/lutaml/xml/schema/compiler/choice_spec.rb +0 -74
- data/spec/lutaml/xml/schema/compiler/complex_content_restriction_spec.rb +0 -60
- data/spec/lutaml/xml/schema/compiler/complex_content_spec.rb +0 -41
- data/spec/lutaml/xml/schema/compiler/complex_type_spec.rb +0 -202
- data/spec/lutaml/xml/schema/compiler/element_spec.rb +0 -68
- data/spec/lutaml/xml/schema/compiler/group_spec.rb +0 -90
- data/spec/lutaml/xml/schema/compiler/restriction_spec.rb +0 -77
- data/spec/lutaml/xml/schema/compiler/sequence_spec.rb +0 -65
- data/spec/lutaml/xml/schema/compiler/simple_content_spec.rb +0 -61
- data/spec/lutaml/xml/schema/compiler/simple_type_spec.rb +0 -184
data/docs/_pages/validation.adoc
CHANGED
|
@@ -72,6 +72,71 @@ The `required: true` option validates that an attribute is present.
|
|
|
72
72
|
attribute :name, :string, required: true
|
|
73
73
|
----
|
|
74
74
|
|
|
75
|
+
=== XML schema validation
|
|
76
|
+
|
|
77
|
+
The `validate_xml_with` class macro validates the model's generated XML
|
|
78
|
+
against one or more XML Schema (XSD) files during `validate` / `validate!`.
|
|
79
|
+
|
|
80
|
+
[source,ruby]
|
|
81
|
+
----
|
|
82
|
+
class Person < Lutaml::Model::Serializable
|
|
83
|
+
attribute :name, :string
|
|
84
|
+
|
|
85
|
+
xml do
|
|
86
|
+
root "person"
|
|
87
|
+
map_element "name", to: :name
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
validate_xml_with "schemas/person.xsd"
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
person = Person.new(name: "Alice")
|
|
94
|
+
person.validate # => collects Lutaml::Xml::Error::SchemaValidationError
|
|
95
|
+
# instances when the generated XML does not conform
|
|
96
|
+
person.validate! # => raises Lutaml::Model::ValidationError on nonconformance
|
|
97
|
+
----
|
|
98
|
+
|
|
99
|
+
The macro accepts one or more schema paths, and repeated calls append to the
|
|
100
|
+
configured list. Subclasses inherit the parent's schema paths parent-first;
|
|
101
|
+
paths added by a subclass do not affect the parent.
|
|
102
|
+
|
|
103
|
+
[source,ruby]
|
|
104
|
+
----
|
|
105
|
+
validate_xml_with "schemas/base.xsd", "schemas/extensions.xsd"
|
|
106
|
+
----
|
|
107
|
+
|
|
108
|
+
Raw XML strings can be checked against the same schemas with the explicit
|
|
109
|
+
class-level helpers, for example to reject nonconforming input before
|
|
110
|
+
`from_xml`:
|
|
111
|
+
|
|
112
|
+
[source,ruby]
|
|
113
|
+
----
|
|
114
|
+
Person.validate_xml(xml_string) # => array of schema validation errors
|
|
115
|
+
Person.validate_xml!(xml_string) # => raises Lutaml::Model::ValidationError
|
|
116
|
+
----
|
|
117
|
+
|
|
118
|
+
NOTE: `to_xml` and `from_xml` never validate implicitly. Call `validate!`
|
|
119
|
+
before serializing, or `validate_xml!` on incoming XML, when enforcement is
|
|
120
|
+
needed — the same explicit contract as every other validation type.
|
|
121
|
+
|
|
122
|
+
XSD validation uses Nokogiri, which is required lazily on first validation.
|
|
123
|
+
The schemas must be local files declared explicitly; `xsi:schemaLocation`
|
|
124
|
+
in documents is not read and remote schemas are not fetched. Relative paths
|
|
125
|
+
resolve against the file that declares `validate_xml_with`, so a model works
|
|
126
|
+
regardless of the process working directory.
|
|
127
|
+
|
|
128
|
+
Misconfiguration raises instead of being collected as validation errors:
|
|
129
|
+
|
|
130
|
+
* a missing schema file raises `Errno::ENOENT`;
|
|
131
|
+
* a malformed XSD raises `Nokogiri::XML::SyntaxError`;
|
|
132
|
+
* a malformed XML string passed to `validate_xml` / `validate_xml!` raises
|
|
133
|
+
`Nokogiri::XML::SyntaxError` — parsing is strict, so malformed input is
|
|
134
|
+
never silently repaired and reported as conforming;
|
|
135
|
+
* a missing nokogiri gem raises `Lutaml::Xml::Error::XmlConfigurationError`;
|
|
136
|
+
* a class using the macro without an XML root mapping raises
|
|
137
|
+
`Lutaml::Model::TypeOnlyMappingError` from `validate`, since validation
|
|
138
|
+
must serialize the model to check it.
|
|
139
|
+
|
|
75
140
|
|
|
76
141
|
== Validation examples
|
|
77
142
|
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# frozen_string: true
|
|
2
|
+
|
|
3
|
+
# One-shot generator for lib/compat/opal/lutaml_model_boot.rb.
|
|
4
|
+
#
|
|
5
|
+
# Walks lib/lutaml/**/*.rb and extracts every `autoload :Name, "path"`
|
|
6
|
+
# declaration (single-line or multi-line), resolving the standard
|
|
7
|
+
# `"#{__dir__}/..."` and `"#{File.dirname(__FILE__)}/..."` interpolation
|
|
8
|
+
# patterns relative to the declaring file's directory.
|
|
9
|
+
#
|
|
10
|
+
# Opal treats autoload as a no-op, so every autoload target must appear
|
|
11
|
+
# here as an explicit `require` for nested constants to resolve at runtime.
|
|
12
|
+
#
|
|
13
|
+
# Run after adding/removing any autoload in lib/lutaml/:
|
|
14
|
+
# ruby lib/compat/opal/generate_boot.rb
|
|
15
|
+
|
|
16
|
+
require "pathname"
|
|
17
|
+
|
|
18
|
+
REPO_ROOT = Pathname.new(File.expand_path("../../..", __dir__))
|
|
19
|
+
LIB = REPO_ROOT.join("lib")
|
|
20
|
+
|
|
21
|
+
# Patterns excluded under Opal because they pull in native-only deps
|
|
22
|
+
# (Nokogiri/Ox C extensions, Thor CLI, etc.). REXML is pure Ruby and
|
|
23
|
+
# ships in the bundled gem + moxml's lib/compat/opal/rexml/* shadows,
|
|
24
|
+
# so it is NOT excluded — it is a fully working second Opal adapter.
|
|
25
|
+
NATIVE_ONLY_PATTERNS = [
|
|
26
|
+
%r{(nokogiri|ox)_adapter\z},
|
|
27
|
+
%r{/schema/(relaxng|xsd)\b},
|
|
28
|
+
%r{/schema_builder/(nokogiri|oga)\b},
|
|
29
|
+
%r{/schema/builder/(nokogiri|oga)\b},
|
|
30
|
+
%r{\Alutaml/model/cli\z},
|
|
31
|
+
].freeze
|
|
32
|
+
|
|
33
|
+
# Match `autoload :Name, "...anything..."` where the string argument may
|
|
34
|
+
# span multiple physical lines (whitespace after the comma).
|
|
35
|
+
DECL_RE = /autoload\s+:[A-Za-z0-9_]+\s*,\s*"([^"]+)"/
|
|
36
|
+
|
|
37
|
+
# Stitches multi-line autoload declarations into a single logical line so
|
|
38
|
+
# DECL_RE can match. We only merge when the line ends right after the
|
|
39
|
+
# comma that follows `autoload :Name`.
|
|
40
|
+
def join_multiline_autoloads(src)
|
|
41
|
+
src.gsub(/(autoload\s+:[A-Za-z0-9_]+\s*,)\s*\n\s*/) { "#{Regexp.last_match(1)} " }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Resolve an autoload's raw string argument to a require path relative to
|
|
45
|
+
# LIB. Both common interpolation shapes resolve relative to the declaring
|
|
46
|
+
# file's directory, which is what MRI does for them.
|
|
47
|
+
def resolve_path(raw, declaring_file)
|
|
48
|
+
declaring_dir = Pathname.new(declaring_file).dirname
|
|
49
|
+
|
|
50
|
+
if raw.start_with?("\#{__dir__}/")
|
|
51
|
+
subdir = raw.sub("\#{__dir__}/", "").delete_suffix(".rb")
|
|
52
|
+
(declaring_dir + subdir).relative_path_from(LIB).to_s.delete_suffix(".rb")
|
|
53
|
+
elsif raw.start_with?("\#{File.dirname(__FILE__)}/")
|
|
54
|
+
subdir = raw.sub("\#{File.dirname(__FILE__)}/", "").delete_suffix(".rb")
|
|
55
|
+
(declaring_dir + subdir).relative_path_from(LIB).to_s.delete_suffix(".rb")
|
|
56
|
+
elsif raw.start_with?("lutaml/")
|
|
57
|
+
raw.delete_suffix(".rb")
|
|
58
|
+
else
|
|
59
|
+
raw.delete_suffix(".rb")
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
paths = []
|
|
64
|
+
Dir.glob("#{LIB}/lutaml/**/*.rb").each do |file|
|
|
65
|
+
src = File.read(file)
|
|
66
|
+
# Strip full-line and trailing comments so commented-out autoload
|
|
67
|
+
# examples (e.g. in type_registry.rb) don't end up in the boot file.
|
|
68
|
+
src = src.lines.reject { |line| line.lstrip.start_with?("#") }.join
|
|
69
|
+
join_multiline_autoloads(src).scan(DECL_RE).each do |(raw)|
|
|
70
|
+
paths << resolve_path(raw, file)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
paths = paths.uniq.sort
|
|
75
|
+
native_only = paths.select { |p| NATIVE_ONLY_PATTERNS.any? { |re| p =~ re } }
|
|
76
|
+
opal_paths = paths - native_only
|
|
77
|
+
|
|
78
|
+
# Order matters: namespace-defining entry files must load before any of
|
|
79
|
+
# their nested files. lutaml/model.rb declares the Lutaml::Model module
|
|
80
|
+
# (referenced by every other file); lutaml/xml.rb declares Lutaml::Xml.
|
|
81
|
+
# After the entry files, load by depth-then-name so a parent file (e.g.
|
|
82
|
+
# lutaml/hash_format.rb) is required before its children (e.g.
|
|
83
|
+
# lutaml/hash_format/adapter/document.rb).
|
|
84
|
+
#
|
|
85
|
+
# ENTRY_FILES are added unconditionally: they are top-level entry points
|
|
86
|
+
# that nothing else autoloads (because they ARE the entry points users
|
|
87
|
+
# require directly), so they would otherwise be missing from the list.
|
|
88
|
+
ENTRY_FILES = %w[lutaml/model lutaml/xml].freeze
|
|
89
|
+
remaining = (opal_paths - ENTRY_FILES).sort_by { |p| [p.count("/"), p] }
|
|
90
|
+
ordered = ENTRY_FILES + remaining
|
|
91
|
+
|
|
92
|
+
out = []
|
|
93
|
+
out << "# frozen_string_literal: true"
|
|
94
|
+
out << ""
|
|
95
|
+
out << "# DO NOT EDIT — regenerate with:"
|
|
96
|
+
out << "# ruby lib/compat/opal/generate_boot.rb"
|
|
97
|
+
out << "#"
|
|
98
|
+
out << "# Opal does not support Ruby autoload (it is a no-op at parse time)."
|
|
99
|
+
out << "# This file explicitly requires every autoload target in lib/lutaml/**"
|
|
100
|
+
out << "# so that nested constants resolve at runtime under Opal."
|
|
101
|
+
out << "#"
|
|
102
|
+
out << "# Native-only paths excluded under Opal:"
|
|
103
|
+
out << "# - nokogiri/ox/rexml adapters (C extensions unavailable)"
|
|
104
|
+
out << "# - XSD / RELAX NG schema generators (require Nokogiri)"
|
|
105
|
+
out << "# - lutaml/model/cli (thor-based, runtime-irrelevant under Opal)"
|
|
106
|
+
out << "#"
|
|
107
|
+
out << "# Ordering: lutaml/model and lutaml/xml define the Lutaml::Model and"
|
|
108
|
+
out << "# Lutaml::Xml namespaces, so they load first. Remaining paths are"
|
|
109
|
+
out << "# ordered by depth (shallower first) so parent files declare their"
|
|
110
|
+
out << "# child namespaces before children load."
|
|
111
|
+
out << "#"
|
|
112
|
+
out << "# Loaded by the Opal Rakefile before spec_helper."
|
|
113
|
+
out << ""
|
|
114
|
+
ordered.each { |p| out << %(require "#{p}") }
|
|
115
|
+
out << ""
|
|
116
|
+
|
|
117
|
+
# OPAL_BOOT_OUTPUT lets the in-sync guard spec regenerate to a temp path
|
|
118
|
+
# without clobbering the committed manifest; unset, it writes canonically.
|
|
119
|
+
target = ENV.fetch("OPAL_BOOT_OUTPUT") do
|
|
120
|
+
File.expand_path("lutaml_model_boot.rb", __dir__)
|
|
121
|
+
end
|
|
122
|
+
File.write(target, out.join("\n"))
|
|
123
|
+
warn "Generated #{ordered.size} requires (excluded #{native_only.size} native-only paths) -> #{target}"
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# JS bundle entry point. Pulls in the Opal-only compat shims and boot
|
|
4
|
+
# files BEFORE lutaml/model so that moxml's adapter constants, the
|
|
5
|
+
# String/Encoding/YAML/Array#pack patches, and the eager-loaded
|
|
6
|
+
# Moxml::* / Lutaml::* constants are all in place by the time
|
|
7
|
+
# lib/lutaml/model.rb runs.
|
|
8
|
+
#
|
|
9
|
+
# Used by scripts/build.rb as the bundle ENTRY (instead of
|
|
10
|
+
# "lutaml/model" directly) so the JS bundle mirrors the load order
|
|
11
|
+
# that lutaml-model's Rakefile applies for `rake spec:opal`.
|
|
12
|
+
|
|
13
|
+
if RUBY_ENGINE == "opal"
|
|
14
|
+
# 0. runtime_compatibility first: it stubs Mutex/ConditionVariable/
|
|
15
|
+
# Thread/WeakRef and patches Module#prepend for Opal. Oga's LRU
|
|
16
|
+
# and other gems reference Mutex at file-load time, so this must
|
|
17
|
+
# run before any gem that touches thread-safety primitives.
|
|
18
|
+
require "lutaml/model/runtime_compatibility"
|
|
19
|
+
|
|
20
|
+
# 0a. Opal's stdlib StringIO < IO loads here so moxml's
|
|
21
|
+
# `class StringIO` (bare, no parent) in rexml_compat.rb re-opens
|
|
22
|
+
# the existing class instead of conflicting with `< ::IO`.
|
|
23
|
+
# Without this, the bare-class definition runs first and Opal's
|
|
24
|
+
# `< IO` definition later raises "superclass mismatch".
|
|
25
|
+
require "stringio"
|
|
26
|
+
|
|
27
|
+
# 1. stdlib shims: String/Encoding/StringIO + Array#pack + nodejs/yaml
|
|
28
|
+
require "rexml_compat"
|
|
29
|
+
require "yaml_compat"
|
|
30
|
+
|
|
31
|
+
# 2. forks' Opal-aware conditionals select the pure-Ruby lexer
|
|
32
|
+
require "oga"
|
|
33
|
+
require "ll/setup"
|
|
34
|
+
|
|
35
|
+
# 3. eager-load boots (Opal ignores autoload)
|
|
36
|
+
require "moxml_boot"
|
|
37
|
+
require "lutaml_model_boot"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# 4. the actual entry point
|
|
41
|
+
require "lutaml/model"
|
|
42
|
+
require "lutaml/xml"
|