oreorenasass 3.4.4 → 3.4.5

Sign up to get free protection for your applications and to get access to all the features.
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