sprockets 3.7.2 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +66 -261
  3. data/{LICENSE → MIT-LICENSE} +2 -2
  4. data/README.md +527 -320
  5. data/bin/sprockets +11 -7
  6. data/lib/rake/sprocketstask.rb +9 -4
  7. data/lib/sprockets/add_source_map_comment_to_asset_processor.rb +60 -0
  8. data/lib/sprockets/asset.rb +39 -27
  9. data/lib/sprockets/autoload/babel.rb +8 -0
  10. data/lib/sprockets/autoload/closure.rb +1 -0
  11. data/lib/sprockets/autoload/coffee_script.rb +1 -0
  12. data/lib/sprockets/autoload/eco.rb +1 -0
  13. data/lib/sprockets/autoload/ejs.rb +1 -0
  14. data/lib/sprockets/autoload/jsminc.rb +8 -0
  15. data/lib/sprockets/autoload/sass.rb +1 -0
  16. data/lib/sprockets/autoload/sassc.rb +8 -0
  17. data/lib/sprockets/autoload/uglifier.rb +1 -0
  18. data/lib/sprockets/autoload/yui.rb +1 -0
  19. data/lib/sprockets/autoload/zopfli.rb +7 -0
  20. data/lib/sprockets/autoload.rb +5 -0
  21. data/lib/sprockets/babel_processor.rb +66 -0
  22. data/lib/sprockets/base.rb +49 -12
  23. data/lib/sprockets/bower.rb +6 -3
  24. data/lib/sprockets/bundle.rb +41 -5
  25. data/lib/sprockets/cache/file_store.rb +25 -3
  26. data/lib/sprockets/cache/memory_store.rb +28 -10
  27. data/lib/sprockets/cache/null_store.rb +8 -0
  28. data/lib/sprockets/cache.rb +37 -2
  29. data/lib/sprockets/cached_environment.rb +15 -20
  30. data/lib/sprockets/closure_compressor.rb +1 -0
  31. data/lib/sprockets/coffee_script_processor.rb +19 -5
  32. data/lib/sprockets/compressing.rb +43 -3
  33. data/lib/sprockets/configuration.rb +5 -9
  34. data/lib/sprockets/context.rb +99 -25
  35. data/lib/sprockets/dependencies.rb +2 -1
  36. data/lib/sprockets/digest_utils.rb +35 -18
  37. data/lib/sprockets/directive_processor.rb +64 -36
  38. data/lib/sprockets/eco_processor.rb +2 -1
  39. data/lib/sprockets/ejs_processor.rb +2 -1
  40. data/lib/sprockets/encoding_utils.rb +1 -0
  41. data/lib/sprockets/environment.rb +9 -4
  42. data/lib/sprockets/erb_processor.rb +34 -21
  43. data/lib/sprockets/errors.rb +1 -0
  44. data/lib/sprockets/exporters/base.rb +71 -0
  45. data/lib/sprockets/exporters/file_exporter.rb +24 -0
  46. data/lib/sprockets/exporters/zlib_exporter.rb +33 -0
  47. data/lib/sprockets/exporters/zopfli_exporter.rb +14 -0
  48. data/lib/sprockets/exporting.rb +73 -0
  49. data/lib/sprockets/file_reader.rb +1 -0
  50. data/lib/sprockets/http_utils.rb +25 -7
  51. data/lib/sprockets/jsminc_compressor.rb +32 -0
  52. data/lib/sprockets/jst_processor.rb +11 -10
  53. data/lib/sprockets/loader.rb +88 -68
  54. data/lib/sprockets/manifest.rb +67 -64
  55. data/lib/sprockets/manifest_utils.rb +9 -6
  56. data/lib/sprockets/mime.rb +8 -42
  57. data/lib/sprockets/npm.rb +52 -0
  58. data/lib/sprockets/path_dependency_utils.rb +3 -11
  59. data/lib/sprockets/path_digest_utils.rb +2 -1
  60. data/lib/sprockets/path_utils.rb +88 -8
  61. data/lib/sprockets/paths.rb +1 -0
  62. data/lib/sprockets/preprocessors/default_source_map.rb +49 -0
  63. data/lib/sprockets/processing.rb +32 -62
  64. data/lib/sprockets/processor_utils.rb +28 -38
  65. data/lib/sprockets/resolve.rb +177 -93
  66. data/lib/sprockets/sass_cache_store.rb +2 -6
  67. data/lib/sprockets/sass_compressor.rb +13 -1
  68. data/lib/sprockets/sass_functions.rb +1 -0
  69. data/lib/sprockets/sass_importer.rb +1 -0
  70. data/lib/sprockets/sass_processor.rb +31 -10
  71. data/lib/sprockets/sassc_compressor.rb +56 -0
  72. data/lib/sprockets/sassc_processor.rb +297 -0
  73. data/lib/sprockets/server.rb +52 -39
  74. data/lib/sprockets/source_map_processor.rb +66 -0
  75. data/lib/sprockets/source_map_utils.rb +483 -0
  76. data/lib/sprockets/transformers.rb +63 -35
  77. data/lib/sprockets/uglifier_compressor.rb +21 -11
  78. data/lib/sprockets/unloaded_asset.rb +13 -11
  79. data/lib/sprockets/uri_tar.rb +1 -0
  80. data/lib/sprockets/uri_utils.rb +12 -9
  81. data/lib/sprockets/utils/gzip.rb +46 -14
  82. data/lib/sprockets/utils.rb +64 -89
  83. data/lib/sprockets/version.rb +2 -1
  84. data/lib/sprockets/yui_compressor.rb +1 -0
  85. data/lib/sprockets.rb +102 -39
  86. metadata +139 -34
  87. data/lib/sprockets/coffee_script_template.rb +0 -17
  88. data/lib/sprockets/deprecation.rb +0 -90
  89. data/lib/sprockets/eco_template.rb +0 -17
  90. data/lib/sprockets/ejs_template.rb +0 -17
  91. data/lib/sprockets/engines.rb +0 -92
  92. data/lib/sprockets/erb_template.rb +0 -11
  93. data/lib/sprockets/legacy.rb +0 -330
  94. data/lib/sprockets/legacy_proc_processor.rb +0 -35
  95. data/lib/sprockets/legacy_tilt_processor.rb +0 -29
  96. data/lib/sprockets/sass_template.rb +0 -19
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'set'
2
3
  require 'sprockets/path_utils'
