klenod-build 0.0.1

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 (59) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +29 -0
  3. data/lib/klenod/build/asset.rb +235 -0
  4. data/lib/klenod/build/asset_compression.rb +58 -0
  5. data/lib/klenod/build/asset_generation_queue.rb +50 -0
  6. data/lib/klenod/build/cli/application.rb +108 -0
  7. data/lib/klenod/build/cli.rb +3 -0
  8. data/lib/klenod/build/config.rb +142 -0
  9. data/lib/klenod/build/context.rb +370 -0
  10. data/lib/klenod/build/dependency.rb +21 -0
  11. data/lib/klenod/build/errors.rb +175 -0
  12. data/lib/klenod/build/filesystem_resolver.rb +147 -0
  13. data/lib/klenod/build/graph/invalidator.rb +246 -0
  14. data/lib/klenod/build/graph.rb +864 -0
  15. data/lib/klenod/build/graphviz.rb +282 -0
  16. data/lib/klenod/build/hashing.rb +21 -0
  17. data/lib/klenod/build/invalidation_result.rb +55 -0
  18. data/lib/klenod/build/load_result.rb +7 -0
  19. data/lib/klenod/build/loaded_module.rb +38 -0
  20. data/lib/klenod/build/module_id.rb +100 -0
  21. data/lib/klenod/build/module_record.rb +22 -0
  22. data/lib/klenod/build/plugin.rb +35 -0
  23. data/lib/klenod/build/plugins/class_names_runtime.rb +125 -0
  24. data/lib/klenod/build/plugins/component_defaults.rb +12 -0
  25. data/lib/klenod/build/plugins/data_plugin.rb +117 -0
  26. data/lib/klenod/build/plugins/gem_import_plugin.rb +125 -0
  27. data/lib/klenod/build/plugins/google_fonts_plugin/font_metrics.json +17687 -0
  28. data/lib/klenod/build/plugins/google_fonts_plugin/font_metrics.rb +105 -0
  29. data/lib/klenod/build/plugins/google_fonts_plugin/font_metrics.txt +31 -0
  30. data/lib/klenod/build/plugins/google_fonts_plugin.rb +387 -0
  31. data/lib/klenod/build/plugins/haml_plugin/companions.rb +40 -0
  32. data/lib/klenod/build/plugins/haml_plugin/errors.rb +114 -0
  33. data/lib/klenod/build/plugins/haml_plugin/helper_source.rb +123 -0
  34. data/lib/klenod/build/plugins/haml_plugin/parser.rb +85 -0
  35. data/lib/klenod/build/plugins/haml_plugin/transformer/ruby_builder.rb +1039 -0
  36. data/lib/klenod/build/plugins/haml_plugin/transformer.rb +766 -0
  37. data/lib/klenod/build/plugins/haml_plugin.rb +369 -0
  38. data/lib/klenod/build/plugins/image_plugin.rb +401 -0
  39. data/lib/klenod/build/plugins/intl_plugin.rb +34 -0
  40. data/lib/klenod/build/plugins/markdown_compiler.rb +180 -0
  41. data/lib/klenod/build/plugins/markdown_plugin.rb +161 -0
  42. data/lib/klenod/build/plugins/router_plugin.rb +942 -0
  43. data/lib/klenod/build/plugins/ruby_plugin.rb +34 -0
  44. data/lib/klenod/build/plugins/svg_plugin.rb +197 -0
  45. data/lib/klenod/build/plugins.rb +22 -0
  46. data/lib/klenod/build/profiler.rb +79 -0
  47. data/lib/klenod/build/resolution_error_formatter.rb +42 -0
  48. data/lib/klenod/build/resolver.rb +95 -0
  49. data/lib/klenod/build/ruby_import_rewriter.rb +436 -0
  50. data/lib/klenod/build/source_map/editor.rb +110 -0
  51. data/lib/klenod/build/source_map/map.rb +168 -0
  52. data/lib/klenod/build/source_map/vlq.rb +68 -0
  53. data/lib/klenod/build/source_map.rb +12 -0
  54. data/lib/klenod/build/transform_result.rb +12 -0
  55. data/lib/klenod/build/version.rb +7 -0
  56. data/lib/klenod/build/watched_pattern.rb +11 -0
  57. data/lib/klenod/build/watcher.rb +141 -0
  58. data/lib/klenod/build.rb +15 -0
  59. metadata +310 -0
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "toml-rb"
5
+ require "yaml"
6
+
7
+ require_relative "../plugin"
8
+ require_relative "../transform_result"
9
+
10
+ module Klenod
11
+ module Build
12
+ module Plugins
13
+ module DataPlugin
14
+ def self.new(...)
15
+ Plugin.new(...)
16
+ end
17
+
18
+ class Plugin < Klenod::Build::Plugin
19
+ def self.extensions(*values)
20
+ const_set(:EXTENSIONS, values.freeze)
21
+ end
22
+
23
+ def transform(module_id, code, _context)
24
+ return super unless self.class::EXTENSIONS.include?(module_id.extname)
25
+
26
+ data = parse(code)
27
+ TransformResult.new(module_source(data), [], nil, [], [], {data: data})
28
+ end
29
+
30
+ def import_value(_resolved_dependency, record, context)
31
+ return nil unless self.class::EXTENSIONS.include?(record.id.extname)
32
+
33
+ context.mods.fetch(record.id).const_get(:Exports)::Default
34
+ end
35
+
36
+ def runtime_import_value(_resolved_dependency, record, _context)
37
+ return nil unless self.class::EXTENSIONS.include?(record.id.extname)
38
+
39
+ record.metadata.fetch(:data)
40
+ end
41
+
42
+ private
43
+
44
+ def module_source(data)
45
+ <<~RUBY
46
+ Default = #{data.inspect}
47
+ RUBY
48
+ end
49
+ end
50
+ end
51
+
52
+ module JsonPlugin
53
+ def self.new(...)
54
+ Plugin.new(...)
55
+ end
56
+
57
+ class Plugin < DataPlugin::Plugin
58
+ extensions ".json"
59
+
60
+ private
61
+
62
+ def parse(code)
63
+ JSON.parse(code)
64
+ end
65
+ end
66
+ end
67
+
68
+ module YamlPlugin
69
+ def self.new(...)
70
+ Plugin.new(...)
71
+ end
72
+
73
+ class Plugin < DataPlugin::Plugin
74
+ extensions ".yaml", ".yml"
75
+
76
+ private
77
+
78
+ def parse(code)
79
+ YAML.safe_load(code, permitted_classes: [Date, Time, Symbol], aliases: true)
80
+ end
81
+ end
82
+ end
83
+
84
+ module TomlPlugin
85
+ def self.new(...)
86
+ Plugin.new(...)
87
+ end
88
+
89
+ class Plugin < DataPlugin::Plugin
90
+ extensions ".toml"
91
+
92
+ private
93
+
94
+ def parse(code)
95
+ TomlRB.parse(code)
96
+ end
97
+ end
98
+ end
99
+
100
+ module TextPlugin
101
+ def self.new(...)
102
+ Plugin.new(...)
103
+ end
104
+
105
+ class Plugin < DataPlugin::Plugin
106
+ extensions ".txt", ".text"
107
+
108
+ private
109
+
110
+ def parse(code)
111
+ code
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,125 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../dependency"
4
+ require_relative "../errors"
5
+ require_relative "../filesystem_resolver"
6
+ require_relative "../hashing"
7
+ require_relative "../load_result"
8
+ require_relative "../module_id"
9
+ require_relative "../plugin"
10
+
11
+ module Klenod
12
+ module Build
13
+ module Plugins
14
+ module GemImportPlugin
15
+ def self.new(...)
16
+ Plugin.new(...)
17
+ end
18
+
19
+ class Plugin < Klenod::Build::Plugin
20
+ DEFAULT_IMPORT_ROOT = "klenod"
21
+ DEFAULT_EXTENSIONS = [".rb", ".haml"].freeze
22
+
23
+ def initialize(import_root: DEFAULT_IMPORT_ROOT, extensions: DEFAULT_EXTENSIONS)
24
+ @import_root = import_root.to_s.delete_prefix("/")
25
+ @extensions = extensions
26
+ @resolved_paths = {}
27
+ @gem_import_roots = {}
28
+ @filesystem_resolvers = {}
29
+ end
30
+
31
+ def resolve(dependency, _context)
32
+ module_id = module_id_for(dependency)
33
+ return nil unless module_id&.scheme == :gem
34
+
35
+ resolved_path = resolve_existing_path(module_id)
36
+ resolved_id = module_id_for_path(module_id, resolved_path)
37
+ ResolvedDependency.new(dependency, resolved_id, {scheme: :gem, path: resolved_path.to_s})
38
+ rescue ResolveError => error
39
+ raise error.with_resolution_context(dependency: dependency, importer_id: dependency.importer_id)
40
+ end
41
+
42
+ def load(module_id, _context)
43
+ return nil unless module_id.scheme == :gem
44
+
45
+ path = path_for(module_id)
46
+ LoadResult.new(path.binread, Hashing.file_hexdigest(path), nil)
47
+ end
48
+
49
+ private
50
+
51
+ def module_id_for(dependency)
52
+ specifier = dependency.specifier.to_s
53
+ if specifier.match?(ModuleId::SCHEME_PATTERN)
54
+ module_id = ModuleId.parse(specifier)
55
+ return nil unless module_id.scheme == :gem
56
+
57
+ module_id
58
+ elsif dependency.importer_id&.scheme == :gem
59
+ dependency.importer_id.merge(specifier)
60
+ end
61
+ end
62
+
63
+ def resolve_existing_path(module_id)
64
+ @resolved_paths.fetch([module_id.to_s, module_id.query]) do |key|
65
+ path_for(module_id)
66
+ resolved = filesystem_resolver_for(module_id).resolve(module_id.relative_path)
67
+ @resolved_paths[key] = resolved
68
+ end
69
+ rescue ResolveError => error
70
+ raise ResolveError.new(
71
+ error.resolution_failure? ? nil : error.message,
72
+ unresolved_path: module_id.to_s,
73
+ reason: error.reason,
74
+ requested_specifier: error.requested_specifier,
75
+ suggestions: error.suggestions
76
+ )
77
+ end
78
+
79
+ def path_for(module_id)
80
+ raise ResolveError, "Gem import requires a gem name in #{module_id}" if module_id.host.to_s.empty?
81
+
82
+ import_root = import_root_for(module_id.host)
83
+ path = Pathname.new(File.expand_path(module_id.relative_path, import_root))
84
+ assert_inside_import_root!(module_id, import_root, path)
85
+ path
86
+ end
87
+
88
+ def import_root_for(gem_name)
89
+ @gem_import_roots.fetch(gem_name) do
90
+ spec = Gem::Specification.find_by_name(gem_name)
91
+ @gem_import_roots[gem_name] = Pathname.new(File.expand_path(@import_root, spec.full_gem_path))
92
+ end
93
+ rescue Gem::LoadError => error
94
+ raise ResolveError, "Could not find gem #{gem_name.inspect}: #{error.message}"
95
+ end
96
+
97
+ def filesystem_resolver_for(module_id)
98
+ @filesystem_resolvers.fetch(module_id.host) do |gem_name|
99
+ @filesystem_resolvers[gem_name] =
100
+ FilesystemResolver.new(
101
+ root: import_root_for(gem_name),
102
+ extensions: @extensions,
103
+ path_prefix: "gem://#{gem_name}/"
104
+ )
105
+ end
106
+ end
107
+
108
+ def assert_inside_import_root!(module_id, import_root, path)
109
+ import_root_path = import_root.to_s
110
+ expanded = path.to_s
111
+ return if expanded == import_root_path || expanded.start_with?("#{import_root_path}/")
112
+
113
+ raise ResolveError, "Gem import escapes import root: #{module_id}"
114
+ end
115
+
116
+ def module_id_for_path(module_id, path)
117
+ import_root = import_root_for(module_id.host)
118
+ relative = path.relative_path_from(import_root).to_s
119
+ ModuleId.new("gem://#{module_id.host}/#{relative}", module_id.query)
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end