lutaml-lml 0.1.2 → 0.1.3

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 (38) hide show
  1. checksums.yaml +4 -4
  2. data/lib/lutaml/lml/cli.rb +1 -1
  3. data/lib/lutaml/lml/data_processor/view_processing.rb +7 -6
  4. data/lib/lutaml/lml/document_builder.rb +1 -8
  5. data/lib/lutaml/lml/entity_types.rb +30 -0
  6. data/lib/lutaml/lml/executor.rb +1 -1
  7. data/lib/lutaml/lml/format/adapter/standard_adapter.rb +1 -1
  8. data/lib/lutaml/lml/formatter/base.rb +7 -4
  9. data/lib/lutaml/lml/grammar/concerns/definitions.rb +29 -21
  10. data/lib/lutaml/lml/grammar/concerns/primitives.rb +4 -1
  11. data/lib/lutaml/lml/grammar/concerns/view_rules.rb +27 -7
  12. data/lib/lutaml/lml/grammar/instances.rb +5 -2
  13. data/lib/lutaml/lml/import_resolver.rb +45 -47
  14. data/lib/lutaml/lml/model_compiler.rb +3 -4
  15. data/lib/lutaml/lml/models/association.rb +1 -1
  16. data/lib/lutaml/lml/models/constraint.rb +1 -1
  17. data/lib/lutaml/lml/models/data_type.rb +5 -1
  18. data/lib/lutaml/lml/models/diagram.rb +1 -1
  19. data/lib/lutaml/lml/models/document.rb +8 -7
  20. data/lib/lutaml/lml/models/enum.rb +5 -1
  21. data/lib/lutaml/lml/models/operation.rb +1 -1
  22. data/lib/lutaml/lml/models/package.rb +1 -1
  23. data/lib/lutaml/lml/models/primitive_type.rb +5 -1
  24. data/lib/lutaml/lml/models/top_element_attribute.rb +5 -5
  25. data/lib/lutaml/lml/models/uml_class.rb +11 -18
  26. data/lib/lutaml/lml/models/value.rb +1 -1
  27. data/lib/lutaml/lml/parser.rb +3 -8
  28. data/lib/lutaml/lml/pipeline.rb +9 -30
  29. data/lib/lutaml/lml/preprocessor.rb +26 -21
  30. data/lib/lutaml/lml/source.rb +49 -0
  31. data/lib/lutaml/lml/transform.rb +5 -1
  32. data/lib/lutaml/lml/types/text_type.rb +28 -0
  33. data/lib/lutaml/lml/types.rb +10 -0
  34. data/lib/lutaml/lml/version.rb +1 -1
  35. data/lib/lutaml/lml/view_resolution.rb +32 -0
  36. data/lib/lutaml/lml/view_resolver.rb +5 -5
  37. data/lib/lutaml/lml.rb +18 -0
  38. metadata +7 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7d0abfcd0323da47f7c05a6df8de6ddd2a17b91a6c022f2d503372bf9ad3ad62
4
- data.tar.gz: 98a5f6ba03661fb78b761e590631aef8870171332cbebe9a51d173633fc1e4a5
3
+ metadata.gz: 848b5d75872b444720cee8fb6cdc2ae93db738657cb8ad13633d0317d8bd9808
4
+ data.tar.gz: f9718ba7428f4948d06bf8e489d55d78584c95086ebc4ff6ea6fb2bd0c0e41a9
5
5
  SHA512:
6
- metadata.gz: 77d556ec76e8d1fc4d60b3d903211d39223f35ed04cbde561e812ca8eadd3ef93553364d36e404c59372add94eb24ca99132147446875eb2e47bebf1e9e90484
7
- data.tar.gz: 8124cc37dac4d70ef905a1b8edb80d23acc40efe1d73496c15414250fb13d15f5dc86ebf576ff674b32d4aa3dd9e5ff69a1c7a33df558f56925813ca064aa035
6
+ metadata.gz: adae7746cdcf26e0709537239e7a4cc234c9287f49615eca76d44add023d11d317b30754ac9fef8d1dd6fbbc0899d19a77c284aa3726b6f8809b9f49ea440b4a
7
+ data.tar.gz: ac7189d5cef1e567485b38b56e23998961280600d157c037e8e21def73ee41e22f632ff82c0ab298c286319c00ab74d9a71e6d3fe0f4e9669ea8644cdd7b03ba
@@ -24,7 +24,7 @@ module Lutaml
24
24
  }.freeze
25
25
 
