sass 3.4.0 → 3.4.25

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 (142) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +3 -1
  3. data/CODE_OF_CONDUCT.md +10 -0
  4. data/CONTRIBUTING.md +148 -0
  5. data/MIT-LICENSE +1 -1
  6. data/README.md +26 -20
  7. data/Rakefile +103 -20
  8. data/VERSION +1 -1
  9. data/VERSION_DATE +1 -1
  10. data/extra/sass-spec-ref.sh +32 -0
  11. data/extra/update_watch.rb +1 -1
  12. data/lib/sass/cache_stores/filesystem.rb +7 -7
  13. data/lib/sass/cache_stores/memory.rb +4 -5
  14. data/lib/sass/callbacks.rb +2 -2
  15. data/lib/sass/css.rb +11 -10
  16. data/lib/sass/deprecation.rb +55 -0
  17. data/lib/sass/engine.rb +83 -38
  18. data/lib/sass/environment.rb +26 -2
  19. data/lib/sass/error.rb +12 -12
  20. data/lib/sass/exec/base.rb +15 -3
  21. data/lib/sass/exec/sass_convert.rb +34 -15
  22. data/lib/sass/exec/sass_scss.rb +23 -7
  23. data/lib/sass/features.rb +2 -2
  24. data/lib/sass/importers/base.rb +1 -1
  25. data/lib/sass/importers/deprecated_path.rb +51 -0
  26. data/lib/sass/importers/filesystem.rb +24 -16
  27. data/lib/sass/importers.rb +1 -0
  28. data/lib/sass/logger/base.rb +8 -2
  29. data/lib/sass/logger/delayed.rb +50 -0
  30. data/lib/sass/logger.rb +8 -3
  31. data/lib/sass/plugin/compiler.rb +42 -25
  32. data/lib/sass/plugin/configuration.rb +38 -22
  33. data/lib/sass/plugin/merb.rb +2 -2
  34. data/lib/sass/plugin/rack.rb +3 -3
  35. data/lib/sass/plugin/rails.rb +1 -1
  36. data/lib/sass/plugin/staleness_checker.rb +3 -3
  37. data/lib/sass/plugin.rb +3 -2
  38. data/lib/sass/script/css_parser.rb +2 -3
  39. data/lib/sass/script/css_variable_warning.rb +52 -0
  40. data/lib/sass/script/functions.rb +140 -73
  41. data/lib/sass/script/lexer.rb +37 -22
  42. data/lib/sass/script/parser.rb +235 -40
  43. data/lib/sass/script/tree/funcall.rb +12 -5
  44. data/lib/sass/script/tree/interpolation.rb +109 -4
  45. data/lib/sass/script/tree/list_literal.rb +31 -4
  46. data/lib/sass/script/tree/literal.rb +4 -0
  47. data/lib/sass/script/tree/node.rb +21 -3
  48. data/lib/sass/script/tree/operation.rb +54 -1
  49. data/lib/sass/script/tree/string_interpolation.rb +58 -37
  50. data/lib/sass/script/tree/variable.rb +1 -1
  51. data/lib/sass/script/value/base.rb +10 -9
  52. data/lib/sass/script/value/color.rb +42 -24
  53. data/lib/sass/script/value/helpers.rb +16 -6
  54. data/lib/sass/script/value/map.rb +1 -1
  55. data/lib/sass/script/value/number.rb +52 -19
  56. data/lib/sass/script/value/string.rb +46 -5
  57. data/lib/sass/script.rb +3 -3
  58. data/lib/sass/scss/css_parser.rb +16 -2
  59. data/lib/sass/scss/parser.rb +120 -75
  60. data/lib/sass/scss/rx.rb +9 -10
  61. data/lib/sass/scss/static_parser.rb +19 -14
  62. data/lib/sass/scss.rb +0 -2
  63. data/lib/sass/selector/abstract_sequence.rb +8 -6
  64. data/lib/sass/selector/comma_sequence.rb +25 -9
  65. data/lib/sass/selector/pseudo.rb +45 -35
  66. data/lib/sass/selector/sequence.rb +54 -18
  67. data/lib/sass/selector/simple.rb +11 -11
  68. data/lib/sass/selector/simple_sequence.rb +34 -15
  69. data/lib/sass/selector.rb +7 -10
  70. data/lib/sass/shared.rb +1 -1
  71. data/lib/sass/source/map.rb +7 -4
  72. data/lib/sass/source/position.rb +4 -4
  73. data/lib/sass/stack.rb +2 -2
  74. data/lib/sass/supports.rb +8 -10
  75. data/lib/sass/tree/comment_node.rb +1 -1
  76. data/lib/sass/tree/css_import_node.rb +9 -1
  77. data/lib/sass/tree/function_node.rb +8 -3
  78. data/lib/sass/tree/import_node.rb +6 -5
  79. data/lib/sass/tree/node.rb +5 -3
  80. data/lib/sass/tree/prop_node.rb +5 -6
  81. data/lib/sass/tree/rule_node.rb +14 -4
  82. data/lib/sass/tree/visitors/check_nesting.rb +18 -22
  83. data/lib/sass/tree/visitors/convert.rb +43 -26
  84. data/lib/sass/tree/visitors/cssize.rb +5 -1
  85. data/lib/sass/tree/visitors/deep_copy.rb +1 -1
  86. data/lib/sass/tree/visitors/extend.rb +15 -13
  87. data/lib/sass/tree/visitors/perform.rb +42 -17
  88. data/lib/sass/tree/visitors/set_options.rb +1 -1
  89. data/lib/sass/tree/visitors/to_css.rb +58 -30
  90. data/lib/sass/util/multibyte_string_scanner.rb +0 -2
  91. data/lib/sass/util/normalized_map.rb +0 -1
  92. data/lib/sass/util/subset_map.rb +1 -2
  93. data/lib/sass/util.rb +125 -68
  94. data/lib/sass/version.rb +2 -2
  95. data/lib/sass.rb +10 -3
  96. data/test/sass/compiler_test.rb +6 -2
  97. data/test/sass/conversion_test.rb +187 -53
  98. data/test/sass/css2sass_test.rb +50 -1
  99. data/test/sass/css_variable_test.rb +132 -0
  100. data/test/sass/engine_test.rb +207 -61
  101. data/test/sass/exec_test.rb +10 -0
  102. data/test/sass/extend_test.rb +101 -29
  103. data/test/sass/functions_test.rb +60 -9
  104. data/test/sass/importer_test.rb +9 -0
  105. data/test/sass/more_templates/more1.sass +10 -10
  106. data/test/sass/more_templates/more_import.sass +2 -2
  107. data/test/sass/plugin_test.rb +10 -8
  108. data/test/sass/results/script.css +3 -3
  109. data/test/sass/script_conversion_test.rb +58 -29
  110. data/test/sass/script_test.rb +430 -53
  111. data/test/sass/scss/css_test.rb +73 -7
  112. data/test/sass/scss/rx_test.rb +4 -0
  113. data/test/sass/scss/scss_test.rb +309 -4
  114. data/test/sass/source_map_test.rb +152 -74
  115. data/test/sass/superselector_test.rb +19 -0
  116. data/test/sass/templates/_partial.sass +1 -1
  117. data/test/sass/templates/basic.sass +10 -10
  118. data/test/sass/templates/bork1.sass +1 -1
  119. data/test/sass/templates/bork5.sass +1 -1
  120. data/test/sass/templates/compact.sass +10 -10
  121. data/test/sass/templates/complex.sass +187 -187
  122. data/test/sass/templates/compressed.sass +10 -10
  123. data/test/sass/templates/expanded.sass +10 -10
  124. data/test/sass/templates/import.sass +2 -2
  125. data/test/sass/templates/importee.sass +3 -3
  126. data/test/sass/templates/mixins.sass +22 -22
  127. data/test/sass/templates/multiline.sass +4 -4
  128. data/test/sass/templates/nested.sass +13 -13
  129. data/test/sass/templates/parent_ref.sass +12 -12
  130. data/test/sass/templates/script.sass +70 -70
  131. data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +1 -1
  132. data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +2 -2
  133. data/test/sass/templates/subdir/subdir.sass +3 -3
  134. data/test/sass/templates/units.sass +10 -10
  135. data/test/sass/util/multibyte_string_scanner_test.rb +10 -2
  136. data/test/sass/util_test.rb +15 -44
  137. data/test/sass-spec.yml +3 -0
  138. data/test/test_helper.rb +5 -4
  139. metadata +302 -295
  140. data/CONTRIBUTING +0 -3
  141. data/lib/sass/scss/script_lexer.rb +0 -15
  142. data/lib/sass/scss/script_parser.rb +0 -25
