sprockets 4.0.0.beta7 → 4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 603199dd1236b7db51572143c09ce33649d81ecd2151d73d01d539b05fb14caa
4
- data.tar.gz: 84e1bf98ebe75d603c8e4ab0c813de0626812226c8315cccdc408bd46ac7e630
3
+ metadata.gz: 7bbf26f3dfff9a86ca4b4407072f1786fafed4040a2f3f25c875842dc834bdcf
4
+ data.tar.gz: 5a6dd07a6568dca18b5d1eca850a1e3a78030c20a6530781d8a16ac31c25649c
5
5
  SHA512:
6
- metadata.gz: 6ca211b8b2f1eadd44b4b199e9ffb88f12efcc844b11d86abd3dd7eb78abdb8fc7a24405d95eb6f53b89686cee97417ca47257fbafbe76d35193c4ac2bf5ba35
7
- data.tar.gz: dd22ed98ff05afe2820a24ca7bfb305ba7c1361a4854ecc69b467653297dffc6c872d17d66095561b0b4ef64f9bcee72999a150afa6b721fd0b0b77ada344d70
6
+ metadata.gz: fa3fb386fe8ded820388ff86e1b505736dadcf5e072fedc124c8635955af70df9db7386ce66f4e2d4f412c652e88df9c8dc93a451ac31b2982f0457393911202
7
+ data.tar.gz: 3dde983e601b16c7b4bc71343543c69b7b8787b70daaaad711bc45ec47b4dd53507d67f6b6a9c1f8de1a7069bfbc12f72c96a0eaa088f976187fe9d4ca8f78f8
@@ -2,7 +2,30 @@
2
2
 
3
3
  Get upgrade notes from Sprockets 3.x to 4.x at https://github.com/rails/sprockets/blob/master/UPGRADING.md
4
4
 
