sass 3.4.21 → 3.4.22

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.
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
  #