sprockets 2.6.0 → 4.2.2

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.
Files changed (100) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +118 -0
  3. data/{LICENSE → MIT-LICENSE} +2 -2
  4. data/README.md +541 -289
  5. data/bin/sprockets +20 -7
  6. data/lib/rake/sprocketstask.rb +34 -17
  7. data/lib/sprockets/add_source_map_comment_to_asset_processor.rb +60 -0
  8. data/lib/sprockets/asset.rb +158 -210
  9. data/lib/sprockets/autoload/babel.rb +8 -0
  10. data/lib/sprockets/autoload/closure.rb +8 -0
  11. data/lib/sprockets/autoload/coffee_script.rb +8 -0
  12. data/lib/sprockets/autoload/eco.rb +8 -0
  13. data/lib/sprockets/autoload/ejs.rb +8 -0
  14. data/lib/sprockets/autoload/jsminc.rb +8 -0
  15. data/lib/sprockets/autoload/sass.rb +8 -0
  16. data/lib/sprockets/autoload/sassc.rb +8 -0
  17. data/lib/sprockets/autoload/uglifier.rb +8 -0
  18. data/lib/sprockets/autoload/yui.rb +8 -0
  19. data/lib/sprockets/autoload/zopfli.rb +7 -0
  20. data/lib/sprockets/autoload.rb +16 -0
  21. data/lib/sprockets/babel_processor.rb +66 -0
  22. data/lib/sprockets/base.rb +89 -378
  23. data/lib/sprockets/bower.rb +61 -0
  24. data/lib/sprockets/bundle.rb +105 -0
  25. data/lib/sprockets/cache/file_store.rb +190 -14
  26. data/lib/sprockets/cache/memory_store.rb +84 -0
  27. data/lib/sprockets/cache/null_store.rb +54 -0
  28. data/lib/sprockets/cache.rb +271 -0
  29. data/lib/sprockets/cached_environment.rb +64 -0
  30. data/lib/sprockets/closure_compressor.rb +48 -0
  31. data/lib/sprockets/coffee_script_processor.rb +39 -0
  32. data/lib/sprockets/compressing.rb +134 -0
  33. data/lib/sprockets/configuration.rb +79 -0
  34. data/lib/sprockets/context.rb +166 -150
  35. data/lib/sprockets/dependencies.rb +74 -0
  36. data/lib/sprockets/digest_utils.rb +197 -0
  37. data/lib/sprockets/directive_processor.rb +241 -215
  38. data/lib/sprockets/eco_processor.rb +33 -0
  39. data/lib/sprockets/ejs_processor.rb +32 -0
  40. data/lib/sprockets/encoding_utils.rb +261 -0
  41. data/lib/sprockets/environment.rb +23 -64
  42. data/lib/sprockets/erb_processor.rb +43 -0
  43. data/lib/sprockets/errors.rb +5 -13
  44. data/lib/sprockets/exporters/base.rb +71 -0
  45. data/lib/sprockets/exporters/file_exporter.rb +24 -0
  46. data/lib/sprockets/exporters/zlib_exporter.rb +33 -0
  47. data/lib/sprockets/exporters/zopfli_exporter.rb +14 -0
  48. data/lib/sprockets/exporting.rb +73 -0
  49. data/lib/sprockets/file_reader.rb +16 -0
  50. data/lib/sprockets/http_utils.rb +135 -0
  51. data/lib/sprockets/jsminc_compressor.rb +32 -0
  52. data/lib/sprockets/jst_processor.rb +36 -19
  53. data/lib/sprockets/loader.rb +347 -0
  54. data/lib/sprockets/manifest.rb +228 -112
  55. data/lib/sprockets/manifest_utils.rb +48 -0
  56. data/lib/sprockets/mime.rb +78 -31
  57. data/lib/sprockets/npm.rb +52 -0
  58. data/lib/sprockets/path_dependency_utils.rb +77 -0
  59. data/lib/sprockets/path_digest_utils.rb +48 -0
  60. data/lib/sprockets/path_utils.rb +367 -0
  61. data/lib/sprockets/paths.rb +43 -19
  62. data/lib/sprockets/preprocessors/default_source_map.rb +49 -0
  63. data/lib/sprockets/processing.rb +146 -164
  64. data/lib/sprockets/processor_utils.rb +170 -0
  65. data/lib/sprockets/resolve.rb +295 -0
  66. data/lib/sprockets/sass_cache_store.rb +20 -15
  67. data/lib/sprockets/sass_compressor.rb +55 -10
  68. data/lib/sprockets/sass_functions.rb +3 -70
  69. data/lib/sprockets/sass_importer.rb +3 -29
  70. data/lib/sprockets/sass_processor.rb +313 -0
  71. data/lib/sprockets/sassc_compressor.rb +56 -0
  72. data/lib/sprockets/sassc_processor.rb +297 -0
  73. data/lib/sprockets/server.rb +159 -91
  74. data/lib/sprockets/source_map_processor.rb +66 -0
  75. data/lib/sprockets/source_map_utils.rb +483 -0
  76. data/lib/sprockets/transformers.rb +173 -0
  77. data/lib/sprockets/uglifier_compressor.rb +66 -0
  78. data/lib/sprockets/unloaded_asset.rb +139 -0
  79. data/lib/sprockets/uri_tar.rb +99 -0
  80. data/lib/sprockets/uri_utils.rb +194 -0
  81. data/lib/sprockets/utils/gzip.rb +99 -0
  82. data/lib/sprockets/utils.rb +193 -52
  83. data/lib/sprockets/version.rb +2 -1
  84. data/lib/sprockets/yui_compressor.rb +56 -0
  85. data/lib/sprockets.rb +217 -75
  86. metadata +272 -117
  87. data/lib/sprockets/asset_attributes.rb +0 -131
  88. data/lib/sprockets/bundled_asset.rb +0 -80
  89. data/lib/sprockets/caching.rb +0 -96
  90. data/lib/sprockets/charset_normalizer.rb +0 -41
  91. data/lib/sprockets/eco_template.rb +0 -38
  92. data/lib/sprockets/ejs_template.rb +0 -37
  93. data/lib/sprockets/engines.rb +0 -74
  94. data/lib/sprockets/index.rb +0 -99
  95. data/lib/sprockets/processed_asset.rb +0 -152
  96. data/lib/sprockets/processor.rb +0 -32
  97. data/lib/sprockets/safety_colons.rb +0 -28
  98. data/lib/sprockets/sass_template.rb +0 -60
  99. data/lib/sprockets/scss_template.rb +0 -13
  100. data/lib/sprockets/static_asset.rb +0 -58
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+ require 'set'
3
+ require 'sprockets/path_utils'
4
+ require 'sprockets/uri_utils'
5
+
6
+ module Sprockets
7
+ # Internal: Related PathUtils helpers that also track all the file system
8
+ # calls they make for caching purposes. All functions return a standard
9
+ # return value and a Set of cache dependency URIs that can be used in the
10
+ # future to see if the returned value should be invalidated from cache.
11
+ #
12
+ # entries_with_dependencies("app/assets/javascripts")
13
+ # # => [
14
+ # # ["application.js", "projects.js", "users.js", ...]
15
+ # # #<Set: {"file-digest:/path/to/app/assets/javascripts"}>
16
+ # # ]
17
+ #
18
+ # The returned dependency set can be passed to resolve_dependencies(deps)
19
+ # to check if the returned result is still fresh. In this case, entry always
20
+ # returns a single path, but multiple calls should accumulate dependencies
21
+ # into a single set thats saved off and checked later.
22
+ #
23
+ # resolve_dependencies(deps)
24
+ # # => "\x01\x02\x03"
25
+ #
26
+ # Later, resolving the same set again will produce a different hash if
27
+ # something on the file system has changed.
28
+ #
29
+ # resolve_dependencies(deps)
30
+ # # => "\x03\x04\x05"
31
+ #
32
+ module PathDependencyUtils
33
+ include PathUtils
34
+ include URIUtils
35
+
36
+ # Internal: List directory entries and return a set of dependencies that
37
+ # would invalid the cached return result.
38
+ #
39
+ # See PathUtils#entries
40
+ #
41
+ # path - String directory path
42
+ #
43
+ # Returns an Array of entry names and a Set of dependency URIs.
44
+ def entries_with_dependencies(path)
45
+ return entries(path), Set.new([build_file_digest_uri(path)])
46
+ end
47
+
48
+ # Internal: List directory filenames and associated Stats under a
49
+ # directory.
50
+ #
51
+ # See PathUtils#stat_directory
52
+ #
53
+ # dir - A String directory
54
+ #
55
+ # Returns an Array of filenames and a Set of dependency URIs.
56
+ def stat_directory_with_dependencies(dir)
57
+ return stat_directory(dir).to_a, Set.new([build_file_digest_uri(dir)])
58
+ end
59
+
60
+ # Internal: List directory filenames and associated Stats under an entire
61
+ # directory tree.
62
+ #
63
+ # See PathUtils#stat_sorted_tree
64
+ #
65
+ # dir - A String directory
66
+ #
67
+ # Returns an Array of filenames and a Set of dependency URIs.
68
+ def stat_sorted_tree_with_dependencies(dir)
69
+ deps = Set.new([build_file_digest_uri(dir)])
70
+ results = stat_sorted_tree(dir).map do |path, stat|
71
+ deps << build_file_digest_uri(path) if stat.directory?
72
+ [path, stat]
73
+ end
74
+ return results, deps
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+ require 'sprockets/digest_utils'
3
+ require 'sprockets/path_utils'
4
+
5
+ module Sprockets
6
+ # Internal: Crossover of path and digest utilities functions.
7
+ module PathDigestUtils
8
+ include DigestUtils, PathUtils
9
+
10
+ # Internal: Compute digest for file stat.
11
+ #
12
+ # path - String filename
13
+ # stat - File::Stat
14
+ #
15
+ # Returns String digest bytes.
16
+ def stat_digest(path, stat)
17
+ if stat.directory?
18
+ # If its a directive, digest the list of filenames
19
+ digest_class.digest(self.entries(path).join(','.freeze))
20
+ elsif stat.file?
21
+ # If its a file, digest the contents
22
+ digest_class.file(path.to_s).digest
23
+ else
24
+ raise TypeError, "stat was not a directory or file: #{stat.ftype}"
25
+ end
26
+ end
27
+
28
+ # Internal: Compute digest for path.
29
+ #
30
+ # path - String filename or directory path.
31
+ #
32
+ # Returns String digest bytes or nil.
33
+ def file_digest(path)
34
+ if stat = self.stat(path)
35
+ self.stat_digest(path, stat)
36
+ end
37
+ end
38
+
39
+ # Internal: Compute digest for a set of paths.
40
+ #
41
+ # paths - Array of filename or directory paths.
42
+ #
43
+ # Returns String digest bytes.
44
+ def files_digest(paths)
45
+ self.digest(paths.map { |path| self.file_digest(path) })
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,367 @@
1
+ # frozen_string_literal: true
2
+ module Sprockets
3
+ # Internal: File and path related utilities. Mixed into Environment.
4
+ #
5
+ # Probably would be called FileUtils, but that causes namespace annoyances
6
+ # when code actually wants to reference ::FileUtils.
7
+ module PathUtils
8
+ extend self
9
+ require 'pathname'
10
+
11
+ # Public: Like `File.stat`.
12
+ #
13
+ # path - String file or directory path
14
+ #
15
+ # Returns nil if the file does not exist.
16
+ def stat(path)
17
+ if File.exist?(path)
18
+ File.stat(path.to_s)
19
+ else
20
+ nil
21
+ end
22
+ end
23
+
24
+ # Public: Like `File.file?`.
25
+ #
26
+ # path - String file path.
27
+ #
28
+ # Returns true path exists and is a file.
29
+ def file?(path)
30
+ if stat = self.stat(path)
31
+ stat.file?
32
+ else
33
+ false
34
+ end
35
+ end
36
+
37
+ # Public: Like `File.directory?`.
38
+ #
39
+ # path - String file path.
40
+ #
41
+ # Returns true path exists and is a directory.
42
+ def directory?(path)
43
+ if stat = self.stat(path)
44
+ stat.directory?
45
+ else
46
+ false
47
+ end
48
+ end
49
+
50
+ # Public: A version of `Dir.entries` that filters out `.` files and `~`
51
+ # swap files.
52
+ #
53
+ # path - String directory path
54
+ #
55
+ # Returns an empty `Array` if the directory does not exist.
56
+ def entries(path)
57
+ if File.directory?(path)
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
66
+ else
67
+ []
68
+ end
69
+ end
70
+
71
+ # Public: Check if path is absolute or relative.
72
+ #
73
+ # path - String path.
74
+ #
75
+ # Returns true if path is absolute, otherwise false.
76
+ if File::ALT_SEPARATOR
77
+ # On Windows, ALT_SEPARATOR is \
78
+ # Delegate to Pathname since the logic gets complex.
79
+ def absolute_path?(path)
80
+ Pathname.new(path).absolute?
81
+ end
82
+ else
83
+ def absolute_path?(path)
84
+ path.start_with?(File::SEPARATOR)
85
+ end
86
+ end
87
+
88
+ if File::ALT_SEPARATOR
89
+ SEPARATOR_PATTERN = "#{Regexp.quote(File::SEPARATOR)}|#{Regexp.quote(File::ALT_SEPARATOR)}"
90
+ else
91
+ SEPARATOR_PATTERN = "#{Regexp.quote(File::SEPARATOR)}"
92
+ end
93
+
94
+ # Public: Check if path is explicitly relative.
95
+ # Starts with "./" or "../".
96
+ #
97
+ # path - String path.
98
+ #
99
+ # Returns true if path is relative, otherwise false.
100
+ def relative_path?(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}"
153
+ end
154
+
155
+ # Internal: Get relative path for root path and subpath.
156
+ #
157
+ # path - String path
158
+ # subpath - String subpath of path
159
+ #
160
+ # Returns relative String path if subpath is a subpath of path, or nil if
161
+ # subpath is outside of path.
162
+ def split_subpath(path, subpath)
163
+ return "" if path == subpath
164
+ path = File.join(path, ''.freeze)
165
+ if subpath&.start_with?(path)
166
+ subpath[path.length..-1]
167
+ else
168
+ nil
169
+ end
170
+ end
171
+
172
+ # Internal: Detect root path and base for file in a set of paths.
173
+ #
174
+ # paths - Array of String paths
175
+ # filename - String path of file expected to be in one of the paths.
176
+ #
177
+ # Returns [String root, String path]
178
+ def paths_split(paths, filename)
179
+ paths.each do |path|
180
+ if subpath = split_subpath(path, filename)
181
+ return path, subpath
182
+ end
183
+ end
184
+ nil
185
+ end
186
+
187
+ # Internal: Get path's extensions.
188
+ #
189
+ # path - String
190
+ #
191
+ # Returns an Array of String extnames.
192
+ def path_extnames(path)
193
+ File.basename(path).scan(/\.[^.]+/)
194
+ end
195
+
196
+ # Internal: Match path extnames against available extensions.
197
+ #
198
+ # path - String
199
+ # extensions - Hash of String extnames to values
200
+ #
201
+ # Returns [String extname, Object value] or nil nothing matched.
202
+ def match_path_extname(path, extensions)
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
241
+ end
242
+ end
243
+ matches
244
+ end
245
+
246
+ # Internal: Returns all parents for path
247
+ #
248
+ # path - String absolute filename or directory
249
+ # root - String path to stop at (default: system root)
250
+ #
251
+ # Returns an Array of String paths.
252
+ def path_parents(path, root = nil)
253
+ root = "#{root}#{File::SEPARATOR}" if root
254
+ parents = []
255
+
256
+ loop do
257
+ parent = File.dirname(path)
258
+ break if parent == path
259
+ break if root && !path.start_with?(root)
260
+ parents << path = parent
261
+ end
262
+
263
+ parents
264
+ end
265
+
266
+ # Internal: Find target basename checking upwards from path.
267
+ #
268
+ # basename - String filename: ".sprocketsrc"
269
+ # path - String path to start search: "app/assets/javascripts/app.js"
270
+ # root - String path to stop at (default: system root)
271
+ #
272
+ # Returns String filename or nil.
273
+ def find_upwards(basename, path, root = nil)
274
+ path_parents(path, root).each do |dir|
275
+ filename = File.join(dir, basename)
276
+ return filename if file?(filename)
277
+ end
278
+ nil
279
+ end
280
+
281
+ # Public: Stat all the files under a directory.
282
+ #
283
+ # dir - A String directory
284
+ #
285
+ # Returns an Enumerator of [path, stat].
286
+ def stat_directory(dir)
287
+ return to_enum(__method__, dir) unless block_given?
288
+
289
+ self.entries(dir).each do |entry|
290
+ path = File.join(dir, entry)
291
+ if stat = self.stat(path)
292
+ yield path, stat
293
+ end
294
+ end
295
+
296
+ nil
297
+ end
298
+
299
+ # Public: Recursive stat all the files under a directory.
300
+ #
301
+ # dir - A String directory
302
+ #
303
+ # Returns an Enumerator of [path, stat].
304
+ def stat_tree(dir, &block)
305
+ return to_enum(__method__, dir) unless block_given?
306
+
307
+ self.stat_directory(dir) do |path, stat|
308
+ yield path, stat
309
+
310
+ if stat.directory?
311
+ stat_tree(path, &block)
312
+ end
313
+ end
314
+
315
+ nil
316
+ end
317
+
318
+ # Public: Recursive stat all the files under a directory in alphabetical
319
+ # order.
320
+ #
321
+ # dir - A String directory
322
+ #
323
+ # Returns an Enumerator of [path, stat].
324
+ def stat_sorted_tree(dir, &block)
325
+ return to_enum(__method__, dir) unless block_given?
326
+
327
+ self.stat_directory(dir).sort_by { |path, stat|
328
+ stat.directory? ? "#{path}/" : path
329
+ }.each do |path, stat|
330
+ yield path, stat
331
+
332
+ if stat.directory?
333
+ stat_sorted_tree(path, &block)
334
+ end
335
+ end
336
+
337
+ nil
338
+ end
339
+
340
+ # Public: Write to a file atomically. Useful for situations where you
341
+ # don't want other processes or threads to see half-written files.
342
+ #
343
+ # Utils.atomic_write('important.file') do |file|
344
+ # file.write('hello')
345
+ # end
346
+ #
347
+ # Returns nothing.
348
+ def atomic_write(filename)
349
+ dirname, basename = File.split(filename)
350
+ basename = [
351
+ basename,
352
+ Thread.current.object_id,
353
+ Process.pid,
354
+ rand(1000000)
355
+ ].join('.'.freeze)
356
+ tmpname = File.join(dirname, basename)
357
+
358
+ File.open(tmpname, 'wb+') do |f|
359
+ yield f
360
+ end
361
+
362
+ File.rename(tmpname, filename)
363
+ ensure
364
+ File.delete(tmpname) if File.exist?(tmpname)
365
+ end
366
+ end
367
+ end
@@ -1,36 +1,54 @@
1
+ # frozen_string_literal: true
2
+ require 'sprockets/path_utils'
3
+ require 'sprockets/utils'
4
+
1
5
  module Sprockets
