oreorenasass 3.4.4 → 3.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +50 -70
  4. data/Rakefile +5 -26
  5. data/VERSION +1 -1
  6. data/VERSION_NAME +1 -1
  7. data/bin/sass +1 -1
  8. data/bin/scss +1 -1
  9. data/lib/sass.rb +12 -19
  10. data/lib/sass/cache_stores/base.rb +2 -2
  11. data/lib/sass/cache_stores/chain.rb +1 -2
  12. data/lib/sass/cache_stores/filesystem.rb +5 -1
  13. data/lib/sass/cache_stores/memory.rb +1 -1
  14. data/lib/sass/cache_stores/null.rb +2 -2
  15. data/lib/sass/callbacks.rb +0 -1
  16. data/lib/sass/css.rb +13 -11
  17. data/lib/sass/engine.rb +173 -424
  18. data/lib/sass/environment.rb +58 -148
  19. data/lib/sass/error.rb +14 -11
  20. data/lib/sass/exec.rb +703 -5
  21. data/lib/sass/importers/base.rb +6 -49
  22. data/lib/sass/importers/filesystem.rb +19 -44
  23. data/lib/sass/logger.rb +4 -1
  24. data/lib/sass/logger/base.rb +4 -2
  25. data/lib/sass/logger/log_level.rb +7 -3
  26. data/lib/sass/media.rb +23 -20
  27. data/lib/sass/plugin.rb +7 -7
  28. data/lib/sass/plugin/compiler.rb +145 -304
  29. data/lib/sass/plugin/configuration.rb +23 -18
  30. data/lib/sass/plugin/merb.rb +1 -1
  31. data/lib/sass/plugin/staleness_checker.rb +3 -3
  32. data/lib/sass/repl.rb +3 -3
  33. data/lib/sass/script.rb +8 -35
  34. data/lib/sass/script/{value/arg_list.rb → arg_list.rb} +25 -9
  35. data/lib/sass/script/bool.rb +18 -0
  36. data/lib/sass/script/color.rb +606 -0
  37. data/lib/sass/script/css_lexer.rb +4 -8
  38. data/lib/sass/script/css_parser.rb +2 -5
  39. data/lib/sass/script/funcall.rb +245 -0
  40. data/lib/sass/script/functions.rb +408 -1491
  41. data/lib/sass/script/interpolation.rb +79 -0
  42. data/lib/sass/script/lexer.rb +68 -172
  43. data/lib/sass/script/list.rb +85 -0
  44. data/lib/sass/script/literal.rb +221 -0
  45. data/lib/sass/script/{tree/node.rb → node.rb} +12 -22
  46. data/lib/sass/script/{value/null.rb → null.rb} +7 -14
  47. data/lib/sass/script/{value/number.rb → number.rb} +75 -152
  48. data/lib/sass/script/{tree/operation.rb → operation.rb} +24 -17
  49. data/lib/sass/script/parser.rb +110 -245
  50. data/lib/sass/script/string.rb +51 -0
  51. data/lib/sass/script/{tree/string_interpolation.rb → string_interpolation.rb} +4 -5
  52. data/lib/sass/script/{tree/unary_operation.rb → unary_operation.rb} +6 -6
  53. data/lib/sass/script/variable.rb +58 -0
  54. data/lib/sass/scss/css_parser.rb +3 -9
  55. data/lib/sass/scss/parser.rb +421 -450
  56. data/lib/sass/scss/rx.rb +11 -19
  57. data/lib/sass/scss/static_parser.rb +7 -321
  58. data/lib/sass/selector.rb +194 -68
  59. data/lib/sass/selector/abstract_sequence.rb +14 -29
  60. data/lib/sass/selector/comma_sequence.rb +25 -108
  61. data/lib/sass/selector/sequence.rb +66 -159
  62. data/lib/sass/selector/simple.rb +25 -23
  63. data/lib/sass/selector/simple_sequence.rb +63 -173
  64. data/lib/sass/shared.rb +1 -1
  65. data/lib/sass/supports.rb +15 -13
  66. data/lib/sass/tree/charset_node.rb +1 -1
  67. data/lib/sass/tree/comment_node.rb +3 -3
  68. data/lib/sass/tree/css_import_node.rb +11 -11
  69. data/lib/sass/tree/debug_node.rb +2 -2
  70. data/lib/sass/tree/directive_node.rb +4 -21
  71. data/lib/sass/tree/each_node.rb +8 -8
  72. data/lib/sass/tree/extend_node.rb +7 -14
  73. data/lib/sass/tree/for_node.rb +4 -4
  74. data/lib/sass/tree/function_node.rb +4 -9
  75. data/lib/sass/tree/if_node.rb +1 -1
  76. data/lib/sass/tree/import_node.rb +5 -4
  77. data/lib/sass/tree/media_node.rb +14 -4
  78. data/lib/sass/tree/mixin_def_node.rb +4 -4
  79. data/lib/sass/tree/mixin_node.rb +8 -21
  80. data/lib/sass/tree/node.rb +12 -54
  81. data/lib/sass/tree/prop_node.rb +20 -39
  82. data/lib/sass/tree/return_node.rb +2 -3
  83. data/lib/sass/tree/root_node.rb +3 -19
  84. data/lib/sass/tree/rule_node.rb +22 -35
  85. data/lib/sass/tree/supports_node.rb +13 -0
  86. data/lib/sass/tree/trace_node.rb +1 -2
  87. data/lib/sass/tree/variable_node.rb +3 -9
  88. data/lib/sass/tree/visitors/base.rb +8 -5
  89. data/lib/sass/tree/visitors/check_nesting.rb +19 -49
  90. data/lib/sass/tree/visitors/convert.rb +56 -74
  91. data/lib/sass/tree/visitors/cssize.rb +74 -202
  92. data/lib/sass/tree/visitors/deep_copy.rb +5 -10
  93. data/lib/sass/tree/visitors/extend.rb +7 -7
  94. data/lib/sass/tree/visitors/perform.rb +185 -278
  95. data/lib/sass/tree/visitors/set_options.rb +6 -20
  96. data/lib/sass/tree/visitors/to_css.rb +81 -234
  97. data/lib/sass/tree/warn_node.rb +2 -2
  98. data/lib/sass/tree/while_node.rb +2 -2
  99. data/lib/sass/util.rb +152 -522
  100. data/lib/sass/util/multibyte_string_scanner.rb +0 -2
  101. data/lib/sass/util/subset_map.rb +3 -4
  102. data/lib/sass/util/test.rb +1 -0
  103. data/lib/sass/version.rb +22 -20
  104. data/test/Gemfile +3 -0
  105. data/test/Gemfile.lock +10 -0
  106. data/test/sass/cache_test.rb +20 -62
  107. data/test/sass/callbacks_test.rb +1 -1
  108. data/test/sass/conversion_test.rb +2 -296
  109. data/test/sass/css2sass_test.rb +4 -23
  110. data/test/sass/engine_test.rb +354 -411
  111. data/test/sass/exec_test.rb +2 -2
  112. data/test/sass/extend_test.rb +145 -324
  113. data/test/sass/functions_test.rb +86 -873
  114. data/test/sass/importer_test.rb +21 -241
  115. data/test/sass/logger_test.rb +1 -1
  116. data/test/sass/more_results/more_import.css +1 -1
  117. data/test/sass/plugin_test.rb +26 -16
  118. data/test/sass/results/compact.css +1 -1
  119. data/test/sass/results/complex.css +4 -4
  120. data/test/sass/results/expanded.css +1 -1
  121. data/test/sass/results/import.css +1 -1
  122. data/test/sass/results/import_charset_ibm866.css +2 -2
  123. data/test/sass/results/mixins.css +17 -17
  124. data/test/sass/results/nested.css +1 -1
  125. data/test/sass/results/parent_ref.css +2 -2
  126. data/test/sass/results/script.css +3 -3
  127. data/test/sass/results/scss_import.css +1 -1
  128. data/test/sass/script_conversion_test.rb +7 -36
  129. data/test/sass/script_test.rb +53 -485
  130. data/test/sass/scss/css_test.rb +28 -143
  131. data/test/sass/scss/rx_test.rb +4 -4
  132. data/test/sass/scss/scss_test.rb +325 -2119
  133. data/test/sass/templates/scss_import.scss +1 -2
  134. data/test/sass/test_helper.rb +1 -1
  135. data/test/sass/util/multibyte_string_scanner_test.rb +1 -1
  136. data/test/sass/util/subset_map_test.rb +2 -2
  137. data/test/sass/util_test.rb +1 -86
  138. data/test/test_helper.rb +8 -37
  139. metadata +19 -66
  140. data/lib/sass/exec/base.rb +0 -187
  141. data/lib/sass/exec/sass_convert.rb +0 -264
  142. data/lib/sass/exec/sass_scss.rb +0 -424
  143. data/lib/sass/features.rb +0 -47
  144. data/lib/sass/script/tree.rb +0 -16
  145. data/lib/sass/script/tree/funcall.rb +0 -306
  146. data/lib/sass/script/tree/interpolation.rb +0 -118
  147. data/lib/sass/script/tree/list_literal.rb +0 -77
  148. data/lib/sass/script/tree/literal.rb +0 -45
  149. data/lib/sass/script/tree/map_literal.rb +0 -64
  150. data/lib/sass/script/tree/selector.rb +0 -26
  151. data/lib/sass/script/tree/variable.rb +0 -57
  152. data/lib/sass/script/value.rb +0 -11
  153. data/lib/sass/script/value/base.rb +0 -240
  154. data/lib/sass/script/value/bool.rb +0 -35
  155. data/lib/sass/script/value/color.rb +0 -680
  156. data/lib/sass/script/value/helpers.rb +0 -262
  157. data/lib/sass/script/value/list.rb +0 -113
  158. data/lib/sass/script/value/map.rb +0 -70
  159. data/lib/sass/script/value/string.rb +0 -97
  160. data/lib/sass/selector/pseudo.rb +0 -256
  161. data/lib/sass/source/map.rb +0 -210
  162. data/lib/sass/source/position.rb +0 -39
  163. data/lib/sass/source/range.rb +0 -41
  164. data/lib/sass/stack.rb +0 -120
  165. data/lib/sass/tree/at_root_node.rb +0 -83
  166. data/lib/sass/tree/error_node.rb +0 -18
  167. data/lib/sass/tree/keyframe_rule_node.rb +0 -15
  168. data/lib/sass/util/cross_platform_random.rb +0 -19
  169. data/lib/sass/util/normalized_map.rb +0 -130
  170. data/lib/sass/util/ordered_hash.rb +0 -192
  171. data/test/sass/compiler_test.rb +0 -232
  172. data/test/sass/encoding_test.rb +0 -219
  173. data/test/sass/source_map_test.rb +0 -977
  174. data/test/sass/superselector_test.rb +0 -191
  175. data/test/sass/util/normalized_map_test.rb +0 -51
  176. data/test/sass/value_helpers_test.rb +0 -179
