sprockets 3.0.1 → 3.7.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +308 -0
  3. data/README.md +49 -187
  4. data/bin/sprockets +1 -0
  5. data/lib/sprockets/asset.rb +3 -2
  6. data/lib/sprockets/base.rb +13 -2
  7. data/lib/sprockets/bundle.rb +5 -1
  8. data/lib/sprockets/cache/file_store.rb +7 -4
  9. data/lib/sprockets/cache.rb +6 -4
  10. data/lib/sprockets/closure_compressor.rb +5 -11
  11. data/lib/sprockets/coffee_script_processor.rb +2 -2
  12. data/lib/sprockets/coffee_script_template.rb +12 -1
  13. data/lib/sprockets/compressing.rb +20 -0
  14. data/lib/sprockets/dependencies.rb +8 -8
  15. data/lib/sprockets/deprecation.rb +90 -0
  16. data/lib/sprockets/digest_utils.rb +81 -57
  17. data/lib/sprockets/directive_processor.rb +2 -0
  18. data/lib/sprockets/eco_processor.rb +2 -2
  19. data/lib/sprockets/eco_template.rb +12 -1
  20. data/lib/sprockets/ejs_processor.rb +2 -2
  21. data/lib/sprockets/ejs_template.rb +12 -1
  22. data/lib/sprockets/encoding_utils.rb +7 -4
  23. data/lib/sprockets/engines.rb +11 -0
  24. data/lib/sprockets/erb_processor.rb +13 -1
  25. data/lib/sprockets/erb_template.rb +6 -1
  26. data/lib/sprockets/errors.rb +0 -1
  27. data/lib/sprockets/http_utils.rb +3 -1
  28. data/lib/sprockets/legacy.rb +20 -12
  29. data/lib/sprockets/legacy_proc_processor.rb +1 -1
  30. data/lib/sprockets/legacy_tilt_processor.rb +2 -2
  31. data/lib/sprockets/loader.rb +208 -59
  32. data/lib/sprockets/manifest.rb +57 -6
  33. data/lib/sprockets/mime.rb +26 -6
  34. data/lib/sprockets/path_utils.rb +20 -15
  35. data/lib/sprockets/processing.rb +10 -0
  36. data/lib/sprockets/processor_utils.rb +77 -0
  37. data/lib/sprockets/resolve.rb +10 -7
  38. data/lib/sprockets/sass_cache_store.rb +6 -1
  39. data/lib/sprockets/sass_compressor.rb +9 -17
  40. data/lib/sprockets/sass_processor.rb +16 -9
  41. data/lib/sprockets/sass_template.rb +14 -2
  42. data/lib/sprockets/server.rb +34 -14
  43. data/lib/sprockets/uglifier_compressor.rb +6 -13
  44. data/lib/sprockets/unloaded_asset.rb +137 -0
  45. data/lib/sprockets/uri_tar.rb +98 -0
  46. data/lib/sprockets/uri_utils.rb +14 -11
  47. data/lib/sprockets/utils/gzip.rb +67 -0
  48. data/lib/sprockets/utils.rb +36 -18
  49. data/lib/sprockets/version.rb +1 -1
  50. data/lib/sprockets/yui_compressor.rb +4 -14
  51. data/lib/sprockets.rb +21 -11
  52. metadata +49 -11
@@ -17,12 +17,11 @@ module Sprockets
17
17
  #
18
18
  # pipeline - String name of pipeline.
19
19
  #
20
- # encoding - A content encoding such as "gzip" or "deflate". NOT a charset
21
- # like "utf-8".
22
- #
23
20
  module URIUtils
24
21
  extend self
25
22
 
23
+ URI_PARSER = defined?(URI::RFC2396_PARSER) ? URI::RFC2396_PARSER : URI::RFC2396_Parser.new
24
+
26
25
  # Internal: Parse URI into component parts.
27
26
  #
28
27
  # uri - String uri
@@ -47,11 +46,14 @@ module Sprockets
47
46
  def split_file_uri(uri)
