sass 3.4.21 → 3.4.22

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +122 -0
  3. data/MIT-LICENSE +1 -1
  4. data/README.md +15 -9
  5. data/Rakefile +71 -18
  6. data/VERSION +1 -1
  7. data/VERSION_DATE +1 -1
  8. data/lib/sass.rb +7 -0
  9. data/lib/sass/callbacks.rb +2 -2
  10. data/lib/sass/css.rb +9 -8
  11. data/lib/sass/engine.rb +14 -8
  12. data/lib/sass/environment.rb +8 -1
  13. data/lib/sass/error.rb +5 -5
  14. data/lib/sass/exec/sass_convert.rb +14 -2
  15. data/lib/sass/exec/sass_scss.rb +2 -25
  16. data/lib/sass/features.rb +2 -2
  17. data/lib/sass/importers/filesystem.rb +6 -3
  18. data/lib/sass/plugin/compiler.rb +15 -7
  19. data/lib/sass/script/css_variable_warning.rb +52 -0
  20. data/lib/sass/script/functions.rb +5 -5
  21. data/lib/sass/script/lexer.rb +3 -1
  22. data/lib/sass/script/parser.rb +67 -15
  23. data/lib/sass/script/tree/funcall.rb +10 -3
  24. data/lib/sass/script/tree/node.rb +8 -0
  25. data/lib/sass/script/tree/operation.rb +7 -0
  26. data/lib/sass/script/value/base.rb +1 -0
  27. data/lib/sass/script/value/color.rb +6 -4
  28. data/lib/sass/script/value/helpers.rb +2 -2
  29. data/lib/sass/script/value/number.rb +5 -5
  30. data/lib/sass/scss.rb +0 -2
  31. data/lib/sass/scss/css_parser.rb +1 -2
  32. data/lib/sass/scss/parser.rb +20 -10
  33. data/lib/sass/scss/rx.rb +2 -2
  34. data/lib/sass/scss/static_parser.rb +11 -13
  35. data/lib/sass/selector/pseudo.rb +1 -1
  36. data/lib/sass/selector/sequence.rb +2 -2
  37. data/lib/sass/selector/simple_sequence.rb +4 -4
  38. data/lib/sass/stack.rb +2 -2
  39. data/lib/sass/tree/function_node.rb +1 -1
  40. data/lib/sass/tree/node.rb +2 -0
  41. data/lib/sass/tree/visitors/check_nesting.rb +2 -0
  42. data/lib/sass/tree/visitors/convert.rb +8 -7
  43. data/lib/sass/tree/visitors/perform.rb +4 -2
  44. data/lib/sass/tree/visitors/to_css.rb +10 -10
  45. data/lib/sass/util.rb +8 -7
  46. data/test/sass-spec.yml +3 -0
  47. data/test/sass/compiler_test.rb +1 -1
  48. data/test/sass/css_variable_test.rb +132 -0
  49. data/test/sass/exec_test.rb +10 -0
  50. data/test/sass/script_test.rb +1 -1
  51. data/test/sass/scss/scss_test.rb +10 -0
  52. metadata +79 -77
  53. data/lib/sass/scss/script_lexer.rb +0 -15
  54. data/lib/sass/scss/script_parser.rb +0 -25
@@ -157,6 +157,10 @@ END
157
157
  @options[:for_engine][:read_cache] = false
158
158
  end
159
159
 
160
+ opts.on('-q', '--quiet', 'Silence warnings and status messages during conversion.') do |bool|
161
+ @options[:for_engine][:quiet] = bool
162
+ end
163
+
160
164
  opts.on('--trace', :NONE, 'Show a full Ruby stack trace on error') do
161
165
  @options[:trace] = true
162
166
  end
@@ -243,12 +247,12 @@ END
243
247
  Sass::Util.silence_sass_warnings do
244
248
  if @options[:from] == :css
245
249
  require 'sass/css'
246
- Sass::CSS.new(input.read, @options[:for_tree]).render(@options[:to])
250
+ Sass::CSS.new(read(input), @options[:for_tree]).render(@options[:to])
247
251
  else
248
252
  if input_path
249
253
  Sass::Engine.for_file(input_path, @options[:for_engine])
250
254
  else
