sprockets 2.6.0 → 4.2.2

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 (100) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +118 -0
  3. data/{LICENSE → MIT-LICENSE} +2 -2
  4. data/README.md +541 -289
  5. data/bin/sprockets +20 -7
  6. data/lib/rake/sprocketstask.rb +34 -17
  7. data/lib/sprockets/add_source_map_comment_to_asset_processor.rb +60 -0
  8. data/lib/sprockets/asset.rb +158 -210
  9. data/lib/sprockets/autoload/babel.rb +8 -0
  10. data/lib/sprockets/autoload/closure.rb +8 -0
  11. data/lib/sprockets/autoload/coffee_script.rb +8 -0
  12. data/lib/sprockets/autoload/eco.rb +8 -0
  13. data/lib/sprockets/autoload/ejs.rb +8 -0
  14. data/lib/sprockets/autoload/jsminc.rb +8 -0
  15. data/lib/sprockets/autoload/sass.rb +8 -0
  16. data/lib/sprockets/autoload/sassc.rb +8 -0
  17. data/lib/sprockets/autoload/uglifier.rb +8 -0
  18. data/lib/sprockets/autoload/yui.rb +8 -0
  19. data/lib/sprockets/autoload/zopfli.rb +7 -0
  20. data/lib/sprockets/autoload.rb +16 -0
  21. data/lib/sprockets/babel_processor.rb +66 -0
  22. data/lib/sprockets/base.rb +89 -378
  23. data/lib/sprockets/bower.rb +61 -0
  24. data/lib/sprockets/bundle.rb +105 -0
  25. data/lib/sprockets/cache/file_store.rb +190 -14
  26. data/lib/sprockets/cache/memory_store.rb +84 -0
  27. data/lib/sprockets/cache/null_store.rb +54 -0
  28. data/lib/sprockets/cache.rb +271 -0
  29. data/lib/sprockets/cached_environment.rb +64 -0
  30. data/lib/sprockets/closure_compressor.rb +48 -0
  31. data/lib/sprockets/coffee_script_processor.rb +39 -0
  32. data/lib/sprockets/compressing.rb +134 -0
  33. data/lib/sprockets/configuration.rb +79 -0
  34. data/lib/sprockets/context.rb +166 -150
  35. data/lib/sprockets/dependencies.rb +74 -0
  36. data/lib/sprockets/digest_utils.rb +197 -0
  37. data/lib/sprockets/directive_processor.rb +241 -215
  38. data/lib/sprockets/eco_processor.rb +33 -0
  39. data/lib/sprockets/ejs_processor.rb +32 -0
  40. data/lib/sprockets/encoding_utils.rb +261 -0
  41. data/lib/sprockets/environment.rb +23 -64
  42. data/lib/sprockets/erb_processor.rb +43 -0
  43. data/lib/sprockets/errors.rb +5 -13
  44. data/lib/sprockets/exporters/base.rb +71 -0
  45. data/lib/sprockets/exporters/file_exporter.rb +24 -0
  46. data/lib/sprockets/exporters/zlib_exporter.rb +33 -0
  47. data/lib/sprockets/exporters/zopfli_exporter.rb +14 -0
  48. data/lib/sprockets/exporting.rb +73 -0
  49. data/lib/sprockets/file_reader.rb +16 -0
  50. data/lib/sprockets/http_utils.rb +135 -0
  51. data/lib/sprockets/jsminc_compressor.rb +32 -0
  52. data/lib/sprockets/jst_processor.rb +36 -19
  53. data/lib/sprockets/loader.rb +347 -0
  54. data/lib/sprockets/manifest.rb +228 -112
  55. data/lib/sprockets/manifest_utils.rb +48 -0
  56. data/lib/sprockets/mime.rb +78 -31
  57. data/lib/sprockets/npm.rb +52 -0
  58. data/lib/sprockets/path_dependency_utils.rb +77 -0
  59. data/lib/sprockets/path_digest_utils.rb +48 -0
  60. data/lib/sprockets/path_utils.rb +367 -0
  61. data/lib/sprockets/paths.rb +43 -19
  62. data/lib/sprockets/preprocessors/default_source_map.rb +49 -0
  63. data/lib/sprockets/processing.rb +146 -164
  64. data/lib/sprockets/processor_utils.rb +170 -0
  65. data/lib/sprockets/resolve.rb +295 -0
  66. data/lib/sprockets/sass_cache_store.rb +20 -15
  67. data/lib/sprockets/sass_compressor.rb +55 -10
  68. data/lib/sprockets/sass_functions.rb +3 -70
  69. data/lib/sprockets/sass_importer.rb +3 -29
  70. data/lib/sprockets/sass_processor.rb +313 -0
  71. data/lib/sprockets/sassc_compressor.rb +56 -0
  72. data/lib/sprockets/sassc_processor.rb +297 -0
  73. data/lib/sprockets/server.rb +159 -91
  74. data/lib/sprockets/source_map_processor.rb +66 -0
  75. data/lib/sprockets/source_map_utils.rb +483 -0
  76. data/lib/sprockets/transformers.rb +173 -0
  77. data/lib/sprockets/uglifier_compressor.rb +66 -0
  78. data/lib/sprockets/unloaded_asset.rb +139 -0
  79. data/lib/sprockets/uri_tar.rb +99 -0
  80. data/lib/sprockets/uri_utils.rb +194 -0
  81. data/lib/sprockets/utils/gzip.rb +99 -0
  82. data/lib/sprockets/utils.rb +193 -52
  83. data/lib/sprockets/version.rb +2 -1
  84. data/lib/sprockets/yui_compressor.rb +56 -0
  85. data/lib/sprockets.rb +217 -75
  86. metadata +272 -117
  87. data/lib/sprockets/asset_attributes.rb +0 -131
  88. data/lib/sprockets/bundled_asset.rb +0 -80
  89. data/lib/sprockets/caching.rb +0 -96
  90. data/lib/sprockets/charset_normalizer.rb +0 -41
  91. data/lib/sprockets/eco_template.rb +0 -38
  92. data/lib/sprockets/ejs_template.rb +0 -37
  93. data/lib/sprockets/engines.rb +0 -74
  94. data/lib/sprockets/index.rb +0 -99
  95. data/lib/sprockets/processed_asset.rb +0 -152
  96. data/lib/sprockets/processor.rb +0 -32
  97. data/lib/sprockets/safety_colons.rb +0 -28
  98. data/lib/sprockets/sass_template.rb +0 -60
  99. data/lib/sprockets/scss_template.rb +0 -13
  100. data/lib/sprockets/static_asset.rb +0 -58
