sprockets 3.7.3 → 4.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +2 -299
  3. data/README.md +21 -35
  4. data/bin/sprockets +11 -8
  5. data/lib/rake/sprocketstask.rb +2 -2
  6. data/lib/sprockets/asset.rb +8 -21
  7. data/lib/sprockets/autoload/babel.rb +7 -0
  8. data/lib/sprockets/autoload/jsminc.rb +7 -0
  9. data/lib/sprockets/autoload/sassc.rb +7 -0
  10. data/lib/sprockets/autoload.rb +3 -0
  11. data/lib/sprockets/babel_processor.rb +58 -0
  12. data/lib/sprockets/base.rb +8 -8
  13. data/lib/sprockets/bower.rb +4 -2
  14. data/lib/sprockets/bundle.rb +1 -1
  15. data/lib/sprockets/cache.rb +2 -4
  16. data/lib/sprockets/closure_compressor.rb +1 -2
  17. data/lib/sprockets/coffee_script_processor.rb +9 -3
  18. data/lib/sprockets/compressing.rb +2 -2
  19. data/lib/sprockets/configuration.rb +1 -7
  20. data/lib/sprockets/context.rb +10 -18
  21. data/lib/sprockets/digest_utils.rb +40 -52
  22. data/lib/sprockets/directive_processor.rb +10 -15
  23. data/lib/sprockets/erb_processor.rb +1 -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 -62
  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 +11 -22
  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 -8
  52. data/lib/sprockets/utils.rb +30 -79
  53. data/lib/sprockets/version.rb +1 -1
  54. data/lib/sprockets.rb +80 -35
  55. metadata +70 -41
  56. data/LICENSE +0 -21
  57. data/lib/sprockets/coffee_script_template.rb +0 -17
  58. data/lib/sprockets/deprecation.rb +0 -90
  59. data/lib/sprockets/eco_template.rb +0 -17
  60. data/lib/sprockets/ejs_template.rb +0 -17
  61. data/lib/sprockets/engines.rb +0 -92
  62. data/lib/sprockets/erb_template.rb +0 -11
  63. data/lib/sprockets/legacy.rb +0 -330
  64. data/lib/sprockets/legacy_proc_processor.rb +0 -35
  65. data/lib/sprockets/legacy_tilt_processor.rb +0 -29
  66. data/lib/sprockets/sass_template.rb +0 -19
@@ -1,7 +1,4 @@
1
- require 'sprockets/engines'
2
1
  require 'sprockets/file_reader'
3
- require 'sprockets/legacy_proc_processor'
4
- require 'sprockets/legacy_tilt_processor'
5
2
  require 'sprockets/mime'
6
3
  require 'sprockets/processor_utils'
7
4
  require 'sprockets/uri_utils'
@@ -17,9 +14,14 @@ module Sprockets
17
14
  config[:pipelines]
18
15
  end
19
16
 
17
+ # Registers a pipeline that will be called by `call_processor` method.
20
18
  def register_pipeline(name, proc = nil, &block)
21
19
  proc ||= block
22
20
 
21
+ self.config = hash_reassoc(config, :pipeline_exts) do |pipeline_exts|
22
+ pipeline_exts.merge(".#{name}".freeze => name.to_sym)
23
+ end
24
+
23
25
  self.config = hash_reassoc(config, :pipelines) do |pipelines|
24
26
  pipelines.merge(name.to_sym => proc)
25
27
  end
@@ -43,12 +45,13 @@ module Sprockets
43
45
  #
44
46
  # A block can be passed for to create a shorthand processor.
45
47
  #
46
- # register_preprocessor 'text/css', :my_processor do |context, data|
47
- # data.gsub(...)
48
+ # register_preprocessor 'text/css' do |input|
49
+ # input[:data].gsub(...)
48
50
  # end
49
51
  #
50
52
  def register_preprocessor(*args, &block)
51
53
  register_config_processor(:preprocessors, *args, &block)
54
+ compute_transformers!(self.config[:registered_transformers])
52
55
  end
53
56
  alias_method :register_processor, :register_preprocessor
54
57
 
