sprockets 3.7.2 → 4.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +2 -295
  3. data/README.md +21 -35
  4. data/bin/sprockets +11 -8
  5. data/lib/rake/sprocketstask.rb +2 -2
  6. data/lib/sprockets.rb +79 -34
  7. data/lib/sprockets/asset.rb +8 -21
  8. data/lib/sprockets/autoload.rb +3 -0
  9. data/lib/sprockets/autoload/babel.rb +7 -0
  10. data/lib/sprockets/autoload/jsminc.rb +7 -0
  11. data/lib/sprockets/autoload/sassc.rb +7 -0
  12. data/lib/sprockets/babel_processor.rb +58 -0
  13. data/lib/sprockets/base.rb +8 -8
  14. data/lib/sprockets/bower.rb +4 -2
  15. data/lib/sprockets/bundle.rb +1 -1
  16. data/lib/sprockets/cache.rb +2 -4
  17. data/lib/sprockets/closure_compressor.rb +1 -2
  18. data/lib/sprockets/coffee_script_processor.rb +9 -3
  19. data/lib/sprockets/compressing.rb +2 -2
  20. data/lib/sprockets/configuration.rb +1 -7
  21. data/lib/sprockets/context.rb +10 -18
  22. data/lib/sprockets/digest_utils.rb +40 -52
  23. data/lib/sprockets/directive_processor.rb +10 -13
  24. data/lib/sprockets/http_utils.rb +19 -4
  25. data/lib/sprockets/jsminc_compressor.rb +31 -0
  26. data/lib/sprockets/jst_processor.rb +10 -10
  27. data/lib/sprockets/loader.rb +34 -28
  28. data/lib/sprockets/manifest.rb +3 -35
  29. data/lib/sprockets/manifest_utils.rb +0 -2
  30. data/lib/sprockets/mime.rb +7 -42
  31. data/lib/sprockets/path_dependency_utils.rb +2 -11
  32. data/lib/sprockets/path_digest_utils.rb +1 -1
  33. data/lib/sprockets/path_utils.rb +43 -18
  34. data/lib/sprockets/preprocessors/default_source_map.rb +24 -0
  35. data/lib/sprockets/processing.rb +30 -61
  36. data/lib/sprockets/processor_utils.rb +27 -28
  37. data/lib/sprockets/resolve.rb +172 -92
  38. data/lib/sprockets/sass_cache_store.rb +1 -6
  39. data/lib/sprockets/sass_compressor.rb +14 -1
  40. data/lib/sprockets/sass_processor.rb +18 -8
  41. data/lib/sprockets/sassc_compressor.rb +30 -0
  42. data/lib/sprockets/sassc_processor.rb +68 -0
  43. data/lib/sprockets/server.rb +9 -20
  44. data/lib/sprockets/source_map_comment_processor.rb +29 -0
  45. data/lib/sprockets/source_map_processor.rb +40 -0
  46. data/lib/sprockets/source_map_utils.rb +345 -0
  47. data/lib/sprockets/transformers.rb +62 -35
  48. data/lib/sprockets/uglifier_compressor.rb +12 -5
  49. data/lib/sprockets/unloaded_asset.rb +12 -11
  50. data/lib/sprockets/uri_tar.rb +4 -2
  51. data/lib/sprockets/uri_utils.rb +5 -5
  52. data/lib/sprockets/utils.rb +30 -78
  53. data/lib/sprockets/version.rb +1 -1
  54. metadata +62 -20
  55. data/LICENSE +0 -21
  56. data/lib/sprockets/coffee_script_template.rb +0 -17
  57. data/lib/sprockets/deprecation.rb +0 -90
  58. data/lib/sprockets/eco_template.rb +0 -17
  59. data/lib/sprockets/ejs_template.rb +0 -17
  60. data/lib/sprockets/engines.rb +0 -92
  61. data/lib/sprockets/erb_template.rb +0 -11
  62. data/lib/sprockets/legacy.rb +0 -330
  63. data/lib/sprockets/legacy_proc_processor.rb +0 -35
  64. data/lib/sprockets/legacy_tilt_processor.rb +0 -29
  65. data/lib/sprockets/sass_template.rb +0 -19