@@ -1,15 +1,13 @@
1
- require 'base64'
1
+ # frozen_string_literal: true
2
2
  require 'rack/utils'
3
- require 'sprockets/errors'
4
- require 'sprockets/utils'
5
- require 'pathname'
6
3
  require 'set'
4
+ require 'sprockets/errors'
5
+ require 'delegate'
7
6
 
8
7
  module Sprockets
9
- # `Context` provides helper methods to all `Tilt` processors. They
10
- # are typically accessed by ERB templates. You can mix in custom
11
- # helpers by injecting them into `Environment#context_class`. Do not
12
- # mix them into `Context` directly.
8
+ # They are typically accessed by ERB templates. You can mix in custom helpers
9
+ # by injecting them into `Environment#context_class`. Do not mix them into
10
+ # `Context` directly.
13
11
  #
14
12
  # environment.context_class.class_eval do
15
13
  # include MyHelper
@@ -21,102 +19,118 @@ module Sprockets
21
19
  # The `Context` also collects dependencies declared by
22
20
  # assets. See `DirectiveProcessor` for an example of this.
23
21
  class Context
24
- attr_reader :environment, :pathname
25
- attr_reader :_required_paths, :_stubbed_assets
26
- attr_reader :_dependency_paths, :_dependency_assets
27
- attr_writer :__LINE__
28
-
29
- def initialize(environment, logical_path, pathname)
30
- @environment = environment
31
- @logical_path = logical_path
32
- @pathname = pathname
33
- @__LINE__ = nil
34
-
35
- @_required_paths = []
36
- @_stubbed_assets = Set.new
37
- @_dependency_paths = Set.new
38
- @_dependency_assets = Set.new([pathname.to_s])
22
+ # Internal: Proxy for ENV that keeps track of the environment variables used
23
+ class ENVProxy < SimpleDelegator
24
+ def initialize(context)
25
+ @context = context
26
+ super(ENV)
27
+ end
28
+
29
+ def [](key)
30
+ @context.depend_on_env(key)
31
+ super
32
+ end
33
+
34
+ def fetch(key, *)
35
+ @context.depend_on_env(key)
36
+ super
37
+ end
38
+ end
39
+
40
+ attr_reader :environment, :filename
41
+
42
+ def initialize(input)
43
+ @environment = input[:environment]
44
+ @metadata = input[:metadata]
45
+ @load_path = input[:load_path]
46
+ @logical_path = input[:name]
47
+ @filename = input[:filename]
48
+ @dirname = File.dirname(@filename)
49
+ @content_type = input[:content_type]
50
+
51
+ @required = Set.new(@metadata[:required])
52
+ @stubbed = Set.new(@metadata[:stubbed])
53
+ @links = Set.new(@metadata[:links])
54
+ @dependencies = Set.new(input[:metadata][:dependencies])
55
+ end
56
+
57
+ def metadata
58
+ { required: @required,
59
+ stubbed: @stubbed,
60
+ links: @links,
61
+ dependencies: @dependencies }
62
+ end
63
+
64
+ def env_proxy
65
+ ENVProxy.new(self)
39
66
  end