3
4
  require 'sprockets/uri_utils'
@@ -41,7 +42,7 @@ module Sprockets
41
42
  #
42
43
  # Returns an Array of entry names and a Set of dependency URIs.
43
44
  def entries_with_dependencies(path)
44
- return entries(path), file_digest_dependency_set(path)
45
+ return entries(path), Set.new([build_file_digest_uri(path)])
45
46
  end
46
47
 
47
48
  # Internal: List directory filenames and associated Stats under a
@@ -53,16 +54,7 @@ module Sprockets
53
54
  #
54
55
  # Returns an Array of filenames and a Set of dependency URIs.
55
56
  def stat_directory_with_dependencies(dir)
56
- return stat_directory(dir).to_a, file_digest_dependency_set(dir)
57
- end
58
-
59
- # Internal: Returns a set of dependencies for a particular path.
60
- #
61
- # path - String directory path
62
- #
63
- # Returns a Set of dependency URIs.
64
- def file_digest_dependency_set(path)
65
- Set.new([build_file_digest_uri(path)])
57
+ return stat_directory(dir).to_a, Set.new([build_file_digest_uri(dir)])
66
58
  end
67
59
 
68
60
  # Internal: List directory filenames and associated Stats under an entire
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'sprockets/digest_utils'
2
3
  require 'sprockets/path_utils'
3
4
 
@@ -15,7 +16,7 @@ module Sprockets
15
16
  def stat_digest(path, stat)
16
17
  if stat.directory?
17
18
  # If its a directive, digest the list of filenames
18
- digest_class.digest(self.entries(path).join(','))
19
+ digest_class.digest(self.entries(path).join(','.freeze))
19
20
  elsif stat.file?
20
21
  # If its a file, digest the contents