@@ -44,7 +44,7 @@ module Sprockets
44
44
  # Internal: Cache key version for this class. Rarely should have to change
45
45
  # unless the cache format radically changes. Will be bump on major version
46
46
  # releases though.
47
- VERSION = '3.0'
47
+ VERSION = '4.0'
48
48
 
49
49
  def self.default_logger
50
50
  logger = Logger.new($stderr)
@@ -153,9 +153,7 @@ module Sprockets
153
153
  #
154
154
  # Returns a String with a length less than 250 characters.
155
155
  def expand_key(key)
156
- digest_key = DigestUtils.pack_urlsafe_base64digest(DigestUtils.digest(key))
157
- namespace = digest_key[0, 2]
158
- "sprockets/v#{VERSION}/#{namespace}/#{digest_key}"
156
+ "sprockets/v#{VERSION}/#{DigestUtils.pack_urlsafe_base64digest(DigestUtils.digest(key))}"
159
157
  end
160
158
 
161
159
  PEEK_SIZE = 100
@@ -35,12 +35,11 @@ module Sprockets
35
35
  attr_reader :cache_key
36
36
 
37
37
  def initialize(options = {})
38
- @options = options
38
+ @compiler = Autoload::Closure::Compiler.new(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)
44
43
  @compiler.compile(input[:data])
45
44
  end
46
45
  end
@@ -1,4 +1,5 @@
1
1
  require 'sprockets/autoload'
2
+ require 'sprockets/source_map_utils'
2
3
 
3
4
  module Sprockets
4
5
  # Processor engine class for the CoffeeScript compiler.
@@ -9,7 +10,7 @@ module Sprockets
9
10
  # https://github.com/josh/ruby-coffee-script
10
11
  #
11
12
  module CoffeeScriptProcessor
12
- VERSION = '1'
13
+ VERSION = '2'
13
14
 
14
15
  def self.cache_key
15
16
  @cache_key ||= "#{name}:#{Autoload::CoffeeScript::Source.version}:#{VERSION}".freeze
@@ -17,9 +18,14 @@ module Sprockets
17
18
 
18
19
  def self.call(input)
19
20
  data = input[:data]
20
- input[:cache].fetch([self.cache_key, data]) do
21
- Autoload::CoffeeScript.compile(data)
21
+
22
+ js, map = input[:cache].fetch([self.cache_key, data]) do
23
+ result = Autoload::CoffeeScript.compile(data, sourceMap: true, sourceFiles: [input[:source_path]])
24
+ [result['js'], SourceMapUtils.decode_json_source_map(result['v3SourceMap'])['mappings']]
22
25
  end
26
+
27
+ map = SourceMapUtils.combine_source_maps(input[:metadata][:map], map)
28
+ { data: js, map: map }
23
29
  end
24
30
  end
25
31
  end
@@ -35,7 +35,7 @@ module Sprockets
35
35
  if compressor.is_a?(Symbol)
36
36
  @css_compressor = klass = config[:compressors]['text/css'][compressor] || raise(Error, "unknown compressor: #{compressor}")
37
37
  elsif compressor.respond_to?(:compress)
38
- klass = LegacyProcProcessor.new(:css_compressor, proc { |context, data| compressor.compress(data) })
38
+ klass = proc { |input| compressor.compress(input[:data]) }
39
39
  @css_compressor = :css_compressor
40
40
  else
41
41
  @css_compressor = klass = compressor
@@ -62,7 +62,7 @@ module Sprockets
62
62
  if compressor.is_a?(Symbol)
63
63
  @js_compressor = klass = config[:compressors]['application/javascript'][compressor] || raise(Error, "unknown compressor: #{compressor}")
64
64
  elsif compressor.respond_to?(:compress)
65
- klass = LegacyProcProcessor.new(:js_compressor, proc { |context, data| compressor.compress(data) })
65
+ klass = proc { |input| compressor.compress(input[:data]) }
66
66
  @js_compressor = :js_compressor
