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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3cb1048dc3dd78965342bb1747ddbf2cc0c84c7c62dbb73fe22a719e64844ffd
4
- data.tar.gz: f1137e211bebc58a87a2624916bca7db8d9e2eb29c67bdd6c554b8b3d306f1cd
3
+ metadata.gz: 4365e60094816d3b24ee259f50cdd2c58ffd60bf85297fa3d5f589932bda2d27
4
+ data.tar.gz: 315471dc4a1f220478bc5c26a96252ed3f97a06f1cda8604a2d0bb55de7f5c89
5
5
  SHA512:
6
- metadata.gz: d90b43e78ed7971c7404d703c0ba7c5965b71cf463ca94fd3a5809a0f0070fd3f8771b5f3f38d5a1ca368e5b5a4381b1a3377b5f3e421d81ac9c550c2066e703
7
- data.tar.gz: 520e8c6e07d5c6f9815f8a71a5f7ce1b08796c358d6792f4952b7c80b636264fcbf28b3d0cf579ecfc7ed4586292f8b0216ff5fff5415b6100281c218eb31a40
6
+ metadata.gz: b068eaf0ceb7cb58284e0f6406326e345d466950ca9474ec2e49b15175d5b7676bee0b7548321b1b6c3adb3b4aa6c0ea9e26f84301dac1349973722b814f831d
7
+ data.tar.gz: a81235611395d6b0702c07da2bea5a862b0a19e76e9ab0b191d9a7b2f314f32596a1ec76618cbcfa2ac8c2cfe5a7367fc31e0c0fd75867a4889cba28d283fed4
data/README.md CHANGED
@@ -121,10 +121,10 @@ View the analysis results in a browser.
121
121
  This gem is specifically designed to analyze large applications with a modular monolithic architecture. It allows users to categorize each analyzed file into specified modules directly through the web interface.
122
122
 
123
123
  - `--definition-dir` Specifies the directory where the analysis results are stored.
124
- - `--module-store-path` Designates a path to save the results that include details on which module each file belongs to. If this option is not specified, the results will be temporarily stored in a default temporary file.
124
+ - `--metadata` Designates a path to save the results that include details on which module each file belongs to. If this option is not specified, the results will be temporarily stored in a default temporary file.
125
125
 
126
126
  ```sh
127
- bundle exec diver_down_web --definition-dir tmp/diver_down --module-store-path tmp/module_store.yml
127
+ bundle exec diver_down_web --definition-dir tmp/diver_down --metadata tmp/metadata.yml
128
128
  open http://localhost:8080
129
129
  ```
130
130
 
@@ -151,7 +151,7 @@ $ pnpm run dev
151
151
 
152
152
  # Start server for backend
153
153
  $ bundle install