2
6
  module Paths
7
+ include PathUtils, Utils
8
+
3
9
  # Returns `Environment` root.
4
10
  #
5
11
  # All relative paths are expanded with root as its base. To be
6
12
  # useful set this to your applications root directory. (`Rails.root`)
7
13
  def root
8
- @trail.root.dup
14
+ config[:root]
15
+ end
16
+
17
+ # Internal: Change Environment root.
18
+ #
19
+ # Only the initializer should change the root.
20
+ def root=(path)
21
+ self.config = hash_reassoc(config, :root) do
22
+ File.expand_path(path)
23
+ end
9
24
  end
25
+ private :root=
10
26
 
11
27
  # Returns an `Array` of path `String`s.
12
28
  #
13
29
  # These paths will be used for asset logical path lookups.
14
- #
15
- # Note that a copy of the `Array` is returned so mutating will
16
- # have no affect on the environment. See `append_path`,
17
- # `prepend_path`, and `clear_paths`.
18
30
  def paths
19
- @trail.paths.dup
31
+ config[:paths]
20
32
  end
21
33
 
22
34
  # Prepend a `path` to the `paths` list.
23
35
  #
24
36
  # Paths at the end of the `Array` have the least priority.
25
37
  def prepend_path(path)
26
- @trail.prepend_path(path)
38
+ self.config = hash_reassoc(config, :paths) do |paths|
39
+ path = File.expand_path(path, config[:root]).freeze
40
+ paths.unshift(path)
41
+ end
27
42
  end
