diver_down 0.0.1.alpha13 → 0.0.1.alpha15

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.
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DiverDown
4
+ class Web
5
+ class DefinitionModuleDependencies
6
+ class ModuleDependency
7
+ attr_accessor :module
8
+ attr_reader :module_dependencies, :module_reverse_dependencies, :source_map, :source_reverse_dependency_map
9
+
10
+ def initialize(modulee)
11
+ @module = modulee
12
+ @module_dependencies = Set.new
13
+ @module_reverse_dependencies = Set.new
14
+ @source_map = {}
15
+ @source_reverse_dependency_map = {}
16
+ end
17
+
18
+ # @return [Array<Source>]
19
+ def sources
20
+ @source_map.keys.sort.map { @source_map.fetch(_1) }
21
+ end
22
+
23
+ # @return [Array<Source>]
24
+ def source_reverse_dependencies
25
+ @source_reverse_dependency_map.keys.sort.map { @source_reverse_dependency_map.fetch(_1) }
26
+ end
27
+ end
28
+
29
+ def initialize(metadata, definition)
30
+ @metadata = metadata
31
+ @definition = definition
32
+ end
33
+
34
+ # @return [Hash{ String => Hash{ String => Array<DiverDown::Definition::Source> } }]
35
+ def build_module_dependency_map
36
+ module_dependency_map = Hash.new { |h, k| h[k] = ModuleDependency.new(k) }
37
+
38
+ @definition.sources.each do |source|
39
+ source_module = @metadata.source(source.source_name).module
40
+ next if source_module.nil?
41
+
42
+ source_module_dependency = module_dependency_map[source_module]
43
+ source_module_dependency.source_map[source.source_name] ||= DiverDown::Definition::Source.new(source_name: source.source_name)
44
+
45
+ source.dependencies.each do |dependency|
46
+ dependency_module = @metadata.source(dependency.source_name).module
47
+
48
+ next if source_module == dependency_module
49
+ next if dependency_module.nil?
50
+
51
+ dependency_module_dependency = module_dependency_map[dependency_module]
52
+
53
+ # Add module dependencies
54
+ source_module_dependency.module_dependencies.add(dependency_module)
55
+
56
+ # Add module reverse dependencies
57
+ dependency_module_dependency.module_reverse_dependencies.add(source_module)
58
+
59
+ # Add source
60
+ definition_source = source_module_dependency.source_map[source.source_name]
61
+ definition_dependency = definition_source.find_or_build_dependency(dependency.source_name)
62
+ dependency.method_ids.each do |method_id|
63
+ definition_dependency.find_or_build_method_id(name: method_id.name, context: method_id.context).add_path(*method_id.paths)
64
+ end
65
+
66
+ # Add source reverse dependencies
67
+ definition_source = dependency_module_dependency.source_reverse_dependency_map[dependency.source_name] ||= DiverDown::Definition::Source.new(source_name: dependency.source_name)
68
+ definition_dependency = definition_source.find_or_build_dependency(source.source_name)
69
+ dependency.method_ids.each do |method_id|
70
+ definition_dependency.find_or_build_method_id(name: method_id.name, context: method_id.context).add_path(*method_id.paths)
71
+ end
72
+ end
73
+ end
74
+
75
+ module_dependency_map
76
+ end
77
+ end
78
+ end
79
+ end
@@ -5,12 +5,11 @@ module DiverDown
5
5
  class DefinitionStore
6
6
  include Enumerable
7
7
 
8
- attr_reader :bit_id
9
-
10
8
  def initialize
11
9
  # Hash{ Integer(unique bit flag) => DiverDown::Definition }
12
10
  @definitions = []
13
11
  @definition_group_store = Hash.new { |h, k| h[k] = [] }
12
+ @combined_definition = nil
14
13
  end
15
14
 
16
15
  # @param id [Integer]
@@ -31,14 +30,33 @@ module DiverDown
31
30
  raise(ArgumentError, 'definition already set') if _1.store_id
32
31
 
33
32
  _1.store_id = @definitions.size + 1
33
+ _1.freeze
34
34
 
35
35
  @definitions.push(_1)
36
36
  @definition_group_store[_1.definition_group] << _1
37
37
 
38
+ # Reset combined_definition
39
+ @combined_definition = nil
40
+
38
41
  _1.store_id