48
47
  scheme, _, host, _, _, path, _, query, _ = URI.split(uri)
49
48
 
50
- path = URI::Generic::DEFAULT_PARSER.unescape(path)
49
+ path = URI_PARSER.unescape(path)
51
50
  path.force_encoding(Encoding::UTF_8)
52
51
 
53
52
  # Hack for parsing Windows "file:///C:/Users/IEUser" paths
54
- path = path.gsub(/^\/([a-zA-Z]:)/, '\1')
53
+ path.gsub!(/^\/([a-zA-Z]:)/, '\1'.freeze)
54
+
55
+ host = nil if host && host.empty?
56
+ query = nil if query && query.empty?
55
57
 
56
58
  [scheme, host, path, query]
57
59
  end
@@ -63,7 +65,7 @@ module Sprockets
63
65
  str = "#{scheme}://"
64
66
  str << host if host
65
67
  path = "/#{path}" unless path.start_with?("/")
66
- str << URI::Generic::DEFAULT_PARSER.escape(path)
68
+ str << URI_PARSER.escape(path)
67
69
  str << "?#{query}" if query
68
70
  str
69
71
  end
@@ -128,7 +130,7 @@ module Sprockets
128
130
  def parse_file_digest_uri(uri)
129
131
  scheme, _, path, _ = split_file_uri(uri)
130
132
 
131
- unless scheme == 'file-digest'
133
+ unless scheme == 'file-digest'.freeze
132
134
  raise URI::InvalidURIError, "expected file-digest scheme: #{uri}"
133
135
  end
134
136
 
@@ -146,7 +148,7 @@ module Sprockets
146
148
  #
147
149
  # Returns String URI.
148
150
  def build_file_digest_uri(path)
149
- join_file_uri("file-digest", nil, path, nil)
151
+ join_file_uri('file-digest'.freeze, nil, path, nil)
150
152
  end
151
153
 
152
154
  # Internal: Serialize hash of params into query string.
@@ -162,7 +164,7 @@ module Sprockets
162
164
  when Integer
163
165
  query << "#{key}=#{value}"
164
166
  when String, Symbol
165
- query << "#{key}=#{URI::Generic::DEFAULT_PARSER.escape(value.to_s)}"
167
+ query << "#{key}=#{URI_PARSER.escape(value.to_s)}"
166
168
  when TrueClass
167
169
  query << "#{key}"
168
170
  when FalseClass, NilClass
@@ -182,8 +184,9 @@ module Sprockets
182
184
  def parse_uri_query_params(query)
183
185
  query.to_s.split('&').reduce({}) do |h, p|
184
186
  k, v = p.split('=', 2)
185
- v = URI::Generic::DEFAULT_PARSER.unescape(v) if v
186
- h.merge(k.to_sym => v || true)
187
+ v = URI_PARSER.unescape(v) if v
188
+ h[k.to_sym] = v || true
189
+ h
187
190
  end
188
191
  end
189
192
  end