26
26
  PARSE_HANDLERS = {
27
- 'lutaml' => ->(path) { Lutaml::Lml::Parser.parse(File.new(path)) },
27
+ 'lutaml' => ->(path) { Lutaml::Lml.parse(File.new(path)) },
28
28
  'yaml' => ->(path) { Lutaml::Lml::YamlParser.parse(path.to_s) },
29
29
  'yml' => ->(path) { Lutaml::Lml::YamlParser.parse(path.to_s) },
30
30
  'exp' => lambda { |path|
@@ -4,20 +4,21 @@ module Lutaml
4
4
  module Lml
5
5
  class DataProcessor
6
6
  module ViewProcessing
7
+ # entity_name_list parses to a Hash (one name) or an Array of
8
+ # Hashes (several); normalize both to one list of strings.
7
9
  def process_show_list(data)
8
- extract_entity_names(data)
10
+ entity_names_from(data)
9
11
  end
10
12
 
11
13
  def process_hide_list(data)
12
- extract_entity_names(data)
14
+ entity_names_from(data)
13
15
  end
14
16
 
15
17
  private
16
18
 
17
- def extract_entity_names(data)
18
- return data.map { |d| extract_entity_names(d) } if data.is_a?(Array)
19
- return data[:entity_name].to_s if data.is_a?(Hash) && data.key?(:entity_name)
20
- data.to_s
19
+ def entity_names_from(data)
20
+ entries = data.is_a?(Array) ? data : [data]
21
+ entries.map { |entry| entry[:entity_name].to_s }
21
22
  end
22
23
  end
23
24
  end
@@ -65,7 +65,6 @@ module Lutaml
65
65
 
66
66
  def set_model_attributes(model, hash)
67
67
  hash.each do |key, value|
68
- value = sanitize_definition(value) if key == :definition
69
68
  apply_attribute(model, key, value)
70
69
  end
71
70
  end
@@ -79,11 +78,6 @@ module Lutaml
79
78
  hash
80
79
  end
81
80
 
82
- def sanitize_definition(value)
83
- value.to_s.gsub(/\\}/, '}').gsub(/\\{/, '{')
84
- .split("\n").map(&:strip).join("\n")
85
- end
86
-
87
81
  def apply_attribute(model, key, value)
88
82
  return unless model.class.attributes.key?(key.to_sym)
89
83
 
@@ -131,8 +125,7 @@ module Lutaml
131
125
  end
132
126
 
133
127
  def build_view_filter(entity_names)
134
- names = entity_names.is_a?(Array) ? entity_names : [entity_names]
135
- ViewFilter.new(entity_names: names.map(&:to_s))
128
+ ViewFilter.new(entity_names: Array(entity_names).map(&:to_s))
136
129
  end
137
130
  end
138
131
  end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lutaml
4
+ module Lml
5
+ # Single source of truth for entity types held on a Document. Each
6
+ # entity model declares self.entity_type (the Document collection
7
+ # name); consumers iterate this registry instead of hardcoding the
8
+ # type list in four places.
9
+ module EntityTypes
10
+ ALL = [UmlClass, Enum, DataType, PrimitiveType].freeze
11
+
12
+ def self.all
13
+ ALL
14
+ end
15
+
16
+ def self.by_symbol
17
+ @by_symbol ||= ALL.each_with_object({}) { |klass, index| index[klass.entity_type] = klass }
18
+ end
19
+
20
+ def self.symbols
21
+ by_symbol.keys
22
+ end
23
+
24
+ # Entities that can own attributes/associations (excludes enums).
25
+ def self.classifiable
26
+ ALL.select(&:classifiable?)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -13,7 +13,7 @@ module Lutaml
13
13
  #
14
14
  # Usage:
15
15
  # compiled = ModelCompiler.new.compile(models_file)
16
- # doc = Pipeline.call(instances_file, resolve: false)
16
+ # doc = Lutaml::Lml.parse_document(instances_file)
17
17
  # result = Executor.run(doc, compiled: compiled)
18
18
  # result.instances # array of hydrated instance objects
19
19
  # result.errors # array of validation error strings
@@ -11,7 +11,7 @@ module Lutaml
11
11
  return data if data.is_a?(Hash)
12
12
 
13
13
  input = data.is_a?(IO) ? data : StringIO.new(data.to_s)
14
- doc = Lutaml::Lml::Pipeline.call(input, resolve: false)
14
+ doc = Lutaml::Lml.parse_document(input)
15
15
  instance_to_hash(doc.instance)
16
16
  end
17
17
 
@@ -9,7 +9,7 @@ module Lutaml
9
9
 
10
10
  def find_by_name(name)
11
11
  name = name.to_sym
12
- all.detect { |formatter_class| formatter_class.name == name }
12
+ all.detect { |formatter_class| formatter_class.formatter_name == name }
13
13
  end
14
14
  end
15
15
 
@@ -34,7 +34,10 @@ module Lutaml
34
34
  new(attributes).format(node)
35
35
  end
36
36
 
37
- def name
37
+ # Registry key for Formatter.find_by_name. Deliberately not
38
+ # `name` — shadowing Class#name breaks Ruby internals and any
39
+ # library that legitimately calls .name on these classes.
40
+ def formatter_name
38
41
  to_s.split('::').last.downcase.to_sym
39
42
  end
40
43
  end
@@ -46,7 +49,7 @@ module Lutaml
46
49
  end
47
50
 
48
51
  def name
49
- self.class.name
52
+ self.class.formatter_name
50
53
  end
51
54
 
52
55
  attr_reader :type
@@ -61,7 +64,7 @@ module Lutaml
61
64
 
62
65
  def dispatch_format(node)
63
66
  handler = FORMAT_HANDLERS.find { |type, _| node.is_a?(type) }&.last
64
- return unless handler
67
+ raise Lml::Error, "no format handler for #{node.class}" unless handler
65
68
 
66
69
  public_send(handler, node)
67
70
  end
@@ -55,13 +55,21 @@ module Lutaml
55
55
  end
56
56
 
57
57
  # -- Definition
58
+ # Balanced-brace body: nested "{...}" and "\"-escapes are allowed,
59
+ # so definition text can contain format templates like "ZB{code}".
60
+ rule(:definition_content) do
61
+ (
62
+ (str("\\") >> any) |
63
+ (str("{") >> definition_content >> str("}")) |
64
+ (str("}").absent? >> any)
65
+ ).repeat(0)
66
+ end
58
67
  rule(:definition_body) do
59
68
  spaces? >>
60
69
  str("definition") >>
61
70
  whitespace? >>
62
71
  str("{") >>
63
- ((str("\\") >> any) | (str("}").absent? >> any))
64
- .repeat.maybe.as(:definition) >>
72
+ definition_content.as(:definition) >>
65
73
  str("}")
66
74
  end
67
75
 
@@ -142,22 +150,20 @@ module Lutaml
142
150
  end
143
151
  rule(:diagram_definitions) { diagram_definition >> whitespace? }
144
152
 
153
+ # A model file: bare top-level definitions with no enclosing
154
+ # named block. Same inner grammar as a diagram body; labeled
155
+ # :members so the document builder sees document shape.
156
+ rule(:model_definitions) { diagram_inner_definition.repeat(1).as(:members) }
157
+
145
158
  # -- View (extends diagram with import/show/hide)
146
159
  rule(:view_keyword) { kw_view >> spaces? }
147
- rule(:view_inner_definitions) do
148
- title_definition |
149
- caption_definition |
150
- fontname_definition |
151
- view_import.as(:view_imports) |
160
+ rule(:view_only_definitions) do
161
+ view_import.as(:view_imports) |
152
162
  show_directive |
153
- hide_directive |
154
- class_definition.as(:classes) |
155
- enum_definition.as(:enums) |
156
- primitive_definition.as(:primitives) |
157
- data_type_definition.as(:data_types) |
158
- association_definition.as(:associations) |
159
- comment_definition |
160
- comment_multiline_definition
163
+ hide_directive
164
+ end
165
+ rule(:view_inner_definitions) do
166
+ view_only_definitions | diagram_inner_definitions
161
167
  end
162
168
  rule(:view_inner_definition) do
163
169
  view_inner_definitions >> whitespace?
@@ -176,17 +182,19 @@ module Lutaml
176
182
 
177
183
  # -- Metadata
178
184
  rule(:title_keyword) { kw_title >> spaces }
185
+ # Quoted titles/captions accept any character (parentheses, commas,
186
+ # Unicode). Unquoted form keeps a conservative charset.
179
187
  rule(:title_text) do
180
- quotes? >>
181
- match['a-zA-Z0-9_\- ,.:;'].repeat(1).as(:title) >>
182
- quotes?
188
+ (str('"') >> (str('"').absent? >> any).repeat(1).as(:title) >> str('"')) |
189
+ (str("'") >> (str("'").absent? >> any).repeat(1).as(:title) >> str("'")) |
190
+ match['a-zA-Z0-9_\- ,.:;()+\'/'].repeat(1).as(:title)
183
191
  end
184
192
  rule(:title_definition) { title_keyword >> title_text }
185
193
  rule(:caption_keyword) { kw_caption >> spaces }
186
194
  rule(:caption_text) do
187
- quotes? >>
188
- match['a-zA-Z0-9_\- ,.:;'].repeat(1).as(:caption) >>
189
- quotes?
195
+ (str('"') >> (str('"').absent? >> any).repeat(1).as(:caption) >> str('"')) |
196
+ (str("'") >> (str("'").absent? >> any).repeat(1).as(:caption) >> str("'")) |
197
+ match['a-zA-Z0-9_\- ,.:;()+\'/'].repeat(1).as(:caption)
190
198
  end
191
199
  rule(:caption_definition) { caption_keyword >> caption_text }
192
200
 
@@ -19,8 +19,11 @@ module Lutaml
19
19
  rule(:whitespace?) { whitespace.maybe }
20
20
  rule(:newline) { match('[\r\n]') }
21
21
 
22
+ rule(:quoted_string_content) do
23
+ (str('"').absent? >> any).repeat
24
+ end
22
25
  rule(:quoted_string) do
23
- str('"') >> (str('"').absent? >> any).repeat.as(:string) >> str('"')
26
+ str('"') >> quoted_string_content.as(:string) >> str('"')
24
27
  end
25
28
  rule(:boolean) { (str("true") | str("false")).as(:boolean) }
26
29
  rule(:number) { (match("[0-9]").repeat(1) >> str(".") >> match("[0-9]").repeat(1)).as(:float) | match("[0-9]").repeat(1).as(:number) }
@@ -7,25 +7,45 @@ module Lutaml
7
7
  module ViewRules
8
8
  include Parslet
9
9
 
10
- rule(:view_import_keyword) { str("import") >> spaces }
10
+ # View-scoped keyword rules. `import` is named view_import to
11
+ # stay MECE with the instances-block kw_import keyword. The
12
+ # trailing `spaces` is the word boundary: `important` fails to
13
+ # match rather than parsing as `import`.
14
+ VIEW_KEYWORDS = {
15
+ "view_import" => "import",
16
+ "show" => "show",
17
+ "hide" => "hide",
18
+ }.freeze
19
+
20
+ VIEW_KEYWORDS.each do |rule_name, keyword|
21
+ rule("kw_#{rule_name}") { whitespace? >> str(keyword) >> spaces }
22
+ end
11
23
 
12
24
  rule(:view_import) do
13
- view_import_keyword >>
14
- str('"') >> (str('"').absent? >> any).repeat.as(:path) >> str('"') >>
25
+ kw_view_import >>
26
+ str('"') >> quoted_string_content.as(:path) >> str('"') >>
15
27
  whitespace?
16
28
  end
17
29
 
30
+ # Entity names in show/hide lists must be space-free: general
31
+ # class_name_chars allows spaces, which would swallow a
32
+ # following directive (`show Foo, Bar hide Baz` would parse
33
+ # "Bar hide Baz" as one name).
34
+ rule(:entity_name_atom) do
35
+ match('[a-zA-Z0-9_.:\-]').repeat(1).as(:entity_name)
36
+ end
37
+
18
38
  rule(:entity_name_list) do
19
- class_name.as(:entity_name) >>
20
- (spaces? >> str(",") >> spaces? >> class_name.as(:entity_name)).repeat
39
+ entity_name_atom >>
40
+ (spaces? >> str(",") >> spaces? >> entity_name_atom).repeat
21
41
  end
22
42
 
23
43
  rule(:show_directive) do
24
- str("show") >> spaces >> entity_name_list.as(:show_list) >> whitespace?
44
+ kw_show >> entity_name_list.as(:show_list) >> whitespace?
25
45
  end
26
46
 
27
47
  rule(:hide_directive) do
28
- str("hide") >> spaces >> entity_name_list.as(:hide_list) >> whitespace?
48
+ kw_hide >> entity_name_list.as(:hide_list) >> whitespace?
29
49
  end
30
50
  end
31
51
  end
@@ -30,8 +30,11 @@ module Lutaml
30
30
  rule("kw_#{keyword}") { whitespace? >> str(keyword) }
31
31
  end
32
32
 
33
- # -- Root (Full: diagram + models + instances)
34
- rule(:diagram) { require_block? >> (models | diagram_definitions | view_definitions | instances | instance) }
33
+ # -- Root (Full: diagram + models + instances + bare model files)
34
+ rule(:diagram) do
35
+ require_block? >>
36
+ (models | diagram_definitions | view_definitions | instances | instance | model_definitions)
37
+ end
35
38
  end
36
39
  end
37
40
  end
@@ -5,83 +5,81 @@ require "set"
5
5
  module Lutaml
6
6
  module Lml
7
7
  class ImportResolver
8
- def initialize(base_path)
9
- @base_path = base_path
8
+ def initialize(base_dir)
9
+ @base_dir = base_dir
10
10
  end
11
11
 
12
+ # Returns [entity_index, associations] where entity_index maps
13
+ # entity name → entity. ViewResolver consumes the index without
14
+ # rebuilding it.
12
15
  def resolve(document)
13
- entities = {}
16
+ @failures = []
17
+ entity_index = {}
14
18
  associations = []
15
19
  visited = Set.new
16
20
 
17
21
  document.view_imports.each do |import|
18
- resolve_import(import.path, entities, associations, visited, @base_path)
22
+ resolve_import(import.path, entity_index, associations, visited, @base_dir)
19
23
  end
20
24
 
21
- collect_local_entities(document, entities, associations)
25
+ collect_local_entities(document, entity_index, associations)
22
26
 
23
- [entities.values, associations]
27
+ raise ImportError, @failures.join("\n") if @failures.any?
28
+
29
+ [entity_index, associations]
24
30
  end
25
31
 
26
32
  private
27
33
 
28
- def resolve_import(path, entities, associations, visited, base_path)
29
- base_dir = base_path ? File.dirname(base_path) : Dir.pwd
34
+ def resolve_import(path, entity_index, associations, visited, base_dir)
30
35
  abs_pattern = File.expand_path(path, base_dir)
36
+ files = Dir.glob(abs_pattern)
37
+ if files.empty?
38
+ @failures << "import matched no files: #{path} (resolved to #{abs_pattern})"
39
+ end
31
40
 
32
- Dir.glob(abs_pattern).each do |file_path|
41
+ files.each do |file_path|
33
42
  next if visited.include?(file_path)
34
43
  visited.add(file_path)
35
44
 
36
- if view_file?(file_path)
37
- resolve_view_file(file_path, entities, associations, visited)
38
- else
39
- resolve_model_file(file_path, entities, associations)
45
+ doc = parse_file(file_path)
46
+ collect_local_entities(doc, entity_index, associations)
47
+
48
+ doc.view_imports.each do |import|
49
+ resolve_import(import.path, entity_index, associations, visited, File.dirname(file_path))
40
50
  end
41
51
  end
42
52
  end
43
53
 
44
- def resolve_view_file(file_path, entities, associations, visited)
45
- doc = Parser.parse_document(File.new(file_path))
46
-
47
- collect_local_entities(doc, entities, associations)
48
-
49
- doc.view_imports&.each do |import|
50
- resolve_import(import.path, entities, associations, visited, file_path)
51
- end
54
+ # The grammar root accepts every file shape (diagram, view,
55
+ # models block, bare definitions) — no content sniffing needed.
56
+ def parse_file(file_path)
57
+ File.open(file_path) { |file| Pipeline.call(file) }
52
58
  rescue Errno::ENOENT, Errno::EACCES => e
53
- warn "Skipping #{file_path}: #{e.message}"
54
- []
59
+ @failures << "cannot read import #{file_path}: #{e.message}"
60
+ Document.new
55
61
  end
56
62
 
57
- def resolve_model_file(file_path, entities, associations)
58
- content = File.read(file_path)
59
- wrapped = "diagram Fragment {\n#{content}\n}"
60
- doc = Parser.parse_document(StringIO.new(wrapped))
61
-
62
- collect_local_entities(doc, entities, associations)
63
- rescue Errno::ENOENT, Errno::EACCES => e
64
- warn "Skipping #{file_path}: #{e.message}"
65
- []
66
- end
67
-
68
- def view_file?(file_path)
69
- head = File.read(file_path, 200, encoding: "UTF-8")
70
- head.match?(/\b(view|diagram)\s+\w/)
71
- rescue Errno::ENOENT, Errno::EACCES
72
- false
73
- end
74
-
75
- def collect_local_entities(doc, entities, associations)
76
- merge_entities(doc.classes, entities)
77
- merge_entities(doc.enums, entities)
78
- merge_entities(doc.data_types, entities)
63
+ def collect_local_entities(doc, entity_index, associations)
64
+ EntityTypes.all.each do |type|
65
+ merge_entities(doc.public_send(type.entity_type), entity_index)
66
+ end
79
67
  associations.concat(doc.associations.to_a)
80
68
  end
81
69
 
82
- def merge_entities(collection, entities)
70
+ # Re-importing the same entity through two paths is legitimate
71
+ # (dedup silently); the same name with different content is a
72
+ # conflict that must not resolve to a silently wrong diagram.
73
+ def merge_entities(collection, entity_index)
83
74
  collection.each do |entity|
84
- entities[entity.name] ||= entity
75
+ next if entity.name.nil?
76
+
77
+ existing = entity_index[entity.name]
78
+ if existing.nil?
79
+ entity_index[entity.name] = entity
80
+ elsif existing.to_hash != entity.to_hash
81
+ @failures << "entity '#{entity.name}' is defined differently in two imports"
82
+ end
85
83
  end
86
84
  end
87
85
  end
@@ -15,7 +15,6 @@ module Lutaml
15
15
  "DateTime" => :date_time,
16
16
  "Time" => :time,
17
17
  "Uri" => :string,
18
- "Hash" => :hash,
19
18
  }.freeze
20
19
 
21
20
  # Tokens that denote unbounded cardinality in LML attribute
@@ -30,13 +29,13 @@ module Lutaml
30
29
  end
31
30
 
32
31
  def compile(input)
33
- doc = Pipeline.call(input, resolve: false)
32
+ doc = Lutaml::Lml.parse_document(input)
34
33
  compile_document(doc)
35
34
  @compiled
36
35
  end
37
36
 
38
37
  def hydrate(input)
39
- doc = input.is_a?(Document) ? input : Pipeline.call(input, resolve: false)
38
+ doc = input.is_a?(Document) ? input : Lutaml::Lml.parse_document(input)
40
39
  compile_document(doc) unless @compiled.any?
41
40
  return {} unless doc.instance
42
41
 
@@ -56,7 +55,7 @@ module Lutaml
56
55
  #
57
56
  # Returns an array of validation error strings (empty if all pass).
58
57
  def validate(input, compiled: nil)
59
- doc = input.is_a?(Document) ? input : Pipeline.call(input, resolve: false)
58
+ doc = input.is_a?(Document) ? input : Lutaml::Lml.parse_document(input)
60
59
  if compiled
61
60
  @compiled = compiled
62
61
  else
@@ -5,7 +5,7 @@ module Lutaml
5
5
  class Association < Lutaml::Model::Serializable
6
6
  # From TopElement
7
7
  attribute :name, :string
8
- attribute :definition, :string
8
+ attribute :definition, Lutaml::Lml::Types::TextType
9
9
  attribute :keyword, :string
10
10
  attribute :stereotype, :string, collection: true, default: -> { [] }
11
11
  attribute :visibility, :string, default: "public"
@@ -5,7 +5,7 @@ module Lutaml
5
5
  class Constraint < Lutaml::Model::Serializable
6
6
  # From TopElement
7
7
  attribute :name, :string
8
- attribute :definition, :string
8
+ attribute :definition, Lutaml::Lml::Types::TextType
9
9
  attribute :keyword, :string
10
10
  attribute :stereotype, :string, collection: true, default: -> { [] }
11
11
  attribute :visibility, :string, default: "public"
@@ -5,7 +5,7 @@ module Lutaml
5
5
  class DataType < Lutaml::Model::Serializable
6
6
  # From TopElement
7
7
  attribute :name, :string
8
- attribute :definition, :string
8
+ attribute :definition, Lutaml::Lml::Types::TextType
9
9
  attribute :keyword, :string, default: "dataType"
10
10
  attribute :stereotype, :string, collection: true, default: -> { [] }
11
11
  attribute :visibility, :string, default: "public"
@@ -26,6 +26,10 @@ module Lutaml
26
26
  def self.entity_type
27
27
  :data_types
28
28
  end
29
+
30
+ def self.classifiable?
31
+ true
32
+ end
29
33
  end
30
34
  end
31
35
  end
@@ -4,7 +4,7 @@ module Lutaml
4
4
  module Lml
5
5
  class Diagram < Lutaml::Model::Serializable
6
6
  attribute :name, :string
7
- attribute :definition, :string
7
+ attribute :definition, Lutaml::Lml::Types::TextType
8
8
  attribute :keyword, :string
9
9
  attribute :stereotype, :string, collection: true, default: -> { [] }
10
10
  attribute :visibility, :string, default: "public"
@@ -7,10 +7,10 @@ module Lutaml
7
7
  attribute :name, :string
8
8
  attribute :title, :string
9
9
  attribute :caption, :string
10
- attribute :groups, "Lutaml::Lml::Group", collection: true
10
+ attribute :groups, "Lutaml::Lml::Group", collection: true, default: -> { [] }
11
11
  attribute :fidelity, "Lutaml::Lml::Fidelity"
12
12
  attribute :fontname, :string
13
- attribute :comments, :string, collection: true
13
+ attribute :comments, :string, collection: true, default: -> { [] }
14
14
 
15
15
  attribute :classes, "Lutaml::Lml::UmlClass", collection: true, default: -> { [] }
16
16
  attribute :data_types, "Lutaml::Lml::DataType", collection: true, default: -> { [] }
@@ -20,11 +20,12 @@ module Lutaml
20
20
  attribute :associations, "Lutaml::Lml::Association", collection: true, default: -> { [] }
21
21
  attribute :diagrams, "Lutaml::Lml::Diagram", collection: true, default: -> { [] }
22
22
 
23
- # LML-specific
23
+ # LML-specific. instance/instances/fidelity/show_filter/hide_filter
24
+ # are deliberately default-less: nil means "absent".
24
25
  attribute :instance, "Lutaml::Lml::Instance"
25
- attribute :requires, :string, collection: true
26
+ attribute :requires, :string, collection: true, default: -> { [] }
26
27
  attribute :instances, "Lutaml::Lml::InstanceCollection"
27
- attribute :view_imports, "Lutaml::Lml::ViewImport", collection: true
28
+ attribute :view_imports, "Lutaml::Lml::ViewImport", collection: true, default: -> { [] }
28
29
  attribute :show_filter, "Lutaml::Lml::ViewFilter"
29
30
  attribute :hide_filter, "Lutaml::Lml::ViewFilter"
30
31
 
@@ -32,13 +33,13 @@ module Lutaml
32
33
  # formatters that need to walk every classifiable type without
33
34
  # caring which collection holds it.
34
35
  def all_classes
35
- classes + enums + data_types + primitives
36
+ EntityTypes.all.flat_map { |type| public_send(type.entity_type) }
36
37
  end
37
38
 
38
39
  # Class-like entities that can own associations. Excludes enums
39
40
  # (which have no attributes/associations of their own).
40
41
  def classifiable_classes
41
- classes + data_types + primitives
42
+ EntityTypes.classifiable.flat_map { |type| public_send(type.entity_type) }
42
43
  end
43
44
  end
44
45
  end
@@ -5,7 +5,7 @@ module Lutaml
5
5
  class Enum < Lutaml::Model::Serializable
6
6
  # From TopElement
7
7
  attribute :name, :string
8
- attribute :definition, :string
8
+ attribute :definition, Lutaml::Lml::Types::TextType
9
9
  attribute :keyword, :string, default: "enumeration"
10
10
  attribute :stereotype, :string, collection: true, default: -> { [] }
11
11
  attribute :visibility, :string, default: "public"
@@ -23,6 +23,10 @@ module Lutaml
23
23
  def self.entity_type
24
24
  :enums
25
25
  end
26
+
27
+ def self.classifiable?
28
+ false
29
+ end
26
30
  end
27
31
  end
28
32
  end
@@ -5,7 +5,7 @@ module Lutaml
5
5
  class Operation < Lutaml::Model::Serializable
6
6
  # From TopElement
7
7
  attribute :name, :string
8
- attribute :definition, :string
8
+ attribute :definition, Lutaml::Lml::Types::TextType
9
9
  attribute :keyword, :string
10
10
  attribute :stereotype, :string, collection: true, default: -> { [] }
11
11
  attribute :visibility, :string, default: "public"
@@ -5,7 +5,7 @@ module Lutaml
5
5
  class Package < Lutaml::Model::Serializable
6
6
  # From TopElement
7
7
  attribute :name, :string
8
- attribute :definition, :string
8
+ attribute :definition, Lutaml::Lml::Types::TextType
9
9
  attribute :keyword, :string
10
10
  attribute :stereotype, :string, collection: true, default: -> { [] }
11
11
  attribute :visibility, :string, default: "public"
@@ -7,7 +7,7 @@ module Lutaml
7
7
  # accesses the same attributes as DataType via format_class.
8
8
  attribute :name, :string
9
9
  attribute :keyword, :string, default: "primitive"
10
- attribute :definition, :string
10
+ attribute :definition, Lutaml::Lml::Types::TextType
11
11
  attribute :stereotype, :string, collection: true, default: -> { [] }
12
12
  attribute :visibility, :string, default: "public"
13
13
  attribute :is_abstract, :boolean, default: false
@@ -21,6 +21,10 @@ module Lutaml
21
21
  def self.entity_type
22
22
  :primitives
23
23
  end
24
+
25
+ def self.classifiable?
26
+ true
27
+ end
24
28
  end
25
29
  end
26
30
  end
@@ -16,16 +16,16 @@ module Lutaml
16
16
  attribute :is_static, :boolean, default: false
17
17
  attribute :is_read_only, :boolean, default: false
18
18
  attribute :stereotype, :string, collection: true, default: -> { [] }
19
- attribute :definition, :string
19
+ attribute :definition, Lutaml::Lml::Types::TextType
20
20
  attribute :association, :string
21
21
  attribute :default, :string
22
22
 
23
23
  # LML-specific attributes
24
- attribute :properties, "Lutaml::Lml::TopElementAttribute", collection: true, default: []
25
- attribute :value, "Lutaml::Lml::TopElementAttribute", collection: true
26
- attribute :attributes, "Lutaml::Lml::TopElementAttribute", collection: true, default: []
24
+ attribute :properties, "Lutaml::Lml::TopElementAttribute", collection: true, default: -> { [] }
25
+ attribute :value, "Lutaml::Lml::TopElementAttribute", collection: true, default: -> { [] }
26
+ attribute :attributes, "Lutaml::Lml::TopElementAttribute", collection: true, default: -> { [] }
27
27
  attribute :extended, :boolean
28
- attribute :instances, "Lutaml::Lml::Instance", collection: true, default: []
28
+ attribute :instances, "Lutaml::Lml::Instance", collection: true, default: -> { [] }
29
29
  end
30
30
  end
31
31
  end
@@ -3,9 +3,10 @@
3
3
  module Lutaml
4
4
  module Lml
5
5
  class UmlClass < Lutaml::Model::Serializable
6
- # From TopElement
6
+ # From TopElement. TextType unescapes \{ \} and normalizes lines
7
+ # on every assignment (builder, yaml, direct).
7
8
  attribute :name, :string
8
- attribute :definition, :string
9
+ attribute :definition, Lutaml::Lml::Types::TextType
9
10
  attribute :keyword, :string
10
11
  attribute :stereotype, :string, collection: true, default: -> { [] }
11
12
  attribute :visibility, :string, default: "public"
@@ -31,9 +32,7 @@ module Lutaml
31
32
  map "name", to: :name
32
33
  map "keyword", to: :keyword
33
34
  map "is_abstract", to: :is_abstract
34
- map "definition", to: :definition, with: {
35
- to: :definition_to_yaml, from: :definition_from_yaml
36
- }
35
+ map "definition", to: :definition
37
36
  map "modifier", to: :modifier
38
37
  map "stereotype", to: :stereotype
39
38
  map "visibility", to: :visibility
@@ -42,6 +41,9 @@ module Lutaml
42
41
  map "operations", to: :operations
43
42
  map "constraints", to: :constraints
44
43
  map "data_types", to: :data_types
44
+ # Owner-side defaulting is a parent-context rule ("an
45
+ # association nested under a class defaults its owner to that
46
+ # class"); only a mapping proc can see the containing model.
45
47
  map "associations", to: :associations, with: {
46
48
  to: :associations_to_yaml, from: :associations_from_yaml
47
49
  }
@@ -63,22 +65,13 @@ module Lutaml
63
65
  model.associations = associations
64
66
  end
65
67
 
66
- def definition_to_yaml(model, doc)
67
- doc["definition"] = model.definition if model.definition
68
- end
69
-
70
- def definition_from_yaml(model, value)
71
- model.definition = value.to_s
72
- .gsub(/\\}/, "}")
73
- .gsub(/\\{/, "{")
74
- .split("\n")
75
- .map(&:strip)
76
- .join("\n")
77
- end
78
-
79
68
  def self.entity_type
80
69
  :classes
81
70
  end
71
+
72
+ def self.classifiable?
73
+ true
74
+ end
82
75
  end
83
76
  end
84
77
  end
@@ -6,7 +6,7 @@ module Lutaml
6
6
  attribute :name, :string
7
7
  attribute :id, :string
8
8
  attribute :type, :string
9
- attribute :definition, :string
9
+ attribute :definition, Lutaml::Lml::Types::TextType
10
10
  end
11
11
  end
12
12
  end
@@ -5,18 +5,13 @@ require "parslet/convenience"
5
5
 
6
6
  module Lutaml
7
7
  module Lml
8
+ # The Parslet parser: raw LML text → parse tree. Pipeline-level
9
+ # entry points live on the Lutaml::Lml module (parse /
10
+ # parse_document).
8
11
  class Parser < Parslet::Parser
9
12
  include Grammar::Full
10
13
 
11
14
  root(:diagram)
12
-
13
- def self.parse(io)
14
- Pipeline.call(io)
15
- end
16
-
17
- def self.parse_document(io)
18
- Pipeline.call(io, resolve: false)
19
- end
20
15
  end
21
16
  end
22
17
  end
@@ -5,26 +5,24 @@ require "parslet/convenience"
5
5
 
6
6
  module Lutaml
7
7
  module Lml
8
+ # Parse pipeline only: preprocess → parse → transform → process →
9
+ # build. View resolution and label enrichment are a separate,
10
+ # explicit post-parse step (ViewResolution) — file I/O for imports
11
+ # does not belong inside parsing.
8
12
  class Pipeline
9
- def self.call(input, resolve: true)
10
- new(input, resolve: resolve).call
13
+ def self.call(input)
14
+ new(input).call
11
15
  end
12
16
 
13
- def initialize(input, resolve: true)
14
- @input = input
15
- @resolve = resolve
17
+ def initialize(input)
18
+ @input = Source.wrap(input)
16
19
  end
17
20
 
18
21
  def call
19
22
  data = Preprocessor.call(@input)
20
23
  hash = parse_raw(data)
21
24
  hash = DataProcessor.process(hash)
22
- document = build_document(hash)
23
- if @resolve
24
- document = resolve_document(document)
25
- AssociationLabelResolver.new.enrich(document)
26
- end
27
- document
25
+ build_document(hash)
28
26
  end
29
27
 
30
28
  private
@@ -40,25 +38,6 @@ module Lutaml
40
38
  def build_document(hash)
41
39
  DocumentBuilder.new(DocumentBuilder::DEFAULT_REGISTRY).build(:document, hash)
42
40
  end
43
-
44
- def resolve_document(document)
45
- return document unless document.view_imports&.any?
46
-
47
- base_path = @input.is_a?(StringIO) ? nil : @input.path
48
- entities, associations = ImportResolver.new(base_path).resolve(document)
49
- entities, associations = ViewResolver.new.resolve(document, entities, associations)
50
- rebuild_document(document, entities, associations)
51
- end
52
-
53
- def rebuild_document(document, entities, associations)
54
- grouped = entities.group_by { |e| e.class.entity_type }
55
-
56
- document.classes = grouped[:classes] || []
57
- document.enums = grouped[:enums] || []
58
- document.data_types = grouped[:data_types] || []
59
- document.associations = associations
60
- document
61
- end
62
41
  end
63
42
  end
64
43
  end
@@ -6,7 +6,7 @@ module Lutaml
6
6
  attr_reader :input_file
7
7
 
8
8
  def initialize(input_file)
9
- @input_file = input_file
9
+ @input_file = Source.wrap(input_file)
10
10
  end
11
11
 
12
12
  class << self
@@ -16,37 +16,42 @@ module Lutaml
16
16
  end
17
17
 
18
18
  def call
19
- input_file.rewind
20
- include_root = input_file.is_a?(StringIO) ? Dir.pwd : File.dirname(input_file.path)
21
- input_file.read.split("\n").reduce([]) do |res, line|
22
- res.push(*process_dsl_line(include_root, line))
23
- end.join("\n")
19
+ expand_lines(@input_file.read, @input_file.base_dir, [])
24
20
  end
25
21
 
26
22
  private
27
23
 
28
- def process_dsl_line(include_root, line)
29
- process_include_line(include_root, process_comment_line(line))
24
+ def expand_lines(text, base_dir, chain)
25
+ text.split(/\r?\n/)
26
+ .flat_map { |line| expand_line(line, base_dir, chain) }
27
+ .join("\n")
30
28
  end
31
29
 
32
- def process_comment_line(line)
33
- has_comment = line.match(%r{//.*})
34
- return line if has_comment.nil?
30
+ def expand_line(line, base_dir, chain)
31
+ cleaned = strip_comment(line)
32
+ path = include_path(cleaned, base_dir)
33
+ return [cleaned] unless path
35
34
 
36
- line.gsub(%r{//.*}, "")
35
+ raise Error, "circular include detected: #{path}" if chain.include?(path)
36
+
37
+ expand_lines(read_included(path), File.dirname(path), chain + [path])
37
38
  end
38
39
 
39
- def process_include_line(include_root, line)
40
- include_path_match = line.match(/^\s*include\s+(.+)/)
41
- return line if include_path_match.nil?
40
+ def include_path(line, base_dir)
41
+ match = line.match(/^\s*include\s+(.+)/)
42
+ return nil unless match
42
43
 
43
- path_to_file = File.expand_path(include_path_match[1].strip, include_root)
44
- File.read(path_to_file).split("\n").map do |l|
45
- process_comment_line(l)
46
- end
44
+ File.expand_path(match[1].strip, base_dir)
45
+ end
46
+
47
+ def read_included(path)
48
+ File.read(path)
47
49
  rescue Errno::ENOENT, Errno::EACCES => e
48
- warn "Skipping #{path_to_file}: #{e.message}"
49
- []
50
+ raise Error, "cannot read include #{path}: #{e.message}"
51
+ end
52
+
53
+ def strip_comment(line)
54
+ line.sub(%r{//.*}, "")
50
55
  end
51
56
  end
52
57
  end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'delegate'
4
+
5
+ module Lutaml
6
+ module Lml
7
+ # Normalizes pipeline input (String, StringIO, File, Tempfile) behind
8
+ # one interface: full text, filesystem path (or nil), and the
9
+ # directory imports/includes resolve against.
10
+ class Source
11
+ attr_reader :input
12
+
13
+ def self.wrap(input)
14
+ input.is_a?(Source) ? input : new(input)
15
+ end
16
+
17
+ def initialize(input)
18
+ @input = input
19
+ end
20
+
21
+ def read
22
+ return @input if @input.is_a?(String)
23
+
24
+ @input.rewind
25
+ @input.read
26
+ end
27
+
28
+ # Filesystem path, or nil for anonymous input (String/StringIO).
29
+ def path
30
+ io = unwrapped
31
+ io.is_a?(File) ? io.path : nil
32
+ end
33
+
34
+ def base_dir
35
+ path ? File.dirname(path) : Dir.pwd
36
+ end
37
+
38
+ private
39
+
40
+ # Tempfile delegates to File (it is not a File subclass on
41
+ # Ruby >= 3.4), so unwrap before type checks.
42
+ def unwrapped
43
+ io = @input
44
+ io = io.__getobj__ while io.is_a?(Delegator)
45
+ io
46
+ end
47
+ end
48
+ end
49
+ end
@@ -14,7 +14,11 @@ module Lutaml
14
14
  rule(visibility_modifier: simple(:visibility_value)) do
15
15
  VISIBILITY_MAP.fetch(visibility_value.to_s, 'public')
16
16
  end
17
- rule(simple(:member)) { member.nil? ? member : member.to_s.strip }
17
+ # Global scalar normalizer: Parslet applies this to every leaf in
18
+ # the parse tree (names may legally contain trailing spaces via
19
+ # class_name_chars). Binding is named :value to make the breadth
20
+ # explicit — it is not tied to any one grammar rule.
21
+ rule(simple(:value)) { value.nil? ? value : value.to_s.strip }
18
22
  end
19
23
  end
20
24
  end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'lutaml/model'
4
+
5
+ module Lutaml
6
+ module Lml
7
+ module Types
8
+ # LML `definition` body text. The grammar allows literal braces to
9
+ # be escaped (\{ \}) so they do not close the definition block;
10
+ # casting unescapes them and normalizes line indentation. One
11
+ # implementation shared by every attribute declared with this
12
+ # type — no per-model (de)serialization procs.
13
+ class TextType < Lutaml::Model::Type::String
14
+ def self.cast(value, options = {})
15
+ text = super
16
+ return nil if text.nil?
17
+ return text if Lutaml::Model::Utils.uninitialized?(text)
18
+
19
+ text.gsub(/\\}/, '}')
20
+ .gsub(/\\{/, '{')
21
+ .split("\n")
22
+ .map(&:strip)
23
+ .join("\n")
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Custom lutaml-model types shared by LML models.
4
+ module Lutaml
5
+ module Lml
6
+ module Types
7
+ autoload :TextType, 'lutaml/lml/types/text_type'
8
+ end
9
+ end
10
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Lutaml
4
4
  module Lml
5
- VERSION = "0.1.2"
5
+ VERSION = "0.1.3"
6
6
  end
7
7
  end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lutaml
4
+ module Lml
5
+ # Post-parse step: expand view imports, apply show/hide filters,
6
+ # rebuild the document's entity collections, and enrich association
7
+ # labels. Import expansion runs only when the document declares
8
+ # view imports; label enrichment always runs.
9
+ class ViewResolution
10
+ def self.call(document, base_dir)
11
+ document = resolve_imports(document, base_dir) if document.view_imports.any?
12
+ AssociationLabelResolver.new.enrich(document)
13
+ end
14
+
15
+ def self.resolve_imports(document, base_dir)
16
+ entity_index, associations = ImportResolver.new(base_dir).resolve(document)
17
+ entities, associations = ViewResolver.new.resolve(document, entity_index, associations)
18
+ rebuild_document(document, entities, associations)
19
+ end
20
+
21
+ def self.rebuild_document(document, entities, associations)
22
+ grouped = entities.group_by { |e| e.class.entity_type }
23
+
24
+ EntityTypes.symbols.each do |symbol|
25
+ document.public_send("#{symbol}=", grouped[symbol] || [])
26
+ end
27
+ document.associations = associations
28
+ document
29
+ end
30
+ end
31
+ end
32
+ end
@@ -3,8 +3,9 @@
3
3
  module Lutaml
4
4
  module Lml
5
5
  class ViewResolver
6
- def resolve(document, entities, associations)
7
- visible = apply_filters(document, entities)
6
+ # entity_index is the ImportResolver's name → entity map.
7
+ def resolve(document, entity_index, associations)
8
+ visible = apply_filters(document, entity_index)
8
9
  filtered_associations = filter_associations(associations, visible)
9
10
 
10
11
  [visible, filtered_associations]
@@ -12,9 +13,8 @@ module Lutaml
12
13
 
13
14
  private
14
15
 
15
- def apply_filters(document, entities)
16
- names = entities.each_with_object({}) { |e, h| h[e.name] = e }
17
-
16
+ def apply_filters(document, entity_index)
17
+ names = entity_index.reject { |name, _| name.nil? }
18
18
  names = apply_show_filter(names, document.show_filter)
19
19
  names = apply_hide_filter(names, document.hide_filter)
20
20
 
data/lib/lutaml/lml.rb CHANGED
@@ -14,21 +14,38 @@ module Lutaml
14
14
  module Lml
15
15
  class Error < Lutaml::Error; end
16
16
  class ParsingError < Error; end
17
+ class ImportError < Error; end
17
18
 
18
19
  def self.compile(input, namespace: nil)
19
20
  ModelCompiler.new(namespace: namespace).compile(input)
20
21
  end
21
22
 
23
+ # Full entry point: parse, then resolve view imports and enrich
24
+ # association labels.
25
+ def self.parse(input)
26
+ source = Source.wrap(input)
27
+ document = Pipeline.call(source)
28
+ ViewResolution.call(document, source.base_dir)
29
+ end
30
+
31
+ # Parse only — no import resolution, no label enrichment.
32
+ def self.parse_document(input)
33
+ Pipeline.call(input)
34
+ end
35
+
22
36
  # Top-level autoloads
23
37
  autoload :Parser, "lutaml/lml/parser"
24
38
  autoload :Pipeline, "lutaml/lml/pipeline"
25
39
  autoload :Preprocessor, "lutaml/lml/preprocessor"
40
+ autoload :Source, "lutaml/lml/source"
26
41
  autoload :Transform, "lutaml/lml/transform"
27
42
  autoload :DataProcessor, "lutaml/lml/data_processor"
28
43
  autoload :DocumentBuilder, "lutaml/lml/document_builder"
29
44
  autoload :ModelCompiler, "lutaml/lml/model_compiler"
30
45
  autoload :ImportResolver, "lutaml/lml/import_resolver"
31
46
  autoload :ViewResolver, "lutaml/lml/view_resolver"
47
+ autoload :ViewResolution, "lutaml/lml/view_resolution"
48
+ autoload :EntityTypes, "lutaml/lml/entity_types"
32
49
  autoload :AssociationLabelResolver, "lutaml/lml/association_label_resolver"
33
50
  autoload :Executor, "lutaml/lml/executor"
34
51
  autoload :YamlParser, "lutaml/lml/yaml_parser"
@@ -64,5 +81,6 @@ module Lutaml
64
81
  # Namespaces with their own autoloads
65
82
  autoload :Grammar, "lutaml/lml/grammar"
66
83
  autoload :Format, "lutaml/lml/format"
84
+ autoload :Types, "lutaml/lml/types"
67
85
  end
68
86
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lutaml-lml
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-08-18 00:00:00.000000000 Z
11
+ date: 2026-08-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: lutaml-model
@@ -87,6 +87,7 @@ files:
87
87
  - lib/lutaml/lml/data_processor/value_processing.rb
88
88
  - lib/lutaml/lml/data_processor/view_processing.rb
89
89
  - lib/lutaml/lml/document_builder.rb
90
+ - lib/lutaml/lml/entity_types.rb
90
91
  - lib/lutaml/lml/executor.rb
91
92
  - lib/lutaml/lml/executor/adapter_helpers.rb
92
93
  - lib/lutaml/lml/executor/condition_evaluator.rb
@@ -150,8 +151,12 @@ files:
150
151
  - lib/lutaml/lml/parser.rb
151
152
  - lib/lutaml/lml/pipeline.rb
152
153
  - lib/lutaml/lml/preprocessor.rb
154
+ - lib/lutaml/lml/source.rb
153
155
  - lib/lutaml/lml/transform.rb
156
+ - lib/lutaml/lml/types.rb
157
+ - lib/lutaml/lml/types/text_type.rb
154
158
  - lib/lutaml/lml/version.rb
159
+ - lib/lutaml/lml/view_resolution.rb
155
160
  - lib/lutaml/lml/view_resolver.rb
156
161
  - lib/lutaml/lml/yaml_parser.rb
157
162
  homepage: https://github.com/lutaml/lutaml-lml