21
22
  digest_class.file(path.to_s).digest
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Sprockets
2
3
  # Internal: File and path related utilities. Mixed into Environment.
3
4
  #
@@ -5,6 +6,7 @@ module Sprockets
5
6
  # when code actually wants to reference ::FileUtils.
6
7
  module PathUtils
7
8
  extend self
9
+ require 'pathname'
8
10
 
9
11
  # Public: Like `File.stat`.
10
12
  #
@@ -53,13 +55,14 @@ module Sprockets
53
55
  # Returns an empty `Array` if the directory does not exist.
54
56
  def entries(path)
55
57
  if File.directory?(path)
56
- entries = Dir.entries(path, :encoding => Encoding.default_internal)
58
+ entries = Dir.entries(path, encoding: Encoding.default_internal)
57
59
  entries.reject! { |entry|
58
60
  entry.start_with?(".".freeze) ||
59
61
  (entry.start_with?("#".freeze) && entry.end_with?("#".freeze)) ||
60
62
  entry.end_with?("~".freeze)
61
63
  }
62
64
  entries.sort!
65
+ entries
63
66
  else
64
67
  []
65
68
  end
@@ -71,8 +74,6 @@ module Sprockets
71
74
  #
72
75
  # Returns true if path is absolute, otherwise false.
73
76
  if File::ALT_SEPARATOR
74
- require 'pathname'
75
-
76
77
  # On Windows, ALT_SEPARATOR is \
77
78
  # Delegate to Pathname since the logic gets complex.
78
79
  def absolute_path?(path)
@@ -80,7 +81,7 @@ module Sprockets
80
81
  end
81
82
  else
82
83
  def absolute_path?(path)
83
- path[0] == File::SEPARATOR
84
+ path.start_with?(File::SEPARATOR)
84
85
  end
85
86
  end
86
87
 
@@ -97,7 +98,58 @@ module Sprockets
97
98
  #
98
99
  # Returns true if path is relative, otherwise false.
99
100
  def relative_path?(path)
