Class: Lutaml::Xsd::PackageBuilder

Inherits:
Object
  • Object
show all
Defined in:
lib/lutaml/xsd/package_builder.rb

Overview

Orchestrates package creation using configuration, bundler, and resolver Implements the Strategy pattern for different package types

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config) ⇒ PackageBuilder

Returns a new instance of PackageBuilder.

Parameters:



11
12
13
14
15
16
# File 'lib/lutaml/xsd/package_builder.rb', line 11

def initialize(config)
  @config = config
  @bundler = XsdBundler.new
  @resolver = SchemaResolver.new
  @warnings = []
end

Instance Attribute Details

#bundlerObject (readonly)

Returns the value of attribute bundler.



8
9
10
# File 'lib/lutaml/xsd/package_builder.rb', line 8

def bundler
  @bundler
end

#configObject (readonly)

Returns the value of attribute config.



8
9
10
# File 'lib/lutaml/xsd/package_builder.rb', line 8

def config
  @config
end

#resolverObject (readonly)

Returns the value of attribute resolver.



8
9
10
# File 'lib/lutaml/xsd/package_builder.rb', line 8

def resolver
  @resolver
end

#warningsObject (readonly)

Returns the value of attribute warnings.



8
9
10
# File 'lib/lutaml/xsd/package_builder.rb', line 8

def warnings
  @warnings
end

Instance Method Details

#build(repository, additional_metadata = {}) ⇒ Hash

Build package metadata from repository

Parameters:

  • repository (SchemaRepository)

    Repository to package

  • additional_metadata (Hash) (defaults to: {})

    Additional metadata fields

Returns:

  • (Hash)

    Package data ready for ZIP creation



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/lutaml/xsd/package_builder.rb', line 22

def build(repository,  = {})
  # Collect XSD files based on configuration
  xsd_files = @bundler.collect_xsd_files(repository, @config)

  # Serialize schemas based on format
  serialized_schemas_data = if @config.resolved_package? && !@config.parse_format?
                              serialize_all_schemas(repository)
                            else
                              {}
                            end

  # Build metadata
   = (
    repository,
    ,
    serialized_schemas_data,
  )

  {
    metadata: ,
    xsd_files: xsd_files,
    serialized_schemas: serialized_schemas_data,
  }
end

#deserialize_schema(data, format) ⇒ Schema

Deserialize a schema based on format

Parameters:

  • data (String)

    Serialized data

  • format (Symbol)

    Serialization format

Returns:

  • (Schema)

    Deserialized schema



89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/lutaml/xsd/package_builder.rb', line 89

def deserialize_schema(data, format)
  case format
  when :marshal
    Marshal.load(data)
  when :json
    Lutaml::Xml::Schema::Xsd::Schema.from_json(data)
  when :yaml
    Lutaml::Xml::Schema::Xsd::Schema.from_yaml(data)
  else
    raise ArgumentError, "Unknown serialization format: #{format}"
  end
end

#display_warnings(warnings) ⇒ Object

Display build warnings

Parameters:

  • warnings (Array<Hash>)

    Array of warning hashes



164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/lutaml/xsd/package_builder.rb', line 164

def display_warnings(warnings)
  return if warnings.empty?

  puts
  puts "⚠ WARNINGS (#{warnings.size})"
  puts "" * 70

  warnings.each_with_index do |w, i|
    puts "#{i + 1}. #{w[:type]}: #{w[:reference]}"
    puts "   Location: #{w[:schema]}:#{w[:line]}" if w[:line]
    puts "   Namespace: #{w[:namespace]}" if w[:namespace]
    puts "   Hint: #{w[:hint]}" if w[:hint]
    puts
  end

  puts "" * 70
  puts "Status: ✓ Package created with #{warnings.size} warning(s)"
  puts "Action: Review warnings and update config if needed"
  puts
end

#load(repository, metadata_hash) ⇒ Object

Load package data into repository

Parameters:

  • repository (SchemaRepository)

    Repository to load into

  • metadata_hash (Hash)

    Metadata from package