67
67
  else
68
68
  @js_compressor = klass = compressor
@@ -1,6 +1,5 @@
1
1
  require 'sprockets/compressing'
2
2
  require 'sprockets/dependencies'
3
- require 'sprockets/engines'
4
3
  require 'sprockets/mime'
5
4
  require 'sprockets/paths'
6
5
  require 'sprockets/processing'
@@ -9,19 +8,16 @@ require 'sprockets/utils'
9
8
 
10
9
  module Sprockets
11
10
  module Configuration
12
- include Paths, Mime, Engines, Transformers, Processing, Compressing, Dependencies, Utils
11
+ include Paths, Mime, Transformers, Processing, Compressing, Dependencies, Utils
13
12
 
14
13
  def initialize_configuration(parent)
15
14
  @config = parent.config
16
- @computed_config = parent.computed_config
17
15
  @logger = parent.logger
18
16
  @context_class = Class.new(parent.context_class)
19
17
  end
20
18
 
21
19
  attr_reader :config
22
20
 
23
- attr_accessor :computed_config
24
-
25
21
  def config=(config)
26
22
  raise TypeError, "can't assign mutable config" unless config.frozen?
27
23
  @config = config
@@ -69,8 +65,6 @@ module Sprockets
69
65
  self.config = config.merge(digest_class: klass).freeze
70
66
  end
71
67
 
72
- # Deprecated: Get `Context` class.
73
- #
74
68
  # This class maybe mutated and mixed in with custom helpers.
75
69
  #
76
70
  # environment.context_class.instance_eval do
@@ -1,10 +1,8 @@
1
- require 'pathname'
2
1
  require 'rack/utils'
3
2
  require 'set'
4
3
  require 'sprockets/errors'
5
4
 
6
5
  module Sprockets
7
- # Deprecated: `Context` provides helper methods to all processors.
8
6
  # They are typically accessed by ERB templates. You can mix in custom helpers
9
7
  # by injecting them into `Environment#context_class`. Do not mix them into
10
8
  # `Context` directly.
@@ -19,10 +17,7 @@ module Sprockets
19
17
  # The `Context` also collects dependencies declared by
20
18
  # assets. See `DirectiveProcessor` for an example of this.
21
19
  class Context
22
- attr_reader :environment, :filename, :pathname
23
-
24
- # Deprecated
25
- attr_accessor :__LINE__
20
+ attr_reader :environment, :filename
26
21
 
27
22
  def initialize(input)
28
23
  @environment = input[:environment]
@@ -31,7 +26,6 @@ module Sprockets
31
26
  @logical_path = input[:name]
32
27
  @filename = input[:filename]
33
28
  @dirname = File.dirname(@filename)
34
- @pathname = Pathname.new(@filename)
35
29
  @content_type = input[:content_type]
36
30
 
37
31
  @required = Set.new(@metadata[:required])
@@ -79,13 +73,13 @@ module Sprockets
79
73
  # resolve("./bar.js")
80
74
  # # => "file:///path/to/app/javascripts/bar.js?type=application/javascript"
81
75
  #
82
- # path - String logical or absolute path
83
- # options
84
- # accept - String content accept type
76
+ # path - String logical or absolute path
77
+ # accept - String content accept type
85
78
  #
86
79
  # Returns an Asset URI String.
87
- def resolve(path, options = {})
88
- uri, deps = environment.resolve!(path, options.merge(base_path: @dirname))
80
+ def resolve(path, **kargs)
81
+ kargs[:base_path] = @dirname
82
+ uri, deps = environment.resolve!(path, **kargs)
89
83
  @dependencies.merge(deps)
90
84
  uri
91
85
  end
@@ -108,12 +102,10 @@ module Sprockets
108
102
  # the dependency file with invalidate the cache of the
109
103
  # source file.
110
104
  def depend_on(path)
111
- path = path.to_s if path.is_a?(Pathname)
112
-
113
105
  if environment.absolute_path?(path) && environment.stat(path)
