suma 0.2.5 → 0.3.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 (63) 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/.gitignore +10 -1
  5. data/.rubocop_todo.yml +237 -28
  6. data/CLAUDE.md +102 -0
  7. data/Gemfile +3 -1
  8. data/README.adoc +188 -1
  9. data/exe/suma +1 -1
  10. data/lib/suma/cli/build.rb +2 -8
  11. data/lib/suma/cli/check_svg_quality.rb +172 -0
  12. data/lib/suma/cli/compare.rb +6 -158
  13. data/lib/suma/cli/convert_jsdai.rb +0 -2
  14. data/lib/suma/cli/core.rb +119 -0
  15. data/lib/suma/cli/export.rb +1 -10
  16. data/lib/suma/cli/extract_terms.rb +10 -654
  17. data/lib/suma/cli/generate_register.rb +34 -0
  18. data/lib/suma/cli/generate_schemas.rb +8 -124
  19. data/lib/suma/cli/reformat.rb +0 -1
  20. data/lib/suma/cli/validate.rb +0 -2
  21. data/lib/suma/cli/validate_links.rb +14 -291
  22. data/lib/suma/cli.rb +12 -102
  23. data/lib/suma/collection_config.rb +0 -2
  24. data/lib/suma/collection_manifest.rb +7 -111
  25. data/lib/suma/eengine/wrapper.rb +0 -1
  26. data/lib/suma/eengine.rb +8 -0
  27. data/lib/suma/express_schema.rb +43 -31
  28. data/lib/suma/jsdai/figure.rb +0 -3
  29. data/lib/suma/jsdai/figure_xml.rb +12 -9
  30. data/lib/suma/jsdai.rb +5 -8
  31. data/lib/suma/link_validator.rb +211 -0
  32. data/lib/suma/manifest_traverser.rb +92 -0
  33. data/lib/suma/processor.rb +76 -105
  34. data/lib/suma/register_manifest_generator.rb +163 -0
  35. data/lib/suma/schema_category.rb +83 -0
  36. data/lib/suma/schema_collection.rb +28 -63
  37. data/lib/suma/schema_comparer.rb +117 -0
  38. data/lib/suma/schema_compiler.rb +86 -0
  39. data/lib/suma/schema_discovery.rb +75 -0
  40. data/lib/suma/schema_exporter.rb +7 -35
  41. data/lib/suma/schema_index.rb +53 -0
  42. data/lib/suma/schema_manifest_generator.rb +113 -0
  43. data/lib/suma/schema_naming.rb +111 -0
  44. data/lib/suma/schema_template/document.rb +141 -0
  45. data/lib/suma/schema_template/plain.rb +46 -0
  46. data/lib/suma/schema_template.rb +19 -0
  47. data/lib/suma/svg_quality/batch_report.rb +78 -0
  48. data/lib/suma/svg_quality/formatters/json_formatter.rb +30 -0
  49. data/lib/suma/svg_quality/formatters/terminal_formatter.rb +168 -0
  50. data/lib/suma/svg_quality/formatters/yaml_formatter.rb +32 -0
  51. data/lib/suma/svg_quality/formatters.rb +12 -0
  52. data/lib/suma/svg_quality/report.rb +52 -0
  53. data/lib/suma/svg_quality.rb +30 -0
  54. data/lib/suma/term_extractor.rb +466 -0
  55. data/lib/suma/urn.rb +61 -0
  56. data/lib/suma/utils.rb +10 -2
  57. data/lib/suma/version.rb +1 -1
  58. data/lib/suma.rb +34 -5
  59. data/suma.gemspec +3 -2
  60. metadata +53 -9
  61. data/lib/suma/export_standalone_schema.rb +0 -14
  62. data/lib/suma/schema_attachment.rb +0 -130
  63. data/lib/suma/schema_document.rb +0 -132
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "expressir"
4
+
5
+ module Suma
6
+ # Tree-walking service over a CollectionManifest.
7
+ #
8
+ # ManifestTraverser owns all imperative operations that walk or mutate a
9
+ # manifest tree: finding schemas-only entries, expanding them into
10
+ # compiled-doc sub-trees, exporting a unified Expressir::SchemaManifest,
11
+ # and removing schemas-only sources after compilation.
12
+ #
13
+ # Each method takes the manifest passed at construction as its root;
14
+ # recursion instantiates a new traverser per child node so the surface
15
+ # stays instance-based and the data model (CollectionManifest) stays pure.
16
+ #
17
+ # Schema-config loading and doc-entry construction are delegated to
18
+ # SchemaDiscovery so this class owns traversal, not schema I/O.
19
+ class ManifestTraverser
20
+ attr_reader :manifest
21
+
22
+ def initialize(manifest)
23
+ @manifest = manifest
24
+ end
25
+
26
+ # Returns every entry (anywhere in the tree) whose `schemas_only` flag
27
+ # is truthy, plus +manifest+ itself if it is schemas-only.
28
+ def find_schemas_only
29
+ results = (manifest.entry || []).select(&:schemas_only)
30
+ results << manifest if manifest.schemas_only
31
+ results
32
+ end
33
+
34
+ # Recursively concatenate every nested schema_config into a single
35
+ # Expressir::SchemaManifest. The manifest's own schema_config (if set)
36
+ # seeds the result; otherwise an empty SchemaManifest is returned.
37
+ def export_schema_config(path)
38
+ export_config = manifest.schema_config || Expressir::SchemaManifest.new
39
+ return export_config unless manifest.entry
40
+
41
+ manifest.entry.each do |child|
42
+ child_config = self.class.new(child).export_schema_config(path)
43
+ export_config.concat(child_config) if child_config
44
+ end
45
+
46
+ export_config
47
+ end
48
+
49
+ # Expand schemas-only entries into compiled-doc sub-trees. If the
50
+ # manifest has no file, walks children via process_entry. Otherwise
51
+ # loads the schema_config (SchemaDiscovery), and if this entry is
52
+ # schemas-only, hides it from the output index and appends a new
53
+ # sub-collection that hosts the compiled docs.
54
+ def expand_schemas_only(schema_output_path)
55
+ return process_entry(schema_output_path) unless manifest.file
56
+
57
+ SchemaDiscovery.new(manifest).load_config
58
+
59
+ return process_entry(schema_output_path) unless manifest.schemas_only
60
+
61
+ manifest.index = false
62
+
63
+ added = SchemaDiscovery.new(manifest).build_added_manifest(schema_output_path)
64
+ [manifest, added]
65
+ end
66
+
67
+ # Drop every direct child whose `schemas_only` is truthy. Called after
68
+ # compilation so the schemas-only manifest file no longer shows up in
69
+ # the rendered collection.
70
+ def remove_schemas_only_sources
71
+ return unless manifest.entry
72
+
73
+ kept = manifest.entry.reject(&:schemas_only)
74
+ manifest.entry = kept
75
+ end
76
+
77
+ private
78
+
79
+ # Walk each child via expand_schemas_only, flattening the results back
80
+ # into manifest.entry.
81
+ def process_entry(schema_output_path)
82
+ return [manifest] unless manifest.entry
83
+
84
+ flattened = manifest.entry.each_with_object([]) do |child, acc|
85
+ acc.concat(self.class.new(child).expand_schemas_only(schema_output_path))
86
+ end
87
+
88
+ manifest.entry = flattened
89
+ [manifest]
90
+ end
91
+ end
92
+ end
@@ -1,114 +1,85 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "schema_collection"
4
- require_relative "utils"
5
- require_relative "collection_config"
6
- require_relative "site_config"
7
3
  require "metanorma"
