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
data/lib/sass/script/parser.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'sass/script/lexer'
|
2
|
+
require 'sass/script/css_variable_warning'
|
2
3
|
|
3
4
|
module Sass
|
4
5
|
module Script
|
@@ -7,28 +8,34 @@ module Sass
|
|
7
8
|
class Parser
|
8
9
|
# The line number of the parser's current position.
|
9
10
|
#
|
10
|
-
# @return [
|
11
|
+
# @return [Integer]
|
11
12
|
def line
|
12
13
|
@lexer.line
|
13
14
|
end
|
14
15
|
|
15
16
|
# The column number of the parser's current position.
|
16
17
|
#
|
17
|
-
# @return [
|
18
|
+
# @return [Integer]
|
18
19
|
def offset
|
19
20
|
@lexer.offset
|
20
21
|
end
|
21
22
|
|
22
23
|
# @param str [String, StringScanner] The source text to parse
|
23
|
-
# @param line [
|
24
|
+
# @param line [Integer] The line on which the SassScript appears.
|
24
25
|
# Used for error reporting and sourcemap building
|
25
|
-
# @param offset [
|
26
|
+
# @param offset [Integer] The character (not byte) offset where the script starts in the line.
|
26
27
|
# Used for error reporting and sourcemap building
|
27
|
-
# @param options [{Symbol => Object}] An options hash;
|
28
|
-
#
|
28
|
+
# @param options [{Symbol => Object}] An options hash; see
|
29
|
+
# {file:SASS_REFERENCE.md#Options the Sass options documentation}.
|
30
|
+
# This supports an additional `:allow_extra_text` option that controls
|
31
|
+
# whether the parser throws an error when extra text is encountered
|
32
|
+
# after the parsed construct.
|
29
33
|
def initialize(str, line, offset, options = {})
|
30
34
|
@options = options
|
35
|
+
@allow_extra_text = options.delete(:allow_extra_text)
|
31
36
|
@lexer = lexer_class.new(str, line, offset, options)
|
37
|
+
@stop_at = nil
|
38
|
+
@css_variable_warning = nil
|
32
39
|
end
|
33
40
|
|
34
41
|
# Parses a SassScript expression within an interpolated segment (`#{}`).
|
@@ -36,13 +43,20 @@ module Sass
|
|
36
43
|
# which signals the end of an interpolated segment,
|
37
44
|
# it returns rather than throwing an error.
|
38
45
|
#
|
46
|
+
# @param warn_for_color [Boolean] Whether raw color values passed to
|
47
|
+
# interoplation should cause a warning.
|
39
48
|
# @return [Script::Tree::Node] The root node of the parse tree
|
40
49
|
# @raise [Sass::SyntaxError] if the expression isn't valid SassScript
|
41
|
-
def parse_interpolated
|
50
|
+
def parse_interpolated(warn_for_color = false)
|
51
|
+
# Start two characters back to compensate for #{
|
52
|
+
start_pos = Sass::Source::Position.new(line, offset - 2)
|
42
53
|
expr = assert_expr :expr
|
43
54
|
assert_tok :end_interpolation
|
55
|
+
expr = Sass::Script::Tree::Interpolation.new(
|
56
|
+
nil, expr, nil, false, false, :warn_for_color => warn_for_color)
|
57
|
+
check_for_interpolation expr
|
44
58
|
expr.options = @options
|
45
|
-
expr
|
59
|
+
node(expr, start_pos)
|
46
60
|
rescue Sass::SyntaxError => e
|
47
61
|
e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
|
48
62
|
raise e
|
@@ -50,12 +64,23 @@ module Sass
|
|
50
64
|
|
51
65
|
# Parses a SassScript expression.
|
52
66
|
#
|
67
|
+
# @param css_variable [Boolean] Whether this is the value of a CSS variable.
|
53
68
|
# @return [Script::Tree::Node] The root node of the parse tree
|
54
69
|
# @raise [Sass::SyntaxError] if the expression isn't valid SassScript
|
55
|
-
def parse
|
70
|
+
def parse(css_variable = false)
|
71
|
+
if css_variable
|
72
|
+
@css_variable_warning = CssVariableWarning.new
|
73
|
+
end
|
74
|
+
|
56
75
|
expr = assert_expr :expr
|
57
76
|
assert_done
|
58
77
|
expr.options = @options
|
78
|
+
check_for_interpolation expr
|
79
|
+
|
80
|
+
if css_variable
|
81
|
+
@css_variable_warning.value = expr
|
82
|
+
end
|
83
|
+
|
59
84
|
expr
|
60
85
|
rescue Sass::SyntaxError => e
|
61
86
|
e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
|
@@ -73,6 +98,7 @@ module Sass
|
|
73
98
|
expr = assert_expr :expr
|
74
99
|
assert_done
|
75
100
|
expr.options = @options
|
101
|
+
check_for_interpolation expr
|
76
102
|
expr
|
77
103
|
rescue Sass::SyntaxError => e
|
78
104
|
e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
|
@@ -96,10 +122,26 @@ module Sass
|
|
96
122
|
end
|
97
123
|
assert_done
|
98
124
|
|
99
|
-
args.each
|
100
|
-
|
101
|
-
|
102
|
-
|
125
|
+
args.each do |a|
|
126
|
+
check_for_interpolation a
|
127
|
+
a.options = @options
|
128
|
+
end
|
129
|
+
|
130
|
+
keywords.each do |_k, v|
|
131
|
+
check_for_interpolation v
|
132
|
+
v.options = @options
|
133
|
+
end
|
134
|
+
|
135
|
+
if splat
|
136
|
+
check_for_interpolation splat
|
137
|
+
splat.options = @options
|
138
|
+
end
|
139
|
+
|
140
|
+
if kwarg_splat
|
141
|
+
check_for_interpolation kwarg_splat
|
142
|
+
kwarg_splat.options = @options
|
143
|
+
end
|
144
|
+
|
103
145
|
return args, keywords, splat, kwarg_splat
|
104
146
|
rescue Sass::SyntaxError => e
|
105
147
|
e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
|
@@ -116,10 +158,20 @@ module Sass
|
|
116
158
|
assert_done
|
117
159
|
|
118
160
|
args.each do |k, v|
|
161
|
+
check_for_interpolation k
|
119
162
|
k.options = @options
|
120
|
-
|
163
|
+
|
164
|
+
if v
|
165
|
+
check_for_interpolation v
|
166
|
+
v.options = @options
|
167
|
+
end
|
121
168
|
end
|
122
|
-
|
169
|
+
|
170
|
+
if splat
|
171
|
+
check_for_interpolation splat
|
172
|
+
splat.options = @options
|
173
|
+
end
|
174
|
+
|
123
175
|
return args, splat
|
124
176
|
rescue Sass::SyntaxError => e
|
125
177
|
e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
|
@@ -136,10 +188,20 @@ module Sass
|
|
136
188
|
assert_done
|
137
189
|
|
138
190
|
args.each do |k, v|
|
191
|
+
check_for_interpolation k
|
139
192
|
k.options = @options
|
140
|
-
|
193
|
+
|
194
|
+
if v
|
195
|
+
check_for_interpolation v
|
196
|
+
v.options = @options
|
197
|
+
end
|
141
198
|
end
|
142
|
-
|
199
|
+
|
200
|
+
if splat
|
201
|
+
check_for_interpolation splat
|
202
|
+
splat.options = @options
|
203
|
+
end
|
204
|
+
|
143
205
|
return args, splat
|
144
206
|
rescue Sass::SyntaxError => e
|
145
207
|
e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
|
@@ -159,6 +221,7 @@ module Sass
|
|
159
221
|
end
|
160
222
|
|
161
223
|
expr = assert_expr :funcall
|
224
|
+
check_for_interpolation expr
|
162
225
|
expr.options = @options
|
163
226
|
@lexer.unpeek!
|
164
227
|
expr
|
@@ -169,12 +232,12 @@ module Sass
|
|
169
232
|
|
170
233
|
# Parses a SassScript expression.
|
171
234
|
#
|
172
|
-
# @overload parse(str, line, offset, filename = nil)
|
173
235
|
# @return [Script::Tree::Node] The root node of the parse tree
|
174
236
|
# @see Parser#initialize
|
175
237
|
# @see Parser#parse
|
176
|
-
def self.parse(
|
177
|
-
|
238
|
+
def self.parse(value, line, offset, options = {})
|
239
|
+
css_variable = options.delete :css_variable
|
240
|
+
new(value, line, offset, options).parse(css_variable)
|
178
241
|
end
|
179
242
|
|
180
243
|
PRECEDENCE = [
|
@@ -187,6 +250,8 @@ module Sass
|
|
187
250
|
|
188
251
|
ASSOCIATIVE = [:plus, :times]
|
189
252
|
|
253
|
+
VALID_CSS_OPS = [:comma, :single_eq, :space, :div]
|
254
|
+
|
190
255
|
class << self
|
191
256
|
# Returns an integer representing the precedence
|
192
257
|
# of the given operator.
|
@@ -226,8 +291,12 @@ module Sass
|
|
226
291
|
return other_interp
|
227
292
|
end
|
228
293
|
|
229
|
-
|
230
|
-
|
294
|
+
if @css_variable_warning && !VALID_CSS_OPS.include?(tok.type)
|
295
|
+
@css_variable_warning.warn!
|
296
|
+
end
|
297
|
+
|
298
|
+
e = node(Tree::Operation.new(e, assert_expr(#{sub.inspect}), tok.type),
|
299
|
+
e.source_range.start_pos)
|
231
300
|
end
|
232
301
|
e
|
233
302
|
end
|
@@ -241,6 +310,8 @@ RUBY
|
|
241
310
|
interp = try_op_before_interp(tok)
|
242
311
|
return interp if interp
|
243
312
|
start_pos = source_position
|
313
|
+
|
314
|
+
@css_variable_warning.warn! if @css_variable_warning
|
244
315
|
node(Tree::UnaryOperation.new(assert_expr(:unary_#{op}), :#{op}), start_pos)
|
245
316
|
end
|
246
317
|
RUBY
|
@@ -267,6 +338,7 @@ RUBY
|
|
267
338
|
return list e, start_pos unless @lexer.peek && @lexer.peek.type == :colon
|
268
339
|
|
269
340
|
pair = map_pair(e)
|
341
|
+
@css_variable_warning.warn! if @css_variable_warning
|
270
342
|
map = node(Sass::Script::Tree::MapLiteral.new([pair]), start_pos)
|
271
343
|
while try_tok(:comma)
|
272
344
|
pair = map_pair
|
@@ -302,19 +374,32 @@ RUBY
|
|
302
374
|
end
|
303
375
|
return list unless (e = interpolation)
|
304
376
|
list.elements << e
|
377
|
+
list.source_range.end_pos = list.elements.last.source_range.end_pos
|
305
378
|
end
|
306
379
|
list
|
307
380
|
end
|
308
381
|
|
309
382
|
production :equals, :interpolation, :single_eq
|
310
383
|
|
311
|
-
def try_op_before_interp(op, prev = nil)
|
384
|
+
def try_op_before_interp(op, prev = nil, after_interp = false)
|
312
385
|
return unless @lexer.peek && @lexer.peek.type == :begin_interpolation
|
386
|
+
unary = !prev && !after_interp
|
313
387
|
wb = @lexer.whitespace?(op)
|
314
388
|
str = literal_node(Script::Value::String.new(Lexer::OPERATORS_REVERSE[op.type]),
|
315
389
|
op.source_range)
|
390
|
+
|
391
|
+
deprecation =
|
392
|
+
case op.type
|
393
|
+
when :comma; :potential
|
394
|
+
when :div, :single_eq; :none
|
395
|
+
when :plus; unary ? :none : :immediate
|
396
|
+
when :minus; @lexer.whitespace?(@lexer.peek) ? :immediate : :none
|
397
|
+
else; :immediate
|
398
|
+
end
|
399
|
+
|
316
400
|
interp = node(
|
317
|
-
Script::Tree::Interpolation.new(
|
401
|
+
Script::Tree::Interpolation.new(
|
402
|
+
prev, str, nil, wb, false, :originally_text => true, :deprecation => deprecation),
|
318
403
|
(prev || str).source_range.start_pos)
|
319
404
|
interpolation(interp)
|
320
405
|
end
|
@@ -323,15 +408,25 @@ RUBY
|
|
323
408
|
return unless @lexer.after_interpolation?
|
324
409
|
op = try_toks(*ops)
|
325
410
|
return unless op
|
326
|
-
interp = try_op_before_interp(op, prev)
|
411
|
+
interp = try_op_before_interp(op, prev, :after_interp)
|
327
412
|
return interp if interp
|
328
413
|
|
329
414
|
wa = @lexer.whitespace?
|
330
415
|
str = literal_node(Script::Value::String.new(Lexer::OPERATORS_REVERSE[op.type]),
|
331
416
|
op.source_range)
|
332
417
|
str.line = @lexer.line
|
418
|
+
|
419
|
+
deprecation =
|
420
|
+
case op.type
|
421
|
+
when :comma; :potential
|
422
|
+
when :div, :single_eq; :none
|
423
|
+
when :minus; @lexer.whitespace?(op) ? :immediate : :none
|
424
|
+
else; :immediate
|
425
|
+
end
|
333
426
|
interp = node(
|
334
|
-
Script::Tree::Interpolation.new(
|
427
|
+
Script::Tree::Interpolation.new(
|
428
|
+
prev, str, assert_expr(name), false, wa,
|
429
|
+
:originally_text => true, :deprecation => deprecation),
|
335
430
|
(prev || str).source_range.start_pos)
|
336
431
|
interp
|
337
432
|
end
|
@@ -340,15 +435,60 @@ RUBY
|
|
340
435
|
e = first
|
341
436
|
while (interp = try_tok(:begin_interpolation))
|
342
437
|
wb = @lexer.whitespace?(interp)
|
343
|
-
|
438
|
+
char_before = @lexer.char(interp.pos - 1)
|
439
|
+
mid = without_css_variable_warning {assert_expr :expr}
|
440
|
+
assert_tok :end_interpolation
|
344
441
|
wa = @lexer.whitespace?
|
442
|
+
char_after = @lexer.char
|
443
|
+
|
444
|
+
after = space
|
445
|
+
before_deprecation = e.is_a?(Script::Tree::Interpolation) ? e.deprecation : :none
|
446
|
+
after_deprecation = after.is_a?(Script::Tree::Interpolation) ? after.deprecation : :none
|
447
|
+
|
448
|
+
deprecation =
|
449
|
+
if before_deprecation == :immediate || after_deprecation == :immediate ||
|
450
|
+
# Warn for #{foo}$var and #{foo}(1) but not #{$foo}1.
|
451
|
+
(after && !wa && char_after =~ /[$(]/) ||
|
452
|
+
# Warn for $var#{foo} and (a)#{foo} but not a#{foo}.
|
453
|
+
(e && !wb && is_unsafe_before?(e, char_before))
|
454
|
+
:immediate
|
455
|
+
else
|
456
|
+
:potential
|
457
|
+
end
|
458
|
+
|
345
459
|
e = node(
|
346
|
-
Script::Tree::Interpolation.new(e, mid,
|
347
|
-
(e ||
|
460
|
+
Script::Tree::Interpolation.new(e, mid, after, wb, wa, :deprecation => deprecation),
|
461
|
+
(e || interp).source_range.start_pos)
|
348
462
|
end
|
349
463
|
e
|
350
464
|
end
|
351
465
|
|
466
|
+
# Returns whether `expr` is unsafe to include before an interpolation.
|
467
|
+
#
|
468
|
+
# @param expr [Node] The expression to check.
|
469
|
+
# @param char_before [String] The character immediately before the
|
470
|
+
# interpolation being checked (and presumably the last character of
|
471
|
+
# `expr`).
|
472
|
+
# @return [Boolean]
|
473
|
+
def is_unsafe_before?(expr, char_before)
|
474
|
+
return char_before == ')' if is_safe_value?(expr)
|
475
|
+
|
476
|
+
# Otherwise, it's only safe if it was another interpolation.
|
477
|
+
!expr.is_a?(Script::Tree::Interpolation)
|
478
|
+
end
|
479
|
+
|
480
|
+
# Returns whether `expr` is safe as the value immediately before an
|
481
|
+
# interpolation.
|
482
|
+
#
|
483
|
+
# It's safe as long as the previous expression is an identifier or number,
|
484
|
+
# or a list whose last element is also safe.
|
485
|
+
def is_safe_value?(expr)
|
486
|
+
return is_safe_value?(expr.elements.last) if expr.is_a?(Script::Tree::ListLiteral)
|
487
|
+
return false unless expr.is_a?(Script::Tree::Literal)
|
488
|
+
expr.value.is_a?(Script::Value::Number) ||
|
489
|
+
(expr.value.is_a?(Script::Value::String) && expr.value.type == :identifier)
|
490
|
+
end
|
491
|
+
|
352
492
|
def space
|
353
493
|
start_pos = source_position
|
354
494
|
e = or_expr
|
@@ -382,7 +522,7 @@ RUBY
|
|
382
522
|
|
383
523
|
name = @lexer.next
|
384
524
|
if (color = Sass::Script::Value::Color::COLOR_NAMES[name.value.downcase])
|
385
|
-
literal_node(Sass::Script::Value::Color.new(color), name.source_range)
|
525
|
+
literal_node(Sass::Script::Value::Color.new(color, name.value), name.source_range)
|
386
526
|
elsif name.value == "true"
|
387
527
|
literal_node(Sass::Script::Value::Bool.new(true), name.source_range)
|
388
528
|
elsif name.value == "false"
|
@@ -487,41 +627,36 @@ RUBY
|
|
487
627
|
end
|
488
628
|
|
489
629
|
def special_fun
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
l, i,
|
501
|
-
r && literal_node(Script::Value::String.new(r),
|
502
|
-
i.source_range.end_pos, end_pos),
|
503
|
-
false, false),
|
504
|
-
start_pos, end_pos)
|
505
|
-
end
|
630
|
+
first = try_tok(:special_fun)
|
631
|
+
return paren unless first
|
632
|
+
str = literal_node(first.value, first.source_range)
|
633
|
+
return str unless try_tok(:string_interpolation)
|
634
|
+
mid = without_css_variable_warning {assert_expr :expr}
|
635
|
+
assert_tok :end_interpolation
|
636
|
+
last = assert_expr(:special_fun)
|
637
|
+
node(
|
638
|
+
Tree::Interpolation.new(str, mid, last, false, false),
|
639
|
+
first.source_range.start_pos)
|
506
640
|
end
|
507
641
|
|
508
642
|
def paren
|
509
643
|
return variable unless try_tok(:lparen)
|
510
|
-
was_in_parens = @in_parens
|
511
|
-
@in_parens = true
|
512
644
|
start_pos = source_position
|
513
645
|
e = map
|
646
|
+
e.force_division! if e
|
514
647
|
end_pos = source_position
|
515
648
|
assert_tok(:rparen)
|
516
|
-
|
517
|
-
|
518
|
-
|
649
|
+
|
650
|
+
@css_variable_warning.warn! if @css_variable_warning
|
651
|
+
e || node(Sass::Script::Tree::ListLiteral.new([], nil), start_pos, end_pos)
|
519
652
|
end
|
520
653
|
|
521
654
|
def variable
|
522
655
|
start_pos = source_position
|
523
656
|
c = try_tok(:const)
|
524
657
|
return string unless c
|
658
|
+
|
659
|
+
@css_variable_warning.warn! if @css_variable_warning
|
525
660
|
node(Tree::Variable.new(*c.value), start_pos)
|
526
661
|
end
|
527
662
|
|
@@ -529,8 +664,9 @@ RUBY
|
|
529
664
|
first = try_tok(:string)
|
530
665
|
return number unless first
|
531
666
|
str = literal_node(first.value, first.source_range)
|
532
|
-
return str unless try_tok(:
|
533
|
-
mid =
|
667
|
+
return str unless try_tok(:string_interpolation)
|
668
|
+
mid = without_css_variable_warning {assert_expr :expr}
|
669
|
+
assert_tok :end_interpolation
|
534
670
|
last = assert_expr(:string)
|
535
671
|
node(Tree::StringInterpolation.new(str, mid, last), first.source_range.start_pos)
|
536
672
|
end
|
@@ -539,13 +675,15 @@ RUBY
|
|
539
675
|
tok = try_tok(:number)
|
540
676
|
return selector unless tok
|
541
677
|
num = tok.value
|
542
|
-
num.
|
678
|
+
num.options = @options
|
679
|
+
num.original = num.to_s
|
543
680
|
literal_node(num, tok.source_range.start_pos)
|
544
681
|
end
|
545
682
|
|
546
683
|
def selector
|
547
684
|
tok = try_tok(:selector)
|
548
685
|
return literal unless tok
|
686
|
+
@css_variable_warning.warn! if @css_variable_warning
|
549
687
|
node(tok.value, tok.source_range.start_pos)
|
550
688
|
end
|
551
689
|
|
@@ -563,6 +701,7 @@ RUBY
|
|
563
701
|
:mixin_arglist => "mixin argument",
|
564
702
|
:fn_arglist => "function argument",
|
565
703
|
:splat => "...",
|
704
|
+
:special_fun => '")"',
|
566
705
|
}
|
567
706
|
|
568
707
|
def assert_expr(name, expected = nil)
|
@@ -596,8 +735,14 @@ RUBY
|
|
596
735
|
end
|
597
736
|
|
598
737
|
def assert_done
|
599
|
-
|
600
|
-
|
738
|
+
if @allow_extra_text
|
739
|
+
# If extra text is allowed, just rewind the lexer so that the
|
740
|
+
# StringScanner is pointing to the end of the parsed text.
|
741
|
+
@lexer.unpeek!
|
742
|
+
else
|
743
|
+
return if @lexer.done?
|
744
|
+
@lexer.expected!(EXPR_NAMES[:default])
|
745
|
+
end
|
601
746
|
end
|
602
747
|
|
603
748
|
# @overload node(value, source_range)
|
@@ -626,11 +771,62 @@ RUBY
|
|
626
771
|
range(source_range_or_start_pos, end_pos)
|
627
772
|
end
|
628
773
|
|
774
|
+
node.css_variable_warning = @css_variable_warning
|
629
775
|
node.line = source_range.start_pos.line
|
630
776
|
node.source_range = source_range
|
631
777
|
node.filename = @options[:filename]
|
632
778
|
node
|
633
779
|
end
|
780
|
+
|
781
|
+
# Runs the given block without CSS variable warnings enabled.
|
782
|
+
#
|
783
|
+
# CSS warnings don't apply within interpolation, so this is used to
|
784
|
+
# disable them.
|
785
|
+
#
|
786
|
+
# @yield []
|
787
|
+
def without_css_variable_warning
|
788
|
+
old_css_variable_warning = @css_variable_warning
|
789
|
+
@css_variable_warning = nil
|
790
|
+
yield
|
791
|
+
ensure
|
792
|
+
@css_variable_warning = old_css_variable_warning
|
793
|
+
end
|
794
|
+
|
795
|
+
# Checks a script node for any immediately-deprecated interpolations, and
|
796
|
+
# emits warnings for them.
|
797
|
+
#
|
798
|
+
# @param node [Sass::Script::Tree::Node]
|
799
|
+
def check_for_interpolation(node)
|
800
|
+
nodes = [node]
|
801
|
+
until nodes.empty?
|
802
|
+
node = nodes.pop
|
803
|
+
unless node.is_a?(Sass::Script::Tree::Interpolation) &&
|
804
|
+
node.deprecation == :immediate
|
805
|
+
nodes.concat node.children
|
806
|
+
next
|
807
|
+
end
|
808
|
+
|
809
|
+
interpolation_deprecation(node)
|
810
|
+
end
|
811
|
+
end
|
812
|
+
|
813
|
+
# Emits a deprecation warning for an interpolation node.
|
814
|
+
#
|
815
|
+
# @param node [Sass::Script::Tree::Node]
|
816
|
+
def interpolation_deprecation(interpolation)
|
817
|
+
return if @options[:_convert]
|
818
|
+
location = "on line #{interpolation.line}"
|
819
|
+
location << " of #{interpolation.filename}" if interpolation.filename
|
820
|
+
Sass::Util.sass_warn <<WARNING
|
821
|
+
DEPRECATION WARNING #{location}:
|
822
|
+
\#{} interpolation near operators will be simplified in a future version of Sass.
|
823
|
+
To preserve the current behavior, use quotes:
|
824
|
+
|
825
|
+
#{interpolation.to_quoted_equivalent.to_sass}
|
826
|
+
|
827
|
+
You can use the sass-convert command to automatically fix most cases.
|
828
|
+
WARNING
|
829
|
+
end
|
634
830
|
end
|
635
831
|
end
|
636
832
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'sass/script/functions'
|
2
|
-
require 'sass/util
|
2
|
+
require 'sass/util'
|
3
3
|
|
4
4
|
module Sass::Script::Tree
|
5
5
|
# A SassScript parse node representing a function call.
|
@@ -128,12 +128,15 @@ module Sass::Script::Tree
|
|
128
128
|
splat = Sass::Tree::Visitors::Perform.perform_splat(
|
129
129
|
@splat, keywords, @kwarg_splat, environment)
|
130
130
|
if (fn = environment.function(@name))
|
131
|
+
css_variable_warning.warn! if css_variable_warning
|
131
132
|
return without_original(perform_sass_fn(fn, args, splat, environment))
|
132
133
|
end
|
133
134
|
|
134
135
|
args = construct_ruby_args(ruby_name, args, splat, environment)
|
135
136
|
|
136
137
|
if Sass::Script::Functions.callable?(ruby_name)
|
138
|
+
css_variable_warning.warn! if css_variable_warning
|
139
|
+
|
137
140
|
local_environment = Sass::Environment.new(environment.global_env, environment.options)
|
138
141
|
local_environment.caller = Sass::ReadOnlyEnvironment.new(environment, environment.options)
|
139
142
|
result = opts(Sass::Script::Functions::EvaluationContext.new(
|
@@ -208,13 +211,13 @@ module Sass::Script::Tree
|
|
208
211
|
|
209
212
|
argnames = signature.args[args.size..-1] || []
|
210
213
|
deprecated_argnames = (signature.deprecated && signature.deprecated[args.size..-1]) || []
|
211
|
-
args
|
214
|
+
args += argnames.zip(deprecated_argnames).map do |(argname, deprecated_argname)|
|
212
215
|
if keywords.has_key?(argname)
|
213
216
|
keywords.delete(argname)
|
214
217
|
elsif deprecated_argname && keywords.has_key?(deprecated_argname)
|
215
218
|
deprecated_argname = keywords.denormalize(deprecated_argname)
|
216
219
|
Sass::Util.sass_warn("DEPRECATION WARNING: The `$#{deprecated_argname}' argument for " +
|
217
|
-
"`#{name}()' has been renamed to `$#{argname}'.")
|
220
|
+
"`#{@name}()' has been renamed to `$#{argname}'.")
|
218
221
|
keywords.delete(deprecated_argname)
|
219
222
|
else
|
220
223
|
raise Sass::SyntaxError.new("Function #{name} requires an argument named $#{argname}")
|
@@ -241,7 +244,7 @@ module Sass::Script::Tree
|
|
241
244
|
end
|
242
245
|
|
243
246
|
def perform_sass_fn(function, args, splat, environment)
|
244
|
-
Sass::Tree::Visitors::Perform.perform_arguments(function, args, splat) do |env|
|
247
|
+
Sass::Tree::Visitors::Perform.perform_arguments(function, args, splat, environment) do |env|
|
245
248
|
env.caller = Sass::Environment.new(environment)
|
246
249
|
|
247
250
|
val = catch :_sass_return do
|
@@ -296,8 +299,12 @@ module Sass::Script::Tree
|
|
296
299
|
message = "wrong number of arguments (#{given} for #{expected})"
|
297
300
|
end
|
298
301
|
end
|
299
|
-
elsif
|
300
|
-
|
302
|
+
elsif (md = /^wrong number of arguments \(given (\d+), expected (\d+)\)/.match(e.message)) &&
|
303
|
+
e.backtrace[0] =~ /:in `#{ruby_name}'$/
|
304
|
+
# Handle ruby 2.3 error formatting
|
305
|
+
message = "wrong number of arguments (#{md[1]} for #{md[2]})"
|
306
|
+
elsif e.message =~ /^wrong number of arguments/ &&
|
307
|
+
e.backtrace[0] !~ /:in `(block in )?#{ruby_name}'$/
|
301
308
|
raise e
|
302
309
|
end
|
303
310
|
raise Sass::SyntaxError.new("#{message} for `#{name}'")
|