sass 3.3.0 → 3.4.25
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardopts +3 -1
- data/CODE_OF_CONDUCT.md +10 -0
- data/CONTRIBUTING.md +148 -0
- data/MIT-LICENSE +1 -1
- data/README.md +76 -62
- data/Rakefile +104 -24
- 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/extra/sass-spec-ref.sh +32 -0
- data/extra/update_watch.rb +1 -1
- data/lib/sass/cache_stores/filesystem.rb +9 -5
- data/lib/sass/cache_stores/memory.rb +4 -5
- data/lib/sass/callbacks.rb +2 -2
- data/lib/sass/css.rb +12 -13
- data/lib/sass/deprecation.rb +55 -0
- data/lib/sass/engine.rb +106 -70
- data/lib/sass/environment.rb +39 -19
- data/lib/sass/error.rb +17 -20
- data/lib/sass/exec/base.rb +199 -0
- data/lib/sass/exec/sass_convert.rb +283 -0
- data/lib/sass/exec/sass_scss.rb +440 -0
- data/lib/sass/exec.rb +5 -771
- data/lib/sass/features.rb +9 -2
- data/lib/sass/importers/base.rb +8 -3
- data/lib/sass/importers/filesystem.rb +30 -38
- data/lib/sass/logger/base.rb +8 -2
- data/lib/sass/logger/delayed.rb +50 -0
- data/lib/sass/logger.rb +8 -3
- data/lib/sass/media.rb +1 -4
- data/lib/sass/plugin/compiler.rb +224 -90
- data/lib/sass/plugin/configuration.rb +38 -22
- data/lib/sass/plugin/merb.rb +2 -2
- data/lib/sass/plugin/rack.rb +3 -3
- data/lib/sass/plugin/rails.rb +1 -1
- data/lib/sass/plugin/staleness_checker.rb +4 -4
- data/lib/sass/plugin.rb +6 -5
- data/lib/sass/script/css_lexer.rb +1 -1
- data/lib/sass/script/css_parser.rb +2 -3
- data/lib/sass/script/css_variable_warning.rb +52 -0
- data/lib/sass/script/functions.rb +739 -318
- data/lib/sass/script/lexer.rb +134 -54
- data/lib/sass/script/parser.rb +252 -56
- data/lib/sass/script/tree/funcall.rb +13 -6
- data/lib/sass/script/tree/interpolation.rb +127 -4
- data/lib/sass/script/tree/list_literal.rb +31 -4
- data/lib/sass/script/tree/literal.rb +4 -0
- data/lib/sass/script/tree/node.rb +21 -3
- data/lib/sass/script/tree/operation.rb +54 -1
- data/lib/sass/script/tree/selector.rb +26 -0
- data/lib/sass/script/tree/string_interpolation.rb +59 -38
- data/lib/sass/script/tree/variable.rb +1 -1
- data/lib/sass/script/tree.rb +1 -0
- data/lib/sass/script/value/base.rb +17 -14
- data/lib/sass/script/value/bool.rb +0 -5
- data/lib/sass/script/value/color.rb +78 -42
- data/lib/sass/script/value/helpers.rb +119 -2
- data/lib/sass/script/value/list.rb +0 -15
- data/lib/sass/script/value/map.rb +1 -1
- data/lib/sass/script/value/null.rb +0 -5
- data/lib/sass/script/value/number.rb +112 -31
- data/lib/sass/script/value/string.rb +102 -13
- data/lib/sass/script/value.rb +0 -1
- data/lib/sass/script.rb +3 -3
- data/lib/sass/scss/css_parser.rb +24 -4
- data/lib/sass/scss/parser.rb +290 -383
- data/lib/sass/scss/rx.rb +17 -9
- data/lib/sass/scss/static_parser.rb +306 -4
- data/lib/sass/scss.rb +0 -2
- data/lib/sass/selector/abstract_sequence.rb +35 -18
- data/lib/sass/selector/comma_sequence.rb +114 -19
- data/lib/sass/selector/pseudo.rb +266 -0
- data/lib/sass/selector/sequence.rb +146 -40
- data/lib/sass/selector/simple.rb +22 -33
- data/lib/sass/selector/simple_sequence.rb +122 -39
- data/lib/sass/selector.rb +57 -197
- data/lib/sass/shared.rb +2 -2
- data/lib/sass/source/map.rb +31 -14
- data/lib/sass/source/position.rb +4 -4
- data/lib/sass/stack.rb +2 -8
- data/lib/sass/supports.rb +10 -13
- data/lib/sass/tree/at_root_node.rb +1 -0
- data/lib/sass/tree/charset_node.rb +1 -1
- data/lib/sass/tree/comment_node.rb +1 -1
- data/lib/sass/tree/css_import_node.rb +9 -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 +9 -0
- data/lib/sass/tree/import_node.rb +6 -5
- data/lib/sass/tree/keyframe_rule_node.rb +15 -0
- data/lib/sass/tree/node.rb +5 -3
- data/lib/sass/tree/prop_node.rb +6 -7
- data/lib/sass/tree/rule_node.rb +26 -11
- data/lib/sass/tree/visitors/check_nesting.rb +56 -32
- data/lib/sass/tree/visitors/convert.rb +59 -44
- data/lib/sass/tree/visitors/cssize.rb +34 -30
- data/lib/sass/tree/visitors/deep_copy.rb +6 -1
- data/lib/sass/tree/visitors/extend.rb +15 -13
- data/lib/sass/tree/visitors/perform.rb +87 -50
- data/lib/sass/tree/visitors/set_options.rb +15 -1
- data/lib/sass/tree/visitors/to_css.rb +72 -43
- data/lib/sass/util/multibyte_string_scanner.rb +0 -2
- data/lib/sass/util/normalized_map.rb +0 -1
- data/lib/sass/util/subset_map.rb +2 -3
- data/lib/sass/util.rb +334 -154
- data/lib/sass/version.rb +7 -7
- data/lib/sass.rb +10 -8
- data/test/sass/cache_test.rb +62 -20
- data/test/sass/callbacks_test.rb +1 -1
- data/test/sass/compiler_test.rb +24 -11
- data/test/sass/conversion_test.rb +241 -50
- data/test/sass/css2sass_test.rb +73 -5
- data/test/sass/css_variable_test.rb +132 -0
- data/test/sass/encoding_test.rb +219 -0
- data/test/sass/engine_test.rb +343 -260
- data/test/sass/exec_test.rb +12 -2
- data/test/sass/extend_test.rb +333 -44
- data/test/sass/functions_test.rb +353 -260
- data/test/sass/importer_test.rb +40 -21
- data/test/sass/logger_test.rb +1 -1
- data/test/sass/more_results/more_import.css +1 -1
- data/test/sass/more_templates/more1.sass +10 -10
- data/test/sass/more_templates/more_import.sass +2 -2
- data/test/sass/plugin_test.rb +24 -21
- 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 +5 -5
- data/test/sass/results/scss_import.css +1 -1
- data/test/sass/script_conversion_test.rb +71 -39
- data/test/sass/script_test.rb +714 -123
- data/test/sass/scss/css_test.rb +213 -30
- data/test/sass/scss/rx_test.rb +8 -4
- data/test/sass/scss/scss_test.rb +766 -22
- data/test/sass/source_map_test.rb +263 -95
- data/test/sass/superselector_test.rb +210 -0
- data/test/sass/templates/_partial.sass +1 -1
- data/test/sass/templates/basic.sass +10 -10
- data/test/sass/templates/bork1.sass +1 -1
- data/test/sass/templates/bork5.sass +1 -1
- data/test/sass/templates/compact.sass +10 -10
- data/test/sass/templates/complex.sass +187 -187
- data/test/sass/templates/compressed.sass +10 -10
- data/test/sass/templates/expanded.sass +10 -10
- data/test/sass/templates/import.sass +2 -2
- data/test/sass/templates/importee.sass +3 -3
- data/test/sass/templates/mixins.sass +22 -22
- data/test/sass/templates/multiline.sass +4 -4
- data/test/sass/templates/nested.sass +13 -13
- data/test/sass/templates/parent_ref.sass +12 -12
- data/test/sass/templates/script.sass +70 -70
- data/test/sass/templates/scss_import.scss +2 -1
- data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +1 -1
- data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +2 -2
- data/test/sass/templates/subdir/subdir.sass +3 -3
- data/test/sass/templates/units.sass +10 -10
- data/test/sass/test_helper.rb +1 -1
- data/test/sass/util/multibyte_string_scanner_test.rb +11 -3
- 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 +46 -45
- data/test/sass/value_helpers_test.rb +5 -7
- data/test/sass-spec.yml +3 -0
- data/test/test_helper.rb +7 -6
- 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 +310 -300
- data/CONTRIBUTING +0 -3
- data/ext/mkrf_conf.rb +0 -27
- data/lib/sass/script/value/deprecated_false.rb +0 -55
- data/lib/sass/scss/script_lexer.rb +0 -15
- data/lib/sass/scss/script_parser.rb +0 -25
- 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
@@ -26,11 +26,10 @@ module Sass
|
|
26
26
|
|
27
27
|
# @see Base#retrieve
|
28
28
|
def retrieve(key, sha)
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
end
|
29
|
+
return unless @contents.has_key?(key)
|
30
|
+
return unless @contents[key][:sha] == sha
|
31
|
+
obj = @contents[key][:obj]
|
32
|
+
obj.respond_to?(:deep_copy) ? obj.deep_copy : obj.dup
|
34
33
|
end
|
35
34
|
|
36
35
|
# @see Base#store
|
data/lib/sass/callbacks.rb
CHANGED
@@ -51,12 +51,12 @@ module Sass
|
|
51
51
|
def define_callback(name)
|
52
52
|
class_eval <<RUBY, __FILE__, __LINE__ + 1
|
53
53
|
def on_#{name}(&block)
|
54
|
-
@_sass_callbacks
|
54
|
+
@_sass_callbacks = {} unless defined? @_sass_callbacks
|
55
55
|
(@_sass_callbacks[#{name.inspect}] ||= []) << block
|
56
56
|
end
|
57
57
|
|
58
58
|
def run_#{name}(*args)
|
59
|
-
return unless @_sass_callbacks
|
59
|
+
return unless defined? @_sass_callbacks
|
60
60
|
return unless @_sass_callbacks[#{name.inspect}]
|
61
61
|
@_sass_callbacks[#{name.inspect}].each {|c| c[*args]}
|
62
62
|
end
|
data/lib/sass/css.rb
CHANGED
@@ -18,7 +18,7 @@ module Sass
|
|
18
18
|
# that can be converted to Unicode.
|
19
19
|
# If the stylesheet contains an `@charset` declaration,
|
20
20
|
# that overrides the Ruby encoding
|
21
|
-
# (see {file:SASS_REFERENCE.md#
|
21
|
+
# (see {file:SASS_REFERENCE.md#Encodings the encoding documentation})
|
22
22
|
# @option options :old [Boolean] (false)
|
23
23
|
# Whether or not to output old property syntax
|
24
24
|
# (`:color blue` as opposed to `color: blue`).
|
@@ -31,10 +31,11 @@ module Sass
|
|
31
31
|
template = template.read
|
32
32
|
end
|
33
33
|
|
34
|
-
@options = options.
|
34
|
+
@options = options.merge(:_convert => true)
|
35
35
|
# Backwards compatibility
|
36
36
|
@options[:old] = true if @options[:alternate] == false
|
37
37
|
@template = template
|
38
|
+
@checked_encoding = false
|
38
39
|
end
|
39
40
|
|
40
41
|
# Converts the CSS template into Sass or SCSS code.
|
@@ -67,9 +68,7 @@ module Sass
|
|
67
68
|
def check_encoding!
|
68
69
|
return if @checked_encoding
|
69
70
|
@checked_encoding = true
|
70
|
-
@template, @original_encoding = Sass::Util.check_sass_encoding(@template)
|
71
|
-
raise Sass::SyntaxError.new(msg, :line => line)
|
72
|
-
end
|
71
|
+
@template, @original_encoding = Sass::Util.check_sass_encoding(@template)
|
73
72
|
end
|
74
73
|
|
75
74
|
# Parses the CSS template and applies various transformations
|
@@ -77,14 +76,14 @@ module Sass
|
|
77
76
|
# @return [Tree::Node] The root node of the parsed tree
|
78
77
|
def build_tree
|
79
78
|
root = Sass::SCSS::CssParser.new(@template, @options[:filename], nil).parse
|
80
|
-
parse_selectors
|
81
|
-
expand_commas
|
82
|
-
nest_seqs
|
83
|
-
parent_ref_rules
|
84
|
-
flatten_rules
|
85
|
-
bubble_subject
|
86
|
-
fold_commas
|
87
|
-
dump_selectors
|
79
|
+
parse_selectors(root)
|
80
|
+
expand_commas(root)
|
81
|
+
nest_seqs(root)
|
82
|
+
parent_ref_rules(root)
|
83
|
+
flatten_rules(root)
|
84
|
+
bubble_subject(root)
|
85
|
+
fold_commas(root)
|
86
|
+
dump_selectors(root)
|
88
87
|
root
|
89
88
|
end
|
90
89
|
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Sass
|
2
|
+
# A deprecation warning that should only be printed once for a given line in a
|
3
|
+
# given file.
|
4
|
+
#
|
5
|
+
# A global Deprecation instance should be created for each type of deprecation
|
6
|
+
# warning, and `warn` should be called each time a warning is needed.
|
7
|
+
class Deprecation
|
8
|
+
@@allow_double_warnings = false
|
9
|
+
|
10
|
+
# Runs a block in which double deprecation warnings for the same location
|
11
|
+
# are allowed.
|
12
|
+
def self.allow_double_warnings
|
13
|
+
old_allow_double_warnings = @@allow_double_warnings
|
14
|
+
@@allow_double_warnings = true
|
15
|
+
yield
|
16
|
+
ensure
|
17
|
+
@@allow_double_warnings = old_allow_double_warnings
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize
|
21
|
+
# A set of filename, line pairs for which warnings have been emitted.
|
22
|
+
@seen = Set.new
|
23
|
+
end
|
24
|
+
|
25
|
+
# Prints `message` as a deprecation warning associated with `filename`,
|
26
|
+
# `line`, and optionally `column`.
|
27
|
+
#
|
28
|
+
# This ensures that only one message will be printed for each line of a
|
29
|
+
# given file.
|
30
|
+
#
|
31
|
+
# @overload warn(filename, line, message)
|
32
|
+
# @param filename [String, nil]
|
33
|
+
# @param line [Number]
|
34
|
+
# @param message [String]
|
35
|
+
# @overload warn(filename, line, column, message)
|
36
|
+
# @param filename [String, nil]
|
37
|
+
# @param line [Number]
|
38
|
+
# @param column [Number]
|
39
|
+
# @param message [String]
|
40
|
+
def warn(filename, line, column_or_message, message = nil)
|
41
|
+
return if !@@allow_double_warnings && @seen.add?([filename, line]).nil?
|
42
|
+
if message
|
43
|
+
column = column_or_message
|
44
|
+
else
|
45
|
+
message = column_or_message
|
46
|
+
end
|
47
|
+
|
48
|
+
location = "line #{line}"
|
49
|
+
location << ", column #{column}" if column
|
50
|
+
location << " of #{filename}" if filename
|
51
|
+
|
52
|
+
Sass::Util.sass_warn("DEPRECATION WARNING on #{location}:\n#{message}")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/sass/engine.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'set'
|
2
2
|
require 'digest/sha1'
|
3
3
|
require 'sass/cache_stores'
|
4
|
+
require 'sass/deprecation'
|
4
5
|
require 'sass/source/position'
|
5
6
|
require 'sass/source/range'
|
6
7
|
require 'sass/source/map'
|
@@ -30,6 +31,8 @@ require 'sass/tree/warn_node'
|
|
30
31
|
require 'sass/tree/import_node'
|
31
32
|
require 'sass/tree/charset_node'
|
32
33
|
require 'sass/tree/at_root_node'
|
34
|
+
require 'sass/tree/keyframe_rule_node'
|
35
|
+
require 'sass/tree/error_node'
|
33
36
|
require 'sass/tree/visitors/base'
|
34
37
|
require 'sass/tree/visitors/perform'
|
35
38
|
require 'sass/tree/visitors/cssize'
|
@@ -82,23 +85,25 @@ module Sass
|
|
82
85
|
# This class handles the parsing and compilation of the Sass template.
|
83
86
|
# Example usage:
|
84
87
|
#
|
85
|
-
# template = File.
|
88
|
+
# template = File.read('stylesheets/sassy.sass')
|
86
89
|
# sass_engine = Sass::Engine.new(template)
|
87
90
|
# output = sass_engine.render
|
88
91
|
# puts output
|
89
92
|
class Engine
|
93
|
+
@@old_property_deprecation = Deprecation.new
|
94
|
+
|
90
95
|
# A line of Sass code.
|
91
96
|
#
|
92
97
|
# `text`: `String`
|
93
98
|
# : The text in the line, without any whitespace at the beginning or end.
|
94
99
|
#
|
95
|
-
# `tabs`: `
|
100
|
+
# `tabs`: `Integer`
|
96
101
|
# : The level of indentation of the line.
|
97
102
|
#
|
98
|
-
# `index`: `
|
103
|
+
# `index`: `Integer`
|
99
104
|
# : The line number in the original document.
|
100
105
|
#
|
101
|
-
# `offset`: `
|
106
|
+
# `offset`: `Integer`
|
102
107
|
# : The number of bytes in on the line that the text begins.
|
103
108
|
# This ends up being the number of bytes of leading whitespace.
|
104
109
|
#
|
@@ -155,7 +160,7 @@ module Sass
|
|
155
160
|
# @api public
|
156
161
|
DEFAULT_OPTIONS = {
|
157
162
|
:style => :nested,
|
158
|
-
:load_paths => [
|
163
|
+
:load_paths => [],
|
159
164
|
:cache => true,
|
160
165
|
:cache_location => './.sass-cache',
|
161
166
|
:syntax => :sass,
|
@@ -166,11 +171,11 @@ module Sass
|
|
166
171
|
# default values and resolving aliases.
|
167
172
|
#
|
168
173
|
# @param options [{Symbol => Object}] The options hash;
|
169
|
-
# see {file:SASS_REFERENCE.md#
|
174
|
+
# see {file:SASS_REFERENCE.md#Options the Sass options documentation}
|
170
175
|
# @return [{Symbol => Object}] The normalized options hash.
|
171
176
|
# @private
|
172
177
|
def self.normalize_options(options)
|
173
|
-
options = DEFAULT_OPTIONS.merge(options.reject {|
|
178
|
+
options = DEFAULT_OPTIONS.merge(options.reject {|_k, v| v.nil?})
|
174
179
|
|
175
180
|
# If the `:filename` option is passed in without an importer,
|
176
181
|
# assume it's using the default filesystem importer.
|
@@ -206,6 +211,8 @@ module Sass
|
|
206
211
|
when :alternate; options[:property_syntax] = :new
|
207
212
|
when :normal; options[:property_syntax] = :old
|
208
213
|
end
|
214
|
+
options[:sourcemap] = :auto if options[:sourcemap] == true
|
215
|
+
options[:sourcemap] = :none if options[:sourcemap] == false
|
209
216
|
|
210
217
|
options
|
211
218
|
end
|
@@ -218,14 +225,14 @@ module Sass
|
|
218
225
|
#
|
219
226
|
# @param filename [String] The path to the Sass or SCSS file
|
220
227
|
# @param options [{Symbol => Object}] The options hash;
|
221
|
-
# See {file:SASS_REFERENCE.md#
|
228
|
+
# See {file:SASS_REFERENCE.md#Options the Sass options documentation}.
|
222
229
|
# @return [Sass::Engine] The Engine for the given Sass or SCSS file.
|
223
230
|
# @raise [Sass::SyntaxError] if there's an error in the document.
|
224
231
|
def self.for_file(filename, options)
|
225
232
|
had_syntax = options[:syntax]
|
226
233
|
|
227
234
|
if had_syntax
|
228
|
-
# Use what was explicitly
|
235
|
+
# Use what was explicitly specified
|
229
236
|
elsif filename =~ /\.scss$/
|
230
237
|
options.merge!(:syntax => :scss)
|
231
238
|
elsif filename =~ /\.sass$/
|
@@ -236,7 +243,7 @@ module Sass
|
|
236
243
|
end
|
237
244
|
|
238
245
|
# The options for the Sass engine.
|
239
|
-
# See {file:SASS_REFERENCE.md#
|
246
|
+
# See {file:SASS_REFERENCE.md#Options the Sass options documentation}.
|
240
247
|
#
|
241
248
|
# @return [{Symbol => Object}]
|
242
249
|
attr_reader :options
|
@@ -253,14 +260,17 @@ module Sass
|
|
253
260
|
# that can be converted to Unicode.
|
254
261
|
# If the template contains an `@charset` declaration,
|
255
262
|
# that overrides the Ruby encoding
|
256
|
-
# (see {file:SASS_REFERENCE.md#
|
263
|
+
# (see {file:SASS_REFERENCE.md#Encodings the encoding documentation})
|
257
264
|
# @param options [{Symbol => Object}] An options hash.
|
258
|
-
# See {file:SASS_REFERENCE.md#
|
265
|
+
# See {file:SASS_REFERENCE.md#Options the Sass options documentation}.
|
259
266
|
# @see {Sass::Engine.for_file}
|
260
267
|
# @see {Sass::Plugin}
|
261
268
|
def initialize(template, options = {})
|
262
269
|
@options = self.class.normalize_options(options)
|
263
270
|
@template = template
|
271
|
+
@checked_encoding = false
|
272
|
+
@filename = nil
|
273
|
+
@line = nil
|
264
274
|
end
|
265
275
|
|
266
276
|
# Render the template to CSS.
|
@@ -271,8 +281,8 @@ module Sass
|
|
271
281
|
# cannot be converted to UTF-8
|
272
282
|
# @raise [ArgumentError] if the document uses an unknown encoding with `@charset`
|
273
283
|
def render
|
274
|
-
return
|
275
|
-
Sass::Util.silence_sass_warnings {
|
284
|
+
return _to_tree.render unless @options[:quiet]
|
285
|
+
Sass::Util.silence_sass_warnings {_to_tree.render}
|
276
286
|
end
|
277
287
|
|
278
288
|
# Render the template to CSS and return the source map.
|
@@ -315,7 +325,7 @@ module Sass
|
|
315
325
|
# @raise [ArgumentError] if the document uses an unknown encoding with `@charset`
|
316
326
|
def source_encoding
|
317
327
|
check_encoding!
|
318
|
-
@
|
328
|
+
@source_encoding
|
319
329
|
end
|
320
330
|
|
321
331
|
# Gets a set of all the documents
|
@@ -360,7 +370,10 @@ Error generating source map: couldn't determine public URL for "#{filename}".
|
|
360
370
|
Without a public URL, there's nothing for the source map to link to.
|
361
371
|
An importer was not set for this file.
|
362
372
|
ERR
|
363
|
-
elsif Sass::Util.silence_warnings
|
373
|
+
elsif Sass::Util.silence_warnings do
|
374
|
+
sourcemap_dir = nil if @options[:sourcemap] == :file
|
375
|
+
importer.public_url(filename, sourcemap_dir).nil?
|
376
|
+
end
|
364
377
|
raise Sass::SyntaxError.new(<<ERR)
|
365
378
|
Error generating source map: couldn't determine public URL for "#{filename}".
|
366
379
|
Without a public URL, there's nothing for the source map to link to.
|
@@ -375,23 +388,12 @@ ERR
|
|
375
388
|
rendered << "/*# sourceMappingURL="
|
376
389
|
rendered << Sass::Util.escape_uri(sourcemap_uri)
|
377
390
|
rendered << " */\n"
|
378
|
-
rendered = encode_and_set_charset(rendered)
|
379
391
|
return rendered, sourcemap
|
380
392
|
end
|
381
393
|
|
382
|
-
def encode_and_set_charset(rendered)
|
383
|
-
return rendered if Sass::Util.ruby1_8?
|
384
|
-
begin
|
385
|
-
# Try to convert the result to the original encoding,
|
386
|
-
# but if that doesn't work fall back on UTF-8
|
387
|
-
rendered = rendered.encode(source_encoding)
|
388
|
-
rescue EncodingError
|
389
|
-
end
|
390
|
-
rendered.gsub(Regexp.new('\A@charset "(.*?)"'.encode(source_encoding)),
|
391
|
-
"@charset \"#{source_encoding.name}\"".encode(source_encoding))
|
392
|
-
end
|
393
|
-
|
394
394
|
def _to_tree
|
395
|
+
check_encoding!
|
396
|
+
|
395
397
|
if (@options[:cache] || @options[:read_cache]) &&
|
396
398
|
@options[:filename] && @options[:importer]
|
397
399
|
key = sassc_key
|
@@ -403,8 +405,6 @@ ERR
|
|
403
405
|
end
|
404
406
|
end
|
405
407
|
|
406
|
-
check_encoding!
|
407
|
-
|
408
408
|
if @options[:syntax] == :scss
|
409
409
|
root = Sass::SCSS::Parser.new(@template, @options[:filename], @options[:importer]).parse
|
410
410
|
else
|
@@ -436,9 +436,7 @@ ERR
|
|
436
436
|
def check_encoding!
|
437
437
|
return if @checked_encoding
|
438
438
|
@checked_encoding = true
|
439
|
-
@template, @
|
440
|
-
raise Sass::SyntaxError.new(msg, :line => line)
|
441
|
-
end
|
439
|
+
@template, @source_encoding = Sass::Util.check_sass_encoding(@template)
|
442
440
|
end
|
443
441
|
|
444
442
|
def tabulate(string)
|
@@ -446,7 +444,7 @@ ERR
|
|
446
444
|
comment_tab_str = nil
|
447
445
|
first = true
|
448
446
|
lines = []
|
449
|
-
string.
|
447
|
+
string.scan(/^[^\n]*?$/).each_with_index do |line, index|
|
450
448
|
index += (@options[:line] || 1)
|
451
449
|
if line.strip.empty?
|
452
450
|
lines.last.text << "\n" if lines.last && lines.last.comment?
|
@@ -484,7 +482,7 @@ ERR
|
|
484
482
|
|
485
483
|
line_tabs = line_tab_str.scan(tab_str).size
|
486
484
|
if tab_str * line_tabs != line_tab_str
|
487
|
-
message = <<END.strip.
|
485
|
+
message = <<END.strip.tr("\n", ' ')
|
488
486
|
Inconsistent indentation: #{Sass::Shared.human_indentation line_tab_str, true} used for indentation,
|
489
487
|
but the rest of the document was indented using #{Sass::Shared.human_indentation tab_str}.
|
490
488
|
END
|
@@ -497,15 +495,13 @@ END
|
|
497
495
|
end
|
498
496
|
|
499
497
|
# @comment
|
500
|
-
# rubocop:disable ParameterLists
|
501
498
|
def try_comment(line, last, tab_str, comment_tab_str, index)
|
502
|
-
# rubocop:enable ParameterLists
|
503
499
|
return unless last && last.comment?
|
504
500
|
# Nested comment stuff must be at least one whitespace char deeper
|
505
501
|
# than the normal indentation
|
506
502
|
return unless line =~ /^#{tab_str}\s/
|
507
503
|
unless line =~ /^(?:#{comment_tab_str})(.*)$/
|
508
|
-
raise SyntaxError.new(<<MSG.strip.
|
504
|
+
raise SyntaxError.new(<<MSG.strip.tr("\n", " "), :line => index)
|
509
505
|
Inconsistent indentation:
|
510
506
|
previous line was indented by #{Sass::Shared.human_indentation comment_tab_str},
|
511
507
|
but this line was indented by #{Sass::Shared.human_indentation line[/^\s*/]}.
|
@@ -582,8 +578,8 @@ MSG
|
|
582
578
|
if continued_comment &&
|
583
579
|
child.line == continued_comment.line +
|
584
580
|
continued_comment.lines + 1
|
585
|
-
continued_comment.value.last.sub!(
|
586
|
-
child.value.first.gsub!(
|
581
|
+
continued_comment.value.last.sub!(%r{ \*/\Z}, '')
|
582
|
+
child.value.first.gsub!(%r{\A/\*}, ' *')
|
587
583
|
continued_comment.value += ["\n"] + child.value
|
588
584
|
next
|
589
585
|
end
|
@@ -632,6 +628,11 @@ WARNING
|
|
632
628
|
raise SyntaxError.new("Invalid property: \"#{line.text}\".",
|
633
629
|
:line => @line) if name.nil? || value.nil?
|
634
630
|
|
631
|
+
@@old_property_deprecation.warn(@options[:filename], @line, <<WARNING)
|
632
|
+
Old-style properties like "#{line.text}" are deprecated and will be an error in future versions of Sass.
|
633
|
+
Use "#{name}: #{value}" instead.
|
634
|
+
WARNING
|
635
|
+
|
635
636
|
value_start_offset = name_end_offset = name_start_offset + name.length
|
636
637
|
unless value.empty?
|
637
638
|
# +1 and -1 both compensate for the leading ':', which is part of line.text
|
@@ -725,9 +726,12 @@ WARNING
|
|
725
726
|
expr = Sass::Script::Tree::Literal.new(Sass::Script::Value::String.new(""))
|
726
727
|
end_offset = start_offset
|
727
728
|
else
|
728
|
-
expr = parse_script(value,
|
729
|
+
expr = parse_script(value,
|
730
|
+
:offset => to_parser_offset(start_offset),
|
731
|
+
:css_variable => name.start_with?("--"))
|
729
732
|
end_offset = expr.source_range.end_pos.offset - 1
|
730
733
|
end
|
734
|
+
|
731
735
|
node = Tree::PropNode.new(parse_interp(name), expr, prop)
|
732
736
|
node.value_source_range = Sass::Source::Range.new(
|
733
737
|
Sass::Source::Position.new(line.index, to_parser_offset(start_offset)),
|
@@ -784,7 +788,19 @@ WARNING
|
|
784
788
|
else
|
785
789
|
:normal
|
786
790
|
end
|
787
|
-
Tree::CommentNode.new(value, type)
|
791
|
+
comment = Tree::CommentNode.new(value, type)
|
792
|
+
comment.line = line.index
|
793
|
+
text = line.text.rstrip
|
794
|
+
if text.include?("\n")
|
795
|
+
end_offset = text.length - text.rindex("\n")
|
796
|
+
else
|
797
|
+
end_offset = to_parser_offset(line.offset + text.length)
|
798
|
+
end
|
799
|
+
comment.source_range = Sass::Source::Range.new(
|
800
|
+
Sass::Source::Position.new(@line, to_parser_offset(line.offset)),
|
801
|
+
Sass::Source::Position.new(@line + text.count("\n"), end_offset),
|
802
|
+
@options[:filename])
|
803
|
+
comment
|
788
804
|
else
|
789
805
|
Tree::RuleNode.new(parse_interp(line.text), full_line_range(line))
|
790
806
|
end
|
@@ -792,16 +808,14 @@ WARNING
|
|
792
808
|
|
793
809
|
DIRECTIVES = Set[:mixin, :include, :function, :return, :debug, :warn, :for,
|
794
810
|
:each, :while, :if, :else, :extend, :import, :media, :charset, :content,
|
795
|
-
:at_root]
|
811
|
+
:at_root, :error]
|
796
812
|
|
797
|
-
# @comment
|
798
|
-
# rubocop:disable MethodLength
|
799
813
|
def parse_directive(parent, line, root)
|
800
814
|
directive, whitespace, value = line.text[1..-1].split(/(\s+)/, 2)
|
801
815
|
raise SyntaxError.new("Invalid directive: '@'.") unless directive
|
802
816
|
offset = directive.size + whitespace.size + 1 if whitespace
|
803
817
|
|
804
|
-
directive_name = directive.
|
818
|
+
directive_name = directive.tr('-', '_').to_sym
|
805
819
|
if DIRECTIVES.include?(directive_name)
|
806
820
|
return send("parse_#{directive_name}_directive", parent, line, root, value, offset)
|
807
821
|
end
|
@@ -834,6 +848,14 @@ WARNING
|
|
834
848
|
Tree::DebugNode.new(parse_script(value, :offset => offset))
|
835
849
|
end
|
836
850
|
|
851
|
+
def parse_error_directive(parent, line, root, value, offset)
|
852
|
+
raise SyntaxError.new("Invalid error directive '@error': expected expression.") unless value
|
853
|
+
raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath error directives.",
|
854
|
+
:line => @line + 1) unless line.children.empty?
|
855
|
+
offset = line.offset + line.text.index(value).to_i
|
856
|
+
Tree::ErrorNode.new(parse_script(value, :offset => offset))
|
857
|
+
end
|
858
|
+
|
837
859
|
def parse_extend_directive(parent, line, root, value, offset)
|
838
860
|
raise SyntaxError.new("Invalid extend directive '@extend': expected expression.") unless value
|
839
861
|
raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath extend directives.",
|
@@ -848,8 +870,6 @@ WARNING
|
|
848
870
|
)
|
849
871
|
Tree::ExtendNode.new(interp_parsed, optional, selector_range)
|
850
872
|
end
|
851
|
-
# @comment
|
852
|
-
# rubocop:enable MethodLength
|
853
873
|
|
854
874
|
def parse_warn_directive(parent, line, root, value, offset)
|
855
875
|
raise SyntaxError.new("Invalid warn directive '@warn': expected expression.") unless value
|
@@ -1009,15 +1029,25 @@ WARNING
|
|
1009
1029
|
script_parser = Sass::Script::Parser.new(scanner, @line, to_parser_offset(offset), @options)
|
1010
1030
|
str = script_parser.parse_string
|
1011
1031
|
|
1012
|
-
|
1013
|
-
@options[:filename], @options[:importer],
|
1014
|
-
@line, str.source_range.end_pos.offset)
|
1015
|
-
if (media = media_parser.parse_media_query_list)
|
1016
|
-
end_pos = Sass::Source::Position.new(@line, media_parser.offset + 1)
|
1017
|
-
node = Tree::CssImportNode.new(str, media.to_a)
|
1018
|
-
else
|
1032
|
+
if scanner.eos?
|
1019
1033
|
end_pos = str.source_range.end_pos
|
1020
1034
|
node = Tree::CssImportNode.new(str)
|
1035
|
+
else
|
1036
|
+
supports_parser = Sass::SCSS::Parser.new(scanner,
|
1037
|
+
@options[:filename], @options[:importer],
|
1038
|
+
@line, str.source_range.end_pos.offset)
|
1039
|
+
supports_condition = supports_parser.parse_supports_clause
|
1040
|
+
|
1041
|
+
if scanner.eos?
|
1042
|
+
node = Tree::CssImportNode.new(str, [], supports_condition)
|
1043
|
+
else
|
1044
|
+
media_parser = Sass::SCSS::Parser.new(scanner,
|
1045
|
+
@options[:filename], @options[:importer],
|
1046
|
+
@line, str.source_range.end_pos.offset)
|
1047
|
+
media = media_parser.parse_media_query_list
|
1048
|
+
end_pos = Sass::Source::Position.new(@line, media_parser.offset + 1)
|
1049
|
+
node = Tree::CssImportNode.new(str, media.to_a, supports_condition)
|
1050
|
+
end
|
1021
1051
|
end
|
1022
1052
|
|
1023
1053
|
node.source_range = Sass::Source::Range.new(
|
@@ -1026,7 +1056,7 @@ WARNING
|
|
1026
1056
|
return node
|
1027
1057
|
end
|
1028
1058
|
|
1029
|
-
unless (
|
1059
|
+
unless (quoted_val = scanner.scan(Sass::SCSS::RX::STRING))
|
1030
1060
|
scanned = scanner.scan(/[^,;]+/)
|
1031
1061
|
node = Tree::ImportNode.new(scanned)
|
1032
1062
|
start_parser_offset = to_parser_offset(offset)
|
@@ -1038,21 +1068,21 @@ WARNING
|
|
1038
1068
|
end
|
1039
1069
|
|
1040
1070
|
start_offset = offset
|
1041
|
-
offset +=
|
1042
|
-
val = scanner[1] || scanner[2]
|
1071
|
+
offset += scanner.matched.length
|
1072
|
+
val = Sass::Script::Value::String.value(scanner[1] || scanner[2])
|
1043
1073
|
scanned = scanner.scan(/\s*/)
|
1044
1074
|
if !scanner.match?(/[,;]|$/)
|
1045
1075
|
offset += scanned.length if scanned
|
1046
1076
|
media_parser = Sass::SCSS::Parser.new(scanner,
|
1047
1077
|
@options[:filename], @options[:importer], @line, offset)
|
1048
1078
|
media = media_parser.parse_media_query_list
|
1049
|
-
node = Tree::CssImportNode.new(
|
1079
|
+
node = Tree::CssImportNode.new(quoted_val, media.to_a)
|
1050
1080
|
node.source_range = Sass::Source::Range.new(
|
1051
1081
|
Sass::Source::Position.new(@line, to_parser_offset(start_offset)),
|
1052
1082
|
Sass::Source::Position.new(@line, media_parser.offset),
|
1053
1083
|
@options[:filename], @options[:importer])
|
1054
1084
|
elsif val =~ %r{^(https?:)?//}
|
1055
|
-
node = Tree::CssImportNode.new(
|
1085
|
+
node = Tree::CssImportNode.new(quoted_val)
|
1056
1086
|
node.source_range = Sass::Source::Range.new(
|
1057
1087
|
Sass::Source::Position.new(@line, to_parser_offset(start_offset)),
|
1058
1088
|
Sass::Source::Position.new(@line, to_parser_offset(offset)),
|
@@ -1124,9 +1154,9 @@ WARNING
|
|
1124
1154
|
end
|
1125
1155
|
|
1126
1156
|
def parse_script(script, options = {})
|
1127
|
-
line = options
|
1128
|
-
offset = options
|
1129
|
-
Script.parse(script, line, offset, @options)
|
1157
|
+
line = options.delete(:line) || @line
|
1158
|
+
offset = options.delete(:offset) || @offset + 1
|
1159
|
+
Script.parse(script, line, offset, @options.merge(options))
|
1130
1160
|
end
|
1131
1161
|
|
1132
1162
|
def format_comment_text(text, silent)
|
@@ -1138,9 +1168,10 @@ WARNING
|
|
1138
1168
|
end
|
1139
1169
|
|
1140
1170
|
return "/* */" if content.empty?
|
1141
|
-
content.last.gsub!(
|
1171
|
+
content.last.gsub!(%r{ ?\*/ *$}, '')
|
1172
|
+
first = content.shift unless removed_first
|
1142
1173
|
content.map! {|l| l.gsub!(/^\*( ?)/, '\1') || (l.empty? ? "" : " ") + l}
|
1143
|
-
content.first
|
1174
|
+
content.unshift first unless removed_first
|
1144
1175
|
if silent
|
1145
1176
|
"/*" + content.join("\n *") + " */"
|
1146
1177
|
else
|
@@ -1178,10 +1209,15 @@ WARNING
|
|
1178
1209
|
res << "\\" * (escapes - 1) << '#{'
|
1179
1210
|
else
|
1180
1211
|
res << "\\" * [0, escapes - 1].max
|
1181
|
-
|
1182
|
-
|
1183
|
-
|
1184
|
-
|
1212
|
+
if scan[1].include?("\n")
|
1213
|
+
line += scan[1].count("\n")
|
1214
|
+
offset = scan.matched_size - scan[1].rindex("\n")
|
1215
|
+
else
|
1216
|
+
offset += scan.matched_size
|
1217
|
+
end
|
1218
|
+
node = Script::Parser.new(scan, line, offset, options).parse_interpolated
|
1219
|
+
offset = node.source_range.end_pos.offset
|
1220
|
+
res << node
|
1185
1221
|
end
|
1186
1222
|
end
|
1187
1223
|
res << rest
|
data/lib/sass/environment.rb
CHANGED
@@ -41,7 +41,7 @@ module Sass
|
|
41
41
|
if @#{name}s.include?(name)
|
42
42
|
@#{name}s[name] = value
|
43
43
|
true
|
44
|
-
elsif @parent
|
44
|
+
elsif @parent && !@parent.global?
|
45
45
|
@parent.try_set_#{name}(name, value)
|
46
46
|
else
|
47
47
|
false
|
@@ -53,6 +53,10 @@ module Sass
|
|
53
53
|
@#{name}s ||= {}
|
54
54
|
@#{name}s[name.tr('_', '-')] = value
|
55
55
|
end
|
56
|
+
|
57
|
+
def set_global_#{name}(name, value)
|
58
|
+
global_env.set_#{name}(name, value)
|
59
|
+
end
|
56
60
|
RUBY
|
57
61
|
end
|
58
62
|
end
|
@@ -76,28 +80,27 @@ module Sass
|
|
76
80
|
# Sass::Callable
|
77
81
|
inherited_hash_reader :function
|
78
82
|
|
79
|
-
# Whether a warning has been emitted for assigning to the given
|
80
|
-
# global variable. This is a set of tuples containing the name of
|
81
|
-
# the variable, its filename, and its line number.
|
82
|
-
#
|
83
|
-
# @return [Set<[String, String, int]>]
|
84
|
-
attr_reader :global_warning_given
|
85
|
-
|
86
|
-
# Whether a warning has been emitted for misusing a deprecated false value.
|
87
|
-
# This is a set of tuples containing the filename and its line number.
|
88
|
-
#
|
89
|
-
# @return [Set<[String, int]>]
|
90
|
-
attr_reader :deprecated_false_warning_given
|
91
|
-
|
92
83
|
# @param options [{Symbol => Object}] The options hash. See
|
93
|
-
# {file:SASS_REFERENCE.md#
|
84
|
+
# {file:SASS_REFERENCE.md#Options the Sass options documentation}.
|
94
85
|
# @param parent [Environment] See \{#parent}
|
95
86
|
def initialize(parent = nil, options = nil)
|
96
87
|
@parent = parent
|
97
88
|
@options = options || (parent && parent.options) || {}
|
98
|
-
@stack = Sass::Stack.new
|
99
|
-
@
|
100
|
-
@
|
89
|
+
@stack = @parent.nil? ? Sass::Stack.new : nil
|
90
|
+
@caller = nil
|
91
|
+
@content = nil
|
92
|
+
@filename = nil
|
93
|
+
@functions = nil
|
94
|
+
@mixins = nil
|
95
|
+
@selector = nil
|
96
|
+
@vars = nil
|
97
|
+
end
|
98
|
+
|
99
|
+
# Returns whether this is the global environment.
|
100
|
+
#
|
101
|
+
# @return [Boolean]
|
102
|
+
def global?
|
103
|
+
@parent.nil?
|
101
104
|
end
|
102
105
|
|
103
106
|
# The environment of the caller of this environment's mixin or function.
|
@@ -128,7 +131,7 @@ module Sass
|
|
128
131
|
#
|
129
132
|
# @return [Environment]
|
130
133
|
def global_env
|
131
|
-
@global_env ||=
|
134
|
+
@global_env ||= global? ? self : @parent.global_env
|
132
135
|
end
|
133
136
|
|
134
137
|
# The import/mixin stack.
|
@@ -192,4 +195,21 @@ module Sass
|
|
192
195
|
@content ||= env.is_a?(ReadOnlyEnvironment) ? env : ReadOnlyEnvironment.new(env, env.options)
|
193
196
|
end
|
194
197
|
end
|
198
|
+
|
199
|
+
# An environment that can write to in-scope global variables, but doesn't
|
200
|
+
# create new variables in the global scope. Useful for top-level control
|
201
|
+
# directives.
|
202
|
+
class SemiGlobalEnvironment < Environment
|
203
|
+
def try_set_var(name, value)
|
204
|
+
@vars ||= {}
|
205
|
+
if @vars.include?(name)
|
206
|
+
@vars[name] = value
|
207
|
+
true
|
208
|
+
elsif @parent
|
209
|
+
@parent.try_set_var(name, value)
|
210
|
+
else
|
211
|
+
false
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
195
215
|
end
|