suma 0.2.6 → 0.4.0

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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +7 -1
  3. data/.rubocop_todo.yml +170 -13
  4. data/CLAUDE.md +37 -11
  5. data/Gemfile +3 -3
  6. data/README.adoc +127 -13
  7. data/exe/suma +1 -1
  8. data/lib/suma/cli/build.rb +0 -5
  9. data/lib/suma/cli/check_svg_quality.rb +82 -97
  10. data/lib/suma/cli/compare.rb +0 -1
  11. data/lib/suma/cli/convert_jsdai.rb +0 -2
  12. data/lib/suma/cli/core.rb +119 -0
  13. data/lib/suma/cli/export.rb +37 -22
  14. data/lib/suma/cli/extract_terms.rb +5 -8
  15. data/lib/suma/cli/generate_register.rb +34 -0
  16. data/lib/suma/cli/generate_schemas.rb +0 -2
  17. data/lib/suma/cli/reformat.rb +39 -64
  18. data/lib/suma/cli/validate.rb +14 -7
  19. data/lib/suma/cli/validate_links.rb +11 -157
  20. data/lib/suma/cli.rb +12 -141
  21. data/lib/suma/collection_config.rb +0 -2
  22. data/lib/suma/collection_manifest.rb +7 -110
  23. data/lib/suma/eengine/wrapper.rb +0 -1
  24. data/lib/suma/eengine.rb +8 -0
  25. data/lib/suma/express_reformatter.rb +94 -0
  26. data/lib/suma/express_schema.rb +0 -1
  27. data/lib/suma/jsdai/figure.rb +0 -3
  28. data/lib/suma/jsdai.rb +5 -2
  29. data/lib/suma/link_validation.rb +144 -0
  30. data/lib/suma/link_validator.rb +17 -8
  31. data/lib/suma/manifest_traverser.rb +92 -0
  32. data/lib/suma/processor.rb +5 -8
  33. data/lib/suma/register_manifest_generator.rb +163 -0
  34. data/lib/suma/schema_category.rb +83 -0
  35. data/lib/suma/schema_collection.rb +30 -34
  36. data/lib/suma/schema_comparer.rb +4 -3
  37. data/lib/suma/schema_compiler.rb +86 -0
  38. data/lib/suma/schema_discovery.rb +75 -0
  39. data/lib/suma/schema_exporter.rb +14 -42
  40. data/lib/suma/schema_manifest_generator.rb +14 -6
  41. data/lib/suma/schema_naming.rb +111 -0
  42. data/lib/suma/schema_template/document.rb +141 -0
  43. data/lib/suma/schema_template/plain.rb +46 -0
  44. data/lib/suma/schema_template.rb +19 -0
  45. data/lib/suma/svg_quality/batch_report.rb +0 -2
  46. data/lib/suma/svg_quality/formatters.rb +12 -0
  47. data/lib/suma/svg_quality/scanner.rb +61 -0
  48. data/lib/suma/svg_quality.rb +4 -1
  49. data/lib/suma/term_classification.rb +78 -0
  50. data/lib/suma/term_extractor.rb +125 -81
  51. data/lib/suma/urn.rb +61 -0
  52. data/lib/suma/version.rb +1 -1
  53. data/lib/suma.rb +35 -3
  54. data/suma.gemspec +1 -1
  55. metadata +28 -6
  56. data/lib/suma/schema_attachment.rb +0 -103
  57. data/lib/suma/schema_document.rb +0 -118
@@ -1,88 +1,63 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "thor"
4
- require_relative "../thor_ext"
5
4
 
6
5
  module Suma
7
6
  module Cli
8
- # Reformat command for reformatting EXPRESS files
7
+ # Reformat command for reformatting EXPRESS files.
8
+ #
9
+ # Thin Thor adapter around Suma::ExpressReformatter: argument
10
+ # parsing, file discovery, and read/transform/write. The content
11
+ # transformation itself lives in the deep module and is tested
12
+ # independently.
9
13
  class Reformat < Thor
10
- desc "reformat EXPRESS_FILE_PATH",
11
- "Reformat EXPRESS files"
14
+ desc "reformat EXPRESS_FILE_PATH", "Reformat EXPRESS files"
12
15
  option :recursive, type: :boolean, default: false, aliases: "-r",