@@ -58,12 +61,13 @@ module Sprockets
58
61
  #
59
62
  # A block can be passed for to create a shorthand processor.
60
63
  #
61
- # register_postprocessor 'application/javascript', :my_processor do |context, data|
62
- # data.gsub(...)
64
+ # register_postprocessor 'application/javascript' do |input|
65
+ # input[:data].gsub(...)
63
66
  # end
64
67
  #
65
68
  def register_postprocessor(*args, &block)
66
69
  register_config_processor(:postprocessors, *args, &block)
70
+ compute_transformers!(self.config[:registered_transformers])
67
71
  end
68
72
 
69
73
  # Remove Preprocessor `klass` for `mime_type`.
@@ -72,6 +76,7 @@ module Sprockets
72
76
  #
73
77
  def unregister_preprocessor(*args)
74
78
  unregister_config_processor(:preprocessors, *args)
79
+ compute_transformers!(self.config[:registered_transformers])
75
80
  end
76
81
  alias_method :unregister_processor, :unregister_preprocessor
77
82
 
@@ -81,6 +86,7 @@ module Sprockets
81
86
  #
82
87
  def unregister_postprocessor(*args)
83
88
  unregister_config_processor(:postprocessors, *args)
89
+ compute_transformers!(self.config[:registered_transformers])
84
90
  end
85
91
 
86
92
  # Bundle Processors are ran on concatenated assets rather than
@@ -95,8 +101,8 @@ module Sprockets
95
101
  #
96
102
  # A block can be passed for to create a shorthand processor.
97
103
  #
98
- # register_bundle_processor 'application/javascript', :my_processor do |context, data|
99
- # data.gsub(...)
104
+ # register_bundle_processor 'application/javascript' do |input|
105
+ # input[:data].gsub(...)
100
106
  # end
101
107
  #
102
108
  def register_bundle_processor(*args, &block)
@@ -154,46 +160,44 @@ module Sprockets
154
160
  protected
155
161
  def resolve_processors_cache_key_uri(uri)
156
162
  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])
163
+ processors = processors_for(params[:type], params[:file_type], params[:pipeline])
159
164
  processors_cache_keys(processors)
160
165
  end
161
166
 
162
- def build_processors_uri(type, file_type, engine_extnames, pipeline)
163
- engines = engine_extnames.join(',') if engine_extnames.any?
167
+ def build_processors_uri(type, file_type, pipeline)
164
168
  query = encode_uri_query_params(
165
169
  type: type,
166
170
  file_type: file_type,
167
- engines: engines,
168
171
  pipeline: pipeline
169
172
  )
170
173
  "processors:#{query}"
171
174
  end
172
175
 
173
- def processors_for(type, file_type, engine_extnames, pipeline)
176
+ def processors_for(type, file_type, pipeline)
174
177
  pipeline ||= :default
175
- config[:pipelines][pipeline.to_sym].call(self, type, file_type, engine_extnames)
178
+ if fn = config[:pipelines][pipeline.to_sym]
179
+ fn.call(self, type, file_type)
180
+ else
181
+ raise Error, "no pipeline: #{pipeline}"
182
+ end
176
183
  end
177
184
 
178
- def default_processors_for(type, file_type, engine_extnames)
185
+ def default_processors_for(type, file_type)
179
186
  bundled_processors = config[:bundle_processors][type]
180
187
  if bundled_processors.any?
181
188
  bundled_processors
182
189
  else
183
- self_processors_for(type, file_type, engine_extnames)
190
+ self_processors_for(type, file_type)
184
191
  end
185
192
  end
186
193
 
187
- def self_processors_for(type, file_type, engine_extnames)
194
+ def self_processors_for(type, file_type)
188
195
  processors = []
189
196
 
190
197
  processors.concat config[:postprocessors][type]
191
-
192
198
  if type != file_type && processor = config[:transformers][file_type][type]
193
199
  processors << processor
194
200
  end
195
-
196
- processors.concat engine_extnames.map { |ext| engines[ext] }
197
201
  processors.concat config[:preprocessors][file_type]
198
202
 
199
203
  if processors.any? || mime_type_charset_detecter(type)