114
106
  @dependencies << environment.build_file_digest_uri(path)
115
107
  else
116
- resolve(path, compat: false)
108
+ resolve(path)
117
109
  end
118
110
  nil
119
111
  end
@@ -126,7 +118,7 @@ module Sprockets
126
118
  # file. Unlike `depend_on`, this will include recursively include
127
119
  # the target asset's dependencies.
128
120
  def depend_on_asset(path)
129
- load(resolve(path, compat: false))
121
+ load(resolve(path))
130
122
  end
131
123
 
132
124
  # `require_asset` declares `path` as a dependency of the file. The
@@ -139,7 +131,7 @@ module Sprockets
139
131
  # <%= require_asset "#{framework}.js" %>
140
132
  #
141
133
  def require_asset(path)
142
- @required << resolve(path, accept: @content_type, pipeline: :self, compat: false)
134
+ @required << resolve(path, accept: @content_type, pipeline: :self)
143
135
  nil
144
136
  end
145
137
 
@@ -147,7 +139,7 @@ module Sprockets
147
139
  # `path` must be an asset which may or may not already be included
148
140
  # in the bundle.
149
141
  def stub_asset(path)
150
- @stubbed << resolve(path, accept: @content_type, pipeline: :self, compat: false)
142
+ @stubbed << resolve(path, accept: @content_type, pipeline: :self)
151
143
  nil
152
144
  end
153
145
 
@@ -34,56 +34,6 @@ 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
-
87
37
  # Internal: Generate a hexdigest for a nested JSON serializable object.
88
38
  #
89
39
  # This is used for generating cache keys, so its pretty important its
@@ -94,8 +44,46 @@ module Sprockets
94
44
  # Returns a String digest of the object.
95
45
  def digest(obj)
96
46
  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
97
86
 
98
- ADD_VALUE_TO_DIGEST[obj.class].call(obj, digest)
99
87
  digest.digest
100
88
  end
101
89
 
@@ -105,7 +93,7 @@ module Sprockets
105
93
  #
106
94
  # Returns hex String.
107
95
  def pack_hexdigest(bin)
108
- bin.unpack('H*').first
96
+ bin.unpack('H*'.freeze).first
109
97
  end
110
98
 
111
99
  # Internal: Unpack a hex encoded digest string into binary bytes.
@@ -34,8 +34,6 @@ module Sprockets
34
34
  # env.register_processor('text/css', MyProcessor)
35
35
  #
36
36
  class DirectiveProcessor
37
- VERSION = '1'
38
-
39
37
  # Directives are denoted by a `=` followed by the name, then
40
38
  # argument list.
41
39
  #
@@ -50,18 +48,16 @@ module Sprockets
50
48
  /x
51
49
 
52
50
  def self.instance
53
- @instance ||= new(
54
- # Deprecated: Default to C and Ruby comment styles
55
- comments: ["//", ["/*", "*/"]] + ["#", ["###", "###"]]
56
- )
51
+ # Default to C omment styles
52
+ @instance ||= new(comments: ["//", ["/*", "*/"]])
57
53
  end
58
54
 
59
55
  def self.call(input)
60
56
  instance.call(input)
61
57
  end
62
58
 
63
- def initialize(options = {})
64
- @header_pattern = compile_header_pattern(Array(options[:comments]))
59
+ def initialize(comments: [])
60
+ @header_pattern = compile_header_pattern(Array(comments))
65
61
  end
66
62
 
67
63
  def call(input)
@@ -162,7 +158,7 @@ module Sprockets
162
158
  # `process_require_glob_directive`.
163
159
  #
164
160
  # class DirectiveProcessor < Sprockets::DirectiveProcessor
165
- # def process_require_glob_directive
161
+ # def process_require_glob_directive(glob)
166
162
  # Dir["#{dirname}/#{glob}"].sort.each do |filename|
167
163
  # require(filename)
168
164
  # end
@@ -358,11 +354,11 @@ module Sprockets
358
354
  end