39
42
  end
40
43
  end
41
44
 
45
+ # @return [DiverDown::Definition]
46
+ def combined_definition
47
+ if @combined_definition.nil?
48
+ @combined_definition = DiverDown::Definition.combine(
49
+ definition_group: nil,
50
+ title: 'All Definitions',
51
+ definitions: @definitions
52
+ )
53
+
54
+ @combined_definition.freeze
55
+ end
56
+
57
+ @combined_definition
58
+ end
59
+
42
60
  # @return [Array<String, nil>]
43
61
  def definition_groups
44
62
  keys = @definition_group_store.keys
@@ -7,13 +7,12 @@ module DiverDown
7
7
  class Web
8
8
  class DefinitionToDot
9
9
  ATTRIBUTE_DELIMITER = ' '
10
- MODULE_DELIMITER = '::'
11
10
 
12
11
  # Between modules is prominently distanced
13
12
  MODULE_MINLEN = 3
14
13
 
15
- class MetadataStore
16
- Metadata = Data.define(:id, :type, :data, :module_store) do
14
+ class DotMetadataStore
15
+ DotMetadata = Data.define(:id, :type, :data, :metadata) do
17
16
  # @return [Hash]
18
17
  def to_h
19
18
  case type
@@ -31,18 +30,12 @@ module DiverDown
31
30
  private
32
31
 
33
32
  def source_to_h
34
- modules = module_store.get_modules(data.source_name).map do
35
- {
36
- module_name: _1,
37
- }
38
- end
39
-
40
33
  {
41
34
  id:,
42
35
  type: 'source',
43
36
  source_name: data.source_name,
44
- memo: module_store.get_memo(data.source_name),
45
- modules:,
37
+ memo: metadata.source(data.source_name).memo,
38
+ module: metadata.source(data.source_name).module,
46
39
  }
47
40
  end
48
41
 
@@ -68,20 +61,16 @@ module DiverDown
68
61
  {
69
62
  id:,
70
63
  type: 'module',
71
- modules: data.map do
72
- {
73
- module_name: _1,
74
- }
75
- end,
64
+ module: data,
76
65
  }
77
66
  end
78
67
  end
79
68
 
80
- def initialize(module_store)
69
+ def initialize(metadata)
81
70
  @prefix = 'graph_'
82
- @module_store = module_store
71
+ @metadata = metadata
83
72
 
84
- # Hash{ id => Metadata }
73
+ # Hash{ id => DotMetadata }
85
74
  @to_h = {}
86
75
  end
87
76
 
@@ -89,34 +78,34 @@ module DiverDown
89
78
  # @param record [DiverDown::Definition::Source]
90
79
  # @return [String]
91
80
  def issue_source_id(source)
92
- build_metadata_and_return_id(:source, source)
81
+ build_dot_metadata_and_return_id(:source, source)
93
82
  end
94
83
 
95
84
  # @param dependency [DiverDown::Definition::Dependency]
96
85
  # @return [String]
97
86
  def issue_dependency_id(dependency)
98
- build_metadata_and_return_id(:dependency, [dependency])
87
+ build_dot_metadata_and_return_id(:dependency, [dependency])
99
88
  end
100
89
 
101
90
  # @param module_names [Array<String>]
102
91
  # @return [String]
103
- def issue_modules_id(module_names)
104
- issued_metadata = @to_h.values.find { _1.type == :module && _1.data == module_names }
92
+ def issue_module_id(modulee)
93
+ issued_metadata = @to_h.values.find { _1.type == :module && _1.data == modulee }
105
94
 
106
95
  if issued_metadata
107
96
  issued_metadata.id
108
97
  else
109
- build_metadata_and_return_id(:module, module_names)
98
+ build_dot_metadata_and_return_id(:module, modulee)
110
99
  end
111
100
  end
112
101
 
113
102
  # @param id [String]
114
103
  # @param dependency [DiverDown::Definition::Dependency]
115
104
  def append_dependency(id, dependency)
116
- metadata = @to_h.fetch(id)
117
- dependencies = metadata.data
105
+ dot_metadata = @to_h.fetch(id)
106
+ dependencies = dot_metadata.data
118
107
  combined_dependencies = DiverDown::Definition::Dependency.combine(*dependencies, dependency)
119
- metadata.data.replace(combined_dependencies)
108
+ dot_metadata.data.replace(combined_dependencies)
120
109
  end