28
43
 
29
44
  # Append a `path` to the `paths` list.
30
45
  #
31
46
  # Paths at the beginning of the `Array` have a higher priority.
32
47
  def append_path(path)
33
- @trail.append_path(path)
48
+ self.config = hash_reassoc(config, :paths) do |paths|
49
+ path = File.expand_path(path, config[:root]).freeze
50
+ paths.push(path)
51
+ end
34
52
  end
35
53
 
36
54
  # Clear all paths and start fresh.
@@ -39,20 +57,26 @@ module Sprockets
39
57
  # completely wipe the paths list and reappend them in the order
40
58
  # you want.
41
59
  def clear_paths
42
- @trail.paths.dup.each { |path| @trail.remove_path(path) }
60
+ self.config = hash_reassoc(config, :paths) do |paths|
61
+ paths.clear
62
+ end
43
63
  end
44
64
 
45
- # Returns an `Array` of extensions.
65
+ # Public: Iterate over every file under all load paths.
46
66
  #
47
- # These extensions maybe omitted from logical path searches.
48
- #
49
- # # => [".js", ".css", ".coffee", ".sass", ...]
50
- #
51
- def extensions
52
- @trail.extensions.dup
53
- end
67
+ # Returns Enumerator if no block is given.
68
+ def each_file
69
+ return to_enum(__method__) unless block_given?
54
70
 