data/lib/sass/engine.rb CHANGED
@@ -1,9 +1,6 @@
1
1
  require 'set'
2
2
  require 'digest/sha1'
3
3
  require 'sass/cache_stores'
4
- require 'sass/source/position'
5
- require 'sass/source/range'
6
- require 'sass/source/map'
7
4
  require 'sass/tree/node'
8
5
  require 'sass/tree/root_node'
9
6
  require 'sass/tree/rule_node'
@@ -29,9 +26,6 @@ require 'sass/tree/debug_node'
29
26
  require 'sass/tree/warn_node'
30
27
  require 'sass/tree/import_node'
31
28
  require 'sass/tree/charset_node'
32
- require 'sass/tree/at_root_node'
33
- require 'sass/tree/keyframe_rule_node'
34
- require 'sass/tree/error_node'
35
29
  require 'sass/tree/visitors/base'
36
30
  require 'sass/tree/visitors/perform'
37
31
  require 'sass/tree/visitors/cssize'
@@ -45,7 +39,6 @@ require 'sass/selector'
45
39
  require 'sass/environment'
46
40
  require 'sass/script'
47
41
  require 'sass/scss'
48
- require 'sass/stack'
49
42
  require 'sass/error'
50
43
  require 'sass/importers'
51
44
  require 'sass/shared'
@@ -53,17 +46,18 @@ require 'sass/media'
53
46
  require 'sass/supports'
54
47
 
55
48
  module Sass
49
+
56
50
  # A Sass mixin or function.
57
51
  #
58
52
  # `name`: `String`
59
53
  # : The name of the mixin/function.
60
54
  #
61
- # `args`: `Array<(Script::Tree::Node, Script::Tree::Node)>`
55
+ # `args`: `Array<(Script::Node, Script::Node)>`
62
56
  # : The arguments for the mixin/function.
63
57
  # Each element is a tuple containing the variable node of the argument
64
58
  # and the parse tree for the default value of the argument.
65
59
  #
66
- # `splat`: `Script::Tree::Node?`
60
+ # `splat`: `Script::Node?`
67
61
  # : The variable node of the splat argument for this callable, or null.
68
62
  #
69
63
  # `environment`: {Sass::Environment}
@@ -89,6 +83,8 @@ module Sass
89
83
  # output = sass_engine.render
90
84
  # puts output
91
85
  class Engine
86
+ include Sass::Util
87
+
92
88
  # A line of Sass code.
93
89
  #
94
90
  # `text`: `String`
@@ -198,8 +194,6 @@ module Sass
198
194
  when :alternate; options[:property_syntax] = :new
199
195
  when :normal; options[:property_syntax] = :old
200
196
  end
201
- options[:sourcemap] = :auto if options[:sourcemap] == true
202
- options[:sourcemap] = :none if options[:sourcemap] == false
203
197
 
204
198
  options
205
199
  end
@@ -252,7 +246,7 @@ module Sass
252
246
  # See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
253
247
  # @see {Sass::Engine.for_file}
254
248
  # @see {Sass::Plugin}
255
- def initialize(template, options = {})
249
+ def initialize(template, options={})
256
250
  @options = self.class.normalize_options(options)
257
251
  @template = template
258
252
  end
@@ -265,27 +259,9 @@ module Sass
265
259
  # cannot be converted to UTF-8
266
260
  # @raise [ArgumentError] if the document uses an unknown encoding with `@charset`
267
261
  def render
268
- return _to_tree.render unless @options[:quiet]
269
- Sass::Util.silence_sass_warnings {_to_tree.render}
262
+ return _render unless @options[:quiet]
263
+ Sass::Util.silence_sass_warnings {_render}
270
264
  end