121
110
 
122
111
  # @return [Array<Hash>]
@@ -126,10 +115,10 @@ module DiverDown
126
115
 
127
116
  private
128
117
 
129
- def build_metadata_and_return_id(type, data)
118
+ def build_dot_metadata_and_return_id(type, data)
130
119
  id = "#{@prefix}#{length + 1}"
131
- metadata = Metadata.new(id:, type:, data:, module_store: @module_store)
132
- @to_h[id] = metadata
120
+ dot_metadata = DotMetadata.new(id:, type:, data:, metadata: @metadata)
121
+ @to_h[id] = dot_metadata
133
122
 
134
123
  id
135
124
  end
@@ -140,24 +129,24 @@ module DiverDown
140
129
  end
141
130
 
142
131
  # @param definition [DiverDown::Definition]
143
- # @param module_store [DiverDown::ModuleStore]
132
+ # @param metadata [DiverDown::Web::Metadata]
144
133
  # @param compound [Boolean]
145
134
  # @param concentrate [Boolean] https://graphviz.org/docs/attrs/concentrate/
146
- def initialize(definition, module_store, compound: false, concentrate: false, only_module: false)
135
+ def initialize(definition, metadata, compound: false, concentrate: false, only_module: false)
147
136
  @definition = definition
148
- @module_store = module_store
137
+ @metadata = metadata
149
138
  @io = DiverDown::Web::IndentedStringIo.new
150
139
  @indent = 0
151
140
  @compound = compound || only_module # When only-module is enabled, dependencies between modules are displayed as compound.
152
141
  @compound_map = Hash.new { |h, k| h[k] = {} } # Hash{ ltail => Hash{ lhead => issued id } }
153
142
  @concentrate = concentrate
154
143
  @only_module = only_module
155
- @metadata_store = MetadataStore.new(module_store)
144
+ @dot_metadata_store = DotMetadataStore.new(metadata)
156
145
  end
157
146
 
158
147
  # @return [Array<Hash>]
159
- def metadata
160
- @metadata_store.to_a
148
+ def dot_metadata
149
+ @dot_metadata_store.to_a
161
150
  end
162
151
 
163
152
  # @return [String]
@@ -179,77 +168,62 @@ module DiverDown
179
168
 
180
169
  private
181
170
 
182
- attr_reader :definition, :module_store, :io
171
+ attr_reader :definition, :metadata, :io
183
172
 
184
173
  def render_only_modules
185
174
  # Hash{ from_module => { to_module => Array<DiverDown::Definition::Dependency> } }
186
175
  dependency_map = Hash.new { |h, k| h[k] = Hash.new { |hi, ki| hi[ki] = [] } }
187
176
 
188
177
  definition.sources.sort_by(&:source_name).each do |source|
189
- source_modules = module_store.get_modules(source.source_name)
190
- next if source_modules.empty?
178
+ source_module = metadata.source(source.source_name).module
179
+ next if source_module.nil?
191
180
 
192
181
  source.dependencies.each do |dependency|
193
- dependency_modules = module_store.get_modules(dependency.source_name)
194
- next if dependency_modules.empty?
182
+ dependency_module = metadata.source(dependency.source_name).module
183
+ next if dependency_module.nil?
195
184
 
196
- dependency_map[source_modules][dependency_modules].push(dependency)
185
+ dependency_map[source_module][dependency_module].push(dependency)
197
186
  end
198
187
  end
199
188
 
200
189
  # Remove duplicated prefix modules
