klenod-build 0.0.4 → 0.0.5

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: 560774e128fafb845afbff51f556e3eb30d3a1b7d280b9fbdc7ac36b48c4b741
4
- data.tar.gz: 559ce8134726f2fa31084811a9dcda01987a957c073370f5ac0595c8d7a3f703
3
+ metadata.gz: f7515626d279801c2dfb15f6b0ff7d00b358c4dc20549f21b60730f1ef1307cf
4
+ data.tar.gz: ea285ea5d5d59188defafb4eced0c96ff316fbb67bd2d1cf0de7728f41cda927
5
5
  SHA512:
6
- metadata.gz: 77cb936bd77e35262827d9903124f1b37cec73bb11db28c1a5e497d02a20d9283e989a46524c2f674b7c0f49734632e3da02b324a4988dbccbe3fe244e591921
7
- data.tar.gz: eccc054b80b674a4f304fb6ec2abbdaf3bdf244576dc0f9bfd7b0d23b7b35ac77f5a47a061ad013cd9743295606b7ca3526a50e8f2dff48cc86ba13d4dac6fc2
6
+ metadata.gz: 7480460dfbedd0e793ceed82b3142d6ea5750f9c11e6752193745248643c53ff8a804cd1c855b4ffb171c8cdd1872a7aae9e66f15b417f8bc5f15d3d3baa8da6
7
+ data.tar.gz: 743b1821300848721a9208b1e6f59fc2736dc89d99f6e9ff24bb01346e9701645c2c88dc75daf83424f6a1e6ad758f98db7877fbccac2a0670cbf3630f26b19f
data/README.md CHANGED
@@ -27,3 +27,6 @@ The CLI can also generate a [Graphviz](https://graphviz.org/) DOT-file from a ge
27
27
  ```sh
28
28
  bundle exec klenod graph dist/klenod.bundle > graph.dot
29
29
  ```
30
+
31
+ Klenod's internal virtual modules are hidden by default. Pass
32
+ `--internal-virtual-modules` to include them in the graph.
@@ -68,13 +68,19 @@ module Klenod
68
68
 
69
69
  options do
70
70
  option "--no-assets", "Hide generated asset nodes and edges."
71
+ option "--internal-virtual-modules", "Include Klenod's internal virtual modules."
71
72
  end
72
73
 
73
74
  one :bundle_path, "Path to a Klenod runtime bundle.", required: true
74
75
 
75
76
  def call
76
77
  bundle = Klenod::Runtime.load_bundle(@bundle_path)
77
- dot = Klenod::Build::Graphviz.call(bundle, include_assets: !@options[:no_assets])
78
+ dot =
79
+ Klenod::Build::Graphviz.call(
80
+ bundle,
81
+ include_assets: !@options[:no_assets],
82
+ include_internal_virtual_modules: @options[:internal_virtual_modules]
83
+ )
78
84
  output.write(dot)
79
85
  dot
80
86
  end
@@ -161,7 +161,6 @@ module Klenod
161
161
  end
162
162
 
163
163
  class DynamicImportError < Error; end
164
- class TestImportError < ResolveError; end
165
164
  class UnsupportedFileError < Error; end
166
165
 
167
166
  class ImportCycleError < Error
@@ -19,13 +19,18 @@ module Klenod
19
19
  ASSET_STYLE = {fillcolor: "#ffe4d6", color: "#e26d39"}.freeze
20
20
  DEFAULT_MODULE_STYLE = {fillcolor: "#f7f7f7", color: "#8a8a8a"}.freeze
21
21
 
22
- def self.call(bundle, include_assets: true)
23
- new(bundle, include_assets: include_assets).to_dot
22
+ def self.call(bundle, include_assets: true, include_internal_virtual_modules: false)
23
+ new(
24
+ bundle,
25
+ include_assets: include_assets,
26
+ include_internal_virtual_modules: include_internal_virtual_modules
27
+ ).to_dot
24
28
  end
25
29
 
26
- def initialize(bundle, include_assets: true)
30
+ def initialize(bundle, include_assets: true, include_internal_virtual_modules: false)
27
31
  @bundle = bundle
28
32
  @include_assets = include_assets
33
+ @include_internal_virtual_modules = include_internal_virtual_modules
29
34
  end
30
35
 
31
36
  def to_dot
@@ -46,8 +51,15 @@ module Klenod
46
51
 
47
52
  private
48
53
 
54
+ def all_module_ids
55
+ @all_module_ids ||= @bundle.modules.keys.sort
56
+ end
57
+
49
58
  def module_ids
50
- @bundle.modules.keys.sort
59
+ @module_ids ||=
60
+ all_module_ids.reject do |id|
61
+ internal_virtual_module?(id) && !entrypoint?(id) && !@include_internal_virtual_modules
62
+ end
51
63
  end
52
64
 
53
65
  def module_node(id)
@@ -75,7 +87,7 @@ module Klenod
75
87
  module_ids.flat_map do |id|
76
88
  @bundle.modules.fetch(id).imports.values.map do |import|
77
89
  import = import_spec(import)
78
- next unless @bundle.modules.key?(import.target_id)
90
+ next unless visible_module?(import.target_id)
79
91
 
80
92
  attributes = {
81
93
  id: svg_edge_id(id, import.target_id),
@@ -91,25 +103,71 @@ module Klenod
91
103
  end
92
104
 
93
105
  def asset_edges
94
- @bundle.assets.values.sort_by(&:output_path).filter_map do |asset|
95
- owner = asset_owner(asset)
96
- next unless owner
97
-
98
- attributes = {
99
- id: svg_edge_id(owner_node_name(owner), asset.output_path),
100
- class: "edge edge-asset",
101
- color: "#e26d39",
102
- style: "dotted",
103
- label: "asset"
104
- }
105
- " #{owner_node_id(owner)} -> #{asset_node_id(asset)} [#{dot_attributes(attributes)}];"
106
+ @bundle.assets.values.sort_by(&:output_path).flat_map do |asset|
107
+ asset_owners(asset).map do |owner|
108
+ attributes = {
109
+ id: svg_edge_id(owner_node_name(owner), asset.output_path),
110
+ class: "edge edge-asset",
111
+ color: "#e26d39",
112
+ style: "dotted",
113
+ label: "asset"
114
+ }
115
+ " #{owner_node_id(owner)} -> #{asset_node_id(asset)} [#{dot_attributes(attributes)}];"
116
+ end
106
117
  end
107
118
  end
108
119
 
109
- def asset_owner(asset)
110
- return [:module, asset.logical_name] if @bundle.modules.key?(asset.logical_name)
120
+ def asset_owners(asset)
121
+ module_id = module_id_for_asset(asset.logical_name)
122
+ return visible_module_owners(module_id) if module_id
111
123
 
112
- google_fonts_css_asset_owner(asset) || query_module_id_for(asset.logical_name)
124
+ [google_fonts_css_asset_owner(asset), *asset_metadata_owners(asset)].compact
125
+ end
126
+
127
+ def visible_module_owners(module_id)
128
+ pending = [module_id]
129
+ seen = Set.new
130
+ owners = []
131
+
132
+ until pending.empty?
133
+ current_id = pending.shift
134
+ next unless seen.add?(current_id)
135
+
136
+ if visible_module?(current_id)
137
+ owners << [:module, current_id]
138
+ else
139
+ pending.concat(module_importers.fetch(current_id, []))
140
+ end
141
+ end
142
+
143
+ owners
144
+ end
145
+
146
+ def module_importers
147
+ @module_importers ||=
148
+ all_module_ids.each_with_object(Hash.new { |index, id| index[id] = [] }) do |id, index|
149
+ @bundle.modules.fetch(id).imports.each_value do |import|
150
+ target_id = import_spec(import).target_id
151
+ index[target_id] << id if @bundle.modules.key?(target_id)
152
+ end
153
+ end
154
+ end
155
+
156
+ def module_id_for_asset(logical_name)
157
+ return logical_name if @bundle.modules.key?(logical_name)
158
+
159
+ module_ids_by_source_path.fetch(logical_name, nil) || query_module_ids_by_path.fetch(logical_name, nil)
160
+ end
161
+
162
+ def module_ids_by_source_path
163
+ @module_ids_by_source_path ||=
164
+ all_module_ids.each_with_object({}) do |id, index|
165
+ source_path = @bundle.modules.fetch(id).source_path
166
+ next unless source_path
167
+
168
+ index[source_path] ||= id
169
+ index[display_path(source_path)] ||= id
170
+ end
113
171
  end
114
172
 
115
173
  def google_fonts_css_asset_owner(asset)
@@ -127,14 +185,18 @@ module Klenod
127
185
  asset.metadata[:source_url]
128
186
  end
129
187
 
130
- def query_module_id_for(logical_name)
131
- module_id = query_module_ids_by_path.fetch(logical_name, nil)
132
- [:module, module_id] if module_id
188
+ def asset_metadata_owners(asset)
189
+ return [] unless asset.metadata[:javascript_runtime] == :asset_metadata
190
+
191
+ @bundle.assets.values
192
+ .select { it.metadata[:image_metadata] || it.metadata[:svg_metadata] }
193
+ .sort_by(&:output_path)
194
+ .map { [:asset, it] }
133
195
  end
134
196
 
135
197
  def query_module_ids_by_path
136
198
  @query_module_ids_by_path ||=
137
- module_ids.each_with_object({}) do |id, index|
199
+ all_module_ids.each_with_object({}) do |id, index|
138
200
  path, query = id.split("?", 2)
139
201
  next unless query
140
202
 
@@ -218,6 +280,15 @@ module Klenod
218
280
  ["edge", import.eager ? "edge-import" : "edge-import edge-lazy"].join(" ")
219
281
  end
220
282
 
283
+ def internal_virtual_module?(id)
284
+ id.start_with?("virtual:/klenod/", "virtual:klenod/")
285
+ end
286
+
287
+ def visible_module?(id)
288
+ @visible_module_ids ||= module_ids.to_set
289
+ @visible_module_ids.include?(id)
290
+ end
291
+
221
292
  def entrypoint?(id)
222
293
  entrypoint_ids.include?(id)
223
294
  end
@@ -17,7 +17,6 @@ module Klenod
17
17
  autoload :TomlPlugin, File.expand_path("plugins/data_plugin", __dir__)
18
18
  autoload :TextPlugin, File.expand_path("plugins/data_plugin", __dir__)
19
19
  autoload :RouterPlugin, File.expand_path("plugins/router_plugin", __dir__)
20
- autoload :TestPlugin, File.expand_path("plugins/test_plugin", __dir__)
21
20
  end
22
21
  end
23
22
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Klenod
4
4
  module Build
5
- VERSION = "0.0.4"
5
+ VERSION = "0.0.5"
6
6
  end
7
7
  end
data/lib/klenod/build.rb CHANGED
@@ -9,8 +9,6 @@ module Klenod
9
9
 
10
10
  module Build
11
11
  autoload :Graphviz, "klenod/build/graphviz"
12
- autoload :TestSelection, "klenod/build/test_suite"
13
- autoload :TestSuite, "klenod/build/test_suite"
14
12
  autoload :UpdateEvent, "klenod/build/watcher"
15
13
  autoload :Watcher, "klenod/build/watcher"
16
14
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: klenod-build
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrés Alin
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - '='
17
17
  - !ruby/object:Gem::Version
18
- version: 0.0.4
18
+ version: 0.0.5
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - '='
24
24
  - !ruby/object:Gem::Version
25
- version: 0.0.4
25
+ version: 0.0.5
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: async
28
28
  requirement: !ruby/object:Gem::Requirement
@@ -272,7 +272,6 @@ files:
272
272
  - lib/klenod/build/plugins/router_plugin.rb
273
273
  - lib/klenod/build/plugins/ruby_plugin.rb
274
274
  - lib/klenod/build/plugins/svg_plugin.rb
275
- - lib/klenod/build/plugins/test_plugin.rb
276
275
  - lib/klenod/build/profiler.rb
277
276
  - lib/klenod/build/resolution_error_formatter.rb
278
277
  - lib/klenod/build/resolver.rb
@@ -281,7 +280,6 @@ files:
281
280
  - lib/klenod/build/source_map/editor.rb
282
281
  - lib/klenod/build/source_map/map.rb
283
282
  - lib/klenod/build/source_map/vlq.rb
284
- - lib/klenod/build/test_suite.rb
285
283
  - lib/klenod/build/transform_result.rb
286
284
  - lib/klenod/build/version.rb
287
285
  - lib/klenod/build/watched_pattern.rb
@@ -1,49 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "../errors"
4
- require_relative "../module_id"
5
- require_relative "../plugin"
6
-
7
- module Klenod
8
- module Build
9
- module Plugins
10
- module TestPlugin
11
- def self.new(...)
12
- Plugin.new(...)
13
- end
14
-
15
- class Plugin < Klenod::Build::Plugin
16
- DEFAULT_PATTERN = "**/*.test.rb"
17
-
18
- def initialize(pattern: DEFAULT_PATTERN)
19
- @pattern = pattern.to_s
20
- end
21
-
22
- attr_reader :pattern
23
-
24
- def discover(source_dir:)
25
- root = Pathname.new(source_dir).expand_path
26
-
27
- root
28
- .glob(pattern)
29
- .select(&:file?)
30
- .map { |path| ModuleId.new(path.relative_path_from(root).to_s.tr("\\", "/"), nil) }
31
- .sort_by(&:to_s)
32
- end
33
-
34
- def test_module_id?(module_id)
35
- module_id.scheme == :app && File.fnmatch?(pattern, module_id.relative_path, File::FNM_PATHNAME | File::FNM_EXTGLOB)
36
- end
37
-
38
- def finalize(module_id, result, resolved_dependencies, _dependency_records, _context)
39
- imported_test = resolved_dependencies.find { |dependency| test_module_id?(dependency.module_id) }
40
- return result unless imported_test
41
-
42
- error = TestImportError.new("Test file #{imported_test.module_id.path.inspect} cannot be imported")
43
- raise error.with_resolution_context(dependency: imported_test.dependency, importer_id: module_id)
44
- end
45
- end
46
- end
47
- end
48
- end
49
- end
@@ -1,94 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Klenod
4
- module Build
5
- TestSelection = Data.define(:test_paths, :removed_test_paths) do
6
- def empty?
7
- test_paths.empty? && removed_test_paths.empty?
8
- end
9
- end
10
-
11
- class TestSuite
12
- def initialize(context:, plugin:)
13
- @context = context
14
- @plugin = plugin
15
- @dependency_ids = {}
16
- @failed_test_ids = Set.new
17
- end
18
-
19
- def collect
20
- test_ids = discover
21
- test_ids.each { |test_id| index(test_id) }
22
- selection(test_ids)
23
- end
24
-
25
- def update(event)
26
- previous_test_ids = @dependency_ids.keys.to_set
27
- current_test_ids = discover.to_set
28
- removed_test_ids = previous_test_ids - current_test_ids
29
- added_test_ids = current_test_ids - previous_test_ids
30
- affected_module_ids = update_module_ids(event)
31
- affected_test_ids =
32
- @dependency_ids.filter_map do |test_id, dependency_ids|
33
- test_id if current_test_ids.include?(test_id) && dependency_ids.intersect?(affected_module_ids)
34
- end
35
-
36
- test_ids = (added_test_ids + affected_test_ids + @failed_test_ids).select { |test_id| current_test_ids.include?(test_id) }
37
- removed_test_ids.each { |test_id| remove(test_id) }
38
- test_ids.each { |test_id| index(test_id) }
39
-
40
- selection(test_ids, removed_test_ids)
41
- end
42
-
43
- private
44
-
45
- attr_reader :context, :plugin
46
-
47
- def discover
48
- plugin.discover(source_dir: context.graph.source_dir)
49
- end
50
-
51
- def index(test_id)
52
- dependency_ids = Set[test_id]
53
- @dependency_ids[test_id] = dependency_ids
54
- collect_dependencies(test_id, dependency_ids)
55
- @failed_test_ids.delete(test_id)
56
- rescue
57
- @failed_test_ids << test_id
58
- end
59
-
60
- def collect_dependencies(module_id, dependency_ids)
61
- record = context.graph.records[module_id] || context.graph.collect_module(module_id)
62
-
63
- record.resolved_dependencies.each do |dependency|
64
- dependency_id = dependency.module_id
65
- next unless dependency_ids.add?(dependency_id)
66
-
67
- collect_dependencies(dependency_id, dependency_ids)
68
- end
69
- end
70
-
71
- def remove(test_id)
72
- @dependency_ids.delete(test_id)
73
- @failed_test_ids.delete(test_id)
74
- end
75
-
76
- def update_module_ids(event)
77
- result = event.result
78
- Set.new(
79
- result.changed_module_ids +
80
- result.removed_module_ids +
81
- result.reloaded_module_ids +
82
- result.reevaluated_module_ids
83
- )
84
- end
85
-
86
- def selection(test_ids, removed_test_ids = [])
87
- TestSelection.new(
88
- test_ids.map(&:relative_path).sort.freeze,
89
- removed_test_ids.map(&:relative_path).sort.freeze
90
- )
91
- end
92
- end
93
- end
94
- end