8
4
 
9
5
  module Suma
10
6
  class Processor
11
- class << self
12
- # rubocop:disable Metrics/MethodLength
13
- def run(metanorma_yaml_path:, schemas_all_path:, compile:,
14
- output_directory: "_site")
15
- Utils.log "Current directory: #{Dir.getwd}, writing #{schemas_all_path}..."
16
-
17
- # Generate EXPRESS Schema Manifest by traversing Metanorma Site Manifest
18
- # This uses Expressir::SchemaManifest for all manifest operations
19
- collection_config = export_schema_config(metanorma_yaml_path,
20
- schemas_all_path)
21
-
22
- unless compile
23
- Utils.log "No compile option set. Skipping schema compilation."
24
- return nil
25
- end
26
-
27
- Utils.log "Compiling schema collection..."
28
- compile_schema(schemas_all_path, collection_config)
29
-
30
- Utils.log "Compiling complete collection..."
31
- compile_collection(collection_config, output_directory)
32
- end
33
- # rubocop:enable Metrics/MethodLength
34
-
35
- private
36
-
37
- # Generates EXPRESS Schema Manifest from Metanorma Site Manifest structure.
38
- #
39
- # This method:
40
- # 1. Reads the Metanorma site manifest to discover collection files
41
- # 2. Traverses collection manifests to find individual schemas.yaml files
42
- # 3. Uses Expressir::SchemaManifest to aggregate and manage schema entries
43
- # 4. Saves the unified schema manifest using Expressir's to_file method
44
- #
45
- # @param metanorma_yaml_path [String] Path to Metanorma site manifest
46
- # @param schemas_all_path [String] Output path for unified schema manifest
47
- # @return [CollectionConfig] The loaded collection configuration
48
- # rubocop:disable Metrics/MethodLength
49
- def export_schema_config(metanorma_yaml_path, schemas_all_path)
50
- # This reads the metanorma.yml file
51
- site_config = Suma::SiteConfig::Config.from_file(metanorma_yaml_path)
52
-
53
- # TODO: only reading the first file, which is a collection.yml, which is a hack...
54
- collection_config_path = site_config.metanorma.source.files.first
55
- collection_config = Suma::CollectionConfig.from_file(collection_config_path)
56
- collection_config.path = collection_config_path
57
- collection_config.manifest.expand_schemas_only("schema_docs")
58
-
59
- # Recursively traverse collection manifests to build unified schema manifest
60
- # Uses Expressir::SchemaManifest methods (concat, to_file) for operations
61
- exported_schema_config = collection_config.manifest.export_schema_config(schemas_all_path)
62
- exported_schema_config.path = schemas_all_path
63
-
64
- # Save using Expressir's SchemaManifest#to_file method
65
- exported_schema_config.to_file
66
-
67
- collection_config
68
- end
69
- # rubocop:enable Metrics/MethodLength
70
-
71
- def compile_schema(schemas_all_path, collection_config)
72
- # now get rid of the source documents for schema sources
73
- col = Suma::SchemaCollection.new(
74
- config_yaml: schemas_all_path,
75
- manifest: collection_config.manifest,
76
- output_path_docs: "schema_docs",
77
- output_path_schemas: "plain_schemas",
78
- )
79
-
80
- col.compile
81
- end
82
-
83
- def compile_collection(collection_config, output_directory)
84
- metanorma_collection, collection_opts = build_collection(
85
- collection_config, output_directory
86
- )
87
-
88
- metanorma_collection.render(collection_opts)
89
-
90
- # TODO: Temporarily disable removal of XML files
91
- Dir.glob(File.join(Dir.getwd, output_directory,
92
- "*.xml")).each do |file|
93
- puts "NOT DELETING ANY FILE #{file.inspect}"
94
- # File.delete(file)
95
- end
96
- end
97
-
98
- def build_collection(collection_config, output_directory)
99
- new_collection_config_path = "collection-output.yaml"
100
- collection_config.manifest.remove_schemas_only_sources
101
- collection_config.to_file(new_collection_config_path)
102
-
103
- collection = Metanorma::Collection.parse(new_collection_config_path)
104
-
105
- collection_opts = {
106
- output_folder: output_directory,
107
- compile: { install_fonts: false },
108
- coverpage: collection_config.coverpage || "cover.html",
109
- }
110
- [collection, collection_opts]
111
- end
7
+ attr_reader :metanorma_yaml_path, :output_directory, :schemas_all_path,
8
+ :compile_flag
9
+
10
+ def initialize(metanorma_yaml_path:, schemas_all_path:, compile: true,
11
+ output_directory: "_site")
12
+ @metanorma_yaml_path = metanorma_yaml_path
13
+ @schemas_all_path = schemas_all_path
14
+ @compile_flag = compile
15
+ @output_directory = output_directory
16
+ end
17
+
18
+ def run
19
+ Utils.log "Current directory: #{Dir.getwd}, writing #{schemas_all_path}..."
20
+
21
+ collection_config = export_schema_config
22
+
23
+ return nil unless @compile_flag
24
+
25
+ Utils.log "Compiling schema collection..."
26
+ compile_schema(schemas_all_path, collection_config)
27
+
28
+ Utils.log "Compiling complete collection..."
29
+ compile_collection(collection_config, output_directory)
30
+ end
31
+
32
+ private
33
+
34
+ def export_schema_config
35
+ site_config = Suma::SiteConfig::Config.from_file(metanorma_yaml_path)
36
+
37
+ collection_config_path = site_config.metanorma.source.files.first
38
+ collection_config = Suma::CollectionConfig.from_file(collection_config_path)
39
+ collection_config.path = collection_config_path
40
+
41
+ traverser = ManifestTraverser.new(collection_config.manifest)
42
+ traverser.expand_schemas_only("schema_docs")
43
+
44
+ exported_schema_config = traverser.export_schema_config(schemas_all_path)
45
+ exported_schema_config.path = schemas_all_path
46
+ exported_schema_config.to_file
47
+
48
+ collection_config
49
+ end
50
+
51
+ def compile_schema(schemas_all_path, collection_config)
52
+ col = Suma::SchemaCollection.new(
53
+ config_yaml: schemas_all_path,
54
+ manifest: collection_config.manifest,
55
+ output_path_docs: "schema_docs",
56
+ output_path_schemas: "plain_schemas",
57
+ )
58
+
59
+ col.compile
60
+ end
61
+
62
+ def compile_collection(collection_config, output_directory)
63
+ metanorma_collection, collection_opts = build_collection(
64
+ collection_config, output_directory
65
+ )
66
+
67
+ metanorma_collection.render(collection_opts)
68
+ end
69
+
70
+ def build_collection(collection_config, output_directory)
71
+ new_collection_config_path = "collection-output.yaml"
72
+ ManifestTraverser.new(collection_config.manifest).remove_schemas_only_sources
73
+ collection_config.to_file(new_collection_config_path)
74
+
75
+ collection = Metanorma::Collection.parse(new_collection_config_path)
76
+
77
+ collection_opts = {
78
+ output_folder: output_directory,
79
+ compile: { install_fonts: false },
80
+ coverpage: collection_config.coverpage || "cover.html",
81
+ }
82
+ [collection, collection_opts]
112
83
  end