@@ -204,55 +208,20 @@ module Sprockets
204
208
  end
205
209
 
206
210
  private
207
- def register_config_processor(type, mime_type, klass, proc = nil, &block)
208
- proc ||= block
209
- processor = wrap_processor(klass, proc)
211
+ def register_config_processor(type, mime_type, processor = nil, &block)
212
+ processor ||= block
210
213
 
211
214
  self.config = hash_reassoc(config, type, mime_type) do |processors|
212
215
  processors.unshift(processor)
213
216
  processors
214
217
  end
215
-
216
- compute_transformers!
217
218
  end
218
219
 
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
-
220
+ def unregister_config_processor(type, mime_type, proccessor)
226
221
  self.config = hash_reassoc(config, type, mime_type) do |processors|
227
- processors.delete(klass)
222
+ processors.delete(proccessor)
228
223
  processors
229
224
  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
225
  end
257
226
  end
258
227
  end
@@ -16,26 +16,34 @@ module Sprockets
16
16
  module ProcessorUtils
17
17
  extend self
18
18
 
19
+ class CompositeProcessor < Struct.new(:processor_strategy, :param, :processors) # :nodoc:
20
+ SINGULAR = lambda { |param, input| ProcessorUtils.call_processor param, input }
21
+ PLURAL = lambda { |param, input| ProcessorUtils.call_processors param, input }
22
+
23
+ def self.create(processors)
24
+ if processors.length == 1
25
+ new SINGULAR, processors.first, processors
26
+ else
27
+ new PLURAL, processors, processors
28
+ end
29
+ end
30
+
31
+ def call(input)
32
+ processor_strategy.call param, input
33
+ end
34
+
35
+ def cache_key
36
+ ProcessorUtils.processors_cache_keys(processors)
37
+ end
38
+ end
39
+
19
40
  # Public: Compose processors in right to left order.
20
41
  #
21
42
  # processors - Array of processors callables
22
43
  #
23
44
  # Returns a composed Proc.
24
45
  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
46
+ CompositeProcessor.create processors
39
47
  end
40
48
 
41
49
  # Public: Invoke list of processors in right to left order.
@@ -107,10 +115,12 @@ module Sprockets
107
115
  VALID_METADATA_VALUE_TYPES = Set.new([
108
116
  String,
109
117
  Symbol,
118
+ Fixnum,
119
+ Bignum,
110
120
  TrueClass,
111
121
  FalseClass,
112
122
  NilClass
113
- ] + (0.class == Integer ? [Integer] : [Bignum, Fixnum])).freeze
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([
@@ -119,17 +129,6 @@ module Sprockets
119
129
  Set
120
130
  ]).freeze
121
131
 
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
-
133
132
  # Internal: Set of all allowed metadata types.
134
133
  VALID_METADATA_TYPES = (VALID_METADATA_VALUE_TYPES + VALID_METADATA_COMPOUND_TYPES).freeze
135
134
 
@@ -168,9 +167,9 @@ module Sprockets
168
167
  #
169
168
  # Returns true if class is in whitelist otherwise false.
170
169
  def valid_processor_metadata_value?(value)
171
- if VALID_METADATA_VALUE_TYPES_HASH[value.class]
170
+ if VALID_METADATA_VALUE_TYPES.include?(value.class)
172
171
  true
173
- elsif VALID_METADATA_COMPOUND_TYPES_HASH[value.class]
172
+ elsif VALID_METADATA_COMPOUND_TYPES.include?(value.class)
174
173
  value.all? { |v| valid_processor_metadata_value?(v) }
175
174
  else
176
175
  false
@@ -20,27 +20,21 @@ module Sprockets
20
20
  # # => "file:///path/to/app/javascripts/application.coffee?type=application/javascript"
21
21
  #
22
22
  # The String Asset URI is returned or nil if no results are found.
23
- def resolve(path, options = {})
24
- path = path.to_s
25
- paths = options[:load_paths] || config[:paths]
26
- accept = options[:accept]
23
+ def resolve(path, load_paths: config[:paths], accept: nil, pipeline: nil, base_path: nil)
24
+ paths = load_paths
27
25
 