100
- path =~ /^\.\.?($|#{SEPARATOR_PATTERN})/ ? true : false
101
+ path.match?(/^\.\.?($|#{SEPARATOR_PATTERN})/) ? true : false
102
+ end
103
+
104
+ # Public: Get relative path from `start` to `dest`.
105
+ #
106
+ # start - String start path (file or dir)
107
+ # dest - String destination path
108
+ #
109
+ # Returns relative String path from `start` to `dest`
110
+ def relative_path_from(start, dest)
111
+ start, dest = Pathname.new(start), Pathname.new(dest)
112
+ start = start.dirname unless start.directory?
113
+ dest.relative_path_from(start).to_s
114
+ end
115
+
116
+ # Public: Joins path to base path.
117
+ #
118
+ # base - Root path
119
+ # path - Extending path
120
+ #
121
+ # Example
122
+ #
123
+ # join('base/path/', '../file.js')
124
+ # # => 'base/file.js'
125
+ #
126
+ # Returns string path starting from base and ending at path
127
+ def join(base, path)
128
+ (Pathname.new(base) + path).to_s
129
+ end
130
+
131
+ # Public: Sets pipeline for path
132
+ #
133
+ # path - String path
134
+ # extensions - List of file extensions
135
+ # pipeline - Pipeline
136
+ #
137
+ # Examples
138
+ #
139
+ # set_pipeline('path/file.js.erb', config[:mime_exts], config[:pipeline_exts], :source)
140
+ # # => 'path/file.source.js.erb'
141
+ #
142
+ # set_pipeline('path/some.file.source.js.erb', config[:mime_exts], config[:pipeline_exts], :debug)
143
+ # # => 'path/some.file.debug.js.erb'
144
+ #
145
+ # Returns string path with pipeline parsed in
146
+ def set_pipeline(path, mime_exts, pipeline_exts, pipeline)
147
+ extension, _ = match_path_extname(path, mime_exts)
148
+ path.chomp!(extension)
149
+ pipeline_old, _ = match_path_extname(path, pipeline_exts)
150
+ path.chomp!(pipeline_old)
151
+
152
+ "#{path}.#{pipeline}#{extension}"
101
153
  end
102
154
 
103
155
  # Internal: Get relative path for root path and subpath.
@@ -109,8 +161,8 @@ module Sprockets
109
161
  # subpath is outside of path.
110
162
  def split_subpath(path, subpath)
111
163
  return "" if path == subpath
112
- path = File.join(path, '')
113
- if subpath.start_with?(path)
164
+ path = File.join(path, ''.freeze)
165
+ if subpath&.start_with?(path)
114
166
  subpath[path.length..-1]
115
167
  else
116
168
  nil
@@ -163,6 +215,34 @@ module Sprockets
163
215
  nil
164
216
  end
165
217
 
218
+ # Internal: Match paths in a directory against available extensions.
219
+ #
220
+ # path - String directory
221
+ # basename - String basename of target file
222
+ # extensions - Hash of String extnames to values
223
+ #
224
+ # Examples
225
+ #
226
+ # exts = { ".js" => "application/javascript" }
227
+ # find_matching_path_for_extensions("app/assets", "application", exts)
228
+ # # => ["app/assets/application.js", "application/javascript"]
229
+ #
230
+ # Returns an Array of [String path, Object value] matches.
231
+ def find_matching_path_for_extensions(path, basename, extensions)
232
+ matches = []
233
+ entries(path).each do |entry|
234
+ next unless File.basename(entry).start_with?(basename)
235
+ extname, value = match_path_extname(entry, extensions)
236
+ if basename == entry.chomp(extname)
237
+ filename = File.join(path, entry)
238
+ if file?(filename)
239
+ matches << [filename, value]
240
+ end
241
+ end
242
+ end
243
+ matches
244
+ end
245
+
166
246
  # Internal: Returns all parents for path
167
247
  #
168
248
  # path - String absolute filename or directory
@@ -272,7 +352,7 @@ module Sprockets
272
352
  Thread.current.object_id,
273
353
  Process.pid,
274
354
  rand(1000000)
275
- ].join('.')
355
+ ].join('.'.freeze)
276
356
  tmpname = File.join(dirname, basename)
277
357
 
278
358
  File.open(tmpname, 'wb+') do |f|
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'sprockets/path_utils'
2
3
  require 'sprockets/utils'
3
4
 
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+ module Sprockets
3
+ module Preprocessors
4
+ # Private: Adds a default map to assets when one is not present
5
+ #
6
+ # If the input file already has a source map, it effectively returns the original
7
+ # result. Otherwise it maps 1 for 1 lines original to generated. This is needed
8
+ # Because other generators run after might depend on having a valid source map
9
+ # available.
10
+ class DefaultSourceMap
11
+ def call(input)
12
+ result = { data: input[:data] }
13
+ map = input[:metadata][:map]
14
+ filename = input[:filename]
15
+ load_path = input[:load_path]
16
+ lines = input[:data].lines.length
17
+ basename = File.basename(filename)
18
+ mime_exts = input[:environment].config[:mime_exts]
19
+ pipeline_exts = input[:environment].config[:pipeline_exts]
20
+ if map.nil? || map.empty?
21
+ result[:map] = {
22
+ "version" => 3,
23
+ "file" => PathUtils.split_subpath(load_path, filename),
24
+ "mappings" => default_mappings(lines),
25
+ "sources" => [PathUtils.set_pipeline(basename, mime_exts, pipeline_exts, :source)],
26
+ "names" => []
27
+ }
28
+ else
29
+ result[:map] = map
30
+ end
31
+
32
+ result[:map]["x_sprockets_linecount"] = lines
33
+ return result
34
+ end
35
+
36
+ private
37
+
38
+ def default_mappings(lines)
39
+ if (lines == 0)
40
+ ""
41
+ elsif (lines == 1)
42
+ "AAAA"
43
+ else
44
+ "AAAA;" + "AACA;"*(lines - 2) + "AACA"
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -1,7 +1,5 @@
1
- require 'sprockets/engines'
1
+ # frozen_string_literal: true
2
2
  require 'sprockets/file_reader'
3
- require 'sprockets/legacy_proc_processor'
4
- require 'sprockets/legacy_tilt_processor'
5
3
  require 'sprockets/mime'
6
4
  require 'sprockets/processor_utils'
7
5
  require 'sprockets/uri_utils'
@@ -17,9 +15,14 @@ module Sprockets
17
15
  config[:pipelines]
18
16
  end
19
17
 
18
+ # Registers a pipeline that will be called by `call_processor` method.
20
19
  def register_pipeline(name, proc = nil, &block)
21
20
  proc ||= block
22
21
 
22
+ self.config = hash_reassoc(config, :pipeline_exts) do |pipeline_exts|
23
+ pipeline_exts.merge(".#{name}".freeze => name.to_sym)
24
+ end
25
+
23
26
  self.config = hash_reassoc(config, :pipelines) do |pipelines|
24
27
  pipelines.merge(name.to_sym => proc)
25
28
  end
@@ -43,12 +46,13 @@ module Sprockets
43
46
  #
44
47
  # A block can be passed for to create a shorthand processor.
45
48
  #
46
- # register_preprocessor 'text/css', :my_processor do |context, data|
47
- # data.gsub(...)
49
+ # register_preprocessor 'text/css' do |input|
50
+ # input[:data].gsub(...)
48
51
  # end
49
52
  #
50
53
  def register_preprocessor(*args, &block)
51
54
  register_config_processor(:preprocessors, *args, &block)
55
+ compute_transformers!(self.config[:registered_transformers])
52
56
  end
53
57
  alias_method :register_processor, :register_preprocessor
54
58
 
@@ -58,12 +62,13 @@ module Sprockets
58
62
  #
59
63
  # A block can be passed for to create a shorthand processor.
60
64
  #
61
- # register_postprocessor 'application/javascript', :my_processor do |context, data|
62
- # data.gsub(...)
65
+ # register_postprocessor 'application/javascript' do |input|
66
+ # input[:data].gsub(...)
63
67
  # end
64
68
  #
65
69
  def register_postprocessor(*args, &block)
66
70
  register_config_processor(:postprocessors, *args, &block)
71
+ compute_transformers!(self.config[:registered_transformers])
67
72
  end
68
73
 
69
74
  # Remove Preprocessor `klass` for `mime_type`.
@@ -72,6 +77,7 @@ module Sprockets
72
77
  #
73
78
  def unregister_preprocessor(*args)
74
79
  unregister_config_processor(:preprocessors, *args)
80
+ compute_transformers!(self.config[:registered_transformers])
75
81
  end
76
82
  alias_method :unregister_processor, :unregister_preprocessor
77
83
 
@@ -81,6 +87,7 @@ module Sprockets
81
87
  #
82
88
  def unregister_postprocessor(*args)
83
89
  unregister_config_processor(:postprocessors, *args)
90
+ compute_transformers!(self.config[:registered_transformers])
84
91
  end
85
92
 
86
93
  # Bundle Processors are ran on concatenated assets rather than
@@ -95,8 +102,8 @@ module Sprockets
95
102
  #
96
103
  # A block can be passed for to create a shorthand processor.
97
104
  #
98
- # register_bundle_processor 'application/javascript', :my_processor do |context, data|
99
- # data.gsub(...)
105
+ # register_bundle_processor 'application/javascript' do |input|
106
+ # input[:data].gsub(...)
100
107
  # end
101
108
  #
102
109
  def register_bundle_processor(*args, &block)
@@ -123,7 +130,7 @@ module Sprockets
123
130
  #
124
131
  # mime_type - String MIME Type. Use '*/*' applies to all types.
125
132
  # key - Symbol metadata key
126
- # initial - Initial memo to pass to the reduce funciton (default: nil)
133
+ # initial - Initial memo to pass to the reduce function (default: nil)
127
134
  # block - Proc accepting the memo accumulator and current value
128
135
  #
129
136
  # Returns nothing.
@@ -154,46 +161,44 @@ module Sprockets
154
161
  protected
155
162
  def resolve_processors_cache_key_uri(uri)
156
163
  params = parse_uri_query_params(uri[11..-1])
157
- params[:engine_extnames] = params[:engines] ? params[:engines].split(',') : []
158
- processors = processors_for(params[:type], params[:file_type], params[:engine_extnames], params[:pipeline])
164
+ processors = processors_for(params[:type], params[:file_type], params[:pipeline])
159
165
  processors_cache_keys(processors)
160
166
  end
161
167
 
162
- def build_processors_uri(type, file_type, engine_extnames, pipeline)
163
- engines = engine_extnames.join(',') if engine_extnames.any?
168
+ def build_processors_uri(type, file_type, pipeline)
164
169
  query = encode_uri_query_params(
165
170
  type: type,
166
171
  file_type: file_type,
167
- engines: engines,
168
172
  pipeline: pipeline
169
173
  )
170
174
  "processors:#{query}"
171
175
  end
172
176
 
173
- def processors_for(type, file_type, engine_extnames, pipeline)
177
+ def processors_for(type, file_type, pipeline)
174
178
  pipeline ||= :default
175
- config[:pipelines][pipeline.to_sym].call(self, type, file_type, engine_extnames)
179
+ if fn = config[:pipelines][pipeline.to_sym]
180
+ fn.call(self, type, file_type)
181
+ else
182
+ raise Error, "no pipeline: #{pipeline}"
183
+ end
176
184
  end
177
185
 
178
- def default_processors_for(type, file_type, engine_extnames)
186
+ def default_processors_for(type, file_type)
179
187
  bundled_processors = config[:bundle_processors][type]
180
188
  if bundled_processors.any?
181
189
  bundled_processors
182
190
  else
183
- self_processors_for(type, file_type, engine_extnames)
191
+ self_processors_for(type, file_type)
184
192
  end
185
193
  end
186
194
 
187
- def self_processors_for(type, file_type, engine_extnames)
195
+ def self_processors_for(type, file_type)
188
196
  processors = []
189
197
 
190
198
  processors.concat config[:postprocessors][type]
191
-
192
199
  if type != file_type && processor = config[:transformers][file_type][type]
193
200
  processors << processor
194
201
  end
195
-
196
- processors.concat engine_extnames.map { |ext| engines[ext] }
197
202
  processors.concat config[:preprocessors][file_type]
198
203
 
199
204
  if processors.any? || mime_type_charset_detecter(type)
@@ -204,55 +209,20 @@ module Sprockets
204
209
  end
205
210
 
206
211
  private
207
- def register_config_processor(type, mime_type, klass, proc = nil, &block)
208
- proc ||= block
209
- processor = wrap_processor(klass, proc)
212
+ def register_config_processor(type, mime_type, processor = nil, &block)
213
+ processor ||= block
210
214
 
211
215
  self.config = hash_reassoc(config, type, mime_type) do |processors|
212
216
  processors.unshift(processor)
213
217
  processors
214
218
  end
215
-
216
- compute_transformers!
217
219
  end
218
220
 
219
- def unregister_config_processor(type, mime_type, klass)
220
- if klass.is_a?(String) || klass.is_a?(Symbol)
221
- klass = config[type][mime_type].detect do |cls|
222
- cls.respond_to?(:name) && cls.name == "Sprockets::LegacyProcProcessor (#{klass})"
223
- end
224
- end
225
-
221
+ def unregister_config_processor(type, mime_type, processor)
226
222
  self.config = hash_reassoc(config, type, mime_type) do |processors|
227
- processors.delete(klass)
223
+ processors.delete_if { |p| p == processor || p.class == processor }
228
224
  processors
229
225
  end
230
-
231
- compute_transformers!
232
- end
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
-
242
- def wrap_processor(klass, proc)
243
- if !proc
244
- if klass.respond_to?(:call)
245
- klass
246
- else
247
- deprecate_legacy_processor_interface(klass)
248
- LegacyTiltProcessor.new(klass)
249
- end
250
- elsif proc.respond_to?(:arity) && proc.arity == 2
251
- deprecate_legacy_processor_interface(proc)
252
- LegacyProcProcessor.new(klass.to_s, proc)
253
- else
254
- proc
255
- end
256
226
  end
257
227
  end
258
228
  end
@@ -1,11 +1,12 @@
1
+ # frozen_string_literal: true
1
2
  require 'set'
2
3
 
3
4
  module Sprockets
4
5
  # Functional utilities for dealing with Processor functions.
5
6
  #
6
- # A Processor is a general function that my modify or transform an asset as
7
+ # A Processor is a general function that may modify or transform an asset as
7
8
  # part of the pipeline. CoffeeScript to JavaScript conversion, Minification
8
- # or Concatenation are all implemented as seperate Processor steps.
9
+ # or Concatenation are all implemented as separate Processor steps.
9
10
  #
10
11
  # Processors maybe any object that responds to call. So procs or a class that
11
12
  # defines a self.call method.
@@ -16,26 +17,34 @@ module Sprockets
16
17
  module ProcessorUtils
17
18
  extend self
18
19
 
20
+ class CompositeProcessor < Struct.new(:processor_strategy, :param, :processors) # :nodoc:
21
+ SINGULAR = lambda { |param, input| ProcessorUtils.call_processor param, input }
22
+ PLURAL = lambda { |param, input| ProcessorUtils.call_processors param, input }
23
+
24
+ def self.create(processors)
25
+ if processors.length == 1
26
+ new SINGULAR, processors.first, processors
27
+ else
28
+ new PLURAL, processors, processors
29
+ end
30
+ end
31
+
32
+ def call(input)
33
+ processor_strategy.call param, input
34
+ end
35
+
36
+ def cache_key
37
+ ProcessorUtils.processors_cache_keys(processors)
38
+ end
39
+ end
40
+
19
41
  # Public: Compose processors in right to left order.
20
42
  #
21
43
  # processors - Array of processors callables
22
44
  #
23
45
  # Returns a composed Proc.
24
46
  def compose_processors(*processors)
25
- context = self
26
-
27
- if processors.length == 1
28
- obj = method(:call_processor).to_proc.curry[processors.first]
29
- else
30
- obj = method(:call_processors).to_proc.curry[processors]
31
- end
32
-
33
- metaclass = (class << obj; self; end)
34
- metaclass.send(:define_method, :cache_key) do
35
- context.processors_cache_keys(processors)
36
- end
37
-
38
- obj
47
+ CompositeProcessor.create processors
39
48
  end
40
49
 
41
50
  # Public: Invoke list of processors in right to left order.
@@ -109,8 +118,9 @@ module Sprockets
109
118
  Symbol,
110
119
  TrueClass,
111
120
  FalseClass,
112
- NilClass
113
- ] + (0.class == Integer ? [Integer] : [Bignum, Fixnum])).freeze
121
+ NilClass,
122
+ Integer
123
+ ]).freeze
114
124
 