13
16
  desc: "Reformat EXPRESS files under the specified " \
14
17
  "path recursively"
15
18
 
16
- def reformat(express_file_path) # rubocop:disable Metrics/AbcSize
17
- if File.file?(express_file_path)
18
- unless File.exist?(express_file_path)
19
- raise Errno::ENOENT, "Specified EXPRESS file " \
20
- "`#{express_file_path}` not found."
21
- end
22
-
23
- if File.extname(express_file_path) != ".exp"
24
- raise ArgumentError, "Specified file `#{express_file_path}` is " \
25
- "not an EXPRESS file."
26
- end
27
-
28
- exp_files = [express_file_path]
29
- elsif options[:recursive]
30
- exp_files = Dir.glob("#{express_file_path}/**/*.exp")
31
- else
32
- exp_files = Dir.glob("#{express_file_path}/*.exp")
33
- end
34
-
35
- if exp_files.empty?
36
- raise Errno::ENOENT, "No EXPRESS files found in " \
37
- "`#{express_file_path}`."
38
- end
39
-
40
- run(exp_files)
19
+ def reformat(express_file_path)
20
+ files = discover_files(express_file_path)
21
+ ensure_files_found!(files, express_file_path)
22
+ process_files(files)
41
23
  end
42
24
 
43
25
  private
44
26
 
45
- def run(exp_files)
46
- exp_files.each do |exp_file|
47
- reformat_exp(exp_file)
48
- end
49
- end
27
+ def discover_files(path)
28
+ return [path] if File.file?(path)
29
+ return Dir.glob("#{path}/**/*.exp") if options[:recursive]
50
30
 