@@ -0,0 +1,67 @@
1
+ module Sprockets
2
+ module Utils
3
+ class Gzip
4
+ # Private: Generates a gzipped file based off of reference file.
5
+ def initialize(asset)
6
+ @content_type = asset.content_type
7
+ @source = asset.source
8
+ @charset = asset.charset
9
+ end
10
+
11
+ # What non-text mime types should we compress? This list comes from:
12
+ # https://www.fastly.com/blog/new-gzip-settings-and-deciding-what-compress
13
+ COMPRESSABLE_MIME_TYPES = {
14
+ "application/vnd.ms-fontobject" => true,
15
+ "application/x-font-opentype" => true,
16
+ "application/x-font-ttf" => true,
17
+ "image/x-icon" => true,
18
+ "image/svg+xml" => true
19
+ }
20
+
21
+ # Private: Returns whether or not an asset can be compressed.
22
+ #
23
+ # We want to compress any file that is text based.
24
+ # You do not want to compress binary
25
+ # files as they may already be compressed and running them
26
+ # through a compression algorithm would make them larger.
27
+ #
28
+ # Return Boolean.
29
+ def can_compress?(mime_types)
30
+ # The "charset" of a mime type is present if the value is
31
+ # encoded text. We can check this value to see if the asset
32
+ # can be compressed.
33
+ #
34
+ # We also check against our list of non-text compressible mime types
35
+ @charset || COMPRESSABLE_MIME_TYPES.include?(@content_type)
36
+ end
37
+
38
+ # Private: Opposite of `can_compress?`.
39
+ #
40
+ # Returns Boolean.
41
+ def cannot_compress?(mime_types)
42
+ !can_compress?(mime_types)
43
+ end
44
+
45
+ # Private: Generates a gzipped file based off of reference asset.
46
+ #
47
+ # Compresses the target asset's contents and puts it into a file with
48
+ # the same name plus a `.gz` extension in the same folder as the original.
49
+ # Does not modify the target asset.
50
+ #
51
+ # Returns nothing.
52
+ def compress(target)
53
+ mtime = PathUtils.stat(target).mtime
54
+ PathUtils.atomic_write("#{target}.gz") do |f|
55
+ gz = Zlib::GzipWriter.new(f, Zlib::BEST_COMPRESSION)
56
+ gz.mtime = mtime
57
+ gz.write(@source)
58
+ gz.close
59
+
60
+ File.utime(mtime, mtime, f.path)
61
+ end
62
+
63
+ nil
64
+ end
65
+ end
66
+ end
67
+ end
@@ -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,32 +78,46 @@ 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
 
90
97
  # Internal: Accumulate asset source to buffer and append a trailing
91
98
  # semicolon if necessary.
92
99
  #
93
- # buf - String memo
94
- # asset - Asset
100
+ # buf - String buffer to append to
101
+ # source - String source to append
95
102
  #
96
- # Returns appended buffer String.
103
+ # Returns buf String.
97
104
  def concat_javascript_sources(buf, source)
98
- if string_end_with_semicolon?(buf)
99
- buf + source
100
- else
101
- buf + ";\n" + source
105
+ buf = +buf
106
+ if source.bytesize > 0
107
+ buf << source
108
+
109
+ # If the source contains non-ASCII characters, indexing on it becomes O(N).
110
+ # 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)
111
+ source = source.encode(Encoding::UTF_32LE) unless source.ascii_only?
112
+
113
+ if !string_end_with_semicolon?(source)
114
+ buf << ";\n"
115
+ elsif source[source.size - 1].ord != 0x0A
116
+ buf << "\n"
117
+ end
102
118
  end
119
+
120
+ buf
103
121
  end
104
122
 
105
123
  # Internal: Prepends a leading "." to an extension if its missing.
@@ -1,3 +1,3 @@
1
1
  module Sprockets
2
- VERSION = "3.0.1"
2
+ VERSION = "3.7.5"
3
3
  end
@@ -1,4 +1,5 @@
1
1
  require 'sprockets/autoload'
2
+ require 'sprockets/digest_utils'
2
3
 
3
4
  module Sprockets
4
5
  # Public: YUI compressor.
@@ -35,12 +36,7 @@ module Sprockets
35
36
 
36
37
  def initialize(options = {})
37
38
  @options = options
38
- @cache_key = [
39
- self.class.name,
40
- Autoload::YUI::Compressor::VERSION,
41
- VERSION,
42
- options
43
- ].freeze
39
+ @cache_key = "#{self.class.name}:#{Autoload::YUI::Compressor::VERSION}:#{VERSION}:#{DigestUtils.digest(options)}".freeze
44
40
  end
45
41
 
46
42
  def call(input)
@@ -48,15 +44,9 @@ module Sprockets
48
44
 
49
45
  case input[:content_type]
50
46
  when 'application/javascript'
