expressir 2.1.25 → 2.1.27
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/.rubocop_todo.yml +199 -26
- data/Gemfile +1 -0
- data/README.adoc +288 -0
- data/expressir.gemspec +1 -1
- data/lib/expressir/changes/edition_change.rb +32 -0
- data/lib/expressir/changes/item_change.rb +22 -0
- data/lib/expressir/changes/mapping_change.rb +18 -0
- data/lib/expressir/changes/schema_change.rb +84 -0
- data/lib/expressir/changes.rb +12 -0
- data/lib/expressir/cli.rb +4 -1
- data/lib/expressir/commands/changes.rb +36 -0
- data/lib/expressir/commands/changes_import_eengine.rb +107 -0
- data/lib/expressir/commands/changes_validate.rb +67 -0
- data/lib/expressir/commands/coverage.rb +90 -54
- data/lib/expressir/schema_manifest.rb +2 -1
- data/lib/expressir/version.rb +1 -1
- data/lib/expressir.rb +9 -0
- metadata +15 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 79f9083d84c90911c68536e3f07c4a2ebeb7675bca18d445b7af90d9ece6e7ee
|
4
|
+
data.tar.gz: 69e648f694b883906a32fc316219db79dbaa053c2633a4543cd4b62673a9f88d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d9cc037357c9803c739a486089fc69b4799b1ba02f5f9de51216175447765f0e650dc02f8c525d2c4be8a3ea38e2ac953c5ef22e530ce4fea1f42f902eead456
|
7
|
+
data.tar.gz: aca50dfe25f95e07453607f76df4ca532a3c3e97f8d95af08442c5a5ff402434a80e3fa6b2f8147992b72fefbaa1c3b9487f001095960b605abd5a3cfecd2bf1
|
data/.rubocop_todo.yml
CHANGED
@@ -1,18 +1,116 @@
|
|
1
1
|
# This configuration was generated by
|
2
2
|
# `rubocop --auto-gen-config`
|
3
|
-
# on 2025-
|
3
|
+
# on 2025-10-12 15:55:59 UTC using RuboCop version 1.81.1.
|
4
4
|
# The point is for the user to remove these configuration records
|
5
5
|
# one by one as the offenses are removed from the code base.
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
7
7
|
# versions of RuboCop, may require this file to be generated again.
|
8
8
|
|
9
|
-
# Offense count:
|
9
|
+
# Offense count: 9
|
10
|
+
# This cop supports safe autocorrection (--autocorrect).
|
11
|
+
# Configuration parameters: EnforcedStyle, IndentationWidth.
|
12
|
+
# SupportedStyles: with_first_argument, with_fixed_indentation
|
13
|
+
Layout/ArgumentAlignment:
|
14
|
+
Exclude:
|
15
|
+
- 'lib/expressir/commands/changes.rb'
|
16
|
+
- 'spec/expressir/changes/schema_change_spec.rb'
|
17
|
+
- 'spec/expressir/commands/changes_import_eengine_spec.rb'
|
18
|
+
- 'spec/expressir/commands/changes_validate_spec.rb'
|
19
|
+
|
20
|
+
# Offense count: 1
|
21
|
+
# This cop supports safe autocorrection (--autocorrect).
|
22
|
+
# Configuration parameters: EnforcedStyleAlignWith.
|
23
|
+
# SupportedStylesAlignWith: either, start_of_block, start_of_line
|
24
|
+
Layout/BlockAlignment:
|
25
|
+
Exclude:
|
26
|
+
- 'lib/expressir/changes/schema_change.rb'
|
27
|
+
|
28
|
+
# Offense count: 1
|
29
|
+
# This cop supports safe autocorrection (--autocorrect).
|
30
|
+
Layout/BlockEndNewline:
|
31
|
+
Exclude:
|
32
|
+
- 'lib/expressir/changes/schema_change.rb'
|
33
|
+
|
34
|
+
# Offense count: 1
|
35
|
+
# This cop supports safe autocorrection (--autocorrect).
|
36
|
+
# Configuration parameters: AllowForAlignment.
|
37
|
+
Layout/CommentIndentation:
|
38
|
+
Exclude:
|
39
|
+
- 'lib/expressir/commands/changes_validate.rb'
|
40
|
+
|
41
|
+
# Offense count: 2
|
42
|
+
# This cop supports safe autocorrection (--autocorrect).
|
43
|
+
Layout/ElseAlignment:
|
44
|
+
Exclude:
|
45
|
+
- 'lib/expressir/commands/changes_validate.rb'
|
46
|
+
|
47
|
+
# Offense count: 2
|
48
|
+
# This cop supports safe autocorrection (--autocorrect).
|
49
|
+
# Configuration parameters: EnforcedStyle.
|
50
|
+
# SupportedStyles: empty_lines, no_empty_lines
|
51
|
+
Layout/EmptyLinesAroundBlockBody:
|
52
|
+
Exclude:
|
53
|
+
- 'bin/validate_all_changes'
|
54
|
+
|
55
|
+
# Offense count: 1
|
56
|
+
# This cop supports safe autocorrection (--autocorrect).
|
57
|
+
# Configuration parameters: EnforcedStyleAlignWith, Severity.
|
58
|
+
# SupportedStylesAlignWith: keyword, variable, start_of_line
|
59
|
+
Layout/EndAlignment:
|
60
|
+
Exclude:
|
61
|
+
- 'lib/expressir/commands/changes_validate.rb'
|
62
|
+
|
63
|
+
# Offense count: 12
|
64
|
+
# This cop supports safe autocorrection (--autocorrect).
|
65
|
+
# Configuration parameters: AllowMultipleStyles, EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle.
|
66
|
+
# SupportedHashRocketStyles: key, separator, table
|
67
|
+
# SupportedColonStyles: key, separator, table
|
68
|
+
# SupportedLastArgumentHashStyles: always_inspect, always_ignore, ignore_implicit, ignore_explicit
|
69
|
+
Layout/HashAlignment:
|
70
|
+
Exclude:
|
71
|
+
- 'lib/expressir/commands/changes.rb'
|
72
|
+
- 'spec/expressir/changes/schema_change_spec.rb'
|
73
|
+
- 'spec/expressir/commands/changes_validate_spec.rb'
|
74
|
+
|
75
|
+
# Offense count: 6
|
76
|
+
# This cop supports safe autocorrection (--autocorrect).
|
77
|
+
# Configuration parameters: Width, AllowedPatterns.
|
78
|
+
Layout/IndentationWidth:
|
79
|
+
Exclude:
|
80
|
+
- 'bin/validate_all_changes'
|
81
|
+
- 'lib/expressir/changes/schema_change.rb'
|
82
|
+
- 'lib/expressir/commands/changes_validate.rb'
|
83
|
+
|
84
|
+
# Offense count: 574
|
10
85
|
# This cop supports safe autocorrection (--autocorrect).
|
11
86
|
# Configuration parameters: Max, AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, IgnoreCopDirectives, AllowedPatterns, SplitStrings.
|
12
87
|
# URISchemes: http, https
|
13
88
|
Layout/LineLength:
|
14
89
|
Enabled: false
|
15
90
|
|
91
|
+
# Offense count: 1
|
92
|
+
# This cop supports safe autocorrection (--autocorrect).
|
93
|
+
Layout/RescueEnsureAlignment:
|
94
|
+
Exclude:
|
95
|
+
- 'bin/validate_all_changes'
|
96
|
+
|
97
|
+
# Offense count: 8
|
98
|
+
# This cop supports safe autocorrection (--autocorrect).
|
99
|
+
# Configuration parameters: AllowInHeredoc.
|
100
|
+
Layout/TrailingWhitespace:
|
101
|
+
Exclude:
|
102
|
+
- 'bin/validate_all_changes'
|
103
|
+
- 'lib/expressir/commands/changes.rb'
|
104
|
+
- 'spec/expressir/changes/schema_change_spec.rb'
|
105
|
+
- 'spec/expressir/commands/changes_import_eengine_spec.rb'
|
106
|
+
- 'spec/expressir/commands/changes_validate_spec.rb'
|
107
|
+
|
108
|
+
# Offense count: 4
|
109
|
+
# This cop supports safe autocorrection (--autocorrect).
|
110
|
+
Lint/AmbiguousOperatorPrecedence:
|
111
|
+
Exclude:
|
112
|
+
- 'bin/validate_all_changes'
|
113
|
+
|
16
114
|
# Offense count: 1
|
17
115
|
# Configuration parameters: IgnoreLiteralBranches, IgnoreConstantBranches, IgnoreDuplicateElseBranch.
|
18
116
|
Lint/DuplicateBranch:
|
@@ -21,43 +119,32 @@ Lint/DuplicateBranch:
|
|
21
119
|
|
22
120
|
# Offense count: 2
|
23
121
|
# This cop supports safe autocorrection (--autocorrect).
|
24
|
-
# Configuration parameters:
|
122
|
+
# Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods, IgnoreNotImplementedMethods, NotImplementedExceptions.
|
25
123
|
# NotImplementedExceptions: NotImplementedError
|
26
124
|
Lint/UnusedMethodArgument:
|
27
125
|
Exclude:
|
28
126
|
- 'lib/expressir/express/cache.rb'
|
29
127
|
- 'lib/expressir/express/parser.rb'
|
30
128
|
|
31
|
-
# Offense count:
|
129
|
+
# Offense count: 83
|
32
130
|
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
|
33
131
|
Metrics/AbcSize:
|
34
|
-
|
35
|
-
- 'lib/expressir/benchmark.rb'
|
36
|
-
- 'lib/expressir/commands/benchmark.rb'
|
37
|
-
- 'lib/expressir/commands/benchmark_cache.rb'
|
38
|
-
- 'lib/expressir/commands/coverage.rb'
|
39
|
-
- 'lib/expressir/commands/validate.rb'
|
40
|
-
- 'lib/expressir/config.rb'
|
41
|
-
- 'lib/expressir/coverage.rb'
|
42
|
-
- 'lib/expressir/express/formatter.rb'
|
43
|
-
- 'lib/expressir/express/hyperlink_formatter.rb'
|
44
|
-
- 'lib/expressir/express/parser.rb'
|
45
|
-
- 'lib/expressir/express/resolve_references_model_visitor.rb'
|
46
|
-
- 'lib/expressir/express/visitor.rb'
|
47
|
-
- 'lib/expressir/model/declarations/schema.rb'
|
48
|
-
- 'lib/expressir/model/model_element.rb'
|
132
|
+
Enabled: false
|
49
133
|
|
50
|
-
# Offense count:
|
134
|
+
# Offense count: 2
|
51
135
|
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns, inherit_mode.
|
52
136
|
# AllowedMethods: refine
|
53
137
|
Metrics/BlockLength:
|
54
|
-
Max:
|
138
|
+
Max: 72
|
55
139
|
|
56
|
-
# Offense count:
|
140
|
+
# Offense count: 59
|
57
141
|
# Configuration parameters: AllowedMethods, AllowedPatterns, Max.
|
58
142
|
Metrics/CyclomaticComplexity:
|
59
143
|
Exclude:
|
60
144
|
- 'lib/expressir/benchmark.rb'
|
145
|
+
- 'lib/expressir/changes/schema_change.rb'
|
146
|
+
- 'lib/expressir/commands/changes_import_eengine.rb'
|
147
|
+
- 'lib/expressir/commands/changes_validate.rb'
|
61
148
|
- 'lib/expressir/commands/coverage.rb'
|
62
149
|
- 'lib/expressir/coverage.rb'
|
63
150
|
- 'lib/expressir/express/formatter.rb'
|
@@ -68,16 +155,19 @@ Metrics/CyclomaticComplexity:
|
|
68
155
|
- 'lib/expressir/model/model_element.rb'
|
69
156
|
- 'spec/support/model_element_helper.rb'
|
70
157
|
|
71
|
-
# Offense count:
|
158
|
+
# Offense count: 109
|
72
159
|
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
|
73
160
|
Metrics/MethodLength:
|
74
161
|
Max: 106
|
75
162
|
|
76
|
-
# Offense count:
|
163
|
+
# Offense count: 47
|
77
164
|
# Configuration parameters: AllowedMethods, AllowedPatterns, Max.
|
78
165
|
Metrics/PerceivedComplexity:
|
79
166
|
Exclude:
|
80
167
|
- 'lib/expressir/benchmark.rb'
|
168
|
+
- 'lib/expressir/changes/schema_change.rb'
|
169
|
+
- 'lib/expressir/commands/changes_import_eengine.rb'
|
170
|
+
- 'lib/expressir/commands/changes_validate.rb'
|
81
171
|
- 'lib/expressir/commands/coverage.rb'
|
82
172
|
- 'lib/expressir/coverage.rb'
|
83
173
|
- 'lib/expressir/express/formatter.rb'
|
@@ -104,7 +194,7 @@ Performance/MapMethodChain:
|
|
104
194
|
- 'spec/expressir/commands/coverage_ignore_files_spec.rb'
|
105
195
|
- 'spec/expressir/coverage_spec.rb'
|
106
196
|
|
107
|
-
# Offense count:
|
197
|
+
# Offense count: 122
|
108
198
|
# Configuration parameters: CountAsOne.
|
109
199
|
RSpec/ExampleLength:
|
110
200
|
Max: 123
|
@@ -121,11 +211,12 @@ RSpec/IndexedLet:
|
|
121
211
|
- 'spec/expressir/model/data_types/string_spec.rb'
|
122
212
|
|
123
213
|
# Offense count: 1
|
214
|
+
# This cop supports safe autocorrection (--autocorrect).
|
124
215
|
RSpec/IteratedExpectation:
|
125
216
|
Exclude:
|
126
217
|
- 'spec/expressir/schema_manifest_spec.rb'
|
127
218
|
|
128
|
-
# Offense count:
|
219
|
+
# Offense count: 254
|
129
220
|
RSpec/MultipleExpectations:
|
130
221
|
Max: 114
|
131
222
|
|
@@ -146,7 +237,89 @@ RSpec/RepeatedExample:
|
|
146
237
|
Exclude:
|
147
238
|
- 'spec/expressir/model/data_types/logical_spec.rb'
|
148
239
|
|
240
|
+
# Offense count: 2
|
241
|
+
# This cop supports unsafe autocorrection (--autocorrect-all).
|
242
|
+
Security/YAMLLoad:
|
243
|
+
Exclude:
|
244
|
+
- 'bin/validate_all_changes'
|
245
|
+
|
246
|
+
# Offense count: 1
|
247
|
+
# This cop supports safe autocorrection (--autocorrect).
|
248
|
+
# Configuration parameters: EnforcedStyle, ProceduralMethods, FunctionalMethods, AllowedMethods, AllowedPatterns, AllowBracesOnProceduralOneLiners, BracesRequiredMethods.
|
249
|
+
# SupportedStyles: line_count_based, semantic, braces_for_chaining, always_braces
|
250
|
+
# ProceduralMethods: benchmark, bm, bmbm, create, each_with_object, measure, new, realtime, tap, with_object
|
251
|
+
# FunctionalMethods: let, let!, subject, watch
|
252
|
+
# AllowedMethods: lambda, proc, it
|
253
|
+
Style/BlockDelimiters:
|
254
|
+
Exclude:
|
255
|
+
- 'lib/expressir/changes/schema_change.rb'
|
256
|
+
|
257
|
+
# Offense count: 1
|
258
|
+
# This cop supports safe autocorrection (--autocorrect).
|
259
|
+
# Configuration parameters: EnforcedStyle, AllowComments.
|
260
|
+
# SupportedStyles: empty, nil, both
|
261
|
+
Style/EmptyElse:
|
262
|
+
Exclude:
|
263
|
+
- 'lib/expressir/commands/changes_validate.rb'
|
264
|
+
|
149
265
|
# Offense count: 1
|
150
266
|
Style/MissingRespondToMissing:
|
151
267
|
Exclude:
|
152
268
|
- 'lib/expressir/express/visitor.rb'
|
269
|
+
|
270
|
+
# Offense count: 1
|
271
|
+
# This cop supports unsafe autocorrection (--autocorrect-all).
|
272
|
+
# Configuration parameters: EnforcedStyle, AllowedMethods, AllowedPatterns.
|
273
|
+
# SupportedStyles: predicate, comparison
|
274
|
+
Style/NumericPredicate:
|
275
|
+
Exclude:
|
276
|
+
- 'spec/**/*'
|
277
|
+
- 'lib/expressir/commands/changes_import_eengine.rb'
|
278
|
+
|
279
|
+
# Offense count: 1
|
280
|
+
# This cop supports safe autocorrection (--autocorrect).
|
281
|
+
Style/RedundantBegin:
|
282
|
+
Exclude:
|
283
|
+
- 'bin/validate_all_changes'
|
284
|
+
|
285
|
+
# Offense count: 4
|
286
|
+
# This cop supports unsafe autocorrection (--autocorrect-all).
|
287
|
+
# Configuration parameters: Mode.
|
288
|
+
Style/StringConcatenation:
|
289
|
+
Exclude:
|
290
|
+
- 'bin/validate_all_changes'
|
291
|
+
|
292
|
+
# Offense count: 4
|
293
|
+
# This cop supports safe autocorrection (--autocorrect).
|
294
|
+
# Configuration parameters: EnforcedStyle.
|
295
|
+
# SupportedStyles: single_quotes, double_quotes
|
296
|
+
Style/StringLiteralsInInterpolation:
|
297
|
+
Exclude:
|
298
|
+
- 'bin/validate_all_changes'
|
299
|
+
|
300
|
+
# Offense count: 4
|
301
|
+
# This cop supports safe autocorrection (--autocorrect).
|
302
|
+
# Configuration parameters: EnforcedStyleForMultiline.
|
303
|
+
# SupportedStylesForMultiline: comma, consistent_comma, diff_comma, no_comma
|
304
|
+
Style/TrailingCommaInArguments:
|
305
|
+
Exclude:
|
306
|
+
- 'lib/expressir/changes/schema_change.rb'
|
307
|
+
- 'lib/expressir/commands/changes_import_eengine.rb'
|
308
|
+
|
309
|
+
# Offense count: 5
|
310
|
+
# This cop supports safe autocorrection (--autocorrect).
|
311
|
+
# Configuration parameters: EnforcedStyleForMultiline.
|
312
|
+
# SupportedStylesForMultiline: comma, consistent_comma, diff_comma, no_comma
|
313
|
+
Style/TrailingCommaInArrayLiteral:
|
314
|
+
Exclude:
|
315
|
+
- 'spec/expressir/changes/schema_change_spec.rb'
|
316
|
+
|
317
|
+
# Offense count: 10
|
318
|
+
# This cop supports safe autocorrection (--autocorrect).
|
319
|
+
# Configuration parameters: EnforcedStyleForMultiline.
|
320
|
+
# SupportedStylesForMultiline: comma, consistent_comma, diff_comma, no_comma
|
321
|
+
Style/TrailingCommaInHashLiteral:
|
322
|
+
Exclude:
|
323
|
+
- 'bin/validate_all_changes'
|
324
|
+
- 'lib/expressir/commands/changes_import_eengine.rb'
|
325
|
+
- 'spec/expressir/changes/schema_change_spec.rb'
|
data/Gemfile
CHANGED
data/README.adoc
CHANGED
@@ -76,6 +76,7 @@ $ expressir
|
|
76
76
|
Commands:
|
77
77
|
expressir benchmark FILE_OR_YAML # Benchmark schema loading performance for a file or list of files from YAML
|
78
78
|
expressir benchmark-cache FILE_OR_YAML # Benchmark schema loading with caching
|
79
|
+
expressir changes SUBCOMMAND # Commands for EXPRESS Changes files
|
79
80
|
expressir clean PATH # Strip remarks and prettify EXPRESS schema at PATH
|
80
81
|
expressir format PATH # pretty print EXPRESS schema located at PATH
|
81
82
|
expressir help [COMMAND] # Describe available commands or one specific command
|
@@ -667,6 +668,103 @@ The default text output displays:
|
|
667
668
|
This helps identify areas of your EXPRESS schemas that need documentation
|
668
669
|
improvement.
|
669
670
|
|
671
|
+
=== EXPRESS Changes files
|
672
|
+
|
673
|
+
Expressir provides commands for working with EXPRESS Changes files that track
|
674
|
+
schema modifications across versions.
|
675
|
+
|
676
|
+
==== Validating change files
|
677
|
+
|
678
|
+
The `changes validate` command validates EXPRESS Changes YAML files and
|
679
|
+
optionally normalizes them through round-trip serialization.
|
680
|
+
|
681
|
+
[source, sh]
|
682
|
+
----
|
683
|
+
# Validate a changes file
|
684
|
+
expressir changes validate schema.changes.yaml
|
685
|
+
|
686
|
+
# Validate with verbose output
|
687
|
+
expressir changes validate schema.changes.yaml --verbose
|
688
|
+
|
689
|
+
# Validate and normalize (outputs to stdout)
|
690
|
+
expressir changes validate schema.changes.yaml --normalize
|
691
|
+
|
692
|
+
# Validate and normalize in-place
|
693
|
+
expressir changes validate schema.changes.yaml --normalize --in-place
|
694
|
+
|
695
|
+
# Validate and save normalized output to a new file
|
696
|
+
expressir changes validate schema.changes.yaml --normalize --output normalized.yaml
|
697
|
+
----
|
698
|
+
|
699
|
+
[options="header"]
|
700
|
+
|===
|
701
|
+
| Option | Description
|
702
|
+
| `--normalize` | Normalize file through round-trip serialization
|
703
|
+
| `--in-place` | Update file in place (requires `--normalize`)
|
704
|
+
| `--output PATH` | Output file path for normalized output
|
705
|
+
| `--verbose` | Show verbose output with validation details
|
706
|
+
|===
|
707
|
+
|
708
|
+
The validate command performs the following checks:
|
709
|
+
|
710
|
+
. Verifies the YAML file can be parsed
|
711
|
+
. Validates against the SchemaChange model structure
|
712
|
+
. Ensures all required fields are present
|
713
|
+
. Checks that change items have valid types
|
714
|
+
|
715
|
+
When using `--normalize`, the command:
|
716
|
+
|
717
|
+
. Loads the file and validates it
|
718
|
+
. Serializes it back to YAML with consistent formatting
|
719
|
+
. Either outputs to stdout, saves in-place, or writes to a new file
|
720
|
+
|
721
|
+
This is useful for:
|
722
|
+
|
723
|
+
* **Standardizing formatting**: Ensures consistent YAML structure
|
724
|
+
* **Catching errors early**: Validates before committing changes
|
725
|
+
* **Cleaning up files**: Removes inconsistencies in formatting
|
726
|
+
|
727
|
+
==== Importing from eengine XML
|
728
|
+
|
729
|
+
The `changes import-eengine` command converts eengine comparison XML files to
|
730
|
+
EXPRESS Changes YAML format.
|
731
|
+
|
732
|
+
[source, sh]
|
733
|
+
----
|
734
|
+
# Import and output to stdout
|
735
|
+
expressir changes import-eengine comparison.xml schema_name "2"
|
736
|
+
|
737
|
+
# Import and save to file
|
738
|
+
expressir changes import-eengine comparison.xml schema_name "2" -o output.yaml
|
739
|
+
|
740
|
+
# Import with verbose output
|
741
|
+
expressir changes import-eengine comparison.xml schema_name "2" -o output.yaml --verbose
|
742
|
+
|
743
|
+
# Append to existing changes file
|
744
|
+
expressir changes import-eengine comparison.xml schema_name "3" -o existing.yaml
|
745
|
+
----
|
746
|
+
|
747
|
+
[options="header"]
|
748
|
+
|===
|
749
|
+
| Option | Description
|
750
|
+
| `-o, --output PATH` | Output YAML file path (stdout if not specified)
|
751
|
+
| `--verbose` | Show verbose output
|
752
|
+
|===
|
753
|
+
|
754
|
+
The import command:
|
755
|
+
|
756
|
+
. Parses the eengine XML comparison file
|
757
|
+
. Extracts additions, modifications, and removals
|
758
|
+
. Creates or updates an EXPRESS Changes YAML file
|
759
|
+
. Supports appending new versions to existing files
|
760
|
+
|
761
|
+
When the output file already exists:
|
762
|
+
|
763
|
+
* **Same version**: Replaces the existing edition with that version
|
764
|
+
* **New version**: Adds a new edition to the file
|
765
|
+
|
766
|
+
This allows you to build up a complete change history incrementally.
|
767
|
+
|
670
768
|
|
671
769
|
== Usage: Ruby
|
672
770
|
|
@@ -1063,6 +1161,196 @@ expressir coverage schemas.yml --format json --exclude=TYPE:SELECT
|
|
1063
1161
|
|
1064
1162
|
|
1065
1163
|
|
1164
|
+
== Working with EXPRESS Changes
|
1165
|
+
|
1166
|
+
=== General
|
1167
|
+
|
1168
|
+
Expressir provides the `Changes` module for managing and tracking changes to
|
1169
|
+
EXPRESS schemas across versions. This module implements the EXPRESS Changes YAML
|
1170
|
+
format defined by ELF (Express Language Foundation).
|
1171
|
+
|
1172
|
+
The Changes module enables:
|
1173
|
+
|
1174
|
+
* Loading and saving schema change records from/to YAML files
|
1175
|
+
* Programmatic creation and manipulation of change records
|
1176
|
+
* Smart edition handling (replace same version, add new version)
|
1177
|
+
* Support for all change types: additions, modifications, removals, deletions
|
1178
|
+
* Support for mapping changes in ARM/MIM schemas
|
1179
|
+
|
1180
|
+
=== Reading change files
|
1181
|
+
|
1182
|
+
Load an existing schema change file:
|
1183
|
+
|
1184
|
+
[source,ruby]
|
1185
|
+
----
|
1186
|
+
require "expressir/changes"
|
1187
|
+
|
1188
|
+
# Load from file
|
1189
|
+
change_schema = Expressir::Changes::SchemaChange.from_file("schema.changes.yaml")
|
1190
|
+
|
1191
|
+
# Access schema name
|
1192
|
+
puts "Schema: #{change_schema.schema}"
|
1193
|
+
|
1194
|
+
# Iterate through change editions
|
1195
|
+
change_schema.edition_change.each do |edition|
|
1196
|
+
puts "Version #{edition.version}: #{edition.description}"
|
1197
|
+
|
1198
|
+
# Access changes by type
|
1199
|
+
puts " Additions: #{edition.additions.size}" if edition.additions
|
1200
|
+
puts " Modifications: #{edition.modifications.size}" if edition.modifications
|
1201
|
+
puts " Deletions: #{edition.deletions.size}" if edition.deletions
|
1202
|
+
puts " Removals: #{edition.removals.size}" if edition.removals
|
1203
|
+
end
|
1204
|
+
----
|
1205
|
+
|
1206
|
+
=== Creating change records
|
1207
|
+
|
1208
|
+
Create a new change schema programmatically:
|
1209
|
+
|
1210
|
+
[source,ruby]
|
1211
|
+
----
|
1212
|
+
# Create a new empty change schema
|
1213
|
+
change_schema = Expressir::Changes::SchemaChange.create_new("my_schema")
|
1214
|
+
|
1215
|
+
# Create change items
|
1216
|
+
new_entity = Expressir::Changes::ItemChange.new(
|
1217
|
+
type: "ENTITY",
|
1218
|
+
name: "new_entity_name"
|
1219
|
+
)
|
1220
|
+
|
1221
|
+
modified_function = Expressir::Changes::ItemChange.new(
|
1222
|
+
type: "FUNCTION",
|
1223
|
+
name: "modified_function",
|
1224
|
+
description: "Updated parameters"
|
1225
|
+
)
|
1226
|
+
|
1227
|
+
# Add a change edition
|
1228
|
+
changes = {
|
1229
|
+
additions: [new_entity],
|
1230
|
+
modifications: [modified_function],
|
1231
|
+
removals: []
|
1232
|
+
}
|
1233
|
+
|
1234
|
+
change_schema.add_or_update_edition(
|
1235
|
+
"2",
|
1236
|
+
"Added new entity and modified function",
|
1237
|
+
changes
|
1238
|
+
)
|
1239
|
+
|
1240
|
+
# Save to file
|
1241
|
+
change_schema.to_file("my_schema.changes.yaml")
|
1242
|
+
----
|
1243
|
+
|
1244
|
+
=== Updating existing change files
|
1245
|
+
|
1246
|
+
The `add_or_update_edition` method provides smart handling:
|
1247
|
+
|
1248
|
+
* **Same version**: Replaces the existing edition
|
1249
|
+
* **Different version**: Adds a new edition
|
1250
|
+
|
1251
|
+
[source,ruby]
|
1252
|
+
----
|
1253
|
+
# Load existing change file
|
1254
|
+
change_schema = Expressir::Changes::SchemaChange.from_file("schema.changes.yaml")
|
1255
|
+
|
1256
|
+
# Add a new version
|
1257
|
+
changes = {
|
1258
|
+
modifications: [
|
1259
|
+
Expressir::Changes::ItemChange.new(type: "TYPE", name: "updated_type")
|
1260
|
+
]
|
1261
|
+
}
|
1262
|
+
change_schema.add_or_update_edition("3", "Modified type definition", changes)
|
1263
|
+
|
1264
|
+
# Or replace existing version
|
1265
|
+
change_schema.add_or_update_edition("2", "Revised description", changes)
|
1266
|
+
|
1267
|
+
# Save changes
|
1268
|
+
change_schema.to_file("schema.changes.yaml")
|
1269
|
+
----
|
1270
|
+
|
1271
|
+
=== Change item fields
|
1272
|
+
|
1273
|
+
Change items support the following fields:
|
1274
|
+
|
1275
|
+
`type`:: (Required) The EXPRESS construct type (ENTITY, TYPE, FUNCTION, etc.)
|
1276
|
+
`name`:: (Required) The name of the construct
|
1277
|
+
`description`:: (Optional) Additional details about the change
|
1278
|
+
`interfaced_items`:: (Optional) For REFERENCE_FROM items
|
1279
|
+
|
1280
|
+
[source,ruby]
|
1281
|
+
----
|
1282
|
+
item = Expressir::Changes::ItemChange.new(
|
1283
|
+
type: "REFERENCE_FROM",
|
1284
|
+
name: "measure_schema",
|
1285
|
+
interfaced_items: "length_measure"
|
1286
|
+
)
|
1287
|
+
----
|
1288
|
+
|
1289
|
+
=== Change edition fields
|
1290
|
+
|
1291
|
+
Change editions support categorizing changes into:
|
1292
|
+
|
1293
|
+
`additions`:: New elements added to the schema
|
1294
|
+
`modifications`:: Existing elements that were modified
|
1295
|
+
`removals`:: Elements removed from the schema
|
1296
|
+
`deletions`:: Alternative term for removals (both supported)
|
1297
|
+
`mapping`:: Mapping-related changes (for ARM/MIM modules)
|
1298
|
+
`changes`:: General changes (alternative to mapping)
|
1299
|
+
|
1300
|
+
[source,ruby]
|
1301
|
+
----
|
1302
|
+
edition = Expressir::Changes::EditionChange.new(
|
1303
|
+
version: "2",
|
1304
|
+
description: "Added support for new functionality",
|
1305
|
+
additions: [item1, item2],
|
1306
|
+
modifications: [item3],
|
1307
|
+
deletions: [item4],
|
1308
|
+
mapping: [mapping_change]
|
1309
|
+
)
|
1310
|
+
----
|
1311
|
+
|
1312
|
+
=== Mapping changes
|
1313
|
+
|
1314
|
+
For ARM/MIM schema mappings, use `MappingChange`:
|
1315
|
+
|
1316
|
+
[source,ruby]
|
1317
|
+
----
|
1318
|
+
mapping_change = Expressir::Changes::MappingChange.new(
|
1319
|
+
change: "Entity_name ENTITY mapping updated"
|
1320
|
+
)
|
1321
|
+
----
|
1322
|
+
|
1323
|
+
=== Example change file format
|
1324
|
+
|
1325
|
+
[source,yaml]
|
1326
|
+
----
|
1327
|
+
---
|
1328
|
+
schema: support_resource_schema
|
1329
|
+
edition_change:
|
1330
|
+
- version: '2'
|
1331
|
+
description: |-
|
1332
|
+
The definitions of the following EXPRESS entity data types were modified:
|
1333
|
+
|
1334
|
+
* action;
|
1335
|
+
* action_directive;
|
1336
|
+
* action_method.
|
1337
|
+
additions:
|
1338
|
+
- type: FUNCTION
|
1339
|
+
name: type_check_function
|
1340
|
+
modifications:
|
1341
|
+
- type: FUNCTION
|
1342
|
+
name: bag_to_set
|
1343
|
+
- version: '4'
|
1344
|
+
description: |-
|
1345
|
+
Added support for external element references.
|
1346
|
+
additions:
|
1347
|
+
- type: ENTITY
|
1348
|
+
name: component_path_shape_aspect
|
1349
|
+
modifications:
|
1350
|
+
- type: FUNCTION
|
1351
|
+
name: type_check_function
|
1352
|
+
----
|
1353
|
+
|
1066
1354
|
== Contributing
|
1067
1355
|
|
1068
1356
|
First, thank you for contributing! We love pull requests from everyone. By
|
data/expressir.gemspec
CHANGED
@@ -38,6 +38,6 @@ Gem::Specification.new do |spec|
|
|
38
38
|
spec.add_dependency "lutaml-model"
|
39
39
|
spec.add_dependency "parslet", "~> 2.0"
|
40
40
|
spec.add_dependency "ruby-progressbar", "~> 1.11"
|
41
|
-
spec.add_dependency "
|
41
|
+
spec.add_dependency "table_tennis"
|
42
42
|
spec.add_dependency "thor", "~> 1.0"
|
43
43
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "lutaml/model"
|
4
|
+
require_relative "item_change"
|
5
|
+
require_relative "mapping_change"
|
6
|
+
|
7
|
+
module Expressir
|
8
|
+
module Changes
|
9
|
+
# Represents a version edition of schema changes
|
10
|
+
class EditionChange < Lutaml::Model::Serializable
|
11
|
+
attribute :version, :string
|
12
|
+
attribute :description, :string
|
13
|
+
attribute :additions, ItemChange, collection: true
|
14
|
+
attribute :modifications, ItemChange, collection: true
|
15
|
+
attribute :removals, ItemChange, collection: true
|
16
|
+
attribute :deletions, ItemChange, collection: true
|
17
|
+
attribute :mapping, MappingChange, collection: true
|
18
|
+
attribute :changes, MappingChange, collection: true
|
19
|
+
|
20
|
+
yaml do
|
21
|
+
map "version", to: :version
|
22
|
+
map "description", to: :description
|
23
|
+
map "additions", to: :additions
|
24
|
+
map "modifications", to: :modifications
|
25
|
+
map "removals", to: :removals
|
26
|
+
map "deletions", to: :deletions
|
27
|
+
map "mapping", to: :mapping
|
28
|
+
map "changes", to: :changes
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "lutaml/model"
|
4
|
+
|
5
|
+
module Expressir
|
6
|
+
module Changes
|
7
|
+
# Represents a single change to an EXPRESS construct
|
8
|
+
class ItemChange < Lutaml::Model::Serializable
|
9
|
+
attribute :type, :string
|
10
|
+
attribute :name, :string
|
11
|
+
attribute :description, :string
|
12
|
+
attribute :interfaced_items, :string
|
13
|
+
|
14
|
+
yaml do
|
15
|
+
map "type", to: :type
|
16
|
+
map "name", to: :name
|
17
|
+
map "description", to: :description
|
18
|
+
map "interfaced_items", to: :interfaced_items
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "lutaml/model"
|
4
|
+
|
5
|
+
module Expressir
|
6
|
+
module Changes
|
7
|
+
# Represents a mapping change entry
|
8
|
+
class MappingChange < Lutaml::Model::Serializable
|
9
|
+
attribute :change, :string
|
10
|
+
attribute :description, :string
|
11
|
+
|
12
|
+
yaml do
|
13
|
+
map "change", to: :change
|
14
|
+
map "description", to: :description
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "lutaml/model"
|
4
|
+
require_relative "edition_change"
|
5
|
+
|
6
|
+
module Expressir
|
7
|
+
module Changes
|
8
|
+
# Represents changes to an EXPRESS schema across multiple versions
|
9
|
+
class SchemaChange < Lutaml::Model::Serializable
|
10
|
+
attribute :schema, :string
|
11
|
+
attribute :edition_change, EditionChange, collection: true
|
12
|
+
|
13
|
+
yaml do
|
14
|
+
map "schema", to: :schema
|
15
|
+
map "edition_change", to: :edition_change
|
16
|
+
end
|
17
|
+
|
18
|
+
class << self
|
19
|
+
# Load a SchemaChange from a YAML file
|
20
|
+
#
|
21
|
+
# @param path [String] Path to the YAML file
|
22
|
+
# @return [SchemaChange] The loaded schema changes
|
23
|
+
def from_file(path)
|
24
|
+
content = File.read(path)
|
25
|
+
# Handle empty or minimal YAML files
|
26
|
+
return new(schema: "", edition_change: []) if content.strip == "---"
|
27
|
+
|
28
|
+
from_yaml(content)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Create a new empty SchemaChange
|
32
|
+
#
|
33
|
+
# @param schema_name [String] Name of the schema
|
34
|
+
# @return [SchemaChange] New instance with empty change editions
|
35
|
+
def create_new(schema_name)
|
36
|
+
new(schema: schema_name, edition_change: [])
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Add or update a change edition in this schema
|
41
|
+
#
|
42
|
+
# @param version [String] Version number
|
43
|
+
# @param description [String] Description of changes
|
44
|
+
# @param changes [Hash] Hash with :additions, :modifications, :removals
|
45
|
+
# @return [EditionChange] The added or updated edition
|
46
|
+
def add_or_update_edition(version, description, changes)
|
47
|
+
version_str = version.to_s
|
48
|
+
|
49
|
+
# Find existing edition with this version
|
50
|
+
existing_index = edition_change.find_index do |ed|
|
51
|
+
ed.version == version_str
|
52
|
+
end
|
53
|
+
|
54
|
+
# Create new edition
|
55
|
+
edition = EditionChange.new(
|
56
|
+
version: version_str,
|
57
|
+
description: description,
|
58
|
+
additions: changes[:additions] || [],
|
59
|
+
modifications: changes[:modifications] || [],
|
60
|
+
removals: changes[:removals] || [],
|
61
|
+
deletions: changes[:deletions] || [],
|
62
|
+
)
|
63
|
+
|
64
|
+
if existing_index
|
65
|
+
# Replace existing edition with same version
|
66
|
+
edition_change[existing_index] = edition
|
67
|
+
else
|
68
|
+
# Add new edition
|
69
|
+
edition_change << edition
|
70
|
+
end
|
71
|
+
|
72
|
+
edition
|
73
|
+
end
|
74
|
+
|
75
|
+
# Save this SchemaChange to a YAML file
|
76
|
+
#
|
77
|
+
# @param path [String] Path where to save the file
|
78
|
+
# @return [Integer] Number of bytes written
|
79
|
+
def to_file(path)
|
80
|
+
File.write(path, to_yaml)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "changes/schema_change"
|
4
|
+
require_relative "changes/edition_change"
|
5
|
+
require_relative "changes/item_change"
|
6
|
+
require_relative "changes/mapping_change"
|
7
|
+
|
8
|
+
module Expressir
|
9
|
+
# Module for EXPRESS schema change tracking and management
|
10
|
+
module Changes
|
11
|
+
end
|
12
|
+
end
|
data/lib/expressir/cli.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
require "thor"
|
2
2
|
require "yaml"
|
3
|
-
require "terminal-table"
|
4
3
|
|
5
4
|
require_relative "commands/base"
|
6
5
|
require_relative "commands/format"
|
@@ -9,6 +8,7 @@ require_relative "commands/benchmark"
|
|
9
8
|
require_relative "commands/benchmark_cache"
|
10
9
|
require_relative "commands/validate"
|
11
10
|
require_relative "commands/coverage"
|
11
|
+
require_relative "commands/changes"
|
12
12
|
require_relative "commands/version"
|
13
13
|
|
14
14
|
module Expressir
|
@@ -74,6 +74,9 @@ module Expressir
|
|
74
74
|
Commands::Coverage.new(options).run(paths)
|
75
75
|
end
|
76
76
|
|
77
|
+
desc "changes SUBCOMMAND", "Commands for EXPRESS Changes files"
|
78
|
+
subcommand "changes", Commands::Changes
|
79
|
+
|
77
80
|
desc "version", "Expressir Version"
|
78
81
|
def version
|
79
82
|
Commands::Version.new(options).run
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "thor"
|
4
|
+
|
5
|
+
module Expressir
|
6
|
+
module Commands
|
7
|
+
# Thor subcommand for EXPRESS Changes file operations
|
8
|
+
class Changes < Thor
|
9
|
+
desc "validate PATH", "Validate EXPRESS Changes YAML file"
|
10
|
+
method_option :normalize, type: :boolean,
|
11
|
+
desc: "Normalize file through round-trip serialization"
|
12
|
+
method_option :in_place, type: :boolean,
|
13
|
+
desc: "Update file in place (requires --normalize)"
|
14
|
+
method_option :output, type: :string,
|
15
|
+
desc: "Output file path (for normalized output)"
|
16
|
+
method_option :verbose, type: :boolean,
|
17
|
+
desc: "Show verbose output"
|
18
|
+
def validate(path)
|
19
|
+
require_relative "changes_validate"
|
20
|
+
ChangesValidate.new(options).run(path)
|
21
|
+
end
|
22
|
+
|
23
|
+
desc "import-eengine INPUT_XML SCHEMA_NAME VERSION",
|
24
|
+
"Import eengine comparison XML to EXPRESS Changes YAML"
|
25
|
+
method_option :output, type: :string, aliases: "-o",
|
26
|
+
desc: "Output YAML file path (stdout if not specified)"
|
27
|
+
method_option :verbose, type: :boolean,
|
28
|
+
desc: "Show verbose output"
|
29
|
+
def import_eengine(input_xml, schema_name, version)
|
30
|
+
require_relative "changes_import_eengine"
|
31
|
+
ChangesImportEengine.call(input_xml, options[:output], schema_name,
|
32
|
+
version, **options)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
require "nokogiri"
|
5
|
+
|
6
|
+
module Expressir
|
7
|
+
module Commands
|
8
|
+
# Command to import eengine comparison XML to EXPRESS Changes YAML
|
9
|
+
class ChangesImportEengine < Base
|
10
|
+
def self.call(input_file, output_file, schema_name, version, **options)
|
11
|
+
new.call(input_file, output_file, schema_name, version, **options)
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(input_file, output_file, schema_name, version, **options)
|
15
|
+
require "expressir/changes"
|
16
|
+
|
17
|
+
# Parse the eengine XML
|
18
|
+
xml_doc = File.open(input_file) { |f| Nokogiri::XML(f) }
|
19
|
+
|
20
|
+
# Extract changes from XML
|
21
|
+
changes = extract_changes(xml_doc)
|
22
|
+
description = generate_description(xml_doc)
|
23
|
+
|
24
|
+
# Load or create change schema
|
25
|
+
change_schema = if output_file && File.exist?(output_file) && File.size(output_file).positive?
|
26
|
+
Expressir::Changes::SchemaChange.from_file(output_file)
|
27
|
+
else
|
28
|
+
Expressir::Changes::SchemaChange.create_new(schema_name)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Add or update edition
|
32
|
+
change_schema.add_or_update_edition(version, description, changes)
|
33
|
+
|
34
|
+
# Save to file
|
35
|
+
if output_file
|
36
|
+
change_schema.to_file(output_file)
|
37
|
+
puts "Change YAML file written to: #{output_file}" if options[:verbose]
|
38
|
+
else
|
39
|
+
puts change_schema.to_yaml
|
40
|
+
end
|
41
|
+
|
42
|
+
change_schema
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def extract_changes(xml_doc)
|
48
|
+
{
|
49
|
+
additions: extract_added_objects(xml_doc),
|
50
|
+
modifications: extract_modified_objects(xml_doc),
|
51
|
+
removals: extract_removed_objects(xml_doc),
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
def extract_modified_objects(xml_doc)
|
56
|
+
xml_doc.xpath("//schema.modifications/modified.object").map do |node|
|
57
|
+
Expressir::Changes::ItemChange.new(
|
58
|
+
type: node["type"],
|
59
|
+
name: node["name"],
|
60
|
+
)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def extract_added_objects(xml_doc)
|
65
|
+
xml_doc.xpath("//schema.additions/added.object").map do |node|
|
66
|
+
Expressir::Changes::ItemChange.new(
|
67
|
+
type: node["type"],
|
68
|
+
name: node["name"],
|
69
|
+
)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def extract_removed_objects(xml_doc)
|
74
|
+
xml_doc.xpath("//schema.removals/removed.object").map do |node|
|
75
|
+
Expressir::Changes::ItemChange.new(
|
76
|
+
type: node["type"],
|
77
|
+
name: node["name"],
|
78
|
+
)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def generate_description(xml_doc)
|
83
|
+
parts = []
|
84
|
+
|
85
|
+
# Get descriptions from modifications
|
86
|
+
xml_doc.xpath("//schema.modifications/modified.object/description").each do |desc|
|
87
|
+
text = desc.text.strip
|
88
|
+
parts << text unless text.empty?
|
89
|
+
end
|
90
|
+
|
91
|
+
# Get descriptions from additions
|
92
|
+
xml_doc.xpath("//schema.additions/added.object/description").each do |desc|
|
93
|
+
text = desc.text.strip
|
94
|
+
parts << text unless text.empty?
|
95
|
+
end
|
96
|
+
|
97
|
+
# Get descriptions from removals
|
98
|
+
xml_doc.xpath("//schema.removals/removed.object/description").each do |desc|
|
99
|
+
text = desc.text.strip
|
100
|
+
parts << text unless text.empty?
|
101
|
+
end
|
102
|
+
|
103
|
+
parts.join("\n\n")
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
module Expressir
|
6
|
+
module Commands
|
7
|
+
# Command to validate and normalize EXPRESS Changes YAML files
|
8
|
+
class ChangesValidate < Base
|
9
|
+
def run(path)
|
10
|
+
require "expressir/changes"
|
11
|
+
|
12
|
+
# Check if file exists
|
13
|
+
unless File.exist?(path)
|
14
|
+
exit_with_error("File not found: #{path}")
|
15
|
+
end
|
16
|
+
|
17
|
+
# Validate --in-place requires --normalize
|
18
|
+
if options[:in_place] && !options[:normalize]
|
19
|
+
exit_with_error("--in-place requires --normalize flag")
|
20
|
+
end
|
21
|
+
|
22
|
+
# Validate --in-place and --output are mutually exclusive
|
23
|
+
if options[:in_place] && options[:output]
|
24
|
+
exit_with_error("Cannot use both --in-place and --output")
|
25
|
+
end
|
26
|
+
|
27
|
+
begin
|
28
|
+
# Load and validate the file
|
29
|
+
say "Validating #{path}..." if options[:verbose]
|
30
|
+
schema_change = Expressir::Changes::SchemaChange.from_file(path)
|
31
|
+
|
32
|
+
say "✓ File is valid" if options[:verbose]
|
33
|
+
say " Schema: #{schema_change.schema}" if options[:verbose]
|
34
|
+
say " Editions: #{schema_change.edition_change.length}" if options[:verbose]
|
35
|
+
|
36
|
+
# Normalize if requested
|
37
|
+
if options[:normalize]
|
38
|
+
say "Normalizing through round-trip serialization..." if options[:verbose]
|
39
|
+
|
40
|
+
output_path = if options[:in_place]
|
41
|
+
path
|
42
|
+
elsif options[:output]
|
43
|
+
options[:output]
|
44
|
+
else
|
45
|
+
# Output to stdout
|
46
|
+
nil
|
47
|
+
end
|
48
|
+
|
49
|
+
if output_path
|
50
|
+
schema_change.to_file(output_path)
|
51
|
+
say "✓ Normalized file written to: #{output_path}"
|
52
|
+
else
|
53
|
+
# Output to stdout
|
54
|
+
puts schema_change.to_yaml
|
55
|
+
end
|
56
|
+
else
|
57
|
+
say "✓ File is valid"
|
58
|
+
end
|
59
|
+
rescue Psych::SyntaxError => e
|
60
|
+
exit_with_error("Invalid YAML syntax: #{e.message}")
|
61
|
+
rescue StandardError => e
|
62
|
+
exit_with_error("Validation failed: #{e.message}")
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require "
|
1
|
+
require "table_tennis"
|
2
2
|
require "json"
|
3
3
|
require "yaml"
|
4
4
|
require "ruby-progressbar"
|
@@ -173,55 +173,79 @@ module Expressir
|
|
173
173
|
end
|
174
174
|
end
|
175
175
|
|
176
|
-
|
177
|
-
table = Terminal::Table.new(
|
178
|
-
title: "Directory Coverage",
|
179
|
-
headings: ["Directory", "Total", "Documented", "Coverage %"],
|
180
|
-
style: {
|
181
|
-
border_x: "-",
|
182
|
-
border_y: "|",
|
183
|
-
border_i: "+",
|
184
|
-
},
|
185
|
-
)
|
186
|
-
|
187
|
-
# Add rows
|
176
|
+
table_data = []
|
188
177
|
dirs.each do |dir, stats|
|
189
178
|
coverage = stats["total"].positive? ? (stats["documented"].to_f / stats["total"] * 100).round(2) : 100.0
|
190
|
-
|
191
|
-
|
179
|
+
table_data << {
|
180
|
+
directory: dir,
|
181
|
+
total: stats["total"].to_s,
|
182
|
+
documented: stats["documented"].to_s,
|
183
|
+
coverage_percentage: "#{coverage}%",
|
184
|
+
}
|
192
185
|
end
|
193
186
|
|
187
|
+
table = TableTennis.new(
|
188
|
+
table_data,
|
189
|
+
{
|
190
|
+
title: "Entity coverage per directory",
|
191
|
+
headers: {
|
192
|
+
file: "Directory",
|
193
|
+
total: "Total Entities",
|
194
|
+
documented: "Documented Entities",
|
195
|
+
coverage_percentage: "Coverage %",
|
196
|
+
},
|
197
|
+
titleize: true,
|
198
|
+
layout: true,
|
199
|
+
},
|
200
|
+
)
|
201
|
+
|
194
202
|
say table
|
195
203
|
end
|
196
204
|
|
197
205
|
def display_file_coverage(reports)
|
198
|
-
|
199
|
-
|
200
|
-
# Create table
|
201
|
-
table = Terminal::Table.new(
|
202
|
-
title: "File Coverage",
|
203
|
-
headings: ["File", "Undocumented Entities", "Coverage %"],
|
204
|
-
style: {
|
205
|
-
border_x: "-",
|
206
|
-
border_y: "|",
|
207
|
-
border_i: "+",
|
208
|
-
},
|
209
|
-
)
|
210
|
-
|
206
|
+
# Prepare data for table_tennis
|
207
|
+
table_data = []
|
211
208
|
reports.each do |report|
|
212
209
|
report.file_reports.each do |file_report|
|
213
210
|
file_path = file_report["file"]
|
214
211
|
|
215
212
|
# Format undocumented entities as "TYPE name, TYPE name, ..."
|
216
|
-
|
213
|
+
undocumented = file_report["undocumented"].map do |entity_info|
|
217
214
|
"#{entity_info['type']} #{entity_info['name']}"
|
218
215
|
end.join(", ")
|
219
216
|
|
220
217
|
coverage = file_report["coverage"].round(2)
|
221
|
-
|
218
|
+
|
219
|
+
table_data << {
|
220
|
+
filename: File.basename(file_path),
|
221
|
+
undocumented_entities: if undocumented.empty?
|
222
|
+
"None"
|
223
|
+
else
|
224
|
+
undocumented
|
225
|
+
end,
|
226
|
+
coverage_percentage: "#{coverage}%",
|
227
|
+
}
|
222
228
|
end
|
223
229
|
end
|
224
230
|
|
231
|
+
table = TableTennis.new(
|
232
|
+
table_data,
|
233
|
+
{
|
234
|
+
title: "Entity coverage in file",
|
235
|
+
headers: {
|
236
|
+
filename: "Filename",
|
237
|
+
undocumented_entities: "Undocumented Entities",
|
238
|
+
coverage_percentage: "Coverage %",
|
239
|
+
},
|
240
|
+
titleize: true,
|
241
|
+
layout: {
|
242
|
+
filename: 30,
|
243
|
+
undocumented_entities: 50,
|
244
|
+
coverage_percentage: 20,
|
245
|
+
},
|
246
|
+
},
|
247
|
+
)
|
248
|
+
|
225
249
|
say table
|
226
250
|
end
|
227
251
|
|
@@ -229,22 +253,35 @@ module Expressir
|
|
229
253
|
# Get structured report for overall statistics
|
230
254
|
overall = build_structured_report(reports)["overall"]
|
231
255
|
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
256
|
+
coverage_percentage = overall["coverage_percentage"]
|
257
|
+
table_data = [
|
258
|
+
{
|
259
|
+
metric: "Coverage Percentage",
|
260
|
+
value: "#{coverage_percentage}%",
|
261
|
+
},
|
262
|
+
{
|
263
|
+
metric: "Total Entities",
|
264
|
+
value: overall["total_entities"].to_s,
|
265
|
+
},
|
266
|
+
{
|
267
|
+
metric: "Documented Entities",
|
268
|
+
value: overall["documented_entities"].to_s,
|
269
|
+
},
|
270
|
+
{
|
271
|
+
metric: "Undocumented Entities",
|
272
|
+
value: overall["undocumented_entities"].to_s,
|
273
|
+
},
|
274
|
+
]
|
275
|
+
|
276
|
+
table = TableTennis.new(
|
277
|
+
table_data,
|
278
|
+
{
|
279
|
+
title: "Entity overall coverage",
|
280
|
+
titleize: true,
|
281
|
+
layout: true,
|
238
282
|
},
|
239
283
|
)
|
240
284
|
|
241
|
-
table.add_row ["Coverage Percentage",
|
242
|
-
"#{overall['coverage_percentage']}%"]
|
243
|
-
table.add_row ["Total Entities", overall["total_entities"]]
|
244
|
-
table.add_row ["Documented Entities", overall["documented_entities"]]
|
245
|
-
table.add_row ["Undocumented Entities",
|
246
|
-
overall["undocumented_entities"]]
|
247
|
-
|
248
285
|
say table
|
249
286
|
end
|
250
287
|
|
@@ -253,6 +290,15 @@ module Expressir
|
|
253
290
|
ignored_files = reports.flat_map(&:ignored_file_reports)
|
254
291
|
ignored_entities_count = ignored_files.sum { |f| f["total"] }
|
255
292
|
|
293
|
+
total = reports.sum { |r| r.total_entities.size }
|
294
|
+
documented = reports.sum { |r| r.documented_entities.size }
|
295
|
+
|
296
|
+
coverage_per = if total.positive?
|
297
|
+
(documented.to_f / total * 100).round(2)
|
298
|
+
else
|
299
|
+
100.0
|
300
|
+
end
|
301
|
+
|
256
302
|
overall_stats = {
|
257
303
|
"total_entities" => reports.sum { |r| r.total_entities.size },
|
258
304
|
"documented_entities" => reports.sum do |r|
|
@@ -261,17 +307,7 @@ module Expressir
|
|
261
307
|
"undocumented_entities" => reports.sum do |r|
|
262
308
|
r.undocumented_entities.size
|
263
309
|
end,
|
264
|
-
"coverage_percentage" =>
|
265
|
-
r.total_entities.size
|
266
|
-
end.positive?
|
267
|
-
(reports.sum do |r|
|
268
|
-
r.documented_entities.size
|
269
|
-
end.to_f / reports.sum do |r|
|
270
|
-
r.total_entities.size
|
271
|
-
end * 100).round(2)
|
272
|
-
else
|
273
|
-
100.0
|
274
|
-
end,
|
310
|
+
"coverage_percentage" => coverage_per,
|
275
311
|
}
|
276
312
|
|
277
313
|
# Add ignored file information if there are any
|
@@ -28,7 +28,8 @@ module Expressir
|
|
28
28
|
x.set_initial_path(path)
|
29
29
|
end
|
30
30
|
rescue StandardError => e
|
31
|
-
raise InvalidSchemaManifestError,
|
31
|
+
raise InvalidSchemaManifestError,
|
32
|
+
"Invalid schema manifest format: #{e.message}"
|
32
33
|
end
|
33
34
|
|
34
35
|
def to_file(to_path = path)
|
data/lib/expressir/version.rb
CHANGED
data/lib/expressir.rb
CHANGED
@@ -170,11 +170,20 @@ module Expressir
|
|
170
170
|
autoload :Benchmark, "expressir/commands/benchmark"
|
171
171
|
autoload :BenchmarkCache, "expressir/commands/benchmark_cache"
|
172
172
|
autoload :Clean, "expressir/commands/clean"
|
173
|
+
autoload :ImportComparison, "expressir/commands/import_comparison"
|
173
174
|
autoload :Coverage, "expressir/commands/coverage"
|
174
175
|
autoload :Format, "expressir/commands/format"
|
175
176
|
autoload :Validate, "expressir/commands/validate"
|
176
177
|
autoload :Version, "expressir/commands/version"
|
177
178
|
end
|
179
|
+
|
180
|
+
# Autoload for Changes module classes
|
181
|
+
module Changes
|
182
|
+
autoload :SchemaChange, "expressir/changes/schema_change"
|
183
|
+
autoload :EditionChange, "expressir/changes/edition_change"
|
184
|
+
autoload :ItemChange, "expressir/changes/item_change"
|
185
|
+
autoload :MappingChange, "expressir/changes/mapping_change"
|
186
|
+
end
|
178
187
|
end
|
179
188
|
|
180
189
|
require_relative "expressir/model"
|
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.1.
|
4
|
+
version: 2.1.27
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ribose Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-10-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: base64
|
@@ -109,19 +109,19 @@ dependencies:
|
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '1.11'
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
|
-
name:
|
112
|
+
name: table_tennis
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
|
-
- - "
|
115
|
+
- - ">="
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version: '
|
117
|
+
version: '0'
|
118
118
|
type: :runtime
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
|
-
- - "
|
122
|
+
- - ">="
|
123
123
|
- !ruby/object:Gem::Version
|
124
|
-
version: '
|
124
|
+
version: '0'
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
126
|
name: thor
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -169,10 +169,18 @@ files:
|
|
169
169
|
- expressir.gemspec
|
170
170
|
- lib/expressir.rb
|
171
171
|
- lib/expressir/benchmark.rb
|
172
|
+
- lib/expressir/changes.rb
|
173
|
+
- lib/expressir/changes/edition_change.rb
|
174
|
+
- lib/expressir/changes/item_change.rb
|
175
|
+
- lib/expressir/changes/mapping_change.rb
|
176
|
+
- lib/expressir/changes/schema_change.rb
|
172
177
|
- lib/expressir/cli.rb
|
173
178
|
- lib/expressir/commands/base.rb
|
174
179
|
- lib/expressir/commands/benchmark.rb
|
175
180
|
- lib/expressir/commands/benchmark_cache.rb
|
181
|
+
- lib/expressir/commands/changes.rb
|
182
|
+
- lib/expressir/commands/changes_import_eengine.rb
|
183
|
+
- lib/expressir/commands/changes_validate.rb
|
176
184
|
- lib/expressir/commands/clean.rb
|
177
185
|
- lib/expressir/commands/coverage.rb
|
178
186
|
- lib/expressir/commands/format.rb
|