sprockets 3.0.0 → 4.0.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 +68 -0
- data/README.md +397 -408
- data/bin/sprockets +12 -7
- data/lib/rake/sprocketstask.rb +3 -2
- data/lib/sprockets/add_source_map_comment_to_asset_processor.rb +60 -0
- data/lib/sprockets/asset.rb +19 -23
- 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 +59 -11
- data/lib/sprockets/bower.rb +5 -2
- data/lib/sprockets/bundle.rb +44 -4
- data/lib/sprockets/cache/file_store.rb +32 -7
- data/lib/sprockets/cache/memory_store.rb +9 -0
- data/lib/sprockets/cache/null_store.rb +8 -0
- data/lib/sprockets/cache.rb +42 -5
- data/lib/sprockets/cached_environment.rb +14 -19
- data/lib/sprockets/closure_compressor.rb +6 -11
- data/lib/sprockets/coffee_script_processor.rb +19 -5
- data/lib/sprockets/compressing.rb +62 -2
- data/lib/sprockets/configuration.rb +3 -7
- data/lib/sprockets/context.rb +98 -23
- data/lib/sprockets/dependencies.rb +9 -8
- data/lib/sprockets/digest_utils.rb +104 -60
- data/lib/sprockets/directive_processor.rb +45 -35
- data/lib/sprockets/eco_processor.rb +3 -2
- data/lib/sprockets/ejs_processor.rb +3 -2
- data/lib/sprockets/encoding_utils.rb +8 -4
- data/lib/sprockets/environment.rb +9 -4
- data/lib/sprockets/erb_processor.rb +28 -21
- data/lib/sprockets/errors.rb +1 -1
- data/lib/sprockets/exporters/base.rb +72 -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 +26 -6
- data/lib/sprockets/jsminc_compressor.rb +32 -0
- data/lib/sprockets/jst_processor.rb +11 -10
- data/lib/sprockets/loader.rb +236 -69
- data/lib/sprockets/manifest.rb +97 -44
- 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 +106 -21
- data/lib/sprockets/paths.rb +1 -0
- data/lib/sprockets/preprocessors/default_source_map.rb +49 -0
- data/lib/sprockets/processing.rb +31 -51
- data/lib/sprockets/processor_utils.rb +81 -15
- data/lib/sprockets/resolve.rb +182 -95
- 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 +45 -17
- data/lib/sprockets/sassc_compressor.rb +56 -0
- data/lib/sprockets/sassc_processor.rb +297 -0
- data/lib/sprockets/server.rb +57 -34
- 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 +15 -14
- data/lib/sprockets/utils/gzip.rb +99 -0
- data/lib/sprockets/utils.rb +43 -59
- data/lib/sprockets/version.rb +2 -1
- data/lib/sprockets/yui_compressor.rb +5 -14
- data/lib/sprockets.rb +103 -33
- metadata +151 -22
- data/LICENSE +0 -21
- 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,9 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
require 'rack/utils'
|
3
3
|
require 'set'
|
4
4
|
require 'sprockets/errors'
|
5
5
|
|
6
6
|
module Sprockets
|
7
|
-
# Deprecated: `Context` provides helper methods to all processors.
|
8
7
|
# They are typically accessed by ERB templates. You can mix in custom helpers
|
9
8
|
# by injecting them into `Environment#context_class`. Do not mix them into
|
10
9
|
# `Context` directly.
|
@@ -19,10 +18,25 @@ module Sprockets
|
|
19
18
|
# The `Context` also collects dependencies declared by
|
20
19
|
# assets. See `DirectiveProcessor` for an example of this.
|
21
20
|
class Context
|
22
|
-
|
21
|
+
# Internal: Proxy for ENV that keeps track of the environment variables used
|
22
|
+
class ENVProxy < SimpleDelegator
|
23
|
+
def initialize(context)
|
24
|
+
@context = context
|
25
|
+
super(ENV)
|
26
|
+
end
|
27
|
+
|
28
|
+
def [](key)
|
29
|
+
@context.depend_on_env(key)
|
30
|
+
super
|
31
|
+
end
|
32
|
+
|
33
|
+
def fetch(key, *)
|
34
|
+
@context.depend_on_env(key)
|
35
|
+
super
|
36
|
+
end
|
37
|
+
end
|
23
38
|
|
24
|
-
|
25
|
-
attr_accessor :__LINE__
|
39
|
+
attr_reader :environment, :filename
|
26
40
|
|
27
41
|
def initialize(input)
|
28
42
|
@environment = input[:environment]
|
@@ -31,7 +45,6 @@ module Sprockets
|
|
31
45
|
@logical_path = input[:name]
|
32
46
|
@filename = input[:filename]
|
33
47
|
@dirname = File.dirname(@filename)
|
34
|
-
@pathname = Pathname.new(@filename)
|
35
48
|
@content_type = input[:content_type]
|
36
49
|
|
37
50
|
@required = Set.new(@metadata[:required])
|
@@ -47,6 +60,10 @@ module Sprockets
|
|
47
60
|
dependencies: @dependencies }
|
48
61
|
end
|
49
62
|
|
63
|
+
def env_proxy
|
64
|
+
ENVProxy.new(self)
|
65
|
+
end
|
66
|
+
|
50
67
|
# Returns the environment path that contains the file.
|
51
68
|
#
|
52
69
|
# If `app/javascripts` and `app/stylesheets` are in your path, and
|
@@ -79,13 +96,13 @@ module Sprockets
|
|
79
96
|
# resolve("./bar.js")
|
80
97
|
# # => "file:///path/to/app/javascripts/bar.js?type=application/javascript"
|
81
98
|
#
|
82
|
-
# path
|
83
|
-
#
|
84
|
-
# accept - String content accept type
|
99
|
+
# path - String logical or absolute path
|
100
|
+
# accept - String content accept type
|
85
101
|
#
|
86
102
|
# Returns an Asset URI String.
|
87
|
-
def resolve(path,
|
88
|
-
|
103
|
+
def resolve(path, **kargs)
|
104
|
+
kargs[:base_path] = @dirname
|
105
|
+
uri, deps = environment.resolve!(path, **kargs)
|
89
106
|
@dependencies.merge(deps)
|
90
107
|
uri
|
91
108
|
end
|
@@ -105,13 +122,13 @@ module Sprockets
|
|
105
122
|
# including it.
|
106
123
|
#
|
107
124
|
# This is used for caching purposes. Any changes made to
|
108
|
-
# the dependency file
|
125
|
+
# the dependency file will invalidate the cache of the
|
109
126
|
# source file.
|
110
127
|
def depend_on(path)
|
111
|
-
if environment.absolute_path?(path) && environment.
|
128
|
+
if environment.absolute_path?(path) && environment.stat(path)
|
112
129
|
@dependencies << environment.build_file_digest_uri(path)
|
113
130
|
else
|
114
|
-
resolve(path
|
131
|
+
resolve(path)
|
115
132
|
end
|
116
133
|
nil
|
117
134
|
end
|
@@ -121,10 +138,19 @@ module Sprockets
|
|
121
138
|
#
|
122
139
|
# This is used for caching purposes. Any changes that would
|
123
140
|
# invalidate the dependency asset will invalidate the source
|
124
|
-
# file. Unlike `depend_on`, this will
|
141
|
+
# file. Unlike `depend_on`, this will recursively include
|
125
142
|
# the target asset's dependencies.
|
126
143
|
def depend_on_asset(path)
|
127
|
-
load(resolve(path
|
144
|
+
load(resolve(path))
|
145
|
+
end
|
146
|
+
|
147
|
+
# `depend_on_env` allows you to state a dependency on an environment
|
148
|
+
# variable.
|
149
|
+
#
|
150
|
+
# This is used for caching purposes. Any changes in the value of the
|
151
|
+
# environment variable will invalidate the cache of the source file.
|
152
|
+
def depend_on_env(key)
|
153
|
+
@dependencies << "env:#{key}"
|
128
154
|
end
|
129
155
|
|
130
156
|
# `require_asset` declares `path` as a dependency of the file. The
|
@@ -137,7 +163,7 @@ module Sprockets
|
|
137
163
|
# <%= require_asset "#{framework}.js" %>
|
138
164
|
#
|
139
165
|
def require_asset(path)
|
140
|
-
@required << resolve(path, accept: @content_type, pipeline: :self
|
166
|
+
@required << resolve(path, accept: @content_type, pipeline: :self)
|
141
167
|
nil
|
142
168
|
end
|
143
169
|
|
@@ -145,7 +171,7 @@ module Sprockets
|
|
145
171
|
# `path` must be an asset which may or may not already be included
|
146
172
|
# in the bundle.
|
147
173
|
def stub_asset(path)
|
148
|
-
@stubbed << resolve(path, accept: @content_type, pipeline: :self
|
174
|
+
@stubbed << resolve(path, accept: @content_type, pipeline: :self)
|
149
175
|
nil
|
150
176
|
end
|
151
177
|
|
@@ -160,9 +186,10 @@ module Sprockets
|
|
160
186
|
asset
|
161
187
|
end
|
162
188
|
|
163
|
-
# Returns a
|
164
|
-
#
|
165
|
-
#
|
189
|
+
# Returns a `data:` URI with the contents of the asset at the specified
|
190
|
+
# path, and marks that path as a dependency of the current file.
|
191
|
+
#
|
192
|
+
# Uses URI encoding for SVG files, base64 encoding for all the other files.
|
166
193
|
#
|
167
194
|
# Use `asset_data_uri` from ERB with CSS or JavaScript assets:
|
168
195
|
#
|
@@ -172,8 +199,11 @@ module Sprockets
|
|
172
199
|
#
|
173
200
|
def asset_data_uri(path)
|
174
201
|
asset = depend_on_asset(path)
|
175
|
-
|
176
|
-
|
202
|
+
if asset.content_type == 'image/svg+xml'
|
203
|
+
svg_asset_data_uri(asset)
|
204
|
+
else
|
205
|
+
base64_asset_data_uri(asset)
|
206
|
+
end
|
177
207
|
end
|
178
208
|
|
179
209
|
# Expands logical path to full url to asset.
|
@@ -225,5 +255,50 @@ Extend your environment context with a custom method.
|
|
225
255
|
def stylesheet_path(path)
|
226
256
|
asset_path(path, type: :stylesheet)
|
227
257
|
end
|
258
|
+
|
259
|
+
protected
|
260
|
+
|
261
|
+
# Returns a URI-encoded data URI (always "-quoted).
|
262
|
+
def svg_asset_data_uri(asset)
|
263
|
+
svg = asset.source.dup
|
264
|
+
optimize_svg_for_uri_escaping!(svg)
|
265
|
+
data = Rack::Utils.escape(svg)
|
266
|
+
optimize_quoted_uri_escapes!(data)
|
267
|
+
"\"data:#{asset.content_type};charset=utf-8,#{data}\""
|
268
|
+
end
|
269
|
+
|
270
|
+
# Returns a Base64-encoded data URI.
|
271
|
+
def base64_asset_data_uri(asset)
|
272
|
+
data = Rack::Utils.escape(EncodingUtils.base64(asset.source))
|
273
|
+
"data:#{asset.content_type};base64,#{data}"
|
274
|
+
end
|
275
|
+
|
276
|
+
# Optimizes an SVG for being URI-escaped.
|
277
|
+
#
|
278
|
+
# This method only performs these basic but crucial optimizations:
|
279
|
+
# * Replaces " with ', because ' does not need escaping.
|
280
|
+
# * Removes comments, meta, doctype, and newlines.
|
281
|
+
# * Collapses whitespace.
|
282
|
+
def optimize_svg_for_uri_escaping!(svg)
|
283
|
+
# Remove comments, xml meta, and doctype
|
284
|
+
svg.gsub!(/<!--.*?-->|<\?.*?\?>|<!.*?>/m, '')
|
285
|
+
# Replace consecutive whitespace and newlines with a space
|
286
|
+
svg.gsub!(/\s+/, ' ')
|
287
|
+
# Collapse inter-tag whitespace
|
288
|
+
svg.gsub!('> <', '><')
|
289
|
+
# Replace " with '
|
290
|
+
svg.gsub!(/([\w:])="(.*?)"/, "\\1='\\2'")
|
291
|
+
svg.strip!
|
292
|
+
end
|
293
|
+
|
294
|
+
# Un-escapes characters in the given URI-escaped string that do not need
|
295
|
+
# escaping in "-quoted data URIs.
|
296
|
+
def optimize_quoted_uri_escapes!(escaped)
|
297
|
+
escaped.gsub!('%3D', '=')
|
298
|
+
escaped.gsub!('%3A', ':')
|
299
|
+
escaped.gsub!('%2F', '/')
|
300
|
+
escaped.gsub!('%27', "'")
|
301
|
+
escaped.tr!('+', ' ')
|
302
|
+
end
|
228
303
|
end
|
229
304
|
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'
|
@@ -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,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'digest/md5'
|
2
3
|
require 'digest/sha1'
|
3
4
|
require 'digest/sha2'
|
@@ -34,6 +35,59 @@ module Sprockets
|
|
34
35
|
DIGEST_SIZES[bytes.bytesize]
|
35
36
|
end
|
36
37
|
|
38
|
+
ADD_VALUE_TO_DIGEST = {
|
39
|
+
String => ->(val, digest) { digest << val },
|
40
|
+
FalseClass => ->(val, digest) { digest << 'FalseClass'.freeze },
|
41
|
+
TrueClass => ->(val, digest) { digest << 'TrueClass'.freeze },
|
42
|
+
NilClass => ->(val, digest) { digest << 'NilClass'.freeze },
|
43
|
+
|
44
|
+
Symbol => ->(val, digest) {
|
45
|
+
digest << 'Symbol'.freeze
|
46
|
+
digest << val.to_s
|
47
|
+
},
|
48
|
+
Integer => ->(val, digest) {
|
49
|
+
digest << 'Integer'.freeze
|
50
|
+
digest << val.to_s
|
51
|
+
},
|
52
|
+
Array => ->(val, digest) {
|
53
|
+
digest << 'Array'.freeze
|
54
|
+
val.each do |element|
|
55
|
+
ADD_VALUE_TO_DIGEST[element.class].call(element, digest)
|
56
|
+
end
|
57
|
+
},
|
58
|
+
Hash => ->(val, digest) {
|
59
|
+
digest << 'Hash'.freeze
|
60
|
+
val.sort.each do |array|
|
61
|
+
ADD_VALUE_TO_DIGEST[Array].call(array, digest)
|
62
|
+
end
|
63
|
+
},
|
64
|
+
Set => ->(val, digest) {
|
65
|
+
digest << 'Set'.freeze
|
66
|
+
ADD_VALUE_TO_DIGEST[Array].call(val, digest)
|
67
|
+
},
|
68
|
+
Encoding => ->(val, digest) {
|
69
|
+
digest << 'Encoding'.freeze
|
70
|
+
digest << val.name
|
71
|
+
},
|
72
|
+
}
|
73
|
+
if 0.class != Integer # Ruby < 2.4
|
74
|
+
ADD_VALUE_TO_DIGEST[Fixnum] = ->(val, digest) {
|
75
|
+
digest << 'Integer'.freeze
|
76
|
+
digest << val.to_s
|
77
|
+
}
|
78
|
+
ADD_VALUE_TO_DIGEST[Bignum] = ->(val, digest) {
|
79
|
+
digest << 'Integer'.freeze
|
80
|
+
digest << val.to_s
|
81
|
+
}
|
82
|
+
end
|
83
|
+
|
84
|
+
ADD_VALUE_TO_DIGEST.compare_by_identity.rehash
|
85
|
+
|
86
|
+
ADD_VALUE_TO_DIGEST.default_proc = ->(_, val) {
|
87
|
+
raise TypeError, "couldn't digest #{ val }"
|
88
|
+
}
|
89
|
+
private_constant :ADD_VALUE_TO_DIGEST
|
90
|
+
|
37
91
|
# Internal: Generate a hexdigest for a nested JSON serializable object.
|
38
92
|
#
|
39
93
|
# This is used for generating cache keys, so its pretty important its
|
@@ -43,48 +97,18 @@ module Sprockets
|
|
43
97
|
#
|
44
98
|
# Returns a String digest of the object.
|
45
99
|
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
|
100
|
+
build_digest(obj).digest
|
101
|
+
end
|
86
102
|
|
87
|
-
|
103
|
+
# Internal: Generate a hexdigest for a nested JSON serializable object.
|
104
|
+
#
|
105
|
+
# The same as `pack_hexdigest(digest(obj))`.
|
106
|
+
#
|
107
|
+
# obj - A JSON serializable object.
|
108
|
+
#
|
109
|
+
# Returns a String digest of the object.
|
110
|
+
def hexdigest(obj)
|
111
|
+
build_digest(obj).hexdigest!
|
88
112
|
end
|
89
113
|
|
90
114
|
# Internal: Pack a binary digest to a hex encoded string.
|
@@ -93,7 +117,16 @@ module Sprockets
|
|
93
117
|
#
|
94
118
|
# Returns hex String.
|
95
119
|
def pack_hexdigest(bin)
|
96
|
-
bin.unpack('H*').first
|
120
|
+
bin.unpack('H*'.freeze).first
|
121
|
+
end
|
122
|
+
|
123
|
+
# Internal: Unpack a hex encoded digest string into binary bytes.
|
124
|
+
#
|
125
|
+
# hex - String hex
|
126
|
+
#
|
127
|
+
# Returns binary String.
|
128
|
+
def unpack_hexdigest(hex)
|
129
|
+
[hex].pack('H*')
|
97
130
|
end
|
98
131
|
|
99
132
|
# Internal: Pack a binary digest to a base64 encoded string.
|
@@ -117,25 +150,20 @@ module Sprockets
|
|
117
150
|
str
|
118
151
|
end
|
119
152
|
|
120
|
-
# Internal: Maps digest class to the
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
Digest::
|
125
|
-
Digest::SHA384 => 'sha-384'.freeze,
|
126
|
-
Digest::SHA512 => 'sha-512'.freeze
|
153
|
+
# Internal: Maps digest class to the CSP hash algorithm name.
|
154
|
+
HASH_ALGORITHMS = {
|
155
|
+
Digest::SHA256 => 'sha256'.freeze,
|
156
|
+
Digest::SHA384 => 'sha384'.freeze,
|
157
|
+
Digest::SHA512 => 'sha512'.freeze
|
127
158
|
}
|
128
159
|
|
129
|
-
#
|
130
|
-
#
|
160
|
+
# Public: Generate hash for use in the `integrity` attribute of an asset tag
|
161
|
+
# as per the subresource integrity specification.
|
131
162
|
#
|
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.
|
163
|
+
# digest - The String byte digest of the asset content.
|
136
164
|
#
|
137
165
|
# Returns a String or nil if hash algorithm is incompatible.
|
138
|
-
def integrity_uri(digest
|
166
|
+
def integrity_uri(digest)
|
139
167
|
case digest
|
140
168
|
when Digest::Base
|
141
169
|
digest_class = digest.class
|
@@ -146,11 +174,27 @@ module Sprockets
|
|
146
174
|
raise TypeError, "unknown digest: #{digest.inspect}"
|
147
175
|
end
|
148
176
|
|
149
|
-
if hash_name =
|
150
|
-
|
151
|
-
uri << "?ct=#{content_type}" if content_type
|
152
|
-
uri
|
177
|
+
if hash_name = HASH_ALGORITHMS[digest_class]
|
178
|
+
"#{hash_name}-#{pack_base64digest(digest)}"
|
153
179
|
end
|
154
180
|
end
|
181
|
+
|
182
|
+
# Public: Generate hash for use in the `integrity` attribute of an asset tag
|
183
|
+
# as per the subresource integrity specification.
|
184
|
+
#
|
185
|
+
# digest - The String hexbyte digest of the asset content.
|
186
|
+
#
|
187
|
+
# Returns a String or nil if hash algorithm is incompatible.
|
188
|
+
def hexdigest_integrity_uri(hexdigest)
|
189
|
+
integrity_uri(unpack_hexdigest(hexdigest))
|
190
|
+
end
|
191
|
+
|
192
|
+
private
|
193
|
+
def build_digest(obj)
|
194
|
+
digest = digest_class.new
|
195
|
+
|
196
|
+
ADD_VALUE_TO_DIGEST[obj.class].call(obj, digest)
|
197
|
+
digest
|
198
|
+
end
|
155
199
|
end
|
156
200
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'set'
|
2
3
|
require 'shellwords'
|
3
4
|
|
@@ -34,8 +35,6 @@ module Sprockets
|
|
34
35
|
# env.register_processor('text/css', MyProcessor)
|
35
36
|
#
|
36
37
|
class DirectiveProcessor
|
37
|
-
VERSION = '1'
|
38
|
-
|
39
38
|
# Directives are denoted by a `=` followed by the name, then
|
40
39
|
# argument list.
|
41
40
|
#
|
@@ -50,18 +49,16 @@ module Sprockets
|
|
50
49
|
/x
|
51
50
|
|
52
51
|
def self.instance
|
53
|
-
|
54
|
-
|
55
|
-
comments: ["//", ["/*", "*/"]] + ["#", ["###", "###"]]
|
56
|
-
)
|
52
|
+
# Default to C comment styles
|
53
|
+
@instance ||= new(comments: ["//", ["/*", "*/"]])
|
57
54
|
end
|
58
55
|
|
59
56
|
def self.call(input)
|
60
57
|
instance.call(input)
|
61
58
|
end
|
62
59
|
|
63
|
-
def initialize(
|
64
|
-
@header_pattern = compile_header_pattern(Array(
|
60
|
+
def initialize(comments: [])
|
61
|
+
@header_pattern = compile_header_pattern(Array(comments))
|
65
62
|
end
|
66
63
|
|
67
64
|
def call(input)
|
@@ -73,20 +70,28 @@ module Sprockets
|
|
73
70
|
@uri = input[:uri]
|
74
71
|
@filename = input[:filename]
|
75
72
|
@dirname = File.dirname(@filename)
|
76
|
-
|
73
|
+
# If loading a source map file like `application.js.map` resolve
|
74
|
+
# dependencies using `.js` instead of `.js.map`
|
75
|
+
@content_type = SourceMapProcessor.original_content_type(input[:content_type], error_when_not_found: false)
|
77
76
|
@required = Set.new(input[:metadata][:required])
|
78
77
|
@stubbed = Set.new(input[:metadata][:stubbed])
|
79
78
|
@links = Set.new(input[:metadata][:links])
|
80
79
|
@dependencies = Set.new(input[:metadata][:dependencies])
|
80
|
+
@to_link = Set.new
|
81
|
+
@to_load = Set.new
|
81
82
|
|
82
83
|
data, directives = process_source(input[:data])
|
83
84
|
process_directives(directives)
|
84
85
|
|
85
|
-
{
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
86
|
+
{
|
87
|
+
data: data,
|
88
|
+
required: @required,
|
89
|
+
stubbed: @stubbed,
|
90
|
+
links: @links,
|
91
|
+
to_load: @to_load,
|
92
|
+
to_link: @to_link,
|
93
|
+
dependencies: @dependencies
|
94
|
+
}
|
90
95
|
end
|
91
96
|
|
92
97
|
protected
|
@@ -116,9 +121,9 @@ module Sprockets
|
|
116
121
|
|
117
122
|
header, directives = extract_directives(header)
|
118
123
|
|
119
|
-
data = ""
|
124
|
+
data = +""
|
120
125
|
data.force_encoding(body.encoding)
|
121
|
-
data << header
|
126
|
+
data << header unless header.empty?
|
122
127
|
data << body
|
123
128
|
# Ensure body ends in a new line
|
124
129
|
data << "\n" if data.length > 0 && data[-1] != "\n"
|
@@ -134,7 +139,7 @@ module Sprockets
|
|
134
139
|
# [[1, "require", "foo"], [2, "require", "bar"]]
|
135
140
|
#
|
136
141
|
def extract_directives(header)
|
137
|
-
processed_header = ""
|
142
|
+
processed_header = +""
|
138
143
|
directives = []
|
139
144
|
|
140
145
|
header.lines.each_with_index do |line, index|
|
@@ -149,7 +154,11 @@ module Sprockets
|
|
149
154
|
processed_header << line
|
150
155
|
end
|
151
156
|
|
152
|
-
|
157
|
+
processed_header.chomp!
|
158
|
+
# Ensure header ends in a new line like before it was processed
|
159
|
+
processed_header << "\n" if processed_header.length > 0 && header[-1] == "\n"
|
160
|
+
|
161
|
+
return processed_header, directives
|
153
162
|
end
|
154
163
|
|
155
164
|
# Gathers comment directives in the source and processes them.
|
@@ -162,7 +171,7 @@ module Sprockets
|
|
162
171
|
# `process_require_glob_directive`.
|
163
172
|
#
|
164
173
|
# class DirectiveProcessor < Sprockets::DirectiveProcessor
|
165
|
-
# def process_require_glob_directive
|
174
|
+
# def process_require_glob_directive(glob)
|
166
175
|
# Dir["#{dirname}/#{glob}"].sort.each do |filename|
|
167
176
|
# require(filename)
|
168
177
|
# end
|
@@ -187,7 +196,7 @@ module Sprockets
|
|
187
196
|
|
188
197
|
# The `require` directive functions similar to Ruby's own `require`.
|
189
198
|
# It provides a way to declare a dependency on a file in your path
|
190
|
-
# and ensures
|
199
|
+
# and ensures it's only loaded once before the source file.
|
191
200
|
#
|
192
201
|
# `require` works with files in the environment path:
|
193
202
|
#
|
@@ -265,15 +274,15 @@ module Sprockets
|
|
265
274
|
# it.
|
266
275
|
#
|
267
276
|
# This is used for caching purposes. Any changes that would
|
268
|
-
#
|
269
|
-
# source file.
|
277
|
+
# invalidate the asset dependency will invalidate the cache of
|
278
|
+
# the source file.
|
270
279
|
#
|
271
280
|
# Unlike `depend_on`, the path must be a requirable asset.
|
272
281
|
#
|
273
282
|
# //= depend_on_asset "bar.js"
|
274
283
|
#
|
275
284
|
def process_depend_on_asset_directive(path)
|
276
|
-
|
285
|
+
to_load(resolve(path))
|
277
286
|
end
|
278
287
|
|
279
288
|
# Allows dependency to be excluded from the asset bundle.
|
@@ -297,7 +306,8 @@ module Sprockets
|
|
297
306
|
# /*= link "logo.png" */
|
298
307
|
#
|
299
308
|
def process_link_directive(path)
|
300
|
-
|
309
|
+
uri = to_load(resolve(path))
|
310
|
+
@to_link << uri
|
301
311
|
end
|
302
312
|
|
303
313
|
# `link_directory` links all the files inside a single
|
@@ -307,7 +317,7 @@ module Sprockets
|
|
307
317
|
# //= link_directory "./fonts"
|
308
318
|
#
|
309
319
|
# Use caution when linking against JS or CSS assets. Include an explicit
|
310
|
-
# extension or content type in these cases
|
320
|
+
# extension or content type in these cases.
|
311
321
|
#
|
312
322
|
# //= link_directory "./scripts" .js
|
313
323
|
#
|
@@ -323,7 +333,7 @@ module Sprockets
|
|
323
333
|
# //= link_tree "./images"
|
324
334
|
#
|
325
335
|
# Use caution when linking against JS or CSS assets. Include an explicit
|
326
|
-
# extension or content type in these cases
|
336
|
+
# extension or content type in these cases.
|
327
337
|
#
|
328
338
|
# //= link_tree "./styles" .css
|
329
339
|
#
|
@@ -354,15 +364,15 @@ module Sprockets
|
|
354
364
|
|
355
365
|
def link_paths(paths, deps, accept)
|
356
366
|
resolve_paths(paths, deps, accept: accept) do |uri|
|
357
|
-
@
|
367
|
+
@to_link << to_load(uri)
|
358
368
|
end
|
359
369
|
end
|
360
370
|
|
361
|
-
def resolve_paths(paths, deps,
|
371
|
+
def resolve_paths(paths, deps, **kargs)
|
362
372
|
@dependencies.merge(deps)
|
363
373
|
paths.each do |subpath, stat|
|
364
374
|
next if subpath == @filename || stat.directory?
|
365
|
-
uri, deps = @environment.resolve(subpath,
|
375
|
+
uri, deps = @environment.resolve(subpath, **kargs)
|
366
376
|
@dependencies.merge(deps)
|
367
377
|
yield uri if uri
|
368
378
|
end
|
@@ -384,19 +394,19 @@ module Sprockets
|
|
384
394
|
end
|
385
395
|
end
|
386
396
|
|
387
|
-
def
|
388
|
-
|
389
|
-
|
390
|
-
asset
|
397
|
+
def to_load(uri)
|
398
|
+
@to_load << uri
|
399
|
+
uri
|
391
400
|
end
|
392
401
|
|
393
|
-
def resolve(path,
|
402
|
+
def resolve(path, **kargs)
|
394
403
|
# Prevent absolute paths in directives
|
395
404
|
if @environment.absolute_path?(path)
|
396
405
|
raise FileOutsidePaths, "can't require absolute file: #{path}"
|
397
406
|
end
|
398
407
|
|
399
|
-
|
408
|
+
kargs[:base_path] = @dirname
|
409
|
+
uri, deps = @environment.resolve!(path, **kargs)
|
400
410
|
@dependencies.merge(deps)
|
401
411
|
uri
|
402
412
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'sprockets/autoload'
|
2
3
|
|
3
4
|
module Sprockets
|
@@ -12,7 +13,7 @@ module Sprockets
|
|
12
13
|
VERSION = '1'
|
13
14
|
|
14
15
|
def self.cache_key
|
15
|
-
@cache_key ||=
|
16
|
+
@cache_key ||= "#{name}:#{Autoload::Eco::Source::VERSION}:#{VERSION}".freeze
|
16
17
|
end
|
17
18
|
|
18
19
|
# Compile template data with Eco compiler.
|
@@ -24,7 +25,7 @@ module Sprockets
|
|
24
25
|
#
|
25
26
|
def self.call(input)
|
26
27
|
data = input[:data]
|
27
|
-
input[:cache].fetch(cache_key
|
28
|
+
input[:cache].fetch([cache_key, data]) do
|
28
29
|
Autoload::Eco.compile(data)
|
29
30
|
end
|
30
31
|
end
|