50
51
52
53
54
55
56
57
58
# File 'lib/lutaml/xsd/package_builder.rb', line 50

def load(repository, )
  # Backward compatibility: check for old serialized_schemas format
  serialized_schemas = ["serialized_schemas"] ||
    [:serialized_schemas]

  return unless serialized_schemas&.any?

  @resolver.load_serialized_schemas(repository, serialized_schemas)
end

#resolve_schema_location_to_file(location, glob_mappings) ⇒ String?

Resolve a schema location (possibly HTTP URL) to actual file path

Parameters:

  • location (String)

    Schema location

  • glob_mappings (Array<Hash>)

    Schema mappings in Glob format

Returns:

  • (String, nil)

    Resolved file path or nil



147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/lutaml/xsd/package_builder.rb', line 147

def resolve_schema_location_to_file(location, glob_mappings)
  glob_mappings.each do |mapping|
    from = mapping[:from]
    to = mapping[:to]

    if from.is_a?(Regexp)
      return location.gsub(from, to) if location&.match?(from)
    elsif location == from
      return to
    end
  end

  nil
end

#serialize_all_schemas(repository) ⇒ Hash

Serialize all schemas from repository

Parameters:

Returns:

  • (Hash)

    Map of file_path => serialized data



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/lutaml/xsd/package_builder.rb', line 105

def serialize_all_schemas(repository)
  all_schemas = repository.send(:get_all_processed_schemas)
  glob_mappings = (repository.schema_location_mappings || []).map(&:to_glob_format)
  serialized = {}

  all_schemas.each do |schema_location, schema|
    # Resolve schema location to actual file path
    file_path = if schema_location.start_with?("/")
                  # Already an absolute file path
                  schema_location
                else
                  # Relative path or HTTP URL - resolve using mappings
                  resolve_schema_location_to_file(schema_location,
                                                  glob_mappings)
                end

    # Skip if we couldn't resolve to a file path
    next unless file_path && File.exist?(file_path)

    data = serialize_schema(schema, @config.serialization_format)
    serialized[file_path] = data if data
  end

  # Also serialize entry point schemas from repository.files
  (repository.files || []).each do |file_path|
    next if serialized.key?(file_path)
    next unless File.exist?(file_path)

    schema = repository.instance_variable_get(:@parsed_schemas)&.[](file_path)
    next unless schema

    data = serialize_schema(schema, @config.serialization_format)
    serialized[file_path] = data if data
  end

  serialized
end

#serialize_schema(schema, format) ⇒ String?

Serialize a single schema based on format

Parameters:

  • schema (Schema)

    Schema to serialize

  • format (Symbol)

    Serialization format

Returns:

  • (String, nil)

    Serialized data or nil for :parse format



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/lutaml/xsd/package_builder.rb', line 64

def serialize_schema(schema, format)
  case format
  when :marshal
    # Clear lazy XML element references that hold non-serializable
    # adapter nodes throughout the object graph.
    # lutaml-model's :lazy import_declaration_plan mode stores
    # XmlElement references (containing Nokogiri nodes) on every
    # model instance during deserialization.
    clear_pending_plan_references(schema)
    Marshal.dump(schema)
  when :json
    schema.to_json
  when :yaml
    schema.to_yaml
  when :parse
    nil
  else
    raise ArgumentError, "Unknown serialization format: #{format}"
  end
end

#suggest_fix(error) ⇒ String

Suggest fix for reference error

Parameters:

  • error (StandardError)

    Error that occurred

Returns:

  • (String)

    Suggestion text



188
189
190
191
192
193
194
195
196
197
198
# File 'lib/lutaml/xsd/package_builder.rb', line 188

def suggest_fix(error)
  message = error.message

  if message.include?("not found")
    "Check that all required schemas are included in dependencies"
  elsif message.include?("namespace")
    "Verify namespace URI is correct and schema is imported"
  else
    "Review schema dependencies and imports"
  end
end