sprockets 2.2.3 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +68 -0
- data/README.md +482 -255
- data/bin/sprockets +20 -7
- data/lib/rake/sprocketstask.rb +28 -15
- data/lib/sprockets/add_source_map_comment_to_asset_processor.rb +60 -0
- data/lib/sprockets/asset.rb +142 -207
- data/lib/sprockets/autoload/babel.rb +8 -0
- data/lib/sprockets/autoload/closure.rb +8 -0
- data/lib/sprockets/autoload/coffee_script.rb +8 -0
- data/lib/sprockets/autoload/eco.rb +8 -0
- data/lib/sprockets/autoload/ejs.rb +8 -0
- data/lib/sprockets/autoload/jsminc.rb +8 -0
- data/lib/sprockets/autoload/sass.rb +8 -0
- data/lib/sprockets/autoload/sassc.rb +8 -0
- data/lib/sprockets/autoload/uglifier.rb +8 -0
- data/lib/sprockets/autoload/yui.rb +8 -0
- data/lib/sprockets/autoload/zopfli.rb +7 -0
- data/lib/sprockets/autoload.rb +16 -0
- data/lib/sprockets/babel_processor.rb +66 -0
- data/lib/sprockets/base.rb +89 -249
- data/lib/sprockets/bower.rb +61 -0
- data/lib/sprockets/bundle.rb +105 -0
- data/lib/sprockets/cache/file_store.rb +190 -14
- data/lib/sprockets/cache/memory_store.rb +75 -0
- data/lib/sprockets/cache/null_store.rb +54 -0
- data/lib/sprockets/cache.rb +271 -0
- data/lib/sprockets/cached_environment.rb +64 -0
- data/lib/sprockets/closure_compressor.rb +48 -0
- data/lib/sprockets/coffee_script_processor.rb +39 -0
- data/lib/sprockets/compressing.rb +134 -0
- data/lib/sprockets/configuration.rb +79 -0
- data/lib/sprockets/context.rb +204 -135
- data/lib/sprockets/dependencies.rb +74 -0
- data/lib/sprockets/digest_utils.rb +200 -0
- data/lib/sprockets/directive_processor.rb +224 -216
- data/lib/sprockets/eco_processor.rb +33 -0
- data/lib/sprockets/ejs_processor.rb +32 -0
- data/lib/sprockets/encoding_utils.rb +262 -0
- data/lib/sprockets/environment.rb +23 -68
- data/lib/sprockets/erb_processor.rb +37 -0
- data/lib/sprockets/errors.rb +6 -13
- 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 +16 -0
- data/lib/sprockets/http_utils.rb +135 -0
- data/lib/sprockets/jsminc_compressor.rb +32 -0
- data/lib/sprockets/jst_processor.rb +36 -19
- data/lib/sprockets/loader.rb +343 -0
- data/lib/sprockets/manifest.rb +231 -96
- data/lib/sprockets/manifest_utils.rb +48 -0
- data/lib/sprockets/mime.rb +80 -32
- data/lib/sprockets/npm.rb +52 -0
- data/lib/sprockets/path_dependency_utils.rb +77 -0
- data/lib/sprockets/path_digest_utils.rb +48 -0
- data/lib/sprockets/path_utils.rb +367 -0
- data/lib/sprockets/paths.rb +82 -0
- data/lib/sprockets/preprocessors/default_source_map.rb +49 -0
- data/lib/sprockets/processing.rb +140 -192
- data/lib/sprockets/processor_utils.rb +169 -0
- data/lib/sprockets/resolve.rb +295 -0
- data/lib/sprockets/sass_cache_store.rb +30 -0
- data/lib/sprockets/sass_compressor.rb +63 -0
- data/lib/sprockets/sass_functions.rb +3 -0
- data/lib/sprockets/sass_importer.rb +3 -0
- data/lib/sprockets/sass_processor.rb +313 -0
- data/lib/sprockets/sassc_compressor.rb +56 -0
- data/lib/sprockets/sassc_processor.rb +297 -0
- data/lib/sprockets/server.rb +138 -90
- data/lib/sprockets/source_map_processor.rb +66 -0
- data/lib/sprockets/source_map_utils.rb +483 -0
- data/lib/sprockets/transformers.rb +173 -0
- data/lib/sprockets/uglifier_compressor.rb +66 -0
- data/lib/sprockets/unloaded_asset.rb +139 -0
- data/lib/sprockets/uri_tar.rb +99 -0
- data/lib/sprockets/uri_utils.rb +191 -0
- data/lib/sprockets/utils/gzip.rb +99 -0
- data/lib/sprockets/utils.rb +186 -53
- data/lib/sprockets/version.rb +2 -1
- data/lib/sprockets/yui_compressor.rb +56 -0
- data/lib/sprockets.rb +217 -52
- metadata +250 -59
- data/LICENSE +0 -21
- data/lib/sprockets/asset_attributes.rb +0 -126
- data/lib/sprockets/bundled_asset.rb +0 -79
- data/lib/sprockets/caching.rb +0 -96
- data/lib/sprockets/charset_normalizer.rb +0 -41
- data/lib/sprockets/eco_template.rb +0 -38
- data/lib/sprockets/ejs_template.rb +0 -37
- data/lib/sprockets/engines.rb +0 -74
- data/lib/sprockets/index.rb +0 -99
- data/lib/sprockets/processed_asset.rb +0 -152
- data/lib/sprockets/processor.rb +0 -32
- data/lib/sprockets/safety_colons.rb +0 -28
- data/lib/sprockets/static_asset.rb +0 -57
- data/lib/sprockets/trail.rb +0 -90
@@ -1,7 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'set'
|
2
3
|
require 'shellwords'
|
3
|
-
require 'tilt'
|
4
|
-
require 'yaml'
|
5
4
|
|
6
5
|
module Sprockets
|
7
6
|
# The `DirectiveProcessor` is responsible for parsing and evaluating
|
@@ -20,10 +19,9 @@ module Sprockets
|
|
20
19
|
# *= require "baz"
|
21
20
|
# */
|
22
21
|
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
# custom directives or invent your own directive syntax.
|
22
|
+
# This makes it possible to disable or modify the processor to do whatever
|
23
|
+
# you'd like. You could add your own custom directives or invent your own
|
24
|
+
# directive syntax.
|
27
25
|
#
|
28
26
|
# `Environment#processors` includes `DirectiveProcessor` by default.
|
29
27
|
#
|
@@ -36,25 +34,7 @@ module Sprockets
|
|
36
34
|
#
|
37
35
|
# env.register_processor('text/css', MyProcessor)
|
38
36
|
#
|
39
|
-
class DirectiveProcessor
|
40
|
-
# Directives will only be picked up if they are in the header
|
41
|
-
# of the source file. C style (/* */), JavaScript (//), and
|
42
|
-
# Ruby (#) comments are supported.
|
43
|
-
#
|
44
|
-
# Directives in comments after the first non-whitespace line
|
45
|
-
# of code will not be processed.
|
46
|
-
#
|
47
|
-
HEADER_PATTERN = /
|
48
|
-
\A (
|
49
|
-
(?m:\s*) (
|
50
|
-
(\/\* (?m:.*?) \*\/) |
|
51
|
-
(\#\#\# (?m:.*?) \#\#\#) |
|
52
|
-
(\/\/ .* \n?)+ |
|
53
|
-
(\# .* \n?)+
|
54
|
-
)
|
55
|
-
)+
|
56
|
-
/x
|
57
|
-
|
37
|
+
class DirectiveProcessor
|
58
38
|
# Directives are denoted by a `=` followed by the name, then
|
59
39
|
# argument list.
|
60
40
|
#
|
@@ -65,77 +45,121 @@ module Sprockets
|
|
65
45
|
# //= require "foo"
|
66
46
|
#
|
67
47
|
DIRECTIVE_PATTERN = /
|
68
|
-
^
|
48
|
+
^ \W* = \s* (\w+.*?) (\*\/)? $
|
69
49
|
/x
|
70
50
|
|
71
|
-
|
72
|
-
|
51
|
+
def self.instance
|
52
|
+
# Default to C comment styles
|
53
|
+
@instance ||= new(comments: ["//", ["/*", "*/"]])
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.call(input)
|
57
|
+
instance.call(input)
|
58
|
+
end
|
73
59
|
|
74
|
-
def
|
75
|
-
@
|
60
|
+
def initialize(comments: [])
|
61
|
+
@header_pattern = compile_header_pattern(Array(comments))
|
62
|
+
end
|
76
63
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
@body += "\n" if @body != "" && @body !~ /\n\Z/m
|
64
|
+
def call(input)
|
65
|
+
dup._call(input)
|
66
|
+
end
|
81
67
|
|
82
|
-
|
83
|
-
@
|
68
|
+
def _call(input)
|
69
|
+
@environment = input[:environment]
|
70
|
+
@uri = input[:uri]
|
71
|
+
@filename = input[:filename]
|
72
|
+
@dirname = File.dirname(@filename)
|
73
|
+
# If loading a source map file like `application.js.map` resolve
|
74
|
+
# dependencies using `.js` instead of `.js.map`
|
75
|
+
@content_type = SourceMapProcessor.original_content_type(input[:content_type], error_when_not_found: false)
|
76
|
+
@required = Set.new(input[:metadata][:required])
|
77
|
+
@stubbed = Set.new(input[:metadata][:stubbed])
|
78
|
+
@links = Set.new(input[:metadata][:links])
|
79
|
+
@dependencies = Set.new(input[:metadata][:dependencies])
|
80
|
+
@to_link = Set.new
|
81
|
+
@to_load = Set.new
|
82
|
+
|
83
|
+
data, directives = process_source(input[:data])
|
84
|
+
process_directives(directives)
|
85
|
+
|
86
|
+
{
|
87
|
+
data: data,
|
88
|
+
required: @required,
|
89
|
+
stubbed: @stubbed,
|
90
|
+
links: @links,
|
91
|
+
to_load: @to_load,
|
92
|
+
to_link: @to_link,
|
93
|
+
dependencies: @dependencies
|
94
|
+
}
|
84
95
|
end
|
85
96
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
97
|
+
protected
|
98
|
+
# Directives will only be picked up if they are in the header
|
99
|
+
# of the source file. C style (/* */), JavaScript (//), and
|
100
|
+
# Ruby (#) comments are supported.
|
101
|
+
#
|
102
|
+
# Directives in comments after the first non-whitespace line
|
103
|
+
# of code will not be processed.
|
104
|
+
def compile_header_pattern(comments)
|
105
|
+
re = comments.map { |c|
|
106
|
+
case c
|
107
|
+
when String
|
108
|
+
"(?:#{Regexp.escape(c)}.*\\n?)+"
|
109
|
+
when Array
|
110
|
+
"(?:#{Regexp.escape(c[0])}(?m:.*?)#{Regexp.escape(c[1])})"
|
111
|
+
else
|
112
|
+
raise TypeError, "unknown comment type: #{c.class}"
|
113
|
+
end
|
114
|
+
}.join("|")
|
115
|
+
Regexp.compile("\\A(?:(?m:\\s*)(?:#{re}))+")
|
116
|
+
end
|
93
117
|
|
94
|
-
|
95
|
-
|
118
|
+
def process_source(source)
|
119
|
+
header = source[@header_pattern, 0] || ""
|
120
|
+
body = $' || source
|
96
121
|
|
97
|
-
|
98
|
-
process_source
|
122
|
+
header, directives = extract_directives(header)
|
99
123
|
|
100
|
-
|
101
|
-
|
124
|
+
data = +""
|
125
|
+
data.force_encoding(body.encoding)
|
126
|
+
data << header unless header.empty?
|
127
|
+
data << body
|
128
|
+
# Ensure body ends in a new line
|
129
|
+
data << "\n" if data.length > 0 && data[-1] != "\n"
|
102
130
|
|
103
|
-
|
104
|
-
|
105
|
-
lineno = 0
|
106
|
-
@processed_header ||= header.lines.map { |line|
|
107
|
-
lineno += 1
|
108
|
-
# Replace directive line with a clean break
|
109
|
-
directives.assoc(lineno) ? "\n" : line
|
110
|
-
}.join.chomp
|
111
|
-
end
|
131
|
+
return data, directives
|
132
|
+
end
|
112
133
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
134
|
+
# Returns an Array of directive structures. Each structure
|
135
|
+
# is an Array with the line number as the first element, the
|
136
|
+
# directive name as the second element, followed by any
|
137
|
+
# arguments.
|
138
|
+
#
|
139
|
+
# [[1, "require", "foo"], [2, "require", "bar"]]
|
140
|
+
#
|
141
|
+
def extract_directives(header)
|
142
|
+
processed_header = +""
|
143
|
+
directives = []
|
117
144
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
@directives ||= header.lines.each_with_index.map { |line, index|
|
127
|
-
if directive = line[DIRECTIVE_PATTERN, 1]
|
128
|
-
name, *args = Shellwords.shellwords(directive)
|
129
|
-
if respond_to?("process_#{name}_directive", true)
|
130
|
-
[index + 1, name, *args]
|
145
|
+
header.lines.each_with_index do |line, index|
|
146
|
+
if directive = line[DIRECTIVE_PATTERN, 1]
|
147
|
+
name, *args = Shellwords.shellwords(directive)
|
148
|
+
if respond_to?("process_#{name}_directive", true)
|
149
|
+
directives << [index + 1, name, *args]
|
150
|
+
# Replace directive line with a clean break
|
151
|
+
line = "\n"
|
152
|
+
end
|
131
153
|
end
|
154
|
+
processed_header << line
|
132
155
|
end
|
133
|
-
}.compact
|
134
|
-
end
|
135
156
|
|
136
|
-
|
137
|
-
|
138
|
-
|
157
|
+
processed_header.chomp!
|
158
|
+
# Ensure header ends in a new line like before it was processed
|
159
|
+
processed_header << "\n" if processed_header.length > 0 && header[-1] == "\n"
|
160
|
+
|
161
|
+
return processed_header, directives
|
162
|
+
end
|
139
163
|
|
140
164
|
# Gathers comment directives in the source and processes them.
|
141
165
|
# Any directive method matching `process_*_directive` will
|
@@ -147,8 +171,8 @@ module Sprockets
|
|
147
171
|
# `process_require_glob_directive`.
|
148
172
|
#
|
149
173
|
# class DirectiveProcessor < Sprockets::DirectiveProcessor
|
150
|
-
# def process_require_glob_directive
|
151
|
-
# Dir["#{
|
174
|
+
# def process_require_glob_directive(glob)
|
175
|
+
# Dir["#{dirname}/#{glob}"].sort.each do |filename|
|
152
176
|
# require(filename)
|
153
177
|
# end
|
154
178
|
# end
|
@@ -159,35 +183,20 @@ module Sprockets
|
|
159
183
|
# env.unregister_processor('text/css', Sprockets::DirectiveProcessor)
|
160
184
|
# env.register_processor('text/css', DirectiveProcessor)
|
161
185
|
#
|
162
|
-
def process_directives
|
186
|
+
def process_directives(directives)
|
163
187
|
directives.each do |line_number, name, *args|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
def process_source
|
171
|
-
unless @has_written_body || processed_header.empty?
|
172
|
-
@result << processed_header << "\n"
|
173
|
-
end
|
174
|
-
|
175
|
-
included_pathnames.each do |pathname|
|
176
|
-
@result << context.evaluate(pathname)
|
177
|
-
end
|
178
|
-
|
179
|
-
unless @has_written_body
|
180
|
-
@result << body
|
181
|
-
end
|
182
|
-
|
183
|
-
if compat? && constants.any?
|
184
|
-
@result.gsub!(/<%=(.*?)%>/) { constants[$1.strip] }
|
188
|
+
begin
|
189
|
+
send("process_#{name}_directive", *args)
|
190
|
+
rescue Exception => e
|
191
|
+
e.set_backtrace(["#{@filename}:#{line_number}"] + e.backtrace)
|
192
|
+
raise e
|
193
|
+
end
|
185
194
|
end
|
186
195
|
end
|
187
196
|
|
188
197
|
# The `require` directive functions similar to Ruby's own `require`.
|
189
198
|
# It provides a way to declare a dependency on a file in your path
|
190
|
-
# and ensures
|
199
|
+
# and ensures it's only loaded once before the source file.
|
191
200
|
#
|
192
201
|
# `require` works with files in the environment path:
|
193
202
|
#
|
@@ -204,22 +213,13 @@ module Sprockets
|
|
204
213
|
# //= require "./bar"
|
205
214
|
#
|
206
215
|
def process_require_directive(path)
|
207
|
-
|
208
|
-
if path =~ /<([^>]+)>/
|
209
|
-
path = $1
|
210
|
-
else
|
211
|
-
path = "./#{path}" unless relative?(path)
|
212
|
-
end
|
213
|
-
end
|
214
|
-
|
215
|
-
context.require_asset(path)
|
216
|
+
@required << resolve(path, accept: @content_type, pipeline: :self)
|
216
217
|
end
|
217
218
|
|
218
|
-
# `require_self` causes the body of the current file to be
|
219
|
-
#
|
220
|
-
#
|
221
|
-
#
|
222
|
-
# before other dependencies are loaded.
|
219
|
+
# `require_self` causes the body of the current file to be inserted
|
220
|
+
# before any subsequent `require` directives. Useful in CSS files, where
|
221
|
+
# it's common for the index file to contain global styles that need to
|
222
|
+
# be defined before other dependencies are loaded.
|
223
223
|
#
|
224
224
|
# /*= require "reset"
|
225
225
|
# *= require_self
|
@@ -227,26 +227,10 @@ module Sprockets
|
|
227
227
|
# */
|
228
228
|
#
|
229
229
|
def process_require_self_directive
|
230
|
-
if @
|
230
|
+
if @required.include?(@uri)
|
231
231
|
raise ArgumentError, "require_self can only be called once per source file"
|
232
232
|
end
|
233
|
-
|
234
|
-
context.require_asset(pathname)
|
235
|
-
process_source
|
236
|
-
included_pathnames.clear
|
237
|
-
@has_written_body = true
|
238
|
-
end
|
239
|
-
|
240
|
-
# The `include` directive works similar to `require` but
|
241
|
-
# inserts the contents of the dependency even if it already
|
242
|
-
# has been required.
|
243
|
-
#
|
244
|
-
# //= include "header"
|
245
|
-
#
|
246
|
-
def process_include_directive(path)
|
247
|
-
pathname = context.resolve(path)
|
248
|
-
context.depend_on_asset(pathname)
|
249
|
-
included_pathnames << pathname
|
233
|
+
@required << @uri
|
250
234
|
end
|
251
235
|
|
252
236
|
# `require_directory` requires all the files inside a single
|
@@ -256,27 +240,8 @@ module Sprockets
|
|
256
240
|
# //= require_directory "./javascripts"
|
257
241
|
#
|
258
242
|
def process_require_directory_directive(path = ".")
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
unless (stats = stat(root)) && stats.directory?
|
263
|
-
raise ArgumentError, "require_directory argument must be a directory"
|
264
|
-
end
|
265
|
-
|
266
|
-
context.depend_on(root)
|
267
|
-
|
268
|
-
entries(root).each do |pathname|
|
269
|
-
pathname = root.join(pathname)
|
270
|
-
if pathname.to_s == self.file
|
271
|
-
next
|
272
|
-
elsif context.asset_requirable?(pathname)
|
273
|
-
context.require_asset(pathname)
|
274
|
-
end
|
275
|
-
end
|
276
|
-
else
|
277
|
-
# The path must be relative and start with a `./`.
|
278
|
-
raise ArgumentError, "require_directory argument must be a relative path"
|
279
|
-
end
|
243
|
+
path = expand_relative_dirname(:require_directory, path)
|
244
|
+
require_paths(*@environment.stat_directory_with_dependencies(path))
|
280
245
|
end
|
281
246
|
|
282
247
|
# `require_tree` requires all the nested files in a directory.
|
@@ -285,28 +250,8 @@ module Sprockets
|
|
285
250
|
# //= require_tree "./public"
|
286
251
|
#
|
287
252
|
def process_require_tree_directive(path = ".")
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
unless (stats = stat(root)) && stats.directory?
|
292
|
-
raise ArgumentError, "require_tree argument must be a directory"
|
293
|
-
end
|
294
|
-
|
295
|
-
context.depend_on(root)
|
296
|
-
|
297
|
-
each_entry(root) do |pathname|
|
298
|
-
if pathname.to_s == self.file
|
299
|
-
next
|
300
|
-
elsif stat(pathname).directory?
|
301
|
-
context.depend_on(pathname)
|
302
|
-
elsif context.asset_requirable?(pathname)
|
303
|
-
context.require_asset(pathname)
|
304
|
-
end
|
305
|
-
end
|
306
|
-
else
|
307
|
-
# The path must be relative and start with a `./`.
|
308
|
-
raise ArgumentError, "require_tree argument must be a relative path"
|
309
|
-
end
|
253
|
+
path = expand_relative_dirname(:require_tree, path)
|
254
|
+
require_paths(*@environment.stat_sorted_tree_with_dependencies(path))
|
310
255
|
end
|
311
256
|
|
312
257
|
# Allows you to state a dependency on a file without
|
@@ -322,22 +267,22 @@ module Sprockets
|
|
322
267
|
# //= depend_on "foo.png"
|
323
268
|
#
|
324
269
|
def process_depend_on_directive(path)
|
325
|
-
|
270
|
+
resolve(path)
|
326
271
|
end
|
327
272
|
|
328
273
|
# Allows you to state a dependency on an asset without including
|
329
274
|
# it.
|
330
275
|
#
|
331
276
|
# This is used for caching purposes. Any changes that would
|
332
|
-
#
|
333
|
-
# source file.
|
277
|
+
# invalidate the asset dependency will invalidate the cache of
|
278
|
+
# the source file.
|
334
279
|
#
|
335
280
|
# Unlike `depend_on`, the path must be a requirable asset.
|
336
281
|
#
|
337
282
|
# //= depend_on_asset "bar.js"
|
338
283
|
#
|
339
284
|
def process_depend_on_asset_directive(path)
|
340
|
-
|
285
|
+
to_load(resolve(path))
|
341
286
|
end
|
342
287
|
|
343
288
|
# Allows dependency to be excluded from the asset bundle.
|
@@ -349,58 +294,121 @@ module Sprockets
|
|
349
294
|
# //= stub "jquery"
|
350
295
|
#
|
351
296
|
def process_stub_directive(path)
|
352
|
-
|
297
|
+
@stubbed << resolve(path, accept: @content_type, pipeline: :self)
|
298
|
+
end
|
299
|
+
|
300
|
+
# Declares a linked dependency on the target asset.
|
301
|
+
#
|
302
|
+
# The `path` must be a valid asset and should not already be part of the
|
303
|
+
# bundle. Any linked assets will automatically be compiled along with the
|
304
|
+
# current.
|
305
|
+
#
|
306
|
+
# /*= link "logo.png" */
|
307
|
+
#
|
308
|
+
def process_link_directive(path)
|
309
|
+
uri = to_load(resolve(path))
|
310
|
+
@to_link << uri
|
353
311
|
end
|
354
312
|
|
355
|
-
#
|
313
|
+
# `link_directory` links all the files inside a single
|
314
|
+
# directory. It's similar to `path/*` since it does not follow
|
315
|
+
# nested directories.
|
316
|
+
#
|
317
|
+
# //= link_directory "./fonts"
|
356
318
|
#
|
357
|
-
#
|
358
|
-
#
|
319
|
+
# Use caution when linking against JS or CSS assets. Include an explicit
|
320
|
+
# extension or content type in these cases.
|
359
321
|
#
|
360
|
-
# //=
|
322
|
+
# //= link_directory "./scripts" .js
|
361
323
|
#
|
362
|
-
def
|
363
|
-
|
324
|
+
def process_link_directory_directive(path = ".", accept = nil)
|
325
|
+
path = expand_relative_dirname(:link_directory, path)
|
326
|
+
accept = expand_accept_shorthand(accept)
|
327
|
+
link_paths(*@environment.stat_directory_with_dependencies(path), accept)
|
364
328
|
end
|
365
329
|
|
366
|
-
#
|
367
|
-
|
368
|
-
|
330
|
+
# `link_tree` links all the nested files in a directory.
|
331
|
+
# Its glob equivalent is `path/**/*`.
|
332
|
+
#
|
333
|
+
# //= link_tree "./images"
|
334
|
+
#
|
335
|
+
# Use caution when linking against JS or CSS assets. Include an explicit
|
336
|
+
# extension or content type in these cases.
|
337
|
+
#
|
338
|
+
# //= link_tree "./styles" .css
|
339
|
+
#
|
340
|
+
def process_link_tree_directive(path = ".", accept = nil)
|
341
|
+
path = expand_relative_dirname(:link_tree, path)
|
342
|
+
accept = expand_accept_shorthand(accept)
|
343
|
+
link_paths(*@environment.stat_sorted_tree_with_dependencies(path), accept)
|
369
344
|
end
|
370
345
|
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
346
|
+
private
|
347
|
+
def expand_accept_shorthand(accept)
|
348
|
+
if accept.nil?
|
349
|
+
nil
|
350
|
+
elsif accept.include?("/")
|
351
|
+
accept
|
352
|
+
elsif accept.start_with?(".")
|
353
|
+
@environment.mime_exts[accept]
|
378
354
|
else
|
379
|
-
{}
|
355
|
+
@environment.mime_exts[".#{accept}"]
|
380
356
|
end
|
381
357
|
end
|
382
358
|
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
359
|
+
def require_paths(paths, deps)
|
360
|
+
resolve_paths(paths, deps, accept: @content_type, pipeline: :self) do |uri|
|
361
|
+
@required << uri
|
362
|
+
end
|
387
363
|
end
|
388
364
|
|
389
|
-
|
390
|
-
|
391
|
-
|
365
|
+
def link_paths(paths, deps, accept)
|
366
|
+
resolve_paths(paths, deps, accept: accept) do |uri|
|
367
|
+
@to_link << to_load(uri)
|
368
|
+
end
|
392
369
|
end
|
393
370
|
|
394
|
-
def
|
395
|
-
|
371
|
+
def resolve_paths(paths, deps, **kargs)
|
372
|
+
@dependencies.merge(deps)
|
373
|
+
paths.each do |subpath, stat|
|
374
|
+
next if subpath == @filename || stat.directory?
|
375
|
+
uri, deps = @environment.resolve(subpath, **kargs)
|
376
|
+
@dependencies.merge(deps)
|
377
|
+
yield uri if uri
|
378
|
+
end
|
396
379
|
end
|
397
380
|
|
398
|
-
def
|
399
|
-
|
381
|
+
def expand_relative_dirname(directive, path)
|
382
|
+
if @environment.relative_path?(path)
|
383
|
+
path = File.expand_path(path, @dirname)
|
384
|
+
stat = @environment.stat(path)
|
385
|
+
|
386
|
+
if stat && stat.directory?
|
387
|
+
path
|
388
|
+
else
|
389
|
+
raise ArgumentError, "#{directive} argument must be a directory"
|
390
|
+
end
|
391
|
+
else
|
392
|
+
# The path must be relative and start with a `./`.
|
393
|
+
raise ArgumentError, "#{directive} argument must be a relative path"
|
394
|
+
end
|
395
|
+
end
|
396
|
+
|
397
|
+
def to_load(uri)
|
398
|
+
@to_load << uri
|
399
|
+
uri
|
400
400
|
end
|
401
401
|
|
402
|
-
def
|
403
|
-
|
402
|
+
def resolve(path, **kargs)
|
403
|
+
# Prevent absolute paths in directives
|
404
|
+
if @environment.absolute_path?(path)
|
405
|
+
raise FileOutsidePaths, "can't require absolute file: #{path}"
|
406
|
+
end
|
407
|
+
|
408
|
+
kargs[:base_path] = @dirname
|
409
|
+
uri, deps = @environment.resolve!(path, **kargs)
|
410
|
+
@dependencies.merge(deps)
|
411
|
+
uri
|
404
412
|
end
|
405
413
|
end
|
406
414
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'sprockets/autoload'
|
3
|
+
|
4
|
+
module Sprockets
|
5
|
+
# Processor engine class for the Eco compiler. Depends on the `eco` gem.
|
6
|
+
#
|
7
|
+
# For more infomation see:
|
8
|
+
#
|
9
|
+
# https://github.com/sstephenson/ruby-eco
|
10
|
+
# https://github.com/sstephenson/eco
|
11
|
+
#
|
12
|
+
module EcoProcessor
|
13
|
+
VERSION = '1'
|
14
|
+
|
15
|
+
def self.cache_key
|
16
|
+
@cache_key ||= "#{name}:#{Autoload::Eco::Source::VERSION}:#{VERSION}".freeze
|
17
|
+
end
|
18
|
+
|
19
|
+
# Compile template data with Eco compiler.
|
20
|
+
#
|
21
|
+
# Returns a JS function definition String. The result should be
|
22
|
+
# assigned to a JS variable.
|
23
|
+
#
|
24
|
+
# # => "function(...) {...}"
|
25
|
+
#
|
26
|
+
def self.call(input)
|
27
|
+
data = input[:data]
|
28
|
+
input[:cache].fetch([cache_key, data]) do
|
29
|
+
Autoload::Eco.compile(data)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'sprockets/autoload'
|
3
|
+
|
4
|
+
module Sprockets
|
5
|
+
# Processor engine class for the EJS compiler. Depends on the `ejs` gem.
|
6
|
+
#
|
7
|
+
# For more infomation see:
|
8
|
+
#
|
9
|
+
# https://github.com/sstephenson/ruby-ejs
|
10
|
+
#
|
11
|
+
module EjsProcessor
|
12
|
+
VERSION = '1'
|
13
|
+
|
14
|
+
def self.cache_key
|
15
|
+
@cache_key ||= "#{name}:#{VERSION}".freeze
|
16
|
+
end
|
17
|
+
|
18
|
+
# Compile template data with EJS compiler.
|
19
|
+
#
|
20
|
+
# Returns a JS function definition String. The result should be
|
21
|
+
# assigned to a JS variable.
|
22
|
+
#
|
23
|
+
# # => "function(obj){...}"
|
24
|
+
#
|
25
|
+
def self.call(input)
|
26
|
+
data = input[:data]
|
27
|
+
input[:cache].fetch([cache_key, data]) do
|
28
|
+
Autoload::EJS.compile(data)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|