251
- Sass::Engine.new(input.read, @options[:for_engine])
255
+ Sass::Engine.new(read(input), @options[:for_engine])
252
256
  end.to_tree.send("to_#{@options[:to]}", @options[:for_tree])
253
257
  end
254
258
  end
@@ -267,5 +271,13 @@ END
267
271
  return file.path if file.is_a?(File)
268
272
  return file if file.is_a?(String)
269
273
  end
274
+
275
+ def read(file)
276
+ if file.respond_to?(:read)
277
+ file.read
278
+ else
279
+ open(file, 'rb') {|f| f.read}
280
+ end
281
+ end
270
282
  end
271
283
  end
@@ -156,7 +156,7 @@ END
156
156
  ' file: always absolute file URIs',
157
157
  ' inline: include the source text in the sourcemap',
158
158
  ' none: no sourcemaps') do |type|
159
- if type && !%w[auto file inline none].include?(type)
159
+ if type && !%w(auto file inline none).include?(type)
160
160
  $stderr.puts "Unknown sourcemap type #{type}.\n\n"
161
161
  $stderr.puts opts
162
162
  exit
@@ -290,29 +290,6 @@ File #{@args[1]} #{err}.
290
290
  MSG
291
291
  end
292
292
 
293
- # Watch the working directory for changes without adding it to the load
294
- # path. This preserves the pre-3.4 behavior when the working directory was
295
- # on the load path. We should remove this when we can look for directories
296
- # to watch by traversing the import graph.
297
- class << Sass::Plugin.compiler
298
- # We have to use a class var to make this visible to #watched_file? and
299
- # #watched_paths.
300
- # rubocop:disable ClassVars
301
- @@working_directory = Sass::Util.realpath('.').to_s
302
- # rubocop:enable ClassVars
303
-
304
- # rubocop:disable NestedMethodDefinition
305
- def watched_file?(file)
306
- super(file) ||
307
- (file =~ /\.s[ac]ss$/ && file.start_with?(@@working_directory + File::SEPARATOR))
308
- end
309
-
310
- def watched_paths
311
- @watched_paths ||= super + [@@working_directory]
312
- end
313
- # rubocop:enable NestedMethodDefinition
314
- end
315
-
316
293
  dirs, files = @args.map {|name| split_colon_path(name)}.
317
294
  partition {|i, _| File.directory? i}
318
295
 
@@ -436,7 +413,7 @@ WARNING
436
413
  def split_colon_path(path)
437
414
  one, two = path.split(':', 2)
438
415
  if one && two && Sass::Util.windows? &&
439
- one =~ /\A[A-Za-z]\Z/ && two =~ /\A[\/\\]/
416
+ one =~ /\A[A-Za-z]\Z/ && two =~ %r{\A[/\\]}
440
417
  # If we're on Windows and we were passed a drive letter path,
441
418
  # don't split on that colon.
442
419
  one2, two = two.split(':', 2)
@@ -7,12 +7,12 @@ module Sass
7
7
  #
8
8
  # When this is updated, the documentation of `feature-exists()` should be
9
9
  # updated as well.
10
- KNOWN_FEATURES = Set[*%w{
10
+ KNOWN_FEATURES = Set[*%w(
11
11
  global-variable-shadowing
12
12
  extend-selector-pseudoclass
13
13
  units-level-3
14
14
  at-error
15
- }]
15
+ )]
16
16
 
17
17
  # Check if a feature exists by name. This is used to implement
18
18
  # the Sass function `feature-exists($feature)`
@@ -122,7 +122,7 @@ module Sass
122
122
  end
123
123
 
124
124
  # JRuby chokes when trying to import files from JARs when the path starts with './'.