40
67
 
41
68
  # Returns the environment path that contains the file.
42
69
  #
43
70
  # If `app/javascripts` and `app/stylesheets` are in your path, and
44
- # current file is `app/javascripts/foo/bar.js`, `root_path` would
71
+ # current file is `app/javascripts/foo/bar.js`, `load_path` would
45
72
  # return `app/javascripts`.
46
- def root_path
47
- environment.paths.detect { |path| pathname.to_s[path] }
48
- end
73
+ attr_reader :load_path
74
+ alias_method :root_path, :load_path
49
75
 
50
76
  # Returns logical path without any file extensions.
51
77
  #
52
78
  # 'app/javascripts/application.js'
53
79
  # # => 'application'
54
80
  #
55
- def logical_path
56
- @logical_path.chomp(File.extname(@logical_path))
57
- end
81
+ attr_reader :logical_path
58
82
 
59
83
  # Returns content type of file
60
84
  #
61
85
  # 'application/javascript'
62
86
  # 'text/css'
63
87
  #
64
- def content_type
65
- environment.content_type_of(pathname)
66
- end
88
+ attr_reader :content_type
67
89
 
68
- # Given a logical path, `resolve` will find and return the fully
69
- # expanded path. Relative paths will also be resolved. An optional
70
- # `:content_type` restriction can be supplied to restrict the
71
- # search.
90
+ # Public: Given a logical path, `resolve` will find and return an Asset URI.
91
+ # Relative paths will also be resolved. An accept type maybe given to
92
+ # restrict the search.
72
93
  #
73
94
  # resolve("foo.js")
74
- # # => "/path/to/app/javascripts/foo.js"
95
+ # # => "file:///path/to/app/javascripts/foo.js?type=application/javascript"
75
96
  #
76
97
  # resolve("./bar.js")
77
- # # => "/path/to/app/javascripts/bar.js"
98
+ # # => "file:///path/to/app/javascripts/bar.js?type=application/javascript"
78
99
  #
79
- def resolve(path, options = {}, &block)
80
- pathname = Pathname.new(path)
81
- attributes = environment.attributes_for(pathname)
82
-
83
- if pathname.absolute?
84
- if environment.stat(pathname)
85
- pathname
86
- else
87
- raise FileNotFound, "couldn't find file '#{pathname}'"
88
- end
89
-
90
- elsif content_type = options[:content_type]
91
- content_type = self.content_type if content_type == :self
92
-
93
- if attributes.format_extension
94
- if content_type != attributes.content_type
95
- raise ContentTypeMismatch, "#{path} is " +
96
- "'#{attributes.content_type}', not '#{content_type}'"
97
- end
98
- end
99
-
100
- resolve(path) do |candidate|
101
- if self.content_type == environment.content_type_of(candidate)
102
- return candidate
103
- end
104
- end
105
-
106
- raise FileNotFound, "couldn't find file '#{path}'"
107
- else
108
- environment.resolve(path, {:base_path => self.pathname.dirname}.merge(options), &block)
109
- end
100
+ # path - String logical or absolute path
101
+ # accept - String content accept type
102
+ #
103
+ # Returns an Asset URI String.
104
+ def resolve(path, **kargs)
105
+ kargs[:base_path] = @dirname
106
+ uri, deps = environment.resolve!(path, **kargs)
107
+ @dependencies.merge(deps)
108
+ uri
109
+ end
110
+
111
+ # Public: Load Asset by AssetURI and track it as a dependency.
112
+ #
113
+ # uri - AssetURI
114
+ #
115
+ # Returns Asset.
116
+ def load(uri)
117
+ asset = environment.load(uri)
118
+ @dependencies.merge(asset.metadata[:dependencies])
119
+ asset
110
120
  end
