sprockets 3.0.0 → 4.0.0
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 +68 -0
- data/README.md +397 -408
- data/bin/sprockets +12 -7
- data/lib/rake/sprocketstask.rb +3 -2
- data/lib/sprockets/add_source_map_comment_to_asset_processor.rb +60 -0
- data/lib/sprockets/asset.rb +19 -23
- data/lib/sprockets/autoload/babel.rb +8 -0
- data/lib/sprockets/autoload/closure.rb +1 -0
- data/lib/sprockets/autoload/coffee_script.rb +1 -0
- data/lib/sprockets/autoload/eco.rb +1 -0
- data/lib/sprockets/autoload/ejs.rb +1 -0
- data/lib/sprockets/autoload/jsminc.rb +8 -0
- data/lib/sprockets/autoload/sass.rb +1 -0
- data/lib/sprockets/autoload/sassc.rb +8 -0
- data/lib/sprockets/autoload/uglifier.rb +1 -0
- data/lib/sprockets/autoload/yui.rb +1 -0
- data/lib/sprockets/autoload/zopfli.rb +7 -0
- data/lib/sprockets/autoload.rb +5 -0
- data/lib/sprockets/babel_processor.rb +66 -0
- data/lib/sprockets/base.rb +59 -11
- data/lib/sprockets/bower.rb +5 -2
- data/lib/sprockets/bundle.rb +44 -4
- data/lib/sprockets/cache/file_store.rb +32 -7
- data/lib/sprockets/cache/memory_store.rb +9 -0
- data/lib/sprockets/cache/null_store.rb +8 -0
- data/lib/sprockets/cache.rb +42 -5
- data/lib/sprockets/cached_environment.rb +14 -19
- data/lib/sprockets/closure_compressor.rb +6 -11
- data/lib/sprockets/coffee_script_processor.rb +19 -5
- data/lib/sprockets/compressing.rb +62 -2
- data/lib/sprockets/configuration.rb +3 -7
- data/lib/sprockets/context.rb +98 -23
- data/lib/sprockets/dependencies.rb +9 -8
- data/lib/sprockets/digest_utils.rb +104 -60
- data/lib/sprockets/directive_processor.rb +45 -35
- data/lib/sprockets/eco_processor.rb +3 -2
- data/lib/sprockets/ejs_processor.rb +3 -2
- data/lib/sprockets/encoding_utils.rb +8 -4
- data/lib/sprockets/environment.rb +9 -4
- data/lib/sprockets/erb_processor.rb +28 -21
- data/lib/sprockets/errors.rb +1 -1
- data/lib/sprockets/exporters/base.rb +72 -0
- data/lib/sprockets/exporters/file_exporter.rb +24 -0
- data/lib/sprockets/exporters/zlib_exporter.rb +33 -0
- data/lib/sprockets/exporters/zopfli_exporter.rb +14 -0
- data/lib/sprockets/exporting.rb +73 -0
- data/lib/sprockets/file_reader.rb +1 -0
- data/lib/sprockets/http_utils.rb +26 -6
- data/lib/sprockets/jsminc_compressor.rb +32 -0
- data/lib/sprockets/jst_processor.rb +11 -10
- data/lib/sprockets/loader.rb +236 -69
- data/lib/sprockets/manifest.rb +97 -44
- data/lib/sprockets/manifest_utils.rb +9 -6
- data/lib/sprockets/mime.rb +8 -42
- data/lib/sprockets/npm.rb +52 -0
- data/lib/sprockets/path_dependency_utils.rb +3 -11
- data/lib/sprockets/path_digest_utils.rb +2 -1
- data/lib/sprockets/path_utils.rb +106 -21
- data/lib/sprockets/paths.rb +1 -0
- data/lib/sprockets/preprocessors/default_source_map.rb +49 -0
- data/lib/sprockets/processing.rb +31 -51
- data/lib/sprockets/processor_utils.rb +81 -15
- data/lib/sprockets/resolve.rb +182 -95
- data/lib/sprockets/sass_cache_store.rb +1 -0
- data/lib/sprockets/sass_compressor.rb +21 -17
- data/lib/sprockets/sass_functions.rb +1 -0
- data/lib/sprockets/sass_importer.rb +1 -0
- data/lib/sprockets/sass_processor.rb +45 -17
- data/lib/sprockets/sassc_compressor.rb +56 -0
- data/lib/sprockets/sassc_processor.rb +297 -0
- data/lib/sprockets/server.rb +57 -34
- data/lib/sprockets/source_map_processor.rb +66 -0
- data/lib/sprockets/source_map_utils.rb +483 -0
- data/lib/sprockets/transformers.rb +63 -35
- data/lib/sprockets/uglifier_compressor.rb +23 -20
- data/lib/sprockets/unloaded_asset.rb +139 -0
- data/lib/sprockets/uri_tar.rb +99 -0
- data/lib/sprockets/uri_utils.rb +15 -14
- data/lib/sprockets/utils/gzip.rb +99 -0
- data/lib/sprockets/utils.rb +43 -59
- data/lib/sprockets/version.rb +2 -1
- data/lib/sprockets/yui_compressor.rb +5 -14
- data/lib/sprockets.rb +103 -33
- metadata +151 -22
- data/LICENSE +0 -21
- data/lib/sprockets/coffee_script_template.rb +0 -6
- data/lib/sprockets/eco_template.rb +0 -6
- data/lib/sprockets/ejs_template.rb +0 -6
- data/lib/sprockets/engines.rb +0 -81
- data/lib/sprockets/erb_template.rb +0 -6
- data/lib/sprockets/legacy.rb +0 -314
- 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 -7
@@ -1,7 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'set'
|
3
|
+
|
1
4
|
module Sprockets
|
2
5
|
# Functional utilities for dealing with Processor functions.
|
3
6
|
#
|
4
|
-
# A Processor is a general function that
|
7
|
+
# A Processor is a general function that may modify or transform an asset as
|
5
8
|
# part of the pipeline. CoffeeScript to JavaScript conversion, Minification
|
6
9
|
# or Concatenation are all implemented as seperate Processor steps.
|
7
10
|
#
|
@@ -14,26 +17,34 @@ module Sprockets
|
|
14
17
|
module ProcessorUtils
|
15
18
|
extend self
|
16
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
|
+
|
17
41
|
# Public: Compose processors in right to left order.
|
18
42
|
#
|
19
43
|
# processors - Array of processors callables
|
20
44
|
#
|
21
45
|
# Returns a composed Proc.
|
22
46
|
def compose_processors(*processors)
|
23
|
-
|
24
|
-
|
25
|
-
if processors.length == 1
|
26
|
-
obj = method(:call_processor).to_proc.curry[processors.first]
|
27
|
-
else
|
28
|
-
obj = method(:call_processors).to_proc.curry[processors]
|
29
|
-
end
|
30
|
-
|
31
|
-
metaclass = (class << obj; self; end)
|
32
|
-
metaclass.send(:define_method, :cache_key) do
|
33
|
-
context.processors_cache_keys(processors)
|
34
|
-
end
|
35
|
-
|
36
|
-
obj
|
47
|
+
CompositeProcessor.create processors
|
37
48
|
end
|
38
49
|
|
39
50
|
# Public: Invoke list of processors in right to left order.
|
@@ -99,5 +110,60 @@ module Sprockets
|
|
99
110
|
def processors_cache_keys(processors)
|
100
111
|
processors.map { |processor| processor_cache_key(processor) }
|
101
112
|
end
|
113
|
+
|
114
|
+
# Internal: Set of all "simple" value types allowed to be returned in
|
115
|
+
# processor metadata.
|
116
|
+
VALID_METADATA_VALUE_TYPES = Set.new([
|
117
|
+
String,
|
118
|
+
Symbol,
|
119
|
+
TrueClass,
|
120
|
+
FalseClass,
|
121
|
+
NilClass
|
122
|
+
] + (0.class == Integer ? [Integer] : [Bignum, Fixnum])).freeze
|
123
|
+
|
124
|
+
# Internal: Set of all nested compound metadata types that can nest values.
|
125
|
+
VALID_METADATA_COMPOUND_TYPES = Set.new([
|
126
|
+
Array,
|
127
|
+
Hash,
|
128
|
+
Set
|
129
|
+
]).freeze
|
130
|
+
|
131
|
+
# Internal: Hash of all "simple" value types allowed to be returned in
|
132
|
+
# processor metadata.
|
133
|
+
VALID_METADATA_VALUE_TYPES_HASH = VALID_METADATA_VALUE_TYPES.each_with_object({}) do |type, hash|
|
134
|
+
hash[type] = true
|
135
|
+
end.freeze
|
136
|
+
|
137
|
+
# Internal: Hash of all nested compound metadata types that can nest values.
|
138
|
+
VALID_METADATA_COMPOUND_TYPES_HASH = VALID_METADATA_COMPOUND_TYPES.each_with_object({}) do |type, hash|
|
139
|
+
hash[type] = true
|
140
|
+
end.freeze
|
141
|
+
|
142
|
+
# Internal: Set of all allowed metadata types.
|
143
|
+
VALID_METADATA_TYPES = (VALID_METADATA_VALUE_TYPES + VALID_METADATA_COMPOUND_TYPES).freeze
|
144
|
+
|
145
|
+
# Internal: Validate returned result of calling a processor pipeline and
|
146
|
+
# raise a friendly user error message.
|
147
|
+
#
|
148
|
+
# result - Metadata Hash returned from call_processors
|
149
|
+
#
|
150
|
+
# Returns result or raises a TypeError.
|
151
|
+
def validate_processor_result!(result)
|
152
|
+
if !result.instance_of?(Hash)
|
153
|
+
raise TypeError, "processor metadata result was expected to be a Hash, but was #{result.class}"
|
154
|
+
end
|
155
|
+
|
156
|
+
if !result[:data].instance_of?(String)
|
157
|
+
raise TypeError, "processor :data was expected to be a String, but as #{result[:data].class}"
|
158
|
+
end
|
159
|
+
|
160
|
+
result.each do |key, value|
|
161
|
+
if !key.instance_of?(Symbol)
|
162
|
+
raise TypeError, "processor metadata[#{key.inspect}] expected to be a Symbol"
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
result
|
167
|
+
end
|
102
168
|
end
|
103
169
|
end
|
data/lib/sprockets/resolve.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'set'
|
2
3
|
require 'sprockets/http_utils'
|
3
4
|
require 'sprockets/path_dependency_utils'
|
@@ -20,27 +21,21 @@ module Sprockets
|
|
20
21
|
# # => "file:///path/to/app/javascripts/application.coffee?type=application/javascript"
|
21
22
|
#
|
22
23
|
# 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]
|
24
|
+
def resolve(path, load_paths: config[:paths], accept: nil, pipeline: nil, base_path: nil)
|
25
|
+
paths = load_paths
|
27
26
|
|
28
27
|
if valid_asset_uri?(path)
|
29
28
|
uri, deps = resolve_asset_uri(path)
|
30
29
|
elsif absolute_path?(path)
|
31
30
|
filename, type, deps = resolve_absolute_path(paths, path, accept)
|
32
31
|
elsif relative_path?(path)
|
33
|
-
filename, type,
|
32
|
+
filename, type, path_pipeline, deps, index_alias = resolve_relative_path(paths, path, base_path, accept)
|
34
33
|
else
|
35
|
-
filename, type,
|
34
|
+
filename, type, path_pipeline, deps, index_alias = resolve_logical_path(paths, path, accept)
|
36
35
|
end
|
37
36
|
|
38
37
|
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)
|
38
|
+
uri = build_asset_uri(filename, type: type, pipeline: pipeline || path_pipeline, index_alias: index_alias)
|
44
39
|
end
|
45
40
|
|
46
41
|
return uri, deps
|
@@ -48,12 +43,22 @@ module Sprockets
|
|
48
43
|
|
49
44
|
# Public: Same as resolve() but raises a FileNotFound exception instead of
|
50
45
|
# nil if no assets are found.
|
51
|
-
def resolve!(path,
|
52
|
-
uri, deps = resolve(path,
|
46
|
+
def resolve!(path, **kargs)
|
47
|
+
uri, deps = resolve(path, **kargs)
|
53
48
|
|
54
49
|
unless uri
|
55
|
-
message = "couldn't find file '#{path}'"
|
56
|
-
|
50
|
+
message = +"couldn't find file '#{path}'"
|
51
|
+
|
52
|
+
if relative_path?(path) && kargs[:base_path]
|
53
|
+
load_path, _ = paths_split(config[:paths], kargs[:base_path])
|
54
|
+
message << " under '#{load_path}'"
|
55
|
+
end
|
56
|
+
|
57
|
+
message << " with type '#{kargs[:accept]}'" if kargs[:accept]
|
58
|
+
|
59
|
+
load_paths = kargs[:load_paths] || config[:paths]
|
60
|
+
message << "\nChecked in these paths: \n #{ load_paths.join("\n ") }"
|
61
|
+
|
57
62
|
raise FileNotFound, message
|
58
63
|
end
|
59
64
|
|
@@ -61,148 +66,230 @@ module Sprockets
|
|
61
66
|
end
|
62
67
|
|
63
68
|
protected
|
69
|
+
|
70
|
+
# Internal: Finds an asset given a URI
|
71
|
+
#
|
72
|
+
# uri - String. Contains file:// scheme, absolute path to
|
73
|
+
# file.
|
74
|
+
# e.g. "file:///Users/schneems/sprockets/test/fixtures/default/gallery.js?type=application/javascript"
|
75
|
+
#
|
76
|
+
# Returns Array. Contains a String uri and Set of dependencies
|
64
77
|
def resolve_asset_uri(uri)
|
65
|
-
filename, _ = parse_asset_uri(uri)
|
66
|
-
return uri, Set.new([build_file_digest_uri(filename)])
|
78
|
+
filename, _ = URIUtils.parse_asset_uri(uri)
|
79
|
+
return uri, Set.new( [URIUtils.build_file_digest_uri(filename)] )
|
67
80
|
end
|
68
81
|
|
82
|
+
# Internal: Finds a file in a set of given paths
|
83
|
+
#
|
84
|
+
# paths - Array of Strings.
|
85
|
+
# filename - String containing absolute path to a file including extension.
|
86
|
+
# e.g. "/Users/schneems/sprockets/test/fixtures/asset/application.js"
|
87
|
+
# accept - String. A Quality value incoded set of
|
88
|
+
# mime types that we are looking for. Can be nil.
|
89
|
+
# e.g. "application/javascript" or "text/css, */*"
|
90
|
+
#
|
91
|
+
# Returns Array. Filename, type, path_pipeline, deps, index_alias
|
69
92
|
def resolve_absolute_path(paths, filename, accept)
|
70
93
|
deps = Set.new
|
71
94
|
filename = File.expand_path(filename)
|
72
95
|
|
73
96
|
# Ensure path is under load paths
|
74
|
-
return nil, nil, deps unless paths_split(paths, filename)
|
97
|
+
return nil, nil, deps unless PathUtils.paths_split(paths, filename)
|
75
98
|
|
76
|
-
_, mime_type
|
99
|
+
_, mime_type = PathUtils.match_path_extname(filename, config[:mime_exts])
|
77
100
|
type = resolve_transform_type(mime_type, accept)
|
78
101
|
return nil, nil, deps if accept && !type
|
79
102
|
|
80
103
|
return nil, nil, deps unless file?(filename)
|
81
104
|
|
82
|
-
deps << build_file_digest_uri(filename)
|
105
|
+
deps << URIUtils.build_file_digest_uri(filename)
|
83
106
|
return filename, type, deps
|
84
107
|
end
|
85
108
|
|
109
|
+
# Internal: Finds a relative file in a set of given paths
|
110
|
+
#
|
111
|
+
# paths - Array of Strings.
|
112
|
+
# path - String. A relative filename with or without extension
|
113
|
+
# e.g. "./jquery" or "../foo.js"
|
114
|
+
# dirname - String. Base path where we start looking for the given file.
|
115
|
+
# accept - String. A Quality value incoded set of
|
116
|
+
# mime types that we are looking for. Can be nil.
|
117
|
+
# e.g. "application/javascript" or "text/css, */*"
|
118
|
+
#
|
119
|
+
# Returns Array. Filename, type, path_pipeline, deps, index_alias
|
86
120
|
def resolve_relative_path(paths, path, dirname, accept)
|
87
121
|
filename = File.expand_path(path, dirname)
|
88
|
-
load_path, _ = paths_split(paths, dirname)
|
89
|
-
if load_path && logical_path = split_subpath(load_path, filename)
|
122
|
+
load_path, _ = PathUtils.paths_split(paths, dirname)
|
123
|
+
if load_path && logical_path = PathUtils.split_subpath(load_path, filename)
|
90
124
|
resolve_logical_path([load_path], logical_path, accept)
|
91
125
|
else
|
92
|
-
return nil, nil, Set.new
|
126
|
+
return nil, nil, nil, Set.new
|
93
127
|
end
|
94
128
|
end
|
95
129
|
|
130
|
+
# Internal: Finds a file in a set of given paths
|
131
|
+
#
|
132
|
+
# paths - Array of Strings.
|
133
|
+
# logical_path - String. A filename with extension
|
134
|
+
# e.g. "coffee/foo.js" or "foo.js"
|
135
|
+
# accept - String. A Quality value incoded set of
|
136
|
+
# mime types that we are looking for. Can be nil.
|
137
|
+
# e.g. "application/javascript" or "text/css, */*"
|
138
|
+
#
|
139
|
+
# Finds a file on the given paths.
|
140
|
+
#
|
141
|
+
# Returns Array. Filename, type, path_pipeline, deps, index_alias
|
96
142
|
def resolve_logical_path(paths, logical_path, accept)
|
97
|
-
|
143
|
+
extname, mime_type = PathUtils.match_path_extname(logical_path, config[:mime_exts])
|
144
|
+
logical_name = logical_path.chomp(extname)
|
145
|
+
|
146
|
+
extname, pipeline = PathUtils.match_path_extname(logical_name, config[:pipeline_exts])
|
147
|
+
logical_name = logical_name.chomp(extname)
|
148
|
+
|
98
149
|
parsed_accept = parse_accept_options(mime_type, accept)
|
99
150
|
transformed_accepts = expand_transform_accepts(parsed_accept)
|
100
|
-
|
151
|
+
|
152
|
+
filename, mime_type, deps, index_alias = resolve_under_paths(paths, logical_name, transformed_accepts)
|
101
153
|
|
102
154
|
if filename
|
103
155
|
deps << build_file_digest_uri(filename)
|
104
156
|
type = resolve_transform_type(mime_type, parsed_accept)
|
105
|
-
return filename, type, pipeline, deps
|
157
|
+
return filename, type, pipeline, deps, index_alias
|
106
158
|
else
|
107
159
|
return nil, nil, nil, deps
|
108
160
|
end
|
109
161
|
end
|
110
162
|
|
163
|
+
# Internal: Finds a file in a set of given paths
|
164
|
+
#
|
165
|
+
# paths - Array of Strings.
|
166
|
+
# logical_name - String. A filename without extension
|
167
|
+
# e.g. "application" or "coffee/foo"
|
168
|
+
# accepts - Array of array containing mime/version pairs
|
169
|
+
# e.g. [["application/javascript", 1.0]]
|
170
|
+
#
|
171
|
+
# Finds a file with the same name as `logical_name` or "index" inside
|
172
|
+
# of the `logical_name` directory that matches a valid mime-type/version from
|
173
|
+
# `accepts`.
|
174
|
+
#
|
175
|
+
# Returns Array. Filename, type, dependencies, and index_alias
|
111
176
|
def resolve_under_paths(paths, logical_name, accepts)
|
112
|
-
|
113
|
-
return nil, nil,
|
177
|
+
deps = Set.new
|
178
|
+
return nil, nil, deps if accepts.empty?
|
179
|
+
|
180
|
+
# TODO: Allow new path resolves to be registered
|
181
|
+
@resolvers ||= [
|
182
|
+
method(:resolve_main_under_path),
|
183
|
+
method(:resolve_alts_under_path),
|
184
|
+
method(:resolve_index_under_path)
|
185
|
+
]
|
186
|
+
mime_exts = config[:mime_exts]
|
114
187
|
|
115
|
-
logical_basename = File.basename(logical_name)
|
116
188
|
paths.each do |load_path|
|
117
|
-
candidates
|
118
|
-
|
119
|
-
|
120
|
-
|
189
|
+
candidates = []
|
190
|
+
@resolvers.each do |fn|
|
191
|
+
result = fn.call(load_path, logical_name, mime_exts)
|
192
|
+
candidates.concat(result[0])
|
193
|
+
deps.merge(result[1])
|
121
194
|
end
|
122
|
-
return candidate + [all_deps] if candidate
|
123
|
-
end
|
124
|
-
|
125
|
-
return nil, nil, all_deps
|
126
|
-
end
|
127
195
|
|
128
|
-
|
129
|
-
|
130
|
-
accepts += parse_q_values(types) if types
|
131
|
-
|
132
|
-
if mime_type
|
133
|
-
if accepts.empty? || accepts.any? { |accept, _| match_mime_type?(mime_type, accept) }
|
134
|
-
accepts = [[mime_type, 1.0]]
|
135
|
-
else
|
136
|
-
return []
|
196
|
+
candidate = HTTPUtils.find_best_q_match(accepts, candidates) do |c, matcher|
|
197
|
+
match_mime_type?(c[:type] || "application/octet-stream", matcher)
|
137
198
|
end
|
199
|
+
return candidate[:filename], candidate[:type], deps, candidate[:index_alias] if candidate
|
138
200
|
end
|
139
201
|
|
140
|
-
|
141
|
-
accepts << ['*/*', 1.0]
|
142
|
-
end
|
143
|
-
|
144
|
-
accepts
|
145
|
-
end
|
146
|
-
|
147
|
-
def normalize_logical_path(path)
|
148
|
-
dirname, basename = File.split(path)
|
149
|
-
path = dirname if basename == 'index'
|
150
|
-
path
|
202
|
+
return nil, nil, deps
|
151
203
|
end
|
152
204
|
|
153
|
-
|
205
|
+
# Internal: Finds candidate files on a given path
|
206
|
+
#
|
207
|
+
# load_path - String. An absolute path to a directory
|
208
|
+
# logical_name - String. A filename without extension
|
209
|
+
# e.g. "application" or "coffee/foo"
|
210
|
+
# mime_exts - Hash of file extensions and their mime types
|
211
|
+
# e.g. {".xml.builder"=>"application/xml+builder"}
|
212
|
+
#
|
213
|
+
# Finds files that match a given `logical_name` with an acceptable
|
214
|
+
# mime type that is included in `mime_exts` on the `load_path`.
|
215
|
+
#
|
216
|
+
# Returns Array. First element is an Array of hashes or empty, second is a String
|
217
|
+
def resolve_main_under_path(load_path, logical_name, mime_exts)
|
154
218
|
dirname = File.dirname(File.join(load_path, logical_name))
|
155
|
-
candidates =
|
156
|
-
|
157
|
-
|
158
|
-
result = resolve_alternates(load_path, logical_name)
|
159
|
-
result[0].each do |fn|
|
160
|
-
candidates << [fn, parse_path_extnames(fn)[1]]
|
219
|
+
candidates = self.find_matching_path_for_extensions(dirname, File.basename(logical_name), mime_exts)
|
220
|
+
candidates.map! do |c|
|
221
|
+
{ filename: c[0], type: c[1] }
|
161
222
|
end
|
162
|
-
|
223
|
+
return candidates, [ URIUtils.build_file_digest_uri(dirname) ]
|
224
|
+
end
|
225
|
+
|
163
226
|
|
227
|
+
# Internal: Finds candidate index files in a given path
|
228
|
+
#
|
229
|
+
# load_path - String. An absolute path to a directory
|
230
|
+
# logical_name - String. A filename without extension
|
231
|
+
# e.g. "application" or "coffee/foo"
|
232
|
+
# mime_exts - Hash of file extensions and their mime types
|
233
|
+
# e.g. {".xml.builder"=>"application/xml+builder"}
|
234
|
+
#
|
235
|
+
# Looking in the given `load_path` this method will find all files under the `logical_name` directory
|
236
|
+
# that are named `index` and have a matching mime type in `mime_exts`.
|
237
|
+
#
|
238
|
+
# Returns Array. First element is an Array of hashes or empty, second is a String
|
239
|
+
def resolve_index_under_path(load_path, logical_name, mime_exts)
|
164
240
|
dirname = File.join(load_path, logical_name)
|
165
|
-
|
166
|
-
|
167
|
-
candidates.
|
241
|
+
|
242
|
+
if self.directory?(dirname)
|
243
|
+
candidates = self.find_matching_path_for_extensions(dirname, "index".freeze, mime_exts)
|
244
|
+
else
|
245
|
+
candidates = []
|
168
246
|
end
|
169
247
|
|
170
|
-
|
248
|
+
candidates.map! do |c|
|
249
|
+
{ filename: c[0],
|
250
|
+
type: c[1],
|
251
|
+
index_alias: compress_from_root(c[0].sub(/\/index(\.[^\/]+)$/, '\1')) }
|
252
|
+
end
|
171
253
|
|
172
|
-
return candidates
|
254
|
+
return candidates, [ URIUtils.build_file_digest_uri(dirname) ]
|
173
255
|
end
|
174
256
|
|
175
|
-
def
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
if basename == name
|
181
|
-
candidates << [File.join(dirname, entry), type]
|
182
|
-
end
|
257
|
+
def resolve_alts_under_path(load_path, logical_name, mime_exts)
|
258
|
+
filenames, deps = self.resolve_alternates(load_path, logical_name)
|
259
|
+
filenames.map! do |fn|
|
260
|
+
_, mime_type = PathUtils.match_path_extname(fn, mime_exts)
|
261
|
+
{ filename: fn, type: mime_type }
|
183
262
|
end
|
184
|
-
|
263
|
+
return filenames, deps
|
185
264
|
end
|
186
265
|
|
187
|
-
|
188
|
-
return [], Set.new
|
189
|
-
end
|
190
|
-
|
191
|
-
# Internal: Returns the name, mime type and `Array` of engine extensions.
|
266
|
+
# Internal: Converts mimetype into accept Array
|
192
267
|
#
|
193
|
-
#
|
194
|
-
#
|
268
|
+
# - mime_type - String, optional. e.g. "text/html"
|
269
|
+
# - explicit_type - String, optional. e.g. "application/javascript"
|
195
270
|
#
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
271
|
+
# When called with an explicit_type and a mime_type, only a mime_type
|
272
|
+
# that matches the given explicit_type will be accepted.
|
273
|
+
#
|
274
|
+
# Returns Array of Array
|
275
|
+
#
|
276
|
+
# [["application/javascript", 1.0]]
|
277
|
+
# [["*/*", 1.0]]
|
278
|
+
# []
|
279
|
+
def parse_accept_options(mime_type, explicit_type)
|
280
|
+
if mime_type
|
281
|
+
return [[mime_type, 1.0]] if explicit_type.nil?
|
282
|
+
return [[mime_type, 1.0]] if HTTPUtils.parse_q_values(explicit_type).any? { |accept, _| HTTPUtils.match_mime_type?(mime_type, accept) }
|
283
|
+
return []
|
203
284
|
end
|
204
285
|
|
205
|
-
|
286
|
+
accepts = HTTPUtils.parse_q_values(explicit_type)
|
287
|
+
accepts << ['*/*'.freeze, 1.0] if accepts.empty?
|
288
|
+
return accepts
|
289
|
+
end
|
290
|
+
|
291
|
+
def resolve_alternates(load_path, logical_name)
|
292
|
+
return [], Set.new
|
206
293
|
end
|
207
294
|
end
|
208
295
|
end
|
@@ -1,4 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'sprockets/autoload'
|
3
|
+
require 'sprockets/digest_utils'
|
4
|
+
require 'sprockets/source_map_utils'
|
2
5
|
|
3
6
|
module Sprockets
|
4
7
|
# Public: Sass CSS minifier.
|
@@ -34,26 +37,27 @@ module Sprockets
|
|
34
37
|
attr_reader :cache_key
|
35
38
|
|
36
39
|
def initialize(options = {})
|
37
|
-
@options =
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
40
|
+
@options = {
|
41
|
+
syntax: :scss,
|
42
|
+
cache: false,
|
43
|
+
read_cache: false,
|
44
|
+
style: :compressed
|
45
|
+
}.merge(options).freeze
|
46
|
+
@cache_key = "#{self.class.name}:#{Autoload::Sass::VERSION}:#{VERSION}:#{DigestUtils.digest(options)}".freeze
|
44
47
|
end
|
45
48
|
|
46
49
|
def call(input)
|
47
|
-
|
48
|
-
|
49
|
-
options
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
50
|
+
css, map = Autoload::Sass::Engine.new(
|
51
|
+
input[:data],
|
52
|
+
@options.merge(filename: input[:filename])
|
53
|
+
).render_with_sourcemap('')
|
54
|
+
|
55
|
+
css = css.sub("/*# sourceMappingURL= */\n", '')
|
56
|
+
|
57
|
+
map = SourceMapUtils.format_source_map(JSON.parse(map.to_json(css_uri: '')), input)
|
58
|
+
map = SourceMapUtils.combine_source_maps(input[:metadata][:map], map)
|
59
|
+
|
60
|
+
{ data: css, map: map }
|
57
61
|
end
|
58
62
|
end
|
59
63
|
end
|
@@ -1,5 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'rack/utils'
|
2
3
|
require 'sprockets/autoload'
|
4
|
+
require 'sprockets/source_map_utils'
|
3
5
|
require 'uri'
|
4
6
|
|
5
7
|
module Sprockets
|
@@ -39,18 +41,14 @@ module Sprockets
|
|
39
41
|
# Public: Initialize template with custom options.
|
40
42
|
#
|
41
43
|
# options - Hash
|
42
|
-
#
|
43
|
-
#
|
44
|
+
# cache_version - String custom cache version. Used to force a cache
|
45
|
+
# change after code changes are made to Sass Functions.
|
44
46
|
#
|
45
47
|
def initialize(options = {}, &block)
|
46
48
|
@cache_version = options[:cache_version]
|
47
|
-
@cache_key =
|
48
|
-
|
49
|
-
|
50
|
-
Autoload::Sass::VERSION,
|
51
|
-
@cache_version
|
52
|
-
].freeze
|
53
|
-
|
49
|
+
@cache_key = "#{self.class.name}:#{VERSION}:#{Autoload::Sass::VERSION}:#{@cache_version}".freeze
|
50
|
+
@importer_class = options[:importer] || Sass::Importers::Filesystem
|
51
|
+
@sass_config = options[:sass_config] || {}
|
54
52
|
@functions = Module.new do
|
55
53
|
include Functions
|
56
54
|
include options[:functions] if options[:functions]
|
@@ -61,24 +59,30 @@ module Sprockets
|
|
61
59
|
def call(input)
|
62
60
|
context = input[:environment].context_class.new(input)
|
63
61
|
|
64
|
-
|
62
|
+
engine_options = merge_options({
|
65
63
|
filename: input[:filename],
|
66
64
|
syntax: self.class.syntax,
|
67
|
-
cache_store:
|
68
|
-
load_paths:
|
65
|
+
cache_store: build_cache_store(input, @cache_version),
|
66
|
+
load_paths: context.environment.paths.map { |p| @importer_class.new(p.to_s) },
|
67
|
+
importer: @importer_class.new(Pathname.new(context.filename).to_s),
|
69
68
|
sprockets: {
|
70
69
|
context: context,
|
71
70
|
environment: input[:environment],
|
72
71
|
dependencies: context.metadata[:dependencies]
|
73
72
|
}
|
74
|
-
}
|
73
|
+
})
|
75
74
|
|
76
|
-
engine = Autoload::Sass::Engine.new(input[:data],
|
75
|
+
engine = Autoload::Sass::Engine.new(input[:data], engine_options)
|
77
76
|
|
78
|
-
css = Utils.module_include(Autoload::Sass::Script::Functions, @functions) do
|
79
|
-
engine.
|
77
|
+
css, map = Utils.module_include(Autoload::Sass::Script::Functions, @functions) do
|
78
|
+
engine.render_with_sourcemap('')
|
80
79
|
end
|
81
80
|
|
81
|
+
css = css.sub("\n/*# sourceMappingURL= */\n", '')
|
82
|
+
|
83
|
+
map = SourceMapUtils.format_source_map(JSON.parse(map.to_json(css_uri: '')), input)
|
84
|
+
map = SourceMapUtils.combine_source_maps(input[:metadata][:map], map)
|
85
|
+
|
82
86
|
# Track all imported files
|
83
87
|
sass_dependencies = Set.new([input[:filename]])
|
84
88
|
engine.dependencies.map do |dependency|
|
@@ -86,7 +90,31 @@ module Sprockets
|
|
86
90
|
context.metadata[:dependencies] << URIUtils.build_file_digest_uri(dependency.options[:filename])
|
87
91
|
end
|
88
92
|
|
89
|
-
context.metadata.merge(data: css, sass_dependencies: sass_dependencies)
|
93
|
+
context.metadata.merge(data: css, sass_dependencies: sass_dependencies, map: map)
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
# Public: Build the cache store to be used by the Sass engine.
|
99
|
+
#
|
100
|
+
# input - the input hash.
|
101
|
+
# version - the cache version.
|
102
|
+
#
|
103
|
+
# Override this method if you need to use a different cache than the
|
104
|
+
# Sprockets cache.
|
105
|
+
def build_cache_store(input, version)
|
106
|
+
CacheStore.new(input[:cache], version)
|
107
|
+
end
|
108
|
+
|
109
|
+
def merge_options(options)
|
110
|
+
defaults = @sass_config.dup
|
111
|
+
|
112
|
+
if load_paths = defaults.delete(:load_paths)
|
113
|
+
options[:load_paths] += load_paths
|
114
|
+
end
|
115
|
+
|
116
|
+
options.merge!(defaults)
|
117
|
+
options
|
90
118
|
end
|
91
119
|
|
92
120
|
# Public: Functions injected into Sass context during Sprockets evaluation.
|