201
- # from [["A"], ["A", "B"]] to [["A", "B"]]
202
- uniq_modules = [*dependency_map.keys, *dependency_map.values.map(&:keys).flatten(1)].uniq
203
- uniq_modules.reject! do |modules|
204
- modules.empty? ||
205
- uniq_modules.any? { _1[0..modules.size - 1] == modules && _1.length > modules.size }
206
- end
207
-
208
- uniq_modules.each do |specific_module_names|
209
- buf = swap_io do
210
- indexes = (0..(specific_module_names.length - 1)).to_a
211
-
212
- chain_yield(indexes) do |index, next_proc|
213
- module_names = specific_module_names[0..index]
214
- module_name = specific_module_names[index]
215
-
216
- io.puts %(subgraph "#{escape_quote(module_label(module_names))}" {)
217
- io.indented do
218
- io.puts %(id="#{@metadata_store.issue_modules_id(module_names)}")
219
- io.puts %(label="#{escape_quote(module_name)}")
220
- io.puts %("#{escape_quote(module_name)}" #{build_attributes(label: module_name, id: @metadata_store.issue_modules_id(module_names))})
221
-
222
- next_proc&.call
223
- end
224
- io.puts '}'
225
- end
190
+ uniq_modules = [*dependency_map.keys, *dependency_map.values.map(&:keys).flatten].uniq.sort
191
+ uniq_modules.reject!(&:nil?)
192
+
193
+ uniq_modules.each do |modulee|
194
+ io.puts %(subgraph "#{escape_quote(module_label(modulee))}" {)
195
+ io.indented do
196
+ io.puts %(id="#{@dot_metadata_store.issue_module_id(modulee)}")
197
+ io.puts %(label="#{escape_quote(modulee)}")
198
+ io.puts %("#{escape_quote(modulee)}" #{build_attributes(label: modulee, id: @dot_metadata_store.issue_module_id(modulee))})
226
199
  end
227
-
228
- io.write buf.string
200
+ io.puts '}'
229
201
  end
230
202
 
231
- dependency_map.each do |from_modules, h|
232
- h.each do |to_modules, all_dependencies|
203
+ dependency_map.keys.sort_by(&:to_s).each do |from_module|
204
+ dependency_map.fetch(from_module).keys.sort_by(&:to_s).each do |to_module|
205
+ all_dependencies = dependency_map.fetch(from_module).fetch(to_module)
206
+
233
207
  # Do not render standalone source
234
208
  # Do not render self-dependency
235
- next if from_modules.empty? || to_modules.empty? || from_modules == to_modules
209
+ next if from_module.nil? || to_module.empty? || from_module == to_module
236
210
 
237
211
  dependencies = DiverDown::Definition::Dependency.combine(*all_dependencies)
238
212
 
239
213
  dependencies.each do
240
214
  attributes = {}
241
- ltail = module_label(*from_modules)
242
- lhead = module_label(*to_modules)
215
+ ltail = module_label(from_module)
216
+ lhead = module_label(to_module)
243
217
 
244
218
  # Already rendered dependencies between modules
245
219
  # Add the dependency to the edge of the compound
246
220
  if @compound_map[ltail].include?(lhead)
247
221
  compound_id = @compound_map[ltail][lhead]
248
- @metadata_store.append_dependency(compound_id, _1)
222
+ @dot_metadata_store.append_dependency(compound_id, _1)
249
223
  next
250
224
  end
251
225
 
252
- compound_id = @metadata_store.issue_dependency_id(_1)
226
+ compound_id = @dot_metadata_store.issue_dependency_id(_1)
253
227
  @compound_map[ltail][lhead] = compound_id
254
228
 
255
229
  attributes.merge!(
@@ -259,7 +233,7 @@ module DiverDown
259
233
  minlen: MODULE_MINLEN
260
234
  )
261
235
 
262
- io.write(%("#{escape_quote(from_modules[-1])}" -> "#{escape_quote(to_modules[-1])}"))
236
+ io.write(%("#{escape_quote(from_module)}" -> "#{escape_quote(to_module)}"))
263
237
  io.write(%( #{build_attributes(**attributes)}), indent: false) unless attributes.empty?
264
238
  io.write("\n")
265
239
  end
@@ -268,67 +242,49 @@ module DiverDown
268
242
  end
269
243
 
270
244
  def render_sources
271
- by_modules = definition.sources.group_by do |source|
272
- module_store.get_modules(source.source_name)
273
- end
274
-
275
- # Remove duplicated prefix modules
276
- # from [["A"], ["A", "B"]] to [["A", "B"]]
277
- uniq_modules = by_modules.keys.uniq
278
- uniq_modules = uniq_modules.reject do |modules|
279
- uniq_modules.any? { _1[0..modules.size - 1] == modules && _1.length > modules.size }
245
+ # Hash{ module => sources }
246
+ # Hash{ String => Array<DiverDown::Definition::Source> }
247
+ by_module = definition.sources.group_by do |source|
248
+ metadata.source(source.source_name).module
280
249
  end
281
250
 
282
- uniq_modules.each do |full_modules|
283
- # Render module and source
284
- if full_modules.empty?
285
- sources = by_modules[full_modules].sort_by(&:source_name)
251
+ # Render subgraph for each module and its sources second
252
+ by_module.keys.sort_by(&:to_s).each do |modulee|
253
+ sources = by_module.fetch(modulee).sort_by(&:source_name)
286
254
 
255
+ if modulee.nil?
287
256
  sources.each do |source|
288
- insert_source(source)
257
+ io.puts build_source_node(source)
289
258
  end
290
259
  else
291
- buf = swap_io do
292
- indexes = (0..(full_modules.length - 1)).to_a
293
-
294
- chain_yield(indexes) do |index, next_proc|
295
- module_names = full_modules[0..index]
296
- module_name = module_names[-1]
297
-
298
- io.puts %(subgraph "#{escape_quote(module_label(module_names))}" {)
299
- io.indented do
300
- io.puts %(id="#{@metadata_store.issue_modules_id(module_names)}")
301
- io.puts %(label="#{escape_quote(module_name)}")
302
-
303
- sources = (by_modules[module_names] || []).sort_by(&:source_name)
304
- sources.each do |source|
305
- insert_source(source)
306
- end
307
-
308
- next_proc&.call
309
- end
310
- io.puts '}'
260
+ io.puts %(subgraph "#{escape_quote(module_label(modulee))}" {)
261
+ io.indented do
262
+ io.puts %(id="#{@dot_metadata_store.issue_module_id(modulee)}")
263
+ io.puts %(label="#{escape_quote(modulee)}")
264
+
265
+ sources.each do |source|
266
+ io.puts build_source_node(source)
311
267
  end
312
268
  end
313
-
314
- io.write buf.string
269
+ io.puts '}'
315
270
  end
316
271
  end
317
272
 
273
+ # Render dependencies last
318
274
  definition.sources.sort_by(&:source_name).each do |source|
319
275
  insert_dependencies(source)
320
276
  end
321
277
  end
322
278
 
323
- def insert_source(source)
324
- io.puts %("#{escape_quote(source.source_name)}" #{build_attributes(label: source.source_name, id: @metadata_store.issue_source_id(source))})
279
+ def build_source_node(source)
280
+ %("#{escape_quote(source.source_name)}" #{build_attributes(label: source.source_name, id: @dot_metadata_store.issue_source_id(source))})
325
281
  end
326
282
 
327
283
  def insert_dependencies(source)
328
284
  source.dependencies.each do
329
285
  attributes = {}
330
- ltail = module_label(*module_store.get_modules(source.source_name))
331
- lhead = module_label(*module_store.get_modules(_1.source_name))
286
+ ltail = module_label(metadata.source(source.source_name).module)
287
+ lhead = module_label(metadata.source(_1.source_name).module)
332
288
 
333
289
  if @compound && (ltail || lhead)
334
290
  # Rendering of dependencies between modules is done only once
@@ -338,11 +294,11 @@ module DiverDown
338
294
  # Add the dependency to the edge of the compound
339
295
  if between_modules && @compound_map[ltail].include?(lhead)
340
296
  compound_id = @compound_map[ltail][lhead]
341
- @metadata_store.append_dependency(compound_id, _1)
297
+ @dot_metadata_store.append_dependency(compound_id, _1)
342
298
  next
343
299
  end
344
300
 
345
- compound_id = @metadata_store.issue_dependency_id(_1)
301
+ compound_id = @dot_metadata_store.issue_dependency_id(_1)
346
302
  @compound_map[ltail][lhead] = compound_id
347
303
 
348
304
  attributes.merge!(
@@ -353,7 +309,8 @@ module DiverDown
353
309
  )
354
310
  else
355
311
  attributes.merge!(
356
- id: @metadata_store.issue_dependency_id(_1)
312
+ id: @dot_metadata_store.issue_dependency_id(_1),
313
+ minlen: MODULE_MINLEN
357
314
  )
358
315
  end
359
316
 
@@ -411,10 +368,10 @@ module DiverDown
411
368
  @io = old_io
412
369
  end
413
370
 
414
- def module_label(*modules)
415
- return if modules.empty?
371
+ def module_label(modulee)
372
+ return if modulee.nil?
416
373
 
417
- "cluster_#{modules.join(MODULE_DELIMITER)}"
374
+ "cluster_#{modulee}"
418
375
  end
419
376
 
420
377
  def escape_quote(string)
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DiverDown
4
+ class Web
5
+ class Metadata
6
+ class SourceAlias
7
+ class ConflictError < StandardError
8
+ attr_reader :source_name
9
+
10
+ def initialize(message, source_name:)
11
+ @source_name = source_name
12
+
13
+ super(message)
14
+ end
15
+ end
16
+
17
+ BLANK_RE = /\A\s*\z/
18
+
19
+ def initialize
20
+ # Hash{ alias_name => Set<source_name, ...> }
21
+ @alias_to_source_names = {}
22
+ @source_name_to_alias = {}
23
+ end
24
+
25
+ # @param alias_name [String]
26
+ # @param source_names [Array<String>]
27
+ # @return [void]
28
+ def update_alias(alias_name, source_names)
29
+ source_names = source_names.reject { BLANK_RE.match?(_1) }
30
+
31
+ if source_names.empty?
32
+ prev_source_names = @alias_to_source_names.delete(alias_name)
33
+ prev_source_names&.each do |prev_source_name|
34
+ @source_name_to_alias.delete(prev_source_name)
35
+ end
36
+ else
37
+ check_conflict(alias_name, source_names)
38
+ @alias_to_source_names[alias_name] = source_names.sort
39
+
40
+ source_names.each do |source_name|
41
+ @source_name_to_alias[source_name] = alias_name
42
+ end
43
+ end
44
+ end
45
+
46
+ # @param alias_name [String]
47
+ # @return [String]
48
+ def resolve_alias(source_name)
49
+ @source_name_to_alias[source_name] if @source_name_to_alias.key?(source_name)
50
+ end
51
+
52
+ # @param alias_name [String]
53
+ # @return [Array<String>]
54
+ def aliased_source_names(alias_name)
55
+ @alias_to_source_names[alias_name] if @alias_to_source_names.key?(alias_name)
56
+ end
57
+
58
+ # Rollback the changes made in the block if an conflict error occurs.
59
+ #
60
+ # @raise [ConflictError]
61
+ def transaction
62
+ alias_to_source_names = deep_dup(@alias_to_source_names)
63
+ source_name_to_alias = deep_dup(@source_name_to_alias)
64
+
65
+ yield
66
+ rescue ConflictError
67
+ @alias_to_source_names = alias_to_source_names
68
+ @source_name_to_alias = source_name_to_alias
69
+
70
+ raise
71
+ end
72
+
73
+ # @return [Hash]
74
+ def to_h
75
+ keys = @alias_to_source_names.keys.sort
76
+ keys.to_h { [_1, aliased_source_names(_1)] }
77
+ end
78
+
79
+ private
80
+
81
+ def deep_dup(hash)
82
+ hash.transform_values do
83
+ if _1.is_a?(Hash)
84
+ deep_dup(_1)
85
+ else
86
+ _1.dup
87
+ end
88
+ end
89
+ end
90
+
91
+ def added_source_names(excluding_alias_name)
92
+ source_names = Set.new
93
+
94
+ @alias_to_source_names.each_key do |name|
95
+ next if excluding_alias_name == name
96
+
97
+ source_names.add(name)
98
+
99
+ @alias_to_source_names[name].each do |source_name|
100
+ source_names.add(source_name)
101
+ end
102
+ end
103
+
104
+ source_names
105
+ end
106
+
107
+ def check_conflict(alias_name, source_names)
108
+ if source_names.any? { _1 == alias_name }
109
+ raise(ConflictError.new("Cannot create an alias for '#{alias_name}' that refers to itself.", source_name: alias_name))
110
+ end
111
+
112
+ registered_source_names = added_source_names(alias_name)
113
+
114
+ if registered_source_names.include?(alias_name)
115
+ raise ConflictError.new("Alias '#{alias_name}' is already aliased.", source_name: alias_name)
116
+ end
117
+
118
+ conflicted_source_name = source_names.find { registered_source_names.include?(_1) }
119
+
120
+ if conflicted_source_name
121
+ resolved_source_name = resolve_alias(conflicted_source_name)
122
+ raise ConflictError.new("Source '#{conflicted_source_name}' is already aliased to '#{resolved_source_name}'.", source_name: conflicted_source_name)
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end