113
84
  end
114
85
  end
@@ -0,0 +1,163 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+ require "pathname"
5
+ require "expressir"
6
+ require "glossarist"
7
+
8
+ module Suma
9
+ # Generates a Glossarist v3 register.yaml from an EXPRESS schema manifest.
10
+ #
11
+ # The schema manifest (schemas-smrl-part-2.yml) is the single source of
12
+ # truth for schema identities and paths. This class reads it, classifies
13
+ # each schema by type (resource/module), and emits a register.yaml with
14
+ # hierarchical sections and human-readable names.
15
+ #
16
+ # Architecture:
17
+ # - Classification: delegates to ExpressSchema::Type (DRY)
18
+ # - Naming: delegates to SchemaNaming (OCP — extend naming without
19
+ # touching this class)
20
+ # - Sections: built from Glossarist::Section models (model-driven)
21
+ # - URN semantics: delegates to Suma::Urn (OCP)
22
+ #
23
+ # @example
24
+ # generator = RegisterManifestGenerator.new(
25
+ # "schemas-smrl-part-2.yml",
26
+ # urn: "urn:iso:std:iso:10303:-2:ed-2:en:tech:*",
27
+ # id: "iso10303-2-express",
28
+ # ref: "ISO 10303-2 EXPRESS Concepts",
29
+ # )
30
+ # generator.generate # writes register.yaml
31
+ class RegisterManifestGenerator
32
+ DEFAULT_OWNER = "ISO/TC 184/SC 4"
33
+ DEFAULT_STATUS = "current"
34
+ DEFAULT_ORDERING = "systematic"
35
+ DEFAULT_SCHEMA_TYPE = "glossarist"
36
+ DEFAULT_SCHEMA_VERSION = "3"
37
+
38
+ # @param schema_manifest_file [String] path to schemas-smrl-part-2.yml
39
+ # @param output_path [String] directory to write register.yaml
40
+ # @param urn [String] base URN for the dataset
41
+ # @param id [String] dataset identifier
42
+ # @param ref [String] human-readable reference label
43
+ # @param language_code [String] language for section names
44
+ # @param owner [String] dataset owner organisation
45
+ def initialize(schema_manifest_file, output_path, urn:, id:, ref:,
46
+ language_code: "eng", owner: DEFAULT_OWNER)
47
+ @schema_manifest_file = File.expand_path(schema_manifest_file)
48
+ @output_path = output_path
49
+ @urn = Suma::Urn.new(urn)
50
+ @id = id
51
+ @ref = ref
52
+ @language_code = language_code
53
+ @owner = owner
54
+ end
55
+
56
+ # Generate and write register.yaml.
57
+ #
58
+ # @return [Glossarist::DatasetRegister] the generated register
59
+ def generate
60
+ validate_inputs
61
+ schemas = load_schemas
62
+ register = build_register(schemas)
63
+
64
+ FileUtils.mkdir_p(@output_path)
65
+ output_file = File.join(@output_path, "register.yaml")
66
+ File.write(output_file, register.to_yaml)
67
+ Utils.log "Generated register.yaml: #{output_file}"
68
+ Utils.log " #{schemas.length} schemas in #{register.sections.length} categories"
69
+
70
+ register
71
+ end
72
+
73
+ private
74
+
75
+ # Verify that the manifest path exists, is a regular file, and contains
76
+ # at least one schema entry. Called from {#generate} so both the CLI
77
+ # shell and direct construction get the same validation behavior.
78
+ #
79
+ # @raise [Errno::ENOENT] when the manifest path is missing or not a file
80
+ # @raise [ArgumentError] when the manifest is empty
81
+ def validate_inputs
82
+ unless File.exist?(@schema_manifest_file)
83
+ raise Errno::ENOENT, "Specified SCHEMA_MANIFEST_FILE " \
84
+ "`#{@schema_manifest_file}` not found."
85
+ end
86
+ unless File.file?(@schema_manifest_file)
87
+ raise Errno::ENOENT, "Specified SCHEMA_MANIFEST_FILE " \
88
+ "`#{@schema_manifest_file}` is not a file."
89
+ end
90
+ end
91
+
92
+ # Load all schemas from the manifest file as SchemaManifestEntry models.
93
+ #
94
+ # @return [Array<Expressir::SchemaManifestEntry>]
95
+ def load_schemas
96
+ manifest = Expressir::SchemaManifest.from_file(@schema_manifest_file)
97
+ schemas = manifest.schemas.sort_by { |s| s.id.downcase }
98
+ if schemas.empty?
99
+ raise ArgumentError, "No schemas found in manifest " \
100
+ "`#{@schema_manifest_file}`."
101
+ end
102
+ schemas
103
+ end
104
+
105
+ # Build a fully-populated DatasetRegister model.
106
+ #
107
+ # @param schemas [Array<Expressir::SchemaManifestEntry>]
108
+ # @return [Glossarist::DatasetRegister]
109
+ def build_register(schemas)
110
+ Glossarist::DatasetRegister.new(
111
+ schema_type: DEFAULT_SCHEMA_TYPE,
112
+ schema_version: DEFAULT_SCHEMA_VERSION,
113
+ id: @id,
114
+ ref: @ref,
115
+ urn: @urn.to_s,
116
+ urn_aliases: @urn.aliases,
117
+ status: DEFAULT_STATUS,
118
+ owner: @owner,
119
+ languages: [@language_code],
120
+ ordering: DEFAULT_ORDERING,
121
+ sections: build_sections(schemas),
122
+ )
123
+ end
124
+
125
+ # Build a list of top-level sections, one per category, in
126
+ # SchemaCategory::ALL declaration order. Categories with no
127
+ # schemas are omitted.
128
+ #
129
+ # @param schemas [Array<Expressir::SchemaManifestEntry>]
130
+ # @return [Array<Glossarist::Section>]
131
+ def build_sections(schemas)
132
+ groups = schemas.group_by do |s|
133
+ SchemaCategory.for_schema(id: s.id, path: s.path)
134
+ end
135
+
136
+ SchemaCategory::ALL.filter_map do |category|
137
+ children = groups[category] || []
138
+ next if children.empty?
139
+
140
+ Glossarist::Section.new(
141
+ id: category.id,
142
+ names: { @language_code => category.label },
143
+ children: children.map { |s| build_section(s) },
144
+ )
145
+ end
146
+ end
147
+
148
+ # Build a single leaf section from a schema descriptor.
149
+ #
150
+ # @param schema [Expressir::SchemaManifestEntry]
151
+ # @return [Glossarist::Section]
152
+ def build_section(schema)
153
+ Glossarist::Section.new(
154
+ id: schema.id,
155
+ names: {
156
+ @language_code => SchemaNaming.prefixed_name(
157
+ schema.id, path: schema.path
158
+ ),
159
+ },
160
+ )
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Suma
4
+ # Value object mapping an ExpressSchema::Type to its register/export category.
5
+ #
6
+ # Single source of truth for category identity across the codebase:
7
+ # directory layout (SchemaExporter), display prefix (SchemaNaming), and
8
+ # register.yaml sections (RegisterManifestGenerator) all derive from this.
9
+ #
10
+ # Each category carries: +id+ (slug used in register.yaml section id and
11
+ # export subdirectory), +label+ (human-readable section heading),
12
+ # +prefix+ (prefix used when forming display names, e.g. "Resource: ..."),
13
+ # +types+ (Array of ExpressSchema::Type symbols that belong to it),
14
+ # and +directory+ (subdirectory name; "." for the root output path).
15
+ class SchemaCategory
16
+ attr_reader :id, :label, :prefix, :types, :directory
17
+
18
+ def initialize(id:, label:, prefix:, types:, directory:)
19
+ @id = id
20
+ @label = label
21
+ @prefix = prefix
22
+ @types = types
23
+ @directory = directory
24
+ end
25
+
26
+ def member?(type)
27
+ types.include?(type)
28
+ end
29
+
30
+ RESOURCES = new(
31
+ id: "resources",
32
+ label: "Resources",
33
+ prefix: "Resource",
34
+ types: [ExpressSchema::Type::RESOURCE].freeze,
35
+ directory: "resources",
36
+ )
37
+ MODULES = new(
38
+ id: "modules",
39
+ label: "Application Modules",
40
+ prefix: "Module",
41
+ types: [ExpressSchema::Type::MODULE_ARM, ExpressSchema::Type::MODULE_MIM].freeze,
42
+ directory: "modules",
43
+ )
44
+ BUSINESS_OBJECT_MODELS = new(
45
+ id: "business_object_models",
46
+ label: "Business Object Models",
47
+ prefix: "Business Object Model",
48
+ types: [ExpressSchema::Type::BUSINESS_OBJECT_MODEL].freeze,
49
+ directory: "business_object_models",
50
+ )
51
+ CORE_MODEL = new(
52
+ id: "core_model",
53
+ label: "Core Model",
54
+ prefix: "Core Model",
55
+ types: [ExpressSchema::Type::CORE_MODEL].freeze,
56
+ directory: "core_model",
57
+ )
58
+ OTHER = new(
59
+ id: "other",
60
+ label: "Other Schemas",
61
+ prefix: "Schema",
62
+ types: [ExpressSchema::Type::STANDALONE].freeze,
63
+ directory: ".",
64
+ )
65
+
66
+ ALL = [
67
+ RESOURCES,
68
+ MODULES,
69
+ BUSINESS_OBJECT_MODELS,
70
+ CORE_MODEL,
71
+ OTHER,
72
+ ].freeze
73
+
74
+ def self.for_type(type)
75
+ ALL.find { |category| category.member?(type) } || OTHER
76
+ end
77
+
78
+ def self.for_schema(id:, path:)
79
+ type = ExpressSchema::Type.classify(id: id, path: path)
80
+ for_type(type)
81
+ end
82
+ end
83
+ end
@@ -1,11 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "express_schema"
4
- require_relative "schema_attachment"
5
- require_relative "schema_document"
6
- require_relative "schema_exporter"
7
3
  require "expressir"