359
355
  end
360
356
 
361
- def resolve_paths(paths, deps, options = {})
357
+ def resolve_paths(paths, deps, **kargs)
362
358
  @dependencies.merge(deps)
363
359
  paths.each do |subpath, stat|
364
360
  next if subpath == @filename || stat.directory?
365
- uri, deps = @environment.resolve(subpath, options.merge(compat: false))
361
+ uri, deps = @environment.resolve(subpath, **kargs)
366
362
  @dependencies.merge(deps)
367
363
  yield uri if uri
368
364
  end
@@ -390,13 +386,14 @@ module Sprockets
390
386
  asset
391
387
  end
392
388
 
393
- def resolve(path, options = {})
389
+ def resolve(path, **kargs)
394
390
  # Prevent absolute paths in directives
395
391
  if @environment.absolute_path?(path)
396
392
  raise FileOutsidePaths, "can't require absolute file: #{path}"
397
393
  end
398
394
 
399
- uri, deps = @environment.resolve!(path, options.merge(base_path: @dirname))
395
+ kargs[:base_path] = @dirname
396
+ uri, deps = @environment.resolve!(path, **kargs)
400
397
  @dependencies.merge(deps)
401
398
  uri
402
399
  end
@@ -13,9 +13,9 @@ module Sprockets
13
13
  # Returns true if the given value is a mime match for the given mime match
14
14
  # specification, false otherwise.
15
15
  def match_mime_type?(value, matcher)
16
- v1, v2 = value.split('/', 2)
17
- m1, m2 = matcher.split('/', 2)
18
- (m1 == '*' || v1 == m1) && (m2.nil? || m2 == '*' || m2 == v2)
16
+ v1, v2 = value.split('/'.freeze, 2)
17
+ m1, m2 = matcher.split('/'.freeze, 2)
18
+ (m1 == '*'.freeze || v1 == m1) && (m2.nil? || m2 == '*'.freeze || m2 == v2)
19
19
  end
20
20
 
21
21
  # Public: Return values from Hash where the key matches the mime type.
@@ -36,7 +36,22 @@ module Sprockets
36
36
 
37
37
  # Internal: Parse Accept header quality values.
38
38
  #
39
- # Adapted from Rack::Utils#q_values.
39
+ # values - String e.g. "application/javascript"
40
+ #
41
+ # Adapted from Rack::Utils#q_values. Quality values are
42
+ # described in http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
43
+ #
44
+ # parse_q_values("application/javascript")
45
+ # # => [["application/javascript", 1.0]]
46
+ #
47
+ # parse_q_values("*/*")
48
+ # # => [["*/*", 1.0]]
49
+ #
50
+ # parse_q_values("text/plain; q=0.5, image/*")
51
+ # # => [["text/plain", 0.5], ["image/*", 1.0]]
52
+ #
53
+ # parse_q_values("application/javascript, text/css")
54
+ # # => [["application/javascript", 1.0], ["text/css", 1.0]]
40
55
  #
41
56
  # Returns an Array of [String, Float].
42
57
  def parse_q_values(values)
@@ -0,0 +1,31 @@
1
+ require 'sprockets/autoload'
2
+ require 'sprockets/digest_utils'
3
+
4
+ module Sprockets
5
+ class JSMincCompressor
6
+ VERSION = '1'
7
+
8
+ def self.instance
9
+ @instance ||= new
10
+ end
11
+
12
+ def self.call(input)
13
+ instance.call(input)
14
+ end
15
+
16
+ def self.cache_key
17
+ instance.cache_key
18
+ end
19
+
20
+ attr_reader :cache_key
21
+
22
+ def initialize(options = {})
23
+ @compressor_class = Autoload::JSMinC
24
+ @cache_key = "#{self.class.name}:#{Autoload::JSMinC::VERSION}:#{VERSION}:#{DigestUtils.digest(options)}".freeze
25
+ end
26
+
27
+ def call(input)
28
+ @compressor_class.minify(input[:data])
29
+ end
30
+ end
31
+ end