28
26
  if valid_asset_uri?(path)
29
27
  uri, deps = resolve_asset_uri(path)
30
28
  elsif absolute_path?(path)
31
29
  filename, type, deps = resolve_absolute_path(paths, path, accept)
32
30
  elsif relative_path?(path)
33
- filename, type, pipeline, deps = resolve_relative_path(paths, path, options[:base_path], accept)
31
+ filename, type, path_pipeline, deps, index_alias = resolve_relative_path(paths, path, base_path, accept)
34
32
  else
35
- filename, type, pipeline, deps = resolve_logical_path(paths, path, accept)
33
+ filename, type, path_pipeline, deps, index_alias = resolve_logical_path(paths, path, accept)
36
34
  end
37
35
 
38
36
  if filename
39
- params = {}
40
- params[:type] = type if type
41
- params[:pipeline] = pipeline if pipeline
42
- params[:pipeline] = options[:pipeline] if options[:pipeline]
43
- uri = build_asset_uri(filename, params)
37
+ uri = build_asset_uri(filename, type: type, pipeline: pipeline || path_pipeline, index_alias: index_alias)
44
38
  end
45
39
 
46
40
  return uri, deps
@@ -48,19 +42,18 @@ module Sprockets
48
42
 
49
43
  # Public: Same as resolve() but raises a FileNotFound exception instead of
50
44
  # nil if no assets are found.
51
- def resolve!(path, options = {})
52
- uri, deps = resolve(path, options.merge(compat: false))
45
+ def resolve!(path, **kargs)
46
+ uri, deps = resolve(path, **kargs)
53
47
 
54
48
  unless uri
55
49
  message = "couldn't find file '#{path}'"
56
50
 
57
- if relative_path?(path) && options[:base_path]
58
- load_path, _ = paths_split(config[:paths], options[:base_path])
51
+ if relative_path?(path) && kargs[:base_path]
52
+ load_path, _ = paths_split(config[:paths], kargs[:base_path])
59
53
  message << " under '#{load_path}'"
60
54
  end
61
55
 
62
- message << " with type '#{options[:accept]}'" if options[:accept]
63
- message << "\nChecked in these paths: \n #{ config[:paths].join("\n ") }"
56
+ message << " with type '#{kargs[:accept]}'" if kargs[:accept]
64
57
 
65
58
  raise FileNotFound, message
66
59
  end
@@ -69,143 +62,230 @@ module Sprockets
69
62
  end
70
63
 
71
64
  protected
65
+
66
+ # Internal: Finds an asset given a URI
67
+ #
68
+ # uri - String. Contains file:// scheme, absolute path to
69
+ # file.
70
+ # e.g. "file:///Users/schneems/sprockets/test/fixtures/default/gallery.js?type=application/javascript"
71
+ #
72
+ # Returns Array. Contains a String uri and Set of dependencies
72
73
  def resolve_asset_uri(uri)
73
- filename, _ = parse_asset_uri(uri)
74
- return uri, Set.new([build_file_digest_uri(filename)])
74
+ filename, _ = URIUtils.parse_asset_uri(uri)
75
+ return uri, Set.new( [URIUtils.build_file_digest_uri(filename)] )
75
76
  end
76
77
 
78
+ # Internal: Finds a file in a set of given paths
79
+ #
80
+ # paths - Array of Strings.
81
+ # filename - String containing absolute path to a file including extension.
82
+ # e.g. "/Users/schneems/sprockets/test/fixtures/asset/application.js"
83
+ # accept - String. A Quality value incoded set of
84
+ # mime types that we are looking for. Can be nil.
85
+ # e.g. "application/javascript" or "text/css, */*"
86
+ #
87
+ # Returns Array. Filename, type, path_pipeline, deps, index_alias
77
88
  def resolve_absolute_path(paths, filename, accept)
78
89
  deps = Set.new
79
90
  filename = File.expand_path(filename)
80
91
 
81
92
  # Ensure path is under load paths
82
- return nil, nil, deps unless paths_split(paths, filename)
93
+ return nil, nil, deps unless PathUtils.paths_split(paths, filename)
83
94
 