111
121
 
112
122
  # `depend_on` allows you to state a dependency on a file without
113
123
  # including it.
114
124
  #
115
125
  # This is used for caching purposes. Any changes made to
116
- # the dependency file with invalidate the cache of the
126
+ # the dependency file will invalidate the cache of the
117
127
  # source file.
118
128
  def depend_on(path)
119
- @_dependency_paths << resolve(path).to_s
129
+ if environment.absolute_path?(path) && environment.stat(path)
130
+ @dependencies << environment.build_file_digest_uri(path)
131
+ else
132
+ resolve(path)
133
+ end
120
134
  nil
121
135
  end
122
136
 
@@ -125,12 +139,19 @@ module Sprockets
125
139
  #
126
140
  # This is used for caching purposes. Any changes that would
127
141
  # invalidate the dependency asset will invalidate the source
128
- # file. Unlike `depend_on`, this will include recursively include
142
+ # file. Unlike `depend_on`, this will recursively include
129
143
  # the target asset's dependencies.
130
144
  def depend_on_asset(path)
131
- filename = resolve(path).to_s
132
- @_dependency_assets << filename
133
- nil
145
+ load(resolve(path))
146
+ end
147
+
148
+ # `depend_on_env` allows you to state a dependency on an environment
149
+ # variable.
150
+ #
151
+ # This is used for caching purposes. Any changes in the value of the
152
+ # environment variable will invalidate the cache of the source file.
153
+ def depend_on_env(key)
154
+ @dependencies << "env:#{key}"
134
155
  end
135
156
 
136
157
  # `require_asset` declares `path` as a dependency of the file. The
@@ -143,9 +164,7 @@ module Sprockets
143
164
  # <%= require_asset "#{framework}.js" %>
144
165
  #
145
166
  def require_asset(path)
146
- pathname = resolve(path, :content_type => :self)
147
- depend_on_asset(pathname)
148
- @_required_paths << pathname.to_s
167
+ @required << resolve(path, accept: @content_type, pipeline: :self)
149
168
  nil
150
169
  end
151
170
 
@@ -153,60 +172,25 @@ module Sprockets
153
172
  # `path` must be an asset which may or may not already be included
154
173
  # in the bundle.
155
174
  def stub_asset(path)
156
- @_stubbed_assets << resolve(path, :content_type => :self).to_s
175
+ @stubbed << resolve(path, accept: @content_type, pipeline: :self)
157
176
  nil
158
177
  end
159
178
 
160
- # Tests if target path is able to be safely required into the
161
- # current concatenation.
162
- def asset_requirable?(path)
163
- pathname = resolve(path)
164
- content_type = environment.content_type_of(pathname)
165
- stat = environment.stat(path)
166
- return false unless stat && stat.file?
167
- self.content_type.nil? || self.content_type == content_type
168
- end
169
-
170
- # Reads `path` and runs processors on the file.
171
- #
172
- # This allows you to capture the result of an asset and include it
173
- # directly in another.
174
- #
175
- # <%= evaluate "bar.js" %>
179
+ # `link_asset` declares an external dependency on an asset without directly
180
+ # including it. The target asset is returned from this function making it
181
+ # easy to construct a link to it.
176
182
  #
