suma 0.2.5 → 0.2.6

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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rake.yml +3 -0
  3. data/.github/workflows/release.yml +5 -1
  4. data/.rubocop_todo.yml +78 -26
  5. data/CLAUDE.md +76 -0
  6. data/Gemfile +3 -1
  7. data/README.adoc +131 -0
  8. data/lib/suma/cli/build.rb +2 -3
  9. data/lib/suma/cli/check_svg_quality.rb +178 -0
  10. data/lib/suma/cli/compare.rb +7 -158
  11. data/lib/suma/cli/export.rb +1 -7
  12. data/lib/suma/cli/extract_terms.rb +7 -648
  13. data/lib/suma/cli/generate_schemas.rb +9 -123
  14. data/lib/suma/cli/validate_links.rb +15 -290
  15. data/lib/suma/cli.rb +39 -0
  16. data/lib/suma/collection_manifest.rb +3 -4
  17. data/lib/suma/express_schema.rb +43 -30
  18. data/lib/suma/jsdai/figure_xml.rb +12 -9
  19. data/lib/suma/jsdai.rb +0 -6
  20. data/lib/suma/link_validator.rb +203 -0
  21. data/lib/suma/processor.rb +75 -101
  22. data/lib/suma/schema_attachment.rb +2 -29
  23. data/lib/suma/schema_collection.rb +1 -32
  24. data/lib/suma/schema_comparer.rb +116 -0
  25. data/lib/suma/schema_document.rb +0 -14
  26. data/lib/suma/schema_exporter.rb +16 -28
  27. data/lib/suma/schema_index.rb +53 -0
  28. data/lib/suma/schema_manifest_generator.rb +105 -0
  29. data/lib/suma/svg_quality/batch_report.rb +80 -0
  30. data/lib/suma/svg_quality/formatters/json_formatter.rb +30 -0
  31. data/lib/suma/svg_quality/formatters/terminal_formatter.rb +168 -0
  32. data/lib/suma/svg_quality/formatters/yaml_formatter.rb +32 -0
  33. data/lib/suma/svg_quality/report.rb +52 -0
  34. data/lib/suma/svg_quality.rb +28 -0
  35. data/lib/suma/term_extractor.rb +393 -0
  36. data/lib/suma/utils.rb +10 -2
  37. data/lib/suma/version.rb +1 -1
  38. data/lib/suma.rb +3 -2
  39. data/suma.gemspec +3 -2
  40. metadata +33 -7
  41. data/lib/suma/export_standalone_schema.rb +0 -14
@@ -1,12 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "thor"
4
- require_relative "../eengine/wrapper"
5
- require_relative "../eengine_converter"
4
+ require_relative "../schema_comparer"
6
5
 
7
6
  module Suma
8
7
  module Cli
9
- # Command to compare EXPRESS schemas using eengine
10
8
  class Compare < Thor
11
9
  desc "compare TRIAL_SCHEMA REFERENCE_SCHEMA",
12
10
  "Compare EXPRESS schemas using eengine and generate Change YAML"
@@ -44,166 +42,17 @@ module Suma
44
42
  desc: "Enable verbose output"
45
43
 
46
44
  def compare(trial_schema, reference_schema)
47
- # Validate schema files exist
48
- unless File.exist?(trial_schema)
49
- say "Error: Trial schema not found: #{trial_schema}", :red
50
- exit 1
51
- end
52
-
53
- unless File.exist?(reference_schema)
54
- say "Error: Reference schema not found: #{reference_schema}", :red
55
- exit 1
56
- end
57
-
58
- # Check eengine availability
59
- unless Eengine::Wrapper.available?
60
- say "Error: eengine not found in PATH", :red
61
- say "Install eengine following instructions at:"
62
- say " macOS: https://github.com/expresslang/homebrew-eengine"
63
- say " Linux: https://github.com/expresslang/eengine-releases"
64
- exit 1
65
- end
45
+ comparer = SchemaComparer.new(trial_schema, reference_schema, options)
66
46
 
67
- # Auto-detect repo roots
68
- trial_stepmod = options[:trial_stepmod] ||
69
- detect_repo_root(trial_schema)
70
- reference_stepmod = options[:reference_stepmod] ||
71
- detect_repo_root(reference_schema)
47
+ result = comparer.compare
72
48
 
73
- if options[:verbose]
74
- say "Using eengine version: #{Eengine::Wrapper.version}", :green
75
- say "Trial repo root: #{trial_stepmod}", :cyan
76
- say "Reference repo root: #{reference_stepmod}", :cyan
77
- end
78
-
79
- # Create a temporary directory for eengine output
80
- require "tmpdir"
81
- out_dir = nil
82
- out_dir = Dir.mktmpdir("eengine-compare-")
83
-
84
- # Run comparison
85
- result = Eengine::Wrapper.compare(
86
- trial_schema,
87
- reference_schema,
88
- mode: options[:mode],
89
- trial_stepmod: trial_stepmod,
90
- reference_stepmod: reference_stepmod,
91
- out_dir: out_dir,
92
- )
93
-
94
- unless result[:has_changes]
49
+ if result.nil?
95
50
  say "No changes detected between schemas", :yellow
