oreorenasass 3.4.4 → 3.4.5
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 +50 -70
- data/Rakefile +5 -26
- data/VERSION +1 -1
- data/VERSION_NAME +1 -1
- data/bin/sass +1 -1
- data/bin/scss +1 -1
- data/lib/sass.rb +12 -19
- data/lib/sass/cache_stores/base.rb +2 -2
- data/lib/sass/cache_stores/chain.rb +1 -2
- data/lib/sass/cache_stores/filesystem.rb +5 -1
- data/lib/sass/cache_stores/memory.rb +1 -1
- data/lib/sass/cache_stores/null.rb +2 -2
- data/lib/sass/callbacks.rb +0 -1
- data/lib/sass/css.rb +13 -11
- data/lib/sass/engine.rb +173 -424
- data/lib/sass/environment.rb +58 -148
- data/lib/sass/error.rb +14 -11
- data/lib/sass/exec.rb +703 -5
- data/lib/sass/importers/base.rb +6 -49
- data/lib/sass/importers/filesystem.rb +19 -44
- data/lib/sass/logger.rb +4 -1
- data/lib/sass/logger/base.rb +4 -2
- data/lib/sass/logger/log_level.rb +7 -3
- data/lib/sass/media.rb +23 -20
- data/lib/sass/plugin.rb +7 -7
- data/lib/sass/plugin/compiler.rb +145 -304
- data/lib/sass/plugin/configuration.rb +23 -18
- data/lib/sass/plugin/merb.rb +1 -1
- data/lib/sass/plugin/staleness_checker.rb +3 -3
- data/lib/sass/repl.rb +3 -3
- data/lib/sass/script.rb +8 -35
- data/lib/sass/script/{value/arg_list.rb → arg_list.rb} +25 -9
- data/lib/sass/script/bool.rb +18 -0
- data/lib/sass/script/color.rb +606 -0
- data/lib/sass/script/css_lexer.rb +4 -8
- data/lib/sass/script/css_parser.rb +2 -5
- data/lib/sass/script/funcall.rb +245 -0
- data/lib/sass/script/functions.rb +408 -1491
- data/lib/sass/script/interpolation.rb +79 -0
- data/lib/sass/script/lexer.rb +68 -172
- data/lib/sass/script/list.rb +85 -0
- data/lib/sass/script/literal.rb +221 -0
- data/lib/sass/script/{tree/node.rb → node.rb} +12 -22
- data/lib/sass/script/{value/null.rb → null.rb} +7 -14
- data/lib/sass/script/{value/number.rb → number.rb} +75 -152
- data/lib/sass/script/{tree/operation.rb → operation.rb} +24 -17
- data/lib/sass/script/parser.rb +110 -245
- data/lib/sass/script/string.rb +51 -0
- data/lib/sass/script/{tree/string_interpolation.rb → string_interpolation.rb} +4 -5
- data/lib/sass/script/{tree/unary_operation.rb → unary_operation.rb} +6 -6
- data/lib/sass/script/variable.rb +58 -0
- data/lib/sass/scss/css_parser.rb +3 -9
- data/lib/sass/scss/parser.rb +421 -450
- data/lib/sass/scss/rx.rb +11 -19
- data/lib/sass/scss/static_parser.rb +7 -321
- data/lib/sass/selector.rb +194 -68
- data/lib/sass/selector/abstract_sequence.rb +14 -29
- data/lib/sass/selector/comma_sequence.rb +25 -108
- data/lib/sass/selector/sequence.rb +66 -159
- data/lib/sass/selector/simple.rb +25 -23
- data/lib/sass/selector/simple_sequence.rb +63 -173
- data/lib/sass/shared.rb +1 -1
- data/lib/sass/supports.rb +15 -13
- data/lib/sass/tree/charset_node.rb +1 -1
- data/lib/sass/tree/comment_node.rb +3 -3
- data/lib/sass/tree/css_import_node.rb +11 -11
- data/lib/sass/tree/debug_node.rb +2 -2
- data/lib/sass/tree/directive_node.rb +4 -21
- data/lib/sass/tree/each_node.rb +8 -8
- data/lib/sass/tree/extend_node.rb +7 -14
- data/lib/sass/tree/for_node.rb +4 -4
- data/lib/sass/tree/function_node.rb +4 -9
- data/lib/sass/tree/if_node.rb +1 -1
- data/lib/sass/tree/import_node.rb +5 -4
- data/lib/sass/tree/media_node.rb +14 -4
- data/lib/sass/tree/mixin_def_node.rb +4 -4
- data/lib/sass/tree/mixin_node.rb +8 -21
- data/lib/sass/tree/node.rb +12 -54
- data/lib/sass/tree/prop_node.rb +20 -39
- data/lib/sass/tree/return_node.rb +2 -3
- data/lib/sass/tree/root_node.rb +3 -19
- data/lib/sass/tree/rule_node.rb +22 -35
- data/lib/sass/tree/supports_node.rb +13 -0
- data/lib/sass/tree/trace_node.rb +1 -2
- data/lib/sass/tree/variable_node.rb +3 -9
- data/lib/sass/tree/visitors/base.rb +8 -5
- data/lib/sass/tree/visitors/check_nesting.rb +19 -49
- data/lib/sass/tree/visitors/convert.rb +56 -74
- data/lib/sass/tree/visitors/cssize.rb +74 -202
- data/lib/sass/tree/visitors/deep_copy.rb +5 -10
- data/lib/sass/tree/visitors/extend.rb +7 -7
- data/lib/sass/tree/visitors/perform.rb +185 -278
- data/lib/sass/tree/visitors/set_options.rb +6 -20
- data/lib/sass/tree/visitors/to_css.rb +81 -234
- data/lib/sass/tree/warn_node.rb +2 -2
- data/lib/sass/tree/while_node.rb +2 -2
- data/lib/sass/util.rb +152 -522
- data/lib/sass/util/multibyte_string_scanner.rb +0 -2
- data/lib/sass/util/subset_map.rb +3 -4
- data/lib/sass/util/test.rb +1 -0
- data/lib/sass/version.rb +22 -20
- data/test/Gemfile +3 -0
- data/test/Gemfile.lock +10 -0
- data/test/sass/cache_test.rb +20 -62
- data/test/sass/callbacks_test.rb +1 -1
- data/test/sass/conversion_test.rb +2 -296
- data/test/sass/css2sass_test.rb +4 -23
- data/test/sass/engine_test.rb +354 -411
- data/test/sass/exec_test.rb +2 -2
- data/test/sass/extend_test.rb +145 -324
- data/test/sass/functions_test.rb +86 -873
- data/test/sass/importer_test.rb +21 -241
- data/test/sass/logger_test.rb +1 -1
- data/test/sass/more_results/more_import.css +1 -1
- data/test/sass/plugin_test.rb +26 -16
- 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 +7 -36
- data/test/sass/script_test.rb +53 -485
- data/test/sass/scss/css_test.rb +28 -143
- data/test/sass/scss/rx_test.rb +4 -4
- data/test/sass/scss/scss_test.rb +325 -2119
- data/test/sass/templates/scss_import.scss +1 -2
- data/test/sass/test_helper.rb +1 -1
- data/test/sass/util/multibyte_string_scanner_test.rb +1 -1
- data/test/sass/util/subset_map_test.rb +2 -2
- data/test/sass/util_test.rb +1 -86
- data/test/test_helper.rb +8 -37
- metadata +19 -66
- data/lib/sass/exec/base.rb +0 -187
- data/lib/sass/exec/sass_convert.rb +0 -264
- data/lib/sass/exec/sass_scss.rb +0 -424
- data/lib/sass/features.rb +0 -47
- data/lib/sass/script/tree.rb +0 -16
- data/lib/sass/script/tree/funcall.rb +0 -306
- data/lib/sass/script/tree/interpolation.rb +0 -118
- data/lib/sass/script/tree/list_literal.rb +0 -77
- data/lib/sass/script/tree/literal.rb +0 -45
- data/lib/sass/script/tree/map_literal.rb +0 -64
- data/lib/sass/script/tree/selector.rb +0 -26
- data/lib/sass/script/tree/variable.rb +0 -57
- data/lib/sass/script/value.rb +0 -11
- data/lib/sass/script/value/base.rb +0 -240
- data/lib/sass/script/value/bool.rb +0 -35
- data/lib/sass/script/value/color.rb +0 -680
- data/lib/sass/script/value/helpers.rb +0 -262
- data/lib/sass/script/value/list.rb +0 -113
- data/lib/sass/script/value/map.rb +0 -70
- data/lib/sass/script/value/string.rb +0 -97
- data/lib/sass/selector/pseudo.rb +0 -256
- data/lib/sass/source/map.rb +0 -210
- data/lib/sass/source/position.rb +0 -39
- data/lib/sass/source/range.rb +0 -41
- data/lib/sass/stack.rb +0 -120
- data/lib/sass/tree/at_root_node.rb +0 -83
- data/lib/sass/tree/error_node.rb +0 -18
- data/lib/sass/tree/keyframe_rule_node.rb +0 -15
- data/lib/sass/util/cross_platform_random.rb +0 -19
- data/lib/sass/util/normalized_map.rb +0 -130
- data/lib/sass/util/ordered_hash.rb +0 -192
- data/test/sass/compiler_test.rb +0 -232
- data/test/sass/encoding_test.rb +0 -219
- data/test/sass/source_map_test.rb +0 -977
- data/test/sass/superselector_test.rb +0 -191
- data/test/sass/util/normalized_map_test.rb +0 -51
- data/test/sass/value_helpers_test.rb +0 -179
data/lib/sass/importers/base.rb
CHANGED
@@ -15,9 +15,13 @@ module Sass
|
|
15
15
|
# They should also implement the \{#find\_relative} method.
|
16
16
|
#
|
17
17
|
# Importers should be serializable via `Marshal.dump`.
|
18
|
+
# In addition to the standard `_dump` and `_load` methods,
|
19
|
+
# importers can define `_before_dump`, `_after_dump`, `_around_dump`,
|
20
|
+
# and `_after_load` methods as per {Sass::Util#dump} and {Sass::Util#load}.
|
18
21
|
#
|
19
22
|
# @abstract
|
20
23
|
class Base
|
24
|
+
|
21
25
|
# Find a Sass file relative to another file.
|
22
26
|
# Importers without a notion of "relative paths"
|
23
27
|
# should just return nil here.
|
@@ -118,34 +122,6 @@ module Sass
|
|
118
122
|
Sass::Util.abstract(self)
|
119
123
|
end
|
120
124
|
|
121
|
-
# Get the publicly-visible URL for an imported file. This URL is used by
|
122
|
-
# source maps to link to the source stylesheet. This may return `nil` to
|
123
|
-
# indicate that no public URL is available; however, this will cause
|
124
|
-
# sourcemap generation to fail if any CSS is generated from files imported
|
125
|
-
# from this importer.
|
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
|
-
#
|
131
|
-
# @param uri [String] A URI known to be valid for this importer.
|
132
|
-
# @param sourcemap_directory [String, NilClass] The absolute path to a
|
133
|
-
# directory on disk where the sourcemap will be saved. If uri refers to
|
134
|
-
# a file on disk that's accessible relative to sourcemap_directory, this
|
135
|
-
# may return a relative URL. This may be `nil` if the sourcemap's
|
136
|
-
# eventual location is unknown.
|
137
|
-
# @return [String?] The publicly-visible URL for this file, or `nil`
|
138
|
-
# indicating that no publicly-visible URL exists. This should be
|
139
|
-
# appropriately URL-escaped.
|
140
|
-
def public_url(uri, sourcemap_directory)
|
141
|
-
return if @public_url_warning_issued
|
142
|
-
@public_url_warning_issued = true
|
143
|
-
Sass::Util.sass_warn <<WARNING
|
144
|
-
WARNING: #{self.class.name} should define the #public_url method.
|
145
|
-
WARNING
|
146
|
-
nil
|
147
|
-
end
|
148
|
-
|
149
125
|
# A string representation of the importer.
|
150
126
|
# Should be overridden by subclasses.
|
151
127
|
#
|
@@ -156,27 +132,8 @@ WARNING
|
|
156
132
|
def to_s
|
157
133
|
Sass::Util.abstract(self)
|
158
134
|
end
|
159
|
-
|
160
|
-
# If the importer is based on files on the local filesystem
|
161
|
-
# this method should return folders which should be watched
|
162
|
-
# for changes.
|
163
|
-
#
|
164
|
-
# @return [Array<String>] List of absolute paths of directories to watch
|
165
|
-
def directories_to_watch
|
166
|
-
[]
|
167
|
-
end
|
168
|
-
|
169
|
-
# If this importer is based on files on the local filesystem This method
|
170
|
-
# should return true if the file, when changed, should trigger a
|
171
|
-
# recompile.
|
172
|
-
#
|
173
|
-
# It is acceptable for non-sass files to be watched and trigger a recompile.
|
174
|
-
#
|
175
|
-
# @param filename [String] The absolute filename for a file that has changed.
|
176
|
-
# @return [Boolean] When the file changed should cause a recompile.
|
177
|
-
def watched_file?(filename)
|
178
|
-
false
|
179
|
-
end
|
180
135
|
end
|
181
136
|
end
|
182
137
|
end
|
138
|
+
|
139
|
+
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'pathname'
|
1
2
|
require 'set'
|
2
3
|
|
3
4
|
module Sass
|
@@ -5,6 +6,7 @@ module Sass
|
|
5
6
|
# The default importer, used for any strings found in the load path.
|
6
7
|
# Simply loads Sass files from the filesystem using the default logic.
|
7
8
|
class Filesystem < Base
|
9
|
+
|
8
10
|
attr_accessor :root
|
9
11
|
|
10
12
|
# Creates a new filesystem importer that imports files relative to a given path.
|
@@ -37,7 +39,7 @@ module Sass
|
|
37
39
|
# @see Base#key
|
38
40
|
def key(name, options)
|
39
41
|
[self.class.name + ":" + File.dirname(File.expand_path(name)),
|
40
|
-
|
42
|
+
File.basename(name)]
|
41
43
|
end
|
42
44
|
|
43
45
|
# @see Base#to_s
|
@@ -53,31 +55,6 @@ module Sass
|
|
53
55
|
root.eql?(other.root)
|
54
56
|
end
|
55
57
|
|
56
|
-
# @see Base#directories_to_watch
|
57
|
-
def directories_to_watch
|
58
|
-
[root]
|
59
|
-
end
|
60
|
-
|
61
|
-
# @see Base#watched_file?
|
62
|
-
def watched_file?(filename)
|
63
|
-
filename =~ /\.s[ac]ss$/ &&
|
64
|
-
filename.start_with?(root + File::SEPARATOR)
|
65
|
-
end
|
66
|
-
|
67
|
-
def public_url(name, sourcemap_directory)
|
68
|
-
file_pathname = Sass::Util.cleanpath(Sass::Util.absolute_path(name, @root))
|
69
|
-
if sourcemap_directory.nil?
|
70
|
-
Sass::Util.file_uri_from_path(file_pathname)
|
71
|
-
else
|
72
|
-
sourcemap_pathname = Sass::Util.cleanpath(sourcemap_directory)
|
73
|
-
begin
|
74
|
-
Sass::Util.file_uri_from_path(file_pathname.relative_path_from(sourcemap_pathname))
|
75
|
-
rescue ArgumentError # when a relative path cannot be constructed
|
76
|
-
Sass::Util.file_uri_from_path(file_pathname)
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
58
|
protected
|
82
59
|
|
83
60
|
# If a full uri is passed, this removes the root from it
|
@@ -121,7 +98,7 @@ module Sass
|
|
121
98
|
end
|
122
99
|
|
123
100
|
# JRuby chokes when trying to import files from JARs when the path starts with './'.
|
124
|
-
ret.map {|f, s| [f.sub(
|
101
|
+
ret.map {|f, s| [f.sub(%r{^\./}, ''), s]}
|
125
102
|
end
|
126
103
|
|
127
104
|
def escape_glob_characters(name)
|
@@ -130,7 +107,7 @@ module Sass
|
|
130
107
|
end
|
131
108
|
end
|
132
109
|
|
133
|
-
REDUNDANT_DIRECTORY =
|
110
|
+
REDUNDANT_DIRECTORY = %r{#{Regexp.escape(File::SEPARATOR)}\.#{Regexp.escape(File::SEPARATOR)}}
|
134
111
|
# Given a base directory and an `@import`ed name,
|
135
112
|
# finds an existant file that matches the name.
|
136
113
|
#
|
@@ -138,16 +115,14 @@ module Sass
|
|
138
115
|
# @param name [String] The filename to search for.
|
139
116
|
# @return [(String, Symbol)] A filename-syntax pair.
|
140
117
|
def find_real_file(dir, name, options)
|
141
|
-
#
|
118
|
+
# on windows 'dir' can be in native File::ALT_SEPARATOR form
|
142
119
|
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
120
|
|
145
121
|
found = possible_files(remove_root(name)).map do |f, s|
|
146
|
-
path = (dir == "." ||
|
147
|
-
"#{escape_glob_characters(dir)}/#{f}"
|
122
|
+
path = (dir == "." || Pathname.new(f).absolute?) ? f : "#{escape_glob_characters(dir)}/#{f}"
|
148
123
|
Dir[path].map do |full_path|
|
149
124
|
full_path.gsub!(REDUNDANT_DIRECTORY, File::SEPARATOR)
|
150
|
-
[
|
125
|
+
[Pathname.new(full_path).cleanpath.to_s, s]
|
151
126
|
end
|
152
127
|
end
|
153
128
|
found = Sass::Util.flatten(found, 1)
|
@@ -155,20 +130,20 @@ module Sass
|
|
155
130
|
|
156
131
|
if found.size > 1 && !@same_name_warnings.include?(found.first.first)
|
157
132
|
found.each {|(f, _)| @same_name_warnings << f}
|
158
|
-
relative_to =
|
159
|
-
if options[:
|
133
|
+
relative_to = Pathname.new(dir)
|
134
|
+
if options[:_line]
|
160
135
|
# If _line exists, we're here due to an actual import in an
|
161
136
|
# import_node and we want to print a warning for a user writing an
|
162
137
|
# ambiguous import.
|
163
|
-
candidates = found.map
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
Candidates:
|
138
|
+
candidates = found.map {|(f, _)| " " + Pathname.new(f).relative_path_from(relative_to).to_s}.join("\n")
|
139
|
+
Sass::Util.sass_warn <<WARNING
|
140
|
+
WARNING: On line #{options[:_line]}#{" of #{options[:filename]}" if options[:filename]}:
|
141
|
+
It's not clear which file to import for '@import "#{name}"'.
|
142
|
+
Candidates:
|
169
143
|
#{candidates}
|
170
|
-
|
171
|
-
|
144
|
+
For now I'll choose #{File.basename found.first.first}.
|
145
|
+
This will be an error in future versions of Sass.
|
146
|
+
WARNING
|
172
147
|
else
|
173
148
|
# Otherwise, we're here via StalenessChecker, and we want to print a
|
174
149
|
# warning for a user running `sass --watch` with two ambiguous files.
|
@@ -188,7 +163,7 @@ WARNING
|
|
188
163
|
def split(name)
|
189
164
|
extension = nil
|
190
165
|
dirname, basename = File.dirname(name), File.basename(name)
|
191
|
-
if basename =~ /^(.*)\.(#{extensions.keys.map
|
166
|
+
if basename =~ /^(.*)\.(#{extensions.keys.map{|e| Regexp.escape(e)}.join('|')})$/
|
192
167
|
basename = $1
|
193
168
|
extension = $2
|
194
169
|
end
|
data/lib/sass/logger.rb
CHANGED
data/lib/sass/logger/base.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'sass/logger/log_level'
|
2
2
|
|
3
3
|
class Sass::Logger::Base
|
4
|
+
|
4
5
|
include Sass::Logger::LogLevel
|
5
6
|
|
6
7
|
attr_accessor :log_level
|
@@ -21,10 +22,11 @@ class Sass::Logger::Base
|
|
21
22
|
end
|
22
23
|
|
23
24
|
def log(level, message)
|
24
|
-
_log(level, message) if logging_level?(level)
|
25
|
+
self._log(level, message) if logging_level?(level)
|
25
26
|
end
|
26
27
|
|
27
28
|
def _log(level, message)
|
28
|
-
Kernel
|
29
|
+
Kernel::warn(message)
|
29
30
|
end
|
31
|
+
|
30
32
|
end
|
@@ -1,21 +1,24 @@
|
|
1
1
|
module Sass
|
2
2
|
module Logger
|
3
3
|
module LogLevel
|
4
|
+
|
4
5
|
def self.included(base)
|
5
6
|
base.extend(ClassMethods)
|
6
7
|
end
|
7
|
-
|
8
|
+
|
8
9
|
module ClassMethods
|
9
10
|
def inherited(subclass)
|
10
11
|
subclass.log_levels = subclass.superclass.log_levels.dup
|
11
12
|
end
|
12
13
|
|
13
|
-
attr_writer :log_levels
|
14
|
-
|
15
14
|
def log_levels
|
16
15
|
@log_levels ||= {}
|
17
16
|
end
|
18
17
|
|
18
|
+
def log_levels=(levels)
|
19
|
+
@log_levels = levels
|
20
|
+
end
|
21
|
+
|
19
22
|
def log_level?(level, min_level)
|
20
23
|
log_levels[level] >= log_levels[min_level]
|
21
24
|
end
|
@@ -40,6 +43,7 @@ module Sass
|
|
40
43
|
RUBY
|
41
44
|
end
|
42
45
|
end
|
46
|
+
|
43
47
|
end
|
44
48
|
end
|
45
49
|
end
|
data/lib/sass/media.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
module Sass::Media
|
3
3
|
# A comma-separated list of queries.
|
4
4
|
#
|
5
|
-
#
|
5
|
+
# media_query [ ',' S* media_query ]*
|
6
6
|
class QueryList
|
7
7
|
# The queries contained in this list.
|
8
8
|
#
|
@@ -43,11 +43,11 @@ module Sass::Media
|
|
43
43
|
end
|
44
44
|
|
45
45
|
# Returns a representation of the query as an array of strings and
|
46
|
-
# potentially {Sass::Script::
|
47
|
-
#
|
48
|
-
#
|
46
|
+
# potentially {Sass::Script::Node}s (if there's interpolation in it). When
|
47
|
+
# the interpolation is resolved and the strings are joined together, this
|
48
|
+
# will be the string representation of this query.
|
49
49
|
#
|
50
|
-
# @return [Array<String, Sass::Script::
|
50
|
+
# @return [Array<String, Sass::Script::Node>]
|
51
51
|
def to_a
|
52
52
|
Sass::Util.intersperse(queries.map {|q| q.to_a}, ', ').flatten
|
53
53
|
end
|
@@ -62,7 +62,7 @@ module Sass::Media
|
|
62
62
|
|
63
63
|
# A single media query.
|
64
64
|
#
|
65
|
-
#
|
65
|
+
# [ [ONLY | NOT]? S* media_type S* | expression ] [ AND S* expression ]*
|
66
66
|
class Query
|
67
67
|
# The modifier for the query.
|
68
68
|
#
|
@@ -70,7 +70,7 @@ module Sass::Media
|
|
70
70
|
# parsed as CSS, it contains a single string (accessible via
|
71
71
|
# \{#resolved_modifier}).
|
72
72
|
#
|
73
|
-
# @return [Array<String, Sass::Script::
|
73
|
+
# @return [Array<String, Sass::Script::Node>]
|
74
74
|
attr_accessor :modifier
|
75
75
|
|
76
76
|
# The type of the query (e.g. `"screen"` or `"print"`).
|
@@ -79,7 +79,7 @@ module Sass::Media
|
|
79
79
|
# parsed as CSS, it contains a single string (accessible via
|
80
80
|
# \{#resolved_type}).
|
81
81
|
#
|
82
|
-
# @return [Array<String, Sass::Script::
|
82
|
+
# @return [Array<String, Sass::Script::Node>]
|
83
83
|
attr_accessor :type
|
84
84
|
|
85
85
|
# The trailing expressions in the query.
|
@@ -87,12 +87,12 @@ module Sass::Media
|
|
87
87
|
# When parsed as Sass code, each expression contains strings and SassScript
|
88
88
|
# nodes. When parsed as CSS, each one contains a single string.
|
89
89
|
#
|
90
|
-
# @return [Array<Array<String, Sass::Script::
|
90
|
+
# @return [Array<Array<String, Sass::Script::Node>>]
|
91
91
|
attr_accessor :expressions
|
92
92
|
|
93
|
-
# @param modifier [Array<String, Sass::Script::
|
94
|
-
# @param type [Array<String, Sass::Script::
|
95
|
-
# @param expressions [Array<Array<String, Sass::Script::
|
93
|
+
# @param modifier [Array<String, Sass::Script::Node>] See \{#modifier}
|
94
|
+
# @param type [Array<String, Sass::Script::Node>] See \{#type}
|
95
|
+
# @param expressions [Array<Array<String, Sass::Script::Node>>] See \{#expressions}
|
96
96
|
def initialize(modifier, type, expressions)
|
97
97
|
@modifier = modifier
|
98
98
|
@type = type
|
@@ -125,7 +125,7 @@ module Sass::Media
|
|
125
125
|
m2, t2 = other.resolved_modifier.downcase, other.resolved_type.downcase
|
126
126
|
t1 = t2 if t1.empty?
|
127
127
|
t2 = t1 if t2.empty?
|
128
|
-
if (m1 == 'not') ^ (m2 == 'not')
|
128
|
+
if ((m1 == 'not') ^ (m2 == 'not'))
|
129
129
|
return if t1 == t2
|
130
130
|
type = m1 == 'not' ? t2 : t1
|
131
131
|
mod = m1 == 'not' ? m2 : m1
|
@@ -140,7 +140,7 @@ module Sass::Media
|
|
140
140
|
type = t1
|
141
141
|
mod = m1.empty? ? m2 : m1
|
142
142
|
end
|
143
|
-
Query.new([mod], [type], other.expressions + expressions)
|
143
|
+
return Query.new([mod], [type], other.expressions + expressions)
|
144
144
|
end
|
145
145
|
|
146
146
|
# Returns the CSS for the media query.
|
@@ -156,7 +156,7 @@ module Sass::Media
|
|
156
156
|
# It's possible for there to be script nodes in Expressions even when
|
157
157
|
# we're converting to CSS in the case where we parsed the document as
|
158
158
|
# CSS originally (as in css_test.rb).
|
159
|
-
e.map {|c| c.is_a?(Sass::Script::
|
159
|
+
e.map {|c| c.is_a?(Sass::Script::Node) ? c.to_sass : c.to_s}.join
|
160
160
|
end.join(' and ')
|
161
161
|
css
|
162
162
|
end
|
@@ -193,18 +193,21 @@ module Sass::Media
|
|
193
193
|
# @return [Query]
|
194
194
|
def deep_copy
|
195
195
|
Query.new(
|
196
|
-
modifier.map {|c| c.is_a?(Sass::Script::
|
197
|
-
type.map {|c| c.is_a?(Sass::Script::
|
198
|
-
expressions.map {|e| e.map {|c| c.is_a?(Sass::Script::
|
196
|
+
modifier.map {|c| c.is_a?(Sass::Script::Node) ? c.deep_copy : c},
|
197
|
+
type.map {|c| c.is_a?(Sass::Script::Node) ? c.deep_copy : c},
|
198
|
+
expressions.map {|e| e.map {|c| c.is_a?(Sass::Script::Node) ? c.deep_copy : c}})
|
199
199
|
end
|
200
200
|
end
|
201
201
|
|
202
202
|
# Converts an interpolation array to source.
|
203
203
|
#
|
204
|
-
# @param
|
204
|
+
# @param [Array<String, Sass::Script::Node>] The interpolation array to convert.
|
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
|
208
|
+
interp.map do |r|
|
209
|
+
next r if r.is_a?(String)
|
210
|
+
"\#{#{r.to_sass(options)}}"
|
211
|
+
end.join
|
209
212
|
end
|
210
213
|
end
|
data/lib/sass/plugin.rb
CHANGED
@@ -11,8 +11,7 @@ module Sass
|
|
11
11
|
# This module is used as the primary interface with Sass
|
12
12
|
# when it's used as a plugin for various frameworks.
|
13
13
|
# All Rack-enabled frameworks are supported out of the box.
|
14
|
-
# The plugin is
|
15
|
-
# {file:SASS_REFERENCE.md#rails_merb_plugin automatically activated for Rails and Merb}.
|
14
|
+
# The plugin is {file:SASS_REFERENCE.md#rails_merb_plugin automatically activated for Rails and Merb}.
|
16
15
|
# Other frameworks must enable it explicitly; see {Sass::Plugin::Rack}.
|
17
16
|
#
|
18
17
|
# This module has a large set of callbacks available
|
@@ -33,6 +32,7 @@ module Sass
|
|
33
32
|
# #=> Compiling app/sass/ie.scss to public/stylesheets/ie.css
|
34
33
|
# @see Sass::Plugin::Compiler
|
35
34
|
module Plugin
|
35
|
+
include Sass::Util
|
36
36
|
extend self
|
37
37
|
|
38
38
|
@checked_for_updates = false
|
@@ -65,8 +65,7 @@ module Sass
|
|
65
65
|
|
66
66
|
# Updates out-of-date stylesheets.
|
67
67
|
#
|
68
|
-
# Checks each Sass/SCSS file in
|
69
|
-
# {file:SASS_REFERENCE.md#template_location-option `:template_location`}
|
68
|
+
# Checks each Sass/SCSS file in {file:SASS_REFERENCE.md#template_location-option `:template_location`}
|
70
69
|
# to see if it's been modified more recently than the corresponding CSS file
|
71
70
|
# in {file:SASS_REFERENCE.md#css_location-option `:css_location`}.
|
72
71
|
# If it has, it updates the CSS file.
|
@@ -120,12 +119,13 @@ module Sass
|
|
120
119
|
def options
|
121
120
|
compiler.options
|
122
121
|
end
|
122
|
+
|
123
123
|
end
|
124
124
|
end
|
125
125
|
|
126
|
-
|
127
|
-
|
128
|
-
require 'sass/plugin/rails'
|
126
|
+
# On Rails 3+ the rails plugin is loaded at the right time in railtie.rb
|
127
|
+
if defined?(ActionController) && !Sass::Util.ap_geq_3?
|
128
|
+
require 'sass/plugin/rails'
|
129
129
|
elsif defined?(Merb::Plugins)
|
130
130
|
require 'sass/plugin/merb'
|
131
131
|
else
|
data/lib/sass/plugin/compiler.rb
CHANGED
@@ -7,6 +7,7 @@ require 'sass/plugin/configuration'
|
|
7
7
|
require 'sass/plugin/staleness_checker'
|
8
8
|
|
9
9
|
module Sass::Plugin
|
10
|
+
|
10
11
|
# The Compiler class handles compilation of multiple files and/or directories,
|
11
12
|
# including checking which CSS files are out-of-date and need to be updated
|
12
13
|
# and calling Sass to perform the compilation on those files.
|
@@ -25,41 +26,31 @@ module Sass::Plugin
|
|
25
26
|
# * `:never_update`
|
26
27
|
# * `:always_check`
|
27
28
|
class Compiler
|
29
|
+
include Sass::Util
|
28
30
|
include Configuration
|
29
31
|
extend Sass::Callbacks
|
30
32
|
|
31
33
|
# Creates a new compiler.
|
32
34
|
#
|
33
|
-
# @param
|
35
|
+
# @param options [{Symbol => Object}]
|
34
36
|
# See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
|
35
|
-
def initialize(
|
36
|
-
options.merge!(
|
37
|
+
def initialize(options = {})
|
38
|
+
self.options.merge!(options)
|
37
39
|
end
|
38
40
|
|
39
|
-
# Register a callback to be run
|
41
|
+
# Register a callback to be run after stylesheets are mass-updated.
|
40
42
|
# This is run whenever \{#update\_stylesheets} is called,
|
41
43
|
# unless the \{file:SASS_REFERENCE.md#never_update-option `:never_update` option}
|
42
44
|
# is enabled.
|
43
45
|
#
|
44
|
-
# @yield [
|
45
|
-
# @yieldparam
|
46
|
-
# Individual files to be updated
|
46
|
+
# @yield [individual_files]
|
47
|
+
# @yieldparam individual_files [<(String, String)>]
|
48
|
+
# Individual files to be updated, in addition to the directories
|
49
|
+
# specified in the options.
|
47
50
|
# The first element of each pair is the source file,
|
48
|
-
# the second is the target CSS file
|
49
|
-
# the third is the target sourcemap file.
|
51
|
+
# the second is the target CSS file.
|
50
52
|
define_callback :updating_stylesheets
|
51
53
|
|
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
|
-
|
63
54
|
# Register a callback to be run after a single stylesheet is updated.
|
64
55
|
# The callback is only run if the stylesheet is really updated;
|
65
56
|
# if the CSS file is fresh, this won't be run.
|
@@ -69,29 +60,35 @@ module Sass::Plugin
|
|
69
60
|
# when an exception CSS file is being written.
|
70
61
|
# To run an action for those files, use \{#on\_compilation\_error}.
|
71
62
|
#
|
72
|
-
# @yield [template, css
|
63
|
+
# @yield [template, css]
|
73
64
|
# @yieldparam template [String]
|
74
65
|
# The location of the Sass/SCSS file being updated.
|
75
66
|
# @yieldparam css [String]
|
76
67
|
# The location of the CSS file being generated.
|
77
|
-
# @yieldparam sourcemap [String]
|
78
|
-
# The location of the sourcemap being generated, if any.
|
79
68
|
define_callback :updated_stylesheet
|
80
69
|
|
81
|
-
# Register a callback to be run
|
70
|
+
# Register a callback to be run before a single stylesheet is updated.
|
71
|
+
# The callback is only run if the stylesheet is guaranteed to be updated;
|
72
|
+
# if the CSS file is fresh, this won't be run.
|
82
73
|
#
|
83
|
-
#
|
84
|
-
#
|
85
|
-
#
|
74
|
+
# Even if the \{file:SASS_REFERENCE.md#full_exception-option `:full_exception` option}
|
75
|
+
# is enabled, this callback won't be run
|
76
|
+
# when an exception CSS file is being written.
|
77
|
+
# To run an action for those files, use \{#on\_compilation\_error}.
|
86
78
|
#
|
87
|
-
# @yield [template, css
|
79
|
+
# @yield [template, css]
|
88
80
|
# @yieldparam template [String]
|
89
81
|
# The location of the Sass/SCSS file being updated.
|
90
82
|
# @yieldparam css [String]
|
91
83
|
# The location of the CSS file being generated.
|
92
|
-
|
93
|
-
|
94
|
-
|
84
|
+
define_callback :updating_stylesheet
|
85
|
+
|
86
|
+
def on_updating_stylesheet_with_deprecation_warning(&block)
|
87
|
+
Sass::Util.sass_warn("Sass::Compiler#on_updating_stylesheet callback is deprecated and will be removed in a future release. Use Sass::Compiler#on_updated_stylesheet instead, which is run after stylesheet compilation.")
|
88
|
+
on_updating_stylesheet_without_deprecation_warning(&block)
|
89
|
+
end
|
90
|
+
alias_method :on_updating_stylesheet_without_deprecation_warning, :on_updating_stylesheet
|
91
|
+
alias_method :on_updating_stylesheet, :on_updating_stylesheet_with_deprecation_warning
|
95
92
|
|
96
93
|
# Register a callback to be run when Sass decides not to update a stylesheet.
|
97
94
|
# In particular, the callback is run when Sass finds that
|
@@ -165,97 +162,49 @@ module Sass::Plugin
|
|
165
162
|
define_callback :template_deleted
|
166
163
|
|
167
164
|
# Register a callback to be run when Sass deletes a CSS file.
|
168
|
-
# This happens when the corresponding Sass/SCSS file has been deleted
|
169
|
-
# and when the compiler cleans the output files.
|
165
|
+
# This happens when the corresponding Sass/SCSS file has been deleted.
|
170
166
|
#
|
171
167
|
# @yield [filename]
|
172
168
|
# @yieldparam filename [String]
|
173
169
|
# The location of the CSS file that was deleted.
|
174
170
|
define_callback :deleting_css
|
175
171
|
|
176
|
-
# Register a callback to be run when Sass deletes a sourcemap file.
|
177
|
-
# This happens when the corresponding Sass/SCSS file has been deleted
|
178
|
-
# and when the compiler cleans the output files.
|
179
|
-
#
|
180
|
-
# @yield [filename]
|
181
|
-
# @yieldparam filename [String]
|
182
|
-
# The location of the sourcemap file that was deleted.
|
183
|
-
define_callback :deleting_sourcemap
|
184
|
-
|
185
172
|
# Updates out-of-date stylesheets.
|
186
173
|
#
|
187
|
-
# Checks each Sass/SCSS file in
|
188
|
-
# {file:SASS_REFERENCE.md#template_location-option `:template_location`}
|
174
|
+
# Checks each Sass/SCSS file in {file:SASS_REFERENCE.md#template_location-option `:template_location`}
|
189
175
|
# to see if it's been modified more recently than the corresponding CSS file
|
190
176
|
# in {file:SASS_REFERENCE.md#css_location-option `:css_location`}.
|
191
177
|
# If it has, it updates the CSS file.
|
192
178
|
#
|
193
|
-
# @param individual_files [Array<(String, String
|
179
|
+
# @param individual_files [Array<(String, String)>]
|
194
180
|
# A list of files to check for updates
|
195
181
|
# **in addition to those specified by the
|
196
182
|
# {file:SASS_REFERENCE.md#template_location-option `:template_location` option}.**
|
197
183
|
# The first string in each pair is the location of the Sass/SCSS file,
|
198
184
|
# 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.
|
200
185
|
def update_stylesheets(individual_files = [])
|
186
|
+
individual_files = individual_files.dup
|
201
187
|
Sass::Plugin.checked_for_updates = true
|
202
188
|
staleness_checker = StalenessChecker.new(engine_options)
|
203
189
|
|
204
|
-
files = file_list(individual_files)
|
205
|
-
run_updating_stylesheets(files)
|
206
|
-
|
207
|
-
updated_stylesheets = []
|
208
|
-
files.each do |file, css, sourcemap|
|
209
|
-
# TODO: Does staleness_checker need to check the sourcemap file as well?
|
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]
|
214
|
-
update_stylesheet(file, css, sourcemap)
|
215
|
-
else
|
216
|
-
run_not_updating_stylesheet(file, css, sourcemap)
|
217
|
-
end
|
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
190
|
template_location_array.each do |template_location, css_location|
|
249
191
|
Sass::Util.glob(File.join(template_location, "**", "[^_]*.s[ca]ss")).sort.each do |file|
|
250
192
|
# Get the relative path to the file
|
251
|
-
name =
|
252
|
-
Sass::Util.pathname(template_location.to_s)).to_s
|
193
|
+
name = file.sub(template_location.to_s.sub(/\/*$/, '/'), "")
|
253
194
|
css = css_filename(name, css_location)
|
254
|
-
|
255
|
-
|
195
|
+
individual_files << [file, css]
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
run_updating_stylesheets individual_files
|
200
|
+
|
201
|
+
individual_files.each do |file, css|
|
202
|
+
if options[:always_update] || staleness_checker.stylesheet_needs_update?(css, file)
|
203
|
+
update_stylesheet(file, css)
|
204
|
+
else
|
205
|
+
run_not_updating_stylesheet(file, css)
|
256
206
|
end
|
257
207
|
end
|
258
|
-
files
|
259
208
|
end
|
260
209
|
|
261
210
|
# Watches the template directory (or directories)
|
@@ -276,62 +225,73 @@ module Sass::Plugin
|
|
276
225
|
# The version of Listen distributed with Sass is loaded by default,
|
277
226
|
# but if another version has already been loaded that will be used instead.
|
278
227
|
#
|
279
|
-
# @param individual_files [Array<(String, String
|
280
|
-
# A list of files to
|
228
|
+
# @param individual_files [Array<(String, String)>]
|
229
|
+
# A list of files to watch for updates
|
281
230
|
# **in addition to those specified by the
|
282
231
|
# {file:SASS_REFERENCE.md#template_location-option `:template_location` option}.**
|
283
232
|
# The first string in each pair is the location of the Sass/SCSS file,
|
284
233
|
# the second is the location of the CSS file that it should be compiled to.
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
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]
|
292
|
-
|
293
|
-
directories = watched_paths
|
294
|
-
individual_files.each do |(source, _, _)|
|
295
|
-
directories << File.dirname(File.expand_path(source))
|
296
|
-
end
|
297
|
-
directories = remove_redundant_directories(directories)
|
234
|
+
def watch(individual_files = [])
|
235
|
+
update_stylesheets(individual_files)
|
236
|
+
|
237
|
+
load_listen!
|
298
238
|
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
239
|
+
template_paths = template_locations # cache the locations
|
240
|
+
individual_files_hash = individual_files.inject({}) do |h, files|
|
241
|
+
parent = File.dirname(files.first)
|
242
|
+
(h[parent] ||= []) << files unless template_paths.include?(parent)
|
243
|
+
h
|
304
244
|
end
|
245
|
+
directories = template_paths + individual_files_hash.keys +
|
246
|
+
[{:relative_paths => true}]
|
305
247
|
|
306
248
|
# TODO: Keep better track of what depends on what
|
307
249
|
# so we don't have to run a global update every time anything changes.
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
# In Listen 2.0.0 and on, :force_polling is an option. In earlier
|
319
|
-
# versions, it's a method on the listener (called below).
|
320
|
-
listener_args.last[:force_polling] = true
|
321
|
-
end
|
250
|
+
listener = Listen::MultiListener.new(*directories) do |modified, added, removed|
|
251
|
+
modified.each do |f|
|
252
|
+
parent = File.dirname(f)
|
253
|
+
if files = individual_files_hash[parent]
|
254
|
+
next unless files.first == f
|
255
|
+
else
|
256
|
+
next unless f =~ /\.s[ac]ss$/
|
257
|
+
end
|
258
|
+
run_template_modified(f)
|
259
|
+
end
|
322
260
|
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
261
|
+
added.each do |f|
|
262
|
+
parent = File.dirname(f)
|
263
|
+
if files = individual_files_hash[parent]
|
264
|
+
next unless files.first == f
|
265
|
+
else
|
266
|
+
next unless f =~ /\.s[ac]ss$/
|
267
|
+
end
|
268
|
+
run_template_created(f)
|
269
|
+
end
|
327
270
|
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
271
|
+
removed.each do |f|
|
272
|
+
parent = File.dirname(f)
|
273
|
+
if files = individual_files_hash[parent]
|
274
|
+
next unless files.first == f
|
275
|
+
try_delete_css files[1]
|
276
|
+
else
|
277
|
+
next unless f =~ /\.s[ac]ss$/
|
278
|
+
try_delete_css f.gsub(/\.s[ac]ss$/, '.css')
|
279
|
+
end
|
280
|
+
run_template_deleted(f)
|
281
|
+
end
|
282
|
+
|
283
|
+
update_stylesheets(individual_files)
|
332
284
|
end
|
333
285
|
|
334
|
-
|
286
|
+
# The native windows listener is much slower than the polling
|
287
|
+
# option, according to https://github.com/nex3/sass/commit/a3031856b22bc834a5417dedecb038b7be9b9e3e#commitcomment-1295118
|
288
|
+
listener.force_polling(true) if @options[:poll] || Sass::Util.windows?
|
289
|
+
|
290
|
+
begin
|
291
|
+
listener.start
|
292
|
+
rescue Exception => e
|
293
|
+
raise e unless e.is_a?(Interrupt)
|
294
|
+
end
|
335
295
|
end
|
336
296
|
|
337
297
|
# Non-destructively modifies \{#options} so that default values are properly set,
|
@@ -342,8 +302,6 @@ module Sass::Plugin
|
|
342
302
|
def engine_options(additional_options = {})
|
343
303
|
opts = options.merge(additional_options)
|
344
304
|
opts[:load_paths] = load_paths(opts)
|
345
|
-
options[:sourcemap] = :auto if options[:sourcemap] == true
|
346
|
-
options[:sourcemap] = :none if options[:sourcemap] == false
|
347
305
|
opts
|
348
306
|
end
|
349
307
|
|
@@ -352,186 +310,81 @@ module Sass::Plugin
|
|
352
310
|
StalenessChecker.stylesheet_needs_update?(css_file, template_file)
|
353
311
|
end
|
354
312
|
|
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
|
-
|
381
313
|
private
|
382
314
|
|
383
|
-
def
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
315
|
+
def load_listen!
|
316
|
+
if defined?(gem)
|
317
|
+
begin
|
318
|
+
gem 'listen', '~> 0.7'
|
319
|
+
require 'listen'
|
320
|
+
rescue Gem::LoadError
|
321
|
+
dir = Sass::Util.scope("vendor/listen/lib")
|
322
|
+
$LOAD_PATH.unshift dir
|
323
|
+
begin
|
324
|
+
require 'listen'
|
325
|
+
rescue LoadError => e
|
326
|
+
e.message << "\n" <<
|
327
|
+
if File.exists?(scope(".git"))
|
328
|
+
'Run "git submodule update --init" to get the recommended version.'
|
329
|
+
else
|
330
|
+
'Run "gem install listen" to get it.'
|
331
|
+
end
|
332
|
+
raise e
|
333
|
+
end
|
390
334
|
end
|
391
335
|
else
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
# Squelch Interrupt for clean exit from Listen::Listener
|
404
|
-
end
|
405
|
-
|
406
|
-
def remove_redundant_directories(directories)
|
407
|
-
dedupped = []
|
408
|
-
directories.each do |new_directory|
|
409
|
-
# no need to add a directory that is already watched.
|
410
|
-
next if dedupped.any? do |existing_directory|
|
411
|
-
child_of_directory?(existing_directory, new_directory)
|
412
|
-
end
|
413
|
-
# get rid of any sub directories of this new directory
|
414
|
-
dedupped.reject! do |existing_directory|
|
415
|
-
child_of_directory?(new_directory, existing_directory)
|
416
|
-
end
|
417
|
-
dedupped << new_directory
|
418
|
-
end
|
419
|
-
dedupped
|
420
|
-
end
|
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
|
336
|
+
begin
|
337
|
+
require 'listen'
|
338
|
+
rescue LoadError => e
|
339
|
+
dir = Sass::Util.scope("vendor/listen/lib")
|
340
|
+
if $LOAD_PATH.include?(dir)
|
341
|
+
raise e unless File.exists?(scope(".git"))
|
342
|
+
e.message << "\n" <<
|
343
|
+
'Run "git submodule update --init" to get the recommended version.'
|
344
|
+
else
|
345
|
+
$LOAD_PATH.unshift dir
|
346
|
+
retry
|
456
347
|
end
|
457
348
|
end
|
458
349
|
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
350
|
end
|
467
351
|
|
468
|
-
def update_stylesheet(filename, css
|
352
|
+
def update_stylesheet(filename, css)
|
469
353
|
dir = File.dirname(css)
|
470
|
-
unless File.
|
354
|
+
unless File.exists?(dir)
|
471
355
|
run_creating_directory dir
|
472
356
|
FileUtils.mkdir_p dir
|
473
357
|
end
|
474
358
|
|
475
359
|
begin
|
476
360
|
File.read(filename) unless File.readable?(filename) # triggers an error for handling
|
477
|
-
engine_opts = engine_options(:css_filename => css,
|
478
|
-
|
479
|
-
|
480
|
-
mapping = nil
|
481
|
-
run_compilation_starting(filename, css, sourcemap)
|
482
|
-
engine = Sass::Engine.for_file(filename, engine_opts)
|
483
|
-
if sourcemap
|
484
|
-
rendered, mapping = engine.render_with_sourcemap(File.basename(sourcemap))
|
485
|
-
else
|
486
|
-
rendered = engine.render
|
487
|
-
end
|
488
|
-
rescue StandardError => e
|
361
|
+
engine_opts = engine_options(:css_filename => css, :filename => filename)
|
362
|
+
result = Sass::Engine.for_file(filename, engine_opts).render
|
363
|
+
rescue Exception => e
|
489
364
|
compilation_error_occured = true
|
490
|
-
run_compilation_error e, filename, css
|
491
|
-
|
492
|
-
|
365
|
+
run_compilation_error e, filename, css
|
366
|
+
result = Sass::SyntaxError.exception_to_css(e, options)
|
367
|
+
else
|
368
|
+
run_updating_stylesheet filename, css
|
493
369
|
end
|
494
370
|
|
495
|
-
write_file(css,
|
496
|
-
|
497
|
-
write_file(sourcemap, mapping.to_json(
|
498
|
-
:css_path => css, :sourcemap_path => sourcemap, :type => options[:sourcemap]))
|
499
|
-
end
|
500
|
-
run_updated_stylesheet(filename, css, sourcemap) unless compilation_error_occured
|
371
|
+
write_file(css, result)
|
372
|
+
run_updated_stylesheet(filename, css) unless compilation_error_occured
|
501
373
|
end
|
502
374
|
|
503
|
-
def write_file(
|
375
|
+
def write_file(css, content)
|
504
376
|
flag = 'w'
|
505
377
|
flag = 'wb' if Sass::Util.windows? && options[:unix_newlines]
|
506
|
-
File.open(
|
378
|
+
File.open(css, flag) do |file|
|
507
379
|
file.set_encoding(content.encoding) unless Sass::Util.ruby1_8?
|
508
380
|
file.print(content)
|
509
381
|
end
|
510
382
|
end
|
511
383
|
|
512
384
|
def try_delete_css(css)
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
end
|
517
|
-
map = Sass::Util.sourcemap_name(css)
|
518
|
-
if File.exist?(map)
|
519
|
-
run_deleting_sourcemap map
|
520
|
-
File.delete map
|
521
|
-
end
|
522
|
-
end
|
523
|
-
|
524
|
-
def watched_file?(file)
|
525
|
-
normalized_load_paths.find {|lp| lp.watched_file?(file)}
|
526
|
-
end
|
527
|
-
|
528
|
-
def watched_paths
|
529
|
-
@watched_paths ||= normalized_load_paths.map {|lp| lp.directories_to_watch}.compact.flatten
|
530
|
-
end
|
531
|
-
|
532
|
-
def normalized_load_paths
|
533
|
-
@normalized_load_paths ||=
|
534
|
-
Sass::Engine.normalize_options(:load_paths => load_paths)[:load_paths]
|
385
|
+
return unless File.exists?(css)
|
386
|
+
run_deleting_css css
|
387
|
+
File.delete css
|
535
388
|
end
|
536
389
|
|
537
390
|
def load_paths(opts = options)
|
@@ -547,19 +400,7 @@ module Sass::Plugin
|
|
547
400
|
end
|
548
401
|
|
549
402
|
def css_filename(name, path)
|
550
|
-
"#{path}
|
551
|
-
gsub(/\.s[ac]ss$/, '.css')
|
552
|
-
end
|
553
|
-
|
554
|
-
def relative_to_pwd(f)
|
555
|
-
Sass::Util.pathname(f).relative_path_from(Sass::Util.pathname(Dir.pwd)).to_s
|
556
|
-
rescue ArgumentError # when a relative path cannot be computed
|
557
|
-
f
|
558
|
-
end
|
559
|
-
|
560
|
-
def child_of_directory?(parent, child)
|
561
|
-
parent_dir = parent.end_with?(File::SEPARATOR) ? parent : (parent + File::SEPARATOR)
|
562
|
-
child.start_with?(parent_dir) || parent == child
|
403
|
+
"#{path}/#{name}".gsub(/\.s[ac]ss$/, '.css')
|
563
404
|
end
|
564
405
|
end
|
565
406
|
end
|