177
- def evaluate(path, options = {})
178
- pathname = resolve(path)
179
- attributes = environment.attributes_for(pathname)
180
- processors = options[:processors] || attributes.processors
181
-
182
- if options[:data]
183
- result = options[:data]
184
- else
185
- if environment.respond_to?(:default_external_encoding)
186
- mime_type = environment.mime_types(pathname.extname)
187
- encoding = environment.encoding_for_mime_type(mime_type)
188
- result = Sprockets::Utils.read_unicode(pathname, encoding)
189
- else
190
- result = Sprockets::Utils.read_unicode(pathname)
191
- end
192
- end
193
-
194
- processors.each do |processor|
195
- begin
196
- template = processor.new(pathname.to_s) { result }
197
- result = template.render(self, {})
198
- rescue Exception => e
199
- annotate_exception! e
200
- raise
201
- end
202
- end
203
-
204
- result
183
+ # Returns an Asset or nil.
184
+ def link_asset(path)
185
+ asset = depend_on_asset(path)
186
+ @links << asset.uri
187
+ asset
205
188
  end
206
189
 
207
- # Returns a Base64-encoded `data:` URI with the contents of the
208
- # asset at the specified path, and marks that path as a dependency
209
- # of the current file.
190
+ # Returns a `data:` URI with the contents of the asset at the specified
191
+ # path, and marks that path as a dependency of the current file.
192
+ #
193
+ # Uses URI encoding for SVG files, base64 encoding for all the other files.
210
194
  #
211
195
  # Use `asset_data_uri` from ERB with CSS or JavaScript assets:
212
196
  #
@@ -215,17 +199,19 @@ module Sprockets
215
199
  # $('<img>').attr('src', '<%= asset_data_uri 'avatar.jpg' %>')
216
200
  #
217
201
  def asset_data_uri(path)
218
- depend_on_asset(path)
219
- asset = environment.find_asset(path)
220
- base64 = Base64.encode64(asset.to_s).gsub(/\s+/, "")
221
- "data:#{asset.content_type};base64,#{Rack::Utils.escape(base64)}"
202
+ asset = depend_on_asset(path)
203
+ if asset.content_type == 'image/svg+xml'
204
+ svg_asset_data_uri(asset)
205
+ else
206
+ base64_asset_data_uri(asset)
207
+ end
222
208
  end
223
209
 
224
210
  # Expands logical path to full url to asset.
225
211
  #
226
212
  # NOTE: This helper is currently not implemented and should be
227
213
  # customized by the application. Though, in the future, some
228
- # basics implemention may be provided with different methods that
214
+ # basic implementation may be provided with different methods that
229
215
  # are required to be overridden.
230
216
  def asset_path(path, options = {})
231
217
  message = <<-EOS
@@ -243,47 +229,77 @@ Extend your environment context with a custom method.
243
229
 
244
230
  # Expand logical image asset path.
245
231
  def image_path(path)
246
- asset_path(path, :type => :image)
232
+ asset_path(path, type: :image)
247
233
  end
248
234
 
249
235
  # Expand logical video asset path.
250
236
  def video_path(path)
251
- asset_path(path, :type => :video)
237
+ asset_path(path, type: :video)
252
238
  end
253
239
 
254
240
  # Expand logical audio asset path.
255
241
  def audio_path(path)
256
- asset_path(path, :type => :audio)
242
+ asset_path(path, type: :audio)
257
243
  end
258
244
 
259
245
  # Expand logical font asset path.
260
246
  def font_path(path)
261
- asset_path(path, :type => :font)
247
+ asset_path(path, type: :font)
262
248
  end
263
249
 
264
250
  # Expand logical javascript asset path.
265
251
  def javascript_path(path)
266
- asset_path(path, :type => :javascript)
252
+ asset_path(path, type: :javascript)
267
253
  end
268
254
 
269
255
  # Expand logical stylesheet asset path.
270
256
  def stylesheet_path(path)
271
- asset_path(path, :type => :stylesheet)
257
+ asset_path(path, type: :stylesheet)
272
258
  end
273
259
 
274
- private
275
- # Annotates exception backtrace with the original template that
276
- # the exception was raised in.
277
- def annotate_exception!(exception)
278
- location = pathname.to_s
279
- location << ":#{@__LINE__}" if @__LINE__
260
+ protected
280
261
 
281
- exception.extend(Sprockets::EngineError)
282
- exception.sprockets_annotation = " (in #{location})"
283
- end
262
+ # Returns a URI-encoded data URI (always "-quoted).
263
+ def svg_asset_data_uri(asset)
264
+ svg = asset.source.dup
265
+ optimize_svg_for_uri_escaping!(svg)
266
+ data = Rack::Utils.escape(svg)
267
+ optimize_quoted_uri_escapes!(data)
268
+ "\"data:#{asset.content_type};charset=utf-8,#{data}\""
269
+ end
284
270
 