96
- # Clean up temp directory
97
- FileUtils.rm_rf(out_dir) if out_dir && File.directory?(out_dir)
98
- return
99
- end
100
-
101
- unless result[:xml_path]
102
- say "Error: XML output not found", :red
103
- exit 1
104
- end
105
-
106
- if options[:verbose]
107
- say "Comparison XML generated: #{result[:xml_path]}", :green
108
- end
109
-
110
- # Convert to Change YAML
111
- convert_to_change_yaml(result[:xml_path], trial_schema, out_dir)
112
- rescue Eengine::EengineError => e
113
- # Clean up temp directory
114
- FileUtils.rm_rf(out_dir) if out_dir && File.directory?(out_dir)
115
- say "Error: #{e.message}", :red
116
- say e.stderr if e.respond_to?(:stderr) && options[:verbose]
117
- exit 1
118
- end
119
-
120
- private
121
-
122
- def detect_repo_root(schema_path)
123
- # Walk up from schema path to find .git directory
124
- current = File.expand_path(File.dirname(schema_path))
125
-
126
- loop do
127
- if File.directory?(File.join(current, ".git"))
128
- return current
129
- end
130
-
131
- parent = File.dirname(current)
132
- break if parent == current # reached root
133
-
134
- current = parent
135
- end
136
-
137
- # If no .git found, use the directory containing the schema
138
- # (for non-git workflows)
139
- File.dirname(schema_path)
140
- end
141
-
142
- def convert_to_change_yaml(xml_path, trial_schema, out_dir)
143
- schema_name = extract_schema_name(trial_schema)
144
- output_path = determine_output_path(trial_schema)
145
-
146
- # Load existing ChangeSchema if it exists
147
- existing_schema = if File.exist?(output_path)
148
- if options[:verbose]
149
- say "Loading existing change schema: " \
150
- "#{output_path}", :cyan
151
- end
152
- require "expressir/changes"
153
- Expressir::Changes::SchemaChange.from_file(output_path)
154
- end
155
-
156
- # Convert using Suma's converter
157
- converter = EengineConverter.new(xml_path, schema_name)
158
- change_schema = converter.convert(
159
- version: options[:version],
160
- existing_change_schema: existing_schema,
161
- )
162
-
163
- # Save using Expressir model
164
- change_schema.to_file(output_path)
165
-
166
- # Determine what action was taken
167
- if existing_schema
168
- existing_version = existing_schema.versions.find do |ed|
169
- ed.version == options[:version]
170
- end
171
-
172
- say "Change YAML file updated: #{output_path}", :green
173
- if existing_version
174
- say " Replaced existing version #{options[:version]}", :green
175
- else
176
- say " Added version #{options[:version]} to change versions",
177
- :green
178
- end
179
- else
180
- say "Change YAML file created: #{output_path}", :green
181
- end
182
-
183
- if options[:verbose]
184
- say "\nGenerated change schema content:", :cyan
185
- say File.read(output_path)
186
- end
187
-
188
- # Clean up temp directory and XML file
189
- FileUtils.rm_rf(out_dir) if out_dir && File.directory?(out_dir)
190
- end
191
-
192
- def extract_schema_name(path)
193
- # Remove version suffix if present (e.g., schema_1.exp -> schema)
194
- basename = File.basename(path, ".exp")
195
- basename.sub(/_\d+$/, "")
196
- end
197
-
198
- def determine_output_path(trial_schema)
199
- if options[:output]
200
- options[:output]
201
51
  else
202
- # Place .changes.yaml next to the trial schema in the NEW repo
203
- base = extract_schema_name(trial_schema)
204
- dir = File.dirname(trial_schema)
205
- File.join(dir, "#{base}.changes.yaml")
52
+ say "Change YAML file: #{result}", :green
206
53
  end
54
+ rescue Suma::Error => e
55
+ raise Thor::Error, e.message
207
56
  end
208
57
  end
209
58
  end
@@ -2,7 +2,6 @@
2
2
 
3
3
  require "thor"
4
4
  require_relative "../thor_ext"
5
- require_relative "../export_standalone_schema"
6
5
 
7
6
  module Suma
8
7
  module Cli
@@ -85,12 +84,7 @@ module Suma
85
84
  end
86
85
 
87
86
  def create_schema_from_exp_file(exp_file)
88
- # Create a schema object from a standalone EXPRESS file
89
- # The id will be determined during parsing
90
- ExportStandaloneSchema.new(
91
- id: nil,
92
- path: File.expand_path(exp_file),
93
- )
87
+ Struct.new(:id, :path).new(nil, File.expand_path(exp_file))
94
88
  end
95
89
 
96
90
  def self.exit_on_failure?