5
- ## Master
5
+ ## 4.0.1
6
+
7
+ - Fix for Ruby 2.7 keyword arguments warning in `base.rb`. [#660](https://github.com/rails/sprockets/pull/660)
8
+ - Fix for when `x_sprockets_linecount` is missing from a source map.
9
+ - Fix subresource integrity to match the digest of the asset.
10
+
11
+ ## 4.0.0
12
+
13
+ - Fixes for Ruby 2.7 keyword arguments warnings [#625](https://github.com/rails/sprockets/pull/625)
14
+ - Manifest files are sorted alphabetically [#626](https://github.com/rails/sprockets/pull/626)
15
+
16
+ ## 4.0.0.beta10
17
+
18
+ - Fix YACB (Yet Another Caching Bug) [Fix broken expansion of asset link paths](https://github.com/rails/sprockets/pull/614)
19
+
20
+ ## 4.0.0.beta9
21
+
22
+ - Minimum Ruby version for Sprockets 4 is now 2.5+ which matches minimum ruby verision of Rails [#604]
23
+ - Fix threading bug introduced in Sprockets 4 [#603]
24
+ - Warn when two potential manifest files exist. [#560]
25
+
26
+ ## 4.0.0.beta8
27
+
28
+ - Security release for [CVE-2018-3760](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-3760)
6
29
 
7
30
  ## 4.0.0.beta7
8
31
 
@@ -47,4 +70,3 @@ Get upgrade notes from Sprockets 3.x to 4.x at https://github.com/rails/sprocket
47
70
  - Initial release of Sprockets 4
48
71
 
49
72
  Please upgrade to the latest Sprockets 3 version before upgrading to Sprockets 4. Check the 3.x branch for previous changes https://github.com/rails/sprockets/blob/3.x/CHANGELOG.md.
50
-
data/README.md CHANGED
@@ -115,9 +115,9 @@ Here is a list of the available directives:
115
115
  - [`require_self`](#require_self) - Change order of where current contents are concatenated to current
116
116
  - [`require_directory`](#require_directory) - Add contents of each file in a folder to current
117
117
  - [`require_tree`](#require_tree) - Add contents of all files in all directories in a path to current
118
- - [`link`](#link) - Make target file compile and be publically available without adding contents to current
119
- - [`link_directory`](#link_directory) - Make target directory compile and be publically available without adding contents to current
120
- - [`link_tree`](#link_tree) - Make target tree compile and be publically available without adding contents to current
118
+ - [`link`](#link) - Make target file compile and be publicly available without adding contents to current
119
+ - [`link_directory`](#link_directory) - Make target directory compile and be publicly available without adding contents to current
120
+ - [`link_tree`](#link_tree) - Make target tree compile and be publicly available without adding contents to current
121
121
  - [`depend_on`](#depend_on) - Recompile current file if target has changed
122
122
  - [`stub`](#stub) - Ignore target file
123
123
 
@@ -363,37 +363,70 @@ directory specified by *path*.
363
363
  ### link
364
364
 
365
365
  `link` *path* declares a dependency on the target *path* and adds it to a list
366
- of subdependencies to automatically be compiled when the asset is written out to
366
+ of subdependencies to be compiled when the asset is written out to
367
367
  disk.
368
368
 
369
369
  Example:
370
370
 
371
- If you've got a `manifest.js` file and you want to explicitly make sure an `admin.js` file is
372
- generated and made available to the public you can link it like this:
371
+ If you've got a `manifest.js` file and you want to specify that a `admin.js` source file should be
372
+ generated and made available to the public you can link it by including this in the `manifest.js` file:
373
373
 
374
374
  ```
375
375
  //= link admin.js
376
376
  ```
377
377
 
378
+ The argument to `link` is a _logical path_, that is it will be resolved according to the
379
+ configured asset load paths. See [Accesing Assets](#accessing-assets) above. A path relative to
380
+ the current file won't work, it must be a logical path.
381
+
382
+ **Caution**: the "link" directive should always have an explicit extension on the end.
383
+
378
384
  ### link_directory
379
385
 
380
- `link_directory` *path* links all the files inside the directory specified by the *path*
386
+ `link_directory` *path* links all the files inside the directory specified by the *path*. By "link", we mean they are specified as compilation targets to be written out to disk, and made available to be served to user-agents.
387
+
388
+ Files in subdirectories will not be linked (Compare to [link_tree](#link_tree)).
389
+
390
+ The *path* argument to `link_directory` is _not_ a logical path (it does not use the asset load paths), but is a path relative to the file the `link_directory` directive is found in, and can use `..` to . For instance, you might want:
391
+
392
+ ```js
393
+ //= link_directory ../stylesheets
394
+ ```
395
+
396
+ `link_directory` can take an optional second argument with an extension or content-type, with the
397
+ two arguments separated by a space:
398
+
399
+ ```js
400
+ //= link_directory ../stylesheets text/css
401
+ //= link_directory ../more_stylesheets .css
402
+ ```
403
+
404
+ This will limit the matching files to link to only files recognized as that type. An extension is
405
+ just a shortcut for the type referenced, it does not need to match the source file exactly, but
406
+ instead identifies the content-type the source file must be recognized as.
381
407
 
382
408
  ### link_tree
383
409
 
384
- `link_tree` *path* works like `link_directory`, but operates
410
+ `link_tree` *path* works like [link_directory](#link_directory), but operates
385
411
  recursively to link all files in all subdirectories of the
386
412
  directory specified by *path*.
387
413
 
388
414
  Example:
389
415
 
390
- You can specify a file extension so any extra files will be ignored:
416
+ ```js
417
+ //= link_tree ./path/to/folder
418
+ ```
419
+
420
+ Like `link_directory`, the argument is path relative to the current file, it is *not* a 'logical path' tresolved against load paths.
421
+
422
+
423
+ As with `link_directory`, you can also specify a second argument -- separated by a space -- so any extra files not matching the content-type specified will be ignored:
391
424
 
392
425
  ```js
393
- //= link_tree path/to/folder .js
426
+ //= link_tree ./path/to/folder text/javascript
427
+ //= link_tree ./path/to/other_folder .js
394
428
  ```
395
429
 
396
- > Note: There is an intentional space between the path and the extension
397
430
 
398
431
  ### depend_on
399
432
 
@@ -119,8 +119,8 @@ module Sprockets
119
119
  register_bundle_processor 'application/javascript', Bundle
120
120
  register_bundle_processor 'text/css', Bundle
121
121
 
122
- register_bundle_metadata_reducer '*/*', :data, proc { String.new("") }, :concat
123
- register_bundle_metadata_reducer 'application/javascript', :data, proc { String.new("") }, Utils.method(:concat_javascript_sources)
122
+ register_bundle_metadata_reducer '*/*', :data, proc { +"" }, :concat
123
+ register_bundle_metadata_reducer 'application/javascript', :data, proc { +"" }, Utils.method(:concat_javascript_sources)
124
124
  register_bundle_metadata_reducer '*/*', :links, :+
125
125
  register_bundle_metadata_reducer '*/*', :sources, proc { [] }, :+
126
126
 
@@ -165,11 +165,11 @@ module Sprockets
165
165
  register_transformer 'application/javascript+function', 'application/javascript', JstProcessor
166
166
 
167
167
  # CSS processors
168
- require 'sprockets/sass_processor'
168
+ require 'sprockets/sassc_processor'
169
169
  register_mime_type 'text/sass', extensions: ['.sass', '.css.sass']
170
170
  register_mime_type 'text/scss', extensions: ['.scss', '.css.scss']
171
- register_transformer 'text/sass', 'text/css', SassProcessor
172
- register_transformer 'text/scss', 'text/css', ScssProcessor
171
+ register_transformer 'text/sass', 'text/css', SasscProcessor
172
+ register_transformer 'text/scss', 'text/css', ScsscProcessor
173
173
  register_preprocessor 'text/sass', DirectiveProcessor.new(comments: ["//", ["/*", "*/"]])
174
174
  register_preprocessor 'text/scss', DirectiveProcessor.new(comments: ["//", ["/*", "*/"]])
175
175
  register_bundle_metadata_reducer 'text/css', :sass_dependencies, Set.new, :+
@@ -123,13 +123,20 @@ module Sprockets
123
123
  metadata[:digest]
124
124
  end
125
125
 
126
+ # Private: Return the version of the environment where the asset was generated.
127
+ def environment_version
128
+ metadata[:environment_version]
129
+ end
130
+
126
131
  # Public: Returns String hexdigest of source.
127
132
  def hexdigest
128
133
  DigestUtils.pack_hexdigest(digest)
129
134
  end
130
135
 
131
136
  # Pubic: ETag String of Asset.
132
- alias_method :etag, :hexdigest
137
+ def etag
138
+ DigestUtils.pack_hexdigest(environment_version + digest)
139
+ end
133
140
 
134
141
  # Public: Returns String base64 digest of source.
135
142
  def base64digest
@@ -138,7 +145,7 @@ module Sprockets
138
145
 
139
146
  # Public: A "named information" URL for subresource integrity.
140
147
  def integrity
141
- DigestUtils.integrity_uri(metadata[:digest])
148
+ DigestUtils.integrity_uri(digest)
142
149
  end
143
150
 
144
151
  # Public: Add enumerator to allow `Asset` instances to be used as Rack
@@ -19,12 +19,12 @@ module Sprockets
19
19
 
20
20
  class DoubleLinkError < Sprockets::Error
21
21
  def initialize(parent_filename:, logical_path:, last_filename:, filename:)
22
- message = String.new
23
- message << "Multiple files with the same output path cannot be linked (#{logical_path.inspect})\n"
24
- message << "In #{parent_filename.inspect} these files were linked:\n"
25
- message << " - #{last_filename}\n"
26
- message << " - #{filename}\n"
27
- super(message)
22
+ super <<~MSG
23
+ Multiple files with the same output path cannot be linked (#{logical_path.inspect})
24
+ In #{parent_filename.inspect} these files were linked:
25
+ - #{last_filename}
26
+ - #{filename}
27
+ MSG
28
28
  end
29
29
  end
30
30
 
@@ -75,8 +75,8 @@ module Sprockets
75
75
  end
76
76
 
77
77
  # Find asset by logical path or expanded path.
78
- def find_asset(*args)
79
- uri, _ = resolve(*args)
78
+ def find_asset(*args, **options)
79
+ uri, _ = resolve(*args, **options)
80
80
  if uri
81
81
  load(uri)
82
82
  end
@@ -115,8 +115,8 @@ module Sprockets
115
115
  #
116
116
  # environment['application.js']
117
117
  #
118
- def [](*args)
119
- find_asset(*args)
118
+ def [](*args, **options)
119
+ find_asset(*args, **options)
120
120
  end
121
121
 
122
122
  # Find asset by logical path or expanded path.
@@ -137,8 +137,10 @@ module Sprockets
137
137
  #
138
138
  # Returns true
139
139
  def clear(options=nil)
140
- root_dirs = Dir.entries(@root).reject { |f| (EXCLUDED_DIRS + GITKEEP_FILES).include?(f) }
141
- FileUtils.rm_r(root_dirs.collect{ |f| File.join(@root, f) })
140
+ if File.exist?(@root)
141
+ root_dirs = Dir.entries(@root).reject { |f| (EXCLUDED_DIRS + GITKEEP_FILES).include?(f) }
142
+ FileUtils.rm_r(root_dirs.collect{ |f| File.join(@root, f) })
143
+ end
142
144
  true
143
145
  end
144
146
 
@@ -121,7 +121,7 @@ module Sprockets
121
121
 
122
122
  header, directives = extract_directives(header)
123
123
 
124
- data = String.new("")
124
+ data = +""
125
125
  data.force_encoding(body.encoding)
126
126
  data << header unless header.empty?
127
127
  data << body
@@ -139,7 +139,7 @@ module Sprockets
139
139
  # [[1, "require", "foo"], [2, "require", "bar"]]
140
140
  #
141
141
  def extract_directives(header)
142
- processed_header = String.new("")
142
+ processed_header = +""
143
143
  directives = []
144
144
 
145
145
  header.lines.each_with_index do |line, index|
@@ -27,8 +27,8 @@ module Sprockets
27
27
  end
28
28
  alias_method :index, :cached
29
29
 
30
- def find_asset(*args)
31
- cached.find_asset(*args)
30
+ def find_asset(*args, **options)
31
+ cached.find_asset(*args, **options)
32
32
  end
33
33
 
34
34
  def find_asset!(*args)
@@ -18,7 +18,12 @@ class Sprockets::ERBProcessor
18
18
  end
19
19
 
20
20
  def call(input)
21
- engine = ::ERB.new(input[:data], nil, '<>')
21
+ match = ERB.version.match(/\Aerb\.rb \[(?<version>[^ ]+) /)
22
+ if match && match[:version] >= "2.2.0" # Ruby 2.6+
23
+ engine = ::ERB.new(input[:data], trim_mode: '<>')
24
+ else
25
+ engine = ::ERB.new(input[:data], nil, '<>')
26
+ end
22
27
  engine.filename = input[:filename]
23
28
 
24
29
  context = input[:environment].context_class.new(input)
@@ -69,4 +69,3 @@ module Sprockets
69
69
  end
70
70
  end
71
71
  end
72
-
@@ -86,14 +86,16 @@ module Sprockets
86
86
  raise TypeError, "unknown q_values type: #{q_values.class}"
87
87
  end
88
88
 
89
+ i = 0
89
90
  q_values.each do |accepted, quality|
90
91
  if match = available.find { |option| matcher.call(option, accepted) }
91
- matches << [match, quality]
92
+ i += 1
93
+ matches << [-quality, i, match]
92
94
  end
93
95
  end
94
96
 
95
- matches.sort_by! { |match, quality| -quality }
96
- matches.map! { |match, quality| match }
97
+ matches.sort!
98
+ matches.map! { |_, _, match| match }
97
99
  matches
98
100
  end
99
101
 
@@ -64,6 +64,43 @@ module Sprockets
64
64
  end
65
65
 
66
66
  private
67
+ def compress_key_from_hash(hash, key)
68
+ return unless hash.key?(key)
69
+ value = hash[key].dup
70
+ return if !value
71
+
72
+ if block_given?
73
+ value.map! do |x|
74
+ if yield x
75
+ compress_from_root(x)
76
+ else
77
+ x
78
+ end
79
+ end
80
+ else
81
+ value.map! { |x| compress_from_root(x) }
82
+ end
83
+ hash[key] = value
84
+ end
85
+
86
+
87
+ def expand_key_from_hash(hash, key)
88
+ return unless hash.key?(key)
89
+ value = hash[key].dup
90
+ return if !value
91
+ if block_given?
92
+ value.map! do |x|
93
+ if yield x
94
+ expand_from_root(x)
95
+ else
96
+ x
97
+ end
98
+ end
99
+ else
100
+ value.map! { |x| expand_from_root(x) }
101
+ end
102
+ hash[key] = value
103
+ end
67
104
 
68
105
  # Internal: Load asset hash from cache
69
106
  #
@@ -77,17 +114,17 @@ module Sprockets
77
114
  asset[:uri] = expand_from_root(asset[:uri])
78
115
  asset[:load_path] = expand_from_root(asset[:load_path])
79
116
  asset[:filename] = expand_from_root(asset[:filename])
80
- asset[:metadata][:included].map! { |uri| expand_from_root(uri) } if asset[:metadata][:included]
81
- asset[:metadata][:links].map! { |uri| expand_from_root(uri) } if asset[:metadata][:links]
82
- asset[:metadata][:stubbed].map! { |uri| expand_from_root(uri) } if asset[:metadata][:stubbed]
83
- asset[:metadata][:required].map! { |uri| expand_from_root(uri) } if asset[:metadata][:required]
84
- asset[:metadata][:to_load].map! { |uri| expand_from_root(uri) } if asset[:metadata][:to_load]
85
- asset[:metadata][:to_link].map! { |uri| expand_from_root(uri) } if asset[:metadata][:to_link]
86
- asset[:metadata][:dependencies].map! { |uri| uri.start_with?("file-digest://") ? expand_from_root(uri) : uri } if asset[:metadata][:dependencies]
117
+ expand_key_from_hash(asset[:metadata], :included)
118
+ expand_key_from_hash(asset[:metadata], :links)
119
+ expand_key_from_hash(asset[:metadata], :stubbed)
120
+ expand_key_from_hash(asset[:metadata], :required)
121
+ expand_key_from_hash(asset[:metadata], :to_load)
122
+ expand_key_from_hash(asset[:metadata], :to_link)
123
+ expand_key_from_hash(asset[:metadata], :dependencies) { |uri| uri.start_with?("file-digest://") }
87
124
 
88
125
  asset[:metadata].each_key do |k|
89
- next unless k =~ /_dependencies\z/
90
- asset[:metadata][k].map! { |uri| expand_from_root(uri) }
126
+ next unless k.match?(/_dependencies\z/) # rubocop:disable Performance/EndWith
127
+ expand_key_from_hash(asset[:metadata], k)
91
128
  end
92
129
  end
93
130
  asset
@@ -158,14 +195,16 @@ module Sprockets
158
195
  source = result.delete(:data)
159
196
  metadata = result
160
197
  metadata[:charset] = source.encoding.name.downcase unless metadata.key?(:charset)
161
- metadata[:digest] = digest(self.version + source)
198
+ metadata[:digest] = digest(source)
162
199
  metadata[:length] = source.bytesize
200
+ metadata[:environment_version] = version
163
201
  else
164
202
  dependencies << build_file_digest_uri(unloaded.filename)
165
203
  metadata = {
166
204
  digest: file_digest(unloaded.filename),
167
205
  length: self.stat(unloaded.filename).size,
168
- dependencies: dependencies
206
+ dependencies: dependencies,
207
+ environment_version: version,
169
208
  }
170
209
  end
171
210
 
@@ -205,48 +244,17 @@ module Sprockets
205
244
  if cached_asset[:metadata]
206
245
  # Deep dup to avoid modifying `asset`
207
246
  cached_asset[:metadata] = cached_asset[:metadata].dup
208
- if cached_asset[:metadata][:included] && !cached_asset[:metadata][:included].empty?
209
- cached_asset[:metadata][:included] = cached_asset[:metadata][:included].dup
210
- cached_asset[:metadata][:included].map! { |uri| compress_from_root(uri) }
211
- end
212
-
213
- if cached_asset[:metadata][:links] && !cached_asset[:metadata][:links].empty?
214
- cached_asset[:metadata][:links] = cached_asset[:metadata][:links].dup
215
- cached_asset[:metadata][:links].map! { |uri| compress_from_root(uri) }
216
- end
217
-
218
- if cached_asset[:metadata][:stubbed] && !cached_asset[:metadata][:stubbed].empty?
219
- cached_asset[:metadata][:stubbed] = cached_asset[:metadata][:stubbed].dup
220
- cached_asset[:metadata][:stubbed].map! { |uri| compress_from_root(uri) }
221
- end
222
-
223
- if cached_asset[:metadata][:required] && !cached_asset[:metadata][:required].empty?
224
- cached_asset[:metadata][:required] = cached_asset[:metadata][:required].dup
225
- cached_asset[:metadata][:required].map! { |uri| compress_from_root(uri) }
226
- end
227
-
228
- if cached_asset[:metadata][:to_load] && !cached_asset[:metadata][:to_load].empty?
229
- cached_asset[:metadata][:to_load] = cached_asset[:metadata][:to_load].dup
230
- cached_asset[:metadata][:to_load].map! { |uri| compress_from_root(uri) }
231
- end
232
-
233
- if cached_asset[:metadata][:to_link] && !cached_asset[:metadata][:to_link].empty?
234
- cached_asset[:metadata][:to_link] = cached_asset[:metadata][:to_link].dup
235
- cached_asset[:metadata][:to_link].map! { |uri| compress_from_root(uri) }
236
- end
237
-
238
- if cached_asset[:metadata][:dependencies] && !cached_asset[:metadata][:dependencies].empty?
239
- cached_asset[:metadata][:dependencies] = cached_asset[:metadata][:dependencies].dup
240
- cached_asset[:metadata][:dependencies].map! do |uri|
241
- uri.start_with?("file-digest://".freeze) ? compress_from_root(uri) : uri
242
- end
243
- end
247
+ compress_key_from_hash(cached_asset[:metadata], :included)
248
+ compress_key_from_hash(cached_asset[:metadata], :links)
249
+ compress_key_from_hash(cached_asset[:metadata], :stubbed)
250
+ compress_key_from_hash(cached_asset[:metadata], :required)
251
+ compress_key_from_hash(cached_asset[:metadata], :to_load)
252
+ compress_key_from_hash(cached_asset[:metadata], :to_link)
253
+ compress_key_from_hash(cached_asset[:metadata], :dependencies) { |uri| uri.start_with?("file-digest://") }
244
254
 
245
- # compress all _dependencies in metadata like `sass_dependencies`
246
255
  cached_asset[:metadata].each do |key, value|
247
- next unless key =~ /_dependencies\z/
248
- cached_asset[:metadata][key] = value.dup
249
- cached_asset[:metadata][key].map! {|uri| compress_from_root(uri) }
256
+ next unless key.match?(/_dependencies\z/) # rubocop:disable Performance/EndWith
257
+ compress_key_from_hash(cached_asset[:metadata], key)
250
258
  end
251
259
  end
252
260
 
@@ -53,7 +53,7 @@ module Sprockets
53
53
 
54
54
  # If directory is given w/o filename, pick a random manifest location
55
55
  if @directory && @filename.nil?
56
- @filename = find_directory_manifest(@directory)
56
+ @filename = find_directory_manifest(@directory, logger)
57
57
  end
58
58
 
59
59
  unless @directory && @filename
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  require 'securerandom'
3
+ require 'logger'
3
4
 
4
5
  module Sprockets
5
6
  # Public: Manifest utilities.
@@ -33,10 +34,14 @@ module Sprockets
33
34
  # # => "/app/public/assets/.sprockets-manifest-abc123.json"
34
35
  #
35
36
  # Returns String filename.
36
- def find_directory_manifest(dirname)
37
+ def find_directory_manifest(dirname, logger = Logger.new($stderr))
37
38
  entries = File.directory?(dirname) ? Dir.entries(dirname) : []
38
- entry = entries.find { |e| e =~ MANIFEST_RE } ||
39
- generate_manifest_path
39
+ manifest_entries = entries.select { |e| e =~ MANIFEST_RE }
40
+ if manifest_entries.length > 1
41
+ manifest_entries.sort!
42
+ logger.warn("Found multiple manifests: #{manifest_entries}. Choosing the first alphabetically: #{manifest_entries.first}")
43
+ end
44
+ entry = manifest_entries.first || generate_manifest_path
40
45
  File.join(dirname, entry)
41
46
  end
42
47
  end
@@ -98,7 +98,7 @@ module Sprockets
98
98
  #
99
99
  # Returns true if path is relative, otherwise false.
100
100
  def relative_path?(path)
101
- path =~ /^\.\.?($|#{SEPARATOR_PATTERN})/ ? true : false
101
+ path.match?(/^\.\.?($|#{SEPARATOR_PATTERN})/) ? true : false
102
102
  end
103
103
 
104
104
  # Public: Get relative path from `start` to `dest`.
@@ -161,29 +161,9 @@ module Sprockets
161
161
  if !key.instance_of?(Symbol)
162
162
  raise TypeError, "processor metadata[#{key.inspect}] expected to be a Symbol"
163
163
  end
164
-
165
- if !valid_processor_metadata_value?(value)
166
- raise TypeError, "processor metadata[:#{key}] returned a complex type: #{value.inspect}\n" +
167
- "Only #{VALID_METADATA_TYPES.to_a.join(", ")} maybe used."
168
- end
169
164
  end
170
165
 
171
166
  result
172
167
  end
173
-
174
- # Internal: Validate object is in validate metadata whitelist.
175
- #
176
- # value - Any Object
177
- #
178
- # Returns true if class is in whitelist otherwise false.
179
- def valid_processor_metadata_value?(value)
180
- if VALID_METADATA_VALUE_TYPES_HASH[value.class]
181
- true
182
- elsif VALID_METADATA_COMPOUND_TYPES_HASH[value.class]
183
- value.all? { |v| valid_processor_metadata_value?(v) }
184
- else
185
- false
186
- end
187
- end
188
168
  end
189
169
  end
@@ -47,7 +47,7 @@ module Sprockets
47
47
  uri, deps = resolve(path, **kargs)
48
48
 
49
49
  unless uri
50
- message = String.new("couldn't find file '#{path}'")
50
+ message = +"couldn't find file '#{path}'"
51
51
 
52
52
  if relative_path?(path) && kargs[:base_path]
53
53
  load_path, _ = paths_split(config[:paths], kargs[:base_path])
@@ -1,10 +1,32 @@
1
1
  # frozen_string_literal: true
2
2
  require 'sprockets/autoload'
3
- require 'sprockets/sass_compressor'
4
- require 'base64'
3
+ require 'sprockets/source_map_utils'
5
4
 
6
5
  module Sprockets
7
- class SasscCompressor < SassCompressor
6
+ # Public: Sass CSS minifier.
7
+ #
8
+ # To accept the default options
9
+ #
10
+ # environment.register_bundle_processor 'text/css',
11
+ # Sprockets::SasscCompressor
12
+ #
13
+ # Or to pass options to the Sass::Engine class.
14
+ #
15
+ # environment.register_bundle_processor 'text/css',
16
+ # Sprockets::SasscCompressor.new({ ... })
17
+ #
18
+ class SasscCompressor
19
+ # Public: Return singleton instance with default options.
20
+ #
21
+ # Returns SasscCompressor object.
22
+ def self.instance
23
+ @instance ||= new
24
+ end
25
+
26
+ def self.call(input)
27
+ instance.call(input)
28
+ end
29
+
8
30
  def initialize(options = {})
9
31
  @options = {
10
32
  syntax: :scss,
@@ -1,17 +1,49 @@
1
1
  # frozen_string_literal: true
2
- require 'sprockets/sass_processor'
3
- require 'sprockets/path_utils'
4
- require 'base64'
2
+ require 'rack/utils'
3
+ require 'sprockets/autoload'
4
+ require 'sprockets/source_map_utils'
5
+ require 'uri'
5
6
 
6
7
  module Sprockets
7
- class SasscProcessor < SassProcessor
8
+ # Processor engine class for the SASS/SCSS compiler. Depends on the `sassc` gem.
9
+ #
10
+ # For more infomation see:
11
+ #
12
+ # https://github.com/sass/sassc-ruby
13
+ # https://github.com/sass/sassc-rails
14
+ #
15
+ class SasscProcessor
16
+
17
+ # Internal: Defines default sass syntax to use. Exposed so the ScsscProcessor
18
+ # may override it.
19
+ def self.syntax
20
+ :sass
21
+ end
22
+
23
+ # Public: Return singleton instance with default options.
24
+ #
25
+ # Returns SasscProcessor object.
26
+ def self.instance
27
+ @instance ||= new
28
+ end
29
+
30
+ def self.call(input)
31
+ instance.call(input)
32
+ end
33
+
34
+ def self.cache_key
35
+ instance.cache_key
36
+ end
37
+
38
+ attr_reader :cache_key
39
+
8
40
  def initialize(options = {}, &block)
9
41
  @cache_version = options[:cache_version]
10
42
  @cache_key = "#{self.class.name}:#{VERSION}:#{Autoload::SassC::VERSION}:#{@cache_version}".freeze
11
43
  @importer_class = options[:importer]
12
44
  @sass_config = options[:sass_config] || {}
13
45
  @functions = Module.new do
14
- include SassProcessor::Functions
46
+ include Functions
15
47
  include options[:functions] if options[:functions]
16
48
  class_eval(&block) if block_given?
17
49
  end
@@ -43,6 +75,201 @@ module Sprockets
43
75
 
44
76
  private
45
77
 
78
+ def merge_options(options)
79
+ defaults = @sass_config.dup
80
+
81
+ if load_paths = defaults.delete(:load_paths)
82
+ options[:load_paths] += load_paths
83
+ end
84
+
85
+ options.merge!(defaults)
86
+ options
87
+ end
88
+
89
+ # Public: Functions injected into Sass context during Sprockets evaluation.
90
+ #
91
+ # This module may be extended to add global functionality to all Sprockets
92
+ # Sass environments. Though, scoping your functions to just your environment
93
+ # is preferred.
94
+ #
95
+ # module Sprockets::SasscProcessor::Functions
96
+ # def asset_path(path, options = {})
97
+ # end
98
+ # end
99
+ #
100
+ module Functions
101
+ # Public: Generate a url for asset path.
102
+ #
103
+ # Default implementation is deprecated. Currently defaults to
104
+ # Context#asset_path.
105
+ #
106
+ # Will raise NotImplementedError in the future. Users should provide their
107
+ # own base implementation.
108
+ #
109
+ # Returns a SassC::Script::Value::String.
110
+ def asset_path(path, options = {})
111
+ path = path.value
112
+
113
+ path, _, query, fragment = URI.split(path)[5..8]
114
+ path = sprockets_context.asset_path(path, options)
115
+ query = "?#{query}" if query
116
+ fragment = "##{fragment}" if fragment
117
+
118
+ Autoload::SassC::Script::Value::String.new("#{path}#{query}#{fragment}", :string)
119
+ end
120
+
121
+ # Public: Generate a asset url() link.
122
+ #
123
+ # path - SassC::Script::Value::String URL path
124
+ #
125
+ # Returns a SassC::Script::Value::String.
126
+ def asset_url(path, options = {})
127
+ Autoload::SassC::Script::Value::String.new("url(#{asset_path(path, options).value})")
128
+ end
129
+
130
+ # Public: Generate url for image path.
131
+ #
132
+ # path - SassC::Script::Value::String URL path
133
+ #
134
+ # Returns a SassC::Script::Value::String.
135
+ def image_path(path)
136
+ asset_path(path, type: :image)
137
+ end
138
+
139
+ # Public: Generate a image url() link.
140
+ #
141
+ # path - SassC::Script::Value::String URL path
142
+ #
143
+ # Returns a SassC::Script::Value::String.
144
+ def image_url(path)
145
+ asset_url(path, type: :image)
146
+ end
147
+
148
+ # Public: Generate url for video path.
149
+ #
150
+ # path - SassC::Script::Value::String URL path
151
+ #
152
+ # Returns a SassC::Script::Value::String.
153
+ def video_path(path)
154
+ asset_path(path, type: :video)
155
+ end
156
+
157
+ # Public: Generate a video url() link.
158
+ #
159
+ # path - SassC::Script::Value::String URL path
160
+ #
161
+ # Returns a SassC::Script::Value::String.
162
+ def video_url(path)
163
+ asset_url(path, type: :video)
164
+ end
165
+
166
+ # Public: Generate url for audio path.
167
+ #
168
+ # path - SassC::Script::Value::String URL path
169
+ #
170
+ # Returns a SassC::Script::Value::String.
171
+ def audio_path(path)
172
+ asset_path(path, type: :audio)
173
+ end
174
+
175
+ # Public: Generate a audio url() link.
176
+ #
177
+ # path - SassC::Script::Value::String URL path
178
+ #
179
+ # Returns a SassC::Script::Value::String.
180
+ def audio_url(path)
181
+ asset_url(path, type: :audio)
182
+ end
183
+
184
+ # Public: Generate url for font path.
185
+ #
186
+ # path - SassC::Script::Value::String URL path
187
+ #
188
+ # Returns a SassC::Script::Value::String.
189
+ def font_path(path)
190
+ asset_path(path, type: :font)
191
+ end
192
+
193
+ # Public: Generate a font url() link.
194
+ #
195
+ # path - SassC::Script::Value::String URL path
196
+ #
197
+ # Returns a SassC::Script::Value::String.
198
+ def font_url(path)
199
+ asset_url(path, type: :font)
200
+ end
201
+
202
+ # Public: Generate url for javascript path.
203
+ #
204
+ # path - SassC::Script::Value::String URL path
205
+ #
206
+ # Returns a SassC::Script::Value::String.
207
+ def javascript_path(path)
208
+ asset_path(path, type: :javascript)
209
+ end
210
+
211
+ # Public: Generate a javascript url() link.
212
+ #
213
+ # path - SassC::Script::Value::String URL path
214
+ #
215
+ # Returns a SassC::Script::Value::String.
216
+ def javascript_url(path)
217
+ asset_url(path, type: :javascript)
218
+ end
219
+
220
+ # Public: Generate url for stylesheet path.
221
+ #
222
+ # path - SassC::Script::Value::String URL path
223
+ #
224
+ # Returns a SassC::Script::Value::String.
225
+ def stylesheet_path(path)
226
+ asset_path(path, type: :stylesheet)
227
+ end
228
+
229
+ # Public: Generate a stylesheet url() link.
230
+ #
231
+ # path - SassC::Script::Value::String URL path
232
+ #
233
+ # Returns a SassC::Script::Value::String.
234
+ def stylesheet_url(path)
235
+ asset_url(path, type: :stylesheet)
236
+ end
237
+
238
+ # Public: Generate a data URI for asset path.
239
+ #
240
+ # path - SassC::Script::Value::String logical asset path
241
+ #
242
+ # Returns a SassC::Script::Value::String.
243
+ def asset_data_url(path)
244
+ url = sprockets_context.asset_data_uri(path.value)
245
+ Autoload::SassC::Script::Value::String.new("url(" + url + ")")
246
+ end
247
+
248
+ protected
249
+ # Public: The Environment.
250
+ #
251
+ # Returns Sprockets::Environment.
252
+ def sprockets_environment
253
+ options[:sprockets][:environment]
254
+ end
255
+
256
+ # Public: Mutatable set of dependencies.
257
+ #
258
+ # Returns a Set.
259
+ def sprockets_dependencies
260
+ options[:sprockets][:dependencies]
261
+ end
262
+
263
+ # Deprecated: Get the Context instance. Use APIs on
264
+ # sprockets_environment or sprockets_dependencies directly.
265
+ #
266
+ # Returns a Context instance.
267
+ def sprockets_context
268
+ options[:sprockets][:context]
269
+ end
270
+
271
+ end
272
+
46
273
  def engine_options(input, context)
47
274
  merge_options({
48
275
  filename: input[:filename],
@@ -114,7 +114,7 @@ module Sprockets
114
114
  #
115
115
  # http://example.org/assets/../../../etc/passwd
116
116
  #
117
- path.include?("..") || absolute_path?(path)
117
+ path.include?("..") || absolute_path?(path) || path.include?("://")
118
118
  end
119
119
 
120
120
  def head_request?(env)
@@ -248,7 +248,7 @@ module Sprockets
248
248
  headers = {}
249
249
 
250
250
  # Set caching headers
251
- headers["Cache-Control"] = String.new("public")
251
+ headers["Cache-Control"] = +"public"
252
252
  headers["ETag"] = %("#{etag}")
253
253
 
254
254
  # If the request url contains a fingerprint, set a long
@@ -78,7 +78,7 @@ module Sprockets
78
78
  offset = 0
79
79
  if a["sections"].count != 0 && !a["sections"].last["map"]["mappings"].empty?
80
80
  last_line_count = a["sections"].last["map"].delete("x_sprockets_linecount")
81
- offset += last_line_count
81
+ offset += last_line_count || 1
82
82
 
83
83
  last_offset = a["sections"].last["offset"]["line"]
84
84
  offset += last_offset
@@ -428,21 +428,23 @@ module Sprockets
428
428
  # Returns an Array of Integers.
429
429
  def vlq_decode(str)
430
430
  result = []
431
- chars = str.split('')
432
- while chars.any?
433
- vlq = 0
434
- shift = 0
435
- continuation = true
436
- while continuation
437
- char = chars.shift
438
- raise ArgumentError unless char
439
- digit = BASE64_VALUES[char]
440
- continuation = false if (digit & VLQ_CONTINUATION_BIT) == 0
441
- digit &= VLQ_BASE_MASK
442
- vlq += digit << shift
431
+ shift = 0
432
+ value = 0
433
+ i = 0
434
+
435
+ while i < str.size do
436
+ digit = BASE64_VALUES[str[i]]
437
+ raise ArgumentError unless digit
438
+ continuation = (digit & VLQ_CONTINUATION_BIT) != 0
439
+ digit &= VLQ_BASE_MASK
440
+ value += digit << shift
441
+ if continuation
443
442
  shift += VLQ_BASE_SHIFT
443
+ else
444
+ result << ((value & 1) == 1 ? -(value >> 1) : value >> 1)
445
+ value = shift = 0
444
446
  end
445
- result << (vlq & 1 == 1 ? -(vlq >> 1) : vlq >> 1)
447
+ i += 1
446
448
  end
447
449
  result
448
450
  end
@@ -48,8 +48,10 @@ module Sprockets
48
48
  path = URI::Generic::DEFAULT_PARSER.unescape(path)
49
49
  path.force_encoding(Encoding::UTF_8)
50
50
 
51
- # Hack for parsing Windows "file:///C:/Users/IEUser" paths
52
- path.gsub!(/^\/([a-zA-Z]:)/, '\1'.freeze)
51
+ # Hack for parsing Windows "/C:/Users/IEUser" paths
52
+ if File::ALT_SEPARATOR && path[2] == ':'
53
+ path = path[1..-1]
54
+ end
53
55
 
54
56
  [scheme, host, path, query]
55
57
  end
@@ -58,7 +60,7 @@ module Sprockets
58
60
  #
59
61
  # Returns String.
60
62
  def join_file_uri(scheme, host, path, query)
61
- str = String.new("#{scheme}://")
63
+ str = +"#{scheme}://"
62
64
  str << host if host
63
65
  path = "/#{path}" unless path.start_with?("/".freeze)
64
66
  str << URI::Generic::DEFAULT_PARSER.escape(path)
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Sprockets
3
- VERSION = "4.0.0.beta7"
3
+ VERSION = "4.0.1"
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sprockets
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.0.beta7
4
+ version: 4.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Stephenson
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2018-03-13 00:00:00.000000000 Z
12
+ date: 2020-06-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack
@@ -171,6 +171,20 @@ dependencies:
171
171
  - - "~>"
172
172
  - !ruby/object:Gem::Version
173
173
  version: '1.1'
174
+ - !ruby/object:Gem::Dependency
175
+ name: timecop
176
+ requirement: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: 0.9.1
181
+ type: :development
182
+ prerelease: false
183
+ version_requirements: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - "~>"
186
+ - !ruby/object:Gem::Version
187
+ version: 0.9.1
174
188
  - !ruby/object:Gem::Dependency
175
189
  name: minitest
176
190
  requirement: !ruby/object:Gem::Requirement
@@ -219,14 +233,14 @@ dependencies:
219
233
  requirements:
220
234
  - - "~>"
221
235
  - !ruby/object:Gem::Version
222
- version: '10.0'
236
+ version: '12.0'
223
237
  type: :development
224
238
  prerelease: false
225
239
  version_requirements: !ruby/object:Gem::Requirement
226
240
  requirements:
227
241
  - - "~>"
228
242
  - !ruby/object:Gem::Version
229
- version: '10.0'
243
+ version: '12.0'
230
244
  - !ruby/object:Gem::Dependency
231
245
  name: sass
232
246
  requirement: !ruby/object:Gem::Requirement
@@ -245,20 +259,14 @@ dependencies:
245
259
  name: sassc
246
260
  requirement: !ruby/object:Gem::Requirement
247
261
  requirements:
248
- - - ">="
249
- - !ruby/object:Gem::Version
250
- version: 1.10.1
251
- - - "<"
262
+ - - "~>"
252
263
  - !ruby/object:Gem::Version
253
264
  version: '2.0'
254
265
  type: :development
255
266
  prerelease: false
256
267
  version_requirements: !ruby/object:Gem::Requirement
257
268
  requirements:
258
- - - ">="
259
- - !ruby/object:Gem::Version
260
- version: 1.10.1
261
- - - "<"
269
+ - - "~>"
262
270
  - !ruby/object:Gem::Version
263
271
  version: '2.0'
264
272
  - !ruby/object:Gem::Dependency
@@ -303,6 +311,20 @@ dependencies:
303
311
  - - "~>"
304
312
  - !ruby/object:Gem::Version
305
313
  version: 0.0.4
314
+ - !ruby/object:Gem::Dependency
315
+ name: rubocop-performance
316
+ requirement: !ruby/object:Gem::Requirement
317
+ requirements:
318
+ - - "~>"
319
+ - !ruby/object:Gem::Version
320
+ version: '1.3'
321
+ type: :development
322
+ prerelease: false
323
+ version_requirements: !ruby/object:Gem::Requirement
324
+ requirements:
325
+ - - "~>"
326
+ - !ruby/object:Gem::Version
327
+ version: '1.3'
306
328
  description: Sprockets is a Rack-based asset packaging system that concatenates and
307
329
  serves JavaScript, CoffeeScript, CSS, Sass, and SCSS.
308
330
  email:
@@ -408,15 +430,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
408
430
  requirements:
409
431
  - - ">="
410
432
  - !ruby/object:Gem::Version
411
- version: 2.2.0
433
+ version: 2.5.0
412
434
  required_rubygems_version: !ruby/object:Gem::Requirement
413
435
  requirements:
414
- - - ">"
436
+ - - ">="
415
437
  - !ruby/object:Gem::Version
416
- version: 1.3.1
438
+ version: '0'
417
439
  requirements: []
418
- rubyforge_project: sprockets
419
- rubygems_version: 2.7.6
440
+ rubygems_version: 3.1.2
420
441
  signing_key:
421
442
  specification_version: 4
422
443
  summary: Rack-based asset packaging system