285
- def logger
286
- environment.logger
287
- end
271
+ # Returns a Base64-encoded data URI.
272
+ def base64_asset_data_uri(asset)
273
+ data = Rack::Utils.escape(EncodingUtils.base64(asset.source))
274
+ "data:#{asset.content_type};base64,#{data}"
275
+ end
276
+
277
+ # Optimizes an SVG for being URI-escaped.
278
+ #
279
+ # This method only performs these basic but crucial optimizations:
280
+ # * Replaces " with ', because ' does not need escaping.
281
+ # * Removes comments, meta, doctype, and newlines.
282
+ # * Collapses whitespace.
283
+ def optimize_svg_for_uri_escaping!(svg)
284
+ # Remove comments, xml meta, and doctype
285
+ svg.gsub!(/<!--.*?-->|<\?.*?\?>|<!.*?>/m, '')
286
+ # Replace consecutive whitespace and newlines with a space
287
+ svg.gsub!(/\s+/, ' ')
288
+ # Collapse inter-tag whitespace
289
+ svg.gsub!('> <', '><')
290
+ # Replace " with '
291
+ svg.gsub!(/([\w:])="(.*?)"/, "\\1='\\2'")
292
+ svg.strip!
293
+ end
294
+
295
+ # Un-escapes characters in the given URI-escaped string that do not need
296
+ # escaping in "-quoted data URIs.
297
+ def optimize_quoted_uri_escapes!(escaped)
298
+ escaped.gsub!('%3D', '=')
299
+ escaped.gsub!('%3A', ':')
300
+ escaped.gsub!('%2F', '/')
301
+ escaped.gsub!('%27', "'")
302
+ escaped.tr!('+', ' ')
303
+ end
288
304
  end
289
305
  end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+ require 'sprockets/digest_utils'
3
+ require 'sprockets/path_digest_utils'
4
+ require 'sprockets/uri_utils'
5
+
6
+ module Sprockets
7
+ # `Dependencies` is an internal mixin whose public methods are exposed on the
8
+ # `Environment` and `CachedEnvironment` classes.
9
+ module Dependencies
10
+ include DigestUtils, PathDigestUtils, URIUtils
11
+
12
+ # Public: Mapping dependency schemes to resolver functions.
13
+ #
14
+ # key - String scheme
15
+ # value - Proc.call(Environment, String)
16
+ #
17
+ # Returns Hash.
18
+ def dependency_resolvers
19
+ config[:dependency_resolvers]
20
+ end
21
+
22
+ # Public: Default set of dependency URIs for assets.
23
+ #
24
+ # Returns Set of String URIs.
25
+ def dependencies
26
+ config[:dependencies]
27
+ end
28
+
29
+ # Public: Register new dependency URI resolver.
30
+ #
31
+ # scheme - String scheme
32
+ # block -
33
+ # environment - Environment
34
+ # uri - String dependency URI
35
+ #
36
+ # Returns nothing.
37
+ def register_dependency_resolver(scheme, &block)
38
+ self.config = hash_reassoc(config, :dependency_resolvers) do |hash|
39
+ hash.merge(scheme => block)
40
+ end
41
+ end
42
+
43
+ # Public: Add environmental dependency inherited by all assets.
44
+ #
45
+ # uri - String dependency URI
46
+ #
47
+ # Returns nothing.
48
+ def add_dependency(uri)
49
+ self.config = hash_reassoc(config, :dependencies) do |set|
50
+ set + Set.new([uri])
51
+ end
52
+ end
53
+ alias_method :depend_on, :add_dependency
54
+
55
+ # Internal: Resolve dependency URIs.
56
+ #
57
+ # Returns resolved Object.
58
+ def resolve_dependency(str)
59
+ # Optimize for the most common scheme to
60
+ # save 22k allocations on an average Spree app.
61
+ scheme = if str.start_with?('file-digest:'.freeze)
62
+ 'file-digest'.freeze
63
+ else
64
+ str[/([^:]+)/, 1]
65
+ end
66
+
67
+ if resolver = config[:dependency_resolvers][scheme]
68
+ resolver.call(self, str)
69
+ else
70
+ nil
71
+ end
72
+ end
73
+ end
74
+ end