84
- _, mime_type, _, _ = parse_path_extnames(filename)
95
+ _, mime_type = PathUtils.match_path_extname(filename, config[:mime_exts])
85
96
  type = resolve_transform_type(mime_type, accept)
86
97
  return nil, nil, deps if accept && !type
87
98
 
88
99
  return nil, nil, deps unless file?(filename)
89
100
 
90
- deps << build_file_digest_uri(filename)
101
+ deps << URIUtils.build_file_digest_uri(filename)
91
102
  return filename, type, deps
92
103
  end
93
104
 
105
+ # Internal: Finds a relative file in a set of given paths
106
+ #
107
+ # paths - Array of Strings.
108
+ # path - String. A relative filename with or without extension
109
+ # e.g. "./jquery" or "../foo.js"
110
+ # dirname - String. Base path where we start looking for the given file.
111
+ # accept - String. A Quality value incoded set of
112
+ # mime types that we are looking for. Can be nil.
113
+ # e.g. "application/javascript" or "text/css, */*"
114
+ #
115
+ # Returns Array. Filename, type, path_pipeline, deps, index_alias
94
116
  def resolve_relative_path(paths, path, dirname, accept)
95
117
  filename = File.expand_path(path, dirname)
96
- load_path, _ = paths_split(paths, dirname)
97
- if load_path && logical_path = split_subpath(load_path, filename)
118
+ load_path, _ = PathUtils.paths_split(paths, dirname)
119
+ if load_path && logical_path = PathUtils.split_subpath(load_path, filename)
98
120
  resolve_logical_path([load_path], logical_path, accept)
99
121
  else
100
- return nil, nil, Set.new
122
+ return nil, nil, nil, Set.new
101
123
  end
102
124
  end
103
125
 
126
+ # Internal: Finds a file in a set of given paths
127
+ #
128
+ # paths - Array of Strings.
129
+ # logical_path - String. A filename with extension
130
+ # e.g. "coffee/foo.js" or "foo.js"
131
+ # accept - String. A Quality value incoded set of
132
+ # mime types that we are looking for. Can be nil.
133
+ # e.g. "application/javascript" or "text/css, */*"
134
+ #
135
+ # Finds a file on the given paths.
136
+ #
137
+ # Returns Array. Filename, type, path_pipeline, deps, index_alias
104
138
  def resolve_logical_path(paths, logical_path, accept)
105
- logical_name, mime_type, _, pipeline = parse_path_extnames(logical_path)
139
+ extname, mime_type = PathUtils.match_path_extname(logical_path, config[:mime_exts])
140
+ logical_name = logical_path.chomp(extname)
141
+
142
+ extname, pipeline = PathUtils.match_path_extname(logical_name, config[:pipeline_exts])
143
+ logical_name = logical_name.chomp(extname)
144
+
106
145
  parsed_accept = parse_accept_options(mime_type, accept)
107
146
  transformed_accepts = expand_transform_accepts(parsed_accept)
108
- filename, mime_type, deps = resolve_under_paths(paths, logical_name, transformed_accepts)
147
+
148
+ filename, mime_type, deps, index_alias = resolve_under_paths(paths, logical_name, transformed_accepts)
109
149
 
110
150
  if filename
111
151
  deps << build_file_digest_uri(filename)
112
152
  type = resolve_transform_type(mime_type, parsed_accept)
113
- return filename, type, pipeline, deps
153
+ return filename, type, pipeline, deps, index_alias
114
154
  else
115
155
  return nil, nil, nil, deps
116
156
  end
117
157
  end
118
158
 
159
+ # Internal: Finds a file in a set of given paths
160
+ #
161
+ # paths - Array of Strings.
162
+ # logical_name - String. A filename without extension
163
+ # e.g. "application" or "coffee/foo"
164
+ # accepts - Array of array containing mime/version pairs
165
+ # e.g. [["application/javascript", 1.0]]
166
+ #
167
+ # Finds a file with the same name as `logical_name` or "index" inside
168
+ # of the `logical_name` directory that matches a valid mime-type/version from
169
+ # `accepts`.
170
+ #
171
+ # Returns Array. Filename, type, dependencies, and index_alias
119
172
  def resolve_under_paths(paths, logical_name, accepts)
