sass 3.3.0 → 3.4.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 +4 -4
- data/MIT-LICENSE +1 -1
- data/README.md +58 -50
- data/Rakefile +1 -4
- data/VERSION +1 -1
- data/VERSION_DATE +1 -1
- data/VERSION_NAME +1 -1
- data/bin/sass +1 -1
- data/bin/scss +1 -1
- data/lib/sass/cache_stores/filesystem.rb +6 -2
- data/lib/sass/css.rb +1 -3
- data/lib/sass/engine.rb +37 -46
- data/lib/sass/environment.rb +13 -17
- data/lib/sass/error.rb +6 -9
- data/lib/sass/exec/base.rb +187 -0
- data/lib/sass/exec/sass_convert.rb +264 -0
- data/lib/sass/exec/sass_scss.rb +424 -0
- data/lib/sass/exec.rb +5 -771
- data/lib/sass/features.rb +7 -0
- data/lib/sass/importers/base.rb +7 -2
- data/lib/sass/importers/filesystem.rb +9 -25
- data/lib/sass/importers.rb +0 -1
- data/lib/sass/media.rb +1 -4
- data/lib/sass/plugin/compiler.rb +200 -83
- data/lib/sass/plugin/staleness_checker.rb +1 -1
- data/lib/sass/plugin.rb +3 -3
- data/lib/sass/script/css_lexer.rb +1 -1
- data/lib/sass/script/functions.rb +622 -268
- data/lib/sass/script/lexer.rb +99 -34
- data/lib/sass/script/parser.rb +24 -23
- data/lib/sass/script/tree/funcall.rb +1 -1
- data/lib/sass/script/tree/interpolation.rb +20 -2
- data/lib/sass/script/tree/selector.rb +26 -0
- data/lib/sass/script/tree/string_interpolation.rb +1 -1
- data/lib/sass/script/tree.rb +1 -0
- data/lib/sass/script/value/base.rb +7 -5
- data/lib/sass/script/value/bool.rb +0 -5
- data/lib/sass/script/value/color.rb +39 -21
- data/lib/sass/script/value/helpers.rb +107 -0
- data/lib/sass/script/value/list.rb +0 -15
- data/lib/sass/script/value/null.rb +0 -5
- data/lib/sass/script/value/number.rb +62 -14
- data/lib/sass/script/value/string.rb +59 -11
- data/lib/sass/script/value.rb +0 -1
- data/lib/sass/scss/css_parser.rb +8 -2
- data/lib/sass/scss/parser.rb +190 -328
- data/lib/sass/scss/rx.rb +15 -6
- data/lib/sass/scss/static_parser.rb +298 -1
- data/lib/sass/selector/abstract_sequence.rb +28 -13
- data/lib/sass/selector/comma_sequence.rb +92 -13
- data/lib/sass/selector/pseudo.rb +256 -0
- data/lib/sass/selector/sequence.rb +94 -24
- data/lib/sass/selector/simple.rb +14 -25
- data/lib/sass/selector/simple_sequence.rb +97 -33
- data/lib/sass/selector.rb +57 -194
- data/lib/sass/shared.rb +1 -1
- data/lib/sass/source/map.rb +26 -12
- data/lib/sass/stack.rb +0 -6
- data/lib/sass/supports.rb +2 -3
- data/lib/sass/tree/at_root_node.rb +1 -0
- data/lib/sass/tree/charset_node.rb +1 -1
- data/lib/sass/tree/directive_node.rb +8 -2
- data/lib/sass/tree/error_node.rb +18 -0
- data/lib/sass/tree/extend_node.rb +1 -1
- data/lib/sass/tree/function_node.rb +4 -0
- data/lib/sass/tree/keyframe_rule_node.rb +15 -0
- data/lib/sass/tree/prop_node.rb +1 -1
- data/lib/sass/tree/rule_node.rb +12 -7
- data/lib/sass/tree/visitors/check_nesting.rb +38 -10
- data/lib/sass/tree/visitors/convert.rb +16 -18
- data/lib/sass/tree/visitors/cssize.rb +29 -29
- data/lib/sass/tree/visitors/deep_copy.rb +5 -0
- data/lib/sass/tree/visitors/perform.rb +45 -33
- data/lib/sass/tree/visitors/set_options.rb +14 -0
- data/lib/sass/tree/visitors/to_css.rb +15 -14
- data/lib/sass/util/subset_map.rb +1 -1
- data/lib/sass/util.rb +222 -99
- data/lib/sass/version.rb +5 -5
- data/lib/sass.rb +0 -5
- data/test/sass/cache_test.rb +62 -20
- data/test/sass/callbacks_test.rb +1 -1
- data/test/sass/compiler_test.rb +19 -10
- data/test/sass/conversion_test.rb +58 -1
- data/test/sass/css2sass_test.rb +23 -4
- data/test/sass/encoding_test.rb +219 -0
- data/test/sass/engine_test.rb +136 -199
- data/test/sass/exec_test.rb +2 -2
- data/test/sass/extend_test.rb +236 -19
- data/test/sass/functions_test.rb +295 -253
- data/test/sass/importer_test.rb +31 -21
- data/test/sass/logger_test.rb +1 -1
- data/test/sass/more_results/more_import.css +1 -1
- data/test/sass/plugin_test.rb +14 -13
- data/test/sass/results/compact.css +1 -1
- data/test/sass/results/complex.css +4 -4
- data/test/sass/results/expanded.css +1 -1
- data/test/sass/results/import.css +1 -1
- data/test/sass/results/import_charset_ibm866.css +2 -2
- data/test/sass/results/mixins.css +17 -17
- data/test/sass/results/nested.css +1 -1
- data/test/sass/results/parent_ref.css +2 -2
- data/test/sass/results/script.css +3 -3
- data/test/sass/results/scss_import.css +1 -1
- data/test/sass/script_conversion_test.rb +10 -7
- data/test/sass/script_test.rb +288 -74
- data/test/sass/scss/css_test.rb +141 -24
- data/test/sass/scss/rx_test.rb +4 -4
- data/test/sass/scss/scss_test.rb +457 -18
- data/test/sass/source_map_test.rb +115 -25
- data/test/sass/superselector_test.rb +191 -0
- data/test/sass/templates/scss_import.scss +2 -1
- data/test/sass/test_helper.rb +1 -1
- data/test/sass/util/multibyte_string_scanner_test.rb +1 -1
- data/test/sass/util/normalized_map_test.rb +1 -1
- data/test/sass/util/subset_map_test.rb +2 -2
- data/test/sass/util_test.rb +31 -1
- data/test/sass/value_helpers_test.rb +5 -7
- data/test/test_helper.rb +2 -2
- data/vendor/listen/CHANGELOG.md +1 -228
- data/vendor/listen/Gemfile +5 -15
- data/vendor/listen/README.md +111 -77
- data/vendor/listen/Rakefile +0 -42
- data/vendor/listen/lib/listen/adapter.rb +195 -82
- data/vendor/listen/lib/listen/adapters/bsd.rb +27 -64
- data/vendor/listen/lib/listen/adapters/darwin.rb +21 -58
- data/vendor/listen/lib/listen/adapters/linux.rb +23 -55
- data/vendor/listen/lib/listen/adapters/polling.rb +25 -34
- data/vendor/listen/lib/listen/adapters/windows.rb +50 -46
- data/vendor/listen/lib/listen/directory_record.rb +96 -61
- data/vendor/listen/lib/listen/listener.rb +135 -37
- data/vendor/listen/lib/listen/turnstile.rb +9 -5
- data/vendor/listen/lib/listen/version.rb +1 -1
- data/vendor/listen/lib/listen.rb +33 -19
- data/vendor/listen/listen.gemspec +6 -0
- data/vendor/listen/spec/listen/adapter_spec.rb +43 -77
- data/vendor/listen/spec/listen/adapters/polling_spec.rb +8 -8
- data/vendor/listen/spec/listen/directory_record_spec.rb +81 -56
- data/vendor/listen/spec/listen/listener_spec.rb +128 -39
- data/vendor/listen/spec/listen_spec.rb +15 -21
- data/vendor/listen/spec/spec_helper.rb +4 -0
- data/vendor/listen/spec/support/adapter_helper.rb +52 -15
- data/vendor/listen/spec/support/directory_record_helper.rb +7 -5
- data/vendor/listen/spec/support/listeners_helper.rb +30 -7
- metadata +25 -22
- data/ext/mkrf_conf.rb +0 -27
- data/lib/sass/importers/deprecated_path.rb +0 -51
- data/lib/sass/script/value/deprecated_false.rb +0 -55
- data/vendor/listen/lib/listen/dependency_manager.rb +0 -126
- data/vendor/listen/lib/listen/multi_listener.rb +0 -143
- data/vendor/listen/spec/listen/dependency_manager_spec.rb +0 -107
- data/vendor/listen/spec/listen/multi_listener_spec.rb +0 -174
data/lib/sass/features.rb
CHANGED
@@ -4,7 +4,14 @@ module Sass
|
|
4
4
|
# by providing a feature name.
|
5
5
|
module Features
|
6
6
|
# This is the set of features that can be detected.
|
7
|
+
#
|
8
|
+
# When this is updated, the documentation of `feature-exists()` should be
|
9
|
+
# updated as well.
|
7
10
|
KNOWN_FEATURES = Set[*%w{
|
11
|
+
global-variable-shadowing
|
12
|
+
extend-selector-pseudoclass
|
13
|
+
units-level-3
|
14
|
+
at-error
|
8
15
|
}]
|
9
16
|
|
10
17
|
# Check if a feature exists by name. This is used to implement
|
data/lib/sass/importers/base.rb
CHANGED
@@ -124,6 +124,10 @@ module Sass
|
|
124
124
|
# sourcemap generation to fail if any CSS is generated from files imported
|
125
125
|
# from this importer.
|
126
126
|
#
|
127
|
+
# If an absolute "file:" URI can be produced for an imported file, that
|
128
|
+
# should be preferred to returning `nil`. However, a URL relative to
|
129
|
+
# `sourcemap_directory` should be preferred over an absolute "file:" URI.
|
130
|
+
#
|
127
131
|
# @param uri [String] A URI known to be valid for this importer.
|
128
132
|
# @param sourcemap_directory [String, NilClass] The absolute path to a
|
129
133
|
# directory on disk where the sourcemap will be saved. If uri refers to
|
@@ -131,8 +135,9 @@ module Sass
|
|
131
135
|
# may return a relative URL. This may be `nil` if the sourcemap's
|
132
136
|
# eventual location is unknown.
|
133
137
|
# @return [String?] The publicly-visible URL for this file, or `nil`
|
134
|
-
# indicating that no publicly-visible URL exists.
|
135
|
-
|
138
|
+
# indicating that no publicly-visible URL exists. This should be
|
139
|
+
# appropriately URL-escaped.
|
140
|
+
def public_url(uri, sourcemap_directory)
|
136
141
|
return if @public_url_warning_issued
|
137
142
|
@public_url_warning_issued = true
|
138
143
|
Sass::Util.sass_warn <<WARNING
|
@@ -64,17 +64,16 @@ module Sass
|
|
64
64
|
filename.start_with?(root + File::SEPARATOR)
|
65
65
|
end
|
66
66
|
|
67
|
-
def public_url(name, sourcemap_directory
|
67
|
+
def public_url(name, sourcemap_directory)
|
68
|
+
file_pathname = Sass::Util.cleanpath(Sass::Util.absolute_path(name, @root))
|
68
69
|
if sourcemap_directory.nil?
|
69
|
-
|
70
|
+
Sass::Util.file_uri_from_path(file_pathname)
|
70
71
|
else
|
71
|
-
|
72
|
-
sourcemap_pathname = Sass::Util.pathname(sourcemap_directory).cleanpath
|
72
|
+
sourcemap_pathname = Sass::Util.cleanpath(sourcemap_directory)
|
73
73
|
begin
|
74
|
-
file_pathname.relative_path_from(sourcemap_pathname)
|
74
|
+
Sass::Util.file_uri_from_path(file_pathname.relative_path_from(sourcemap_pathname))
|
75
75
|
rescue ArgumentError # when a relative path cannot be constructed
|
76
|
-
|
77
|
-
nil
|
76
|
+
Sass::Util.file_uri_from_path(file_pathname)
|
78
77
|
end
|
79
78
|
end
|
80
79
|
end
|
@@ -139,15 +138,16 @@ module Sass
|
|
139
138
|
# @param name [String] The filename to search for.
|
140
139
|
# @return [(String, Symbol)] A filename-syntax pair.
|
141
140
|
def find_real_file(dir, name, options)
|
142
|
-
#
|
141
|
+
# On windows 'dir' or 'name' can be in native File::ALT_SEPARATOR form.
|
143
142
|
dir = dir.gsub(File::ALT_SEPARATOR, File::SEPARATOR) unless File::ALT_SEPARATOR.nil?
|
143
|
+
name = name.gsub(File::ALT_SEPARATOR, File::SEPARATOR) unless File::ALT_SEPARATOR.nil?
|
144
144
|
|
145
145
|
found = possible_files(remove_root(name)).map do |f, s|
|
146
146
|
path = (dir == "." || Sass::Util.pathname(f).absolute?) ? f :
|
147
147
|
"#{escape_glob_characters(dir)}/#{f}"
|
148
148
|
Dir[path].map do |full_path|
|
149
149
|
full_path.gsub!(REDUNDANT_DIRECTORY, File::SEPARATOR)
|
150
|
-
[Sass::Util.
|
150
|
+
[Sass::Util.cleanpath(full_path).to_s, s]
|
151
151
|
end
|
152
152
|
end
|
153
153
|
found = Sass::Util.flatten(found, 1)
|
@@ -195,22 +195,6 @@ WARNING
|
|
195
195
|
[dirname, basename, extension]
|
196
196
|
end
|
197
197
|
|
198
|
-
# Issues a warning about being unable to determine a public url.
|
199
|
-
#
|
200
|
-
# @param uri [String] A URI known to be valid for this importer.
|
201
|
-
# @return [NilClass] nil
|
202
|
-
def warn_about_public_url(uri)
|
203
|
-
@warnings_issued ||= Set.new
|
204
|
-
unless @warnings_issued.include?(uri)
|
205
|
-
Sass::Util.sass_warn <<WARNING
|
206
|
-
WARNING: Couldn't determine public URL for "#{uri}" while generating sourcemap.
|
207
|
-
Without a public URL, there's nothing for the source map to link to.
|
208
|
-
WARNING
|
209
|
-
@warnings_issued << uri
|
210
|
-
end
|
211
|
-
nil
|
212
|
-
end
|
213
|
-
|
214
198
|
private
|
215
199
|
|
216
200
|
def _find(dir, name, options)
|
data/lib/sass/importers.rb
CHANGED
data/lib/sass/media.rb
CHANGED
@@ -205,9 +205,6 @@ module Sass::Media
|
|
205
205
|
# @param options [{Symbol => Object}] An options hash (see {Sass::CSS#initialize}).
|
206
206
|
# @return [String]
|
207
207
|
def self._interp_to_src(interp, options)
|
208
|
-
interp.map
|
209
|
-
next r if r.is_a?(String)
|
210
|
-
"\#{#{r.to_sass(options)}}"
|
211
|
-
end.join
|
208
|
+
interp.map {|r| r.is_a?(String) ? r : r.to_sass(options)}.join
|
212
209
|
end
|
213
210
|
end
|
data/lib/sass/plugin/compiler.rb
CHANGED
@@ -36,19 +36,30 @@ module Sass::Plugin
|
|
36
36
|
options.merge!(opts)
|
37
37
|
end
|
38
38
|
|
39
|
-
# Register a callback to be run
|
39
|
+
# Register a callback to be run before stylesheets are mass-updated.
|
40
40
|
# This is run whenever \{#update\_stylesheets} is called,
|
41
41
|
# unless the \{file:SASS_REFERENCE.md#never_update-option `:never_update` option}
|
42
42
|
# is enabled.
|
43
43
|
#
|
44
|
-
# @yield [
|
45
|
-
# @yieldparam
|
46
|
-
# Individual files to be updated
|
47
|
-
# specified in the options.
|
44
|
+
# @yield [files]
|
45
|
+
# @yieldparam files [<(String, String, String)>]
|
46
|
+
# Individual files to be updated. Files in directories specified are included in this list.
|
48
47
|
# The first element of each pair is the source file,
|
49
|
-
# the second is the target CSS file
|
48
|
+
# the second is the target CSS file,
|
49
|
+
# the third is the target sourcemap file.
|
50
50
|
define_callback :updating_stylesheets
|
51
51
|
|
52
|
+
# Register a callback to be run after stylesheets are mass-updated.
|
53
|
+
# This is run whenever \{#update\_stylesheets} is called,
|
54
|
+
# unless the \{file:SASS_REFERENCE.md#never_update-option `:never_update` option}
|
55
|
+
# is enabled.
|
56
|
+
#
|
57
|
+
# @yield [updated_files]
|
58
|
+
# @yieldparam updated_files [<(String, String)>]
|
59
|
+
# Individual files that were updated.
|
60
|
+
# The first element of each pair is the source file, the second is the target CSS file.
|
61
|
+
define_callback :updated_stylesheets
|
62
|
+
|
52
63
|
# Register a callback to be run after a single stylesheet is updated.
|
53
64
|
# The callback is only run if the stylesheet is really updated;
|
54
65
|
# if the CSS file is fresh, this won't be run.
|
@@ -67,6 +78,21 @@ module Sass::Plugin
|
|
67
78
|
# The location of the sourcemap being generated, if any.
|
68
79
|
define_callback :updated_stylesheet
|
69
80
|
|
81
|
+
# Register a callback to be run when compilation starts.
|
82
|
+
#
|
83
|
+
# In combination with on_updated_stylesheet, this could be used
|
84
|
+
# to collect compilation statistics like timing or to take a
|
85
|
+
# diff of the changes to the output file.
|
86
|
+
#
|
87
|
+
# @yield [template, css, sourcemap]
|
88
|
+
# @yieldparam template [String]
|
89
|
+
# The location of the Sass/SCSS file being updated.
|
90
|
+
# @yieldparam css [String]
|
91
|
+
# The location of the CSS file being generated.
|
92
|
+
# @yieldparam sourcemap [String]
|
93
|
+
# The location of the sourcemap being generated, if any.
|
94
|
+
define_callback :compilation_starting
|
95
|
+
|
70
96
|
# Register a callback to be run when Sass decides not to update a stylesheet.
|
71
97
|
# In particular, the callback is run when Sass finds that
|
72
98
|
# the template file and none of its dependencies
|
@@ -139,7 +165,8 @@ module Sass::Plugin
|
|
139
165
|
define_callback :template_deleted
|
140
166
|
|
141
167
|
# Register a callback to be run when Sass deletes a CSS file.
|
142
|
-
# This happens when the corresponding Sass/SCSS file has been deleted
|
168
|
+
# This happens when the corresponding Sass/SCSS file has been deleted
|
169
|
+
# and when the compiler cleans the output files.
|
143
170
|
#
|
144
171
|
# @yield [filename]
|
145
172
|
# @yieldparam filename [String]
|
@@ -147,7 +174,8 @@ module Sass::Plugin
|
|
147
174
|
define_callback :deleting_css
|
148
175
|
|
149
176
|
# Register a callback to be run when Sass deletes a sourcemap file.
|
150
|
-
# This happens when the corresponding Sass/SCSS file has been deleted
|
177
|
+
# This happens when the corresponding Sass/SCSS file has been deleted
|
178
|
+
# and when the compiler cleans the output files.
|
151
179
|
#
|
152
180
|
# @yield [filename]
|
153
181
|
# @yieldparam filename [String]
|
@@ -162,35 +190,72 @@ module Sass::Plugin
|
|
162
190
|
# in {file:SASS_REFERENCE.md#css_location-option `:css_location`}.
|
163
191
|
# If it has, it updates the CSS file.
|
164
192
|
#
|
165
|
-
# @param individual_files [Array<(String, String)>]
|
193
|
+
# @param individual_files [Array<(String, String[, String])>]
|
166
194
|
# A list of files to check for updates
|
167
195
|
# **in addition to those specified by the
|
168
196
|
# {file:SASS_REFERENCE.md#template_location-option `:template_location` option}.**
|
169
197
|
# The first string in each pair is the location of the Sass/SCSS file,
|
170
198
|
# the second is the location of the CSS file that it should be compiled to.
|
199
|
+
# The third string, if provided, is the location of the Sourcemap file.
|
171
200
|
def update_stylesheets(individual_files = [])
|
172
|
-
individual_files = individual_files.dup
|
173
201
|
Sass::Plugin.checked_for_updates = true
|
174
202
|
staleness_checker = StalenessChecker.new(engine_options)
|
175
203
|
|
176
|
-
|
177
|
-
|
178
|
-
# Get the relative path to the file
|
179
|
-
name = file.sub(template_location.to_s.sub(/\/*$/, '/'), "")
|
180
|
-
css = css_filename(name, css_location)
|
181
|
-
sourcemap = Sass::Util.sourcemap_name(css) if engine_options[:sourcemap]
|
182
|
-
individual_files << [file, css, sourcemap]
|
183
|
-
end
|
184
|
-
end
|
204
|
+
files = file_list(individual_files)
|
205
|
+
run_updating_stylesheets(files)
|
185
206
|
|
186
|
-
|
207
|
+
updated_stylesheets = []
|
208
|
+
files.each do |file, css, sourcemap|
|
187
209
|
# TODO: Does staleness_checker need to check the sourcemap file as well?
|
188
210
|
if options[:always_update] || staleness_checker.stylesheet_needs_update?(css, file)
|
211
|
+
# XXX For consistency, this should return the sourcemap too, but it would
|
212
|
+
# XXX be an API change.
|
213
|
+
updated_stylesheets << [file, css]
|
189
214
|
update_stylesheet(file, css, sourcemap)
|
190
215
|
else
|
191
216
|
run_not_updating_stylesheet(file, css, sourcemap)
|
192
217
|
end
|
193
218
|
end
|
219
|
+
run_updated_stylesheets(updated_stylesheets)
|
220
|
+
end
|
221
|
+
|
222
|
+
# Construct a list of files that might need to be compiled
|
223
|
+
# from the provided individual_files and the template_locations.
|
224
|
+
#
|
225
|
+
# Note: this method does not cache the results as they can change
|
226
|
+
# across invocations when sass files are added or removed.
|
227
|
+
#
|
228
|
+
# @param individual_files [Array<(String, String[, String])>]
|
229
|
+
# A list of files to check for updates
|
230
|
+
# **in addition to those specified by the
|
231
|
+
# {file:SASS_REFERENCE.md#template_location-option `:template_location` option}.**
|
232
|
+
# The first string in each pair is the location of the Sass/SCSS file,
|
233
|
+
# the second is the location of the CSS file that it should be compiled to.
|
234
|
+
# The third string, if provided, is the location of the Sourcemap file.
|
235
|
+
# @return [Array<(String, String, String)>]
|
236
|
+
# A list of [sass_file, css_file, sourcemap_file] tuples similar
|
237
|
+
# to what was passed in, but expanded to include the current state
|
238
|
+
# of the directories being updated.
|
239
|
+
def file_list(individual_files = [])
|
240
|
+
files = individual_files.map do |tuple|
|
241
|
+
if tuple.size < 3
|
242
|
+
[tuple[0], tuple[1], Sass::Util.sourcemap_name(tuple[1])]
|
243
|
+
else
|
244
|
+
tuple
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
template_location_array.each do |template_location, css_location|
|
249
|
+
Sass::Util.glob(File.join(template_location, "**", "[^_]*.s[ca]ss")).sort.each do |file|
|
250
|
+
# Get the relative path to the file
|
251
|
+
name = Sass::Util.pathname(file).relative_path_from(
|
252
|
+
Sass::Util.pathname(template_location.to_s)).to_s
|
253
|
+
css = css_filename(name, css_location)
|
254
|
+
sourcemap = Sass::Util.sourcemap_name(css) unless engine_options[:sourcemap] == :none
|
255
|
+
files << [file, css, sourcemap]
|
256
|
+
end
|
257
|
+
end
|
258
|
+
files
|
194
259
|
end
|
195
260
|
|
196
261
|
# Watches the template directory (or directories)
|
@@ -211,14 +276,19 @@ module Sass::Plugin
|
|
211
276
|
# The version of Listen distributed with Sass is loaded by default,
|
212
277
|
# but if another version has already been loaded that will be used instead.
|
213
278
|
#
|
214
|
-
# @param individual_files [Array<(String, String)>]
|
215
|
-
# A list of files to
|
279
|
+
# @param individual_files [Array<(String, String[, String])>]
|
280
|
+
# A list of files to check for updates
|
216
281
|
# **in addition to those specified by the
|
217
282
|
# {file:SASS_REFERENCE.md#template_location-option `:template_location` option}.**
|
218
283
|
# The first string in each pair is the location of the Sass/SCSS file,
|
219
284
|
# the second is the location of the CSS file that it should be compiled to.
|
220
|
-
|
221
|
-
|
285
|
+
# The third string, if provided, is the location of the Sourcemap file.
|
286
|
+
# @param options [Hash] The options that control how watching works.
|
287
|
+
# @option options [Boolean] :skip_initial_update
|
288
|
+
# Don't do an initial update when starting the watcher when true
|
289
|
+
def watch(individual_files = [], options = {})
|
290
|
+
options, individual_files = individual_files, [] if individual_files.is_a?(Hash)
|
291
|
+
update_stylesheets(individual_files) unless options[:skip_initial_update]
|
222
292
|
|
223
293
|
directories = watched_paths
|
224
294
|
individual_files.each do |(source, _, _)|
|
@@ -226,9 +296,20 @@ module Sass::Plugin
|
|
226
296
|
end
|
227
297
|
directories = remove_redundant_directories(directories)
|
228
298
|
|
299
|
+
# A Listen version prior to 2.0 will write a test file to a directory to
|
300
|
+
# see if a watcher supports watching that directory. That breaks horribly
|
301
|
+
# on read-only directories, so we filter those out.
|
302
|
+
unless Sass::Util.listen_geq_2?
|
303
|
+
directories = directories.select {|d| File.directory?(d) && File.writable?(d)}
|
304
|
+
end
|
305
|
+
|
229
306
|
# TODO: Keep better track of what depends on what
|
230
307
|
# so we don't have to run a global update every time anything changes.
|
231
|
-
|
308
|
+
# XXX The :additional_watch_paths option exists for Compass to use until
|
309
|
+
# a deprecated feature is removed. It may be removed without warning.
|
310
|
+
listener_args = directories +
|
311
|
+
Array(options[:additional_watch_paths]) +
|
312
|
+
[{:relative_paths => false}]
|
232
313
|
|
233
314
|
# The native windows listener is much slower than the polling option, according to
|
234
315
|
# https://github.com/nex3/sass/commit/a3031856b22bc834a5417dedecb038b7be9b9e3e
|
@@ -240,49 +321,8 @@ module Sass::Plugin
|
|
240
321
|
end
|
241
322
|
|
242
323
|
listener = create_listener(*listener_args) do |modified, added, removed|
|
243
|
-
|
244
|
-
|
245
|
-
modified.uniq.each do |f|
|
246
|
-
next unless watched_file?(f)
|
247
|
-
recompile_required = true
|
248
|
-
run_template_modified(relative_to_pwd(f))
|
249
|
-
end
|
250
|
-
|
251
|
-
added.uniq.each do |f|
|
252
|
-
next unless watched_file?(f)
|
253
|
-
recompile_required = true
|
254
|
-
run_template_created(relative_to_pwd(f))
|
255
|
-
end
|
256
|
-
|
257
|
-
removed.uniq.each do |f|
|
258
|
-
if (files = individual_files.find {|(source, _, _)| File.expand_path(source) == f})
|
259
|
-
recompile_required = true
|
260
|
-
# This was a file we were watching explicitly and compiling to a particular location.
|
261
|
-
# Delete the corresponding file.
|
262
|
-
try_delete_css files[1]
|
263
|
-
else
|
264
|
-
next unless watched_file?(f)
|
265
|
-
recompile_required = true
|
266
|
-
# Look for the sass directory that contained the sass file
|
267
|
-
# And try to remove the css file that corresponds to it
|
268
|
-
template_location_array.each do |(sass_dir, css_dir)|
|
269
|
-
sass_dir = File.expand_path(sass_dir)
|
270
|
-
if child_of_directory?(sass_dir, f)
|
271
|
-
remainder = f[(sass_dir.size + 1)..-1]
|
272
|
-
try_delete_css(css_filename(remainder, css_dir))
|
273
|
-
break
|
274
|
-
end
|
275
|
-
end
|
276
|
-
end
|
277
|
-
run_template_deleted(relative_to_pwd(f))
|
278
|
-
end
|
279
|
-
|
280
|
-
if recompile_required
|
281
|
-
# In case a file we're watching is removed and then recreated we
|
282
|
-
# prune out the non-existant files here.
|
283
|
-
watched_files_remaining = individual_files.select {|(source, _, _)| File.exists?(source)}
|
284
|
-
update_stylesheets(watched_files_remaining)
|
285
|
-
end
|
324
|
+
on_file_changed(individual_files, modified, added, removed)
|
325
|
+
yield(modified, added, removed) if block_given?
|
286
326
|
end
|
287
327
|
|
288
328
|
if poll && !Sass::Util.listen_geq_2?
|
@@ -302,6 +342,8 @@ module Sass::Plugin
|
|
302
342
|
def engine_options(additional_options = {})
|
303
343
|
opts = options.merge(additional_options)
|
304
344
|
opts[:load_paths] = load_paths(opts)
|
345
|
+
options[:sourcemap] = :auto if options[:sourcemap] == true
|
346
|
+
options[:sourcemap] = :none if options[:sourcemap] == false
|
305
347
|
opts
|
306
348
|
end
|
307
349
|
|
@@ -310,12 +352,42 @@ module Sass::Plugin
|
|
310
352
|
StalenessChecker.stylesheet_needs_update?(css_file, template_file)
|
311
353
|
end
|
312
354
|
|
355
|
+
# Remove all output files that would be created by calling update_stylesheets, if they exist.
|
356
|
+
#
|
357
|
+
# This method runs the deleting_css and deleting_sourcemap callbacks for
|
358
|
+
# the files that are deleted.
|
359
|
+
#
|
360
|
+
# @param individual_files [Array<(String, String[, String])>]
|
361
|
+
# A list of files to check for updates
|
362
|
+
# **in addition to those specified by the
|
363
|
+
# {file:SASS_REFERENCE.md#template_location-option `:template_location` option}.**
|
364
|
+
# The first string in each pair is the location of the Sass/SCSS file,
|
365
|
+
# the second is the location of the CSS file that it should be compiled to.
|
366
|
+
# The third string, if provided, is the location of the Sourcemap file.
|
367
|
+
def clean(individual_files = [])
|
368
|
+
file_list(individual_files).each do |(_, css_file, sourcemap_file)|
|
369
|
+
if File.exist?(css_file)
|
370
|
+
run_deleting_css css_file
|
371
|
+
File.delete(css_file)
|
372
|
+
end
|
373
|
+
if sourcemap_file && File.exist?(sourcemap_file)
|
374
|
+
run_deleting_sourcemap sourcemap_file
|
375
|
+
File.delete(sourcemap_file)
|
376
|
+
end
|
377
|
+
end
|
378
|
+
nil
|
379
|
+
end
|
380
|
+
|
313
381
|
private
|
314
382
|
|
315
383
|
def create_listener(*args, &block)
|
316
|
-
|
384
|
+
Sass::Util.load_listen!
|
317
385
|
if Sass::Util.listen_geq_2?
|
318
|
-
|
386
|
+
# Work around guard/listen#243.
|
387
|
+
options = args.pop if args.last.is_a?(Hash)
|
388
|
+
args.map do |dir|
|
389
|
+
Listen.to(dir, options, &block)
|
390
|
+
end
|
319
391
|
else
|
320
392
|
Listen::Listener.new(*args, &block)
|
321
393
|
end
|
@@ -323,16 +395,12 @@ module Sass::Plugin
|
|
323
395
|
|
324
396
|
def listen_to(listener)
|
325
397
|
if Sass::Util.listen_geq_2?
|
326
|
-
listener.start
|
327
|
-
listener.thread.join
|
328
|
-
listener.stop # Partially work around guard/listen#146
|
398
|
+
listener.map {|l| l.start}.each {|thread| thread.join}
|
329
399
|
else
|
330
|
-
|
331
|
-
listener.start!
|
332
|
-
rescue Interrupt
|
333
|
-
# Squelch Interrupt for clean exit from Listen::Listener
|
334
|
-
end
|
400
|
+
listener.start!
|
335
401
|
end
|
402
|
+
rescue Interrupt
|
403
|
+
# Squelch Interrupt for clean exit from Listen::Listener
|
336
404
|
end
|
337
405
|
|
338
406
|
def remove_redundant_directories(directories)
|
@@ -351,9 +419,55 @@ module Sass::Plugin
|
|
351
419
|
dedupped
|
352
420
|
end
|
353
421
|
|
422
|
+
def on_file_changed(individual_files, modified, added, removed)
|
423
|
+
recompile_required = false
|
424
|
+
|
425
|
+
modified.uniq.each do |f|
|
426
|
+
next unless watched_file?(f)
|
427
|
+
recompile_required = true
|
428
|
+
run_template_modified(relative_to_pwd(f))
|
429
|
+
end
|
430
|
+
|
431
|
+
added.uniq.each do |f|
|
432
|
+
next unless watched_file?(f)
|
433
|
+
recompile_required = true
|
434
|
+
run_template_created(relative_to_pwd(f))
|
435
|
+
end
|
436
|
+
|
437
|
+
removed.uniq.each do |f|
|
438
|
+
run_template_deleted(relative_to_pwd(f))
|
439
|
+
if (files = individual_files.find {|(source, _, _)| File.expand_path(source) == f})
|
440
|
+
recompile_required = true
|
441
|
+
# This was a file we were watching explicitly and compiling to a particular location.
|
442
|
+
# Delete the corresponding file.
|
443
|
+
try_delete_css files[1]
|
444
|
+
else
|
445
|
+
next unless watched_file?(f)
|
446
|
+
recompile_required = true
|
447
|
+
# Look for the sass directory that contained the sass file
|
448
|
+
# And try to remove the css file that corresponds to it
|
449
|
+
template_location_array.each do |(sass_dir, css_dir)|
|
450
|
+
sass_dir = File.expand_path(sass_dir)
|
451
|
+
if child_of_directory?(sass_dir, f)
|
452
|
+
remainder = f[(sass_dir.size + 1)..-1]
|
453
|
+
try_delete_css(css_filename(remainder, css_dir))
|
454
|
+
break
|
455
|
+
end
|
456
|
+
end
|
457
|
+
end
|
458
|
+
end
|
459
|
+
|
460
|
+
if recompile_required
|
461
|
+
# In case a file we're watching is removed and then recreated we
|
462
|
+
# prune out the non-existant files here.
|
463
|
+
watched_files_remaining = individual_files.select {|(source, _, _)| File.exist?(source)}
|
464
|
+
update_stylesheets(watched_files_remaining)
|
465
|
+
end
|
466
|
+
end
|
467
|
+
|
354
468
|
def update_stylesheet(filename, css, sourcemap)
|
355
469
|
dir = File.dirname(css)
|
356
|
-
unless File.
|
470
|
+
unless File.exist?(dir)
|
357
471
|
run_creating_directory dir
|
358
472
|
FileUtils.mkdir_p dir
|
359
473
|
end
|
@@ -364,6 +478,7 @@ module Sass::Plugin
|
|
364
478
|
:filename => filename,
|
365
479
|
:sourcemap_filename => sourcemap)
|
366
480
|
mapping = nil
|
481
|
+
run_compilation_starting(filename, css, sourcemap)
|
367
482
|
engine = Sass::Engine.for_file(filename, engine_opts)
|
368
483
|
if sourcemap
|
369
484
|
rendered, mapping = engine.render_with_sourcemap(File.basename(sourcemap))
|
@@ -373,12 +488,14 @@ module Sass::Plugin
|
|
373
488
|
rescue StandardError => e
|
374
489
|
compilation_error_occured = true
|
375
490
|
run_compilation_error e, filename, css, sourcemap
|
376
|
-
|
491
|
+
raise e unless options[:full_exception]
|
492
|
+
rendered = Sass::SyntaxError.exception_to_css(e, options[:line] || 1)
|
377
493
|
end
|
378
494
|
|
379
495
|
write_file(css, rendered)
|
380
496
|
if mapping
|
381
|
-
write_file(sourcemap, mapping.to_json(
|
497
|
+
write_file(sourcemap, mapping.to_json(
|
498
|
+
:css_path => css, :sourcemap_path => sourcemap, :type => options[:sourcemap]))
|
382
499
|
end
|
383
500
|
run_updated_stylesheet(filename, css, sourcemap) unless compilation_error_occured
|
384
501
|
end
|
@@ -393,12 +510,12 @@ module Sass::Plugin
|
|
393
510
|
end
|
394
511
|
|
395
512
|
def try_delete_css(css)
|
396
|
-
if File.
|
513
|
+
if File.exist?(css)
|
397
514
|
run_deleting_css css
|
398
515
|
File.delete css
|
399
516
|
end
|
400
517
|
map = Sass::Util.sourcemap_name(css)
|
401
|
-
if File.
|
518
|
+
if File.exist?(map)
|
402
519
|
run_deleting_sourcemap map
|
403
520
|
File.delete map
|
404
521
|
end
|
@@ -46,7 +46,7 @@ module Sass
|
|
46
46
|
@actively_checking = Set.new
|
47
47
|
|
48
48
|
# Entries in the following instance-level caches are never explicitly expired.
|
49
|
-
# Instead they are supposed to
|
49
|
+
# Instead they are supposed to automatically go out of scope when a series of staleness
|
50
50
|
# checks (this instance of StalenessChecker was created for) is finished.
|
51
51
|
@mtimes, @dependencies_stale, @parse_trees = {}, {}, {}
|
52
52
|
@options = Sass::Engine.normalize_options(options)
|
data/lib/sass/plugin.rb
CHANGED
@@ -123,9 +123,9 @@ module Sass
|
|
123
123
|
end
|
124
124
|
end
|
125
125
|
|
126
|
-
|
127
|
-
|
128
|
-
require 'sass/plugin/rails'
|
126
|
+
if defined?(ActionController)
|
127
|
+
# On Rails 3+ the rails plugin is loaded at the right time in railtie.rb
|
128
|
+
require 'sass/plugin/rails' unless Sass::Util.ap_geq_3?
|
129
129
|
elsif defined?(Merb::Plugins)
|
130
130
|
require 'sass/plugin/merb'
|
131
131
|
else
|
@@ -18,7 +18,7 @@ module Sass
|
|
18
18
|
end
|
19
19
|
|
20
20
|
return unless scan(STRING)
|
21
|
-
string_value = (@scanner[1] || @scanner[2])
|
21
|
+
string_value = Sass::Script::Value::String.value(@scanner[1] || @scanner[2])
|
22
22
|
value = Script::Value::String.new(string_value, :string)
|
23
23
|
[:string, value]
|
24
24
|
end
|