8
- require_relative "utils"
9
4
 
10
5
  module Suma
11
6
  class SchemaCollection
@@ -30,46 +25,20 @@ module Suma
30
25
  @schema_name_to_docs[schema_name]
31
26
  end
32
27
 
33
- def process_schemas(schemas, klass)
34
- schemas.each do |config_schema|
35
- process_schema(config_schema, klass)
36
- end
37
- end
38
-
39
- def process_schema(config_schema, klass)
40
- s = ExpressSchema.new(
41
- id: config_schema.id, path: config_schema.path.to_s,
42
- output_path: @output_path_schemas.to_s
43
- )
44
-
45
- doc = klass.new(
46
- schema: s, output_path: @output_path_docs.join(s.id),
47
- )
48
-
49
- @docs[s.id] = doc
50
- @schemas[s.id] = s
51
- @schema_name_to_docs[s.id] = doc
52
- end
53
-
54
28
  def finalize
55
- # Process each schema in @config.schemas
56
- process_schemas(@config.schemas, SchemaAttachment)
29
+ process_schemas(@config.schemas, SchemaTemplate::Plain)
57
30
 
58
- manifest_entry = @manifest.lookup(:schemas_only, true)
59
-
60
- manifest_entry.each do |entry|
31
+ schemas_only_entries = ManifestTraverser.new(@manifest).find_schemas_only
32
+ schemas_only_entries.each do |entry|
61
33
  next unless entry.schema_config