51
- def reformat_exp(file) # rubocop:disable Metrics/AbcSize
52
- # Read the file content
53
- file_content = File.read(file)
54
-
55
- # Extract all comments between '(*"' and '\n*)'
56
- # Avoid incorrect selection of some comment blocks
57
- # containing '(*text*)' inside
58
- comments = file_content.scan(/\(\*"(.*?)\n\*\)/m).map(&:first)
59
-
60
- if comments.any?
61
- content_without_comments = file_content.gsub(/\(\*".*?\n\*\)/m, "")
62
-
63
- # remove extra newlines
64
- new_content = content_without_comments.gsub(/(\n\n+)/, "\n\n")
65
- # Add '(*"' and '\n*)' to enclose the comment block
66
- new_comments = comments.map { |c| "(*\"#{c}\n*)" }.join("\n\n")
67
- # Append the comments to the end of the file
68
- new_content = "#{new_content}\n\n#{new_comments}\n"
31
+ Dir.glob("#{path}/*.exp")
32
+ end
69
33
 
70
- # Compare the changes between the original content with the modified
71
- # content, if the changes are just whitespaces, skip modifying the
72
- # file
73
- if file_content.gsub(/(\n+)/, "\n") == new_content.gsub(/(\n+)/, "\n")
74
- puts "No changes made to #{file}"
75
- return
34
+ def ensure_files_found!(files, path)
35
+ if File.file?(path)
36
+ unless File.extname(path) == ".exp"
37
+ raise ArgumentError,
38
+ "Specified file `#{path}` is not an EXPRESS file."
76
39
  end
77
-
78
- update_exp(file, new_content)
40
+ elsif !File.exist?(path)
41
+ raise Errno::ENOENT,
42
+ "Specified EXPRESS file `#{path}` not found."
79
43
  end
44
+ return unless files.empty?
45
+
46
+ raise Errno::ENOENT, "No EXPRESS files found in `#{path}`."
47
+ end
48
+
49
+ def process_files(files)
50
+ files.each { |file| reformat_one(file) }
80
51
  end
81
52
 
82
- def update_exp(file, content)
83
- # Write the modified content to a new file
84
- File.write(file, content)
85
- puts "Reformatted EXPRESS file and saved to #{file}"
53
+ def reformat_one(file)
54
+ result = ExpressReformatter.call(File.read(file))
55
+ if result.changed?
56
+ File.write(file, result.content)
57
+ puts "Reformatted EXPRESS file and saved to #{file}"
58
+ else
59
+ puts "No changes made to #{file}"
60
+ end
86
61
  end
87
62
  end
88
63
  end
@@ -4,16 +4,23 @@ require "thor"
4
4
 
5
5
  module Suma
6
6
  module Cli
7
- # Main validate command that groups the validation subcommands
7
+ # Validate command group. Thin Thor adapter around
8
+ # +Suma::LinkValidation+ — argument parsing, result presentation.
9
+ # All orchestration (manifest loading, link extraction, schema
10
+ # indexing, validation) lives in the deep module and is reachable
11
+ # from specs without invoking Thor.
8
12
  class Validate < Thor
9
13
  desc "links SCHEMAS_FILE DOCUMENTS_PATH [OUTPUT_FILE]",
10
14
  "Extract and validate express links without creating intermediate file"
11
- def links(*args)
12
- require_relative "validate_links"
13
-
14
- # Forward the command to ValidateLinks
15
- links = Cli::ValidateLinks.new
16
- links.extract_and_validate(*args)
15
+ def links(schemas_file = "schemas-srl.yml",
16
+ documents_path = "documents",
17
+ output_file = "validation_results.txt")
18
+ result = LinkValidation.new(
19
+ schemas_file: schemas_file,
20
+ documents_path: documents_path,
21
+ output_file: output_file,
22
+ ).call
23
+ puts LinkValidation.generate_summary(result)
17
24
  end
18
25
  end
19
26
  end
@@ -1,170 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "thor"
4
- require_relative "../utils"
5
- require_relative "../link_validator"
6
- require "expressir"
7
4
 
8
5
  module Suma
9
6
  module Cli
7
+ # Deprecated: prefer +Cli::Validate#links+ (the +suma validate links+
8
+ # subcommand). This class is retained as a backwards-compat entry
9
+ # point — all orchestration now lives in +Suma::LinkValidation+.
10
10
  class ValidateLinks < Thor
11
11
  desc "extract_and_validate SCHEMAS_FILE DOCUMENTS_PATH [OUTPUT_FILE]",
12
12
  "Extract and validate express links without creating intermediate file"
13
13
  def extract_and_validate(schemas_file = "schemas-srl.yml",
14
- documents_path = "documents",
15
- output_file = "validation_results.txt")
16
- load_dependencies
17
- paths = prepare_file_paths(schemas_file, documents_path, output_file)
18
-
19
- schemas_config = load_schemas_config(paths[:schemas_file])
20
- exp_files = collect_schema_paths(schemas_config, paths[:schemas_file_rel])
21
- adoc_files = find_adoc_files(paths[:documents_path])
22
-
23
- all_files = adoc_files + exp_files
24
- display_file_counts(adoc_files, exp_files)
25
-
26
- links_by_file = extract_links(all_files)
27
-
28
- repo = load_express_schemas(schemas_config)
29
- index = SchemaIndex.new(repo)
30
- unresolved = LinkValidator.new(index).validate(links_by_file)
31
-
32
- write_validation_results(paths[:output_file], paths[:output_file_rel],
33
- unresolved, links_by_file)
34
- end
35
-
36
- private
37
-
38
- def load_dependencies
39
- require "expressir"
40
- require "ruby-progressbar"
41
- require "pathname"
42
- end
43
-
44
- def prepare_file_paths(schemas_file, documents_path, output_file)
45
- schemas_file_path = Pathname.new(schemas_file).expand_path
46
- documents_path_exp = Pathname.new(documents_path).expand_path
47
- output_file_path = Pathname.new(output_file).expand_path
48
-
49
- schemas_file_rel = Pathname.new(schemas_file_path).relative_path_from(Pathname.pwd).to_s
50
- documents_path_rel = Pathname.new(documents_path_exp).relative_path_from(Pathname.pwd).to_s
51
- output_file_rel = Pathname.new(output_file_path).relative_path_from(Pathname.pwd).to_s
52
-
53
- puts "Extracting and validating express links using schemas from #{schemas_file_rel}..."
54
- puts "Looking for documents in #{documents_path_rel}..."
55
-
56
- {
57
- schemas_file: schemas_file_path,
58
- schemas_file_rel: schemas_file_rel,
59
- documents_path: documents_path_exp,
60
- documents_path_rel: documents_path_rel,
61
- output_file: output_file_path,
62
- output_file_rel: output_file_rel,
63
- }
64
- end
65
-
66
- def load_schemas_config(schemas_file_path)
67
- schemas_config = Expressir::SchemaManifest.from_yaml(File.read(schemas_file_path))
68
- schemas_config.set_initial_path(schemas_file_path.to_s)
69
- schemas_config
70
- rescue StandardError => e
71
- raise Suma::Error, "Error loading schemas file: #{e.message}"
72
- end
73
-
74
- def collect_schema_paths(schemas_config, schemas_file_rel)
75
- exp_files = schemas_config.schemas.filter_map(&:path)
76
- puts "Found #{exp_files.size} EXPRESS schema files from #{schemas_file_rel}"
77
- exp_files
78
- end
79
-
80
- def find_adoc_files(documents_path)
81
- Dir.glob(documents_path.join("**", "*.adoc").to_s)
82
- end
83
-
84
- def display_file_counts(adoc_files, exp_files)
85
- puts "Found #{adoc_files.size} AsciiDoc files and #{exp_files.size} EXPRESS files"
86
- end
87
-
88
- def create_progress_bar(title, total)
89
- ProgressBar.create(
90
- title: title,
91
- total: total,
92
- format: "%t: [%B] %p%% %c/%C %e",
93
- progress_mark: "=",
94
- remainder_mark: " ",
95
- length: 80,
96
- )
97
- end
98
-
99
- def extract_links(files)
100
- links_by_file = {}
101
- link_count = 0
102
-
103
- progress = create_progress_bar("Processing files", files.size)
104
-
105
- files.each do |file|
106
- progress.increment
107
- begin
108
- content = File.read(file)
109
- express_links = content.scan(/<<express:([^,>]+)(?:,[^>]+)?>>/).flatten.uniq
110
-
111
- if express_links.any?
112
- links_by_file[file] = express_links
113
- link_count += express_links.size
114
- end
115
- rescue StandardError => e
116
- puts "\nWarning: Could not read file #{file}: #{e.message}"
117
- end
118
- end
119
-
120
- puts "\nExtracted #{link_count} unique express links from #{links_by_file.size} files"
121
- links_by_file
122
- end
123
-
124
- def load_express_schemas(schemas_config)
125
- schema_paths = {}
126
- schemas_config.schemas.each { |s| schema_paths[s.id] = s.path }
127
-
128
- puts "Loading #{schema_paths.size} EXPRESS schemas for validation..."
129
-
130
- loading_progress = create_progress_bar("Loading schemas", schema_paths.size)
131
-
132
- begin
133
- repo = Expressir::Express::Parser.from_files(schema_paths.values) do |filename, _schemas, error|
134
- loading_progress.increment
135
- puts "\nWarning: Error loading schema #{filename}: #{error.message}" if error
136
- end
137
-
138
- puts "Successfully loaded #{repo.schemas.size} schemas"
139
- repo
140
- rescue StandardError => e
141
- raise Suma::Error, "Error loading schemas: #{e.message}"
142
- end
143
- end
144
-
145
- def write_validation_results(output_file_path, output_file_rel,
146
- unresolved_links, links_by_file)
147
- total_links = links_by_file.values.sum(&:size)
148
-
149
- results = []
150
- results << "Validation complete. Checked #{total_links} links."
151
-
152
- if unresolved_links.empty?
153
- results << "✅ All links resolved successfully!"
154
- else
155
- results << "❌ Found #{unresolved_links.size} unresolved links:"
156
- unresolved_links.each do |issue|
157
- results << "#{issue.file}:#{issue.line} - <<express:#{issue.link}>> - #{issue.reason}"
158
- end
159
- end
160
-
161
- begin
162
- File.write(output_file_path, results.join("\n"))
163
- puts "Validation results written to #{output_file_rel}"
164
- rescue StandardError => e
165
- puts "Error writing to output file: #{e.message}"
166
- puts results
167
- end
14
+ documents_path = "documents",
15
+ output_file = "validation_results.txt")
16
+ result = LinkValidation.new(
17
+ schemas_file: schemas_file,
18
+ documents_path: documents_path,
19
+ output_file: output_file,
20
+ ).call
21
+ puts LinkValidation.generate_summary(result)
168
22
  end
169
23
  end
170
24
  end
data/lib/suma/cli.rb CHANGED
@@ -1,147 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "thor"
4
- require_relative "thor_ext"
5
- require_relative "cli/validate"
6
- require_relative "cli/check_svg_quality"
7
- require "expressir"
8
- require "expressir/cli"
9
-
10
3
  module Suma
11
4
  module Cli
12
- # Core command class for handling CLI entrypoints
13
- class Core < Thor
14
- extend ThorExt::Start
15
-
16
- desc "build METANORMA_SITE_MANIFEST",
17
- "Build collection specified in site manifest (`metanorma*.yml`)"
18
- option :compile, type: :boolean, default: true,
19
- desc: "Compile or skip compile of collection"
20
- option :schemas_all_path, type: :string, aliases: "-s",
21
- desc: "Generate file that contains all " \
22
- "schemas in the collection."
23
- def build(_site_manifest)
24
- require_relative "cli/build"
25
- Cli::Build.start
26
- end
27
-
28
- desc "generate-schemas METANORMA_MANIFEST_FILE SCHEMA_MANIFEST_FILE",
29
- "Generate EXPRESS schema manifest file from Metanorma site manifest"
30
- option :exclude_paths, type: :string, default: nil, aliases: "-e",
31
- desc: "Exclude schemas paths by pattern " \
32
- "(e.g. `*_lf.exp`)"
33
- def generate_schemas(_metanorma_manifest_file, _schema_manifest_file)
34
- require_relative "cli/generate_schemas"
35
- Cli::GenerateSchemas.start
36
- end
37
-
38
- desc "reformat EXPRESS_FILE_PATH",
39
- "Reformat EXPRESS files"
40
- option :recursive, type: :boolean, default: false, aliases: "-r",
41
- desc: "Reformat EXPRESS files under the specified " \
42
- "path recursively"
43
- def reformat(_express_file_path)
44
- require_relative "cli/reformat"
45
- Cli::Reformat.start
46
- end
47
-
48
- desc "extract-terms SCHEMA_MANIFEST_FILE GLOSSARIST_OUTPUT_PATH",
49
- "Extract terms from SCHEMA_MANIFEST_FILE into " \
50
- "Glossarist v2 format"
51
- option :language_code, type: :string, default: "eng", aliases: "-l",
52
- desc: "Language code for the Glossarist"
53
- def extract_terms(_schema_manifest_file, _glossarist_output_path)
54
- require_relative "cli/extract_terms"
55
- Cli::ExtractTerms.start
56
- end
57
-
58
- desc "convert-jsdai XML_FILE IMAGE_FILE OUTPUT_DIR",
59
- "Convert JSDAI XML and image files to SVG and EXP files"
60
- def convert_jsdai(_xml_file, _image_file, _output_dir)
61
- require_relative "cli/convert_jsdai"
62
- Cli::ConvertJsdai.start
63
- end
64
-
65
- desc "export *FILES",
66
- "Export EXPRESS schemas from manifest files or " \
67
- "standalone EXPRESS files"
68
- option :output, type: :string, aliases: "-o", required: true,
69
- desc: "Output directory path"
70
- option :annotations, type: :boolean, default: false,
71
- desc: "Include annotations (remarks/comments)"
72
- option :zip, type: :boolean, default: false,
73
- desc: "Create ZIP archive of exported schemas"
74
- def export(*_files)
75
- require_relative "cli/export"
76
- Cli::Export.start
77
- end
78
-
79
- desc "compare TRIAL_SCHEMA REFERENCE_SCHEMA",
80
- "Compare EXPRESS schemas using eengine and generate Change YAML"
81
- option :output, type: :string, aliases: "-o",
82
- desc: "Output Change YAML file path"
83
- option :version, type: :string, aliases: "-v", required: true,
84
- desc: "Version number for this change version"
85
- option :mode, type: :string, default: "resource",
86
- desc: "Schema comparison mode (resource/module)"
87
- option :trial_stepmod, type: :string,
88
- desc: "Override auto-detected trial repo root"
89
- option :reference_stepmod, type: :string,
90
- desc: "Override auto-detected reference repo root"
91
- option :verbose, type: :boolean, default: false,
92
- desc: "Enable verbose output"
93
- def compare(_trial_schema, _reference_schema)
94
- require_relative "cli/compare"
95
- Cli::Compare.start
96
- end
97
-
98
- desc "validate SUBCOMMAND ...ARGS", "Validate express documents"
99
- subcommand "validate", Cli::Validate
100
-
101
- desc "check_svg_quality [PATH]",
102
- "Check SVG quality and sort by severity (critical files first)"
103
- option :pattern, type: :string, default: Cli::CheckSvgQuality::DEFAULT_PATTERN,
104
- desc: "Glob pattern for finding SVG files"
105
- option :profile, type: :string,
106
- default: Cli::CheckSvgQuality::DEFAULT_PROFILE,
107
- desc: "Validation profile to use (metanorma, svg_1_2_rfc, etc.)"
108
- option :format, type: :string, default: "terminal",
109
- desc: "Output format: terminal, yaml, json"
110
- option :output, type: :string, aliases: "-o",
111
- desc: "Output file path"
112
- option :min_errors, type: :numeric,
113
- desc: "Minimum error count threshold"
114
- option :limit, type: :numeric, default: nil,
115
- desc: "Maximum number of files to show (default: unlimited)"
116
- option :sort, type: :string, default: "errors",
117
- desc: "Sort by: errors (most errors first) or quality (lowest scores first)"
118
- option :progress, type: :boolean, default: false,
119
- desc: "Show progress during processing"
120
- option :summary_only, type: :boolean, default: false,
121
- desc: "Show only summary"
122
- def check_svg_quality(path = Cli::CheckSvgQuality::DATA_PATH)
123
- require_relative "cli/check_svg_quality"
124
-
125
- analyzer = Cli::CheckSvgQuality.new(
126
- pattern: options[:pattern],
127
- profile: options[:profile],
128
- format: options[:format],
129
- output: options[:output],
130
- min_errors: options[:min_errors],
131
- summary_only: options[:summary_only],
132
- progress: options[:progress],
133
- limit: options[:limit],
134
- sort: options[:sort],
135
- )
136
- analyzer.run(path)
137
- end
138
-
139
- desc "expressir SUBCOMMAND ...ARGS", "Expressir commands"
140
- subcommand "expressir", Expressir::Cli
141
-
142
- def self.exit_on_failure?
143
- true
144
- end
145
- end
5
+ autoload :Core, "suma/cli/core"
6
+ autoload :Build, "suma/cli/build"
7
+ autoload :CheckSvgQuality, "suma/cli/check_svg_quality"
8
+ autoload :Compare, "suma/cli/compare"
9
+ autoload :ConvertJsdai, "suma/cli/convert_jsdai"
10
+ autoload :Export, "suma/cli/export"
11
+ autoload :ExtractTerms, "suma/cli/extract_terms"
12
+ autoload :GenerateRegister, "suma/cli/generate_register"
13
+ autoload :GenerateSchemas, "suma/cli/generate_schemas"
14
+ autoload :Reformat, "suma/cli/reformat"
15
+ autoload :Validate, "suma/cli/validate"
16
+ autoload :ValidateLinks, "suma/cli/validate_links"
146
17
  end
147
18
  end
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "utils"
4
3
  require "lutaml/model"
5
- require_relative "collection_manifest"
6
4
  require "metanorma"
7
5
 
8
6
  module Suma
@@ -4,6 +4,13 @@ require "metanorma"
4
4
  require "expressir"
5
5
 
6
6
  module Suma
7
+ # Pure data model for one node of a Metanorma collection manifest.
8
+ #
9
+ # CollectionManifest extends the Metanorma config manifest to add the
10
+ # `schemas_only` flag and an `entry` sub-collection. It owns only state:
11
+ # attributes, YAML mappings, and the `schema_config` slot populated by
12
+ # SchemaDiscovery. Tree-walking logic lives in ManifestTraverser; schema
13
+ # I/O lives in SchemaDiscovery.
7
14
  class CollectionManifest < Metanorma::Collection::Config::Manifest
8
15
  attribute :schemas_only, Lutaml::Model::Type::Boolean
9
16
  attribute :entry, CollectionManifest, collection: true,
@@ -32,115 +39,5 @@ module Suma
32
39
  def docref_from_yaml(model, value)
33
40
  model.entry = CollectionManifest.from_yaml(value.to_yaml)
34
41
  end
35
-
36
- # Recursively exports schema configuration by traversing collection manifests.
37
- #
38
- # This method builds an EXPRESS Schema Manifest (Expressir::SchemaManifest) by:
39
- # 1. Starting with an empty or existing Expressir::SchemaManifest
40
- # 2. Recursively traversing child entries to collect schemas
41
- # 3. Using Expressir::SchemaManifest#concat to combine manifests
42
- #
43
- # The actual schema manifest operations (creation, concatenation, serialization)
44
- # are handled by Expressir's SchemaManifest class, keeping the logic DRY.
45
- #
46
- # @param path [String] Base path for resolving relative schema paths
47
- # @return [Expressir::SchemaManifest] Combined schema manifest
48
- def export_schema_config(path)
49
- export_config = @schema_config || Expressir::SchemaManifest.new
50
- return export_config unless entry
51
-
52
- entry.each do |x|
53
- child_config = x.export_schema_config(path)
54
- # Use Expressir's concat method to combine schema manifests
55
- export_config.concat(child_config) if child_config
56
- end
57
-
58
- export_config
59
- end
60
-
61
- def lookup_schemas_only
62
- results = entry.select(&:schemas_only)
63
- results << self if schemas_only
64
- results
65
- end
66
-
67
- def process_entry(schema_output_path)
68
- return [self] unless entry
69
-
70
- ret = entry.each_with_object([]) do |e, m|
71
- add = e.expand_schemas_only(schema_output_path)
72
- m.concat(add)
73
- end
74
-
75
- self.entry = ret
76
- [self]
77
- end
78
-
79
- def expand_schemas_only(schema_output_path)
80
- return process_entry(schema_output_path) unless file
81
-
82
- update_schema_config
83
-
84
- return process_entry(schema_output_path) unless schemas_only
85
-
86
- # If we are going to keep the schemas-only file and compile it, we can't
87
- # have it showing up in output.
88
- self.index = false
89
-
90
- [self, added_collection_manifest(schema_output_path)]
91
- end
92
-
93
- def remove_schemas_only_sources
94
- ret = entry.each_with_object([]) do |e, m|
95
- e.schemas_only or m << e
96
- end
97
- self.entry = ret
98
- end
99
-
100
- def entries(schema_output_path)
101
- @schema_config.schemas.map do |schema|
102
- fname = [File.basename(schema.path, ".exp"), ".xml"].join
103
-
104
- CollectionManifest.new(
105
- identifier: schema.id,
106
- title: schema.id,
107
- file: File.join(schema_output_path, schema.id, "doc_#{fname}"),
108
- # schema_source: schema.path
109
- )
110
- end
111
- end
112
-
113
- def added_collection_manifest(schema_output_path)
114
- doc = CollectionConfig.from_file(file)
115
- doc_id = doc.bibdata.id
116
-
117
- # we need to separate this file from the following new entries
118
- added = CollectionManifest.new(
119
- title: "Collection",
120
- type: "collection",
121
- identifier: "#{identifier}_",
122
- )
123
-
124
- added.entry = [
125
- CollectionManifest.new(
126
- title: doc_id,
127
- type: "document",
128
- entry: entries(schema_output_path),
129
- ),
130
- ]
131
-
132
- added
133
- end
134
-
135
- def update_schema_config
136
- # If there is collection.yml, this is a document collection, we process
137
- # schemas.yaml.
138
- if File.basename(file) == "collection.yml"
139
- schemas_yaml_path = File.join(File.dirname(file), "schemas.yaml")
140
- if schemas_yaml_path && File.exist?(schemas_yaml_path)
141
- @schema_config = Expressir::SchemaManifest.from_file(schemas_yaml_path)
142
- end
143
- end
144
- end
145
42
  end
146
43
  end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "open3"
4
- require_relative "errors"
5
4
 
6
5
  module Suma
7
6
  module Eengine
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Suma
4
+ module Eengine
5
+ autoload :Errors, "suma/eengine/errors"
6
+ autoload :Wrapper, "suma/eengine/wrapper"
7
+ end
8
+ end