@@ -16,21 +16,20 @@ module Sass
16
16
  # warnings and source maps.
17
17
  # @param importer [Sass::Importers::Base] The importer used to import the
18
18
  # file being parsed. Used for source maps.
19
- # @param line [Fixnum] The 1-based line on which the source string appeared,
19
+ # @param line [Integer] The 1-based line on which the source string appeared,
20
20
  # if it's part of another document.
21
- # @param offset [Fixnum] The 1-based character (not byte) offset in the line on
21
+ # @param offset [Integer] The 1-based character (not byte) offset in the line on
22
22
  # which the source string starts. Used for error reporting and sourcemap
23
23
  # building.
24
- # @comment
25
- # rubocop:disable ParameterLists
26
24
  def initialize(str, filename, importer, line = 1, offset = 1)
27
- # rubocop:enable ParameterLists
28
25
  @template = str
29
26
  @filename = filename
30
27
  @importer = importer
31
28
  @line = line
32
29
  @offset = offset
33
30
  @strs = []
31
+ @expected = nil
32
+ @throw_error = false
34
33
  end
35
34
 
36
35
  # Parses an SCSS document.
@@ -55,6 +54,15 @@ module Sass
55
54
  interp_ident
56
55
  end
57
56
 
57
+ # Parses a supports clause for an @import directive
58
+ def parse_supports_clause
59
+ init_scanner!
60
+ ss
61
+ clause = supports_clause
62
+ ss
63
+ clause
64
+ end
65
+
58
66
  # Parses a media query list.