62
34
 
63
- # Process each schema in entry.schema_config.schemas
64
- process_schemas(entry.schema_config.schemas, SchemaDocument)
35
+ process_schemas(entry.schema_config.schemas, SchemaTemplate::Document)
65
36
  end
66
37
  end
67
38
 
68
- # rubocop:disable Metrics/MethodLength
69
39
  def compile
70
40
  finalize
71
41
 
72
- # Use SchemaExporter for schema export
73
42
  exporter = SchemaExporter.new(
74
43
  schemas: @config.schemas,
75
44
  output_path: @output_path_schemas,
@@ -77,36 +46,32 @@ module Suma
77
46
  )
78
47
  exporter.export
79
48
 
80
- docs.each_pair do |_schema_id, entry|
81
- entry.compile
49
+ docs.each_pair do |_schema_id, compiler|
50
+ compiler.compile
82
51
  end
52
+ end
53
+
54
+ private
55
+
56
+ def process_schemas(schemas, template_class)
57
+ schemas.each { |s| process_schema(s, template_class) }
58
+ end
59
+
60
+ def process_schema(config_schema, template_class)
61
+ express = ExpressSchema.new(
62
+ id: config_schema.id, path: config_schema.path.to_s,
63
+ output_path: @output_path_schemas.to_s
64
+ )
65
+
66
+ compiler = SchemaCompiler.new(
67
+ schema: express,
68
+ output_path: @output_path_docs.join(express.id),
69
+ template: template_class.new(express.id),
70
+ )
83
71
 
84
- # TODO: make this parallel
85
- # Utils.log"Starting Ractor processing"
86
- # pool = Ractor.new do
87
- # loop do
88
- # Ractor.yield(Ractor.receive)
89
- # end
90
- # end
91
- # workers = (1..4).map do |i|
92
- # Ractor.new(pool, name: "r#{i}") do |p|
93
- # loop do
94
- # input = p.take
95
- # Utils.log"compiling in ractor for #{input.filename_adoc}"
96
- # output_value = input.compile
97
- # Ractor.yield(output_value)
98
- # end
99
- # end
100
- # end
101
- # docs.each do |doc|
102
- # pool.send(doc)
103
- # end
104
- # results = []
105
- # docs.size.times do
106
- # results << Ractor.select(*workers)
107
- # end
108
- # pp results
72
+ @docs[express.id] = compiler
73
+ @schemas[express.id] = express
74
+ @schema_name_to_docs[express.id] = compiler
109
75
  end
110
- # rubocop:enable Metrics/MethodLength
111
76
  end
112
77
  end