expressir 2.4.11 → 2.4.13
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/README.adoc +34 -1
- data/ext/expressir_core/src/lib.rs +41 -0
- data/lib/expressir/cli.rb +12 -0
- data/lib/expressir/commands/mapping_validate.rb +40 -0
- data/lib/expressir/commands/parity_inputs.rb +86 -45
- data/lib/expressir/commands/xsd.rb +23 -0
- data/lib/expressir/commands.rb +2 -0
- data/lib/expressir/express/checker.rb +18 -6
- data/lib/expressir/express/core.rb +18 -0
- data/lib/expressir/express/shtolo.rb +38 -15
- data/lib/expressir/version.rb +1 -1
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e3cf38ff1a09f95805cc5a6dc8c074832e47eeb8ceb7e62c79f503d521d775ac
|
|
4
|
+
data.tar.gz: a308605c1d7c97d33f766d08e8262e6e2039104ff7362e36a0fa5bd8e3839ccf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4c97b4d258e50604fba0bdc0365c3f8272d6944dc225755e6408c6b585324b917448134352a4ffb4da445ca21ef910858283931abef43625d0b4138c90ecf694
|
|
7
|
+
data.tar.gz: d268fd6aef2e11bdafe5f81845931e91742dcd33ff48f3a2f6bb0076a6f9bad440045609a501b81fcc2130fef6dcd565d972ebc6634861d0341f9efa2649b5b5
|
data/README.adoc
CHANGED
|
@@ -215,6 +215,8 @@ Commands:
|
|
|
215
215
|
expressir flatten PATH # Flatten the interface closure into an ISO 10303-11:1994 longform schema
|
|
216
216
|
expressir fix PATH # Rewrite self-schema-qualified references (#125)
|
|
217
217
|
expressir format PATH # pretty print EXPRESS schema located at PATH
|
|
218
|
+
expressir mapping_validate PATH # Validate <<express:...>> links in a module mapping.yaml against its ARM/MIM closure
|
|
219
|
+
expressir xsd PATH -o OUT.xsd # Write an XML Schema rendering of the EXPRESS schema at PATH
|
|
218
220
|
expressir help [COMMAND] # Describe available commands or one specific command
|
|
219
221
|
expressir validate load *PATH # validate EXPRESS schema located at PATH
|
|
220
222
|
expressir validate ascii PATH # Validate EXPRESS files for ASCII-only content (excluding remarks)
|
|
@@ -1266,7 +1268,38 @@ The default text output displays:
|
|
|
1266
1268
|
This helps identify areas of your EXPRESS schemas that need documentation
|
|
1267
1269
|
improvement.
|
|
1268
1270
|
|
|
1269
|
-
===
|
|
1271
|
+
=== Schema hyperlinked source faces
|
|
1272
|
+
|
|
1273
|
+
`Schema#source`, `Schema#source_hyperlinked`, and
|
|
1274
|
+
`Schema#formatted_hyperlinked(_adoc)` render a schema head or the full
|
|
1275
|
+
schema with cross-references either verbatim or as links (the adoc
|
|
1276
|
+
variant emits `<<schema.item,item>>` xref macros — render inside a
|
|
1277
|
+
`[source,subs="+macros"]` block for live links; see the
|
|
1278
|
+
`Expressir::Express::SmrlXml` and `Expressir::Express::Xsd` writers
|
|
1279
|
+
for the XML faces).
|
|
1280
|
+
|
|
1281
|
+
== MIM mapping validation (mapping.yaml)
|
|
1282
|
+
|
|
1283
|
+
`expressir mapping_validate PATH` loads a module `mapping.yaml`
|
|
1284
|
+
(lutaml-model typed: `Expressir::Mapping::Document`) and resolves every
|
|
1285
|
+
`<<express:SCHEMA.ITEM,ITEM>>` link against the ARM/MIM interface
|
|
1286
|
+
closure, reporting links whose schema or item is unknown.
|
|
1287
|
+
|
|
1288
|
+
== XML faces
|
|
1289
|
+
|
|
1290
|
+
- `Expressir::Express::SmrlXml.format(repository)` — the SMRL index
|
|
1291
|
+
block per schema (eeng wo-smrl-xml shape).
|
|
1292
|
+
- `Expressir::Express::Xsd.format(schema)` — an XML Schema rendering
|
|
1293
|
+
(entities as element/complexType, substitutionGroup for subtypes,
|
|
1294
|
+
enumeration facets).
|
|
1295
|
+
|
|
1296
|
+
== Lazy compiled-set access
|
|
1297
|
+
|
|
1298
|
+
`Expressir::Express::Core.lazy_set(artifact)` lists a compiled set's
|
|
1299
|
+
wire paths without hydrating and hydrates individual files on demand —
|
|
1300
|
+
renderers that touch one schema per page hydrate one schema per page.
|
|
1301
|
+
|
|
1302
|
+
== EXPRESS Changes files
|
|
1270
1303
|
|
|
1271
1304
|
Expressir provides commands for working with EXPRESS Changes files that track
|
|
1272
1305
|
schema modifications across versions.
|
|
@@ -304,6 +304,45 @@ fn set_count(_ruby: &Ruby, reader: &SetReader) -> usize {
|
|
|
304
304
|
reader.set.files.len()
|
|
305
305
|
}
|
|
306
306
|
|
|
307
|
+
/// Every wire path in the artifact, in artifact order — no hydration.
|
|
308
|
+
fn set_wire_paths(_ruby: &Ruby, reader: &SetReader) -> Result<magnus::Value, Error> {
|
|
309
|
+
let paths = RArray::with_capacity(reader.set.files.len());
|
|
310
|
+
for file in &reader.set.files {
|
|
311
|
+
paths.push(ruby_str(_ruby, &file.wire_path))?;
|
|
312
|
+
}
|
|
313
|
+
Ok(paths.as_value())
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
fn ruby_str(ruby: &Ruby, s: &str) -> magnus::Value {
|
|
317
|
+
ruby.str_new(s).as_value()
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/// `[wire_path, model]` for ONE file, addressed by wire path — the
|
|
321
|
+
/// lazy-access path (M2): callers hydrate only the schemas a render
|
|
322
|
+
/// touches instead of the whole set.
|
|
323
|
+
fn set_hydrate_one(ruby: &Ruby, reader: &SetReader, wire_path: String) -> Result<magnus::Value, Error> {
|
|
324
|
+
let file = reader
|
|
325
|
+
.set
|
|
326
|
+
.files
|
|
327
|
+
.iter()
|
|
328
|
+
.find(|f| f.wire_path == wire_path)
|
|
329
|
+
.ok_or_else(|| {
|
|
330
|
+
Error::new(
|
|
331
|
+
ruby.exception_runtime_error(),
|
|
332
|
+
format!("wire path {wire_path} not in compiled set"),
|
|
333
|
+
)
|
|
334
|
+
})?;
|
|
335
|
+
let wire = file.wire().map_err(|e| {
|
|
336
|
+
Error::new(ruby.exception_runtime_error(), format!("{}: {e}", file.wire_path))
|
|
337
|
+
})?;
|
|
338
|
+
let mut cache = reader.cache.lock().expect("class cache");
|
|
339
|
+
let model = value_to_ruby(ruby, &mut cache, &wire)?;
|
|
340
|
+
let pair = RArray::with_capacity(2);
|
|
341
|
+
pair.push(ruby.str_new(&file.wire_path))?;
|
|
342
|
+
pair.push(model)?;
|
|
343
|
+
Ok(pair.as_value())
|
|
344
|
+
}
|
|
345
|
+
|
|
307
346
|
/// `[wire_path, model]` for the next file in artifact order, nil at
|
|
308
347
|
/// the end.
|
|
309
348
|
fn set_next(ruby: &Ruby, reader: &SetReader) -> Result<magnus::Value, Error> {
|
|
@@ -441,6 +480,8 @@ fn init(ruby: &Ruby) -> Result<(), Error> {
|
|
|
441
480
|
set_class.define_method("digest", method!(set_digest, 0))?;
|
|
442
481
|
set_class.define_method("count", method!(set_count, 0))?;
|
|
443
482
|
set_class.define_method("next", method!(set_next, 0))?;
|
|
483
|
+
set_class.define_method("wire_paths", method!(set_wire_paths, 0))?;
|
|
484
|
+
set_class.define_method("hydrate_one", method!(set_hydrate_one, 1))?;
|
|
444
485
|
set_class.define_method("matches_sources", method!(set_matches_sources, 1))?;
|
|
445
486
|
Ok(())
|
|
446
487
|
}
|
data/lib/expressir/cli.rb
CHANGED
|
@@ -99,6 +99,18 @@ module Expressir
|
|
|
99
99
|
Expressir::Commands::BenchmarkCache.new(options).run(path)
|
|
100
100
|
end
|
|
101
101
|
|
|
102
|
+
desc "mapping_validate PATH", "Validate <<express:...>> links in a module mapping.yaml against its ARM/MIM closure"
|
|
103
|
+
def mapping_validate(path)
|
|
104
|
+
Expressir::Commands::MappingValidate.new(options).run(path)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
desc "xsd PATH", "Write an XML Schema rendering of the EXPRESS schema at PATH"
|
|
108
|
+
method_option :output, type: :string, aliases: "-o",
|
|
109
|
+
desc: "Output file path (defaults to stdout)"
|
|
110
|
+
def xsd(path)
|
|
111
|
+
Expressir::Commands::Xsd.new(options).run(path)
|
|
112
|
+
end
|
|
113
|
+
|
|
102
114
|
desc "validate SUBCOMMAND", "EXPRESS schema validation commands"
|
|
103
115
|
subcommand "validate", Expressir::Commands::Validate
|
|
104
116
|
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Expressir
|
|
4
|
+
module Commands
|
|
5
|
+
# `expressir mapping validate` (#88): load a module mapping.yaml
|
|
6
|
+
# and resolve every <<express:...>> link against the ARM/MIM
|
|
7
|
+
# interface closure. Exits 1 when unknown links remain.
|
|
8
|
+
class MappingValidate < Base
|
|
9
|
+
def run(path)
|
|
10
|
+
document = Expressir::Mapping.load_file(path)
|
|
11
|
+
unknown = Expressir::Mapping.unknown_links(document, repository_for(path))
|
|
12
|
+
|
|
13
|
+
if unknown.empty?
|
|
14
|
+
say "all links resolve"
|
|
15
|
+
return
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
unknown.each do |link|
|
|
19
|
+
say "unknown: #{link.text}"
|
|
20
|
+
end
|
|
21
|
+
raise Thor::Error, "#{unknown.size} unknown link(s)"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def repository_for(path)
|
|
27
|
+
dir = File.dirname(File.expand_path(path))
|
|
28
|
+
arm = Dir[File.join(dir, "arm.exp")].first
|
|
29
|
+
mim = Dir[File.join(dir, "mim.exp")].first
|
|
30
|
+
roots = [arm, mim].compact
|
|
31
|
+
raise Thor::Error, "no arm.exp/mim.exp next to #{path}" if roots.empty?
|
|
32
|
+
|
|
33
|
+
files = roots.flat_map do |root|
|
|
34
|
+
ParityInputs.closure_paths(root)
|
|
35
|
+
end.uniq.select { |f| File.exist?(f) }
|
|
36
|
+
Expressir::Express::Parser.from_files(files)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -5,58 +5,92 @@ module Expressir
|
|
|
5
5
|
# Common parser/discovery helpers shared by parity CLI commands
|
|
6
6
|
# (expand, flatten, check) — they all need: list of files in the
|
|
7
7
|
# interface closure of a root file, and the root schema parsed.
|
|
8
|
+
#
|
|
9
|
+
# Schema resolution order (per the ELF schema manifest directive):
|
|
10
|
+
# 1. `--manifest PATH` — an ELF schema manifest explicitly defines
|
|
11
|
+
# where each schema lives; this is the primary mode.
|
|
12
|
+
# 2. `--stepmod DIR` — explicit opt-in to the STEPmod directory
|
|
13
|
+
# convention (`schemas/**/<name>.exp`) as the fallback.
|
|
14
|
+
# 3. Otherwise the file's own directory is used; a lookup failure
|
|
15
|
+
# warns and points at the two explicit modes.
|
|
8
16
|
module ParityInputs
|
|
9
17
|
module_function
|
|
10
18
|
|
|
11
|
-
# Resolve the transitive interface closure of +root_path+.
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
19
|
+
# Resolve the transitive interface closure of +root_path+. The queue
|
|
20
|
+
# holds paths and `seen` guards by schema name: mutual USE FROM
|
|
21
|
+
# cycles must terminate (this loop once span rounds forever on them,
|
|
22
|
+
# re-reading the same files).
|
|
15
23
|
def closure_paths(root_path, manifest: nil, stepmod: nil)
|
|
16
|
-
index = schema_index(root_path)
|
|
24
|
+
index = schema_index(root_path, manifest: manifest, stepmod: stepmod)
|
|
17
25
|
seen = { File.basename(root_path, ".exp").downcase => root_path }
|
|
18
|
-
|
|
26
|
+
missing = []
|
|
27
|
+
queue = [root_path]
|
|
19
28
|
until queue.empty?
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
next if seen.key?(name) && seen[name] != root_path
|
|
29
|
+
closure_names(File.read(queue.shift)).each do |dep|
|
|
30
|
+
name = dep.downcase
|
|
31
|
+
next if seen.key?(name)
|
|
24
32
|
|
|
25
|
-
|
|
26
|
-
|
|
33
|
+
path = index&.[](name)
|
|
34
|
+
unless path
|
|
35
|
+
missing << name
|
|
36
|
+
seen[name] = nil
|
|
37
|
+
next
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
seen[name] = path
|
|
41
|
+
queue << path
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
unless missing.empty?
|
|
45
|
+
warn "expressir: schema(s) not found: #{missing.uniq.join(', ')}" \
|
|
46
|
+
"#{resolver_hint(manifest, stepmod)}"
|
|
27
47
|
end
|
|
28
|
-
seen.values.uniq
|
|
48
|
+
seen.values.compact.uniq
|
|
29
49
|
end
|
|
30
50
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
parent = File.dirname(dir)
|
|
42
|
-
break if parent == dir
|
|
51
|
+
def resolver_hint(manifest, stepmod)
|
|
52
|
+
if manifest
|
|
53
|
+
" (not in schema manifest #{manifest})"
|
|
54
|
+
elsif stepmod
|
|
55
|
+
" (not found under STEPmod root #{stepmod})"
|
|
56
|
+
else
|
|
57
|
+
" - provide --manifest PATH (ELF schema manifest) or " \
|
|
58
|
+
"--stepmod DIR to resolve them"
|
|
59
|
+
end
|
|
60
|
+
end
|
|
43
61
|
|
|
44
|
-
|
|
62
|
+
# Schema-name → path index from the ELF schema manifest.
|
|
63
|
+
def manifest_index(manifest_path)
|
|
64
|
+
manifest = Expressir::SchemaManifest.from_file(manifest_path)
|
|
65
|
+
manifest.schemas.to_h do |entry|
|
|
66
|
+
[entry.id.downcase, entry.path]
|
|
45
67
|
end
|
|
46
|
-
|
|
68
|
+
rescue StandardError => e
|
|
69
|
+
warn "expressir: could not load schema manifest #{manifest_path}: #{e.message}"
|
|
70
|
+
nil
|
|
71
|
+
end
|
|
47
72
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
73
|
+
# Schema-name → path index over a STEPmod checkout root (the
|
|
74
|
+
# directory holding `schemas/`, or that directory itself).
|
|
75
|
+
def stepmod_index(stepmod_dir)
|
|
76
|
+
root = File.join(File.expand_path(stepmod_dir), "schemas")
|
|
77
|
+
root = File.expand_path(stepmod_dir) unless File.directory?(root)
|
|
78
|
+
h = {}
|
|
79
|
+
Find.find(root) do |path|
|
|
80
|
+
next unless path.end_with?(".exp")
|
|
53
81
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
end
|
|
58
|
-
h
|
|
82
|
+
declared = File.read(path)[/\bSCHEMA\s+(\w+)/i, 1]
|
|
83
|
+
h[declared.downcase] = path if declared
|
|
84
|
+
h[File.basename(path, ".exp").downcase] ||= path
|
|
59
85
|
end
|
|
86
|
+
h
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def schema_index(root_path, manifest: nil, stepmod: nil)
|
|
90
|
+
return manifest_index(manifest) if manifest
|
|
91
|
+
return stepmod_index(stepmod) if stepmod
|
|
92
|
+
|
|
93
|
+
same_dir_index(root_path)
|
|
60
94
|
end
|
|
61
95
|
|
|
62
96
|
def same_dir_index(root_path)
|
|
@@ -66,19 +100,26 @@ module Expressir
|
|
|
66
100
|
end
|
|
67
101
|
end
|
|
68
102
|
|
|
103
|
+
# Interface names declared by +source+. Remark text is stripped
|
|
104
|
+
# first: prose like "use from the main schema" must not spawn
|
|
105
|
+
# phantom dependencies.
|
|
69
106
|
def closure_names(source)
|
|
70
|
-
source.
|
|
71
|
-
|
|
107
|
+
code = source.gsub(/--[^\n]*/, "").gsub(/\(\*.*?\*\)/m, "")
|
|
108
|
+
code.scan(/\bUSE\s+FROM\s+(\w+)/i).flatten.uniq +
|
|
109
|
+
code.scan(/\bREFERENCE\s+FROM\s+(\w+)/i).flatten.uniq
|
|
72
110
|
end
|
|
73
111
|
|
|
74
|
-
# manifest:/stepmod: are accepted for the ELF-manifest resolver
|
|
75
|
-
# contract; the directory-index fallback ignores them until that
|
|
76
|
-
# resolver lands.
|
|
77
112
|
def root_schema(root_path, manifest: nil, stepmod: nil)
|
|
78
113
|
name = File.read(root_path)[/\bSCHEMA\s+(\w+)/, 1]
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
114
|
+
# skip_references: longform generation and checking run their own
|
|
115
|
+
# resolution; resolving every reference of a large closure here made
|
|
116
|
+
# flatten crawl (minutes vs seconds).
|
|
117
|
+
repo = Expressir::Express::Parser.from_files(
|
|
118
|
+
closure_paths(root_path, manifest: manifest, stepmod: stepmod),
|
|
119
|
+
skip_references: true,
|
|
120
|
+
max_processes: 1,
|
|
121
|
+
)
|
|
122
|
+
[repo.schemas.find { |s| s.id&.downcase == name&.downcase }, repo]
|
|
82
123
|
end
|
|
83
124
|
end
|
|
84
125
|
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Expressir
|
|
4
|
+
module Commands
|
|
5
|
+
# `expressir xsd` (#276): write the XML Schema rendering of the
|
|
6
|
+
# schema at PATH.
|
|
7
|
+
class Xsd < Base
|
|
8
|
+
def run(path)
|
|
9
|
+
repo = Expressir::Express::Parser.from_file(path)
|
|
10
|
+
schema = repo.schemas.first
|
|
11
|
+
raise Thor::Error, "no schema in #{path}" unless schema
|
|
12
|
+
|
|
13
|
+
xml = Expressir::Express::Xsd.format(schema)
|
|
14
|
+
if options[:output]
|
|
15
|
+
File.write(options[:output], xml)
|
|
16
|
+
say "written to #{options[:output]}"
|
|
17
|
+
else
|
|
18
|
+
$stdout.write(xml)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
data/lib/expressir/commands.rb
CHANGED
|
@@ -24,5 +24,7 @@ module Expressir
|
|
|
24
24
|
autoload :Version, "#{__dir__}/commands/version"
|
|
25
25
|
autoload :Package, "#{__dir__}/commands/package"
|
|
26
26
|
autoload :Manifest, "#{__dir__}/commands/manifest"
|
|
27
|
+
autoload :MappingValidate, "#{__dir__}/commands/mapping_validate"
|
|
28
|
+
autoload :Xsd, "#{__dir__}/commands/xsd"
|
|
27
29
|
end
|
|
28
30
|
end
|
|
@@ -307,20 +307,32 @@ module Expressir
|
|
|
307
307
|
|
|
308
308
|
Array(type.underlying_type.items).each do |item|
|
|
309
309
|
next if item.id.nil?
|
|
310
|
-
next if
|
|
311
|
-
next if find_entity(schema, item.id).nil? # unresolved handled elsewhere
|
|
310
|
+
next if select_item_resolves?(schema, item.id)
|
|
312
311
|
|
|
313
312
|
note!(:check_select_named_type, :error, schema,
|
|
314
|
-
"TYPE #{type.id}
|
|
315
|
-
"
|
|
313
|
+
"In the SELECT TYPE #{type.id}, '#{item.id}' does not " \
|
|
314
|
+
"name an existing TYPE or ENTITY", type)
|
|
316
315
|
end
|
|
317
316
|
end
|
|
318
317
|
|
|
319
318
|
def find_type(schema, id)
|
|
320
319
|
key = id.safe_downcase
|
|
321
|
-
|
|
320
|
+
schema.types.find { |t| t.id.safe_downcase == key }
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
# ISO 10303-11 rule 258: select_list items are named_types —
|
|
324
|
+
# entity_ref | type_ref. The item is fine when it names either,
|
|
325
|
+
# in this schema or any repository schema (interface-visible).
|
|
326
|
+
def select_item_resolves?(schema, id)
|
|
327
|
+
return true if find_entity(schema, id)
|
|
328
|
+
return true if schema.types.to_a.any? { |t| t.id.safe_downcase == id.safe_downcase }
|
|
322
329
|
|
|
323
|
-
|
|
330
|
+
@by_name.each_value.any? do |group|
|
|
331
|
+
group.any? do |other|
|
|
332
|
+
other.types.to_a.any? { |t| t.id.safe_downcase == id.safe_downcase } ||
|
|
333
|
+
other.entities.to_a.any? { |e| e.id.safe_downcase == id.safe_downcase }
|
|
334
|
+
end
|
|
335
|
+
end
|
|
324
336
|
end
|
|
325
337
|
|
|
326
338
|
# eeng declared-kind probe: :type when a TYPE of that name is
|
|
@@ -43,6 +43,24 @@ module Expressir
|
|
|
43
43
|
::Expressir::Core.parse_to_model(source, path)
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
+
# Lazy handle over a compiled-set artifact (M2): `wire_paths`
|
|
47
|
+
# lists the set's files without hydrating anything; `hydrate_one`
|
|
48
|
+
# builds a single file's model on demand. Renderers that touch
|
|
49
|
+
# one schema per page hydrate one schema per page instead of the
|
|
50
|
+
# whole repository.
|
|
51
|
+
def self.lazy_set(path)
|
|
52
|
+
unless NATIVE_AVAILABLE
|
|
53
|
+
raise NotImplementedError,
|
|
54
|
+
"lazy set unavailable without the native extension"
|
|
55
|
+
end
|
|
56
|
+
unless ::Expressir::Core.const_defined?(:Set) &&
|
|
57
|
+
::Expressir::Core::Set.method_defined?(:hydrate_one)
|
|
58
|
+
raise NotImplementedError, "lazy set unavailable; ext too old"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
::Expressir::Core::Set.open(path)
|
|
62
|
+
end
|
|
63
|
+
|
|
46
64
|
# Compile many files concurrently: jobs are [read_path,
|
|
47
65
|
# wire_path] pairs; the block receives (wire_path, model, error)
|
|
48
66
|
# per job in completion order. Workers run on native threads, so
|
|
@@ -351,15 +351,22 @@ module Expressir
|
|
|
351
351
|
end
|
|
352
352
|
end
|
|
353
353
|
|
|
354
|
-
# Every identifier a
|
|
355
|
-
#
|
|
354
|
+
# Every identifier a call site names, across the artifact's
|
|
355
|
+
# surviving declarations: FunctionCall for functions and
|
|
356
|
+
# ProcedureCall statements for procedures. (A zero-argument
|
|
357
|
+
# function reference written bare is not represented as a
|
|
358
|
+
# FunctionCall by the parser and is counted via any SimpleReference
|
|
359
|
+
# miss — accepted v1 blind spot, see tranche notes.)
|
|
356
360
|
def called_ids(schema)
|
|
357
361
|
called = {}
|
|
358
362
|
each_node(schema) do |node|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
+
id = nil
|
|
364
|
+
case node
|
|
365
|
+
when Expressir::Model::Expressions::FunctionCall
|
|
366
|
+
id = node.function.is_a?(String) ? node.function : node.function&.id
|
|
367
|
+
when Expressir::Model::Statements::ProcedureCall
|
|
368
|
+
id = node.procedure.is_a?(String) ? node.procedure : node.procedure&.id
|
|
369
|
+
end
|
|
363
370
|
called[id.safe_downcase] = true if id
|
|
364
371
|
end
|
|
365
372
|
called
|
|
@@ -392,19 +399,28 @@ module Expressir
|
|
|
392
399
|
def reduce_supertype_expression(expr, visible_ids)
|
|
393
400
|
case expr
|
|
394
401
|
when Model::SupertypeExpressions::OneofSupertypeExpression
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
id.nil? || visible_ids.key?(id.safe_downcase)
|
|
402
|
+
reduced = expr.operands.filter_map do |operand|
|
|
403
|
+
reduce_supertype_expression(operand, visible_ids)
|
|
398
404
|
end
|
|
399
|
-
return nil if
|
|
405
|
+
return nil if reduced.empty?
|
|
400
406
|
|
|
401
|
-
|
|
407
|
+
reduced.one? ? reduced.first : reset_oneof(expr, reduced)
|
|
402
408
|
when Model::SupertypeExpressions::BinarySupertypeExpression
|
|
403
|
-
left = reduce_supertype_expression(expr.
|
|
404
|
-
right = reduce_supertype_expression(expr.
|
|
405
|
-
|
|
409
|
+
left = reduce_supertype_expression(expr.operand1, visible_ids)
|
|
410
|
+
right = reduce_supertype_expression(expr.operand2, visible_ids)
|
|
411
|
+
if left.nil?
|
|
412
|
+
return right
|
|
413
|
+
end
|
|
414
|
+
if right.nil?
|
|
415
|
+
return left
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
rebuild_binary(expr, left, right)
|
|
419
|
+
when Model::References::SimpleReference
|
|
420
|
+
id = expr.id
|
|
421
|
+
return nil if id && !visible_ids.key?(id.safe_downcase)
|
|
406
422
|
|
|
407
|
-
|
|
423
|
+
expr
|
|
408
424
|
else
|
|
409
425
|
expr
|
|
410
426
|
end
|
|
@@ -416,6 +432,13 @@ module Expressir
|
|
|
416
432
|
copy
|
|
417
433
|
end
|
|
418
434
|
|
|
435
|
+
def rebuild_binary(expr, left, right)
|
|
436
|
+
copy = deep_copy(expr)
|
|
437
|
+
copy.operand1 = left
|
|
438
|
+
copy.operand2 = right
|
|
439
|
+
copy
|
|
440
|
+
end
|
|
441
|
+
|
|
419
442
|
def resolve_extensible_enumerations!(schema)
|
|
420
443
|
schema.types.select do |t|
|
|
421
444
|
t.underlying_type.is_a?(Model::DataTypes::Enumeration) && t.underlying_type.extensible
|
data/lib/expressir/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
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.13
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
@@ -425,6 +425,7 @@ files:
|
|
|
425
425
|
- lib/expressir/commands/flatten.rb
|
|
426
426
|
- lib/expressir/commands/format.rb
|
|
427
427
|
- lib/expressir/commands/manifest.rb
|
|
428
|
+
- lib/expressir/commands/mapping_validate.rb
|
|
428
429
|
- lib/expressir/commands/non_ascii_character.rb
|
|
429
430
|
- lib/expressir/commands/non_ascii_violation_collection.rb
|
|
430
431
|
- lib/expressir/commands/package.rb
|
|
@@ -433,6 +434,7 @@ files:
|
|
|
433
434
|
- lib/expressir/commands/validate_ascii.rb
|
|
434
435
|
- lib/expressir/commands/validate_load.rb
|
|
435
436
|
- lib/expressir/commands/version.rb
|
|
437
|
+
- lib/expressir/commands/xsd.rb
|
|
436
438
|
- lib/expressir/config.rb
|
|
437
439
|
- lib/expressir/coverage.rb
|
|
438
440
|
- lib/expressir/eengine.rb
|