120
- all_deps = Set.new
121
- return nil, nil, all_deps if accepts.empty?
173
+ deps = Set.new
174
+ return nil, nil, deps if accepts.empty?
175
+
176
+ # TODO: Allow new path resolves to be registered
177
+ @resolvers ||= [
178
+ method(:resolve_main_under_path),
179
+ method(:resolve_alts_under_path),
180
+ method(:resolve_index_under_path)
181
+ ]
182
+ mime_exts = config[:mime_exts]
122
183
 
123
- logical_basename = File.basename(logical_name)
124
184
  paths.each do |load_path|
125
- candidates, deps = path_matches(load_path, logical_name, logical_basename)
126
- all_deps.merge(deps)
127
- candidate = find_best_q_match(accepts, candidates) do |c, matcher|
128
- match_mime_type?(c[1] || "application/octet-stream", matcher)
185
+ candidates = []
186
+ @resolvers.each do |fn|
187
+ result = fn.call(load_path, logical_name, mime_exts)
188
+ candidates.concat(result[0])
189
+ deps.merge(result[1])
129
190
  end
130
- return candidate + [all_deps] if candidate
131
- end
132
191
 
133
- return nil, nil, all_deps
134
- end
135
-
136
- def parse_accept_options(mime_type, types)
137
- accepts = []
138
- accepts += parse_q_values(types) if types
139
-
140
- if mime_type
141
- if accepts.empty? || accepts.any? { |accept, _| match_mime_type?(mime_type, accept) }
142
- accepts = [[mime_type, 1.0]]
143
- else
144
- return []
192
+ candidate = HTTPUtils.find_best_q_match(accepts, candidates) do |c, matcher|
193
+ match_mime_type?(c[:type] || "application/octet-stream", matcher)
145
194
  end
195
+ return candidate[:filename], candidate[:type], deps, candidate[:index_alias] if candidate
146
196
  end
147
197
 
148
- if accepts.empty?
149
- accepts << ['*/*', 1.0]
150
- end
151
-
152
- accepts
198
+ return nil, nil, deps
153
199
  end
154
200
 
155
- def path_matches(load_path, logical_name, logical_basename)
201
+ # Internal: Finds candidate files on a given path
202
+ #
203
+ # load_path - String. An absolute path to a directory
204
+ # logical_name - String. A filename without extension
205
+ # e.g. "application" or "coffee/foo"
206
+ # mime_exts - Hash of file extensions and their mime types
207
+ # e.g. {".xml.builder"=>"application/xml+builder"}
208
+ #
209
+ # Finds files that match a given `logical_name` with an acceptable
210
+ # mime type that is included in `mime_exts` on the `load_path`.
211
+ #
212
+ # Returns Array. First element is an Array of hashes or empty, second is a String
213
+ def resolve_main_under_path(load_path, logical_name, mime_exts)
156
214
  dirname = File.dirname(File.join(load_path, logical_name))
157
- candidates = dirname_matches(dirname, logical_basename)
158
- deps = file_digest_dependency_set(dirname)
159
-
160
- result = resolve_alternates(load_path, logical_name)
161
- result[0].each do |fn|
162
- candidates << [fn, parse_path_extnames(fn)[1]]
215
+ candidates = self.find_matching_path_for_extensions(dirname, File.basename(logical_name), mime_exts)
216
+ candidates.map! do |c|
217
+ { filename: c[0], type: c[1] }
163
218
  end
164
- deps.merge(result[1])
219
+ return candidates, [ URIUtils.build_file_digest_uri(dirname) ]
220
+ end
221
+
165
222
 
223
+ # Internal: Finds candidate index files in a given path
224
+ #
225
+ # load_path - String. An absolute path to a directory
226
+ # logical_name - String. A filename without extension
227
+ # e.g. "application" or "coffee/foo"
228
+ # mime_exts - Hash of file extensions and their mime types
229
+ # e.g. {".xml.builder"=>"application/xml+builder"}
230
+ #
231
+ # Looking in the given `load_path` this method will find all files under the `logical_name` directory
232
+ # that are named `index` and have a matching mime type in `mime_exts`.
233
+ #
234
+ # Returns Array. First element is an Array of hashes or empty, second is a String
235
+ def resolve_index_under_path(load_path, logical_name, mime_exts)
166
236
  dirname = File.join(load_path, logical_name)