154
- $ DIVER_DOWN_DIR=/path/to/definitions_dir DIVER_DOWN_MODULE_STORE=/path/to/module_store.yml bundle exec puma
154
+ $ DIVER_DOWN_DIR=/path/to/definitions_dir DIVER_DOWN_METADATA=/path/to/metadata.yml bundle exec puma
155
155
  ```
156
156
 
157
157
  ## Contributing
data/exe/diver_down_web CHANGED
@@ -3,7 +3,6 @@
3
3
 
4
4
  require 'bundler/setup'
5
5
  require 'rack/contrib'
6
- require 'webrick'
7
6
  require 'diver_down'
8
7
  require 'diver_down-web'
9
8
  require 'optparse'
@@ -14,7 +13,7 @@ option_parser = OptionParser.new do |opts|
14
13
  Usage: diver_down_web [options]
15
14
 
16
15
  Example:
17
- diver_down_web --definition-dir /path/to/definitions --module-store /path/to/module_store.yml
16
+ diver_down_web --definition-dir /path/to/definitions --metadata /path/to/metadata.yml
18
17
 
19
18
  Options:
20
19
  BANNER
@@ -23,8 +22,8 @@ option_parser = OptionParser.new do |opts|
23
22
  options[:definition_dir] = path
24
23
  end
25
24
 
26
- opts.on('--module-store PATH', 'Path to the module store') do |path|
27
- options[:module_store] = path
25
+ opts.on('--metadata PATH', 'Path to the metadata.yml') do |path|
26
+ options[:metadata] = path
28
27
  end
29
28
  end
30
29
  option_parser.parse!(ARGV)
@@ -39,7 +38,7 @@ end
39
38
  app = Rack::JSONBodyParser.new(
40
39
  DiverDown::Web.new(
41
40
  definition_dir: options.fetch(:definition_dir),
42
- module_store: DiverDown::Web::ModuleStore.new(options[:module_store] || Tempfile.new(['module_store', '.yaml']))
41
+ metadata: DiverDown::Web::Metadata.new(options[:metadata] || Tempfile.new(['metadata', '.yaml']).path)
43
42
  )
44
43
  )
45
44
 
@@ -47,9 +46,9 @@ begin
47
46
  # Rack 2.0
48
47
  require 'rack'
49
48
  require 'rack/server'
50
- Rack::Server.new(app:, server: :webrick).start
49
+ Rack::Server.new(app:).start
51
50
  rescue LoadError
52
51
  # Rack 3.0
53
52
  require 'rackup'
54
- Rackup::Server.new(app:, server: :webrick).start
53
+ Rackup::Server.new(app:).start
55
54
  end
@@ -102,6 +102,16 @@ module DiverDown
102
102
  def inspect
103
103
  %(#<#{self.class} source_name="#{source_name}" method_ids=#{method_ids}>")
104
104
  end
105
+
106
+ # @return [void]
107
+ def freeze
108
+ super
109
+ @method_id_map.transform_values do
110
+ _1.transform_values(&:freeze)
111
+ _1.freeze
112
+ end
113
+ @method_id_map.freeze
114
+ end
105
115
  end
106
116
  end
107
117
  end
@@ -78,6 +78,12 @@ module DiverDown
78
78
  def inspect
79
79
  %(#<#{self.class} #{human_method_name} paths=#{paths.inspect}>")
80
80
  end
81
+
82
+ # @return [void]
83
+ def freeze
84
+ super
85
+ @paths.freeze
86
+ end
81
87
  end
82
88
  end
83
89
  end
@@ -52,6 +52,12 @@ module DiverDown
52
52
  @dependency_map[dependency_source_name]
53
53
  end
54
54
 
55
+ # @param dependency_source_name [String]
56
+ # @return [void]
57
+ def delete_dependency(dependency_source_name)
58
+ @dependency_map.delete(dependency_source_name)
59
+ end
60
+
55
61
  # @return [Array<DiverDown::Definition::Dependency>]
56
62
  def dependencies
57
63
  @dependency_map.values.sort
@@ -85,6 +91,13 @@ module DiverDown
85
91
  def hash
86
92
  [self.class, source_name, dependencies].hash
87
93
  end
94
+
95
+ # @return [void]
96
+ def freeze
97
+ super
98
+ @dependency_map.transform_values(&:freeze)
99
+ @dependency_map.freeze
100
+ end
88
101
  end
89
102
  end
90
103
  end
@@ -103,5 +103,13 @@ module DiverDown
103
103
  [self.class, definition_group, title, sources].hash
104
104
  end
105
105
  end
106
+
107
+ # @return [void]
108
+ def freeze
109
+ super
110
+
111
+ @source_map.transform_values(&:freeze)
112
+ @source_map.freeze
113
+ end
106
114
  end
107
115
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DiverDown
4
- VERSION = '0.0.1.alpha13'
4
+ VERSION = '0.0.1.alpha15'
5
5
  end
@@ -12,37 +12,74 @@ module DiverDown
12
12
  :per
13
13
  )
14
14
 
15
+ M = Mutex.new
16
+
17
+ attr_reader :store
18
+
15
19
  # @param store [DiverDown::Definition::Store]
16
- # @param module_store [DiverDown::Web::ModuleStore]
17
- # @param request [Rack::Request]
18
- def initialize(store:, module_store:, request:)
20
+ # @param metadata [DiverDown::Web::Metadata]
21
+ def initialize(store:, metadata:)
19
22
  @store = store
20
- @module_store = module_store
21
- @request = request
23
+ @metadata = metadata
24
+ @source_alias_resolver = DiverDown::Web::SourceAliasResolver.new(@metadata.source_alias)
25
+ @module_dependency_map = nil
26
+ @module_dependency_map_cache_id = nil
27
+ end
28
+
29
+ # GET /api/source_aliases.json
30
+ def source_aliases
31
+ source_aliases = @metadata.source_alias.to_h.map do |alias_name, source_names|
32
+ {
33
+ alias_name:,
34
+ source_names:,
35
+ }
36
+ end
37
+
38
+ json(
39
+ source_aliases:
40
+ )
41
+ end
42
+
43
+ # POST /api/source_aliases.json
44
+ # @param alias_name [String]
45
+ # @param old_alias_name [String]
46
+ # @param source_names [Array<String>]
47
+ def update_source_alias(alias_name, old_alias_name, source_names)
48
+ @metadata.source_alias.transaction do
49
+ unless old_alias_name.to_s.empty?
50
+ # Delete old alias
51
+ @metadata.source_alias.update_alias(old_alias_name, [])
52
+ end
53
+
54
+ @metadata.source_alias.update_alias(alias_name, source_names)
55
+ end
56
+
57
+ @metadata.flush
58
+
59
+ json({})
60
+ rescue DiverDown::Web::Metadata::SourceAlias::ConflictError => e
61
+ json_error(e.message)
22
62
  end
23
63
 
24
64
  # GET /api/sources.json
25
65
  def sources
26
66
  source_names = Set.new
27
67
 
28
- # rubocop:disable Style/HashEachMethods
29
- @store.each do |_, definition|
30
- definition.sources.each do |source|
31
- source_names.add(source.source_name)
32
- end
68
+ @store.combined_definition.sources.each do |source|
69
+ source_names.add(source.source_name)
33
70
  end
34
- # rubocop:enable Style/HashEachMethods
35
71
 
36
- classified_sources_count = source_names.count { @module_store.classified?(_1) }
72
+ classified_sources_count = source_names.count { @metadata.source(_1).module? }
37
73
 
38
74
  json(
39
75
  sources: source_names.sort.map do |source_name|
76
+ source_metadata = @metadata.source(source_name)
77
+
40
78
  {
41
79
  source_name:,
42
- memo: @module_store.get_memo(source_name),
43
- modules: @module_store.get_modules(source_name).map do |module_name|
44
- { module_name: }
45
- end,
80
+ resolved_alias: @metadata.source_alias.resolve_alias(source_name),
81
+ memo: source_metadata.memo,
82
+ module: source_metadata.module,
46
83
  }
47
84
  end,
48
85
  classified_sources_count:
@@ -52,70 +89,71 @@ module DiverDown
52
89
  # GET /api/modules.json
53
90
  def modules
54
91
  # Hash{ DiverDown::Definition::Modulee => Set<Integer> }
55
- module_set = Set.new
92
+ modules = Set.new
56
93
 
57
- # rubocop:disable Style/HashEachMethods
58
- @store.each do |_, definition|
59
- definition.sources.each do |source|
60
- modules = @module_store.get_modules(source.source_name)
61
- module_set.add(modules) unless modules.empty?
62
- end
94
+ @store.combined_definition.sources.each do |source|
95
+ modulee = @metadata.source(source.source_name).module
96
+ modules.add(modulee) unless modulee.nil?
63
97
  end
64
- # rubocop:enable Style/HashEachMethods
65
98
 
66
99
  json(
67
- modules: module_set.sort.map do
68
- _1.map do |module_name|
69
- {
70
- module_name:,
71
- }
72
- end
73
- end
100
+ modules: modules.sort
74
101
  )
75
102
  end
76
103
 
77
- # GET /api/modules/:module_name.json
78
- # @param module_names [Array<String>]
79
- def module(module_names)
80
- # Hash{ DiverDown::Definition::Modulee => Set<Integer> }
81
- related_definition_store_ids = Set.new
82
- source_names = Set.new
83
-
84
- # rubocop:disable Style/HashEachMethods
85
- @store.each do |_, definition|
86
- definition.sources.each do |source|
87
- source_module_names = @module_store.get_modules(source.source_name)
88
-
89
- next unless source_module_names[0..module_names.size - 1] == module_names
90
-
91
- source_names.add(source.source_name)
92
- related_definition_store_ids.add(definition.store_id)
93
- end
94
- end
95
- # rubocop:enable Style/HashEachMethods
104
+ # GET /api/modules/:modulee.json
105
+ # @param modulee [String]
106
+ def module(modulee)
107
+ module_dependency_map = fetch_module_dependency_map
96
108
 
97
- if related_definition_store_ids.empty?
109
+ unless module_dependency_map.key?(modulee)
98
110
  return not_found
99
111
  end
100
112
 
101
- related_definitions = related_definition_store_ids.map { @store.get(_1) }
113
+ module_dependency = module_dependency_map.fetch(modulee)
102
114
 
103
115
  json(
104
- modules: module_names.map do
116
+ module: modulee,
117
+ module_dependencies: module_dependency.module_dependencies.compact.sort,
118
+ module_reverse_dependencies: module_dependency.module_reverse_dependencies.compact.sort,
119
+ sources: module_dependency.sources.map do |source|
105
120
  {
106
- module_name: _1,
107
- }
108
- end,
109
- sources: source_names.sort.map do |source_name|
110
- {
111
- source_name:,
112
- memo: @module_store.get_memo(source_name),
121
+ source_name: source.source_name,
122
+ module: @metadata.source(source.source_name).module,
123
+ memo: @metadata.source(source.source_name).memo,
124
+ dependencies: source.dependencies.map do |dependency|
125
+ {
126
+ source_name: dependency.source_name,
127
+ module: @metadata.source(dependency.source_name).module,
128
+ method_ids: dependency.method_ids.sort.map do |method_id|
129
+ {
130
+ context: method_id.context,
131
+ name: method_id.name,
132
+ paths: method_id.paths.sort,
133
+ }
134
+ end,
135
+ }
136
+ end,
113
137
  }
114
138
  end,
115
- related_definitions: related_definitions.map do |definition|
139
+ source_reverse_dependencies: module_dependency.source_reverse_dependencies.map do |source|
116
140
  {
117
- id: definition.store_id,
118
- title: definition.title,
141
+ source_name: source.source_name,
142
+ module: @metadata.source(source.source_name).module,
143
+ memo: @metadata.source(source.source_name).memo,
144
+ dependencies: source.dependencies.map do |dependency|
145
+ {
146
+ source_name: dependency.source_name,
147
+ module: @metadata.source(dependency.source_name).module,
148
+ method_ids: dependency.method_ids.sort.map do |method_id|
149
+ {
150
+ context: method_id.context,
151
+ name: method_id.name,
152
+ paths: method_id.paths.sort,
153
+ }
154
+ end,
155
+ }
156
+ end,
119
157
  }
120
158
  end
121
159
  )
@@ -139,7 +177,7 @@ module DiverDown
139
177
  definition_group: definition.definition_group,
140
178
  title: definition.title,
141
179
  sources_count: definition.sources.size,
142
- unclassified_sources_count: definition.sources.reject { @module_store.classified?(_1.source_name) }.size,
180
+ unclassified_sources_count: definition.sources.reject { @metadata.source(_1.source_name).module? }.size,
143
181
  }
144
182
  end,
145
183
  pagination: pagination.to_h
@@ -167,7 +205,7 @@ module DiverDown
167
205
  # @param compound [Boolean]
168
206
  # @param concentrate [Boolean]
169
207
  # @param only_module [Boolean]
170
- def combine_definitions(bit_id, compound, concentrate, only_module)
208
+ def combine_definitions(bit_id, compound, concentrate, only_module, remove_internal_sources, focus_modules, modules)
171
209
  ids = DiverDown::Web::BitId.bit_id_to_ids(bit_id)
172
210
 
173
211
  valid_ids = ids.select do
@@ -187,22 +225,18 @@ module DiverDown
187
225
  end
188
226
 
189
227
  if definition
190
- definition_to_dot = DiverDown::Web::DefinitionToDot.new(definition, @module_store, compound:, concentrate:, only_module:)
191
-
192
- json(
193
- titles:,
194
- bit_id: DiverDown::Web::BitId.ids_to_bit_id(valid_ids).to_s,
195
- dot: definition_to_dot.to_s,
196
- dot_metadata: definition_to_dot.metadata,
197
- sources: definition.sources.map do
198
- {
199
- source_name: _1.source_name,
200
- memo: @module_store.get_memo(_1.source_name),
201
- modules: @module_store.get_modules(_1.source_name).map do |module_name|
202
- { module_name: }
203
- end,
204
- }
205
- end
228
+ # Resolve source aliases
229
+ resolved_definition = @source_alias_resolver.resolve(definition)
230
+ # Filter sources and dependencies by condition
231
+ resolved_definition = DiverDown::Web::DefinitionFilter.new(@metadata, focus_modules:, modules:, remove_internal_sources:).filter(resolved_definition)
232
+
233
+ render_combined_definition(
234
+ valid_ids,
235
+ resolved_definition,
236
+ titles,
237
+ compound:,
238
+ concentrate:,
239
+ only_module:
206
240
  )
207
241
  else
208
242
  not_found
@@ -245,19 +279,18 @@ module DiverDown
245
279
 
246
280
  return not_found if related_definitions.empty?
247
281
 
248
- module_names = if found_sources.empty?
249
- []
250
- else
251
- source = DiverDown::Definition::Source.combine(*found_sources)
252
- @module_store.get_modules(source.source_name)
253
- end
282
+ modulee = if found_sources.empty?
283
+ nil
284
+ else
285
+ source = DiverDown::Definition::Source.combine(*found_sources)
286
+ @metadata.source(source.source_name).module
287
+ end
254
288
 
255
289
  json(
256
290
  source_name:,
257
- memo: @module_store.get_memo(source_name),
258
- modules: module_names.map do
259
- { module_name: _1 }
260
- end,
291
+ resolved_alias: @metadata.source_alias.resolve_alias(source_name),
292
+ memo: @metadata.source(source_name).memo,
293
+ module: modulee,
261
294
  related_definitions: related_definitions.map do |id, definition|
262
295
  {
263
296
  id:,
@@ -267,6 +300,7 @@ module DiverDown
267
300
  reverse_dependencies: reverse_dependencies.values.map { |reverse_dependency|
268
301
  {
269
302
  source_name: reverse_dependency.source_name,
303
+ module: @metadata.source(reverse_dependency.source_name).module,
270
304
  method_ids: reverse_dependency.method_ids.sort.map do |method_id|
271
305
  {
272
306
  context: method_id.context,
@@ -279,11 +313,11 @@ module DiverDown
279
313
  )
280
314
  end
281
315
 
282
- # POST /api/sources/:source_name/modules.json
316
+ # POST /api/sources/:source_name/module.json
283
317
  #
284
318
  # @param source_name [String]
285
- # @param modules [Array<String>]
286
- def set_modules(source_name, modules)
319
+ # @param module [Array<String>]
320
+ def set_module(source_name, modulee)
287
321
  found_source = @store.any? do |_, definition|
288
322
  definition.sources.any? do |source|
289
323
  source.source_name == source_name
@@ -291,8 +325,8 @@ module DiverDown
291
325
  end
292
326
 
293
327
  if found_source
294
- @module_store.set_modules(source_name, modules)
295
- @module_store.flush
328
+ @metadata.source(source_name).module = modulee
329
+ @metadata.flush
296
330
 
297
331
  json({})
298
332
  else
@@ -312,8 +346,8 @@ module DiverDown
312
346
  end
313
347
 
314
348
  if found_source
315
- @module_store.set_memo(source_name, memo)
316
- @module_store.flush
349
+ @metadata.source(source_name).memo = memo
350
+ @metadata.flush
317
351
 
318
352
  json({})
319
353
  else
@@ -328,8 +362,6 @@ module DiverDown
328
362
 
329
363
  private
330
364
 
331
- attr_reader :request, :store
332
-
333
365
  def build_method_id_key(dependency, method_id)
334
366
  "#{dependency.source_name}-#{method_id.context}-#{method_id.name}"
335
367
  end
@@ -370,8 +402,48 @@ module DiverDown
370
402
  end
371
403
  end
372
404
 
373
- def json(data)
374
- [200, { 'content-type' => 'application/json' }, [data.to_json]]
405
+ def json(data, status = 200)
406
+ [status, { 'content-type' => 'application/json' }, [data.to_json]]
407
+ end
408
+
409
+ def json_error(message, status = 422)
410
+ json({ message: }, status)
411
+ end
412
+
413
+ def render_combined_definition(ids, definition, titles, compound:, concentrate:, only_module:)
414
+ definition_to_dot = DiverDown::Web::DefinitionToDot.new(definition, @metadata, compound:, concentrate:, only_module:)
415
+
416
+ json(
417
+ titles:,
418
+ bit_id: DiverDown::Web::BitId.ids_to_bit_id(ids).to_s,
419
+ dot: definition_to_dot.to_s,
420
+ dot_metadata: definition_to_dot.dot_metadata,
421
+ sources: definition.sources.map do
422
+ {
423
+ source_name: _1.source_name,
424
+ resolved_alias: @metadata.source_alias.resolve_alias(_1.source_name),
425
+ memo: @metadata.source(_1.source_name).memo,
426
+ module: @metadata.source(_1.source_name).module,
427
+ dependencies: _1.dependencies.map do |dependency|
428
+ {
429
+ source_name: dependency.source_name,
430
+ }
431
+ end,
432
+ }
433
+ end
434
+ )
435
+ end
436
+
437
+ def fetch_module_dependency_map
438
+ M.synchronize do
439
+ if @module_dependency_map_cache_id != @store.combined_definition.object_id
440
+ definition = @store.combined_definition
441
+ @module_dependency_map = DiverDown::Web::DefinitionModuleDependencies.new(@metadata, definition).build_module_dependency_map
442
+ @module_dependency_map_cache_id = definition.object_id
443
+ end
444
+ end
445
+
446
+ @module_dependency_map
375
447
  end
376
448
  end
377
449
  end
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DiverDown
4
+ class Web
5
+ class DefinitionFilter
6
+ # @param metadata_alias [DiverDown::Web::Metadata]
7
+ # @param focus_modules [Array<String>]
8
+ # @param modules [Array<String>]
9
+ # @param remove_internal_sources [Boolean]
10
+ def initialize(metadata, focus_modules: [], modules: [], remove_internal_sources: false)
11
+ @metadata = metadata
12
+ @focus_modules = focus_modules
13
+ @modules = modules | focus_modules
14
+ @remove_internal_sources = remove_internal_sources
15
+ end
16
+
17
+ # @param definition [DiverDown::Definition]
18
+ # @return [DiverDown::Definition]
19
+ def filter(definition)
20
+ return definition if !@remove_internal_sources && @modules.empty?
21
+
22
+ new_definition = DiverDown::Definition.new(
23
+ definition_group: definition.definition_group,
24
+ title: definition.title
25
+ )
26
+
27
+ source_names = extract_match_source_names(definition.sources)
28
+
29
+ definition.sources.each do |source|
30
+ next unless source_names.include?(source.source_name)
31
+
32
+ new_source = new_definition.find_or_build_source(source.source_name)
33
+
34
+ source.dependencies.each do |dependency|
35
+ next unless source_names.include?(dependency.source_name)
36
+ next unless focus_module?(source, dependency)
37
+ next if @remove_internal_sources && @metadata.source(source.source_name).module == @metadata.source(dependency.source_name).module
38
+
39
+ new_dependency = new_source.find_or_build_dependency(dependency.source_name)
40
+
41
+ next unless new_dependency
42
+
43
+ dependency.method_ids.each do |method_id|
44
+ new_method_id = new_dependency.find_or_build_method_id(
45
+ context: method_id.context,
46
+ name: method_id.name
47
+ )
48
+
49
+ method_id.paths.each do |path|
50
+ new_method_id.add_path(path)
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ new_definition
57
+ end
58
+
59
+ private
60
+
61
+ def focus_module?(source, dependency)
62
+ return true if @focus_modules.empty?
63
+ return true if @focus_modules.include?(@metadata.source(source.source_name).module)
64
+ return true if @focus_modules.include?(@metadata.source(dependency.source_name).module)
65
+
66
+ false
67
+ end
68
+
69
+ def extract_match_source_names(sources)
70
+ # Filter sources by modules.
71
+ source_names = sources.filter_map do |source|
72
+ source.source_name if match_module?(source.source_name)
73
+ end.to_set
74
+
75
+ if @remove_internal_sources
76
+ # Remove internal sources.
77
+ external_called_sources = Set.new
78
+
79
+ sources.each do |source|
80
+ next unless source_names.include?(source.source_name)
81
+
82
+ source_module = @metadata.source(source.source_name).module
83
+
84
+ source.dependencies.each do |dependency|
85
+ next unless source_names.include?(dependency.source_name)
86
+
87
+ dependency_module = @metadata.source(dependency.source_name).module
88
+
89
+ next if source_module == dependency_module
90
+
91
+ external_called_sources << source.source_name
92
+ external_called_sources << dependency.source_name
93
+ break
94
+ end
95
+ end
96
+
97
+ external_called_sources
98
+ else
99
+ source_names
100
+ end
101
+ end
102
+
103
+ def top_module(source_name)
104
+ @metadata.source(source_name).modules.first
105
+ end
106
+
107
+ def match_module?(source_name)
108
+ @modules.empty? || @modules.include?(@metadata.source(source_name).module)
109
+ end
110
+ end
111
+ end
112
+ end