271
-
272
- # Render the template to CSS and return the source map.
273
- #
274
- # @param sourcemap_uri [String] The sourcemap URI to use in the
275
- # `@sourceMappingURL` comment. If this is relative, it should be relative
276
- # to the location of the CSS file.
277
- # @return [(String, Sass::Source::Map)] The rendered CSS and the associated
278
- # source map
279
- # @raise [Sass::SyntaxError] if there's an error in the document, or if the
280
- # public URL for this document couldn't be determined.
281
- # @raise [Encoding::UndefinedConversionError] if the source encoding
282
- # cannot be converted to UTF-8
283
- # @raise [ArgumentError] if the document uses an unknown encoding with `@charset`
284
- def render_with_sourcemap(sourcemap_uri)
285
- return _render_with_sourcemap(sourcemap_uri) unless @options[:quiet]
286
- Sass::Util.silence_sass_warnings {_render_with_sourcemap(sourcemap_uri)}
287
- end
288
-
289
265
  alias_method :to_css, :render
290
266
 
291
267
  # Parses the document into its parse tree. Memoized.
@@ -293,11 +269,9 @@ module Sass
293
269
  # @return [Sass::Tree::Node] The root of the parse tree.
294
270
  # @raise [Sass::SyntaxError] if there's an error in the document
295
271
  def to_tree
296
- @tree ||= if @options[:quiet]
297
- Sass::Util.silence_sass_warnings {_to_tree}
298
- else
299
- _to_tree
300
- end
272
+ @tree ||= @options[:quiet] ?
273
+ Sass::Util.silence_sass_warnings {_to_tree} :
274
+ _to_tree
301
275
  end
302
276
 
303
277
  # Returns the original encoding of the document,
@@ -309,7 +283,7 @@ module Sass
309
283
  # @raise [ArgumentError] if the document uses an unknown encoding with `@charset`
310
284
  def source_encoding
311
285
  check_encoding!
312
- @source_encoding
286
+ @original_encoding
313
287
  end
314
288
 
315
289
  # Gets a set of all the documents
@@ -326,8 +300,7 @@ module Sass
326
300
  #
327
301
  # @private
328
302
  def _dependencies(seen, engines)
329
- key = [@options[:filename], @options[:importer]]
330
- return if seen.include?(key)
303
+ return if seen.include?(key = [@options[:filename], @options[:importer]])
331
304
  seen << key
332
305
  engines << self
333
306
  to_tree.grep(Tree::ImportNode) do |n|
@@ -338,59 +311,35 @@ module Sass
338
311
 
339
312
  private
340
313
 
341
- def _render_with_sourcemap(sourcemap_uri)
342
- filename = @options[:filename]
343
- importer = @options[:importer]
344
- sourcemap_dir = @options[:sourcemap_filename] &&
345
- File.dirname(File.expand_path(@options[:sourcemap_filename]))
346
- if filename.nil?
347
- raise Sass::SyntaxError.new(<<ERR)
348
- Error generating source map: couldn't determine public URL for the source stylesheet.
349
- No filename is available so there's nothing for the source map to link to.
350
- ERR
351
- elsif importer.nil?
352
- raise Sass::SyntaxError.new(<<ERR)
353
- Error generating source map: couldn't determine public URL for "#{filename}".
354
- Without a public URL, there's nothing for the source map to link to.
355
- An importer was not set for this file.
356
- ERR
357
- elsif Sass::Util.silence_warnings do
358
- sourcemap_dir = nil if @options[:sourcemap] == :file
359
- importer.public_url(filename, sourcemap_dir).nil?
360
- end
361
- raise Sass::SyntaxError.new(<<ERR)
362
- Error generating source map: couldn't determine public URL for "#{filename}".
363
- Without a public URL, there's nothing for the source map to link to.
364
- Custom importers should define the #public_url method.
365
- ERR
314
+ def _render
315
+ rendered = _to_tree.render
316
+ return rendered if ruby1_8?
317
+ begin
318
+ # Try to convert the result to the original encoding,
319
+ # but if that doesn't work fall back on UTF-8
320
+ rendered = rendered.encode(source_encoding)
321
+ rescue EncodingError
366
322
  end
367
-
368
- rendered, sourcemap = _to_tree.render_with_sourcemap
369
- compressed = @options[:style] == :compressed
370
- rendered << "\n" if rendered[-1] != ?\n
371
- rendered << "\n" unless compressed
372
- rendered << "/*# sourceMappingURL="
373
- rendered << Sass::Util.escape_uri(sourcemap_uri)
374
- rendered << " */\n"
375
- return rendered, sourcemap
323
+ rendered.gsub(Regexp.new('\A@charset "(.*?)"'.encode(source_encoding)),
324
+ "@charset \"#{source_encoding.name}\"".encode(source_encoding))
376
325
  end
377
326
 
378
327
  def _to_tree
379
- check_encoding!
380
-
381
328
  if (@options[:cache] || @options[:read_cache]) &&
382
329
  @options[:filename] && @options[:importer]
383
330
  key = sassc_key
384
331
  sha = Digest::SHA1.hexdigest(@template)
385
332
 
386
- if (root = @options[:cache_store].retrieve(key, sha))
333
+ if root = @options[:cache_store].retrieve(key, sha)
387
334
  root.options = @options
388
335
  return root
389
336
  end
390
337
  end
391
338
 
339
+ check_encoding!
340
+
392
341
  if @options[:syntax] == :scss
393
- root = Sass::SCSS::Parser.new(@template, @options[:filename], @options[:importer]).parse
342
+ root = Sass::SCSS::Parser.new(@template, @options[:filename]).parse
394
343
  else
395
344
  root = Tree::RootNode.new(@template)
396
345
  append_children(root, tree(tabulate(@template)).first, true)
@@ -420,7 +369,9 @@ ERR
420
369
  def check_encoding!
421
370
  return if @checked_encoding
422
371
  @checked_encoding = true
423
- @template, @source_encoding = Sass::Util.check_sass_encoding(@template)
372
+ @template, @original_encoding = check_sass_encoding(@template) do |msg, line|
373
+ raise Sass::SyntaxError.new(msg, :line => line)
374
+ end
424
375
  end
425
376
 
426
377
  def tabulate(string)
@@ -428,7 +379,7 @@ ERR
428
379
  comment_tab_str = nil
429
380
  first = true
430
381
  lines = []
431
- string.scan(/^[^\n]*?$/).each_with_index do |line, index|
382
+ string.gsub(/\r\n|\r|\n/, "\n").scan(/^[^\n]*?$/).each_with_index do |line, index|
432
383
  index += (@options[:line] || 1)
433
384
  if line.strip.empty?
434
385
  lines.last.text << "\n" if lines.last && lines.last.comment?
@@ -473,15 +424,12 @@ END
473
424
  raise SyntaxError.new(message, :line => index)
474
425
  end
475
426
 
476
- lines << Line.new(line.strip, line_tabs, index, line_tab_str.size, @options[:filename], [])
427
+ lines << Line.new(line.strip, line_tabs, index, tab_str.size, @options[:filename], [])
477
428
  end
478
429
  lines
479
430
  end
480
431
 
481
- # @comment
482
- # rubocop:disable ParameterLists
483
432
  def try_comment(line, last, tab_str, comment_tab_str, index)