55
- protected
56
- attr_reader :trail
71
+ paths.each do |root|
72
+ stat_tree(root).each do |filename, stat|
73
+ if stat.file?
74
+ yield filename
75
+ end
76
+ end
77
+ end
78
+
79
+ nil
80
+ end
57
81
  end
58
82
  end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+ module Sprockets
3
+ module Preprocessors
4
+ # Private: Adds a default map to assets when one is not present
5
+ #
6
+ # If the input file already has a source map, it effectively returns the original
7
+ # result. Otherwise it maps 1 for 1 lines original to generated. This is needed
8
+ # Because other generators run after might depend on having a valid source map
9
+ # available.
10
+ class DefaultSourceMap
11
+ def call(input)
12
+ result = { data: input[:data] }
13
+ map = input[:metadata][:map]
14
+ filename = input[:filename]
15
+ load_path = input[:load_path]
16
+ lines = input[:data].lines.length
17
+ basename = File.basename(filename)
18
+ mime_exts = input[:environment].config[:mime_exts]
19
+ pipeline_exts = input[:environment].config[:pipeline_exts]
20
+ if map.nil? || map.empty?
21
+ result[:map] = {
22
+ "version" => 3,
23
+ "file" => PathUtils.split_subpath(load_path, filename),
24
+ "mappings" => default_mappings(lines),
25
+ "sources" => [PathUtils.set_pipeline(basename, mime_exts, pipeline_exts, :source)],
26
+ "names" => []
27
+ }
28
+ else
29
+ result[:map] = map
30
+ end
31
+
32
+ result[:map]["x_sprockets_linecount"] = lines
33
+ return result
34
+ end
35
+
36
+ private
37
+
38
+ def default_mappings(lines)
39
+ if (lines == 0)
40
+ ""
41
+ elsif (lines == 1)
42
+ "AAAA"
43
+ else
44
+ "AAAA;" + "AACA;"*(lines - 2) + "AACA"
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end