167
- if directory? dirname
168
- result = dirname_matches(dirname, "index")
169
- candidates.concat(result)
237
+
238
+ if self.directory?(dirname)
239
+ candidates = self.find_matching_path_for_extensions(dirname, "index".freeze, mime_exts)
240
+ else
241
+ candidates = []
170
242
  end
171
243
 
172
- deps.merge(file_digest_dependency_set(dirname))
244
+ candidates.map! do |c|
245
+ { filename: c[0],
246
+ type: c[1],
247
+ index_alias: compress_from_root(c[0].sub(/\/index(\.[^\/]+)$/, '\1')) }
248
+ end
173
249
 
174
- return candidates.select { |fn, _| file?(fn) }, deps
250
+ return candidates, [ URIUtils.build_file_digest_uri(dirname) ]
175
251
  end
176
252
 
177
- def dirname_matches(dirname, basename)
178
- candidates = []
179
- entries = self.entries(dirname)
180
- entries.each do |entry|
181
- next unless File.basename(entry).start_with?(basename)
182
- name, type, _, _ = parse_path_extnames(entry)
183
- if basename == name
184
- candidates << [File.join(dirname, entry), type]
185
- end
253
+ def resolve_alts_under_path(load_path, logical_name, mime_exts)
254
+ filenames, deps = self.resolve_alternates(load_path, logical_name)
255
+ filenames.map! do |fn|
256
+ _, mime_type = PathUtils.match_path_extname(fn, mime_exts)
257
+ { filename: fn, type: mime_type }
186
258
  end
187
- candidates
259
+ return filenames, deps
188
260
  end
189
261
 
190
- def resolve_alternates(load_path, logical_name)
191
- return [], Set.new
192
- end
193
-
194
- # Internal: Returns the name, mime type and `Array` of engine extensions.
262
+ # Internal: Converts mimetype into accept Array
195
263
  #
196
- # "foo.js.coffee.erb"
197
- # # => ["foo", "application/javascript", [".coffee", ".erb"]]
264
+ # - mime_type - String, optional. e.g. "text/html"
265
+ # - explicit_type - String, optional. e.g. "application/javascript"
198
266
  #
199
- def parse_path_extnames(path)
200
- engines = []
201
- extname, value = match_path_extname(path, extname_map)
202
-
203
- if extname
204
- path = path.chomp(extname)
205
- type, engines, pipeline = value
267
+ # When called with an explicit_type and a mime_type, only a mime_type
268
+ # that matches the given explicit_type will be accepted.
269
+ #
270
+ # Returns Array of Array
271
+ #
272
+ # [["application/javascript", 1.0]]
273
+ # [["*/*", 1.0]]
274
+ # []
275
+ def parse_accept_options(mime_type, explicit_type)
276
+ if mime_type
277
+ return [[mime_type, 1.0]] if explicit_type.nil?
278
+ return [[mime_type, 1.0]] if HTTPUtils.parse_q_values(explicit_type).any? { |accept, _| HTTPUtils.match_mime_type?(mime_type, accept) }
279
+ return []
206
280
  end
207
281
 
208
- return path, type, engines, pipeline
282
+ accepts = HTTPUtils.parse_q_values(explicit_type)
283
+ accepts << ['*/*'.freeze, 1.0] if accepts.empty?
284
+ return accepts
285
+ end
286
+
287
+ def resolve_alternates(load_path, logical_name)
288
+ return [], Set.new
209
289
  end
210
290
  end
211
291
  end
@@ -25,10 +25,5 @@ module Sprockets
25
25
  end
26
26
 
27
27
  # Deprecated: Use Sprockets::SassProcessor::CacheStore instead.
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
28
+ SassCacheStore = SassProcessor::CacheStore
34
29
  end