125
- ret.map {|f, s| [f.sub(/^\.\//, ''), s]}
125
+ ret.map {|f, s| [f.sub(%r{^\./}, ''), s]}
126
126
  end
127
127
 
128
128
  def escape_glob_characters(name)
@@ -144,8 +144,11 @@ module Sass
144
144
  name = name.gsub(File::ALT_SEPARATOR, File::SEPARATOR) unless File::ALT_SEPARATOR.nil?
145
145
 
146
146
  found = possible_files(remove_root(name)).map do |f, s|
147
- path = (dir == "." || Sass::Util.pathname(f).absolute?) ? f :
148
- "#{escape_glob_characters(dir)}/#{f}"
147
+ path = if dir == "." || Sass::Util.pathname(f).absolute?
148
+ f
149
+ else
150
+ "#{escape_glob_characters(dir)}/#{f}"
151
+ end
149
152
  Dir[path].map do |full_path|
150
153
  full_path.gsub!(REDUNDANT_DIRECTORY, File::SEPARATOR)
151
154
  [Sass::Util.cleanpath(full_path).to_s, s]
@@ -289,6 +289,7 @@ module Sass::Plugin
289
289
  # @option options [Boolean] :skip_initial_update
290
290
  # Don't do an initial update when starting the watcher when true
291
291
  def watch(individual_files = [], options = {})
292
+ @inferred_directories = []
292
293
  options, individual_files = individual_files, [] if individual_files.is_a?(Hash)
293
294
  update_stylesheets(individual_files) unless options[:skip_initial_update]
294
295
 
@@ -296,8 +297,10 @@ module Sass::Plugin
296
297
  individual_files.each do |(source, _, _)|
297
298
  source = File.expand_path(source)
298
299
  @watched_files << Sass::Util.realpath(source).to_s
299
- directories << File.dirname(source)
300
+ @inferred_directories << File.dirname(source)
300
301
  end
302
+
303
+ directories += @inferred_directories
301
304
  directories = remove_redundant_directories(directories)
302
305
 
303
306
  # A Listen version prior to 2.0 will write a test file to a directory to
@@ -454,11 +457,10 @@ module Sass::Plugin
454
457
  # And try to remove the css file that corresponds to it
455
458
  template_location_array.each do |(sass_dir, css_dir)|
456
459
  sass_dir = File.expand_path(sass_dir)
457
- if child_of_directory?(sass_dir, f)
458
- remainder = f[(sass_dir.size + 1)..-1]
459
- try_delete_css(css_filename(remainder, css_dir))
460
- break
461
- end
460
+ next unless child_of_directory?(sass_dir, f)
461
+ remainder = f[(sass_dir.size + 1)..-1]
462
+ try_delete_css(css_filename(remainder, css_dir))
463
+ break
462
464
  end
463
465
  end
464
466
  end
@@ -531,7 +533,13 @@ module Sass::Plugin
531
533
  end
532
534
 
533
535
  def watched_file?(file)
534
- @watched_files.include?(file) || normalized_load_paths.any? {|lp| lp.watched_file?(file)}
536
+ @watched_files.include?(file) ||
537
+ normalized_load_paths.any? {|lp| lp.watched_file?(file)} ||
538
+ @inferred_directories.any? {|d| sass_file_in_directory?(d, file)}
539
+ end
540
+
541
+ def sass_file_in_directory?(directory, filename)
542
+ filename =~ /\.s[ac]ss$/ && filename.start_with?(directory + File::SEPARATOR)
535
543
  end
536
544
 
537
545
  def watched_paths
@@ -0,0 +1,52 @@
1
+ module Sass
2
+ module Script
3
+ # An object tracking whether a warning has been emitted for a given script
4
+ # tree.
5
+ #
6
+ # This is shared among all objects in a script tree. Whenever any of those
7
+ # objects encounters a situation in which it wouldn't produce semantically
8
+ # identical CSS to its input, it calls \{#warn!\}. The first time \{#warn!}
9
+ # is called for a given warning object, it prints a deprecation warning.
10
+ class CssVariableWarning
11
+ def initialize
12
+ @warned = false
13
+ @value = nil
14
+ end
15
+
16
+ # Sets the root of the script tree that this warning refers to.
17
+ #
18
+ # @param value [Sass::Script::Tree::Node]
19
+ def value=(value)
20
+ warn_called = @warned && !@value
21
+ @value = value
22
+ print_warning if warn_called
23
+ end
24
+
25
+ # The first time this is called, it prints a deprecation warning.
26
+ #
27
+ # This may be called before \{#value=}. If it is, the warning is emitted
28
+ # once the script tree is set.
29
+ def warn!
30
+ return if @warned
31
+ @warned = true
32
+ return unless @value
33
+
34
+ print_warning
35
+ end
36
+
37
+ private
38
+
39
+ # Prints this node's warning.
40
+ def print_warning
41
+ of_filename = " of #{@value.filename}" if @value.filename
42
+ Sass::Util.sass_warn(
43
+ "DEPRECATION WARNING on line #{@value.line}#{of_filename}:\n" +
44
+ "Sass 3.6 will change the way CSS variables are parsed. Instead of being parsed as\n" +
45
+ "normal properties, they will not allow any Sass-specific behavior other than \#{}.\n" +
46
+ "For forwards-compatibility, use \#{}:\n" +
47
+ "\n" +
48
+ " --variable: \#{#{@value.to_sass}};")
49
+ end
50
+ end
51
+ end
52
+ end
@@ -901,7 +901,7 @@ module Sass::Script
901
901
  a.value =~ /^[a-zA-Z]+\s*=/
902
902
  end
903
903
  # Support the proprietary MS alpha() function
904
- return identifier("alpha(#{args.map {|a| a.to_s}.join(", ")})")
904
+ return identifier("alpha(#{args.map {|a| a.to_s}.join(', ')})")
905
905
  end
906
906
 
907
907
  raise ArgumentError.new("wrong number of arguments (#{args.size} for 1)") if args.size != 1
@@ -1913,7 +1913,7 @@ MESSAGE
1913
1913
  # @return [Sass::Script::Value::List]
1914
1914
  def join(list1, list2, separator = identifier("auto"))
1915
1915
  assert_type separator, :String, :separator
1916
- unless %w[auto space comma].include?(separator.value)
1916
+ unless %w(auto space comma).include?(separator.value)
1917
1917
  raise ArgumentError.new("Separator name must be space, comma, or auto")
1918
1918
  end
1919
1919
  sep = if separator.value == 'auto'
@@ -1949,7 +1949,7 @@ MESSAGE
1949
1949
  # @return [Sass::Script::Value::List]
1950
1950
  def append(list, val, separator = identifier("auto"))
1951
1951
  assert_type separator, :String, :separator
1952
- unless %w[auto space comma].include?(separator.value)
1952
+ unless %w(auto space comma).include?(separator.value)
1953
1953
  raise ArgumentError.new("Separator name must be space, comma, or auto")
1954
1954
  end
1955
1955
  sep = if separator.value == 'auto'
@@ -2419,7 +2419,7 @@ MESSAGE
2419
2419
  end
2420
2420
 
2421
2421
  parsed = [parse_selector(selectors.first, :selectors)]
2422
- parsed += selectors[1..-1].map {|sel| parse_selector(sel, :selectors, !!:parse_parent_ref)}
2422
+ parsed += selectors[1..-1].map {|sel| parse_selector(sel, :selectors, true)}
2423
2423
  parsed.inject {|result, child| child.resolve_parent_refs(result)}.to_sass_script
2424
2424
  end
2425
2425
  declare :selector_nest, [], :var_args => true
@@ -2551,7 +2551,7 @@ MESSAGE
2551
2551
  extends = Sass::Util::SubsetMap.new
2552
2552
  begin
2553
2553
  replacement.populate_extends(extends, original)
2554
- selector.do_extend(extends, [], !!:replace).to_sass_script
2554
+ selector.do_extend(extends, [], true).to_sass_script
2555
2555
  rescue Sass::SyntaxError => e
2556
2556
  raise ArgumentError.new(e.to_s)
2557
2557
  end
@@ -155,6 +155,8 @@ module Sass
155
155
  @options = options
156
156
  @interpolation_stack = []
157
157
  @prev = nil
158
+ @tok = nil
159
+ @next_tok = nil
158
160
  end
159
161
 
160
162
  # Moves the lexer forward one token.
@@ -417,7 +419,7 @@ MESSAGE
417
419
  end
418
420
 
419
421
  def special_val
420
- return unless scan(/!important/i)
422
+ return unless scan(/!#{W}important/i)
421
423
  [:string, Script::Value::String.new("!important")]
422
424
  end
423
425
 
@@ -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
@@ -24,11 +25,17 @@ module Sass
24
25
  # Used for error reporting and sourcemap building
25
26
  # @param offset [Fixnum] 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
- # see {file:SASS_REFERENCE.md#sass_options the Sass options documentation}
28
+ # @param options [{Symbol => Object}] An options hash; see
29
+ # {file:SASS_REFERENCE.md#sass_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 (`#{}`).
@@ -46,7 +53,7 @@ module Sass
46
53
  expr = assert_expr :expr
47
54
  assert_tok :end_interpolation
48
55
  expr = Sass::Script::Tree::Interpolation.new(
49
- nil, expr, nil, !:wb, !:wa, :warn_for_color => warn_for_color)
56
+ nil, expr, nil, false, false, :warn_for_color => warn_for_color)
50
57
  check_for_interpolation expr
51
58
  expr.options = @options
52
59
  node(expr, start_pos)
@@ -57,13 +64,23 @@ module Sass
57
64
 
58
65
  # Parses a SassScript expression.
59
66
  #
67
+ # @param css_variable [Boolean] Whether this is the value of a CSS variable.
60
68
  # @return [Script::Tree::Node] The root node of the parse tree
61
69
  # @raise [Sass::SyntaxError] if the expression isn't valid SassScript
62
- def parse
70
+ def parse(css_variable = false)
71
+ if css_variable
72
+ @css_variable_warning = CssVariableWarning.new
73
+ end
74
+
63
75
  expr = assert_expr :expr
64
76
  assert_done
65
77
  expr.options = @options
66
78
  check_for_interpolation expr
79
+
80
+ if css_variable
81
+ @css_variable_warning.value = expr
82
+ end
83
+
67
84
  expr
68
85
  rescue Sass::SyntaxError => e
69
86
  e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
@@ -215,12 +232,12 @@ module Sass
215
232
 
216
233
  # Parses a SassScript expression.
217
234
  #
218
- # @overload parse(str, line, offset, filename = nil)
219
235
  # @return [Script::Tree::Node] The root node of the parse tree
220
236
  # @see Parser#initialize
221
237
  # @see Parser#parse
222
- def self.parse(*args)
223
- new(*args).parse
238
+ def self.parse(value, line, offset, options = {})
239
+ css_variable = options.delete :css_variable
240
+ new(value, line, offset, options).parse(css_variable)
224
241
  end
225
242
 
226
243
  PRECEDENCE = [
@@ -233,6 +250,8 @@ module Sass
233
250
 
234
251
  ASSOCIATIVE = [:plus, :times]
235
252
 
253
+ VALID_CSS_OPS = [:comma, :single_eq, :space, :div]
254
+
236
255
  class << self
237
256
  # Returns an integer representing the precedence
238
257
  # of the given operator.
@@ -272,6 +291,10 @@ module Sass
272
291
  return other_interp
273
292
  end
274
293
 
294
+ if @css_variable_warning && !VALID_CSS_OPS.include?(tok.type)
295
+ @css_variable_warning.warn!
296
+ end
297
+
275
298
  e = node(Tree::Operation.new(e, assert_expr(#{sub.inspect}), tok.type),
276
299
  e.source_range.start_pos)
277
300
  end
@@ -287,6 +310,8 @@ RUBY
287
310
  interp = try_op_before_interp(tok)
288
311
  return interp if interp
289
312
  start_pos = source_position
313
+
314
+ @css_variable_warning.warn! if @css_variable_warning
290
315
  node(Tree::UnaryOperation.new(assert_expr(:unary_#{op}), :#{op}), start_pos)
291
316
  end
292
317
  RUBY
@@ -313,6 +338,7 @@ RUBY
313
338
  return list e, start_pos unless @lexer.peek && @lexer.peek.type == :colon
314
339
 
315
340
  pair = map_pair(e)
341
+ @css_variable_warning.warn! if @css_variable_warning
316
342
  map = node(Sass::Script::Tree::MapLiteral.new([pair]), start_pos)
317
343
  while try_tok(:comma)
318
344
  pair = map_pair
@@ -373,7 +399,7 @@ RUBY
373
399
 
374
400
  interp = node(
375
401
  Script::Tree::Interpolation.new(
376
- prev, str, nil, wb, !:wa, :originally_text => true, :deprecation => deprecation),
402
+ prev, str, nil, wb, false, :originally_text => true, :deprecation => deprecation),
377
403
  (prev || str).source_range.start_pos)
378
404
  interpolation(interp)
379
405
  end
@@ -399,7 +425,7 @@ RUBY
399
425
  end
400
426
  interp = node(
401
427
  Script::Tree::Interpolation.new(
402
- prev, str, assert_expr(name), !:wb, wa,
428
+ prev, str, assert_expr(name), false, wa,
403
429
  :originally_text => true, :deprecation => deprecation),
404
430
  (prev || str).source_range.start_pos)
405
431
  interp
@@ -410,7 +436,7 @@ RUBY
410
436
  while (interp = try_tok(:begin_interpolation))
411
437
  wb = @lexer.whitespace?(interp)
412
438
  char_before = @lexer.char(interp.pos - 1)
413
- mid = assert_expr :expr
439
+ mid = without_css_variable_warning {assert_expr :expr}
414
440
  assert_tok :end_interpolation
415
441
  wa = @lexer.whitespace?
416
442
  char_after = @lexer.char
@@ -599,11 +625,11 @@ RUBY
599
625
  return paren unless first
600
626
  str = literal_node(first.value, first.source_range)
601
627
  return str unless try_tok(:string_interpolation)
602
- mid = assert_expr :expr
628
+ mid = without_css_variable_warning {assert_expr :expr}
603
629
  assert_tok :end_interpolation
604
630
  last = assert_expr(:special_fun)
605
631
  node(
606
- Tree::Interpolation.new(str, mid, last, !:wb, !:wa),
632
+ Tree::Interpolation.new(str, mid, last, false, false),
607
633
  first.source_range.start_pos)
608
634
  end
609
635
 
@@ -614,6 +640,8 @@ RUBY
614
640
  e.force_division! if e
615
641
  end_pos = source_position
616
642
  assert_tok(:rparen)
643
+
644
+ @css_variable_warning.warn! if @css_variable_warning
617
645
  e || node(Sass::Script::Tree::ListLiteral.new([], nil), start_pos, end_pos)
618
646
  end
619
647
 
@@ -621,6 +649,8 @@ RUBY
621
649
  start_pos = source_position
622
650
  c = try_tok(:const)
623
651
  return string unless c
652
+
653
+ @css_variable_warning.warn! if @css_variable_warning
624
654
  node(Tree::Variable.new(*c.value), start_pos)
625
655
  end
626
656
 
@@ -629,7 +659,7 @@ RUBY
629
659
  return number unless first
630
660
  str = literal_node(first.value, first.source_range)
631
661
  return str unless try_tok(:string_interpolation)
632
- mid = assert_expr :expr
662
+ mid = without_css_variable_warning {assert_expr :expr}
633
663
  assert_tok :end_interpolation
634
664
  last = assert_expr(:string)
635
665
  node(Tree::StringInterpolation.new(str, mid, last), first.source_range.start_pos)
@@ -647,6 +677,7 @@ RUBY
647
677
  def selector
648
678
  tok = try_tok(:selector)
649
679
  return literal unless tok
680
+ @css_variable_warning.warn! if @css_variable_warning
650
681
  node(tok.value, tok.source_range.start_pos)
651
682
  end
652
683
 
@@ -698,8 +729,14 @@ RUBY
698
729
  end
699
730
 
700
731
  def assert_done
701
- return if @lexer.done?
702
- @lexer.expected!(EXPR_NAMES[:default])
732
+ if @allow_extra_text
733
+ # If extra text is allowed, just rewind the lexer so that the
734
+ # StringScanner is pointing to the end of the parsed text.
735
+ @lexer.unpeek!
736
+ else
737
+ return if @lexer.done?
738
+ @lexer.expected!(EXPR_NAMES[:default])
739
+ end
703
740
  end
704
741
 
705
742
  # @overload node(value, source_range)
@@ -728,12 +765,27 @@ RUBY
728
765
  range(source_range_or_start_pos, end_pos)
729
766
  end
730
767
 
768
+ node.css_variable_warning = @css_variable_warning
731
769
  node.line = source_range.start_pos.line
732
770
  node.source_range = source_range
733
771
  node.filename = @options[:filename]
734
772
  node
735
773
  end
736
774
 
775
+ # Runs the given block without CSS variable warnings enabled.
776
+ #
777
+ # CSS warnings don't apply within interpolation, so this is used to
778
+ # disable them.
779
+ #
780
+ # @yield []
781
+ def without_css_variable_warning
782
+ old_css_variable_warning = @css_variable_warning
783
+ @css_variable_warning = nil
784
+ yield
785
+ ensure
786
+ @css_variable_warning = old_css_variable_warning
787
+ end
788
+
737
789
  # Checks a script node for any immediately-deprecated interpolations, and
738
790
  # emits warnings for them.
739
791
  #