484
- # rubocop:enable ParameterLists
485
433
  return unless last && last.comment?
486
434
  # Nested comment stuff must be at least one whitespace char deeper
487
435
  # than the normal indentation
@@ -506,8 +454,7 @@ MSG
506
454
  nodes = []
507
455
  while (line = arr[i]) && line.tabs >= base
508
456
  if line.tabs > base
509
- raise SyntaxError.new(
510
- "The line was indented #{line.tabs - base} levels deeper than the previous line.",
457
+ raise SyntaxError.new("The line was indented #{line.tabs - base} levels deeper than the previous line.",
511
458
  :line => line.index) if line.tabs > base + 1
512
459
 
513
460
  nodes.last.children, i = tree(arr, i)
@@ -521,7 +468,6 @@ MSG
521
468
 
522
469
  def build_tree(parent, line, root = false)
523
470
  @line = line.index
524
- @offset = line.offset
525
471
  node_or_nodes = parse_line(parent, line, root)
526
472
 
527
473
  Array(node_or_nodes).each do |node|
@@ -564,8 +510,6 @@ MSG
564
510
  if continued_comment &&
565
511
  child.line == continued_comment.line +
566
512
  continued_comment.lines + 1
567
- continued_comment.value.last.sub!(/ \*\/\Z/, '')
568
- child.value.first.gsub!(/\A\/\*/, ' *')
569
513
  continued_comment.value += ["\n"] + child.value
570
514
  next
571
515
  end
@@ -607,25 +551,12 @@ WARNING
607
551
  # which begin with ::,
608
552
  # as well as pseudo-classes
609
553
  # if we're using the new property syntax
610
- Tree::RuleNode.new(parse_interp(line.text), full_line_range(line))
554
+ Tree::RuleNode.new(parse_interp(line.text))
611
555
  else
612
- name_start_offset = line.offset + 1 # +1 for the leading ':'
613
556
  name, value = line.text.scan(PROPERTY_OLD)[0]
614
557
  raise SyntaxError.new("Invalid property: \"#{line.text}\".",
615
558
  :line => @line) if name.nil? || value.nil?
616
-
617
- value_start_offset = name_end_offset = name_start_offset + name.length
618
- unless value.empty?
619
- # +1 and -1 both compensate for the leading ':', which is part of line.text
620
- value_start_offset = name_start_offset + line.text.index(value, name.length + 1) - 1
621
- end
622
-
623
- property = parse_property(name, parse_interp(name), value, :old, line, value_start_offset)
624
- property.name_source_range = Sass::Source::Range.new(
625
- Sass::Source::Position.new(@line, to_parser_offset(name_start_offset)),
626
- Sass::Source::Position.new(@line, to_parser_offset(name_end_offset)),
627
- @options[:filename], @options[:importer])
628
- property
559
+ parse_property(name, parse_interp(name), value, :old, line)
629
560
  end
630
561
  when ?$
631
562
  parse_variable(line)
@@ -634,12 +565,12 @@ WARNING
634
565
  when DIRECTIVE_CHAR
635
566
  parse_directive(parent, line, root)
636
567
  when ESCAPE_CHAR
637
- Tree::RuleNode.new(parse_interp(line.text[1..-1]), full_line_range(line))
568
+ Tree::RuleNode.new(parse_interp(line.text[1..-1]))
638
569
  when MIXIN_DEFINITION_CHAR
639
570
  parse_mixin_definition(line)
640
571
  when MIXIN_INCLUDE_CHAR
641
572
  if line.text[1].nil? || line.text[1] == ?\s
642
- Tree::RuleNode.new(parse_interp(line.text), full_line_range(line))
573
+ Tree::RuleNode.new(parse_interp(line.text))
643
574
  else
644
575
  parse_mixin_include(line, root)
645
576
  end
@@ -651,70 +582,32 @@ WARNING
651
582
  def parse_property_or_rule(line)
652
583
  scanner = Sass::Util::MultibyteStringScanner.new(line.text)
653
584
  hack_char = scanner.scan(/[:\*\.]|\#(?!\{)/)
654
- offset = line.offset
655
- offset += hack_char.length if hack_char
656
- parser = Sass::SCSS::Parser.new(scanner,
657
- @options[:filename], @options[:importer],
658
- @line, to_parser_offset(offset))
659
-
660
- unless (res = parser.parse_interp_ident)
661
- parsed = parse_interp(line.text, line.offset)
662
- return Tree::RuleNode.new(parsed, full_line_range(line))
663
- end
585
+ parser = Sass::SCSS::Parser.new(scanner, @options[:filename], @line)
664
586
 
665
- ident_range = Sass::Source::Range.new(
666
- Sass::Source::Position.new(@line, to_parser_offset(line.offset)),
667
- Sass::Source::Position.new(@line, parser.offset),
668
- @options[:filename], @options[:importer])
669
- offset = parser.offset - 1
587
+ unless res = parser.parse_interp_ident
588
+ return Tree::RuleNode.new(parse_interp(line.text))
589
+ end
670
590
  res.unshift(hack_char) if hack_char
671
-
672
- # Handle comments after a property name but before the colon.
673
- if (comment = scanner.scan(Sass::SCSS::RX::COMMENT))
591
+ if comment = scanner.scan(Sass::SCSS::RX::COMMENT)
674
592
  res << comment
675
- offset += comment.length
676
593
  end
677
594
 
678
595
  name = line.text[0...scanner.pos]
679
- if (scanned = scanner.scan(/\s*:(?:\s+|$)/)) # test for a property
680
- offset += scanned.length
681
- property = parse_property(name, res, scanner.rest, :new, line, offset)
682
- property.name_source_range = ident_range
683
- property
596
+ if scanner.scan(/\s*:(?:\s|$)/)
597
+ parse_property(name, res, scanner.rest, :new, line)
684
598
  else
685
599
  res.pop if comment
686
-
687
- if (trailing = (scanner.scan(/\s*#{Sass::SCSS::RX::COMMENT}/) ||
688
- scanner.scan(/\s*#{Sass::SCSS::RX::SINGLE_LINE_COMMENT}/)))
689
- trailing.strip!
690
- end
691
- interp_parsed = parse_interp(scanner.rest)
692
- selector_range = Sass::Source::Range.new(
693
- ident_range.start_pos,
694
- Sass::Source::Position.new(@line, to_parser_offset(line.offset) + line.text.length),
695
- @options[:filename], @options[:importer])
696
- rule = Tree::RuleNode.new(res + interp_parsed, selector_range)
697
- rule << Tree::CommentNode.new([trailing], :silent) if trailing
698
- rule
600
+ Tree::RuleNode.new(res + parse_interp(scanner.rest))
699
601
  end
700
602
  end
701
603
 
702
- # @comment
703
- # rubocop:disable ParameterLists
704
- def parse_property(name, parsed_name, value, prop, line, start_offset)
705
- # rubocop:enable ParameterLists
604
+ def parse_property(name, parsed_name, value, prop, line)
706
605
  if value.strip.empty?
707
- expr = Sass::Script::Tree::Literal.new(Sass::Script::Value::String.new(""))
708
- end_offset = start_offset
606
+ expr = Sass::Script::String.new("")
709
607
  else
710
- expr = parse_script(value, :offset => to_parser_offset(start_offset))
711
- end_offset = expr.source_range.end_pos.offset - 1
608
+ expr = parse_script(value, :offset => line.offset + line.text.index(value))
712
609
  end
713
610
  node = Tree::PropNode.new(parse_interp(name), expr, prop)
714
- node.value_source_range = Sass::Source::Range.new(
715
- Sass::Source::Position.new(line.index, to_parser_offset(start_offset)),
716
- Sass::Source::Position.new(line.index, to_parser_offset(end_offset)),
717
- @options[:filename], @options[:importer])
718
611
  if value.strip.empty? && line.children.empty?
719
612
  raise SyntaxError.new(
720
613
  "Invalid property: \"#{node.declaration}\" (no value)." +
@@ -725,24 +618,15 @@ WARNING
725
618
  end
726
619
 
727
620
  def parse_variable(line)
728
- name, value, flags = line.text.scan(Script::MATCH)[0]
621
+ name, value, default = line.text.scan(Script::MATCH)[0]
729
622
  raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath variable declarations.",
730
623
  :line => @line + 1) unless line.children.empty?
731
624
  raise SyntaxError.new("Invalid variable: \"#{line.text}\".",
732
625
  :line => @line) unless name && value
733
- flags = flags ? flags.split(/\s+/) : []
734
- if (invalid_flag = flags.find {|f| f != '!default' && f != '!global'})
735
- raise SyntaxError.new("Invalid flag \"#{invalid_flag}\".", :line => @line)
736
- end
737
626
 
738
- # This workaround is needed for the case when the variable value is part of the identifier,
739
- # otherwise we end up with the offset equal to the value index inside the name:
740
- # $red_color: red;
741
- var_lhs_length = 1 + name.length # 1 stands for '$'
742
- index = line.text.index(value, line.offset + var_lhs_length) || 0
743
- expr = parse_script(value, :offset => to_parser_offset(line.offset + index))
627
+ expr = parse_script(value, :offset => line.offset + line.text.index(value))
744
628
 
745
- Tree::VariableNode.new(name, expr, flags.include?('!default'), flags.include?('!global'))
629
+ Tree::VariableNode.new(name, expr, default)
746
630
  end
747
631
 
748
632
  def parse_comment(line)
@@ -752,171 +636,108 @@ WARNING
752
636
  if silent
753
637
  value = [line.text]
754
638
  else
755
- value = self.class.parse_interp(
756
- line.text, line.index, to_parser_offset(line.offset), :filename => @filename)
639
+ value = self.class.parse_interp(line.text, line.index, line.offset, :filename => @filename)
757
640
  end
758
- value = Sass::Util.with_extracted_values(value) do |str|
641
+ value = with_extracted_values(value) do |str|
759
642
  str = str.gsub(/^#{line.comment_tab_str}/m, '')[2..-1] # get rid of // or /*
760
643
  format_comment_text(str, silent)
761
644
  end
762
- type = if silent
763
- :silent
764
- elsif loud
765
- :loud
766
- else
767
- :normal
768
- end
645
+ type = if silent then :silent elsif loud then :loud else :normal end
769
646
  Tree::CommentNode.new(value, type)
770
647
  else
771
- Tree::RuleNode.new(parse_interp(line.text), full_line_range(line))
648
+ Tree::RuleNode.new(parse_interp(line.text))
772
649
  end
773
650
  end
774
651
 
775
- DIRECTIVES = Set[:mixin, :include, :function, :return, :debug, :warn, :for,
776
- :each, :while, :if, :else, :extend, :import, :media, :charset, :content,
777
- :at_root, :error]
778
-
779
- # @comment
780
- # rubocop:disable MethodLength
781
652
  def parse_directive(parent, line, root)
782
653
  directive, whitespace, value = line.text[1..-1].split(/(\s+)/, 2)
783
- raise SyntaxError.new("Invalid directive: '@'.") unless directive
784
654
  offset = directive.size + whitespace.size + 1 if whitespace
785
655
 
786
- directive_name = directive.gsub('-', '_').to_sym
787
- if DIRECTIVES.include?(directive_name)
788
- return send("parse_#{directive_name}_directive", parent, line, root, value, offset)
789
- end
790
-
791
- unprefixed_directive = directive.gsub(/^-[a-z0-9]+-/i, '')
792
- if unprefixed_directive == 'supports'
656
+ # If value begins with url( or ",
657
+ # it's a CSS @import rule and we don't want to touch it.
658
+ case directive
659
+ when 'import'
660
+ parse_import(line, value, offset)
661
+ when 'mixin'
662
+ parse_mixin_definition(line)
663
+ when 'content'
664
+ parse_content_directive(line)
665
+ when 'include'
666
+ parse_mixin_include(line, root)
667
+ when 'function'
668
+ parse_function(line, root)
669
+ when 'for'
670
+ parse_for(line, root, value)
671
+ when 'each'
672
+ parse_each(line, root, value)
673
+ when 'else'
674
+ parse_else(parent, line, value)
675
+ when 'while'
676
+ raise SyntaxError.new("Invalid while directive '@while': expected expression.") unless value
677
+ Tree::WhileNode.new(parse_script(value, :offset => offset))
678
+ when 'if'
679
+ raise SyntaxError.new("Invalid if directive '@if': expected expression.") unless value
680
+ Tree::IfNode.new(parse_script(value, :offset => offset))
681
+ when 'debug'
682
+ raise SyntaxError.new("Invalid debug directive '@debug': expected expression.") unless value
683
+ raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath debug directives.",
684
+ :line => @line + 1) unless line.children.empty?
685
+ offset = line.offset + line.text.index(value).to_i
686
+ Tree::DebugNode.new(parse_script(value, :offset => offset))
687
+ when 'extend'
688
+ raise SyntaxError.new("Invalid extend directive '@extend': expected expression.") unless value
689
+ raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath extend directives.",
690
+ :line => @line + 1) unless line.children.empty?
691
+ optional = !!value.gsub!(/\s+#{Sass::SCSS::RX::OPTIONAL}$/, '')
692
+ offset = line.offset + line.text.index(value).to_i
693
+ Tree::ExtendNode.new(parse_interp(value, offset), optional)
694
+ when 'warn'
695
+ raise SyntaxError.new("Invalid warn directive '@warn': expected expression.") unless value
696
+ raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath warn directives.",
697
+ :line => @line + 1) unless line.children.empty?
698
+ offset = line.offset + line.text.index(value).to_i
699
+ Tree::WarnNode.new(parse_script(value, :offset => offset))
700
+ when 'return'
701
+ raise SyntaxError.new("Invalid @return: expected expression.") unless value
702
+ raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath return directives.",
703
+ :line => @line + 1) unless line.children.empty?
704
+ offset = line.offset + line.text.index(value).to_i
705
+ Tree::ReturnNode.new(parse_script(value, :offset => offset))
706
+ when 'charset'
707
+ name = value && value[/\A(["'])(.*)\1\Z/, 2] #"
708
+ raise SyntaxError.new("Invalid charset directive '@charset': expected string.") unless name
709
+ raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath charset directives.",
710
+ :line => @line + 1) unless line.children.empty?
711
+ Tree::CharsetNode.new(name)
712
+ when 'media'
793
713
  parser = Sass::SCSS::Parser.new(value, @options[:filename], @line)
794
- return Tree::SupportsNode.new(directive, parser.parse_supports_condition)
795
- end
796
-
797
- Tree::DirectiveNode.new(
798
- value.nil? ? ["@#{directive}"] : ["@#{directive} "] + parse_interp(value, offset))
799
- end
800
-
801
- def parse_while_directive(parent, line, root, value, offset)
802
- raise SyntaxError.new("Invalid while directive '@while': expected expression.") unless value
803
- Tree::WhileNode.new(parse_script(value, :offset => offset))
804
- end
805
-
806
- def parse_if_directive(parent, line, root, value, offset)
807
- raise SyntaxError.new("Invalid if directive '@if': expected expression.") unless value
808
- Tree::IfNode.new(parse_script(value, :offset => offset))
809
- end
810
-
811
- def parse_debug_directive(parent, line, root, value, offset)
812
- raise SyntaxError.new("Invalid debug directive '@debug': expected expression.") unless value
813
- raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath debug directives.",
814
- :line => @line + 1) unless line.children.empty?
815
- offset = line.offset + line.text.index(value).to_i
816
- Tree::DebugNode.new(parse_script(value, :offset => offset))
817
- end
818
-
819
- def parse_error_directive(parent, line, root, value, offset)
820
- raise SyntaxError.new("Invalid error directive '@error': expected expression.") unless value
821
- raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath error directives.",
822
- :line => @line + 1) unless line.children.empty?
823
- offset = line.offset + line.text.index(value).to_i
824
- Tree::ErrorNode.new(parse_script(value, :offset => offset))
825
- end
826
-
827
- def parse_extend_directive(parent, line, root, value, offset)
828
- raise SyntaxError.new("Invalid extend directive '@extend': expected expression.") unless value
829
- raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath extend directives.",
830
- :line => @line + 1) unless line.children.empty?
831
- optional = !!value.gsub!(/\s+#{Sass::SCSS::RX::OPTIONAL}$/, '')
832
- offset = line.offset + line.text.index(value).to_i
833
- interp_parsed = parse_interp(value, offset)
834
- selector_range = Sass::Source::Range.new(
835
- Sass::Source::Position.new(@line, to_parser_offset(offset)),
836
- Sass::Source::Position.new(@line, to_parser_offset(line.offset) + line.text.length),
837
- @options[:filename], @options[:importer]
838
- )
839
- Tree::ExtendNode.new(interp_parsed, optional, selector_range)
840
- end
841
- # @comment
842
- # rubocop:enable MethodLength
843
-
844
- def parse_warn_directive(parent, line, root, value, offset)
845
- raise SyntaxError.new("Invalid warn directive '@warn': expected expression.") unless value
846
- raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath warn directives.",
847
- :line => @line + 1) unless line.children.empty?
848
- offset = line.offset + line.text.index(value).to_i
849
- Tree::WarnNode.new(parse_script(value, :offset => offset))
850
- end
851
-
852
- def parse_return_directive(parent, line, root, value, offset)
853
- raise SyntaxError.new("Invalid @return: expected expression.") unless value
854
- raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath return directives.",
855
- :line => @line + 1) unless line.children.empty?
856
- offset = line.offset + line.text.index(value).to_i
857
- Tree::ReturnNode.new(parse_script(value, :offset => offset))
858
- end
859
-
860
- def parse_charset_directive(parent, line, root, value, offset)
861
- name = value && value[/\A(["'])(.*)\1\Z/, 2] # "
862
- raise SyntaxError.new("Invalid charset directive '@charset': expected string.") unless name
863
- raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath charset directives.",
864
- :line => @line + 1) unless line.children.empty?
865
- Tree::CharsetNode.new(name)
866
- end
867
-
868
- def parse_media_directive(parent, line, root, value, offset)
869
- parser = Sass::SCSS::Parser.new(value,
870
- @options[:filename], @options[:importer],
871
- @line, to_parser_offset(@offset))
872
- offset = line.offset + line.text.index('media').to_i - 1
873
- parsed_media_query_list = parser.parse_media_query_list.to_a
874
- node = Tree::MediaNode.new(parsed_media_query_list)
875
- node.source_range = Sass::Source::Range.new(
876
- Sass::Source::Position.new(@line, to_parser_offset(offset)),
877
- Sass::Source::Position.new(@line, to_parser_offset(line.offset) + line.text.length),
878
- @options[:filename], @options[:importer])
879
- node
880
- end
881
-
882
- def parse_at_root_directive(parent, line, root, value, offset)
883
- return Sass::Tree::AtRootNode.new unless value
714
+ Tree::MediaNode.new(parser.parse_media_query_list.to_a)
715
+ when nil
716
+ raise SyntaxError.new("Invalid directive: '@'.")
717
+ else
718
+ unprefixed_directive = directive.gsub(/^-[a-z0-9]+-/i, '')
719
+ if unprefixed_directive == 'supports'
720
+ parser = Sass::SCSS::Parser.new(value, @options[:filename], @line)
721
+ return Tree::SupportsNode.new(directive, parser.parse_supports_condition)
722
+ end
884
723
 
885
- if value.start_with?('(')
886
- parser = Sass::SCSS::Parser.new(value,
887
- @options[:filename], @options[:importer],
888
- @line, to_parser_offset(@offset))
889
- offset = line.offset + line.text.index('at-root').to_i - 1
890
- return Tree::AtRootNode.new(parser.parse_at_root_query)
724
+ Tree::DirectiveNode.new(
725
+ value.nil? ? ["@#{directive}"] : ["@#{directive} "] + parse_interp(value, offset))
891
726
  end
892
-
893
- at_root_node = Tree::AtRootNode.new
894
- parsed = parse_interp(value, offset)
895
- rule_node = Tree::RuleNode.new(parsed, full_line_range(line))
896
-
897
- # The caller expects to automatically add children to the returned node
898
- # and we want it to add children to the rule node instead, so we
899
- # manually handle the wiring here and return nil so the caller doesn't
900
- # duplicate our efforts.
901
- append_children(rule_node, line.children, false)
902
- at_root_node << rule_node
903
- parent << at_root_node
904
- nil
905
727
  end
906
728
 
907
- def parse_for_directive(parent, line, root, value, offset)
908
- var, from_expr, to_name, to_expr =
909
- value.scan(/^([^\s]+)\s+from\s+(.+)\s+(to|through)\s+(.+)$/).first
729
+ def parse_for(line, root, text)
730
+ var, from_expr, to_name, to_expr = text.scan(/^([^\s]+)\s+from\s+(.+)\s+(to|through)\s+(.+)$/).first
910
731
 
911
732
  if var.nil? # scan failed, try to figure out why for error message
912
- if value !~ /^[^\s]+/
733
+ if text !~ /^[^\s]+/
913
734
  expected = "variable name"
914
- elsif value !~ /^[^\s]+\s+from\s+.+/
735
+ elsif text !~ /^[^\s]+\s+from\s+.+/
915
736
  expected = "'from <expr>'"
916
737
  else
917
738
  expected = "'to <expr>' or 'through <expr>'"
918
739
  end
919
- raise SyntaxError.new("Invalid for directive '@for #{value}': expected #{expected}.")
740
+ raise SyntaxError.new("Invalid for directive '@for #{text}': expected #{expected}.")
920
741
  end
921
742
  raise SyntaxError.new("Invalid variable \"#{var}\".") unless var =~ Script::VALIDATE
922
743
 
@@ -926,35 +747,31 @@ WARNING
926
747
  Tree::ForNode.new(var, parsed_from, parsed_to, to_name == 'to')
927
748
  end
928
749
 
929
- def parse_each_directive(parent, line, root, value, offset)
930
- vars, list_expr = value.scan(/^([^\s]+(?:\s*,\s*[^\s]+)*)\s+in\s+(.+)$/).first
750
+ def parse_each(line, root, text)
751
+ var, list_expr = text.scan(/^([^\s]+)\s+in\s+(.+)$/).first
931
752
 
932
- if vars.nil? # scan failed, try to figure out why for error message
933
- if value !~ /^[^\s]+/
753
+ if var.nil? # scan failed, try to figure out why for error message
754
+ if text !~ /^[^\s]+/
934
755
  expected = "variable name"
935
- elsif value !~ /^[^\s]+(?:\s*,\s*[^\s]+)*[^\s]+\s+from\s+.+/
756
+ elsif text !~ /^[^\s]+\s+from\s+.+/
936
757
  expected = "'in <expr>'"
937
758
  end
938
- raise SyntaxError.new("Invalid each directive '@each #{value}': expected #{expected}.")
939
- end
940
-
941
- vars = vars.split(',').map do |var|
942
- var.strip!
943
- raise SyntaxError.new("Invalid variable \"#{var}\".") unless var =~ Script::VALIDATE
944
- var[1..-1]
759
+ raise SyntaxError.new("Invalid for directive '@each #{text}': expected #{expected}.")
945
760
  end
761
+ raise SyntaxError.new("Invalid variable \"#{var}\".") unless var =~ Script::VALIDATE
946
762
 
763
+ var = var[1..-1]
947
764
  parsed_list = parse_script(list_expr, :offset => line.offset + line.text.index(list_expr))
948
- Tree::EachNode.new(vars, parsed_list)
765
+ Tree::EachNode.new(var, parsed_list)
949
766
  end
950
767
 
951
- def parse_else_directive(parent, line, root, value, offset)
768
+ def parse_else(parent, line, text)
952
769
  previous = parent.children.last
953
770
  raise SyntaxError.new("@else must come after @if.") unless previous.is_a?(Tree::IfNode)
954
771
 
955
- if value
956
- if value !~ /^if\s+(.+)/
957
- raise SyntaxError.new("Invalid else directive '@else #{value}': expected 'if <expr>'.")
772
+ if text
773
+ if text !~ /^if\s+(.+)/
774
+ raise SyntaxError.new("Invalid else directive '@else #{text}': expected 'if <expr>'.")
958
775
  end
959
776
  expr = parse_script($1, :offset => line.offset + line.text.index($1))
960
777
  end
@@ -965,7 +782,7 @@ WARNING
965
782
  nil
966
783
  end
967
784
 
968
- def parse_import_directive(parent, line, root, value, offset)
785
+ def parse_import(line, value, offset)
969
786
  raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath import directives.",
970
787
  :line => @line + 1) unless line.children.empty?
971
788
 
@@ -973,9 +790,8 @@ WARNING
973
790
  values = []
974
791
 
975
792
  loop do
976
- unless (node = parse_import_arg(scanner, offset + scanner.pos))
977
- raise SyntaxError.new(
978
- "Invalid @import: expected file to import, was #{scanner.rest.inspect}",
793
+ unless node = parse_import_arg(scanner, offset + scanner.pos)
794
+ raise SyntaxError.new("Invalid @import: expected file to import, was #{scanner.rest.inspect}",
979
795
  :line => @line)
980
796
  end
981
797
  values << node
@@ -987,81 +803,35 @@ WARNING
987
803
  :line => @line)
988
804
  end
989
805
 
990
- values
806
+ return values
991
807
  end
992
808
 
993
- # @comment
994
- # rubocop:disable MethodLength
995
809
  def parse_import_arg(scanner, offset)
996
810
  return if scanner.eos?
997
811
 
998
812
  if scanner.match?(/url\(/i)
999
- script_parser = Sass::Script::Parser.new(scanner, @line, to_parser_offset(offset), @options)
813
+ script_parser = Sass::Script::Parser.new(scanner, @line, offset, @options)
1000
814
  str = script_parser.parse_string
1001
-
1002
- if scanner.eos?
1003
- end_pos = str.source_range.end_pos
1004
- node = Tree::CssImportNode.new(str)
1005
- else
1006
- media_parser = Sass::SCSS::Parser.new(scanner,
1007
- @options[:filename], @options[:importer],
1008
- @line, str.source_range.end_pos.offset)
1009
- media = media_parser.parse_media_query_list
1010
- end_pos = Sass::Source::Position.new(@line, media_parser.offset + 1)
1011
- node = Tree::CssImportNode.new(str, media.to_a)
1012
- end
1013
-
1014
- node.source_range = Sass::Source::Range.new(
1015
- str.source_range.start_pos, end_pos,
1016
- @options[:filename], @options[:importer])
1017
- return node
815
+ media_parser = Sass::SCSS::Parser.new(scanner, @options[:filename], @line)
816
+ media = media_parser.parse_media_query_list
817
+ return Tree::CssImportNode.new(str, media.to_a)
1018
818
  end
1019
819
 
1020
- unless (quoted_val = scanner.scan(Sass::SCSS::RX::STRING))
1021
- scanned = scanner.scan(/[^,;]+/)
1022
- node = Tree::ImportNode.new(scanned)
1023
- start_parser_offset = to_parser_offset(offset)
1024
- node.source_range = Sass::Source::Range.new(
1025
- Sass::Source::Position.new(@line, start_parser_offset),
1026
- Sass::Source::Position.new(@line, start_parser_offset + scanned.length),
1027
- @options[:filename], @options[:importer])
1028
- return node
820
+ unless str = scanner.scan(Sass::SCSS::RX::STRING)
821
+ return Tree::ImportNode.new(scanner.scan(/[^,;]+/))
1029
822
  end
1030
823
 
1031
- start_offset = offset
1032
- offset += scanner.matched.length
1033
- val = Sass::Script::Value::String.value(scanner[1] || scanner[2])
1034
- scanned = scanner.scan(/\s*/)
824
+ val = scanner[1] || scanner[2]
825
+ scanner.scan(/\s*/)
1035
826
  if !scanner.match?(/[,;]|$/)
1036
- offset += scanned.length if scanned
1037
- media_parser = Sass::SCSS::Parser.new(scanner,
1038
- @options[:filename], @options[:importer], @line, offset)
827
+ media_parser = Sass::SCSS::Parser.new(scanner, @options[:filename], @line)
1039
828
  media = media_parser.parse_media_query_list
1040
- node = Tree::CssImportNode.new(quoted_val, media.to_a)
1041
- node.source_range = Sass::Source::Range.new(
1042
- Sass::Source::Position.new(@line, to_parser_offset(start_offset)),
1043
- Sass::Source::Position.new(@line, media_parser.offset),
1044
- @options[:filename], @options[:importer])
1045
- elsif val =~ %r{^(https?:)?//}
1046
- node = Tree::CssImportNode.new(quoted_val)
1047
- node.source_range = Sass::Source::Range.new(
1048
- Sass::Source::Position.new(@line, to_parser_offset(start_offset)),
1049
- Sass::Source::Position.new(@line, to_parser_offset(offset)),
1050
- @options[:filename], @options[:importer])
829
+ Tree::CssImportNode.new(str || uri, media.to_a)
830
+ elsif val =~ /^(https?:)?\/\//
831
+ Tree::CssImportNode.new("url(#{val})")
1051
832
  else
1052
- node = Tree::ImportNode.new(val)
1053
- node.source_range = Sass::Source::Range.new(
1054
- Sass::Source::Position.new(@line, to_parser_offset(start_offset)),
1055
- Sass::Source::Position.new(@line, to_parser_offset(offset)),
1056
- @options[:filename], @options[:importer])
833
+ Tree::ImportNode.new(val)
1057
834
  end
1058
- node
1059
- end
1060
- # @comment
1061
- # rubocop:enable MethodLength
1062
-
1063
- def parse_mixin_directive(parent, line, root, value, offset)
1064
- parse_mixin_definition(line)
1065
835
  end
1066
836
 
1067
837
  MIXIN_DEF_RE = /^(?:=|@mixin)\s*(#{Sass::SCSS::RX::IDENT})(.*)$/
@@ -1070,53 +840,45 @@ WARNING
1070
840
  raise SyntaxError.new("Invalid mixin \"#{line.text[1..-1]}\".") if name.nil?
1071
841
 
1072
842
  offset = line.offset + line.text.size - arg_string.size
1073
- args, splat = Script::Parser.new(arg_string.strip, @line, to_parser_offset(offset), @options).
843
+ args, splat = Script::Parser.new(arg_string.strip, @line, offset, @options).
1074
844
  parse_mixin_definition_arglist
1075
845
  Tree::MixinDefNode.new(name, args, splat)
1076
846
  end
1077
847
 
1078
848
  CONTENT_RE = /^@content\s*(.+)?$/
1079
- def parse_content_directive(parent, line, root, value, offset)
849
+ def parse_content_directive(line)
1080
850
  trailing = line.text.scan(CONTENT_RE).first.first
1081
- unless trailing.nil?
1082
- raise SyntaxError.new(
1083
- "Invalid content directive. Trailing characters found: \"#{trailing}\".")
1084
- end
851
+ raise SyntaxError.new("Invalid content directive. Trailing characters found: \"#{trailing}\".") unless trailing.nil?
1085
852
  raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath @content directives.",
1086
853
  :line => line.index + 1) unless line.children.empty?
1087
854
  Tree::ContentNode.new
1088
855
  end
1089
856
 
1090
- def parse_include_directive(parent, line, root, value, offset)
1091
- parse_mixin_include(line, root)
1092
- end
1093
-
1094
857
  MIXIN_INCLUDE_RE = /^(?:\+|@include)\s*(#{Sass::SCSS::RX::IDENT})(.*)$/
1095
858
  def parse_mixin_include(line, root)
1096
859
  name, arg_string = line.text.scan(MIXIN_INCLUDE_RE).first
1097
860
  raise SyntaxError.new("Invalid mixin include \"#{line.text}\".") if name.nil?
1098
861
 
1099
862
  offset = line.offset + line.text.size - arg_string.size
1100
- args, keywords, splat, kwarg_splat =
1101
- Script::Parser.new(arg_string.strip, @line, to_parser_offset(offset), @options).
1102
- parse_mixin_include_arglist
1103
- Tree::MixinNode.new(name, args, keywords, splat, kwarg_splat)
863
+ args, keywords, splat = Script::Parser.new(arg_string.strip, @line, offset, @options).
864
+ parse_mixin_include_arglist
865
+ Tree::MixinNode.new(name, args, keywords, splat)
1104
866
  end
1105
867
 
1106
868
  FUNCTION_RE = /^@function\s*(#{Sass::SCSS::RX::IDENT})(.*)$/
1107
- def parse_function_directive(parent, line, root, value, offset)
869
+ def parse_function(line, root)
1108
870
  name, arg_string = line.text.scan(FUNCTION_RE).first
1109
871
  raise SyntaxError.new("Invalid function definition \"#{line.text}\".") if name.nil?
1110
872
 
1111
873
  offset = line.offset + line.text.size - arg_string.size
1112
- args, splat = Script::Parser.new(arg_string.strip, @line, to_parser_offset(offset), @options).
874
+ args, splat = Script::Parser.new(arg_string.strip, @line, offset, @options).
1113
875
  parse_function_definition_arglist
1114
876
  Tree::FunctionNode.new(name, args, splat)
1115
877
  end
1116
878
 
1117
879
  def parse_script(script, options = {})
1118
880
  line = options[:line] || @line
1119
- offset = options[:offset] || @offset + 1
881
+ offset = options[:offset] || 0
1120
882
  Script.parse(script, line, offset, @options)
1121
883
  end
1122
884
 
@@ -1128,12 +890,12 @@ WARNING
1128
890
  content.shift
1129
891
  end
1130
892
 
1131
- return "/* */" if content.empty?
1132
- content.last.gsub!(/ ?\*\/ *$/, '')
893
+ return silent ? "//" : "/* */" if content.empty?
894
+ content.last.gsub!(%r{ ?\*/ *$}, '')
1133
895
  content.map! {|l| l.gsub!(/^\*( ?)/, '\1') || (l.empty? ? "" : " ") + l}
1134
896
  content.first.gsub!(/^ /, '') unless removed_first
1135
897
  if silent
1136
- "/*" + content.join("\n *") + " */"
898
+ "//" + content.join("\n//")
1137
899
  else
1138
900
  # The #gsub fixes the case of a trailing */
1139
901
  "/*" + content.join("\n *").gsub(/ \*\Z/, '') + " */"
@@ -1144,20 +906,8 @@ WARNING
1144
906
  self.class.parse_interp(text, @line, offset, :filename => @filename)
1145
907
  end
1146
908
 
1147
- # Parser tracks 1-based line and offset, so our offset should be converted.
1148
- def to_parser_offset(offset)
1149
- offset + 1
1150
- end
1151
-
1152
- def full_line_range(line)
1153
- Sass::Source::Range.new(
1154
- Sass::Source::Position.new(@line, to_parser_offset(line.offset)),
1155
- Sass::Source::Position.new(@line, to_parser_offset(line.offset) + line.text.length),
1156
- @options[:filename], @options[:importer])
1157
- end
1158
-
1159
909
  # It's important that this have strings (at least)
1160
- # at the beginning, the end, and between each Script::Tree::Node.
910
+ # at the beginning, the end, and between each Script::Node.
1161
911
  #
1162
912
  # @private
1163
913
  def self.parse_interp(text, line, offset, options)
@@ -1165,13 +915,12 @@ WARNING
1165
915
  rest = Sass::Shared.handle_interpolation text do |scan|
1166
916
  escapes = scan[2].size
1167
917
  res << scan.matched[0...-2 - escapes]
1168
- if escapes.odd?
918
+ if escapes % 2 == 1
1169
919
  res << "\\" * (escapes - 1) << '#{'
1170
920
  else
1171
921
  res << "\\" * [0, escapes - 1].max
1172
- # Add 1 to emulate to_parser_offset.
1173
922
  res << Script::Parser.new(
1174
- scan, line, offset + scan.pos - scan.matched_size + 1, options).
923
+ scan, line, offset + scan.pos - scan.matched_size, options).
1175
924
  parse_interpolated
1176
925
  end
1177
926
  end