sprockets 3.0.3 → 4.2.0
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 +5 -5
- data/CHANGELOG.md +101 -0
- data/{LICENSE → MIT-LICENSE} +2 -2
- data/README.md +531 -276
- data/bin/sprockets +12 -7
- data/lib/rake/sprocketstask.rb +9 -4
- data/lib/sprockets/add_source_map_comment_to_asset_processor.rb +60 -0
- data/lib/sprockets/asset.rb +41 -28
- data/lib/sprockets/autoload/babel.rb +8 -0
- data/lib/sprockets/autoload/closure.rb +1 -0
- data/lib/sprockets/autoload/coffee_script.rb +1 -0
- data/lib/sprockets/autoload/eco.rb +1 -0
- data/lib/sprockets/autoload/ejs.rb +1 -0
- data/lib/sprockets/autoload/jsminc.rb +8 -0
- data/lib/sprockets/autoload/sass.rb +1 -0
- data/lib/sprockets/autoload/sassc.rb +8 -0
- data/lib/sprockets/autoload/uglifier.rb +1 -0
- data/lib/sprockets/autoload/yui.rb +1 -0
- data/lib/sprockets/autoload/zopfli.rb +7 -0
- data/lib/sprockets/autoload.rb +5 -0
- data/lib/sprockets/babel_processor.rb +66 -0
- data/lib/sprockets/base.rb +61 -13
- data/lib/sprockets/bower.rb +6 -3
- data/lib/sprockets/bundle.rb +41 -5
- data/lib/sprockets/cache/file_store.rb +32 -7
- data/lib/sprockets/cache/memory_store.rb +28 -10
- data/lib/sprockets/cache/null_store.rb +8 -0
- data/lib/sprockets/cache.rb +43 -6
- data/lib/sprockets/cached_environment.rb +15 -20
- data/lib/sprockets/closure_compressor.rb +6 -11
- data/lib/sprockets/coffee_script_processor.rb +20 -6
- data/lib/sprockets/compressing.rb +62 -2
- data/lib/sprockets/configuration.rb +5 -9
- data/lib/sprockets/context.rb +99 -25
- data/lib/sprockets/dependencies.rb +10 -9
- data/lib/sprockets/digest_utils.rb +103 -62
- data/lib/sprockets/directive_processor.rb +64 -36
- data/lib/sprockets/eco_processor.rb +4 -3
- data/lib/sprockets/ejs_processor.rb +4 -3
- data/lib/sprockets/encoding_utils.rb +1 -0
- data/lib/sprockets/environment.rb +9 -4
- data/lib/sprockets/erb_processor.rb +34 -21
- data/lib/sprockets/errors.rb +1 -0
- data/lib/sprockets/exporters/base.rb +71 -0
- data/lib/sprockets/exporters/file_exporter.rb +24 -0
- data/lib/sprockets/exporters/zlib_exporter.rb +33 -0
- data/lib/sprockets/exporters/zopfli_exporter.rb +14 -0
- data/lib/sprockets/exporting.rb +73 -0
- data/lib/sprockets/file_reader.rb +1 -0
- data/lib/sprockets/http_utils.rb +25 -7
- data/lib/sprockets/jsminc_compressor.rb +32 -0
- data/lib/sprockets/jst_processor.rb +11 -10
- data/lib/sprockets/loader.rb +244 -62
- data/lib/sprockets/manifest.rb +100 -46
- data/lib/sprockets/manifest_utils.rb +9 -6
- data/lib/sprockets/mime.rb +8 -42
- data/lib/sprockets/npm.rb +52 -0
- data/lib/sprockets/path_dependency_utils.rb +3 -11
- data/lib/sprockets/path_digest_utils.rb +2 -1
- data/lib/sprockets/path_utils.rb +107 -22
- data/lib/sprockets/paths.rb +1 -0
- data/lib/sprockets/preprocessors/default_source_map.rb +49 -0
- data/lib/sprockets/processing.rb +32 -52
- data/lib/sprockets/processor_utils.rb +38 -39
- data/lib/sprockets/resolve.rb +177 -97
- data/lib/sprockets/sass_cache_store.rb +1 -0
- data/lib/sprockets/sass_compressor.rb +21 -17
- data/lib/sprockets/sass_functions.rb +1 -0
- data/lib/sprockets/sass_importer.rb +1 -0
- data/lib/sprockets/sass_processor.rb +46 -18
- data/lib/sprockets/sassc_compressor.rb +56 -0
- data/lib/sprockets/sassc_processor.rb +297 -0
- data/lib/sprockets/server.rb +77 -44
- data/lib/sprockets/source_map_processor.rb +66 -0
- data/lib/sprockets/source_map_utils.rb +483 -0
- data/lib/sprockets/transformers.rb +63 -35
- data/lib/sprockets/uglifier_compressor.rb +23 -20
- data/lib/sprockets/unloaded_asset.rb +139 -0
- data/lib/sprockets/uri_tar.rb +99 -0
- data/lib/sprockets/uri_utils.rb +14 -14
- data/lib/sprockets/utils/gzip.rb +99 -0
- data/lib/sprockets/utils.rb +63 -71
- data/lib/sprockets/version.rb +2 -1
- data/lib/sprockets/yui_compressor.rb +5 -14
- data/lib/sprockets.rb +105 -33
- metadata +157 -27
- data/lib/sprockets/coffee_script_template.rb +0 -6
- data/lib/sprockets/eco_template.rb +0 -6
- data/lib/sprockets/ejs_template.rb +0 -6
- data/lib/sprockets/engines.rb +0 -81
- data/lib/sprockets/erb_template.rb +0 -6
- data/lib/sprockets/legacy.rb +0 -314
- data/lib/sprockets/legacy_proc_processor.rb +0 -35
- data/lib/sprockets/legacy_tilt_processor.rb +0 -29
- data/lib/sprockets/sass_template.rb +0 -7
data/lib/sprockets/context.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
require 'rack/utils'
|
3
3
|
require 'set'
|
4
4
|
require 'sprockets/errors'
|
5
|
+
require 'delegate'
|
5
6
|
|
6
7
|
module Sprockets
|
7
|
-
# Deprecated: `Context` provides helper methods to all processors.
|
8
8
|
# They are typically accessed by ERB templates. You can mix in custom helpers
|
9
9
|
# by injecting them into `Environment#context_class`. Do not mix them into
|
10
10
|
# `Context` directly.
|
@@ -19,10 +19,25 @@ module Sprockets
|
|
19
19
|
# The `Context` also collects dependencies declared by
|
20
20
|
# assets. See `DirectiveProcessor` for an example of this.
|
21
21
|
class Context
|
22
|
-
|
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
|
23
28
|
|
24
|
-
|
25
|
-
|
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
|
26
41
|
|
27
42
|
def initialize(input)
|
28
43
|
@environment = input[:environment]
|
@@ -31,7 +46,6 @@ module Sprockets
|
|
31
46
|
@logical_path = input[:name]
|
32
47
|
@filename = input[:filename]
|
33
48
|
@dirname = File.dirname(@filename)
|
34
|
-
@pathname = Pathname.new(@filename)
|
35
49
|
@content_type = input[:content_type]
|
36
50
|
|
37
51
|
@required = Set.new(@metadata[:required])
|
@@ -47,6 +61,10 @@ module Sprockets
|
|
47
61
|
dependencies: @dependencies }
|
48
62
|
end
|
49
63
|
|
64
|
+
def env_proxy
|
65
|
+
ENVProxy.new(self)
|
66
|
+
end
|
67
|
+
|
50
68
|
# Returns the environment path that contains the file.
|
51
69
|
#
|
52
70
|
# If `app/javascripts` and `app/stylesheets` are in your path, and
|
@@ -79,13 +97,13 @@ module Sprockets
|
|
79
97
|
# resolve("./bar.js")
|
80
98
|
# # => "file:///path/to/app/javascripts/bar.js?type=application/javascript"
|
81
99
|
#
|
82
|
-
# path
|
83
|
-
#
|
84
|
-
# accept - String content accept type
|
100
|
+
# path - String logical or absolute path
|
101
|
+
# accept - String content accept type
|
85
102
|
#
|
86
103
|
# Returns an Asset URI String.
|
87
|
-
def resolve(path,
|
88
|
-
|
104
|
+
def resolve(path, **kargs)
|
105
|
+
kargs[:base_path] = @dirname
|
106
|
+
uri, deps = environment.resolve!(path, **kargs)
|
89
107
|
@dependencies.merge(deps)
|
90
108
|
uri
|
91
109
|
end
|
@@ -105,15 +123,13 @@ module Sprockets
|
|
105
123
|
# including it.
|
106
124
|
#
|
107
125
|
# This is used for caching purposes. Any changes made to
|
108
|
-
# the dependency file
|
126
|
+
# the dependency file will invalidate the cache of the
|
109
127
|
# source file.
|
110
128
|
def depend_on(path)
|
111
|
-
path = path.to_s if path.is_a?(Pathname)
|
112
|
-
|
113
129
|
if environment.absolute_path?(path) && environment.stat(path)
|
114
130
|
@dependencies << environment.build_file_digest_uri(path)
|
115
131
|
else
|
116
|
-
resolve(path
|
132
|
+
resolve(path)
|
117
133
|
end
|
118
134
|
nil
|
119
135
|
end
|
@@ -123,10 +139,19 @@ module Sprockets
|
|
123
139
|
#
|
124
140
|
# This is used for caching purposes. Any changes that would
|
125
141
|
# invalidate the dependency asset will invalidate the source
|
126
|
-
# file. Unlike `depend_on`, this will
|
142
|
+
# file. Unlike `depend_on`, this will recursively include
|
127
143
|
# the target asset's dependencies.
|
128
144
|
def depend_on_asset(path)
|
129
|
-
load(resolve(path
|
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}"
|
130
155
|
end
|
131
156
|
|
132
157
|
# `require_asset` declares `path` as a dependency of the file. The
|
@@ -139,7 +164,7 @@ module Sprockets
|
|
139
164
|
# <%= require_asset "#{framework}.js" %>
|
140
165
|
#
|
141
166
|
def require_asset(path)
|
142
|
-
@required << resolve(path, accept: @content_type, pipeline: :self
|
167
|
+
@required << resolve(path, accept: @content_type, pipeline: :self)
|
143
168
|
nil
|
144
169
|
end
|
145
170
|
|
@@ -147,7 +172,7 @@ module Sprockets
|
|
147
172
|
# `path` must be an asset which may or may not already be included
|
148
173
|
# in the bundle.
|
149
174
|
def stub_asset(path)
|
150
|
-
@stubbed << resolve(path, accept: @content_type, pipeline: :self
|
175
|
+
@stubbed << resolve(path, accept: @content_type, pipeline: :self)
|
151
176
|
nil
|
152
177
|
end
|
153
178
|
|
@@ -162,9 +187,10 @@ module Sprockets
|
|
162
187
|
asset
|
163
188
|
end
|
164
189
|
|
165
|
-
# Returns a
|
166
|
-
#
|
167
|
-
#
|
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.
|
168
194
|
#
|
169
195
|
# Use `asset_data_uri` from ERB with CSS or JavaScript assets:
|
170
196
|
#
|
@@ -174,15 +200,18 @@ module Sprockets
|
|
174
200
|
#
|
175
201
|
def asset_data_uri(path)
|
176
202
|
asset = depend_on_asset(path)
|
177
|
-
|
178
|
-
|
203
|
+
if asset.content_type == 'image/svg+xml'
|
204
|
+
svg_asset_data_uri(asset)
|
205
|
+
else
|
206
|
+
base64_asset_data_uri(asset)
|
207
|
+
end
|
179
208
|
end
|
180
209
|
|
181
210
|
# Expands logical path to full url to asset.
|
182
211
|
#
|
183
212
|
# NOTE: This helper is currently not implemented and should be
|
184
213
|
# customized by the application. Though, in the future, some
|
185
|
-
#
|
214
|
+
# basic implementation may be provided with different methods that
|
186
215
|
# are required to be overridden.
|
187
216
|
def asset_path(path, options = {})
|
188
217
|
message = <<-EOS
|
@@ -227,5 +256,50 @@ Extend your environment context with a custom method.
|
|
227
256
|
def stylesheet_path(path)
|
228
257
|
asset_path(path, type: :stylesheet)
|
229
258
|
end
|
259
|
+
|
260
|
+
protected
|
261
|
+
|
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
|
270
|
+
|
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
|
230
304
|
end
|
231
305
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'sprockets/digest_utils'
|
2
3
|
require 'sprockets/path_digest_utils'
|
3
4
|
require 'sprockets/uri_utils'
|
@@ -39,7 +40,7 @@ module Sprockets
|
|
39
40
|
end
|
40
41
|
end
|
41
42
|
|
42
|
-
# Public: Add environmental dependency
|
43
|
+
# Public: Add environmental dependency inherited by all assets.
|
43
44
|
#
|
44
45
|
# uri - String dependency URI
|
45
46
|
#
|
@@ -51,18 +52,18 @@ module Sprockets
|
|
51
52
|
end
|
52
53
|
alias_method :depend_on, :add_dependency
|
53
54
|
|
54
|
-
# Internal: Resolve set of dependency URIs.
|
55
|
-
#
|
56
|
-
# Returns Array of resolved Objects.
|
57
|
-
def resolve_dependencies(uris)
|
58
|
-
uris.map { |uri| resolve_dependency(uri) }
|
59
|
-
end
|
60
|
-
|
61
55
|
# Internal: Resolve dependency URIs.
|
62
56
|
#
|
63
57
|
# Returns resolved Object.
|
64
58
|
def resolve_dependency(str)
|
65
|
-
|
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
|
+
|
66
67
|
if resolver = config[:dependency_resolvers][scheme]
|
67
68
|
resolver.call(self, str)
|
68
69
|
else
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
require 'digest/sha1'
|
3
3
|
require 'digest/sha2'
|
4
4
|
require 'set'
|
@@ -18,7 +18,6 @@ module Sprockets
|
|
18
18
|
|
19
19
|
# Internal: Maps digest bytesize to the digest class.
|
20
20
|
DIGEST_SIZES = {
|
21
|
-
16 => Digest::MD5,
|
22
21
|
20 => Digest::SHA1,
|
23
22
|
32 => Digest::SHA256,
|
24
23
|
48 => Digest::SHA384,
|
@@ -34,6 +33,49 @@ module Sprockets
|
|
34
33
|
DIGEST_SIZES[bytes.bytesize]
|
35
34
|
end
|
36
35
|
|
36
|
+
ADD_VALUE_TO_DIGEST = {
|
37
|
+
String => ->(val, digest) { digest << val },
|
38
|
+
FalseClass => ->(val, digest) { digest << 'FalseClass'.freeze },
|
39
|
+
TrueClass => ->(val, digest) { digest << 'TrueClass'.freeze },
|
40
|
+
NilClass => ->(val, digest) { digest << 'NilClass'.freeze },
|
41
|
+
|
42
|
+
Symbol => ->(val, digest) {
|
43
|
+
digest << 'Symbol'.freeze
|
44
|
+
digest << val.to_s
|
45
|
+
},
|
46
|
+
Integer => ->(val, digest) {
|
47
|
+
digest << 'Integer'.freeze
|
48
|
+
digest << val.to_s
|
49
|
+
},
|
50
|
+
Array => ->(val, digest) {
|
51
|
+
digest << 'Array'.freeze
|
52
|
+
val.each do |element|
|
53
|
+
ADD_VALUE_TO_DIGEST[element.class].call(element, digest)
|
54
|
+
end
|
55
|
+
},
|
56
|
+
Hash => ->(val, digest) {
|
57
|
+
digest << 'Hash'.freeze
|
58
|
+
val.sort.each do |array|
|
59
|
+
ADD_VALUE_TO_DIGEST[Array].call(array, digest)
|
60
|
+
end
|
61
|
+
},
|
62
|
+
Set => ->(val, digest) {
|
63
|
+
digest << 'Set'.freeze
|
64
|
+
ADD_VALUE_TO_DIGEST[Array].call(val, digest)
|
65
|
+
},
|
66
|
+
Encoding => ->(val, digest) {
|
67
|
+
digest << 'Encoding'.freeze
|
68
|
+
digest << val.name
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
72
|
+
ADD_VALUE_TO_DIGEST.compare_by_identity.rehash
|
73
|
+
|
74
|
+
ADD_VALUE_TO_DIGEST.default_proc = ->(_, val) {
|
75
|
+
raise TypeError, "couldn't digest #{ val }"
|
76
|
+
}
|
77
|
+
private_constant :ADD_VALUE_TO_DIGEST
|
78
|
+
|
37
79
|
# Internal: Generate a hexdigest for a nested JSON serializable object.
|
38
80
|
#
|
39
81
|
# This is used for generating cache keys, so its pretty important its
|
@@ -43,48 +85,18 @@ module Sprockets
|
|
43
85
|
#
|
44
86
|
# Returns a String digest of the object.
|
45
87
|
def digest(obj)
|
46
|
-
digest
|
47
|
-
|
48
|
-
|
49
|
-
while queue.length > 0
|
50
|
-
obj = queue.shift
|
51
|
-
klass = obj.class
|
52
|
-
|
53
|
-
if klass == String
|
54
|
-
digest << obj
|
55
|
-
elsif klass == Symbol
|
56
|
-
digest << 'Symbol'
|
57
|
-
digest << obj.to_s
|
58
|
-
elsif klass == Fixnum
|
59
|
-
digest << 'Fixnum'
|
60
|
-
digest << obj.to_s
|
61
|
-
elsif klass == Bignum
|
62
|
-
digest << 'Bignum'
|
63
|
-
digest << obj.to_s
|
64
|
-
elsif klass == TrueClass
|
65
|
-
digest << 'TrueClass'
|
66
|
-
elsif klass == FalseClass
|
67
|
-
digest << 'FalseClass'
|
68
|
-
elsif klass == NilClass
|
69
|
-
digest << 'NilClass'
|
70
|
-
elsif klass == Array
|
71
|
-
digest << 'Array'
|
72
|
-
queue.concat(obj)
|
73
|
-
elsif klass == Hash
|
74
|
-
digest << 'Hash'
|
75
|
-
queue.concat(obj.sort)
|
76
|
-
elsif klass == Set
|
77
|
-
digest << 'Set'
|
78
|
-
queue.concat(obj.to_a)
|
79
|
-
elsif klass == Encoding
|
80
|
-
digest << 'Encoding'
|
81
|
-
digest << obj.name
|
82
|
-
else
|
83
|
-
raise TypeError, "couldn't digest #{klass}"
|
84
|
-
end
|
85
|
-
end
|
88
|
+
build_digest(obj).digest
|
89
|
+
end
|
86
90
|
|
87
|
-
|
91
|
+
# Internal: Generate a hexdigest for a nested JSON serializable object.
|
92
|
+
#
|
93
|
+
# The same as `pack_hexdigest(digest(obj))`.
|
94
|
+
#
|
95
|
+
# obj - A JSON serializable object.
|
96
|
+
#
|
97
|
+
# Returns a String digest of the object.
|
98
|
+
def hexdigest(obj)
|
99
|
+
build_digest(obj).hexdigest!
|
88
100
|
end
|
89
101
|
|
90
102
|
# Internal: Pack a binary digest to a hex encoded string.
|
@@ -93,7 +105,16 @@ module Sprockets
|
|
93
105
|
#
|
94
106
|
# Returns hex String.
|
95
107
|
def pack_hexdigest(bin)
|
96
|
-
bin.unpack('H*').first
|
108
|
+
bin.unpack('H*'.freeze).first
|
109
|
+
end
|
110
|
+
|
111
|
+
# Internal: Unpack a hex encoded digest string into binary bytes.
|
112
|
+
#
|
113
|
+
# hex - String hex
|
114
|
+
#
|
115
|
+
# Returns binary String.
|
116
|
+
def unpack_hexdigest(hex)
|
117
|
+
[hex].pack('H*')
|
97
118
|
end
|
98
119
|
|
99
120
|
# Internal: Pack a binary digest to a base64 encoded string.
|
@@ -117,25 +138,20 @@ module Sprockets
|
|
117
138
|
str
|
118
139
|
end
|
119
140
|
|
120
|
-
# Internal: Maps digest class to the
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
Digest::
|
125
|
-
Digest::SHA384 => 'sha-384'.freeze,
|
126
|
-
Digest::SHA512 => 'sha-512'.freeze
|
141
|
+
# Internal: Maps digest class to the CSP hash algorithm name.
|
142
|
+
HASH_ALGORITHMS = {
|
143
|
+
Digest::SHA256 => 'sha256'.freeze,
|
144
|
+
Digest::SHA384 => 'sha384'.freeze,
|
145
|
+
Digest::SHA512 => 'sha512'.freeze
|
127
146
|
}
|
128
147
|
|
129
|
-
#
|
130
|
-
#
|
148
|
+
# Public: Generate hash for use in the `integrity` attribute of an asset tag
|
149
|
+
# as per the subresource integrity specification.
|
131
150
|
#
|
132
|
-
# digest
|
133
|
-
# content_type - The content-type the asset will be served with. This *must*
|
134
|
-
# be accurate if provided. Otherwise, subresource integrity
|
135
|
-
# will block the loading of the asset.
|
151
|
+
# digest - The String byte digest of the asset content.
|
136
152
|
#
|
137
153
|
# Returns a String or nil if hash algorithm is incompatible.
|
138
|
-
def integrity_uri(digest
|
154
|
+
def integrity_uri(digest)
|
139
155
|
case digest
|
140
156
|
when Digest::Base
|
141
157
|
digest_class = digest.class
|
@@ -146,11 +162,36 @@ module Sprockets
|
|
146
162
|
raise TypeError, "unknown digest: #{digest.inspect}"
|
147
163
|
end
|
148
164
|
|
149
|
-
if hash_name =
|
150
|
-
|
151
|
-
uri << "?ct=#{content_type}" if content_type
|
152
|
-
uri
|
165
|
+
if hash_name = HASH_ALGORITHMS[digest_class]
|
166
|
+
"#{hash_name}-#{pack_base64digest(digest)}"
|
153
167
|
end
|
154
168
|
end
|
169
|
+
|
170
|
+
# Public: Generate hash for use in the `integrity` attribute of an asset tag
|
171
|
+
# as per the subresource integrity specification.
|
172
|
+
#
|
173
|
+
# digest - The String hexbyte digest of the asset content.
|
174
|
+
#
|
175
|
+
# Returns a String or nil if hash algorithm is incompatible.
|
176
|
+
def hexdigest_integrity_uri(hexdigest)
|
177
|
+
integrity_uri(unpack_hexdigest(hexdigest))
|
178
|
+
end
|
179
|
+
|
180
|
+
# Internal: Checks an asset name for a valid digest
|
181
|
+
#
|
182
|
+
# name - The name of the asset
|
183
|
+
#
|
184
|
+
# Returns true if the name contains a digest like string and .digested before the extension
|
185
|
+
def already_digested?(name)
|
186
|
+
return name =~ /-([0-9a-zA-Z]{7,128})\.digested/
|
187
|
+
end
|
188
|
+
|
189
|
+
private
|
190
|
+
def build_digest(obj)
|
191
|
+
digest = digest_class.new
|
192
|
+
|
193
|
+
ADD_VALUE_TO_DIGEST[obj.class].call(obj, digest)
|
194
|
+
digest
|
195
|
+
end
|
155
196
|
end
|
156
197
|
end
|