sprockets 3.7.2 → 4.0.0.beta1
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 +5 -5
- data/CHANGELOG.md +2 -295
- data/README.md +21 -35
- data/bin/sprockets +11 -8
- data/lib/rake/sprocketstask.rb +2 -2
- data/lib/sprockets.rb +79 -34
- data/lib/sprockets/asset.rb +8 -21
- data/lib/sprockets/autoload.rb +3 -0
- data/lib/sprockets/autoload/babel.rb +7 -0
- data/lib/sprockets/autoload/jsminc.rb +7 -0
- data/lib/sprockets/autoload/sassc.rb +7 -0
- data/lib/sprockets/babel_processor.rb +58 -0
- data/lib/sprockets/base.rb +8 -8
- data/lib/sprockets/bower.rb +4 -2
- data/lib/sprockets/bundle.rb +1 -1
- data/lib/sprockets/cache.rb +2 -4
- data/lib/sprockets/closure_compressor.rb +1 -2
- data/lib/sprockets/coffee_script_processor.rb +9 -3
- data/lib/sprockets/compressing.rb +2 -2
- data/lib/sprockets/configuration.rb +1 -7
- data/lib/sprockets/context.rb +10 -18
- data/lib/sprockets/digest_utils.rb +40 -52
- data/lib/sprockets/directive_processor.rb +10 -13
- data/lib/sprockets/http_utils.rb +19 -4
- data/lib/sprockets/jsminc_compressor.rb +31 -0
- data/lib/sprockets/jst_processor.rb +10 -10
- data/lib/sprockets/loader.rb +34 -28
- data/lib/sprockets/manifest.rb +3 -35
- data/lib/sprockets/manifest_utils.rb +0 -2
- data/lib/sprockets/mime.rb +7 -42
- data/lib/sprockets/path_dependency_utils.rb +2 -11
- data/lib/sprockets/path_digest_utils.rb +1 -1
- data/lib/sprockets/path_utils.rb +43 -18
- data/lib/sprockets/preprocessors/default_source_map.rb +24 -0
- data/lib/sprockets/processing.rb +30 -61
- data/lib/sprockets/processor_utils.rb +27 -28
- data/lib/sprockets/resolve.rb +172 -92
- data/lib/sprockets/sass_cache_store.rb +1 -6
- data/lib/sprockets/sass_compressor.rb +14 -1
- data/lib/sprockets/sass_processor.rb +18 -8
- data/lib/sprockets/sassc_compressor.rb +30 -0
- data/lib/sprockets/sassc_processor.rb +68 -0
- data/lib/sprockets/server.rb +9 -20
- data/lib/sprockets/source_map_comment_processor.rb +29 -0
- data/lib/sprockets/source_map_processor.rb +40 -0
- data/lib/sprockets/source_map_utils.rb +345 -0
- data/lib/sprockets/transformers.rb +62 -35
- data/lib/sprockets/uglifier_compressor.rb +12 -5
- data/lib/sprockets/unloaded_asset.rb +12 -11
- data/lib/sprockets/uri_tar.rb +4 -2
- data/lib/sprockets/uri_utils.rb +5 -5
- data/lib/sprockets/utils.rb +30 -78
- data/lib/sprockets/version.rb +1 -1
- metadata +62 -20
- data/LICENSE +0 -21
- data/lib/sprockets/coffee_script_template.rb +0 -17
- data/lib/sprockets/deprecation.rb +0 -90
- data/lib/sprockets/eco_template.rb +0 -17
- data/lib/sprockets/ejs_template.rb +0 -17
- data/lib/sprockets/engines.rb +0 -92
- data/lib/sprockets/erb_template.rb +0 -11
- data/lib/sprockets/legacy.rb +0 -330
- data/lib/sprockets/legacy_proc_processor.rb +0 -35
- data/lib/sprockets/legacy_tilt_processor.rb +0 -29
- data/lib/sprockets/sass_template.rb +0 -19
@@ -0,0 +1,24 @@
|
|
1
|
+
module Sprockets
|
2
|
+
module Preprocessors
|
3
|
+
# Private: Adds a default map to assets when one is not present
|
4
|
+
#
|
5
|
+
# If the input file already has a source map, it effectively returns the original
|
6
|
+
# result. Otherwise it maps 1 for 1 lines original to generated. This is needed
|
7
|
+
# Because other generators run after might depend on having a valid source map
|
8
|
+
# available.
|
9
|
+
class DefaultSourceMap
|
10
|
+
def call(input)
|
11
|
+
result = { data: input[:data] }
|
12
|
+
map = input[:metadata][:map]
|
13
|
+
if map.nil? || map.empty?
|
14
|
+
result[:map] ||= []
|
15
|
+
input[:data].each_line.with_index do |_, index|
|
16
|
+
line = index + 1
|
17
|
+
result[:map] << { source: input[:source_path], generated: [line , 0], original: [line, 0] }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
return result
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/sprockets/processing.rb
CHANGED
@@ -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'
|
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'
|
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'
|
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
|
-
|
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,
|
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,
|
176
|
+
def processors_for(type, file_type, pipeline)
|
174
177
|
pipeline ||= :default
|
175
|
-
config[:pipelines][pipeline.to_sym]
|
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
|
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
|
190
|
+
self_processors_for(type, file_type)
|
184
191
|
end
|
185
192
|
end
|
186
193
|
|
187
|
-
def self_processors_for(type, file_type
|
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,
|
208
|
-
|
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,
|
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(
|
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
|
-
|
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
|
-
]
|
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
|
170
|
+
if VALID_METADATA_VALUE_TYPES.include?(value.class)
|
172
171
|
true
|
173
|
-
elsif
|
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
|
data/lib/sprockets/resolve.rb
CHANGED
@@ -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,
|
24
|
-
|
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,
|
31
|
+
filename, type, path_pipeline, deps, index_alias = resolve_relative_path(paths, path, base_path, accept)
|
34
32
|
else
|
35
|
-
filename, type,
|
33
|
+
filename, type, path_pipeline, deps, index_alias = resolve_logical_path(paths, path, accept)
|
36
34
|
end
|
37
35
|
|
38
36
|
if filename
|
39
|
-
|
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,
|
52
|
-
uri, deps = resolve(path,
|
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) &&
|
58
|
-
load_path, _ = paths_split(config[:paths],
|
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 '#{
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
121
|
-
return nil, nil,
|
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
|
126
|
-
|
127
|
-
|
128
|
-
|
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
|
-
|
134
|
-
|
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
|
-
|
149
|
-
accepts << ['*/*', 1.0]
|
150
|
-
end
|
151
|
-
|
152
|
-
accepts
|
198
|
+
return nil, nil, deps
|
153
199
|
end
|
154
200
|
|
155
|
-
|
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 =
|
158
|
-
|
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
|
-
|
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
|
-
|
168
|
-
|
169
|
-
candidates.
|
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
|
-
|
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
|
250
|
+
return candidates, [ URIUtils.build_file_digest_uri(dirname) ]
|
175
251
|
end
|
176
252
|
|
177
|
-
def
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
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
|
-
|
259
|
+
return filenames, deps
|
188
260
|
end
|
189
261
|
|
190
|
-
|
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
|
-
#
|
197
|
-
#
|
264
|
+
# - mime_type - String, optional. e.g. "text/html"
|
265
|
+
# - explicit_type - String, optional. e.g. "application/javascript"
|
198
266
|
#
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
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
|
-
|
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
|