115
125
  # Internal: Set of all nested compound metadata types that can nest values.
116
126
  VALID_METADATA_COMPOUND_TYPES = Set.new([
@@ -152,29 +162,9 @@ module Sprockets
152
162
  if !key.instance_of?(Symbol)
153
163
  raise TypeError, "processor metadata[#{key.inspect}] expected to be a Symbol"
154
164
  end
155
-
156
- if !valid_processor_metadata_value?(value)
157
- raise TypeError, "processor metadata[:#{key}] returned a complex type: #{value.inspect}\n" +
158
- "Only #{VALID_METADATA_TYPES.to_a.join(", ")} maybe used."
159
- end
160
165
  end
161
166
 
162
167
  result
163
168
  end
164
-
165
- # Internal: Validate object is in validate metadata whitelist.
166
- #
167
- # value - Any Object
168
- #
169
- # Returns true if class is in whitelist otherwise false.
170
- def valid_processor_metadata_value?(value)
171
- if VALID_METADATA_VALUE_TYPES_HASH[value.class]
172
- true
173
- elsif VALID_METADATA_COMPOUND_TYPES_HASH[value.class]
174
- value.all? { |v| valid_processor_metadata_value?(v) }
175
- else
176
- false
177
- end
178
- end
179
169
  end
180
170
  end