sprockets 3.6.0 → 3.7.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: a1eef394792f4af6343438fcc3666a88ca893348
4
- data.tar.gz: 464e323e318b96534f12621a3f1a5dfc9a024425
2
+ SHA256:
3
+ metadata.gz: 46e0f0a150aa8333d2a1d2663167b6f20c1e77db067cea7b545f75927f770807
4
+ data.tar.gz: 5acd5cb5c64e240dd8180e91f34620195fa1433e625ee48a132fdae58be71ba5
5
5
  SHA512:
6
- metadata.gz: 446a6718c9ae7f0e94e57672680c7bbb2233855000dd813d3dc1867d0d3c6f12f3dcb43abe21f9a72bfcc05bff7524b9030eb771c342d4ea65fdde1169887f21
7
- data.tar.gz: e49c3925afb5988848f46439b1e9c3b5334932e599c13398f0a7a6a312dde2f228c0e679bd8fc898e80dd1861bc4fcfedfd807a9872b91b2af14be210870ab7d
6
+ metadata.gz: 97a06eb2e0767903da7bcda387211d881f3b98d57269a8abed5045e277db5f133f381c4f8fd23fcccf45a4032c85309841abba13b9218a52b21121a5a9bfc02a
7
+ data.tar.gz: 1d9c8d75bab64c366473226cc61806cd64c1951a67d90cc1220c1474e6a02cc5003b2dffb1b6324abefb7e7c8b292145635ac0bed6ae947a35393d67acd3c40e
data/CHANGELOG.md CHANGED
@@ -1,3 +1,30 @@
1
+ **3.7.2** (June 19, 2018)
2
+
3
+ * Security release for [CVE-2018-3760](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-3760).
4
+
5
+ **3.7.1** (December 19, 2016)
6
+
7
+ * Ruby 2.4 support for Sprockets 3.
8
+
9
+ **3.7.0** (July 21, 2016)
10
+
11
+ * Deprecated interfaces now emit deprecation warnings #345
12
+
13
+ **3.6.3** (July 1, 2016)
14
+
15
+ * Faster asset lookup in large directories #336
16
+ * Faster PathUtils.match_path_extname https://github.com/rails/sprockets/commit/697269cf81e5261fdd7072e32bd489403027fd7e
17
+ * Fixed uglifier comment stripping #326
18
+ * Error messages now show load path info #313
19
+
20
+ **3.6.2** (June 21, 2016)
21
+
22
+ * More performance improvements.
23
+
24
+ **3.6.1** (June 17, 2016)
25
+
26
+ * Some performance improvements.
27
+
1
28
  **3.6.0** (April 6, 2016)
2
29
 
3
30
  * Add `Manifest#find_sources` to return the source of the compiled assets.
@@ -84,7 +111,7 @@
84
111
 
85
112
  **3.0.0** (April 12, 2015)
86
113
 
