sprockets 3.0.3 → 4.2.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 +101 -0
- data/{LICENSE → MIT-LICENSE} +2 -2
- data/README.md +531 -276
- data/bin/sprockets +12 -7
- data/lib/rake/sprocketstask.rb +9 -4
- data/lib/sprockets/add_source_map_comment_to_asset_processor.rb +60 -0
- data/lib/sprockets/asset.rb +41 -28
- 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 +61 -13
- data/lib/sprockets/bower.rb +6 -3
- data/lib/sprockets/bundle.rb +41 -5
- data/lib/sprockets/cache/file_store.rb +32 -7
- data/lib/sprockets/cache/memory_store.rb +28 -10
- data/lib/sprockets/cache/null_store.rb +8 -0
- data/lib/sprockets/cache.rb +43 -6
- data/lib/sprockets/cached_environment.rb +15 -20
- data/lib/sprockets/closure_compressor.rb +6 -11
- data/lib/sprockets/coffee_script_processor.rb +20 -6
- data/lib/sprockets/compressing.rb +62 -2
- data/lib/sprockets/configuration.rb +5 -9
- data/lib/sprockets/context.rb +99 -25
- data/lib/sprockets/dependencies.rb +10 -9
- data/lib/sprockets/digest_utils.rb +103 -62
- data/lib/sprockets/directive_processor.rb +64 -36
- data/lib/sprockets/eco_processor.rb +4 -3
- data/lib/sprockets/ejs_processor.rb +4 -3
- data/lib/sprockets/encoding_utils.rb +1 -0
- data/lib/sprockets/environment.rb +9 -4
- data/lib/sprockets/erb_processor.rb +34 -21
- data/lib/sprockets/errors.rb +1 -0
- data/lib/sprockets/exporters/base.rb +71 -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 +25 -7
- data/lib/sprockets/jsminc_compressor.rb +32 -0
- data/lib/sprockets/jst_processor.rb +11 -10
- data/lib/sprockets/loader.rb +244 -62
- data/lib/sprockets/manifest.rb +100 -46
- 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 +107 -22
- data/lib/sprockets/paths.rb +1 -0
- data/lib/sprockets/preprocessors/default_source_map.rb +49 -0
- data/lib/sprockets/processing.rb +32 -52
- data/lib/sprockets/processor_utils.rb +38 -39
- data/lib/sprockets/resolve.rb +177 -97
- 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 +46 -18
- data/lib/sprockets/sassc_compressor.rb +56 -0
- data/lib/sprockets/sassc_processor.rb +297 -0
- data/lib/sprockets/server.rb +77 -44
- 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 +14 -14
- data/lib/sprockets/utils/gzip.rb +99 -0
- data/lib/sprockets/utils.rb +63 -71
- data/lib/sprockets/version.rb +2 -1
- data/lib/sprockets/yui_compressor.rb +5 -14
- data/lib/sprockets.rb +105 -33
- metadata +157 -27
- 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
data/lib/sprockets/manifest.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'json'
|
2
3
|
require 'time'
|
4
|
+
|
5
|
+
require 'concurrent'
|
6
|
+
|
3
7
|
require 'sprockets/manifest_utils'
|
4
8
|
|
5
9
|
module Sprockets
|
@@ -11,7 +15,7 @@ module Sprockets
|
|
11
15
|
# The JSON is part of the public API and should be considered stable. This
|
12
16
|
# should make it easy to read from other programming languages and processes
|
13
17
|
# that don't have sprockets loaded. See `#assets` and `#files` for more
|
14
|
-
#
|
18
|
+
# information about the structure.
|
15
19
|
class Manifest
|
16
20
|
include ManifestUtils
|
17
21
|
|
@@ -48,14 +52,8 @@ module Sprockets
|
|
48
52
|
@directory ||= File.dirname(@filename) if @filename
|
49
53
|
|
50
54
|
# If directory is given w/o filename, pick a random manifest location
|
51
|
-
@rename_filename = nil
|
52
55
|
if @directory && @filename.nil?
|
53
|
-
@filename = find_directory_manifest(@directory)
|
54
|
-
|
55
|
-
# If legacy manifest name autodetected, mark to rename on save
|
56
|
-
if File.basename(@filename).start_with?("manifest")
|
57
|
-
@rename_filename = File.join(@directory, generate_manifest_path)
|
58
|
-
end
|
56
|
+
@filename = find_directory_manifest(@directory, logger)
|
59
57
|
end
|
60
58
|
|
61
59
|
unless @directory && @filename
|
@@ -114,38 +112,46 @@ module Sprockets
|
|
114
112
|
# Public: Find all assets matching pattern set in environment.
|
115
113
|
#
|
116
114
|
# Returns Enumerator of Assets.
|
117
|
-
def find(*args)
|
115
|
+
def find(*args, &block)
|
118
116
|
unless environment
|
119
117
|
raise Error, "manifest requires environment for compilation"
|
120
118
|
end
|
121
119
|
|
122
120
|
return to_enum(__method__, *args) unless block_given?
|
123
121
|
|
124
|
-
paths, filters = args.flatten.partition { |arg| self.class.simple_logical_path?(arg) }
|
125
|
-
filters = filters.map { |arg| self.class.compile_match_filter(arg) }
|
126
|
-
|
127
122
|
environment = self.environment.cached
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
yield asset
|
123
|
+
promises = args.flatten.map do |path|
|
124
|
+
Concurrent::Promise.execute(executor: executor) do
|
125
|
+
environment.find_all_linked_assets(path).to_a
|
132
126
|
end
|
133
127
|
end
|
134
128
|
|
135
|
-
|
136
|
-
|
137
|
-
if filters.any? { |f| f.call(logical_path, filename) }
|
138
|
-
environment.find_all_linked_assets(filename) do |asset|
|
139
|
-
yield asset
|
140
|
-
end
|
141
|
-
end
|
142
|
-
end
|
129
|
+
promises.each do |promise|
|
130
|
+
promise.value!.each(&block)
|
143
131
|
end
|
144
132
|
|
145
133
|
nil
|
146
134
|
end
|
147
135
|
|
148
|
-
#
|
136
|
+
# Public: Find the source of assets by paths.
|
137
|
+
#
|
138
|
+
# Returns Enumerator of assets file content.
|
139
|
+
def find_sources(*args)
|
140
|
+
return to_enum(__method__, *args) unless block_given?
|
141
|
+
|
142
|
+
if environment
|
143
|
+
find(*args).each do |asset|
|
144
|
+
yield asset.source
|
145
|
+
end
|
146
|
+
else
|
147
|
+
args.each do |path|
|
148
|
+
asset = assets[path]
|
149
|
+
yield File.binread(File.join(dir, asset)) if asset
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
# Compile asset to directory. The asset is written to a
|
149
155
|
# fingerprinted filename like
|
150
156
|
# `application-2e8e9a7c6b0aafa0c9bdeec90ea30213.js`. An entry is
|
151
157
|
# also inserted into the manifest file.
|
@@ -157,29 +163,46 @@ module Sprockets
|
|
157
163
|
raise Error, "manifest requires environment for compilation"
|
158
164
|
end
|
159
165
|
|
160
|
-
filenames
|
166
|
+
filenames = []
|
167
|
+
concurrent_exporters = []
|
161
168
|
|
169
|
+
assets_to_export = Concurrent::Array.new
|
162
170
|
find(*args) do |asset|
|
171
|
+
assets_to_export << asset
|
172
|
+
end
|
173
|
+
|
174
|
+
assets_to_export.each do |asset|
|
175
|
+
mtime = Time.now.iso8601
|
163
176
|
files[asset.digest_path] = {
|
164
177
|
'logical_path' => asset.logical_path,
|
165
|
-
'mtime' =>
|
178
|
+
'mtime' => mtime,
|
166
179
|
'size' => asset.bytesize,
|
167
180
|
'digest' => asset.hexdigest,
|
168
|
-
|
181
|
+
|
182
|
+
# Deprecated: Remove beta integrity attribute in next release.
|
183
|
+
# Callers should DigestUtils.hexdigest_integrity_uri to compute the
|
184
|
+
# digest themselves.
|
185
|
+
'integrity' => DigestUtils.hexdigest_integrity_uri(asset.hexdigest)
|
169
186
|
}
|
170
187
|
assets[asset.logical_path] = asset.digest_path
|
171
188
|
|
172
|
-
|
189
|
+
filenames << asset.filename
|
173
190
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
logger.info "Writing #{target}"
|
178
|
-
asset.write_to target
|
179
|
-
end
|
191
|
+
promise = nil
|
192
|
+
exporters_for_asset(asset) do |exporter|
|
193
|
+
next if exporter.skip?(logger)
|
180
194
|
|
181
|
-
|
195
|
+
if promise.nil?
|
196
|
+
promise = Concurrent::Promise.new(executor: executor) { exporter.call }
|
197
|
+
concurrent_exporters << promise.execute
|
198
|
+
else
|
199
|
+
concurrent_exporters << promise.then { exporter.call }
|
200
|
+
end
|
201
|
+
end
|
182
202
|
end
|
203
|
+
|
204
|
+
# make sure all exporters have finished before returning the main thread
|
205
|
+
concurrent_exporters.each(&:wait!)
|
183
206
|
save
|
184
207
|
|
185
208
|
filenames
|
@@ -192,6 +215,7 @@ module Sprockets
|
|
192
215
|
#
|
193
216
|
def remove(filename)
|
194
217
|
path = File.join(dir, filename)
|
218
|
+
gzip = "#{path}.gz"
|
195
219
|
logical_path = files[filename]['logical_path']
|
196
220
|
|
197
221
|
if assets[logical_path] == filename
|
@@ -200,6 +224,7 @@ module Sprockets
|
|
200
224
|
|
201
225
|
files.delete(filename)
|
202
226
|
FileUtils.rm(path) if File.exist?(path)
|
227
|
+
FileUtils.rm(gzip) if File.exist?(gzip)
|
203
228
|
|
204
229
|
save
|
205
230
|
|
@@ -230,9 +255,9 @@ module Sprockets
|
|
230
255
|
# Sort by timestamp
|
231
256
|
Time.parse(attrs['mtime'])
|
232
257
|
}.reverse.each_with_index.drop_while { |(_, attrs), index|
|
233
|
-
|
258
|
+
_age = [0, Time.now - Time.parse(attrs['mtime'])].max
|
234
259
|
# Keep if under age or within the count limit
|
235
|
-
|
260
|
+
_age < age || index < count
|
236
261
|
}.each { |(path, _), _|
|
237
262
|
# Remove old assets
|
238
263
|
remove(path)
|
@@ -244,18 +269,13 @@ module Sprockets
|
|
244
269
|
def clobber
|
245
270
|
FileUtils.rm_r(directory) if File.exist?(directory)
|
246
271
|
logger.info "Removed #{directory}"
|
272
|
+
# if we have an environment clear the cache too
|
273
|
+
environment.cache.clear if environment
|
247
274
|
nil
|
248
275
|
end
|
249
276
|
|
250
|
-
# Persist
|
277
|
+
# Persist manifest back to FS
|
251
278
|
def save
|
252
|
-
if @rename_filename
|
253
|
-
logger.info "Renaming #{@filename} to #{@rename_filename}"
|
254
|
-
FileUtils.mv(@filename, @rename_filename)
|
255
|
-
@filename = @rename_filename
|
256
|
-
@rename_filename = nil
|
257
|
-
end
|
258
|
-
|
259
279
|
data = json_encode(@data)
|
260
280
|
FileUtils.mkdir_p File.dirname(@filename)
|
261
281
|
PathUtils.atomic_write(@filename) do |f|
|
@@ -264,6 +284,36 @@ module Sprockets
|
|
264
284
|
end
|
265
285
|
|
266
286
|
private
|
287
|
+
|
288
|
+
# Given an asset, finds all exporters that
|
289
|
+
# match its mime-type.
|
290
|
+
#
|
291
|
+
# Will yield each expoter to the passed in block.
|
292
|
+
#
|
293
|
+
# array = []
|
294
|
+
# puts asset.content_type # => "application/javascript"
|
295
|
+
# exporters_for_asset(asset) do |exporter|
|
296
|
+
# array << exporter
|
297
|
+
# end
|
298
|
+
# # puts array => [Exporters::FileExporter, Exporters::ZlibExporter]
|
299
|
+
def exporters_for_asset(asset)
|
300
|
+
exporters = [Exporters::FileExporter]
|
301
|
+
|
302
|
+
environment.exporters.each do |mime_type, exporter_list|
|
303
|
+
next unless asset.content_type
|
304
|
+
next unless environment.match_mime_type? asset.content_type, mime_type
|
305
|
+
exporter_list.each do |exporter|
|
306
|
+
exporters << exporter
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
exporters.uniq!
|
311
|
+
|
312
|
+
exporters.each do |exporter|
|
313
|
+
yield exporter.new(asset: asset, environment: environment, directory: dir)
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
267
317
|
def json_decode(obj)
|
268
318
|
JSON.parse(obj, create_additions: false)
|
269
319
|
end
|
@@ -281,5 +331,9 @@ module Sprockets
|
|
281
331
|
logger
|
282
332
|
end
|
283
333
|
end
|
334
|
+
|
335
|
+
def executor
|
336
|
+
@executor ||= environment.export_concurrent ? :fast : :immediate
|
337
|
+
end
|
284
338
|
end
|
285
339
|
end
|
@@ -1,4 +1,6 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'securerandom'
|
3
|
+
require 'logger'
|
2
4
|
|
3
5
|
module Sprockets
|
4
6
|
# Public: Manifest utilities.
|
@@ -6,7 +8,6 @@ module Sprockets
|
|
6
8
|
extend self
|
7
9
|
|
8
10
|
MANIFEST_RE = /^\.sprockets-manifest-[0-9a-f]{32}.json$/
|
9
|
-
LEGACY_MANIFEST_RE = /^manifest(-[0-9a-f]{32})?.json$/
|
10
11
|
|
11
12
|
# Public: Generate a new random manifest path.
|
12
13
|
#
|
@@ -33,12 +34,14 @@ module Sprockets
|
|
33
34
|
# # => "/app/public/assets/.sprockets-manifest-abc123.json"
|
34
35
|
#
|
35
36
|
# Returns String filename.
|
36
|
-
def find_directory_manifest(dirname)
|
37
|
+
def find_directory_manifest(dirname, logger = Logger.new($stderr))
|
37
38
|
entries = File.directory?(dirname) ? Dir.entries(dirname) : []
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
39
|
+
manifest_entries = entries.select { |e| e =~ MANIFEST_RE }
|
40
|
+
if manifest_entries.length > 1
|
41
|
+
manifest_entries.sort!
|
42
|
+
logger.warn("Found multiple manifests: #{manifest_entries}. Choosing the first alphabetically: #{manifest_entries.first}")
|
43
|
+
end
|
44
|
+
entry = manifest_entries.first || generate_manifest_path
|
42
45
|
File.join(dirname, entry)
|
43
46
|
end
|
44
47
|
end
|
data/lib/sprockets/mime.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'sprockets/encoding_utils'
|
2
3
|
require 'sprockets/http_utils'
|
3
4
|
require 'sprockets/utils'
|
@@ -36,29 +37,18 @@ module Sprockets
|
|
36
37
|
|
37
38
|
# Public: Register a new mime type.
|
38
39
|
#
|
39
|
-
# mime_type
|
40
|
-
#
|
41
|
-
#
|
42
|
-
#
|
43
|
-
# See EncodingUtils.
|
40
|
+
# mime_type - String MIME Type
|
41
|
+
# extensions - Array of String extnames
|
42
|
+
# charset - Proc/Method that detects the charset of a file.
|
43
|
+
# See EncodingUtils.
|
44
44
|
#
|
45
45
|
# Returns nothing.
|
46
|
-
def register_mime_type(mime_type,
|
47
|
-
|
48
|
-
if options.is_a?(String)
|
49
|
-
options = { extensions: [options] }
|
50
|
-
end
|
51
|
-
|
52
|
-
extnames = Array(options[:extensions]).map { |extname|
|
53
|
-
Sprockets::Utils.normalize_extension(extname)
|
54
|
-
}
|
46
|
+
def register_mime_type(mime_type, extensions: [], charset: nil)
|
47
|
+
extnames = Array(extensions)
|
55
48
|
|
56
|
-
charset = options[:charset]
|
57
49
|
charset ||= :default if mime_type.start_with?('text/')
|
58
50
|
charset = EncodingUtils::CHARSET_DETECT[charset] if charset.is_a?(Symbol)
|
59
51
|
|
60
|
-
self.computed_config = {}
|
61
|
-
|
62
52
|
self.config = hash_reassoc(config, :mime_exts) do |mime_exts|
|
63
53
|
extnames.each do |extname|
|
64
54
|
mime_exts[extname] = mime_type
|
@@ -97,34 +87,10 @@ module Sprockets
|
|
97
87
|
data = File.binread(filename)
|
98
88
|
|
99
89
|
if detect = mime_type_charset_detecter(content_type)
|
100
|
-
detect.call(data).encode(Encoding::UTF_8, :
|
90
|
+
detect.call(data).encode(Encoding::UTF_8, universal_newline: true)
|
101
91
|
else
|
102
92
|
data
|
103
93
|
end
|
104
94
|
end
|
105
|
-
|
106
|
-
private
|
107
|
-
def extname_map
|
108
|
-
self.computed_config[:_extnames] ||= compute_extname_map
|
109
|
-
end
|
110
|
-
|
111
|
-
def compute_extname_map
|
112
|
-
graph = {}
|
113
|
-
|
114
|
-
([nil] + pipelines.keys.map(&:to_s)).each do |pipeline|
|
115
|
-
pipeline_extname = ".#{pipeline}" if pipeline
|
116
|
-
([[nil, nil]] + config[:mime_exts].to_a).each do |format_extname, format_type|
|
117
|
-
4.times do |n|
|
118
|
-
config[:engines].keys.permutation(n).each do |engine_extnames|
|
119
|
-
key = "#{pipeline_extname}#{format_extname}#{engine_extnames.join}"
|
120
|
-
type = format_type || config[:engine_mime_types][engine_extnames.first]
|
121
|
-
graph[key] = {type: type, engines: engine_extnames, pipeline: pipeline}
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
graph
|
128
|
-
end
|
129
95
|
end
|
130
96
|
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module Sprockets
|
5
|
+
module Npm
|
6
|
+
# Internal: Override resolve_alternates to install package.json behavior.
|
7
|
+
#
|
8
|
+
# load_path - String environment path
|
9
|
+
# logical_path - String path relative to base
|
10
|
+
#
|
11
|
+
# Returns candidate filenames.
|
12
|
+
def resolve_alternates(load_path, logical_path)
|
13
|
+
candidates, deps = super
|
14
|
+
|
15
|
+
dirname = File.join(load_path, logical_path)
|
16
|
+
|
17
|
+
if directory?(dirname)
|
18
|
+
filename = File.join(dirname, 'package.json')
|
19
|
+
|
20
|
+
if self.file?(filename)
|
21
|
+
deps << build_file_digest_uri(filename)
|
22
|
+
read_package_directives(dirname, filename) do |path|
|
23
|
+
if file?(path)
|
24
|
+
candidates << path
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
return candidates, deps
|
31
|
+
end
|
32
|
+
|
33
|
+
# Internal: Read package.json's main and style directives.
|
34
|
+
#
|
35
|
+
# dirname - String path to component directory.
|
36
|
+
# filename - String path to package.json.
|
37
|
+
#
|
38
|
+
# Returns nothing.
|
39
|
+
def read_package_directives(dirname, filename)
|
40
|
+
package = JSON.parse(File.read(filename), create_additions: false)
|
41
|
+
|
42
|
+
case package['main']
|
43
|
+
when String
|
44
|
+
yield File.expand_path(package['main'], dirname)
|
45
|
+
when nil
|
46
|
+
yield File.expand_path('index.js', dirname)
|
47
|
+
end
|
48
|
+
|
49
|
+
yield File.expand_path(package['style'], dirname) if package['style']
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -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),
|
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,
|
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
|
data/lib/sprockets/path_utils.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
3
2
|
module Sprockets
|
4
3
|
# Internal: File and path related utilities. Mixed into Environment.
|
5
4
|
#
|
@@ -7,6 +6,7 @@ module Sprockets
|
|
7
6
|
# when code actually wants to reference ::FileUtils.
|
8
7
|
module PathUtils
|
9
8
|
extend self
|
9
|
+
require 'pathname'
|
10
10
|
|
11
11
|
# Public: Like `File.stat`.
|
12
12
|
#
|
@@ -55,9 +55,14 @@ module Sprockets
|
|
55
55
|
# Returns an empty `Array` if the directory does not exist.
|
56
56
|
def entries(path)
|
57
57
|
if File.directory?(path)
|
58
|
-
Dir.entries(path, :
|
59
|
-
|
60
|
-
|
58
|
+
entries = Dir.entries(path, encoding: Encoding.default_internal)
|
59
|
+
entries.reject! { |entry|
|
60
|
+
entry.start_with?(".".freeze) ||
|
61
|
+
(entry.start_with?("#".freeze) && entry.end_with?("#".freeze)) ||
|
62
|
+
entry.end_with?("~".freeze)
|
63
|
+
}
|
64
|
+
entries.sort!
|
65
|
+
entries
|
61
66
|
else
|
62
67
|
[]
|
63
68
|
end
|
@@ -69,8 +74,6 @@ module Sprockets
|
|
69
74
|
#
|
70
75
|
# Returns true if path is absolute, otherwise false.
|
71
76
|
if File::ALT_SEPARATOR
|
72
|
-
require 'pathname'
|
73
|
-
|
74
77
|
# On Windows, ALT_SEPARATOR is \
|
75
78
|
# Delegate to Pathname since the logic gets complex.
|
76
79
|
def absolute_path?(path)
|
@@ -78,7 +81,7 @@ module Sprockets
|
|
78
81
|
end
|
79
82
|
else
|
80
83
|
def absolute_path?(path)
|
81
|
-
path
|
84
|
+
path.start_with?(File::SEPARATOR)
|
82
85
|
end
|
83
86
|
end
|
84
87
|
|
@@ -95,7 +98,58 @@ module Sprockets
|
|
95
98
|
#
|
96
99
|
# Returns true if path is relative, otherwise false.
|
97
100
|
def relative_path?(path)
|
98
|
-
path
|
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}"
|
99
153
|
end
|
100
154
|
|
101
155
|
# Internal: Get relative path for root path and subpath.
|
@@ -107,8 +161,8 @@ module Sprockets
|
|
107
161
|
# subpath is outside of path.
|
108
162
|
def split_subpath(path, subpath)
|
109
163
|
return "" if path == subpath
|
110
|
-
path = File.join(path, '')
|
111
|
-
if subpath
|
164
|
+
path = File.join(path, ''.freeze)
|
165
|
+
if subpath&.start_with?(path)
|
112
166
|
subpath[path.length..-1]
|
113
167
|
else
|
114
168
|
nil
|
@@ -146,16 +200,47 @@ module Sprockets
|
|
146
200
|
#
|
147
201
|
# Returns [String extname, Object value] or nil nothing matched.
|
148
202
|
def match_path_extname(path, extensions)
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
203
|
+
basename = File.basename(path)
|
204
|
+
|
205
|
+
i = basename.index('.'.freeze)
|
206
|
+
while i && i < basename.length - 1
|
207
|
+
extname = basename[i..-1]
|
208
|
+
if value = extensions[extname]
|
209
|
+
return extname, value
|
210
|
+
end
|
211
|
+
|
212
|
+
i = basename.index('.'.freeze, i+1)
|
213
|
+
end
|
214
|
+
|
215
|
+
nil
|
216
|
+
end
|
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
|
156
241
|
end
|
157
242
|
end
|
158
|
-
|
243
|
+
matches
|
159
244
|
end
|
160
245
|
|
161
246
|
# Internal: Returns all parents for path
|
@@ -267,16 +352,16 @@ module Sprockets
|
|
267
352
|
Thread.current.object_id,
|
268
353
|
Process.pid,
|
269
354
|
rand(1000000)
|
270
|
-
].join('.')
|
355
|
+
].join('.'.freeze)
|
271
356
|
tmpname = File.join(dirname, basename)
|
272
357
|
|
273
358
|
File.open(tmpname, 'wb+') do |f|
|
274
359
|
yield f
|
275
360
|
end
|
276
361
|
|
277
|
-
|
362
|
+
File.rename(tmpname, filename)
|
278
363
|
ensure
|
279
|
-
|
364
|
+
File.delete(tmpname) if File.exist?(tmpname)
|
280
365
|
end
|
281
366
|
end
|
282
367
|
end
|
data/lib/sprockets/paths.rb
CHANGED