sprockets-sass 1.3.1 → 2.0.0.beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.reek +12 -0
- data/.rubocop.yml +77 -0
- data/.travis.yml +16 -0
- data/Appraisals +32 -15
- data/Gemfile +5 -0
- data/README.md +41 -4
- data/Rakefile +15 -3
- data/gemfiles/compass_0.11.gemfile +1 -1
- data/gemfiles/sass_3.1.gemfile +1 -1
- data/gemfiles/sass_3.3.gemfile +8 -0
- data/gemfiles/sass_3.4.gemfile +8 -0
- data/gemfiles/sprockets_2.10.gemfile +1 -1
- data/gemfiles/sprockets_2.11.gemfile +1 -1
- data/gemfiles/sprockets_2.2.gemfile +1 -1
- data/gemfiles/sprockets_2.3.gemfile +1 -1
- data/gemfiles/sprockets_2.4.gemfile +1 -1
- data/gemfiles/sprockets_2.5.gemfile +1 -1
- data/gemfiles/sprockets_2.6.gemfile +1 -1
- data/gemfiles/sprockets_2.7.gemfile +1 -1
- data/gemfiles/sprockets_2.8.gemfile +1 -1
- data/gemfiles/sprockets_2.9.gemfile +1 -1
- data/gemfiles/sprockets_3.7.gemfile +9 -0
- data/gemfiles/sprockets_4.0.gemfile +10 -0
- data/gemfiles/sprockets_4.0_beta2.gemfile +9 -0
- data/lib/sprockets-sass.rb +1 -0
- data/lib/sprockets/sass.rb +37 -12
- data/lib/sprockets/sass/functions.rb +24 -159
- data/lib/sprockets/sass/registration.rb +126 -0
- data/lib/sprockets/sass/utils.rb +115 -0
- data/lib/sprockets/sass/v2/cache_store.rb +26 -0
- data/lib/sprockets/sass/v2/compressor.rb +31 -0
- data/lib/sprockets/sass/v2/functions.rb +142 -0
- data/lib/sprockets/sass/v2/importer.rb +209 -0
- data/lib/sprockets/sass/v2/sass_template.rb +221 -0
- data/lib/sprockets/sass/v2/scss_template.rb +14 -0
- data/lib/sprockets/sass/v3/cache_store.rb +28 -0
- data/lib/sprockets/sass/v3/compressor.rb +97 -0
- data/lib/sprockets/sass/v3/functions.rb +12 -0
- data/lib/sprockets/sass/v3/importer.rb +212 -0
- data/lib/sprockets/sass/v3/sass_template.rb +37 -0
- data/lib/sprockets/sass/v3/scss_template.rb +15 -0
- data/lib/sprockets/sass/v4/cache_store.rb +11 -0
- data/lib/sprockets/sass/v4/compressor.rb +11 -0
- data/lib/sprockets/sass/v4/functions.rb +12 -0
- data/lib/sprockets/sass/v4/importer.rb +105 -0
- data/lib/sprockets/sass/v4/sass_template.rb +27 -0
- data/lib/sprockets/sass/v4/scss_template.rb +16 -0
- data/lib/sprockets/sass/version.rb +2 -1
- data/spec/custom_importer_spec.rb +4 -6
- data/spec/spec_helper.rb +30 -3
- data/spec/sprockets-sass_spec.rb +101 -61
- data/spec/support/be_fresh_matcher.rb +10 -6
- data/spec/support/dummy_importer.rb +1 -1
- data/spec/support/fail_postprocessor.rb +23 -0
- data/spec/support/sass_template.rb +11 -0
- data/sprockets-sass.gemspec +27 -8
- metadata +92 -95
- data/gemfiles/compass_0.12.gemfile +0 -7
- data/gemfiles/sass_3.2.gemfile +0 -7
- data/gemfiles/sprockets_2.0.gemfile +0 -7
- data/gemfiles/sprockets_2.1.gemfile +0 -9
- data/lib/sprockets/sass/cache_store.rb +0 -27
- data/lib/sprockets/sass/compressor.rb +0 -22
- data/lib/sprockets/sass/importer.rb +0 -142
- data/lib/sprockets/sass/sass_template.rb +0 -115
- data/lib/sprockets/sass/scss_template.rb +0 -12
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Sprockets
|
3
|
+
module Sass
|
4
|
+
module V2
|
5
|
+
# Class used to compress CSS files
|
6
|
+
class Compressor
|
7
|
+
def self.instance
|
8
|
+
@instance ||= new
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.compress(input)
|
12
|
+
instance.compress(input)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Compresses the given CSS using Sass::Engine's
|
16
|
+
# :compressed output style.
|
17
|
+
def compress(css)
|
18
|
+
if css.count("\n") >= 2
|
19
|
+
::Sass::Engine.new(css,
|
20
|
+
syntax: :scss,
|
21
|
+
cache: false,
|
22
|
+
read_cache: false,
|
23
|
+
style: :compressed).render
|
24
|
+
else
|
25
|
+
css
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Sprockets
|
3
|
+
module Sass
|
4
|
+
module V2
|
5
|
+
# Module used to inject helpers into SASS engine
|
6
|
+
module Functions
|
7
|
+
# Using Sprockets::Context#asset_data_uri return a Base64-encoded `data:`
|
8
|
+
# URI with the contents of the asset at the specified path.
|
9
|
+
#
|
10
|
+
# === Examples
|
11
|
+
#
|
12
|
+
# background: asset-data-uri("image.jpg"); // background: url(data:image/jpeg;base64,...);
|
13
|
+
#
|
14
|
+
def asset_data_uri(source)
|
15
|
+
::Sass::Script::String.new "url(#{sprockets_context.asset_data_uri(source.value)})"
|
16
|
+
end
|
17
|
+
|
18
|
+
# Using Sprockets::Helpers#asset_path, return the full path
|
19
|
+
# for the given +source+ as a Sass String. This supports keyword
|
20
|
+
# arguments that mirror the +options+.
|
21
|
+
#
|
22
|
+
# === Examples
|
23
|
+
#
|
24
|
+
# background: url(asset-path("image.jpg")); // background: url("/assets/image.jpg");
|
25
|
+
# background: url(asset-path("image.jpg", $digest: true)); // background: url("/assets/image-27a8f1f96afd8d4c67a59eb9447f45bd.jpg");
|
26
|
+
#
|
27
|
+
def asset_path(source, options = {})
|
28
|
+
# Work with the Sass::Rails #asset_path API
|
29
|
+
if options.respond_to? :value
|
30
|
+
kind = options.value
|
31
|
+
options = {}
|
32
|
+
end
|
33
|
+
|
34
|
+
if kind && sprockets_context.respond_to?("#{kind}_path")
|
35
|
+
::Sass::Script::String.new sprockets_context.send("#{kind}_path", source.value), :string
|
36
|
+
else
|
37
|
+
::Sass::Script::String.new sprockets_context.asset_path(source.value, map_options(options)).to_s, :string
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Using Sprockets::Helpers#asset_path, return the url CSS
|
42
|
+
# for the given +source+ as a Sass String. This supports keyword
|
43
|
+
# arguments that mirror the +options+.
|
44
|
+
#
|
45
|
+
# === Examples
|
46
|
+
#
|
47
|
+
# background: asset-url("image.jpg"); // background: url("/assets/image.jpg");
|
48
|
+
# background: asset-url("image.jpg", $digest: true); // background: url("/assets/image-27a8f1f96afd8d4c67a59eb9447f45bd.jpg");
|
49
|
+
#
|
50
|
+
def asset_url(source, options = {})
|
51
|
+
::Sass::Script::String.new "url(#{asset_path(source, options)})"
|
52
|
+
end
|
53
|
+
|
54
|
+
# Using Sprockets::Helpers#image_path, return the full path
|
55
|
+
# for the given +source+ as a Sass String. This supports keyword
|
56
|
+
# arguments that mirror the +options+.
|
57
|
+
#
|
58
|
+
# === Examples
|
59
|
+
#
|
60
|
+
# background: url(image-path("image.jpg")); // background: url("/assets/image.jpg");
|
61
|
+
# background: url(image-path("image.jpg", $digest: true)); // background: url("/assets/image-27a8f1f96afd8d4c67a59eb9447f45bd.jpg");
|
62
|
+
#
|
63
|
+
def image_path(source, options = {})
|
64
|
+
::Sass::Script::String.new sprockets_context.image_path(source.value, map_options(options)).to_s, :string
|
65
|
+
end
|
66
|
+
|
67
|
+
# Using Sprockets::Helpers#image_path, return the url CSS
|
68
|
+
# for the given +source+ as a Sass String. This supports keyword
|
69
|
+
# arguments that mirror the +options+.
|
70
|
+
#
|
71
|
+
# === Examples
|
72
|
+
#
|
73
|
+
# background: image-url("image.jpg"); // background: url("/assets/image.jpg");
|
74
|
+
# background: image-url("image.jpg", $digest: true); // background: url("/assets/image-27a8f1f96afd8d4c67a59eb9447f45bd.jpg");
|
75
|
+
#
|
76
|
+
def image_url(source, options = {}, _cache_buster = nil)
|
77
|
+
# Work with the Compass #image_url API
|
78
|
+
if options.respond_to? :value
|
79
|
+
case options.value
|
80
|
+
when true
|
81
|
+
return image_path source
|
82
|
+
else
|
83
|
+
options = {}
|
84
|
+
end
|
85
|
+
end
|
86
|
+
::Sass::Script::String.new "url(#{image_path(source, options)})"
|
87
|
+
end
|
88
|
+
|
89
|
+
# Using Sprockets::Helpers#font_path, return the full path
|
90
|
+
# for the given +source+ as a Sass String. This supports keyword
|
91
|
+
# arguments that mirror the +options+.
|
92
|
+
#
|
93
|
+
# === Examples
|
94
|
+
#
|
95
|
+
# src: url(font-path("font.ttf")); // src: url("/assets/font.ttf");
|
96
|
+
# src: url(font-path("font.ttf", $digest: true)); // src: url("/assets/font-27a8f1f96afd8d4c67a59eb9447f45bd.ttf");
|
97
|
+
#
|
98
|
+
def font_path(source, options = {})
|
99
|
+
::Sass::Script::String.new sprockets_context.font_path(source.value, map_options(options)).to_s, :string
|
100
|
+
end
|
101
|
+
|
102
|
+
# Using Sprockets::Helpers#font_path, return the url CSS
|
103
|
+
# for the given +source+ as a Sass String. This supports keyword
|
104
|
+
# arguments that mirror the +options+.
|
105
|
+
#
|
106
|
+
# === Examples
|
107
|
+
#
|
108
|
+
# src: font-url("font.ttf"); // src: url("/assets/font.ttf");
|
109
|
+
# src: font-url("image.jpg", $digest: true); // src: url("/assets/font-27a8f1f96afd8d4c67a59eb9447f45bd.ttf");
|
110
|
+
#
|
111
|
+
def font_url(source, options = {})
|
112
|
+
# Work with the Compass #font_url API
|
113
|
+
if options.respond_to? :value
|
114
|
+
case options.value
|
115
|
+
when true
|
116
|
+
return font_path source
|
117
|
+
else
|
118
|
+
options = {}
|
119
|
+
end
|
120
|
+
end
|
121
|
+
::Sass::Script::String.new "url(#{font_path(source, options)})"
|
122
|
+
end
|
123
|
+
|
124
|
+
protected
|
125
|
+
|
126
|
+
# Returns a reference to the Sprocket's context through
|
127
|
+
# the importer.
|
128
|
+
def sprockets_context # :nodoc:
|
129
|
+
options[:custom][:sprockets_context]
|
130
|
+
end
|
131
|
+
|
132
|
+
# Returns an options hash where the keys are symbolized
|
133
|
+
# and the values are unwrapped Sass literals.
|
134
|
+
def map_options(options = {}) # :nodoc:
|
135
|
+
::Sass::Util.map_hash(options) do |key, value|
|
136
|
+
[key.to_sym, value.respond_to?(:value) ? value.value : value]
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
@@ -0,0 +1,209 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sprockets
|
4
|
+
module Sass
|
5
|
+
module V2
|
6
|
+
# class used for importing files from SCCS and SASS files
|
7
|
+
class Importer < ::Sass::Importers::Base
|
8
|
+
GLOB = /\*|\[.+\]/
|
9
|
+
|
10
|
+
# @see Sass::Importers::Base#find_relative
|
11
|
+
def find_relative(path, base_path, options)
|
12
|
+
if path.to_s =~ GLOB
|
13
|
+
engine_from_glob(path, base_path, options)
|
14
|
+
else
|
15
|
+
engine_from_path(path, base_path, options)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# @see Sass::Importers::Base#find
|
20
|
+
def find(path, options)
|
21
|
+
engine_from_path(path, nil, options)
|
22
|
+
end
|
23
|
+
|
24
|
+
# @see Sass::Importers::Base#mtime
|
25
|
+
def mtime(path, _options)
|
26
|
+
if pathname = resolve(path)
|
27
|
+
pathname.mtime
|
28
|
+
end
|
29
|
+
rescue Errno::ENOENT
|
30
|
+
nil
|
31
|
+
end
|
32
|
+
|
33
|
+
# @see Sass::Importers::Base#key
|
34
|
+
def key(path, _options)
|
35
|
+
path = Pathname.new(path)
|
36
|
+
["#{self.class.name}:#{path.dirname.expand_path}", path.basename]
|
37
|
+
end
|
38
|
+
|
39
|
+
# @see Sass::Importers::Base#to_s
|
40
|
+
def to_s
|
41
|
+
inspect
|
42
|
+
end
|
43
|
+
|
44
|
+
protected
|
45
|
+
|
46
|
+
# Create a Sass::Engine from the given path.
|
47
|
+
def engine_from_path(path, base_path, options)
|
48
|
+
context = options[:custom][:sprockets_context]
|
49
|
+
(pathname = resolve(context, path, base_path)) || (return nil)
|
50
|
+
context.depend_on pathname
|
51
|
+
::Sass::Engine.new evaluate(context, pathname), options.merge(
|
52
|
+
filename: pathname.to_s,
|
53
|
+
syntax: syntax(pathname),
|
54
|
+
importer: self,
|
55
|
+
custom: { sprockets_context: context }
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Create a Sass::Engine that will handle importing
|
60
|
+
# a glob of files.
|
61
|
+
def engine_from_glob(glob, base_path, options)
|
62
|
+
context = options[:custom][:sprockets_context]
|
63
|
+
engine_imports = resolve_glob(context, glob, base_path).reduce(''.dup) do |imports, path|
|
64
|
+
context.depend_on path
|
65
|
+
relative_path = path.relative_path_from Pathname.new(base_path).dirname
|
66
|
+
imports << %(@import "#{relative_path}";\n)
|
67
|
+
end
|
68
|
+
return nil if engine_imports.empty?
|
69
|
+
::Sass::Engine.new engine_imports, options.merge(
|
70
|
+
filename: base_path.to_s,
|
71
|
+
syntax: syntax(base_path.to_s),
|
72
|
+
importer: self,
|
73
|
+
custom: { sprockets_context: context }
|
74
|
+
)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Finds an asset from the given path. This is where
|
78
|
+
# we make Sprockets behave like Sass, and import partial
|
79
|
+
# style paths.
|
80
|
+
def resolve(context, path, base_path)
|
81
|
+
paths, _root_path = possible_files(context, path, base_path)
|
82
|
+
paths.each do |file|
|
83
|
+
context.resolve(file.to_s) do |found|
|
84
|
+
return found if context.asset_requirable?(found)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
nil
|
88
|
+
end
|
89
|
+
|
90
|
+
# Finds all of the assets using the given glob.
|
91
|
+
def resolve_glob(context, glob, base_path)
|
92
|
+
base_path = Pathname.new(base_path)
|
93
|
+
path_with_glob = base_path.dirname.join(glob).to_s
|
94
|
+
|
95
|
+
Pathname.glob(path_with_glob).sort.select do |path|
|
96
|
+
asset_requirable = context.asset_requirable?(path)
|
97
|
+
path != context.pathname && asset_requirable
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def context_root_path(context)
|
102
|
+
Pathname.new(context.root_path)
|
103
|
+
end
|
104
|
+
|
105
|
+
def context_load_pathnames(context)
|
106
|
+
context.environment.paths.map { |p| Pathname.new(p) }
|
107
|
+
end
|
108
|
+
|
109
|
+
# Returns all of the possible paths (including partial variations)
|
110
|
+
# to attempt to resolve with the given path.
|
111
|
+
def possible_files(context, path, base_path)
|
112
|
+
path = Pathname.new(path)
|
113
|
+
base_path = Pathname.new(base_path).dirname
|
114
|
+
partial_path = partialize_path(path)
|
115
|
+
additional_paths = [Pathname.new("#{path}.css"), Pathname.new("#{partial_path}.css"), Pathname.new("#{path}.css.#{syntax(path)}"), Pathname.new("#{partial_path}.css.#{syntax(path)}")]
|
116
|
+
paths = additional_paths.concat([path, partial_path])
|
117
|
+
|
118
|
+
# Find base_path's root
|
119
|
+
paths, root_path = add_root_to_possible_files(context, base_path, path, paths)
|
120
|
+
[paths.compact, root_path]
|
121
|
+
end
|
122
|
+
|
123
|
+
def add_root_to_possible_files(context, base_path, path, paths)
|
124
|
+
env_root_paths = context_load_pathnames(context)
|
125
|
+
root_path = env_root_paths.find do |env_root_path|
|
126
|
+
base_path.to_s.start_with?(env_root_path.to_s)
|
127
|
+
end
|
128
|
+
root_path ||= context_root_path(context)
|
129
|
+
# Add the relative path from the root, if necessary
|
130
|
+
if path.relative? && base_path != root_path
|
131
|
+
relative_path = base_path.relative_path_from(root_path).join path
|
132
|
+
paths.unshift(relative_path, partialize_path(relative_path))
|
133
|
+
end
|
134
|
+
[paths, root_path]
|
135
|
+
end
|
136
|
+
|
137
|
+
# Returns the partialized version of the given path.
|
138
|
+
# Returns nil if the path is already to a partial.
|
139
|
+
def partialize_path(path)
|
140
|
+
return unless path.basename.to_s !~ /\A_/
|
141
|
+
Pathname.new path.to_s.sub(/([^\/]+)\Z/, '_\1')
|
142
|
+
end
|
143
|
+
|
144
|
+
# Returns the Sass syntax of the given path.
|
145
|
+
def syntax(path)
|
146
|
+
path.to_s.include?('.sass') ? :sass : :scss
|
147
|
+
end
|
148
|
+
|
149
|
+
def syntax_mime_type(_path)
|
150
|
+
'text/css'
|
151
|
+
end
|
152
|
+
|
153
|
+
def filtered_processor_classes
|
154
|
+
classes = [Sprockets::Sass::Utils.get_class_by_version('SassTemplate'), Sprockets::Sass::Utils.get_class_by_version('ScssTemplate')]
|
155
|
+
classes << Sprockets::SassProcessor if defined?(Sprockets::SassProcessor)
|
156
|
+
classes << Sprockets::SasscProcessor if defined?(Sprockets::SasscProcessor)
|
157
|
+
classes
|
158
|
+
end
|
159
|
+
|
160
|
+
def content_type_of_path(context, path)
|
161
|
+
attributes = context.environment.attributes_for(path)
|
162
|
+
content_type = attributes.content_type
|
163
|
+
[content_type, attributes]
|
164
|
+
end
|
165
|
+
|
166
|
+
def get_context_preprocessors(context, content_type)
|
167
|
+
context.environment.preprocessors(content_type)
|
168
|
+
end
|
169
|
+
|
170
|
+
def get_context_transformers(_context, _content_type, _path)
|
171
|
+
[]
|
172
|
+
end
|
173
|
+
|
174
|
+
def get_engines_from_attributes(attributes)
|
175
|
+
attributes.engines
|
176
|
+
end
|
177
|
+
|
178
|
+
def get_all_processors_for_evaluate(context, content_type, attributes, path)
|
179
|
+
engines = get_engines_from_attributes(attributes)
|
180
|
+
preprocessors = get_context_preprocessors(context, content_type)
|
181
|
+
additional_transformers = get_context_transformers(context, content_type, path)
|
182
|
+
additional_transformers.reverse + preprocessors + engines.reverse
|
183
|
+
end
|
184
|
+
|
185
|
+
def filter_all_processors(processors)
|
186
|
+
processors.delete_if do |processor|
|
187
|
+
filtered_processor_classes.include?(processor) || filtered_processor_classes.any? do |filtered_processor|
|
188
|
+
!processor.is_a?(Proc) && processor < filtered_processor
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def evaluate_path_from_context(context, path, processors)
|
194
|
+
context.evaluate(path, processors: processors)
|
195
|
+
end
|
196
|
+
|
197
|
+
# Returns the string to be passed to the Sass engine. We use
|
198
|
+
# Sprockets to process the file, but we remove any Sass processors
|
199
|
+
# because we need to let the Sass::Engine handle that.
|
200
|
+
def evaluate(context, path)
|
201
|
+
content_type, attributes = content_type_of_path(context, path)
|
202
|
+
processors = get_all_processors_for_evaluate(context, content_type, attributes, path)
|
203
|
+
filter_all_processors(processors)
|
204
|
+
evaluate_path_from_context(context, path, processors)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
@@ -0,0 +1,221 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Sprockets
|
3
|
+
module Sass
|
4
|
+
module V2
|
5
|
+
# Preprocessor for SASS files
|
6
|
+
class SassTemplate
|
7
|
+
VERSION = '1'
|
8
|
+
|
9
|
+
def self.default_mime_type
|
10
|
+
'text/css'
|
11
|
+
end
|
12
|
+
|
13
|
+
# Internal: Defines default sass syntax to use. Exposed so the ScssProcessor
|
14
|
+
# may override it.
|
15
|
+
def self.syntax
|
16
|
+
:sass
|
17
|
+
end
|
18
|
+
|
19
|
+
# Public: Return singleton instance with default options.
|
20
|
+
#
|
21
|
+
# Returns SassProcessor object.
|
22
|
+
def self.instance
|
23
|
+
@instance ||= new
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.call(input)
|
27
|
+
instance.call(input)
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.cache_key
|
31
|
+
instance.cache_key
|
32
|
+
end
|
33
|
+
|
34
|
+
attr_reader :cache_key, :filename, :source, :context, :options
|
35
|
+
|
36
|
+
def initialize(options = {}, &block)
|
37
|
+
@default_options = { default_encoding: Encoding.default_external || 'utf-8' }
|
38
|
+
initialize_engine
|
39
|
+
if options.is_a?(Hash)
|
40
|
+
instantiate_with_options(options, &block)
|
41
|
+
else
|
42
|
+
instantiate_with_filename_and_source(options, &block)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def instantiate_with_filename_and_source(options)
|
47
|
+
@filename = options
|
48
|
+
@source = block_given? ? yield : nil
|
49
|
+
@options = @default_options
|
50
|
+
@cache_version = VERSION
|
51
|
+
@cache_key = "#{self.class.name}:#{::Sass::VERSION}:#{VERSION}:#{Sprockets::Sass::Utils.digest(options)}"
|
52
|
+
@functions = Module.new do
|
53
|
+
include Sprockets::Helpers if defined?(Sprockets::Helpers)
|
54
|
+
include Sprockets::Sass::Utils.get_class_by_version('Functions')
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def instantiate_with_options(options, &block)
|
59
|
+
@cache_version = options[:cache_version] || VERSION
|
60
|
+
@cache_key = "#{self.class.name}:#{::Sass::VERSION}:#{@cache_version}:#{Sprockets::Sass::Utils.digest(options)}"
|
61
|
+
@filename = options[:filename]
|
62
|
+
@source = options[:data]
|
63
|
+
@options = options.merge(@default_options)
|
64
|
+
@importer_class = options[:importer]
|
65
|
+
@sass_config = options[:sass_config] || {}
|
66
|
+
@input = options
|
67
|
+
@functions = Module.new do
|
68
|
+
include Sprockets::Helpers if defined?(Sprockets::Helpers)
|
69
|
+
include Sprockets::Sass::Utils.get_class_by_version('Functions')
|
70
|
+
include options[:functions] if options[:functions]
|
71
|
+
class_eval(&block) if block_given?
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
@sass_functions_initialized = false
|
76
|
+
class << self
|
77
|
+
attr_accessor :sass_functions_initialized
|
78
|
+
alias sass_functions_initialized? sass_functions_initialized
|
79
|
+
# Templates are initialized once the functions are added.
|
80
|
+
def engine_initialized?
|
81
|
+
sass_functions_initialized?
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Add the Sass functions if they haven't already been added.
|
86
|
+
def initialize_engine
|
87
|
+
return if self.class.engine_initialized?
|
88
|
+
|
89
|
+
if Sass.add_sass_functions != false
|
90
|
+
begin
|
91
|
+
require 'sprockets/helpers'
|
92
|
+
require 'sprockets/sass/functions'
|
93
|
+
self.class.sass_functions_initialized = true
|
94
|
+
rescue LoadError; end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def call(input)
|
99
|
+
@input = input
|
100
|
+
@filename = input[:filename]
|
101
|
+
@source = input[:data]
|
102
|
+
@context = input[:environment].context_class.new(input)
|
103
|
+
run
|
104
|
+
end
|
105
|
+
|
106
|
+
def render(context, _empty_hash_wtf)
|
107
|
+
@context = context
|
108
|
+
run
|
109
|
+
end
|
110
|
+
|
111
|
+
def run
|
112
|
+
data = Sprockets::Sass::Utils.read_file_binary(filename, options)
|
113
|
+
|
114
|
+
engine = ::Sass::Engine.new(data, sass_options)
|
115
|
+
css = Sprockets::Sass::Utils.module_include(::Sass::Script::Functions, @functions) do
|
116
|
+
css = engine.render
|
117
|
+
end
|
118
|
+
|
119
|
+
sass_dependencies = Set.new([filename])
|
120
|
+
if context.respond_to?(:metadata)
|
121
|
+
engine.dependencies.map do |dependency|
|
122
|
+
sass_dependencies << dependency.options[:filename]
|
123
|
+
context.metadata[:dependencies] << Sprockets::URIUtils.build_file_digest_uri(dependency.options[:filename])
|
124
|
+
end
|
125
|
+
context.metadata.merge(data: css, sass_dependencies: sass_dependencies)
|
126
|
+
else
|
127
|
+
css
|
128
|
+
end
|
129
|
+
|
130
|
+
# Tilt::SassTemplate.new(filename, sass_options(filename, context)).render(self)
|
131
|
+
rescue => e
|
132
|
+
# Annotates exception message with parse line number
|
133
|
+
# context.__LINE__ = e.sass_backtrace.first[:line]
|
134
|
+
raise [e, e.backtrace].join("\n")
|
135
|
+
end
|
136
|
+
|
137
|
+
def merge_sass_options(options, other_options)
|
138
|
+
if (load_paths = options[:load_paths]) && (other_paths = other_options[:load_paths])
|
139
|
+
other_options[:load_paths] = other_paths + load_paths
|
140
|
+
end
|
141
|
+
options = options.merge(other_options)
|
142
|
+
options[:load_paths] = options[:load_paths].is_a?(Array) ? options[:load_paths] : []
|
143
|
+
options[:load_paths] = options[:load_paths].concat(context.environment.paths)
|
144
|
+
options
|
145
|
+
end
|
146
|
+
|
147
|
+
def default_sass_config
|
148
|
+
if defined?(Compass)
|
149
|
+
merge_sass_options Compass.sass_engine_options.dup, Sprockets::Sass.options
|
150
|
+
else
|
151
|
+
Sprockets::Sass.options.dup
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def default_sass_options
|
156
|
+
sass = default_sass_config
|
157
|
+
sass = merge_sass_options(sass.dup, @sass_config) if defined?(@sass_config) && @sass_config.is_a?(Hash)
|
158
|
+
sass
|
159
|
+
end
|
160
|
+
|
161
|
+
def build_cache_store(context)
|
162
|
+
return nil if context.environment.cache.nil?
|
163
|
+
if defined?(Sprockets::SassProcessor::CacheStore)
|
164
|
+
Sprockets::SassProcessor::CacheStore.new(context.environment)
|
165
|
+
else
|
166
|
+
custom_cache_store(context.environment)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def custom_cache_store(*args)
|
171
|
+
Sprockets::Sass::V2::CacheStore.new(*args)
|
172
|
+
end
|
173
|
+
|
174
|
+
# Allow the use of custom SASS importers, making sure the
|
175
|
+
# custom importer is a `Sprockets::Sass::Importer`
|
176
|
+
def fetch_importer_class
|
177
|
+
if defined?(@importer_class) && !@importer_class.nil?
|
178
|
+
@importer_class
|
179
|
+
elsif default_sass_options.key?(:importer) && default_sass_options[:importer].is_a?(Importer)
|
180
|
+
default_sass_options[:importer]
|
181
|
+
else
|
182
|
+
custom_importer_class
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def custom_importer_class(*_args)
|
187
|
+
Sprockets::Sass::V2::Importer.new
|
188
|
+
end
|
189
|
+
|
190
|
+
def fetch_sprockets_options
|
191
|
+
sprockets_options = {
|
192
|
+
context: context,
|
193
|
+
environment: context.environment,
|
194
|
+
dependencies: context.respond_to?(:metadata) ? context.metadata[:dependencies] : []
|
195
|
+
}
|
196
|
+
if context.respond_to?(:metadata)
|
197
|
+
sprockets_options.merge(load_paths: context.environment.paths + default_sass_options[:load_paths])
|
198
|
+
end
|
199
|
+
sprockets_options
|
200
|
+
end
|
201
|
+
|
202
|
+
def sass_options
|
203
|
+
importer = fetch_importer_class
|
204
|
+
sprockets_options = fetch_sprockets_options
|
205
|
+
|
206
|
+
sass = merge_sass_options(default_sass_options, options).merge(
|
207
|
+
filename: filename,
|
208
|
+
line: 1,
|
209
|
+
syntax: self.class.syntax,
|
210
|
+
cache: true,
|
211
|
+
cache_store: build_cache_store(context),
|
212
|
+
importer: importer,
|
213
|
+
custom: { sprockets_context: context },
|
214
|
+
sprockets: sprockets_options
|
215
|
+
)
|
216
|
+
sass
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|