expressir 2.4.31-x86_64-linux → 2.4.35-x86_64-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 +4 -4
- data/TODO.eengine/00-overview.md +39 -0
- data/TODO.eengine/01-resolution-diagnostics.md +30 -0
- data/TODO.eengine/02-check-catalog-completion.md +53 -0
- data/TODO.eengine/03-entity-computations.md +22 -0
- data/TODO.eengine/04-shtolo-rule-audit.md +32 -0
- data/TODO.eengine/05-shtolo-longform-flatten.md +12 -0
- data/TODO.eengine/06-population-p21.md +34 -0
- data/TODO.eengine/07-schema-compare-patch.md +25 -0
- data/TODO.eengine/08-official-corpus-gate.md +7 -0
- data/TODO.eengine/09-mim-mapping-parser.md +9 -0
- data/TODO.parity-ee/00-overview.md +1 -1
- data/TODO.suma-improvements/07-part28-xml.md +10 -13
- data/lib/expressir/3.2/expressir_core.so +0 -0
- data/lib/expressir/3.3/expressir_core.so +0 -0
- data/lib/expressir/3.4/expressir_core.so +0 -0
- data/lib/expressir/4.0/expressir_core.so +0 -0
- data/lib/expressir/cli.rb +7 -0
- data/lib/expressir/commands/smrl_xml_index.rb +25 -0
- data/lib/expressir/commands.rb +1 -0
- data/lib/expressir/express/builder.rb +17 -5
- data/lib/expressir/express/builders/entity_decl_builder.rb +17 -5
- data/lib/expressir/express/checker.rb +191 -3
- data/lib/expressir/express/formatters/declarations_formatter.rb +21 -14
- data/lib/expressir/express/pretty_formatter.rb +9 -14
- data/lib/expressir/express/schema_compare.rb +194 -0
- data/lib/expressir/express/shtolo.rb +194 -63
- data/lib/expressir/express.rb +2 -0
- data/lib/expressir/model/declarations/entity.rb +132 -0
- data/lib/expressir/model/declarations/schema.rb +37 -6
- data/lib/expressir/p21/builder.rb +92 -0
- data/lib/expressir/p21/grammar.rb +107 -0
- data/lib/expressir/p21/parser.rb +16 -0
- data/lib/expressir/p21/population.rb +35 -0
- data/lib/expressir/p21/validator.rb +213 -0
- data/lib/expressir/p21.rb +17 -0
- data/lib/expressir/version.rb +1 -1
- data/lib/expressir.rb +1 -0
- metadata +20 -2
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "parsanol"
|
|
4
|
+
|
|
5
|
+
module Expressir
|
|
6
|
+
module P21
|
|
7
|
+
# ISO 10303-21 exchange-structure grammar (TODO.eengine/06 step 1).
|
|
8
|
+
# Parses the HEADER section and the DATA section's instance list
|
|
9
|
+
# into a capture tree; {Expressir::P21::PopulationBuilder} turns
|
|
10
|
+
# the tree into a {Expressir::P21::Population}.
|
|
11
|
+
#
|
|
12
|
+
# Reference: ISO 10303-21 exchange structure grammar
|
|
13
|
+
# (`~/src/mn/iso-10303-detached-docs/sources/iso-10303-21*/`);
|
|
14
|
+
# scope ladder in TODO.eengine/06 — the supported subset is the
|
|
15
|
+
# header FILE_* entities plus simple/complex data instances with
|
|
16
|
+
# lists, typed parameters, references, enumerations, binaries,
|
|
17
|
+
# strings, unset ($) and derived (*).
|
|
18
|
+
class Grammar < Parsanol::Parser
|
|
19
|
+
root(:exchange_structure)
|
|
20
|
+
|
|
21
|
+
rule(:comment) { str("/*") >> (str("*/").absent? >> any).repeat >> str("*/") }
|
|
22
|
+
rule(:ws?) { (match[" \t\r\n"] | comment).repeat }
|
|
23
|
+
rule(:ws1) { (match[" \t\r\n"] | comment).repeat(1) }
|
|
24
|
+
rule(:keyword) { match["!"].maybe >> match["A-Za-z0-9_"].repeat(1) }
|
|
25
|
+
rule(:entity_instance_name) { str("#") >> match["0-9"].repeat(1) }
|
|
26
|
+
|
|
27
|
+
rule(:string_literal) do
|
|
28
|
+
# ISO 10303-21: doubled quotes are escaped quotes
|
|
29
|
+
str("'") >> ((str("'").absent? >> any) | str("''")).repeat >> str("'")
|
|
30
|
+
end
|
|
31
|
+
rule(:binary_literal) { str('"') >> match["0-9A-Fa-f"].repeat >> str('"') }
|
|
32
|
+
rule(:enumeration) { str(".") >> match["A-Za-z0-9_"].repeat(1) >> str(".") }
|
|
33
|
+
rule(:unset) { str("$") }
|
|
34
|
+
rule(:derived) { str("*") }
|
|
35
|
+
|
|
36
|
+
rule(:parameter_list) do
|
|
37
|
+
str("(") >> ws? >>
|
|
38
|
+
(parameter.as(:parameter) >>
|
|
39
|
+
(str(",") >> ws? >> parameter.as(:parameter)).repeat).maybe >>
|
|
40
|
+
str(")") >> ws?
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
rule(:typed_parameter) do
|
|
44
|
+
keyword.as(:keyword) >> ws? >> parameter_list.as(:parameter_list)
|
|
45
|
+
end
|
|
46
|
+
rule(:list_parameter) { parameter_list }
|
|
47
|
+
|
|
48
|
+
rule(:number_literal) do
|
|
49
|
+
match["+-"].maybe >> match["0-9"].repeat(1) >>
|
|
50
|
+
(str(".") >> match["0-9"].repeat(1)).maybe >>
|
|
51
|
+
(match["Ee"] >> match["+-"].maybe >> match["0-9"].repeat(1)).maybe
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
rule(:parameter) do
|
|
55
|
+
typed_parameter.as(:typed_parameter) |
|
|
56
|
+
list_parameter.as(:parameter_list) |
|
|
57
|
+
entity_instance_name.as(:entity_instance_name) |
|
|
58
|
+
number_literal.as(:number_literal) |
|
|
59
|
+
enumeration.as(:enumeration) |
|
|
60
|
+
binary_literal.as(:binary_literal) |
|
|
61
|
+
string_literal.as(:string_literal) |
|
|
62
|
+
unset.as(:unset) | derived.as(:derived)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
rule(:simple_record) do
|
|
66
|
+
keyword.as(:keyword) >> ws? >> parameter_list.as(:parameter_list)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
rule(:subsuper_record) do
|
|
70
|
+
str("(") >> ws? >> simple_record.as(:simple_record).repeat(1) >>
|
|
71
|
+
str(")") >> ws?
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
rule(:simple_entity_instance) do
|
|
75
|
+
(entity_instance_name.as(:entity_instance_name) >> ws? >>
|
|
76
|
+
str("=") >> ws? >> simple_record.as(:simple_record) >>
|
|
77
|
+
str(";") >> ws?).as(:simple_entity_instance)
|
|
78
|
+
end
|
|
79
|
+
rule(:complex_entity_instance) do
|
|
80
|
+
(entity_instance_name.as(:entity_instance_name) >> ws? >>
|
|
81
|
+
str("=") >> ws? >> subsuper_record.as(:subsuper_record) >>
|
|
82
|
+
str(";") >> ws?).as(:complex_entity_instance)
|
|
83
|
+
end
|
|
84
|
+
rule(:entity_instance) { complex_entity_instance | simple_entity_instance }
|
|
85
|
+
|
|
86
|
+
rule(:header_entity) do
|
|
87
|
+
simple_record.as(:simple_record) >> str(";") >> ws?
|
|
88
|
+
end
|
|
89
|
+
rule(:header_section) do
|
|
90
|
+
str("HEADER;") >> ws? >> header_entity.repeat(1).as(:header_entity) >>
|
|
91
|
+
str("ENDSEC;") >> ws?
|
|
92
|
+
end
|
|
93
|
+
rule(:data_section) do
|
|
94
|
+
str("DATA;") >> ws? >>
|
|
95
|
+
(str("(") >> ws? >> parameter >> str(");") >> ws?).maybe >>
|
|
96
|
+
entity_instance.repeat.as(:instance_list) >>
|
|
97
|
+
str("ENDSEC;") >> ws?
|
|
98
|
+
end
|
|
99
|
+
rule(:exchange_structure) do
|
|
100
|
+
ws? >> str("ISO-10303-21;") >> ws? >>
|
|
101
|
+
header_section.as(:header_section) >>
|
|
102
|
+
data_section.as(:data_section) >>
|
|
103
|
+
str("END-ISO-10303-21;") >> ws?
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Expressir
|
|
4
|
+
module P21
|
|
5
|
+
# Facade: parse an ISO 10303-21 exchange structure into a
|
|
6
|
+
# {Population} (TODO.eengine/06 step 1).
|
|
7
|
+
module Parser
|
|
8
|
+
module_function
|
|
9
|
+
|
|
10
|
+
def parse(source)
|
|
11
|
+
tree = Grammar.new.parse(source)
|
|
12
|
+
Builder.build(tree)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Expressir
|
|
4
|
+
module P21
|
|
5
|
+
# A parsed ISO 10303-21 exchange structure (TODO.eengine/06).
|
|
6
|
+
# `header` — Hash: keyword => parameters (Array of values).
|
|
7
|
+
# `instances`— Hash: "#id" => Record.
|
|
8
|
+
#
|
|
9
|
+
# Values: String (string literal), Integer (reference id, keyed as
|
|
10
|
+
# "#id" in instances), Expressir::P21::Enumeration,
|
|
11
|
+
# Expressir::P21::Binary, Expressir::P21::TypedValue,
|
|
12
|
+
# Expressir::P21::ComplexRecord, :unset, :derived, or nested
|
|
13
|
+
# Arrays for lists.
|
|
14
|
+
class Population
|
|
15
|
+
attr_reader :header, :instances
|
|
16
|
+
|
|
17
|
+
def initialize(header: {}, instances: {})
|
|
18
|
+
@header = header
|
|
19
|
+
@instances = instances
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# A data-section instance: `#12 = KEYWORD(param, ...) ;`
|
|
24
|
+
Record = Struct.new(:keyword, :params)
|
|
25
|
+
|
|
26
|
+
# `#21 = (A(...) B(...))` — complex entity instance.
|
|
27
|
+
ComplexRecord = Struct.new(:records)
|
|
28
|
+
|
|
29
|
+
TypedValue = Struct.new(:keyword, :value)
|
|
30
|
+
|
|
31
|
+
Enumeration = Struct.new(:name)
|
|
32
|
+
|
|
33
|
+
Binary = Struct.new(:hex)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Expressir
|
|
4
|
+
module P21
|
|
5
|
+
# Validates a {Population} against a loaded schema
|
|
6
|
+
# (TODO.eengine/06 step 2). Single-schema scope: instance keywords
|
|
7
|
+
# must be declared in the given schema; USE/REFERENCE visibility is
|
|
8
|
+
# a later ladder step.
|
|
9
|
+
#
|
|
10
|
+
# Mapping follows ISO 10303-21 clause 12: derived attributes are
|
|
11
|
+
# not mapped (a supertype attribute redeclared as DERIVED keeps its
|
|
12
|
+
# slot, valued `*`), inverse attributes are not mapped, and the
|
|
13
|
+
# value order is supertype attributes first.
|
|
14
|
+
module Validator
|
|
15
|
+
Note = Struct.new(:id, :severity, :instance, :message, keyword_init: true)
|
|
16
|
+
|
|
17
|
+
module_function
|
|
18
|
+
|
|
19
|
+
# `short_names` maps exchange-structure short names (ISO 10303-21,
|
|
20
|
+
# clause 12.3) to schema entity names, e.g. {"CPT" => "cartesian_point"}.
|
|
21
|
+
def validate(population, schema, short_names: nil)
|
|
22
|
+
short_names = short_names&.transform_keys(&:downcase)
|
|
23
|
+
notes = []
|
|
24
|
+
check_file_schema(notes, population, schema)
|
|
25
|
+
population.instances.each do |id, instance|
|
|
26
|
+
if instance.is_a?(ComplexRecord)
|
|
27
|
+
check_complex(notes, schema, population, id, instance, short_names)
|
|
28
|
+
else
|
|
29
|
+
check_simple(notes, schema, population, id, instance, short_names)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
notes
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def errors(notes)
|
|
36
|
+
notes.select { |note| note.severity == :error }
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def warnings(notes)
|
|
40
|
+
notes.select { |note| note.severity == :warning }
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def valid?(notes)
|
|
44
|
+
errors(notes).empty?
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def note!(notes, id, severity, instance, message)
|
|
48
|
+
notes << Note.new(id: id, severity: severity, instance: instance,
|
|
49
|
+
message: message)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def check_file_schema(notes, population, schema)
|
|
53
|
+
declared = Array(population.header["FILE_SCHEMA"]).flatten.first
|
|
54
|
+
return unless declared && schema.id
|
|
55
|
+
return if declared.downcase == schema.id.downcase
|
|
56
|
+
|
|
57
|
+
note!(notes, :p21_schema_mismatch, :warning, nil,
|
|
58
|
+
"FILE_SCHEMA '#{declared}' does not match schema '#{schema.id}'")
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def check_simple(notes, schema, population, id, record, short_names)
|
|
62
|
+
entity = find_entity(schema, record.keyword, short_names)
|
|
63
|
+
unless entity
|
|
64
|
+
note!(notes, :p21_unknown_entity, :error, id,
|
|
65
|
+
"#{record.keyword} is not declared in schema '#{schema.id}'")
|
|
66
|
+
return
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
check_params(notes, schema, population, id, record.params,
|
|
70
|
+
mapped_slots(entity))
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def check_complex(notes, schema, population, id, complex, short_names)
|
|
74
|
+
pairs = complex.records.filter_map do |record|
|
|
75
|
+
entity = find_entity(schema, record.keyword, short_names)
|
|
76
|
+
unless entity
|
|
77
|
+
note!(notes, :p21_unknown_entity, :error, id,
|
|
78
|
+
"#{record.keyword} is not declared in schema '#{schema.id}'")
|
|
79
|
+
next nil
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
[record, entity]
|
|
83
|
+
end
|
|
84
|
+
return if pairs.empty?
|
|
85
|
+
|
|
86
|
+
check_clique(notes, id, pairs.map { |_, entity| entity })
|
|
87
|
+
pairs.each do |record, entity|
|
|
88
|
+
slots = explicit_attributes(entity).map { |attr| [attr, false] }
|
|
89
|
+
check_params(notes, schema, population, id, record.params, slots)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# A complex instance's records must form a valid supertype graph
|
|
94
|
+
# path: they share at least one common supertype.
|
|
95
|
+
def check_clique(notes, id, entities)
|
|
96
|
+
common = closure_keys(entities.first)
|
|
97
|
+
entities.drop(1).each { |entity| common &= closure_keys(entity) }
|
|
98
|
+
return unless common.empty?
|
|
99
|
+
|
|
100
|
+
note!(notes, :p21_complex_clique, :error, id,
|
|
101
|
+
"#{id}: complex records share no common supertype")
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def closure_keys(entity)
|
|
105
|
+
keys = entity.supertype_closure.filter_map { |e| e.id&.downcase }
|
|
106
|
+
keys << entity.id&.downcase
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Part 21 value order: supertype attributes first; an attribute
|
|
110
|
+
# redeclared as DERIVED in the entity keeps its inherited slot,
|
|
111
|
+
# valued `*` (12.2.6).
|
|
112
|
+
def mapped_slots(entity)
|
|
113
|
+
own_derived_keys = own_derived_attributes(entity)
|
|
114
|
+
.filter_map { |attr| attr.id&.downcase }
|
|
115
|
+
inherited = entity.supertype_closure.flat_map do |supertype|
|
|
116
|
+
explicit_attributes(supertype)
|
|
117
|
+
end
|
|
118
|
+
inherited.map do |attr|
|
|
119
|
+
[attr, own_derived_keys.include?(attr.id&.downcase)]
|
|
120
|
+
end + explicit_attributes(entity).map { |attr| [attr, false] }
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def check_params(notes, schema, population, id, params, slots)
|
|
124
|
+
if params.size != slots.size
|
|
125
|
+
note!(notes, :p21_arity_mismatch, :error, id,
|
|
126
|
+
"#{id}: #{params.size} values for #{slots.size} mapped attributes")
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
slots.zip(params).each do |(attr, derived_slot), value|
|
|
130
|
+
next if value.nil?
|
|
131
|
+
|
|
132
|
+
if derived_slot
|
|
133
|
+
next if value == :derived
|
|
134
|
+
|
|
135
|
+
note!(notes, :p21_derived_slot, :error, id,
|
|
136
|
+
"#{id}: attribute '#{attr.id}' redeclared DERIVED must be '*'")
|
|
137
|
+
next
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
check_value(notes, schema, population, id, attr, value)
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def check_value(notes, schema, population, id, attr, value)
|
|
145
|
+
case value
|
|
146
|
+
when String
|
|
147
|
+
return unless value.match?(/\A#\d+\z/)
|
|
148
|
+
|
|
149
|
+
return if population.instances.key?(value)
|
|
150
|
+
|
|
151
|
+
note!(notes, :p21_unknown_reference, :error, id,
|
|
152
|
+
"#{id}: reference #{value} has no instance")
|
|
153
|
+
when :derived
|
|
154
|
+
note!(notes, :p21_derived_value, :error, id,
|
|
155
|
+
"#{id}: '*' outside a derived slot")
|
|
156
|
+
when TypedValue
|
|
157
|
+
return if find_entity(schema, value.keyword) || find_type(schema, value.keyword)
|
|
158
|
+
|
|
159
|
+
note!(notes, :p21_unknown_typed_keyword, :error, id,
|
|
160
|
+
"#{id}: typed parameter '#{value.keyword}' does not resolve")
|
|
161
|
+
when Enumeration
|
|
162
|
+
items = enumeration_items(schema, attr)
|
|
163
|
+
return unless items
|
|
164
|
+
|
|
165
|
+
names = items.filter_map { |item| item.id&.downcase }
|
|
166
|
+
return if names.include?(value.name.downcase)
|
|
167
|
+
|
|
168
|
+
note!(notes, :p21_enum_value, :error, id,
|
|
169
|
+
"#{id}: .#{value.name}. is not in attribute '#{attr.id}' enumeration")
|
|
170
|
+
when Array
|
|
171
|
+
value.each { |item| check_value(notes, schema, population, id, attr, item) }
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def explicit_attributes(entity)
|
|
176
|
+
Array(entity.attributes)
|
|
177
|
+
.select { |attr| attr.instance_of?(Model::Declarations::Attribute) }
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def own_derived_attributes(entity)
|
|
181
|
+
Array(entity.attributes)
|
|
182
|
+
.select { |attr| attr.instance_of?(Model::Declarations::DerivedAttribute) }
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def find_entity(schema, keyword, short_names = nil)
|
|
186
|
+
key = keyword.downcase
|
|
187
|
+
Array(schema.entities).find { |entity| entity.id&.downcase == key } ||
|
|
188
|
+
resolve_short_name(schema, key, short_names)
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def resolve_short_name(schema, key, short_names)
|
|
192
|
+
return nil unless short_names.is_a?(Hash) && short_names[key]
|
|
193
|
+
|
|
194
|
+
find_entity(schema, short_names[key], nil)
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def find_type(schema, keyword)
|
|
198
|
+
Array(schema.types).find { |type| type.id&.downcase == keyword.downcase }
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def enumeration_items(schema, attr)
|
|
202
|
+
type = attr&.type
|
|
203
|
+
return Array(type.items) if type.is_a?(Model::DataTypes::Enumeration)
|
|
204
|
+
|
|
205
|
+
return nil unless type.is_a?(Model::References::SimpleReference)
|
|
206
|
+
|
|
207
|
+
declaration = find_type(schema, type.id.to_s)
|
|
208
|
+
underlying = declaration&.underlying_type
|
|
209
|
+
underlying.is_a?(Model::DataTypes::Enumeration) ? Array(underlying.items) : nil
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Expressir
|
|
4
|
+
# ISO 10303-21 exchange-structure support (TODO.eengine/06).
|
|
5
|
+
module P21
|
|
6
|
+
autoload :Population, "#{__dir__}/p21/population"
|
|
7
|
+
autoload :Record, "#{__dir__}/p21/population"
|
|
8
|
+
autoload :ComplexRecord, "#{__dir__}/p21/population"
|
|
9
|
+
autoload :TypedValue, "#{__dir__}/p21/population"
|
|
10
|
+
autoload :Enumeration, "#{__dir__}/p21/population"
|
|
11
|
+
autoload :Binary, "#{__dir__}/p21/population"
|
|
12
|
+
autoload :Grammar, "#{__dir__}/p21/grammar"
|
|
13
|
+
autoload :Builder, "#{__dir__}/p21/builder"
|
|
14
|
+
autoload :Validator, "#{__dir__}/p21/validator"
|
|
15
|
+
autoload :Parser, "#{__dir__}/p21/parser"
|
|
16
|
+
end
|
|
17
|
+
end
|
data/lib/expressir/version.rb
CHANGED
data/lib/expressir.rb
CHANGED
|
@@ -30,6 +30,7 @@ module Expressir
|
|
|
30
30
|
|
|
31
31
|
autoload :Version, "#{__dir__}/expressir/version"
|
|
32
32
|
autoload :Mapping, "#{__dir__}/expressir/mapping"
|
|
33
|
+
autoload :P21, "#{__dir__}/expressir/p21"
|
|
33
34
|
|
|
34
35
|
# Error classes — autoload the same errors.rb file from each name.
|
|
35
36
|
# The first reference triggers the load; the file defines all 21 classes.
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: expressir
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.4.
|
|
4
|
+
version: 2.4.35
|
|
5
5
|
platform: x86_64-linux
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-10-
|
|
11
|
+
date: 2026-10-16 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: base64
|
|
@@ -287,6 +287,16 @@ files:
|
|
|
287
287
|
- TODO.bugs/29-validate-ascii-god-class.md
|
|
288
288
|
- TODO.bugs/30-unicode-map-extraction.md
|
|
289
289
|
- TODO.bugs/README.md
|
|
290
|
+
- TODO.eengine/00-overview.md
|
|
291
|
+
- TODO.eengine/01-resolution-diagnostics.md
|
|
292
|
+
- TODO.eengine/02-check-catalog-completion.md
|
|
293
|
+
- TODO.eengine/03-entity-computations.md
|
|
294
|
+
- TODO.eengine/04-shtolo-rule-audit.md
|
|
295
|
+
- TODO.eengine/05-shtolo-longform-flatten.md
|
|
296
|
+
- TODO.eengine/06-population-p21.md
|
|
297
|
+
- TODO.eengine/07-schema-compare-patch.md
|
|
298
|
+
- TODO.eengine/08-official-corpus-gate.md
|
|
299
|
+
- TODO.eengine/09-mim-mapping-parser.md
|
|
290
300
|
- TODO.max-perf/01-restore-ci-green.md
|
|
291
301
|
- TODO.max-perf/02-streaming-parse-path.md
|
|
292
302
|
- TODO.max-perf/03-cli-parallel-opt-in.md
|
|
@@ -445,6 +455,7 @@ files:
|
|
|
445
455
|
- lib/expressir/commands/non_ascii_violation_collection.rb
|
|
446
456
|
- lib/expressir/commands/package.rb
|
|
447
457
|
- lib/expressir/commands/parity_inputs.rb
|
|
458
|
+
- lib/expressir/commands/smrl_xml_index.rb
|
|
448
459
|
- lib/expressir/commands/validate.rb
|
|
449
460
|
- lib/expressir/commands/validate_ascii.rb
|
|
450
461
|
- lib/expressir/commands/validate_load.rb
|
|
@@ -536,6 +547,7 @@ files:
|
|
|
536
547
|
- lib/expressir/express/remark_scanner.rb
|
|
537
548
|
- lib/expressir/express/resolve_references_model_visitor.rb
|
|
538
549
|
- lib/expressir/express/schema_block_scanner.rb
|
|
550
|
+
- lib/expressir/express/schema_compare.rb
|
|
539
551
|
- lib/expressir/express/schema_head_formatter.rb
|
|
540
552
|
- lib/expressir/express/schema_plain_source_formatter.rb
|
|
541
553
|
- lib/expressir/express/schema_source_formatter.rb
|
|
@@ -648,6 +660,12 @@ files:
|
|
|
648
660
|
- lib/expressir/model/supertype_expressions.rb
|
|
649
661
|
- lib/expressir/model/supertype_expressions/binary_supertype_expression.rb
|
|
650
662
|
- lib/expressir/model/supertype_expressions/oneof_supertype_expression.rb
|
|
663
|
+
- lib/expressir/p21.rb
|
|
664
|
+
- lib/expressir/p21/builder.rb
|
|
665
|
+
- lib/expressir/p21/grammar.rb
|
|
666
|
+
- lib/expressir/p21/parser.rb
|
|
667
|
+
- lib/expressir/p21/population.rb
|
|
668
|
+
- lib/expressir/p21/validator.rb
|
|
651
669
|
- lib/expressir/package.rb
|
|
652
670
|
- lib/expressir/package/builder.rb
|
|
653
671
|
- lib/expressir/package/metadata.rb
|