87
- [Guide to upgrading from Sprockets 2.x to 3.x](https://github.com/rails/sprockets/blob/master/UPGRADING.md)
114
+ [Guide to upgrading from Sprockets 2.x to 3.x](https://github.com/rails/sprockets/blob/3.x/UPGRADING.md)
88
115
 
89
116
  * New processor API. Tilt interface is deprecated.
90
117
  * Improved file store caching backend.
data/bin/sprockets CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ $VERBOSE = nil
2
3
 
3
4
  require 'sprockets'
4
5
  require 'optparse'
@@ -36,7 +36,6 @@ module Sprockets
36
36
  # (default: 1000).
37
37
  def initialize(root, max_size = DEFAULT_MAX_SIZE, logger = self.class.default_logger)
38
38
  @root = root
39
- @size = find_caches.inject(0) { |n, (_, stat)| n + stat.size }
40
39
  @max_size = max_size
41
40
  @gc_size = max_size * 0.75
42
41
  @logger = logger
@@ -107,11 +106,11 @@ module Sprockets
107
106
  # Write data
108
107
  PathUtils.atomic_write(path) do |f|
109
108
  f.write(raw)
110
- @size += f.size unless exists
109
+ @size = size + f.size unless exists
111
110
  end
112
111
 
113
112
  # GC if necessary
114
- gc! if @size > @max_size
113
+ gc! if size > @max_size
115
114
 
116
115
  value
117
116
  end
@@ -120,7 +119,7 @@ module Sprockets
120
119
  #
121
120
  # Returns String.
122
121
  def inspect
123
- "#<#{self.class} size=#{@size}/#{@max_size}>"
122
+ "#<#{self.class} size=#{size}/#{@max_size}>"
124
123
  end
125
124
 
126
125
  private
@@ -138,6 +137,10 @@ module Sprockets
138
137
  }.sort_by { |_, stat| stat.mtime.to_i }
139
138
  end
140
139
 
140
+ def size
141
+ @size ||= compute_size(find_caches)
142
+ end
143
+
141
144
  def compute_size(caches)
142
145
  caches.inject(0) { |sum, (_, stat)| sum + stat.size }
143
146
  end
@@ -35,11 +35,12 @@ module Sprockets
35
35
  attr_reader :cache_key
36
36
 
37
37
  def initialize(options = {})
38
- @compiler = Autoload::Closure::Compiler.new(options)
38
+ @options = options
39
39
  @cache_key = "#{self.class.name}:#{Autoload::Closure::VERSION}:#{Autoload::Closure::COMPILER_VERSION}:#{VERSION}:#{DigestUtils.digest(options)}".freeze
40
40
  end
41
41
 
42
42
  def call(input)
43
+ @compiler ||= Autoload::Closure::Compiler.new(@options)
43
44
  @compiler.compile(input[:data])
44
45
  end
45
46
  end
@@ -2,5 +2,16 @@ require 'sprockets/coffee_script_processor'
2
2
 
3
3
  module Sprockets
4
4
  # Deprecated
5
- CoffeeScriptTemplate = CoffeeScriptProcessor
5
+ module CoffeeScriptTemplate
6
+ VERSION = CoffeeScriptProcessor::VERSION
7
+
8
+ def self.cache_key
9
+ CoffeeScriptProcessor.cache_key
10
+ end
11
+
12
+ def self.call(*args)
13
+ Deprecation.new.warn "CoffeeScriptTemplate is deprecated please use CoffeeScriptProcessor instead"
14
+ CoffeeScriptProcessor.call(*args)
15
+ end
16
+ end
6
17
  end
@@ -0,0 +1,90 @@
1
+ module Sprockets
2
+ class Deprecation
3
+ THREAD_LOCAL__SILENCE_KEY = "_sprockets_deprecation_silence".freeze
4
+ DEFAULT_BEHAVIORS = {
5
+ raise: ->(message, callstack) {
6
+ e = DeprecationException.new(message)
7
+ e.set_backtrace(callstack.map(&:to_s))
8
+ raise e
9
+ },
10
+
11
+ stderr: ->(message, callstack) {
12
+ $stderr.puts(message)
13
+ },
14
+ }
15
+
16
+ attr_reader :callstack
17
+
18
+ def self.silence(&block)
19
+ Thread.current[THREAD_LOCAL__SILENCE_KEY] = true
20
+ block.call
21
+ ensure
22
+ Thread.current[THREAD_LOCAL__SILENCE_KEY] = false
23
+ end
24
+
25
+ def initialize(callstack = nil)
26
+ @callstack = callstack || caller(2)
27
+ end
28
+
29
+ def warn(message)
30
+ return if Thread.current[THREAD_LOCAL__SILENCE_KEY]
31
+ deprecation_message(message).tap do |m|
32
+ behavior.each { |b| b.call(m, callstack) }
33
+ end
34
+ end
35
+
36
+ private
37
+ def behavior
38
+ @behavior ||= [DEFAULT_BEHAVIORS[:stderr]]
39
+ end
40
+
41
+ def behavior=(behavior)
42
+ @behavior = Array(behavior).map { |b| DEFAULT_BEHAVIORS[b] || b }
43
+ end
44
+
45
+ def deprecation_message(message = nil)
46
+ message ||= "You are using deprecated behavior which will be removed from the next major or minor release."
47
+ "DEPRECATION WARNING: #{message} #{ deprecation_caller_message }"
48
+ end
49
+
50
+ def deprecation_caller_message
51
+ file, line, method = extract_callstack
52
+ if file
53
+ if line && method
54
+ "(called from #{method} at #{file}:#{line})"
55
+ else
56
+ "(called from #{file}:#{line})"
57
+ end
58
+ end
59
+ end
60
+
61
+ SPROCKETS_GEM_ROOT = File.expand_path("../../../../..", __FILE__) + "/"
62
+
63
+ def ignored_callstack(path)
64
+ path.start_with?(SPROCKETS_GEM_ROOT) || path.start_with?(RbConfig::CONFIG['rubylibdir'])
65
+ end
66
+
67
+ def extract_callstack
68
+ return _extract_callstack if callstack.first.is_a? String
69
+
70
+ offending_line = callstack.find { |frame|
71
+ frame.absolute_path && !ignored_callstack(frame.absolute_path)
72
+ } || callstack.first
73
+
74
+ [offending_line.path, offending_line.lineno, offending_line.label]
75
+ end
76
+
77
+ def _extract_callstack
78
+ offending_line = callstack.find { |line| !ignored_callstack(line) } || callstack.first
79
+
80
+ if offending_line
81
+ if md = offending_line.match(/^(.+?):(\d+)(?::in `(.*?)')?/)
82
+ md.captures
83
+ else
84
+ offending_line
85
+ end
86
+ end
87
+ end
88
+ end
89
+ private_constant :Deprecation
90
+ end
@@ -34,6 +34,56 @@ module Sprockets
34
34
  DIGEST_SIZES[bytes.bytesize]
35
35
  end
36
36
 
37
+ ADD_VALUE_TO_DIGEST = {
38
+ String => ->(val, digest) { digest << val },
39
+ FalseClass => ->(val, digest) { digest << 'FalseClass'.freeze },
40
+ TrueClass => ->(val, digest) { digest << 'TrueClass'.freeze },
41
+ NilClass => ->(val, digest) { digest << 'NilClass'.freeze },
42
+
43
+ Symbol => ->(val, digest) {
44
+ digest << 'Symbol'.freeze
45
+ digest << val.to_s
46
+ },
47
+ Integer => ->(val, digest) {
48
+ digest << 'Integer'.freeze
49
+ digest << val.to_s
50
+ },
51
+ Array => ->(val, digest) {
52
+ digest << 'Array'.freeze
53
+ val.each do |element|
54
+ ADD_VALUE_TO_DIGEST[element.class].call(element, digest)
55
+ end
56
+ },
57
+ Hash => ->(val, digest) {
58
+ digest << 'Hash'.freeze
59
+ val.sort.each do |array|
60
+ ADD_VALUE_TO_DIGEST[Array].call(array, digest)
61
+ end
62
+ },
63
+ Set => ->(val, digest) {
64
+ digest << 'Set'.freeze
65
+ ADD_VALUE_TO_DIGEST[Array].call(val.to_a, digest)
66
+ },
67
+ Encoding => ->(val, digest) {
68
+ digest << 'Encoding'.freeze
69
+ digest << val.name
70
+ },
71
+ }
72
+ if 0.class != Integer # Ruby < 2.4
73
+ ADD_VALUE_TO_DIGEST[Fixnum] = ->(val, digest) {
74
+ digest << 'Integer'.freeze
75
+ digest << val.to_s
76
+ }
77
+ ADD_VALUE_TO_DIGEST[Bignum] = ->(val, digest) {
78
+ digest << 'Integer'.freeze
79
+ digest << val.to_s
80
+ }
81
+ end
82
+ ADD_VALUE_TO_DIGEST.default_proc = ->(_, val) {
83
+ raise TypeError, "couldn't digest #{ val }"
84
+ }
85
+ private_constant :ADD_VALUE_TO_DIGEST
86
+
37
87
  # Internal: Generate a hexdigest for a nested JSON serializable object.
38
88
  #
39
89
  # This is used for generating cache keys, so its pretty important its
@@ -44,46 +94,8 @@ module Sprockets
44
94
  # Returns a String digest of the object.
45
95
  def digest(obj)
46
96
  digest = digest_class.new
47
- queue = [obj]
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'.freeze
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
86
97
 
98
+ ADD_VALUE_TO_DIGEST[obj.class].call(obj, digest)
87
99
  digest.digest
88
100
  end
89
101
 
@@ -2,5 +2,16 @@ require 'sprockets/eco_processor'
2
2
 
3
3
  module Sprockets
4
4
  # Deprecated
5
- EcoTemplate = EcoProcessor
5
+ module EcoTemplate
6
+ VERSION = EcoProcessor::VERSION
7
+
8
+ def self.cache_key
9
+ EcoProcessor.cache_key
10
+ end
11
+
12
+ def self.call(*args)
13
+ Deprecation.new.warn "EcoTemplate is deprecated please use EcoProcessor instead"
14
+ EcoProcessor.call(*args)
15
+ end
16
+ end
6
17
  end
@@ -2,5 +2,16 @@ require 'sprockets/ejs_processor'
2
2
 
3
3
  module Sprockets
4
4
  # Deprecated
5
- EjsTemplate = EjsProcessor
5
+ module EjsTemplate
6
+ VERSION = EjsProcessor::VERSION
7
+
8
+ def self.cache_key
9
+ EjsProcessor.cache_key
10
+ end
11
+
12
+ def self.call(*args)
13
+ Deprecation.new.warn "EjsTemplate is deprecated please use EjsProcessor instead"
14
+ EjsProcessor.call(*args)
15
+ end
16
+ end
6
17
  end
@@ -51,6 +51,17 @@ module Sprockets
51
51
  # environment.register_engine '.coffee', CoffeeScriptProcessor
52
52
  #
53
53
  def register_engine(ext, klass, options = {})
54
+ unless options[:silence_deprecation]
55
+ msg = <<-MSG
56
+ Sprockets method `register_engine` is deprecated.
57
+ Please register a mime type using `register_mime_type` then
58
+ use `register_compressor` or `register_transformer`.
59
+ https://github.com/rails/sprockets/blob/master/guides/extending_sprockets.md#supporting-all-versions-of-sprockets-in-processors
60
+ MSG
61
+
62
+ Deprecation.new([caller.first]).warn(msg)
63
+ end
64
+
54
65
  ext = Sprockets::Utils.normalize_extension(ext)
55
66
 
56
67
  self.computed_config = {}
@@ -2,5 +2,10 @@ require 'sprockets/erb_processor'
2
2
 
3
3
  module Sprockets
4
4
  # Deprecated
5
- ERBTemplate = ERBProcessor
5
+ class ERBTemplate < ERBProcessor
6
+ def call(*args)
7
+ Deprecation.new.warn "ERBTemplate is deprecated please use ERBProcessor instead"
8
+ super
9
+ end
10
+ end
6
11
  end
@@ -161,7 +161,8 @@ module Sprockets
161
161
  end
162
162
  else
163
163
  args.each do |path|
164
- yield File.binread(File.join(dir, assets[path]))
164
+ asset = assets[path]
165
+ yield File.binread(File.join(dir, asset)) if asset
165
166
  end
166
167
  end
167
168
  end
@@ -55,7 +55,9 @@ module Sprockets
55
55
  if File.directory?(path)
56
56
  entries = Dir.entries(path, :encoding => Encoding.default_internal)
57
57
  entries.reject! { |entry|
58
- entry =~ /^\.|~$|^\#.*\#$/
58
+ entry.start_with?(".".freeze) ||
59
+ (entry.start_with?("#".freeze) && entry.end_with?("#".freeze)) ||
60
+ entry.end_with?("~".freeze)
59
61
  }
60
62
  entries.sort!
61
63
  else
@@ -146,16 +148,19 @@ module Sprockets
146
148
  #
147
149
  # Returns [String extname, Object value] or nil nothing matched.
148
150
  def match_path_extname(path, extensions)
149
- match, key = nil, ""
150
- path_extnames(path).reverse_each do |extname|
151
- key.prepend(extname)
152
- if value = extensions[key]
153
- match = [key.dup, value]
154
- elsif match
155
- break
151
+ basename = File.basename(path)
152
+
153
+ i = basename.index('.'.freeze)
154
+ while i && i < basename.length - 1
155
+ extname = basename[i..-1]
156
+ if value = extensions[extname]
157
+ return extname, value
156
158
  end
159
+
160
+ i = basename.index('.'.freeze, i+1)
157
161
  end
158
- match
162
+
163
+ nil
159
164
  end
160
165
 
161
166
  # Internal: Returns all parents for path
@@ -231,14 +231,24 @@ module Sprockets
231
231
  compute_transformers!
232
232
  end
233
233
 
234
+ def deprecate_legacy_processor_interface(interface)
235
+ msg = "You are using a deprecated processor interface #{ interface.inspect }.\n" +
236
+ "Please update your processor interface:\n" +
237
+ "https://github.com/rails/sprockets/blob/master/guides/extending_sprockets.md#supporting-all-versions-of-sprockets-in-processors\n"
238
+
239
+ Deprecation.new([caller[3]]).warn msg
240
+ end
241
+
234
242
  def wrap_processor(klass, proc)
235
243
  if !proc
236
244
  if klass.respond_to?(:call)
237
245
  klass
238
246
  else
247
+ deprecate_legacy_processor_interface(klass)
239
248
  LegacyTiltProcessor.new(klass)
240
249
  end
241
250
  elsif proc.respond_to?(:arity) && proc.arity == 2
251
+ deprecate_legacy_processor_interface(proc)
242
252
  LegacyProcProcessor.new(klass.to_s, proc)
243
253
  else
244
254
  proc
@@ -107,12 +107,10 @@ module Sprockets
107
107
  VALID_METADATA_VALUE_TYPES = Set.new([
108
108
  String,
109
109
  Symbol,
110
- Fixnum,
111
- Bignum,
112
110
  TrueClass,
113
111
  FalseClass,
114
112
  NilClass
115
- ]).freeze
113
+ ] + (0.class == Integer ? [Integer] : [Bignum, Fixnum])).freeze
116
114
 
117
115
  # Internal: Set of all nested compound metadata types that can nest values.
118
116
  VALID_METADATA_COMPOUND_TYPES = Set.new([
@@ -121,6 +119,17 @@ module Sprockets
121
119
  Set
122
120
  ]).freeze
123
121
 
122
+ # Internal: Hash of all "simple" value types allowed to be returned in
123
+ # processor metadata.
124
+ VALID_METADATA_VALUE_TYPES_HASH = VALID_METADATA_VALUE_TYPES.each_with_object({}) do |type, hash|
125
+ hash[type] = true
126
+ end.freeze
127
+
128
+ # Internal: Hash of all nested compound metadata types that can nest values.
129
+ VALID_METADATA_COMPOUND_TYPES_HASH = VALID_METADATA_COMPOUND_TYPES.each_with_object({}) do |type, hash|
130
+ hash[type] = true
131
+ end.freeze
132
+
124
133
  # Internal: Set of all allowed metadata types.
125
134
  VALID_METADATA_TYPES = (VALID_METADATA_VALUE_TYPES + VALID_METADATA_COMPOUND_TYPES).freeze
126
135
 
@@ -159,9 +168,9 @@ module Sprockets
159
168
  #
160
169
  # Returns true if class is in whitelist otherwise false.
161
170
  def valid_processor_metadata_value?(value)
162
- if VALID_METADATA_VALUE_TYPES.include?(value.class)
171
+ if VALID_METADATA_VALUE_TYPES_HASH[value.class]
163
172
  true
164
- elsif VALID_METADATA_COMPOUND_TYPES.include?(value.class)
173
+ elsif VALID_METADATA_COMPOUND_TYPES_HASH[value.class]
165
174
  value.all? { |v| valid_processor_metadata_value?(v) }
166
175
  else
167
176
  false
@@ -60,6 +60,7 @@ module Sprockets
60
60
  end
61
61
 
62
62
  message << " with type '#{options[:accept]}'" if options[:accept]
63
+ message << "\nChecked in these paths: \n #{ config[:paths].join("\n ") }"
63
64
 
64
65
  raise FileNotFound, message
65
66
  end
@@ -177,6 +178,7 @@ module Sprockets
177
178
  candidates = []
178
179
  entries = self.entries(dirname)
179
180
  entries.each do |entry|
181
+ next unless File.basename(entry).start_with?(basename)
180
182
  name, type, _, _ = parse_path_extnames(entry)
181
183
  if basename == name
182
184
  candidates << [File.join(dirname, entry), type]
@@ -25,5 +25,10 @@ module Sprockets
25
25
  end
26
26
 
27
27
  # Deprecated: Use Sprockets::SassProcessor::CacheStore instead.
28
- SassCacheStore = SassProcessor::CacheStore
28
+ class SassCacheStore < SassProcessor::CacheStore
29
+ def initialize(*args)
30
+ Deprecation.new.warn "SassCacheStore is deprecated please use SassProcessor::CacheStore instead"
31
+ super
32
+ end
33
+ end
29
34
  end
@@ -2,6 +2,18 @@ require 'sprockets/sass_processor'
2
2
 
3
3
  module Sprockets
4
4
  # Deprecated
5
- SassTemplate = SassProcessor
6
- ScssTemplate = ScssProcessor
5
+ class SassTemplate < SassProcessor
6
+ def self.call(*args)
7
+ Deprecation.new.warn "SassTemplate is deprecated please use SassProcessor instead"
8
+ super
9
+ end
10
+ end
11
+
12
+ # Deprecated
13
+ class ScssTemplate < ScssProcessor
14
+ def self.call(*args)
15
+ Deprecation.new.warn "ScssTemplate is deprecated please use ScssProcessor instead"
16
+ super
17
+ end
18
+ end
7
19
  end
@@ -23,7 +23,7 @@ module Sprockets
23
23
  start_time = Time.now.to_f
24
24
  time_elapsed = lambda { ((Time.now.to_f - start_time) * 1000).to_i }
25
25
 
26
- if env['REQUEST_METHOD'] != 'GET'
26
+ if !['GET', 'HEAD'].include?(env['REQUEST_METHOD'])
27
27
  return method_not_allowed_response
28
28
  end
29
29
 
@@ -39,7 +39,7 @@ module Sprockets
39
39
 
40
40
  # URLs containing a `".."` are rejected for security reasons.
41
41
  if forbidden_request?(path)
42
- return forbidden_response
42
+ return forbidden_response(env)
43
43
  end
44
44
 
45
45
  # Look up the asset.
@@ -86,10 +86,10 @@ module Sprockets
86
86
  not_modified_response(env, if_none_match)
87
87
  when :not_found
88
88
  logger.info "#{msg} 404 Not Found (#{time_elapsed.call}ms)"
89
- not_found_response
89
+ not_found_response(env)
90
90
  when :precondition_failed
91
91
  logger.info "#{msg} 412 Precondition Failed (#{time_elapsed.call}ms)"
92
- precondition_failed_response
92
+ precondition_failed_response(env)
93
93
  end
94
94
  rescue Exception => e
95
95
  logger.error "Error compiling asset #{path}:"
@@ -115,12 +115,20 @@ module Sprockets
115
115
  #
116
116
  # http://example.org/assets/../../../etc/passwd
117
117
  #
118
- path.include?("..") || absolute_path?(path)
118
+ path.include?("..") || absolute_path?(path) || path.include?("://")
119
+ end
120
+
121
+ def head_request?(env)
122
+ env['REQUEST_METHOD'] == 'HEAD'
119
123
  end
120
124
 
121
125
  # Returns a 200 OK response tuple
122
126
  def ok_response(asset, env)
123
- [ 200, headers(env, asset, asset.length), asset ]
127
+ if head_request?(env)
128
+ [ 200, headers(env, asset, 0), [] ]
129
+ else
130
+ [ 200, headers(env, asset, asset.length), asset ]
131
+ end
124
132
  end
125
133
 
126
134
  # Returns a 304 Not Modified response tuple
@@ -129,21 +137,33 @@ module Sprockets
129
137
  end
130
138
 
131
139
  # Returns a 403 Forbidden response tuple
132
- def forbidden_response
133
- [ 403, { "Content-Type" => "text/plain", "Content-Length" => "9" }, [ "Forbidden" ] ]
140
+ def forbidden_response(env)
141
+ if head_request?(env)
142
+ [ 403, { "Content-Type" => "text/plain", "Content-Length" => "0" }, [] ]
143
+ else
144
+ [ 403, { "Content-Type" => "text/plain", "Content-Length" => "9" }, [ "Forbidden" ] ]
145
+ end
134
146
  end
135
147
 
136
148
  # Returns a 404 Not Found response tuple
137
- def not_found_response
138
- [ 404, { "Content-Type" => "text/plain", "Content-Length" => "9", "X-Cascade" => "pass" }, [ "Not found" ] ]
149
+ def not_found_response(env)
150
+ if head_request?(env)
151
+ [ 404, { "Content-Type" => "text/plain", "Content-Length" => "0", "X-Cascade" => "pass" }, [] ]
152
+ else
153
+ [ 404, { "Content-Type" => "text/plain", "Content-Length" => "9", "X-Cascade" => "pass" }, [ "Not found" ] ]
154
+ end
139
155
  end
140
156
 
141
157
  def method_not_allowed_response
142
158
  [ 405, { "Content-Type" => "text/plain", "Content-Length" => "18" }, [ "Method Not Allowed" ] ]
143
159
  end
144
160
 
145
- def precondition_failed_response
146
- [ 412, { "Content-Type" => "text/plain", "Content-Length" => "19", "X-Cascade" => "pass" }, [ "Precondition Failed" ] ]
161
+ def precondition_failed_response(env)
162
+ if head_request?(env)
163
+ [ 412, { "Content-Type" => "text/plain", "Content-Length" => "0", "X-Cascade" => "pass" }, [] ]
164
+ else
165
+ [ 412, { "Content-Type" => "text/plain", "Content-Length" => "19", "X-Cascade" => "pass" }, [ "Precondition Failed" ] ]
166
+ end
147
167
  end
148
168
 
149
169
  # Returns a JavaScript response that re-throws a Ruby exception
@@ -41,14 +41,15 @@ module Sprockets
41
41
  options[:copyright] ||= false
42
42
  else
43
43
  # Uglifier >= 2.x
44
- options[:copyright] ||= :none
44
+ options[:comments] ||= :none
45
45
  end
46
46
 
47
- @uglifier = Autoload::Uglifier.new(options)
47
+ @options = options
48
48
  @cache_key = "#{self.class.name}:#{Autoload::Uglifier::VERSION}:#{VERSION}:#{DigestUtils.digest(options)}".freeze
49
49
  end
50
50
 
51
51
  def call(input)
52
+ @uglifier ||= Autoload::Uglifier.new(@options)
52
53
  @uglifier.compile(input[:data])
53
54
  end
54
55
  end
@@ -14,10 +14,8 @@ module Sprockets
14
14
  @env = env
15
15
  uri = uri.to_s
16
16
  if uri.include?("://".freeze)
17
- uri_array = uri.split("://".freeze)
18
- @scheme = uri_array.shift
19
- @scheme << "://".freeze
20
- @path = uri_array.join("".freeze)
17
+ @scheme, _, @path = uri.partition("://".freeze)
18
+ @scheme << "://".freeze
21
19
  else
22
20
  @scheme = "".freeze
23
21
  @path = uri
@@ -14,11 +14,15 @@ module Sprockets
14
14
  #
15
15
  # Returns false if .dup would raise a TypeError, otherwise true.
16
16
  def duplicable?(obj)
17
- case obj
18
- when NilClass, FalseClass, TrueClass, Symbol, Numeric
19
- false
20
- else
17
+ if RUBY_VERSION >= "2.4.0"
21
18
  true
19
+ else
20
+ case obj
21
+ when NilClass, FalseClass, TrueClass, Symbol, Numeric
22
+ false
23
+ else
24
+ true
25
+ end
22
26
  end
23
27
  end
24
28
 
@@ -74,16 +78,19 @@ module Sprockets
74
78
  def string_end_with_semicolon?(str)
75
79
  i = str.size - 1
76
80
  while i >= 0
77
- c = str[i]
81
+ c = str[i].ord
78
82
  i -= 1
79
- if c == "\n" || c == " " || c == "\t"
80
- next
81
- elsif c != ";"
82
- return false
83
- else
84
- return true
83
+
84
+ # Need to compare against the ordinals because the string can be UTF_8 or UTF_32LE encoded
85
+ # 0x0A == "\n"
86
+ # 0x20 == " "
87
+ # 0x09 == "\t"
88
+ # 0x3B == ";"
89
+ unless c == 0x0A || c == 0x20 || c == 0x09
90
+ return c === 0x3B
85
91
  end
86
92
  end
93
+
87
94
  true
88
95
  end
89
96
 
@@ -95,11 +102,21 @@ module Sprockets
95
102
  #
96
103
  # Returns buf String.
97
104
  def concat_javascript_sources(buf, source)
98
- if buf.bytesize > 0
99
- buf << ";" unless string_end_with_semicolon?(buf)
100
- buf << "\n" unless buf.end_with?("\n")
105
+ if source.bytesize > 0
106
+ buf << source
107
+
108
+ # If the source contains non-ASCII characters, indexing on it becomes O(N).
109
+ # This will lead to O(N^2) performance in string_end_with_semicolon?, so we should use 32 bit encoding to make sure indexing stays O(1)
110
+ source = source.encode(Encoding::UTF_32LE) unless source.ascii_only?
111
+
112
+ if !string_end_with_semicolon?(source)
113
+ buf << ";\n"
114
+ elsif source[source.size - 1].ord != 0x0A
115
+ buf << "\n"
116
+ end
101
117
  end
102
- buf << source
118
+
119
+ buf
103
120
  end
104
121
 
105
122
  # Internal: Prepends a leading "." to an extension if its missing.
@@ -1,3 +1,3 @@
1
1
  module Sprockets
2
- VERSION = "3.6.0"
2
+ VERSION = "3.7.2"
3
3
  end
data/lib/sprockets.rb CHANGED
@@ -4,6 +4,7 @@ require 'sprockets/cache'
4
4
  require 'sprockets/environment'
5
5
  require 'sprockets/errors'
6
6
  require 'sprockets/manifest'
7
+ require 'sprockets/deprecation'
7
8
 
8
9
  module Sprockets
9
10
  require 'sprockets/processor_utils'
@@ -122,25 +123,31 @@ module Sprockets
122
123
 
123
124
  # Mmm, CoffeeScript
124
125
  require 'sprockets/coffee_script_processor'
125
- register_engine '.coffee', CoffeeScriptProcessor, mime_type: 'application/javascript'
126
+ Deprecation.silence do
127
+ register_engine '.coffee', CoffeeScriptProcessor, mime_type: 'application/javascript', silence_deprecation: true
128
+ end
126
129
 
127
130
  # JST engines
128
131
  require 'sprockets/eco_processor'
129
132
  require 'sprockets/ejs_processor'
130
133
  require 'sprockets/jst_processor'
131
- register_engine '.jst', JstProcessor, mime_type: 'application/javascript'
132
- register_engine '.eco', EcoProcessor, mime_type: 'application/javascript'
133
- register_engine '.ejs', EjsProcessor, mime_type: 'application/javascript'
134
+ Deprecation.silence do
135
+ register_engine '.jst', JstProcessor, mime_type: 'application/javascript', silence_deprecation: true
136
+ register_engine '.eco', EcoProcessor, mime_type: 'application/javascript', silence_deprecation: true
137
+ register_engine '.ejs', EjsProcessor, mime_type: 'application/javascript', silence_deprecation: true
138
+ end
134
139
 
135
140
  # CSS engines
136
141
  require 'sprockets/sass_processor'
137
- register_engine '.sass', SassProcessor, mime_type: 'text/css'
138
- register_engine '.scss', ScssProcessor, mime_type: 'text/css'
142
+ Deprecation.silence do
143
+ register_engine '.sass', SassProcessor, mime_type: 'text/css', silence_deprecation: true
144
+ register_engine '.scss', ScssProcessor, mime_type: 'text/css', silence_deprecation: true
145
+ end
139
146
  register_bundle_metadata_reducer 'text/css', :sass_dependencies, Set.new, :+
140
147
 
141
148
  # Other
142
149
  require 'sprockets/erb_processor'
143
- register_engine '.erb', ERBProcessor, mime_type: 'text/plain'
150
+ register_engine '.erb', ERBProcessor, mime_type: 'text/plain', silence_deprecation: true
144
151
 
145
152
  register_dependency_resolver 'environment-version' do |env|
146
153
  env.version
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: 3.6.0
4
+ version: 3.7.2
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: 2016-04-06 00:00:00.000000000 Z
12
+ date: 2018-06-19 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack
@@ -267,6 +267,7 @@ files:
267
267
  - lib/sprockets/configuration.rb
268
268
  - lib/sprockets/context.rb
269
269
  - lib/sprockets/dependencies.rb
270
+ - lib/sprockets/deprecation.rb
270
271
  - lib/sprockets/digest_utils.rb
271
272
  - lib/sprockets/directive_processor.rb
272
273
  - lib/sprockets/eco_processor.rb
@@ -332,7 +333,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
332
333
  version: '0'
333
334
  requirements: []
334
335
  rubyforge_project: sprockets
335
- rubygems_version: 2.5.1
336
+ rubygems_version: 2.7.6
336
337
  signing_key:
337
338
  specification_version: 4
338
339
  summary: Rack-based asset packaging system