51
- key = @cache_key + [input[:content_type], input[:data]]
52
- input[:cache].fetch(key) do
53
- Autoload::YUI::JavaScriptCompressor.new(@options).compress(data)
54
- end
47
+ Autoload::YUI::JavaScriptCompressor.new(@options).compress(data)
55
48
  when 'text/css'
56
- key = @cache_key + [input[:content_type], input[:data]]
57
- input[:cache].fetch(key) do
58
- Autoload::YUI::CssCompressor.new(@options).compress(data)
59
- end
49
+ Autoload::YUI::CssCompressor.new(@options).compress(data)
60
50
  else
61
51
  data
62
52
  end
data/lib/sprockets.rb CHANGED
@@ -1,8 +1,10 @@
1
+ # encoding: utf-8
1
2
  require 'sprockets/version'
2
3
  require 'sprockets/cache'
3
4
  require 'sprockets/environment'
4
5
  require 'sprockets/errors'
5
6
  require 'sprockets/manifest'
7
+ require 'sprockets/deprecation'
6
8
 
7
9
  module Sprockets
8
10
  require 'sprockets/processor_utils'
@@ -32,7 +34,8 @@ module Sprockets
32
34
  registered_transformers: Hash.new { |h, k| {}.freeze }.freeze,
33
35
  root: File.expand_path('..', __FILE__).freeze,
34
36
  transformers: Hash.new { |h, k| {}.freeze }.freeze,
35
- version: ""
37
+ version: "",
38
+ gzip_enabled: true
36
39
  }.freeze
37
40
  self.computed_config = {}
38
41
 
@@ -74,6 +77,7 @@ module Sprockets
74
77
 
75
78
  # Common font types
76
79
  register_mime_type 'application/vnd.ms-fontobject', extensions: ['.eot']
80
+ register_mime_type 'application/x-font-opentype', extensions: ['.otf']
77
81
  register_mime_type 'application/x-font-ttf', extensions: ['.ttf']
78
82
  register_mime_type 'application/font-woff', extensions: ['.woff']
79
83
 
@@ -101,8 +105,8 @@ module Sprockets
101
105
  register_bundle_processor 'application/javascript', Bundle
102
106
  register_bundle_processor 'text/css', Bundle
103
107
 
104
- register_bundle_metadata_reducer '*/*', :data, :+
105
- register_bundle_metadata_reducer 'application/javascript', :data, Utils.method(:concat_javascript_sources)
108
+ register_bundle_metadata_reducer '*/*', :data, proc { "" }, :+
109
+ register_bundle_metadata_reducer 'application/javascript', :data, proc { "" }, Utils.method(:concat_javascript_sources)
106
110
  register_bundle_metadata_reducer '*/*', :links, :+
107
111
 
108
112
  require 'sprockets/closure_compressor'
@@ -119,31 +123,37 @@ module Sprockets
119
123
 
120
124
  # Mmm, CoffeeScript
121
125
  require 'sprockets/coffee_script_processor'
122
- 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
123
129
 
124
130
  # JST engines
125
131
  require 'sprockets/eco_processor'
126
132
  require 'sprockets/ejs_processor'
127
133
  require 'sprockets/jst_processor'
128
- register_engine '.jst', JstProcessor, mime_type: 'application/javascript'
129
- register_engine '.eco', EcoProcessor, mime_type: 'application/javascript'
130
- 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
131
139
 
132
140
  # CSS engines
133
141
  require 'sprockets/sass_processor'
134
- register_engine '.sass', SassProcessor, mime_type: 'text/css'
135
- 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
136
146
  register_bundle_metadata_reducer 'text/css', :sass_dependencies, Set.new, :+
137
147
 
138
148
  # Other
139
149
  require 'sprockets/erb_processor'
140
- register_engine '.erb', ERBProcessor, mime_type: 'text/plain'
150
+ register_engine '.erb', ERBProcessor, mime_type: 'text/plain', silence_deprecation: true
141
151
 
142
152
  register_dependency_resolver 'environment-version' do |env|
143
153
  env.version
144
154
  end
145
155
  register_dependency_resolver 'environment-paths' do |env|