59
67
  #
60
68
  # @return [Sass::Media::QueryList] The parsed query list
@@ -108,7 +116,7 @@ module Sass
108
116
  if @template.is_a?(StringScanner)
109
117
  @template
110
118
  else
111
- Sass::Util::MultibyteStringScanner.new(@template.gsub("\r", ""))
119
+ Sass::Util::MultibyteStringScanner.new(@template.tr("\r", ""))
112
120
  end
113
121
  end
114
122
 
@@ -150,21 +158,16 @@ module Sass
150
158
  silent = text =~ %r{\A//}
151
159
  loud = !silent && text =~ %r{\A/[/*]!}
152
160
  line = @line - text.count("\n")
161
+ comment_start = @scanner.pos - text.length
162
+ index_before_line = @scanner.string.rindex("\n", comment_start) || -1
163
+ offset = comment_start - index_before_line
153
164
 
154
165
  if silent
155
166
  value = [text.sub(%r{\A\s*//}, '/*').gsub(%r{^\s*//}, ' *') + ' */']
156
167
  else
157
- value = Sass::Engine.parse_interp(
158
- text, line, @scanner.pos - text.size, :filename => @filename)
159
- string_before_comment = @scanner.string[0...@scanner.pos - text.length]
160
- newline_before_comment = string_before_comment.rindex("\n")
161
- last_line_before_comment =
162
- if newline_before_comment
163
- string_before_comment[newline_before_comment + 1..-1]
164
- else
165
- string_before_comment
166
- end
167
- value.unshift(last_line_before_comment.gsub(/[^\s]/, ' '))
168
+ value = Sass::Engine.parse_interp(text, line, offset, :filename => @filename)
169
+ line_before_comment = @scanner.string[index_before_line + 1...comment_start]
170
+ value.unshift(line_before_comment.gsub(/[^\s]/, ' '))
168
171
  end
169
172
 
170
173
  type = if silent
@@ -174,8 +177,8 @@ module Sass
174
177
  else
175
178
  :normal
176
179
  end
177
- comment = Sass::Tree::CommentNode.new(value, type)
178
- comment.line = line
180
+ start_pos = Sass::Source::Position.new(line, offset)
181
+ comment = node(Sass::Tree::CommentNode.new(value, type), start_pos)
179
182
  node << comment
180
183
  end
181
184
 
@@ -215,12 +218,12 @@ module Sass
215
218
  end
216
219
 
217
220
  def special_directive(name, start_pos)
218
- sym = name.gsub('-', '_').to_sym
221
+ sym = name.tr('-', '_').to_sym
219
222
  DIRECTIVES.include?(sym) && send("#{sym}_directive", start_pos)
220
223
  end
221
224
 
222
225
  def prefixed_directive(name, start_pos)
223
- sym = deprefix(name).gsub('-', '_').to_sym
226
+ sym = deprefix(name).tr('-', '_').to_sym
224
227
  PREFIXED_DIRECTIVES.include?(sym) && send("#{sym}_directive", name, start_pos)
225
228
  end
226
229
 
@@ -380,16 +383,21 @@ module Sass
380
383
  if uri
381
384
  str = sass_script(:parse_string)
382
385
  ss
386
+ supports = supports_clause
387
+ ss
383
388
  media = media_query_list
384
389
  ss
385
- return node(Tree::CssImportNode.new(str, media.to_a), start_pos)
390
+ return node(Tree::CssImportNode.new(str, media.to_a, supports), start_pos)
386
391
  end
387
392
  ss
388
393
 
394
+ supports = supports_clause
395
+ ss
389
396
  media = media_query_list
390
- if str =~ %r{^(https?:)?//} || media || use_css_import?
391
- return node(Sass::Tree::CssImportNode.new(
392
- Sass::Script::Value::String.quote(str), media.to_a), start_pos)
397
+ if str =~ %r{^(https?:)?//} || media || supports || use_css_import?
398
+ return node(
399
+ Sass::Tree::CssImportNode.new(
400
+ Sass::Script::Value::String.quote(str), media.to_a, supports), start_pos)
393
401
  end
394
402
 
395
403
  node(Sass::Tree::ImportNode.new(str.strip), start_pos)
@@ -503,7 +511,7 @@ module Sass
503
511
 
504
512
  def moz_document_function
505
513
  val = interp_uri || _interp_string(:url_prefix) ||
506
- _interp_string(:domain) || function(!:allow_var) || interpolation
514
+ _interp_string(:domain) || function(false) || interpolation
507
515
  return unless val
508
516
  ss
509
517
  val
@@ -549,10 +557,23 @@ module Sass
549
557
  node(node, start_pos)
550
558
  end
551
559
 
560
+ def supports_clause
561
+ return unless tok(/supports\(/i)
562
+ ss
563
+ supports = import_supports_condition
564
+ ss
565
+ tok!(/\)/)
566
+ supports
567
+ end
568
+
552
569
  def supports_condition
553
570
  supports_negation || supports_operator || supports_interpolation
554
571
  end
555
572
 
573
+ def import_supports_condition
574
+ supports_condition || supports_declaration
575
+ end
576
+
556
577
  def supports_negation
557
578
  return unless tok(/not/i)
558
579
  ss
@@ -562,7 +583,9 @@ module Sass
562
583
  def supports_operator
563
584
  cond = supports_condition_in_parens
564
585
  return unless cond
565
- while (op = tok(/and|or/i))
586
+ re = /and|or/i
587
+ while (op = tok(re))
588
+ re = /#{op}/i
566
589
  ss
567
590
  cond = Sass::Supports::Operator.new(
568
591
  cond, expr!(:supports_condition_in_parens), op)
@@ -570,6 +593,13 @@ module Sass
570
593
  cond
571
594
  end
572
595
 
596
+ def supports_declaration
597
+ name = sass_script(:parse)
598
+ tok!(/:/); ss
599
+ value = sass_script(:parse)
600
+ Sass::Supports::Declaration.new(name, value)
601
+ end
602
+
573
603
  def supports_condition_in_parens
574
604
  interp = supports_interpolation
575
605
  return interp if interp
@@ -578,19 +608,12 @@ module Sass
578
608
  tok!(/\)/); ss
579
609
  cond
580
610
  else
581
- name = sass_script(:parse)
582
- tok!(/:/); ss
583
- value = sass_script(:parse)
611
+ decl = supports_declaration
584
612
  tok!(/\)/); ss
585
- Sass::Supports::Declaration.new(name, value)
613
+ decl
586
614
  end
587
615
  end
588
616
 
589
- def supports_declaration_condition
590
- return unless tok(/\(/); ss
591
- supports_declaration_body
592
- end
593
-
594
617
  def supports_interpolation
595
618
  interp = interpolation
596
619
  return unless interp
@@ -626,14 +649,15 @@ module Sass
626
649
  # are disallowed by the CSS spec,
627
650
  # but they're included here for compatibility
628
651
  # with some proprietary MS properties
629
- str {ss if tok(/[\/,:.=]/)}
652
+ str {ss if tok(%r{[/,:.=]})}
630
653
  end
631
654
 
632
655
  def ruleset
633
656
  start_pos = source_position
634
657
  return unless (rules = almost_any_value)
635
- block(node(
636
- Sass::Tree::RuleNode.new(rules, range(start_pos)), start_pos), :ruleset)
658
+ block(
659
+ node(
660
+ Sass::Tree::RuleNode.new(rules, range(start_pos)), start_pos), :ruleset)
637
661
  end
638
662
 
639
663
  def block(node, context)
@@ -708,8 +732,9 @@ module Sass
708
732
  selector << additional_selector
709
733
  end
710
734
 
711
- block(node(
712
- Sass::Tree::RuleNode.new(merge(selector), range(start_pos)), start_pos), :ruleset)
735
+ block(
736
+ node(
737
+ Sass::Tree::RuleNode.new(merge(selector), range(start_pos)), start_pos), :ruleset)
713
738
  end
714
739
 
715
740
  # Tries to parse a declaration, and returns the value parsed so far if it
@@ -750,7 +775,7 @@ module Sass
750
775
  value_start_pos = source_position
751
776
  value = nil
752
777
  error = catch_error do
753
- value = value!
778
+ value = value!(name.first.is_a?(String) && name.first.start_with?("--"))
754
779
  if tok?(/\{/)
755
780
  # Properties that are ambiguous with selectors can't have additional
756
781
  # properties nested beneath them.
@@ -808,8 +833,13 @@ module Sass
808
833
  def almost_any_value_token
809
834
  tok(%r{
810
835
  (
836
+ \\.
837
+ |
811
838
  (?!url\()
812
- [^"/\#!;\{\}] # "
839
+ [^"'/\#!;\{\}] # "
840
+ |
841
+ # interp_uri will handle most url() calls, but not ones that take strings
842
+ url\(#{W}(?=")
813
843
  |
814
844
  /(?![/*])
815
845
  |
@@ -841,7 +871,7 @@ module Sass
841
871
  tok!(/:/)
842
872
  ss
843
873
  value_start_pos = source_position
844
- value = value!
874
+ value = value!(name.first.is_a?(String) && name.first.start_with?("--"))
845
875
  value_end_pos = source_position
846
876
  ss
847
877
  require_block = tok?(/\{/)
@@ -855,7 +885,7 @@ module Sass
855
885
  nested_properties! node
856
886
  end
857
887
 
858
- def value!
888
+ def value!(css_variable = false)
859
889
  if tok?(/\{/)
860
890
  str = Sass::Script::Tree::Literal.new(Sass::Script::Value::String.new(""))
861
891
  str.line = source_position.line
@@ -875,10 +905,19 @@ module Sass
875
905
  str.source_range = range(start_pos)
876
906
  return str
877
907
  end
878
- sass_script(:parse)
908
+
909
+ sass_script(:parse, css_variable)
879
910
  end
880
911
 
881
912
  def nested_properties!(node)
913
+ if node.name.first.is_a?(String) && node.name.first.start_with?("--")
914
+ Sass::Util.sass_warn(<<WARNING)
915
+ DEPRECATION WARNING on line #{@line}#{" of #{@filename}" if @filename}:
916
+ Sass 3.6 will change the way CSS variables are parsed. Instead of being parsed as
917
+ normal properties, they will not allow any Sass-specific behavior other than \#{}.
918
+ WARNING
919
+ end
920
+
882
921
  @expected = 'expression (e.g. 1px, bold) or "{"'
883
922
  block(node, :property)
884
923
  end
@@ -983,7 +1022,7 @@ module Sass
983
1022
  end
984
1023
 
985
1024
  def str
986
- @strs.push ""
1025
+ @strs.push String.new("")
987
1026
  yield
988
1027
  @strs.last
989
1028
  ensure
@@ -1011,8 +1050,7 @@ module Sass
1011
1050
  node
1012
1051
  end
1013
1052
 
1014
- @sass_script_parser = Class.new(Sass::Script::Parser)
1015
- @sass_script_parser.send(:include, ScriptParser)
1053
+ @sass_script_parser = Sass::Script::Parser
1016
1054
 
1017
1055
  class << self
1018
1056
  # @private
@@ -1021,7 +1059,7 @@ module Sass
1021
1059
 
1022
1060
  def sass_script(*args)
1023
1061
  parser = self.class.sass_script_parser.new(@scanner, @line, @offset,
1024
- :filename => @filename, :importer => @importer)
1062
+ :filename => @filename, :importer => @importer, :allow_extra_text => true)
1025
1063
  result = parser.send(*args)
1026
1064
  unless @strs.empty?
1027
1065
  # Convert to CSS manually so that comments are ignored.
@@ -1086,7 +1124,7 @@ module Sass
1086
1124
 
1087
1125
  unless name
1088
1126
  # Display basic regexps as plain old strings
1089
- source = rx.source.gsub(/\\\//, '/')
1127
+ source = rx.source.gsub(%r{\\/}, '/')
1090
1128
  string = rx.source.gsub(/\\(.)/, '\1')
1091
1129
  name = source == Regexp.escape(string) ? string.inspect : rx.inspect
1092
1130
  end
@@ -1117,14 +1155,20 @@ module Sass
1117
1155
  line = @line
1118
1156
  offset = @offset
1119
1157
  expected = @expected
1158
+
1159
+ logger = Sass::Logger::Delayed.install!
1120
1160
  if catch(:_sass_parser_error) {yield; false}
1121
1161
  @scanner.pos = pos
1122
1162
  @line = line
1123
1163
  @offset = offset
1124
1164
  @expected = expected
1125
1165
  {:pos => pos, :line => line, :expected => @expected, :block => block}
1166
+ else
1167
+ logger.flush
1168
+ nil
1126
1169
  end
1127
1170
  ensure
1171
+ logger.uninstall! if logger
1128
1172
  @throw_error = old_throw_error
1129
1173
  end
1130
1174
 
@@ -1171,33 +1215,34 @@ module Sass
1171
1215
 
1172
1216
  def tok(rx, last_group_lookahead = false)
1173
1217
  res = @scanner.scan(rx)
1174
- if res
1175
- # This fixes https://github.com/nex3/sass/issues/104, which affects
1176
- # Ruby 1.8.7 and REE. This fix is to replace the ?= zero-width
1177
- # positive lookahead operator in the Regexp (which matches without
1178
- # consuming the matched group), with a match that does consume the
1179
- # group, but then rewinds the scanner and removes the group from the
1180
- # end of the matched string. This fix makes the assumption that the
1181
- # matched group will always occur at the end of the match.
1182
- if last_group_lookahead && @scanner[-1]
1183
- @scanner.pos -= @scanner[-1].length
1184
- res.slice!(-@scanner[-1].length..-1)
1185
- end
1186
1218
 
1187
- newline_count = res.count(NEWLINE)
1188
- if newline_count > 0
1189
- @line += newline_count
1190
- @offset = res[res.rindex(NEWLINE)..-1].size
1191
- else
1192
- @offset += res.size
1193
- end
1219
+ return unless res
1220
+
1221
+ # This fixes https://github.com/nex3/sass/issues/104, which affects
1222
+ # Ruby 1.8.7 and REE. This fix is to replace the ?= zero-width
1223
+ # positive lookahead operator in the Regexp (which matches without
1224
+ # consuming the matched group), with a match that does consume the
1225
+ # group, but then rewinds the scanner and removes the group from the
1226
+ # end of the matched string. This fix makes the assumption that the
1227
+ # matched group will always occur at the end of the match.
1228
+ if last_group_lookahead && @scanner[-1]
1229
+ @scanner.pos -= @scanner[-1].length
1230
+ res.slice!(-@scanner[-1].length..-1)
1231
+ end
1194
1232
 
1195
- @expected = nil
1196
- if !@strs.empty? && rx != COMMENT && rx != SINGLE_LINE_COMMENT
1197
- @strs.each {|s| s << res}
1198
- end
1199
- res
1233
+ newline_count = res.count(NEWLINE)
1234
+ if newline_count > 0
1235
+ @line += newline_count
1236
+ @offset = res[res.rindex(NEWLINE)..-1].size
1237
+ else
1238
+ @offset += res.size
1200
1239
  end
1240
+
1241
+ @expected = nil
1242
+ if !@strs.empty? && rx != COMMENT && rx != SINGLE_LINE_COMMENT
1243
+ @strs.each {|s| s << res}
1244
+ end
1245
+ res
1201
1246
  end
1202
1247
 
1203
1248
  # Remove a vendor prefix from `str`.
data/lib/sass/scss/rx.rb CHANGED
@@ -32,7 +32,7 @@ module Sass
32
32
  # @return [String] The escaped character
33
33
  # @private
34
34
  def self.escape_char(c)
35
- return "\\%06x" % Sass::Util.ord(c) unless c =~ /[ -\/:-~]/
35
+ return "\\%06x" % (Sass::Util.ord(c)) unless c =~ %r{[ -/:-~]}
36
36
  "\\#{c}"
37
37
  end
38
38
 
@@ -40,7 +40,7 @@ module Sass
40
40
  # escaping all significant characters.
41
41
  #
42
42
  # @param str [String] The text of the regexp
43
- # @param flags [Fixnum] Flags for the created regular expression
43
+ # @param flags [Integer] Flags for the created regular expression
44
44
  # @return [Regexp]
45
45
  # @private
46
46
  def self.quote(str, flags = 0)
@@ -66,7 +66,6 @@ module Sass
66
66
 
67
67
  IDENT = /-*#{NMSTART}#{NMCHAR}*/
68
68
  NAME = /#{NMCHAR}+/
69
- NUM = //
70
69
  STRING = /#{STRING1}|#{STRING2}/
71
70
  URLCHAR = /[#%&*-~]|#{NONASCII}|#{ESCAPE}/
72
71
  URL = /(#{URLCHAR}*)/
@@ -96,8 +95,13 @@ module Sass
96
95
 
97
96
  IMPORTANT = /!#{W}important/i
98
97
 
98
+ # A unit is like an IDENT, but disallows a hyphen followed by a digit.
99
+ # This allows "1px-2px" to be interpreted as subtraction rather than "1"
100
+ # with the unit "px-2px". It also allows "%".
101
+ UNIT = /-?#{NMSTART}(?:[a-zA-Z0-9_]|#{NONASCII}|#{ESCAPE}|-(?!\.?\d))*|%/
102
+
99
103
  UNITLESS_NUMBER = /(?:[0-9]+|[0-9]*\.[0-9]+)(?:[eE][+-]?\d+)?/
100
- NUMBER = /#{UNITLESS_NUMBER}(?:#{IDENT}|%)?/
104
+ NUMBER = /#{UNITLESS_NUMBER}(?:#{UNIT})?/
101
105
  PERCENTAGE = /#{UNITLESS_NUMBER}%/
102
106
 
103
107
  URI = /url\(#{W}(?:#{STRING}|#{URL})#{W}\)/i
@@ -123,18 +127,13 @@ module Sass
123
127
  OPTIONAL = /!#{W}optional/i
124
128
  IDENT_START = /-|#{NMSTART}/
125
129
 
126
- # A unit is like an IDENT, but disallows a hyphen followed by a digit.
127
- # This allows "1px-2px" to be interpreted as subtraction rather than "1"
128
- # with the unit "px-2px". It also allows "%".
129
- UNIT = /-?#{NMSTART}(?:[a-zA-Z0-9_]|#{NONASCII}|#{ESCAPE}|-(?!\d))*|%/
130
-
131
130
  IDENT_HYPHEN_INTERP = /-(#\{)/
132
131
  STRING1_NOINTERP = /\"((?:[^\n\r\f\\"#]|#(?!\{)|#{ESCAPE})*)\"/
133
132
  STRING2_NOINTERP = /\'((?:[^\n\r\f\\'#]|#(?!\{)|#{ESCAPE})*)\'/
134
133
  STRING_NOINTERP = /#{STRING1_NOINTERP}|#{STRING2_NOINTERP}/
135
134
 
136
135
  STATIC_COMPONENT = /#{IDENT}|#{STRING_NOINTERP}|#{HEXCOLOR}|[+-]?#{NUMBER}|\!important/i
137
- STATIC_VALUE = /#{STATIC_COMPONENT}(\s*[\s,\/]\s*#{STATIC_COMPONENT})*([;}])/i
136
+ STATIC_VALUE = %r(#{STATIC_COMPONENT}(\s*[\s,/]\s*#{STATIC_COMPONENT})*([;}]))i
138
137
  STATIC_SELECTOR = /(#{NMCHAR}|[ \t]|[,>+*]|[:#.]#{NMSTART}){1,50}([{])/i
139
138
  end
140
139
  end
@@ -62,7 +62,7 @@ module Sass
62
62
  private
63
63
 
64
64
  def moz_document_function
65
- val = tok(URI) || tok(URL_PREFIX) || tok(DOMAIN) || function(!:allow_var)
65
+ val = tok(URI) || tok(URL_PREFIX) || tok(DOMAIN) || function(false)
66
66
  return unless val
67
67
  ss
68
68
  [val]
@@ -78,7 +78,7 @@ module Sass
78
78
  def use_css_import?; true; end
79
79
 
80
80
  def special_directive(name, start_pos)
81
- return unless %w[media import charset -moz-document].include?(name)
81
+ return unless %w(media import charset -moz-document).include?(name)
82
82
  super
83
83
  end
84
84
 
@@ -89,13 +89,12 @@ module Sass
89
89
  ws = ''
90
90
  while tok(/,/)
91
91
  ws << str {ss}
92
- if (sel = selector)
93
- selectors << sel
94
- if ws.include?("\n")
95
- selectors[-1] = Selector::Sequence.new(["\n"] + selectors.last.members)
96
- end
97
- ws = ''
92
+ next unless (sel = selector)
93
+ selectors << sel
94
+ if ws.include?("\n")
95
+ selectors[-1] = Selector::Sequence.new(["\n"] + selectors.last.members)
98
96
  end
97
+ ws = ''
99
98
  end
100
99
  Selector::CommaSequence.new(selectors)
101
100
  end
@@ -140,11 +139,18 @@ MESSAGE
140
139
  end
141
140
 
142
141
  def reference_combinator
143
- return unless tok(/\//)
142
+ return unless tok(%r{/})
144
143
  res = '/'
145
144
  ns, name = expr!(:qualified_name)
146
145
  res << ns << '|' if ns
147
- res << name << tok!(/\//)
146
+ res << name << tok!(%r{/})
147
+
148
+ location = " of #{@filename}" if @filename
149
+ Sass::Util.sass_warn <<MESSAGE
150
+ DEPRECATION WARNING on line #{@line}, column #{@offset}#{location}:
151
+ The reference combinator #{res} is deprecated and will be removed in a future release.
152
+ MESSAGE
153
+
148
154
  res
149
155
  end
150
156
 
@@ -266,9 +272,9 @@ MESSAGE
266
272
  return ns, name
267
273
  end
268
274
 
269
- SELECTOR_PSEUDO_CLASSES = %w[not matches current any has host host-context].to_set
275
+ SELECTOR_PSEUDO_CLASSES = %w(not matches current any has host host-context).to_set
270
276
 
271
- PREFIXED_SELECTOR_PSEUDO_CLASSES = %w[nth-child nth-last-child].to_set
277
+ PREFIXED_SELECTOR_PSEUDO_CLASSES = %w(nth-child nth-last-child).to_set
272
278
 
273
279
  def pseudo
274
280
  s = tok(/::?/)
@@ -358,11 +364,10 @@ MESSAGE
358
364
  end
359
365
 
360
366
  def keyframes_selector_component
361
- tok(/from|to/i) || tok(PERCENTAGE)
367
+ tok(IDENT) || tok(PERCENTAGE)
362
368
  end
363
369
 
364
370
  @sass_script_parser = Class.new(Sass::Script::CssParser)
365
- @sass_script_parser.send(:include, ScriptParser)
366
371
  end
367
372
  end
368
373
  end
data/lib/sass/scss.rb CHANGED
@@ -1,6 +1,4 @@
1
1
  require 'sass/scss/rx'
2
- require 'sass/scss/script_lexer'
3
- require 'sass/scss/script_parser'
4
2
  require 'sass/scss/parser'
5
3
  require 'sass/scss/static_parser'
6
4
  require 'sass/scss/css_parser'
@@ -8,7 +8,7 @@ module Sass
8
8
  class AbstractSequence
9
9
  # The line of the Sass template on which this selector was declared.
10
10
  #
11
- # @return [Fixnum]
11
+ # @return [Integer]
12
12
  attr_reader :line
13
13
 
14
14
  # The name of the file in which this selector was declared.
@@ -19,8 +19,8 @@ module Sass
19
19
  # Sets the line of the Sass template on which this selector was declared.
20
20
  # This also sets the line for all child selectors.
21
21
  #
22
- # @param line [Fixnum]
23
- # @return [Fixnum]
22
+ # @param line [Integer]
23
+ # @return [Integer]
24
24
  def line=(line)
25
25
  members.each {|m| m.line = line}
26
26
  @line = line
@@ -42,7 +42,7 @@ module Sass
42
42
  # Subclasses should define `#_hash` rather than overriding this method,
43
43
  # which automatically handles memoizing the result.
44
44
  #
45
- # @return [Fixnum]
45
+ # @return [Integer]
46
46
  def hash
47
47
  @_hash ||= _hash
48
48
  end
@@ -71,8 +71,10 @@ module Sass
71
71
 
72
72
  # Returns the selector string.
73
73
  #
74
+ # @param opts [Hash] rendering options.
75
+ # @option opts [Symbol] :style The css rendering style.
74
76
  # @return [String]
75
- def to_s
77
+ def to_s(opts = {})
76
78
  Sass::Util.abstract(self)
77
79
  end
78
80
 
@@ -81,7 +83,7 @@ module Sass
81
83
  # The base is given by {Sass::Selector::SPECIFICITY_BASE}. This can be a
82
84
  # number or a range representing possible specificities.
83
85
  #
84
- # @return [Fixnum, Range]
86
+ # @return [Integer, Range]
85
87
  def specificity
86
88
  _specificity(members)
87
89
  end
@@ -2,6 +2,8 @@ module Sass
2
2
  module Selector
3
3
  # A comma-separated sequence of selectors.
4
4
  class CommaSequence < AbstractSequence
5
+ @@compound_extend_deprecation = Sass::Deprecation.new
6
+
5
7
  # The comma-separated selector sequences
6
8
  # represented by this class.
7
9
  #
@@ -25,12 +27,7 @@ module Sass
25
27
  # @raise [Sass::SyntaxError] If a parent selector is invalid
26
28
  def resolve_parent_refs(super_cseq, implicit_parent = true)
27
29
  if super_cseq.nil?
28
- if @members.any? do |sel|
29
- sel.members.any? do |sel_or_op|
30
- sel_or_op.is_a?(SimpleSequence) &&
31
- sel_or_op.members.any? {|ssel| ssel.is_a?(Parent)}
32
- end
33
- end
30
+ if contains_parent_ref?
34
31
  raise Sass::SyntaxError.new(
35
32
  "Base-level rules cannot contain the parent-selector-referencing character '&'.")
36
33
  end
@@ -42,6 +39,13 @@ module Sass
42
39
  end))
43
40
  end
44
41
 
42
+ # Returns whether there's a {Parent} selector anywhere in this sequence.
43
+ #
44
+ # @return [Boolean]
45
+ def contains_parent_ref?
46
+ @members.any? {|sel| sel.contains_parent_ref?}
47
+ end
48
+
45
49
  # Non-destrucively extends this selector with the extensions specified in a hash
46
50
  # (which should come from {Sass::Tree::Visitors::Cssize}).
47
51
  #
@@ -94,8 +98,11 @@ module Sass
94
98
  # The node that caused this extension.
95
99
  # @param parent_directives [Array<Sass::Tree::DirectiveNode>]
96
100
  # The parent directives containing `extend_node`.
101
+ # @param allow_compound_target [Boolean]
102
+ # Whether `extendee` is allowed to contain compound selectors.
97
103
  # @raise [Sass::SyntaxError] if this extension is invalid.
98
- def populate_extends(extends, extendee, extend_node = nil, parent_directives = [])
104
+ def populate_extends(extends, extendee, extend_node = nil, parent_directives = [],
105
+ allow_compound_target = false)
99
106
  extendee.members.each do |seq|
100
107
  if seq.members.size > 1
101
108
  raise Sass::SyntaxError.new("Can't extend #{seq}: can't extend nested selectors")
@@ -109,6 +116,13 @@ module Sass
109
116
  end
110
117
 
111
118
  sel = sseq.members
119
+ if !allow_compound_target && sel.length > 1
120
+ @@compound_extend_deprecation.warn(sseq.filename, sseq.line, <<WARNING)
121
+ Extending a compound selector, #{sseq}, is deprecated and will not be supported in a future release.
122
+ See https://github.com/sass/sass/issues/1599 for details.
123
+ WARNING
124
+ end
125
+
112
126
  members.each do |member|
113
127
  unless member.members.last.is_a?(Sass::Selector::SimpleSequence)
114
128
  raise Sass::SyntaxError.new("#{member} can't extend: invalid selector")
@@ -157,8 +171,10 @@ module Sass
157
171
  end
158
172
 
159
173
  # @see AbstractSequence#to_s
160
- def to_s
161
- @members.join(", ").gsub(", \n", ",\n")
174
+ def to_s(opts = {})
175
+ @members.map {|m| m.to_s(opts)}.
176
+ join(opts[:style] == :compressed ? "," : ", ").
177
+ gsub(", \n", ",\n")
162
178
  end
163
179
 
164
180
  private