expressir 2.1.30 → 2.1.31
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/docs.yml +98 -0
- data/.github/workflows/links.yml +100 -0
- data/.github/workflows/rake.yml +4 -0
- data/.github/workflows/release.yml +5 -0
- data/.github/workflows/validate_schemas.yml +1 -1
- data/.gitignore +3 -0
- data/.rubocop.yml +1 -1
- data/.rubocop_todo.yml +244 -39
- data/Gemfile +2 -1
- data/README.adoc +621 -54
- data/docs/Gemfile +12 -0
- data/docs/_config.yml +141 -0
- data/docs/_guides/changes/changes-format.adoc +778 -0
- data/docs/_guides/changes/importing-eengine.adoc +898 -0
- data/docs/_guides/changes/index.adoc +396 -0
- data/docs/_guides/changes/programmatic-usage.adoc +1038 -0
- data/docs/_guides/changes/validating-changes.adoc +681 -0
- data/docs/_guides/cli/benchmark-performance.adoc +834 -0
- data/docs/_guides/cli/coverage-analysis.adoc +921 -0
- data/docs/_guides/cli/format-schemas.adoc +547 -0
- data/docs/_guides/cli/index.adoc +8 -0
- data/docs/_guides/cli/managing-changes.adoc +927 -0
- data/docs/_guides/cli/validate-ascii.adoc +645 -0
- data/docs/_guides/cli/validate-schemas.adoc +534 -0
- data/docs/_guides/index.adoc +165 -0
- data/docs/_guides/ler/creating-packages.adoc +664 -0
- data/docs/_guides/ler/index.adoc +305 -0
- data/docs/_guides/ler/loading-packages.adoc +707 -0
- data/docs/_guides/ler/package-formats.adoc +748 -0
- data/docs/_guides/ler/querying-packages.adoc +826 -0
- data/docs/_guides/ler/validating-packages.adoc +750 -0
- data/docs/_guides/liquid/basic-templates.adoc +813 -0
- data/docs/_guides/liquid/documentation-generation.adoc +1042 -0
- data/docs/_guides/liquid/drops-reference.adoc +829 -0
- data/docs/_guides/liquid/filters-and-tags.adoc +912 -0
- data/docs/_guides/liquid/index.adoc +468 -0
- data/docs/_guides/manifests/creating-manifests.adoc +483 -0
- data/docs/_guides/manifests/index.adoc +307 -0
- data/docs/_guides/manifests/resolving-manifests.adoc +557 -0
- data/docs/_guides/manifests/validating-manifests.adoc +713 -0
- data/docs/_guides/ruby-api/formatting-schemas.adoc +605 -0
- data/docs/_guides/ruby-api/index.adoc +257 -0
- data/docs/_guides/ruby-api/parsing-files.adoc +421 -0
- data/docs/_guides/ruby-api/search-engine.adoc +609 -0
- data/docs/_guides/ruby-api/working-with-repository.adoc +577 -0
- data/docs/_pages/data-model.adoc +665 -0
- data/docs/_pages/express-language.adoc +506 -0
- data/docs/_pages/getting-started.adoc +414 -0
- data/docs/_pages/index.adoc +116 -0
- data/docs/_pages/introduction.adoc +256 -0
- data/docs/_pages/ler-packages.adoc +837 -0
- data/docs/_pages/parsers.adoc +683 -0
- data/docs/_pages/schema-manifests.adoc +431 -0
- data/docs/_references/index.adoc +228 -0
- data/docs/_tutorials/creating-ler-package.adoc +735 -0
- data/docs/_tutorials/documentation-coverage.adoc +795 -0
- data/docs/_tutorials/index.adoc +221 -0
- data/docs/_tutorials/liquid-templates.adoc +806 -0
- data/docs/_tutorials/parsing-your-first-schema.adoc +522 -0
- data/docs/_tutorials/querying-schemas.adoc +751 -0
- data/docs/_tutorials/working-with-multiple-schemas.adoc +676 -0
- data/docs/index.adoc +242 -0
- data/docs/lychee.toml +84 -0
- data/examples/demo_ler_usage.sh +86 -0
- data/examples/ler/README.md +111 -0
- data/examples/ler/simple_example.ler +0 -0
- data/examples/ler/simple_schema.exp +33 -0
- data/examples/ler_build.rb +75 -0
- data/examples/ler_cli.rb +79 -0
- data/examples/ler_demo_complete.rb +276 -0
- data/examples/ler_query.rb +91 -0
- data/examples/ler_query_examples.rb +305 -0
- data/examples/ler_stats.rb +81 -0
- data/examples/phase3_demo.rb +159 -0
- data/examples/query_demo_simple.rb +131 -0
- data/expressir.gemspec +2 -0
- data/lib/expressir/cli.rb +12 -4
- data/lib/expressir/commands/manifest.rb +427 -0
- data/lib/expressir/commands/package.rb +1274 -0
- data/lib/expressir/commands/validate.rb +70 -37
- data/lib/expressir/commands/validate_ascii.rb +607 -0
- data/lib/expressir/commands/validate_load.rb +88 -0
- data/lib/expressir/express/formatter.rb +5 -1
- data/lib/expressir/express/formatters/remark_item_formatter.rb +25 -0
- data/lib/expressir/express/parser.rb +33 -0
- data/lib/expressir/manifest/resolver.rb +213 -0
- data/lib/expressir/manifest/validator.rb +195 -0
- data/lib/expressir/model/declarations/entity.rb +6 -0
- data/lib/expressir/model/dependency_resolver.rb +270 -0
- data/lib/expressir/model/indexes/entity_index.rb +103 -0
- data/lib/expressir/model/indexes/reference_index.rb +148 -0
- data/lib/expressir/model/indexes/type_index.rb +149 -0
- data/lib/expressir/model/interface_validator.rb +384 -0
- data/lib/expressir/model/repository.rb +400 -5
- data/lib/expressir/model/repository_validator.rb +295 -0
- data/lib/expressir/model/search_engine.rb +525 -0
- data/lib/expressir/model.rb +4 -94
- data/lib/expressir/package/builder.rb +200 -0
- data/lib/expressir/package/metadata.rb +81 -0
- data/lib/expressir/package/reader.rb +165 -0
- data/lib/expressir/schema_manifest.rb +11 -1
- data/lib/expressir/version.rb +1 -1
- data/lib/expressir.rb +15 -2
- metadata +114 -4
- data/docs/benchmarking.adoc +0 -107
- data/docs/liquid_drops.adoc +0 -1547
data/lib/expressir/cli.rb
CHANGED
|
@@ -7,9 +7,13 @@ require_relative "commands/clean"
|
|
|
7
7
|
require_relative "commands/benchmark"
|
|
8
8
|
require_relative "commands/benchmark_cache"
|
|
9
9
|
require_relative "commands/validate"
|
|
10
|
+
require_relative "commands/validate_load"
|
|
11
|
+
require_relative "commands/validate_ascii"
|
|
10
12
|
require_relative "commands/coverage"
|
|
11
13
|
require_relative "commands/changes"
|
|
12
14
|
require_relative "commands/version"
|
|
15
|
+
require_relative "commands/package"
|
|
16
|
+
require_relative "commands/manifest"
|
|
13
17
|
|
|
14
18
|
module Expressir
|
|
15
19
|
class Cli < Thor
|
|
@@ -55,10 +59,8 @@ module Expressir
|
|
|
55
59
|
Commands::BenchmarkCache.new(options).run(path)
|
|
56
60
|
end
|
|
57
61
|
|
|
58
|
-
desc "validate
|
|
59
|
-
|
|
60
|
-
Commands::Validate.new(options).run(paths)
|
|
61
|
-
end
|
|
62
|
+
desc "validate SUBCOMMAND", "EXPRESS schema validation commands"
|
|
63
|
+
subcommand "validate", Commands::Validate
|
|
62
64
|
|
|
63
65
|
desc "coverage *PATH",
|
|
64
66
|
"List EXPRESS entities and check documentation coverage"
|
|
@@ -77,6 +79,12 @@ module Expressir
|
|
|
77
79
|
desc "changes SUBCOMMAND", "Commands for EXPRESS Changes files"
|
|
78
80
|
subcommand "changes", Commands::Changes
|
|
79
81
|
|
|
82
|
+
desc "manifest SUBCOMMAND", "Schema manifest management commands"
|
|
83
|
+
subcommand "manifest", Commands::Manifest
|
|
84
|
+
|
|
85
|
+
desc "package SUBCOMMAND", "LER package management commands"
|
|
86
|
+
subcommand "package", Commands::Package
|
|
87
|
+
|
|
80
88
|
desc "version", "Expressir Version"
|
|
81
89
|
def version
|
|
82
90
|
Commands::Version.new(options).run
|
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "thor"
|
|
4
|
+
require_relative "../schema_manifest"
|
|
5
|
+
require_relative "../model/dependency_resolver"
|
|
6
|
+
|
|
7
|
+
module Expressir
|
|
8
|
+
module Commands
|
|
9
|
+
# Manifest management CLI commands
|
|
10
|
+
# Handles schema manifest creation and validation
|
|
11
|
+
class Manifest < Thor
|
|
12
|
+
include Thor::Actions
|
|
13
|
+
|
|
14
|
+
desc "create ROOT_SCHEMA [MORE_SCHEMAS...]",
|
|
15
|
+
"Generate schema manifest from root schema(s)"
|
|
16
|
+
long_desc <<~DESC
|
|
17
|
+
Generate a YAML manifest of all schemas required for packaging.
|
|
18
|
+
|
|
19
|
+
The manifest uses the existing SchemaManifest format:
|
|
20
|
+
schemas:
|
|
21
|
+
schema_id:
|
|
22
|
+
path: /path/to/schema.exp
|
|
23
|
+
|
|
24
|
+
Workflow:
|
|
25
|
+
1. Create manifest from root schema
|
|
26
|
+
2. Edit manifest to add paths for schemas with null paths
|
|
27
|
+
3. Validate manifest
|
|
28
|
+
4. Build package using manifest
|
|
29
|
+
|
|
30
|
+
Example:
|
|
31
|
+
expressir manifest create schemas/activity/mim.exp \\
|
|
32
|
+
-o activity_manifest.yaml \\
|
|
33
|
+
--base-dirs /path/to/schemas
|
|
34
|
+
|
|
35
|
+
# With multiple base directories (space-separated)
|
|
36
|
+
expressir manifest create schemas/activity/mim.exp \\
|
|
37
|
+
-o activity_manifest.yaml \\
|
|
38
|
+
--base-dirs /path/to/resources /path/to/modules
|
|
39
|
+
|
|
40
|
+
# Or comma-separated for backward compatibility
|
|
41
|
+
expressir manifest create schemas/activity/mim.exp \\
|
|
42
|
+
-o activity_manifest.yaml \\
|
|
43
|
+
--base-dirs /path/to/resources,/path/to/modules
|
|
44
|
+
DESC
|
|
45
|
+
option :output, aliases: "-o", type: :string, required: true,
|
|
46
|
+
desc: "Output YAML file path"
|
|
47
|
+
option :base_dirs, type: :array,
|
|
48
|
+
desc: "Base directories for schema resolution (can be specified multiple times)"
|
|
49
|
+
option :verbose, type: :boolean, default: false,
|
|
50
|
+
desc: "Show detailed output"
|
|
51
|
+
def create(*root_schemas)
|
|
52
|
+
# Convert string keys to symbols for compatibility with tests
|
|
53
|
+
opts = options.transform_keys(&:to_sym)
|
|
54
|
+
|
|
55
|
+
if root_schemas.empty?
|
|
56
|
+
say "Error: At least one root schema is required", :red
|
|
57
|
+
say "Usage: expressir manifest create ROOT_SCHEMA [MORE_SCHEMAS...] -o OUTPUT.yaml",
|
|
58
|
+
:yellow
|
|
59
|
+
raise Thor::Error, "At least one root schema is required"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Verify root schemas exist
|
|
63
|
+
root_schemas.each do |schema|
|
|
64
|
+
unless File.exist?(schema)
|
|
65
|
+
say "Error: Root schema not found: #{schema}", :red
|
|
66
|
+
raise Thor::Error, "Root schema not found: #{schema}"
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
say "Creating manifest from #{root_schemas.size} root schema(s)..." if opts[:verbose]
|
|
71
|
+
|
|
72
|
+
# Parse base directories - now an array directly from Thor
|
|
73
|
+
base_dirs = if opts[:base_dirs]
|
|
74
|
+
# Thor array type accepts space-separated values in a single flag
|
|
75
|
+
# or we can also split comma-separated values for backward compatibility
|
|
76
|
+
opts[:base_dirs].flat_map do |dir|
|
|
77
|
+
dir.split(",")
|
|
78
|
+
end.map(&:strip)
|
|
79
|
+
else
|
|
80
|
+
# Default to directories containing root schemas
|
|
81
|
+
root_schemas.map do |s|
|
|
82
|
+
File.dirname(File.expand_path(s))
|
|
83
|
+
end.uniq
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
if opts[:verbose]
|
|
87
|
+
say " Base directories:"
|
|
88
|
+
base_dirs.each_with_index do |dir, index|
|
|
89
|
+
say " - [source #{index + 1}]: #{dir}"
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Resolve dependencies
|
|
94
|
+
say "Resolving dependencies..." if opts[:verbose]
|
|
95
|
+
resolver = Expressir::Model::DependencyResolver.new(
|
|
96
|
+
base_dirs: base_dirs,
|
|
97
|
+
verbose: opts[:verbose],
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
resolved_paths = resolver.resolve_dependencies(root_schemas.first)
|
|
101
|
+
|
|
102
|
+
# Create manifest using existing SchemaManifest class
|
|
103
|
+
manifest = Expressir::SchemaManifest.new
|
|
104
|
+
|
|
105
|
+
# Add resolved schemas - use actual schema name from file, not filename
|
|
106
|
+
resolved_paths.each do |path|
|
|
107
|
+
schema_id = extract_schema_name(path)
|
|
108
|
+
manifest.schemas << Expressir::SchemaManifestEntry.new(
|
|
109
|
+
id: schema_id,
|
|
110
|
+
path: path,
|
|
111
|
+
)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Add unresolved schemas with empty string paths (not nil to avoid serialization issues)
|
|
115
|
+
resolver.unresolved.uniq { |e| e[:schema_name] }.each do |entry|
|
|
116
|
+
manifest.schemas << Expressir::SchemaManifestEntry.new(
|
|
117
|
+
id: entry[:schema_name],
|
|
118
|
+
path: "",
|
|
119
|
+
)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Save manifest
|
|
123
|
+
FileUtils.mkdir_p(File.dirname(opts[:output]))
|
|
124
|
+
File.write(opts[:output], manifest.to_yaml)
|
|
125
|
+
|
|
126
|
+
# Use validator for consistent warnings (DRY - single source of truth)
|
|
127
|
+
require_relative "../manifest/validator"
|
|
128
|
+
validator = Expressir::Manifest::Validator.new(manifest, opts)
|
|
129
|
+
path_warnings = validator.validate_path_completeness
|
|
130
|
+
|
|
131
|
+
unresolved_count = path_warnings.size
|
|
132
|
+
resolved_count = manifest.schemas.size - unresolved_count
|
|
133
|
+
|
|
134
|
+
say "✓ Manifest created: #{opts[:output]}", :green
|
|
135
|
+
say " Resolved schemas: #{resolved_count}", :green
|
|
136
|
+
|
|
137
|
+
# Warn about multiple matches
|
|
138
|
+
stats = resolver.statistics
|
|
139
|
+
if stats[:multiple_matches].any?
|
|
140
|
+
say ""
|
|
141
|
+
say "⚠ Multiple matches found (#{stats[:multiple_matches].size}):",
|
|
142
|
+
:yellow
|
|
143
|
+
stats[:multiple_matches].each do |match_info|
|
|
144
|
+
say " Schema '#{match_info[:schema_name]}' found in #{match_info[:matches].size} locations:",
|
|
145
|
+
:yellow
|
|
146
|
+
match_info[:matches].each_with_index do |m, idx|
|
|
147
|
+
relative_path = m[:path].sub("#{m[:base_dir]}/", "")
|
|
148
|
+
marker = idx.zero? ? "[USING]" : " "
|
|
149
|
+
say " #{marker} [source #{m[:index] + 1}] #{relative_path}",
|
|
150
|
+
:yellow
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
say ""
|
|
154
|
+
say "The first match was used for each schema.", :yellow
|
|
155
|
+
say "If you need a different version, manually edit #{opts[:output]}",
|
|
156
|
+
:yellow
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Warn about unresolved using validator results
|
|
160
|
+
if path_warnings.any?
|
|
161
|
+
say ""
|
|
162
|
+
say "⚠ Unresolved schemas (#{unresolved_count}):", :yellow
|
|
163
|
+
path_warnings.each { |w| say " - #{w[:schema]}", :yellow }
|
|
164
|
+
say ""
|
|
165
|
+
say "Please edit #{opts[:output]} and set 'path:' for unresolved schemas",
|
|
166
|
+
:yellow
|
|
167
|
+
say "Then validate with: expressir manifest validate #{opts[:output]}",
|
|
168
|
+
:yellow
|
|
169
|
+
else
|
|
170
|
+
say " All schemas resolved successfully!", :green
|
|
171
|
+
end
|
|
172
|
+
rescue StandardError => e
|
|
173
|
+
say "Error creating manifest: #{e.message}", :red
|
|
174
|
+
say e.backtrace.join("\n") if options[:verbose]
|
|
175
|
+
raise Thor::Error, "Failed to create manifest: #{e.message}"
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
desc "resolve MANIFEST", "Resolve schema paths in manifest"
|
|
179
|
+
long_desc <<~DESC
|
|
180
|
+
Resolve missing or incomplete schema paths in a manifest file.
|
|
181
|
+
|
|
182
|
+
This command attempts to find file paths for schemas with missing or empty paths
|
|
183
|
+
by searching in base directories using naming patterns:
|
|
184
|
+
|
|
185
|
+
Supported patterns:
|
|
186
|
+
- Resource schemas: {schema_name}.exp
|
|
187
|
+
- Module ARM/MIM: {module_name}/{arm|mim}.exp
|
|
188
|
+
Example: Activity_method_mim -> activity_method/mim.exp
|
|
189
|
+
|
|
190
|
+
The resolved manifest is written to the output file, leaving the original unchanged.
|
|
191
|
+
|
|
192
|
+
Use this command after 'expressir manifest validate --check-references' fails
|
|
193
|
+
to automatically resolve missing schema paths.
|
|
194
|
+
|
|
195
|
+
Examples:
|
|
196
|
+
# Resolve paths using manifest's existing base directories
|
|
197
|
+
expressir manifest resolve manifest.yaml -o resolved_manifest.yaml
|
|
198
|
+
|
|
199
|
+
# Resolve with explicit base directories (space-separated)
|
|
200
|
+
expressir manifest resolve manifest.yaml -o resolved.yaml \\
|
|
201
|
+
--base-dirs /path/to/schemas /another/path
|
|
202
|
+
|
|
203
|
+
# Or comma-separated for backward compatibility
|
|
204
|
+
expressir manifest resolve manifest.yaml -o resolved.yaml \\
|
|
205
|
+
--base-dirs /path/to/schemas,/another/path
|
|
206
|
+
|
|
207
|
+
# With verbose output
|
|
208
|
+
expressir manifest resolve manifest.yaml -o resolved.yaml --verbose
|
|
209
|
+
DESC
|
|
210
|
+
option :output, aliases: "-o", type: :string, required: true,
|
|
211
|
+
desc: "Output file path for resolved manifest"
|
|
212
|
+
option :base_dirs, type: :array,
|
|
213
|
+
desc: "Base directories for schema search (can be specified multiple times)"
|
|
214
|
+
option :verbose, type: :boolean, default: false,
|
|
215
|
+
desc: "Show detailed resolution progress"
|
|
216
|
+
def resolve(manifest_path)
|
|
217
|
+
unless File.exist?(manifest_path)
|
|
218
|
+
say "Error: Manifest file not found: #{manifest_path}", :red
|
|
219
|
+
raise Thor::Error, "Manifest file not found: #{manifest_path}"
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
say "Resolving schema paths in: #{manifest_path}..." if options[:verbose]
|
|
223
|
+
|
|
224
|
+
# Load manifest
|
|
225
|
+
manifest = Expressir::SchemaManifest.from_file(manifest_path)
|
|
226
|
+
|
|
227
|
+
# Parse base directories - now an array directly from Thor
|
|
228
|
+
resolver_options = { verbose: options[:verbose] }
|
|
229
|
+
if options[:base_dirs]
|
|
230
|
+
# Thor array type accepts space-separated values in a single flag
|
|
231
|
+
# or we can also split comma-separated values for backward compatibility
|
|
232
|
+
resolver_options[:base_dirs] = options[:base_dirs].flat_map do |dir|
|
|
233
|
+
dir.split(",")
|
|
234
|
+
end.map(&:strip)
|
|
235
|
+
if options[:verbose]
|
|
236
|
+
say " Using base directories:"
|
|
237
|
+
resolver_options[:base_dirs].each_with_index do |dir, index|
|
|
238
|
+
say " - [source #{index + 1}]: #{dir}"
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
# Create resolver and resolve paths
|
|
244
|
+
require_relative "../manifest/resolver"
|
|
245
|
+
resolver = Expressir::Manifest::Resolver.new(manifest, resolver_options)
|
|
246
|
+
|
|
247
|
+
say "Attempting to resolve paths..." if options[:verbose]
|
|
248
|
+
resolved_manifest = resolver.resolve_paths
|
|
249
|
+
|
|
250
|
+
# Save resolved manifest
|
|
251
|
+
FileUtils.mkdir_p(File.dirname(options[:output]))
|
|
252
|
+
File.write(options[:output], resolved_manifest.to_yaml)
|
|
253
|
+
|
|
254
|
+
# Display statistics based on RESOLVED manifest (like manifest create)
|
|
255
|
+
require_relative "../manifest/validator"
|
|
256
|
+
validator = Expressir::Manifest::Validator.new(resolved_manifest,
|
|
257
|
+
options)
|
|
258
|
+
path_warnings = validator.validate_path_completeness
|
|
259
|
+
|
|
260
|
+
unresolved_count = path_warnings.size
|
|
261
|
+
resolved_count = resolved_manifest.schemas.size - unresolved_count
|
|
262
|
+
|
|
263
|
+
say "✓ Manifest resolved: #{options[:output]}", :green
|
|
264
|
+
say " Total schemas: #{resolved_manifest.schemas.size}", :green
|
|
265
|
+
say " Resolved schemas: #{resolved_count}", :green
|
|
266
|
+
|
|
267
|
+
# Warn about unresolved (like manifest create)
|
|
268
|
+
if path_warnings.any?
|
|
269
|
+
say ""
|
|
270
|
+
say "⚠ Unresolved schemas (#{unresolved_count}):", :yellow
|
|
271
|
+
path_warnings.each { |w| say " - #{w[:schema]}", :yellow }
|
|
272
|
+
say ""
|
|
273
|
+
say "These schemas could not be found in the search directories.",
|
|
274
|
+
:yellow
|
|
275
|
+
say "You may need to:", :yellow
|
|
276
|
+
say " 1. Add more base directories with --base-dirs", :yellow
|
|
277
|
+
say " 2. Manually edit #{options[:output]} and set their paths",
|
|
278
|
+
:yellow
|
|
279
|
+
else
|
|
280
|
+
say " All schema paths resolved successfully!", :green
|
|
281
|
+
end
|
|
282
|
+
rescue StandardError => e
|
|
283
|
+
say "Error resolving manifest: #{e.message}", :red
|
|
284
|
+
say e.backtrace.join("\n") if options[:verbose]
|
|
285
|
+
raise Thor::Error, "Failed to resolve manifest: #{e.message}"
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
desc "validate MANIFEST", "Validate a schema manifest"
|
|
289
|
+
long_desc <<~DESC
|
|
290
|
+
Validate a schema manifest file.
|
|
291
|
+
|
|
292
|
+
Validation types:
|
|
293
|
+
- File existence: All schema paths exist on disk
|
|
294
|
+
- Path completeness: All schemas have paths specified (warnings)
|
|
295
|
+
- Referential integrity (--check-references): All USE/REFERENCE FROM resolve
|
|
296
|
+
|
|
297
|
+
Examples:
|
|
298
|
+
# Basic validation (file existence and path completeness)
|
|
299
|
+
expressir manifest validate activity_manifest.yaml
|
|
300
|
+
|
|
301
|
+
# With referential integrity checking
|
|
302
|
+
expressir manifest validate activity_manifest.yaml --check-references
|
|
303
|
+
|
|
304
|
+
# With verbose output
|
|
305
|
+
expressir manifest validate activity_manifest.yaml --check-references --verbose
|
|
306
|
+
DESC
|
|
307
|
+
option :verbose, type: :boolean, default: false,
|
|
308
|
+
desc: "Show detailed validation results"
|
|
309
|
+
option :check_references, type: :boolean, default: false,
|
|
310
|
+
desc: "Validate referential integrity using dependency resolver"
|
|
311
|
+
def validate(manifest_path)
|
|
312
|
+
unless File.exist?(manifest_path)
|
|
313
|
+
say "Error: Manifest file not found: #{manifest_path}", :red
|
|
314
|
+
raise Thor::Error, "Manifest file not found: #{manifest_path}"
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
# Convert string keys to symbols for compatibility with tests
|
|
318
|
+
opts = options.transform_keys(&:to_sym)
|
|
319
|
+
|
|
320
|
+
say "Validating manifest: #{manifest_path}..." if opts[:verbose]
|
|
321
|
+
|
|
322
|
+
# Load manifest
|
|
323
|
+
manifest = Expressir::SchemaManifest.from_file(manifest_path)
|
|
324
|
+
|
|
325
|
+
# Create validator - SINGLE SOURCE OF TRUTH
|
|
326
|
+
require_relative "../manifest/validator"
|
|
327
|
+
validator = Expressir::Manifest::Validator.new(manifest, opts)
|
|
328
|
+
|
|
329
|
+
# Run validations using validator (NO INLINE LOGIC)
|
|
330
|
+
file_errors = validator.validate_file_existence
|
|
331
|
+
path_warnings = validator.validate_path_completeness
|
|
332
|
+
name_errors = validator.validate_schema_names
|
|
333
|
+
|
|
334
|
+
reference_errors = []
|
|
335
|
+
if opts[:check_references]
|
|
336
|
+
say "Checking referential integrity..." if opts[:verbose]
|
|
337
|
+
reference_errors = validator.validate_referential_integrity
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
# Display results
|
|
341
|
+
display_validation_results(manifest, file_errors, path_warnings,
|
|
342
|
+
name_errors, reference_errors)
|
|
343
|
+
rescue StandardError => e
|
|
344
|
+
say "Error validating manifest: #{e.message}", :red
|
|
345
|
+
say e.backtrace.join("\n") if options && options[:verbose]
|
|
346
|
+
raise Thor::Error, "Failed to validate manifest: #{e.message}"
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
private
|
|
350
|
+
|
|
351
|
+
# Extract the actual schema name from a schema file by parsing it
|
|
352
|
+
# @param schema_path [String] Path to the schema file
|
|
353
|
+
# @return [String] The schema name declared in the file
|
|
354
|
+
def extract_schema_name(schema_path)
|
|
355
|
+
require_relative "../express/parser"
|
|
356
|
+
repo = Expressir::Express::Parser.from_file(schema_path)
|
|
357
|
+
schema = repo.schemas.first
|
|
358
|
+
schema&.id || File.basename(schema_path, ".*")
|
|
359
|
+
rescue StandardError
|
|
360
|
+
# Fallback to filename if parsing fails
|
|
361
|
+
File.basename(schema_path, ".*")
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
def display_validation_results(manifest, file_errors, path_warnings,
|
|
365
|
+
name_errors, reference_errors)
|
|
366
|
+
# Convert string keys to symbols for compatibility with tests
|
|
367
|
+
opts = options.transform_keys(&:to_sym)
|
|
368
|
+
|
|
369
|
+
# Calculate counts
|
|
370
|
+
unresolved_count = manifest.schemas.count do |s|
|
|
371
|
+
s.path.nil? || s.path.empty?
|
|
372
|
+
end
|
|
373
|
+
resolved_count = manifest.schemas.size - unresolved_count
|
|
374
|
+
|
|
375
|
+
# Determine if validation passed
|
|
376
|
+
has_errors = file_errors.any? || name_errors.any? || reference_errors.any?
|
|
377
|
+
|
|
378
|
+
if has_errors
|
|
379
|
+
say "✗ Manifest validation failed", :red
|
|
380
|
+
say ""
|
|
381
|
+
|
|
382
|
+
if file_errors.any?
|
|
383
|
+
say "File Errors (#{file_errors.size}):", :red
|
|
384
|
+
file_errors.each { |e| say " - #{e[:message]}", :red }
|
|
385
|
+
say ""
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
if name_errors.any?
|
|
389
|
+
say "Schema Name Errors (#{name_errors.size}):", :red
|
|
390
|
+
name_errors.each { |e| say " - #{e[:message]}", :red }
|
|
391
|
+
say ""
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
if reference_errors.any?
|
|
395
|
+
say "Reference Errors (#{reference_errors.size}):", :red
|
|
396
|
+
reference_errors.each { |e| say " - #{e[:message]}", :red }
|
|
397
|
+
say ""
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
if path_warnings.any?
|
|
401
|
+
say "Warnings (#{path_warnings.size}):", :yellow
|
|
402
|
+
path_warnings.each { |w| say " - #{w[:message]}", :yellow }
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
raise Thor::Error, "Manifest validation failed"
|
|
406
|
+
else
|
|
407
|
+
say "✓ Manifest is valid", :green
|
|
408
|
+
if opts[:verbose]
|
|
409
|
+
say " Total schemas: #{manifest.schemas.size}",
|
|
410
|
+
:green
|
|
411
|
+
end
|
|
412
|
+
say " Resolved schemas: #{resolved_count}", :green if opts[:verbose]
|
|
413
|
+
if opts[:verbose] && unresolved_count.positive?
|
|
414
|
+
say " Unresolved schemas: #{unresolved_count}",
|
|
415
|
+
:green
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
if path_warnings.any?
|
|
419
|
+
say ""
|
|
420
|
+
say "Warnings (#{path_warnings.size}):", :yellow
|
|
421
|
+
path_warnings.each { |w| say " - #{w[:message]}", :yellow }
|
|
422
|
+
end
|
|
423
|
+
end
|
|
424
|
+
end
|
|
425
|
+
end
|
|
426
|
+
end
|
|
427
|
+
end
|