146
- env.paths
156
+ env.paths.map {|path| env.compress_from_root(path) }
147
157
  end
148
158
  register_dependency_resolver 'file-digest' do |env, str|
149
159
  env.file_digest(env.parse_file_digest_uri(str))
metadata CHANGED
@@ -1,18 +1,52 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sprockets
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.1
4
+ version: 3.7.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Stephenson
8
8
  - Joshua Peek
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-04-14 00:00:00.000000000 Z
12
+ date: 2024-09-19 00:00:00.000000000 Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: base64
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
14
28
  - !ruby/object:Gem::Dependency
15
29
  name: rack
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">"
33
+ - !ruby/object:Gem::Version
34
+ version: '1'
35
+ - - "<"
36
+ - !ruby/object:Gem::Version
37
+ version: '3'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">"
43
+ - !ruby/object:Gem::Version
44
+ version: '1'
45
+ - - "<"
46
+ - !ruby/object:Gem::Version
47
+ version: '3'
48
+ - !ruby/object:Gem::Dependency
49
+ name: concurrent-ruby
16
50
  requirement: !ruby/object:Gem::Requirement
17
51
  requirements:
18
52
  - - "~>"
@@ -155,16 +189,16 @@ dependencies:
155
189
  name: rake
156
190
  requirement: !ruby/object:Gem::Requirement
157
191
  requirements:
158
- - - "~>"
192
+ - - ">="
159
193
  - !ruby/object:Gem::Version
160
- version: '10.0'
194
+ version: '0'
161
195
  type: :development
162
196
  prerelease: false
163
197
  version_requirements: !ruby/object:Gem::Requirement
164
198
  requirements:
165
- - - "~>"
199
+ - - ">="
166
200
  - !ruby/object:Gem::Version
167
- version: '10.0'
201
+ version: '0'
168
202
  - !ruby/object:Gem::Dependency
169
203
  name: sass
170
204
  requirement: !ruby/object:Gem::Requirement
@@ -217,6 +251,7 @@ executables:
217
251
  extensions: []
218
252
  extra_rdoc_files: []
219
253
  files:
254
+ - CHANGELOG.md
220
255
  - LICENSE
221
256
  - README.md
222
257
  - bin/sprockets
@@ -246,6 +281,7 @@ files:
246
281
  - lib/sprockets/configuration.rb
247
282
  - lib/sprockets/context.rb
248
283
  - lib/sprockets/dependencies.rb
284
+ - lib/sprockets/deprecation.rb
249
285
  - lib/sprockets/digest_utils.rb
250
286
  - lib/sprockets/directive_processor.rb
251
287
  - lib/sprockets/eco_processor.rb
@@ -284,15 +320,18 @@ files:
284
320
  - lib/sprockets/server.rb
285
321
  - lib/sprockets/transformers.rb
286
322
  - lib/sprockets/uglifier_compressor.rb
323
+ - lib/sprockets/unloaded_asset.rb
324
+ - lib/sprockets/uri_tar.rb
287
325
  - lib/sprockets/uri_utils.rb
288
326
  - lib/sprockets/utils.rb
327
+ - lib/sprockets/utils/gzip.rb
289
328
  - lib/sprockets/version.rb
290
329
  - lib/sprockets/yui_compressor.rb
291
330
  homepage: https://github.com/rails/sprockets
292
331
  licenses:
293
332
  - MIT
294
333
  metadata: {}
295
- post_install_message:
334
+ post_install_message:
296
335
  rdoc_options: []
297
336
  require_paths:
298
337
  - lib
@@ -307,9 +346,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
307
346
  - !ruby/object:Gem::Version
308
347
  version: '0'
309
348
  requirements: []
310
- rubyforge_project: sprockets
311
- rubygems_version: 2.4.5
312
- signing_key:
349
+ rubygems_version: 3.5.11
350
+ signing_key:
313
351
  specification_version: 4
314
352
  summary: Rack-based asset packaging system
315
353
  test_files: []