sass 3.2.0.alpha.247 → 3.2.0.alpha.258

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.
data/REVISION CHANGED
@@ -1 +1 @@
1
- 5cc7590756da94e5c6df3da3be9ca8ff946d7279
1
+ 77bf74d8fe5dc1ee1301f5e06676ae8581ddfd73
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.2.0.alpha.247
1
+ 3.2.0.alpha.258
@@ -82,6 +82,7 @@ module Sass
82
82
  nest_seqs root
83
83
  parent_ref_rules root
84
84
  flatten_rules root
85
+ bubble_subject root
85
86
  fold_commas root
86
87
  dump_selectors root
87
88
  root
@@ -212,14 +213,16 @@ module Sass
212
213
  firsts, rest = [sseq.members.first], sseq.members[1..-1]
213
214
  firsts.push rest.shift if firsts.first.is_a?(Sass::Selector::Parent)
214
215
 
215
- if current_rule.nil? || first_sseq(current_rule).members != firsts
216
+ last_simple_subject = rest.empty? && sseq.subject?
217
+ if current_rule.nil? || first_sseq(current_rule).members != firsts ||
218
+ !!first_sseq(current_rule).subject? != !!last_simple_subject
216
219
  current_rule = Tree::RuleNode.new([])
217
- current_rule.parsed_rules = make_sseq(*firsts)
220
+ current_rule.parsed_rules = make_sseq(last_simple_subject, *firsts)
218
221
  end
219
222
 
220
223
  unless rest.empty?
221
224
  rest.unshift Sass::Selector::Parent.new
222
- child.parsed_rules = make_sseq(*rest)
225
+ child.parsed_rules = make_sseq(sseq.subject?, *rest)
223
226
  current_rule << child
224
227
  else
225
228
  current_rule.children += child.children
@@ -287,6 +290,19 @@ module Sass
287
290
  flatten_rules(rule)
288
291
  end
289
292
 
293
+ def bubble_subject(root)
294
+ root.children.each do |child|
295
+ bubble_subject(child) if child.is_a?(Tree::RuleNode) || child.is_a?(Tree::DirectiveNode)
296
+ next unless child.is_a?(Tree::RuleNode)
297
+ next unless child.children.all? do |c|
298
+ next unless c.is_a?(Tree::RuleNode)
299
+ first_simple_sel(c).is_a?(Sass::Selector::Parent) && first_sseq(c).subject?
300
+ end
301
+ first_sseq(child).subject = true
302
+ child.children.each {|c| first_sseq(c).subject = false}
303
+ end
304
+ end
305
+
290
306
  # Transform
291
307
  #
292
308
  # foo
@@ -355,10 +371,11 @@ module Sass
355
371
  # {Sass::Selector::Sequence} which in turn contains only a single
356
372
  # {Sass::Selector::SimpleSequence}.
357
373
  #
374
+ # @param subject [Boolean] Whether this is a subject selector
358
375
  # @param sseqs [Array<Sass::Selector::Sequence, String>]
359
376
  # @return [Sass::Selector::CommaSequence]
360
- def make_sseq(*sseqs)
361
- make_seq(Sass::Selector::SimpleSequence.new(sseqs))
377
+ def make_sseq(subject, *sseqs)
378
+ make_seq(Sass::Selector::SimpleSequence.new(sseqs, subject))
362
379
  end
363
380
 
364
381
  # Return the first {Sass::Selector::Sequence} in a {Sass::Tree::RuleNode}.
@@ -144,6 +144,9 @@ module Sass::Script
144
144
  # \{#join join($list1, $list2, \[$separator\])}
145
145
  # : Joins together two lists into one.
146
146
  #
147
+ # \{#append append($list1, $val, \[$separator\])}
148
+ # : Appends a single value onto the end of a list.
149
+ #
147
150
  # ## Introspection Functions
148
151
  #
149
152
  # \{#type_of type-of($value)}
@@ -582,7 +585,10 @@ module Sass::Script
582
585
  return Sass::Script::String.new("alpha(#{args.map {|a| a.to_s}.join(", ")})")
583
586
  end
584
587
 
585
- opacity(*args)
588
+ raise ArgumentError.new("wrong number of arguments (#{args.size} for 1)") if args.size != 1
589
+
590
+ assert_type args.first, :Color
591
+ Sass::Script::Number.new(args.first.alpha)
586
592
  end
587
593
  declare :alpha, [:color]
588
594
 
@@ -595,6 +601,7 @@ module Sass::Script
595
601
  # @see #transparentize
596
602
  # @raise [ArgumentError] If `color` isn't a color
597
603
  def opacity(color)
604
+ return Sass::Script::String.new("opacity(#{color})") if color.is_a?(Sass::Script::Number)
598
605
  assert_type color, :Color
599
606
  Sass::Script::Number.new(color.alpha)
600
607
  end
@@ -685,16 +692,21 @@ module Sass::Script
685
692
  # @example
686
693
  # saturate(hsl(120, 30%, 90%), 20%) => hsl(120, 50%, 90%)
687
694
  # saturate(#855, 20%) => #9e3f3f
688
- # @param color [Color]
689
- # @param amount [Number]
690
- # @return [Color]
691
- # @see #desaturate
692
- # @raise [ArgumentError] If `color` isn't a color,
693
- # or `number` isn't a number between 0% and 100%
694
- def saturate(color, amount)
695
+ # @overload saturate(color, amount)
696
+ # @param color [Color]
697
+ # @param amount [Number]
698
+ # @return [Color]
699
+ # @see #desaturate
700
+ # @raise [ArgumentError] If `color` isn't a color,
701
+ # or `number` isn't a number between 0% and 100%
702
+ def saturate(color, amount = nil)
703
+ # Support the filter effects definition of saturate.
704
+ # https://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html
705
+ return Sass::Script::String.new("saturate(#{color})") if amount.nil?
695
706
  _adjust(color, amount, :saturation, 0..100, :+, "%")
696
707
  end
697
708
  declare :saturate, [:color, :amount]
709
+ declare :saturate, [:amount]
698
710
 
699
711
  # Makes a color less saturated.
700
712
  # Takes a color and an amount between 0% and 100%,
@@ -995,21 +1007,13 @@ module Sass::Script
995
1007
  declare :mix, [:color_1, :color_2]
996
1008
  declare :mix, [:color_1, :color_2, :weight]
997
1009
 
998
- # @overload grayscale(color)
999
- # Converts a color to grayscale.
1000
- # This is identical to `desaturate(color, 100%)`.
1001
- #
1002
- # @param color [Color]
1003
- # @return [Color]
1004
- # @raise [ArgumentError] if `color` isn't a color
1005
- # @see #desaturate
1006
- # @overload grayscale(number)
1007
- # Returns an unquoted string `grayscale(number)`, as though the function
1008
- # were not defined. This is for the `grayscale` function used in
1009
- # `-webkit-filter`.
1010
+ # Converts a color to grayscale.
1011
+ # This is identical to `desaturate(color, 100%)`.
1010
1012
  #
1011
- # @param number [Number]
1012
- # @return [Sass::Script::String]
1013
+ # @param color [Color]
1014
+ # @return [Color]
1015
+ # @raise [ArgumentError] if `color` isn't a color
1016
+ # @see #desaturate
1013
1017
  def grayscale(color)
1014
1018
  return Sass::Script::String.new("grayscale(#{color})") if color.is_a?(Sass::Script::Number)
1015
1019
  desaturate color, Number.new(100)
@@ -1035,6 +1039,8 @@ module Sass::Script
1035
1039
  # @return [Color]
1036
1040
  # @raise [ArgumentError] if `color` isn't a color
1037
1041
  def invert(color)
1042
+ return Sass::Script::String.new("invert(#{color})") if color.is_a?(Sass::Script::Number)
1043
+
1038
1044
  assert_type color, :Color
1039
1045
  color.with(
1040
1046
  :red => (255 - color.red),
@@ -1328,14 +1334,14 @@ module Sass::Script
1328
1334
  # append(10px 20px, 30px) => 10px 20px 30px
1329
1335
  # append((blue, red), green) => blue, red, green
1330
1336
  # append(10px 20px, 30px 40px) => 10px 20px (30px 40px)
1331
- # join(10px, 20px, comma) => 10px, 20px
1332
- # join((blue, red), green, space) => blue red green
1333
- # @overload join(list, val, separator: auto)
1334
- # @param list1 [Literal] The first list to join
1335
- # @param list2 [Literal] The second list to join
1337
+ # append(10px, 20px, comma) => 10px, 20px
1338
+ # append((blue, red), green, space) => blue red green
1339
+ # @overload append(list, val, separator: auto)
1340
+ # @param list [Literal] The list to add the value to
1341
+ # @param val [Literal] The value to add to the end of the list
1336
1342
  # @param separator [String] How the list separator (comma or space) should be determined.
1337
1343
  # If this is `comma` or `space`, that is always the separator;
1338
- # if this is `auto` (the default), the separator is determined as explained above.
1344
+ # if this is `auto` (the default), the separator is the same as that used by the list.
1339
1345
  def append(list, val, separator = Sass::Script::String.new("auto"))
1340
1346
  assert_type separator, :String
1341
1347
  unless %w[auto space comma].include?(separator.value)
@@ -82,7 +82,7 @@ module Sass::Script
82
82
 
83
83
  literal2 = @operand2.perform(environment)
84
84
 
85
- if literal1.is_a?(Null) || literal2.is_a?(Null)
85
+ if (literal1.is_a?(Null) || literal2.is_a?(Null)) && @operator != :eq && @operator != :neq
86
86
  raise Sass::SyntaxError.new("Invalid null operation: \"#{literal1.inspect} #{@operator} #{literal2.inspect}\".")
87
87
  end
88
88
 
@@ -541,7 +541,7 @@ module Sass
541
541
  end
542
542
 
543
543
  # This is a nasty hack, and the only place in the parser
544
- # that requires backtracking.
544
+ # that requires a large amount of backtracking.
545
545
  # The reason is that we can't figure out if certain strings
546
546
  # are declarations or rulesets with fixed finite lookahead.
547
547
  # For example, "foo:bar baz baz baz..." could be either a property
@@ -631,19 +631,31 @@ module Sass
631
631
  end
632
632
 
633
633
  def combinator
634
- tok(PLUS) || tok(GREATER) || tok(TILDE)
634
+ tok(PLUS) || tok(GREATER) || tok(TILDE) || reference_combinator
635
+ end
636
+
637
+ def reference_combinator
638
+ return unless tok(/\//)
639
+ res = ['/']
640
+ ns, name = expr!(:qualified_name)
641
+ res << ns << '|' if ns
642
+ res << name << tok!(/\//)
643
+ res = res.flatten
644
+ res = res.join '' if res.all? {|e| e.is_a?(String)}
645
+ res
635
646
  end
636
647
 
637
648
  def simple_selector_sequence
638
- # This allows for stuff like http://www.w3.org/TR/css3-animations/#keyframes-
649
+ # Returning expr by default allows for stuff like
650
+ # http://www.w3.org/TR/css3-animations/#keyframes-
639
651
  return expr(!:allow_var) unless e = element_name || id_selector ||
640
- class_selector || placeholder_selector || attrib || negation ||
641
- pseudo || parent_selector || interpolation_selector
652
+ class_selector || placeholder_selector || attrib || pseudo ||
653
+ parent_selector || interpolation_selector
642
654
  res = [e]
643
655
 
644
656
  # The tok(/\*/) allows the "E*" hack
645
657
  while v = id_selector || class_selector || placeholder_selector || attrib ||
646
- negation || pseudo || interpolation_selector ||
658
+ pseudo || interpolation_selector ||
647
659
  (tok(/\*/) && Selector::Universal.new(nil))
648
660
  res << v
649
661
  end
@@ -664,7 +676,7 @@ module Sass
664
676
  end
665
677
  end
666
678
 
667
- Selector::SimpleSequence.new(res)
679
+ Selector::SimpleSequence.new(res, tok(/!/))
668
680
  end
669
681
 
670
682
  def parent_selector
@@ -691,12 +703,8 @@ module Sass
691
703
  end
692
704
 
693
705
  def element_name
694
- return unless name = interp_ident || tok(/\*/) || (tok?(/\|/) && "")
695
- if tok(/\|/)
696
- @expected = "element name or *"
697
- ns = name
698
- name = interp_ident || tok!(/\*/)
699
- end
706
+ ns, name = qualified_name(:allow_star_name)
707
+ return unless ns || name
700
708
 
701
709
  if name == '*'
702
710
  Selector::Universal.new(merge(ns))
@@ -705,6 +713,15 @@ module Sass
705
713
  end
706
714
  end
707
715
 
716
+ def qualified_name(allow_star_name=false)
717
+ return unless name = interp_ident || tok(/\*/) || (tok?(/\|/) && "")
718
+ return nil, name unless tok(/\|/)
719
+
720
+ return name, expr!(:interp_ident) unless allow_star_name
721
+ @expected = "identifier or *"
722
+ return name, interp_ident || tok!(/\*/)
723
+ end
724
+
708
725
  def interpolation_selector
709
726
  return unless script = interpolation
710
727
  Selector::Interpolation.new(script)
@@ -727,9 +744,10 @@ module Sass
727
744
  val = interp_ident || expr!(:interp_string)
728
745
  ss
729
746
  end
747
+ flags = interp_ident || interp_string
730
748
  tok!(/\]/)
731
749
 
732
- Selector::Attribute.new(merge(name), merge(ns), op, merge(val))
750
+ Selector::Attribute.new(merge(name), merge(ns), op, merge(val), merge(flags))
733
751
  end
734
752
 
735
753
  def attrib_name!
@@ -756,32 +774,53 @@ module Sass
756
774
  name = expr!(:interp_ident)
757
775
  if tok(/\(/)
758
776
  ss
759
- arg = expr!(:pseudo_expr)
777
+ arg = expr!(:pseudo_arg)
778
+ while tok(/,/)
779
+ arg << ',' << str{ss}
780
+ arg.concat expr!(:pseudo_arg)
781
+ end
760
782
  tok!(/\)/)
761
783
  end
762
784
  Selector::Pseudo.new(s == ':' ? :class : :element, merge(name), merge(arg))
763
785
  end
764
786
 
787
+ def pseudo_arg
788
+ # In the CSS spec, every pseudo-class/element either takes a pseudo
789
+ # expression or a selector comma sequence as an argument. However, we
790
+ # don't want to have to know which takes which, so we handle both at
791
+ # once.
792
+ #
793
+ # However, there are some ambiguities between the two. For instance, "n"
794
+ # could start a pseudo expression like "n+1", or it could start a
795
+ # selector like "n|m". In order to handle this, we must regrettably
796
+ # backtrack.
797
+ expr, sel = nil
798
+ pseudo_err = catch_error do
799
+ expr = pseudo_expr
800
+ next if tok?(/[,)]/)
801
+ expr = nil
802
+ expected '")"'
803
+ end
804
+
805
+ return expr if expr
806
+ sel_err = catch_error {sel = selector}
807
+ return sel if sel
808
+ rethrow pseudo_err if pseudo_err
809
+ rethrow sel_err if sel_err
810
+ return
811
+ end
812
+
765
813
  def pseudo_expr
766
- return unless e = tok(PLUS) || tok(/-/) || tok(NUMBER) ||
814
+ return unless e = tok(PLUS) || tok(/[-*]/) || tok(NUMBER) ||
767
815
  interp_string || tok(IDENT) || interpolation
768
816
  res = [e, str{ss}]
769
- while e = tok(PLUS) || tok(/-/) || tok(NUMBER) ||
817
+ while e = tok(PLUS) || tok(/[-*]/) || tok(NUMBER) ||
770
818
  interp_string || tok(IDENT) || interpolation
771
819
  res << e << str{ss}
772
820
  end
773
821
  res
774
822
  end
775
823
 
776
- def negation
777
- return unless name = tok(NOT) || tok(ANY)
778
- ss
779
- @expected = "selector"
780
- sel = selector_comma_sequence
781
- tok!(/\)/)
782
- Selector::SelectorPseudoClass.new(name[1...-1], sel)
783
- end
784
-
785
824
  def declaration
786
825
  # This allows the "*prop: val", ":prop: val", and ".prop: val" hacks
787
826
  if s = tok(/[:\*\.]|\#(?!\{)/)
@@ -980,12 +1019,12 @@ MESSAGE
980
1019
  EXPR_NAMES = {
981
1020
  :media_query => "media query (e.g. print, screen, print and screen)",
982
1021
  :media_expr => "media expression (e.g. (min-device-width: 800px))",
983
- :pseudo_expr => "expression (e.g. fr, 2n+1)",
1022
+ :pseudo_arg => "expression (e.g. fr, 2n+1)",
984
1023
  :interp_ident => "identifier",
985
1024
  :interp_name => "identifier",
1025
+ :qualified_name => "identifier",
986
1026
  :expr => "expression (e.g. 1px, bold)",
987
1027
  :_selector => "selector",
988
- :selector_comma_sequence => "selector",
989
1028
  :simple_selector_sequence => "selector",
990
1029
  :import_arg => "file to import (string or url())",
991
1030
  :moz_document_function => "matching function (e.g. url-prefix(), domain())",
@@ -1041,7 +1080,7 @@ MESSAGE
1041
1080
  pos = @scanner.pos
1042
1081
  line = @line
1043
1082
  expected = @expected
1044
- if catch(:_sass_parser_error, &block)
1083
+ if catch(:_sass_parser_error) {yield; false}
1045
1084
  @scanner.pos = pos
1046
1085
  @line = line
1047
1086
  @expected = expected
@@ -309,15 +309,22 @@ module Sass
309
309
  # @return [Array<String, Sass::Script::Node>]
310
310
  attr_reader :value
311
311
 
312
+ # Flags for the attribute selector (e.g. `i`).
313
+ #
314
+ # @return [Array<String, Sass::Script::Node>]
315
+ attr_reader :flags
316
+
312
317
  # @param name [Array<String, Sass::Script::Node>] The attribute name
313
318
  # @param namespace [Array<String, Sass::Script::Node>, nil] See \{#namespace}
314
319
  # @param operator [String] The matching operator, e.g. `"="` or `"^="`
315
320
  # @param value [Array<String, Sass::Script::Node>] See \{#value}
316
- def initialize(name, namespace, operator, value)
321
+ # @param value [Array<String, Sass::Script::Node>] See \{#flags}
322
+ def initialize(name, namespace, operator, value, flags)
317
323
  @name = name
318
324
  @namespace = namespace
319
325
  @operator = operator
320
326
  @value = value
327
+ @flags = flags
321
328
  end
322
329
 
323
330
  # @see Selector#to_a
@@ -326,6 +333,7 @@ module Sass
326
333
  res.concat(@namespace) << "|" if @namespace
327
334
  res.concat @name
328
335
  (res << @operator).concat @value if @value
336
+ (res << " ").concat @flags if @flags
329
337
  res << "]"
330
338
  end
331
339
 
@@ -24,17 +24,16 @@ module Sass
24
24
  filename
25
25
  end
26
26
 
27
- # The array of {SimpleSequence simple selector sequences}, operators, and newlines.
28
- # The operators are strings such as `"+"` and `">"`
29
- # representing the corresponding CSS operators.
30
- # Newlines are also newline strings;
31
- # these aren't semantically relevant,
32
- # but they do affect formatting.
27
+ # The array of {SimpleSequence simple selector sequences}, operators, and
28
+ # newlines. The operators are strings such as `"+"` and `">"` representing
29
+ # the corresponding CSS operators, or interpolated SassScript. Newlines
30
+ # are also newline strings; these aren't semantically relevant, but they
31
+ # do affect formatting.
33
32
  #
34
- # @return [Array<SimpleSequence, String>]
33
+ # @return [Array<SimpleSequence, String|Array<Sass::Tree::Node, String>>]
35
34
  attr_reader :members
36
35
 
37
- # @param seqs_and_ops [Array<SimpleSequence, String>] See \{#members}
36
+ # @param seqs_and_ops [Array<SimpleSequence, String|Array<Sass::Tree::Node, String>>] See \{#members}
38
37
  def initialize(seqs_and_ops)
39
38
  @members = seqs_and_ops
40
39
  end
@@ -54,7 +53,7 @@ module Sass
54
53
  end
55
54
  members = []
56
55
  members << nl if nl
57
- members << SimpleSequence.new([Parent.new])
56
+ members << SimpleSequence.new([Parent.new], false)
58
57
  members += @members
59
58
  end
60
59
 
@@ -198,7 +197,7 @@ module Sass
198
197
  diff += fin.map {|sel| sel.is_a?(Array) ? sel : [sel]}
199
198
  diff.reject! {|c| c.empty?}
200
199
 
201
- Sass::Util.paths(diff).map {|p| p.flatten}
200
+ Sass::Util.paths(diff).map {|p| p.flatten}.reject {|p| path_has_two_subjects?(p)}
202
201
  end
203
202
 
204
203
  # Extracts initial selector combinators (`"+"`, `">"`, `"~"`, and `"\n"`)
@@ -272,7 +271,7 @@ module Sass
272
271
  elsif sel2.superselector?(sel1)
273
272
  res.unshift sel1, '~'
274
273
  else
275
- merged = sel1.unify(sel2.members)
274
+ merged = sel1.unify(sel2.members, sel2.subject?)
276
275
  res.unshift [
277
276
  [sel1, '~', sel2, '~'],
278
277
  [sel2, '~', sel1, '~'],
@@ -289,7 +288,7 @@ module Sass
289
288
  if tilde_sel.superselector?(plus_sel)
290
289
  res.unshift plus_sel, '+'
291
290
  else
292
- merged = plus_sel.unify(tilde_sel.members)
291
+ merged = plus_sel.unify(tilde_sel.members, tilde_sel.subject?)
293
292
  res.unshift [
294
293
  [tilde_sel, '~', plus_sel, '+'],
295
294
  ([merged, '+'] if merged)
@@ -302,7 +301,7 @@ module Sass
302
301
  res.unshift sel1, op1
303
302
  seq2.push sel2, op2
304
303
  elsif op1 == op2
305
- return unless merged = sel1.unify(sel2.members)
304
+ return unless merged = sel1.unify(sel2.members, sel2.subject?)
306
305
  res.unshift merged, op1
307
306
  else
308
307
  # Unknown selector combinators can't be unified
@@ -422,7 +421,7 @@ module Sass
422
421
  # @param seq2 [Array<SimpleSequence or String>]
423
422
  # @return [Boolean]
424
423
  def parent_superselector?(seq1, seq2)
425
- base = Sass::Selector::SimpleSequence.new([Sass::Selector::Placeholder.new('<temp>')])
424
+ base = Sass::Selector::SimpleSequence.new([Sass::Selector::Placeholder.new('<temp>')], false)
426
425
  _superselector?(seq1 + [base], seq2 + [base])
427
426
  end
428
427
 
@@ -467,6 +466,17 @@ module Sass
467
466
 
468
467
  private
469
468
 
469
+ def path_has_two_subjects?(path)
470
+ subject = false
471
+ path.each do |sseq_or_op|
472
+ next unless sseq_or_op.is_a?(SimpleSequence)
473
+ next unless sseq_or_op.subject?
474
+ return true if subject
475
+ subject = true
476
+ end
477
+ false
478
+ end
479
+
470
480
  def _sources(seq)
471
481
  s = Set.new
472
482
  seq.map {|sseq_or_op| s.merge sseq_or_op.sources if sseq_or_op.is_a?(SimpleSequence)}
@@ -26,6 +26,9 @@ module Sass
26
26
  # @return {Set<Sequence>}
27
27
  attr_accessor :sources
28
28
 
29
+ # @see \{#subject?}
30
+ attr_writer :subject
31
+
29
32
  # Returns the element or universal selector in this sequence,
30
33
  # if it exists.
31
34
  #
@@ -41,10 +44,21 @@ module Sass
41
44
  @rest ||= Set.new(base ? members[1..-1] : members)
42
45
  end
43
46
 
47
+ # Whether or not this compound selector is the subject of the parent
48
+ # selector; that is, whether it is prepended with `$` and represents the
49
+ # actual element that will be selected.
50
+ #
51
+ # @return [Boolean]
52
+ def subject?
53
+ @subject
54
+ end
55
+
44
56
  # @param selectors [Array<Simple>] See \{#members}
57
+ # @param subject [Boolean] See \{#subject?}
45
58
  # @param sources [Set<Sequence>]
46
- def initialize(selectors, sources = Set.new)
59
+ def initialize(selectors, subject, sources = Set.new)
47
60
  @members = selectors
61
+ @subject = subject
48
62
  @sources = sources
49
63
  end
50
64
 
@@ -66,7 +80,7 @@ module Sass
66
80
  end
67
81
 
68
82
  super_seq.members[0...-1] +
69
- [SimpleSequence.new(super_seq.members.last.members + @members[1..-1])]
83
+ [SimpleSequence.new(super_seq.members.last.members + @members[1..-1], subject?)]
70
84
  end
71
85
 
72
86
  # Non-destrucively extends this selector with the extensions specified in a hash
@@ -88,7 +102,7 @@ module Sass
88
102
  # seq is A, sels is B, and self is C
89
103
 
90
104
  self_without_sel = self.members - sels
91
- next unless unified = seq.members.last.unify(self_without_sel)
105
+ next unless unified = seq.members.last.unify(self_without_sel, subject?)
92
106
  next if group.map {|e, _| check_directives_match!(e, parent_directives)}.none?
93
107
  new_seq = Sequence.new(seq.members[0...-1] + [unified])
94
108
  new_seq.add_sources!(sources + [seq])
@@ -103,6 +117,7 @@ module Sass
103
117
  # that matches both this selector and the input selector.
104
118
  #
105
119
  # @param sels [Array<Simple>] A {SimpleSequence}'s {SimpleSequence#members members array}
120
+ # @param subject [Boolean] Whether the {SimpleSequence} being merged is a subject.
106
121
  # @return [SimpleSequence, nil] A {SimpleSequence} matching both `sels` and this selector,
107
122
  # or `nil` if this is impossible (e.g. unifying `#foo` and `#bar`)
108
123
  # @raise [Sass::SyntaxError] If this selector cannot be unified.
@@ -111,12 +126,12 @@ module Sass
111
126
  # Since these selectors should be resolved
112
127
  # by the time extension and unification happen,
113
128
  # this exception will only ever be raised as a result of programmer error
114
- def unify(sels)
129
+ def unify(sels, other_subject)
115
130
  return unless sseq = members.inject(sels) do |sseq, sel|
116
131
  return unless sseq
117
132
  sel.unify(sseq)
118
133
  end
119
- SimpleSequence.new(sseq)
134
+ SimpleSequence.new(sseq, other_subject || subject?)
120
135
  end
121
136
 
122
137
  # Returns whether or not this selector matches all elements
@@ -133,7 +148,9 @@ module Sass
133
148
 
134
149
  # @see Simple#to_a
135
150
  def to_a
136
- @members.map {|sel| sel.to_a}.flatten
151
+ res = @members.map {|sel| sel.to_a}.flatten
152
+ res << '!' if subject?
153
+ res
137
154
  end
138
155
 
139
156
  # Returns a string representation of the sequence.
@@ -178,7 +195,8 @@ WARNING
178
195
  end
179
196
 
180
197
  def _eql?(other)
181
- other.base.eql?(self.base) && Sass::Util.set_eql?(other.rest, self.rest)
198
+ other.base.eql?(self.base) && Sass::Util.set_eql?(other.rest, self.rest) &&
199
+ other.subject? == self.subject?
182
200
  end
183
201
  end
184
202
  end
@@ -214,7 +214,8 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
214
214
  rule.resolved_rules = Sass::Selector::CommaSequence.new(
215
215
  [Sass::Selector::Sequence.new(
216
216
  [Sass::Selector::SimpleSequence.new(
217
- [Sass::Selector::Element.new(k.to_s.gsub(/[^\w-]/, "\\\\\\0"), nil)])
217
+ [Sass::Selector::Element.new(k.to_s.gsub(/[^\w-]/, "\\\\\\0"), nil)],
218
+ false)
218
219
  ])
219
220
  ])
220
221
  prop = Sass::Tree::PropNode.new([""], Sass::Script::String.new(''), :new)
@@ -462,9 +462,9 @@ module Sass
462
462
  # Like `Dir.glob`, but works with backslash-separated paths on Windows.
463
463
  #
464
464
  # @param path [String]
465
- def glob(path)
465
+ def glob(path, &block)
466
466
  path = path.gsub('\\', '/') if windows?
467
- Dir.glob(path)
467
+ Dir.glob(path, &block)
468
468
  end
469
469
 
470
470
  ## Cross-Ruby-Version Compatibility
@@ -74,10 +74,17 @@ SCSS
74
74
  assert_renders <<SASS, <<SCSS
75
75
  foo \#{$bar + "baz"}.bip
76
76
  baz: bang
77
+
78
+ foo /\#{$bar + "baz"}/ .bip
79
+ baz: bang
77
80
  SASS
78
81
  foo \#{$bar + "baz"}.bip {
79
82
  baz: bang;
80
83
  }
84
+
85
+ foo /\#{$bar + "baz"}/ .bip {
86
+ baz: bang;
87
+ }
81
88
  SCSS
82
89
  end
83
90
 
@@ -1403,6 +1410,28 @@ SASS
1403
1410
  SCSS
1404
1411
  end
1405
1412
 
1413
+ def test_reference_selector
1414
+ assert_renders(<<SASS, <<SCSS)
1415
+ foo /bar|baz/ bang
1416
+ a: b
1417
+ SASS
1418
+ foo /bar|baz/ bang {
1419
+ a: b;
1420
+ }
1421
+ SCSS
1422
+ end
1423
+
1424
+ def test_subject
1425
+ assert_renders(<<SASS, <<SCSS)
1426
+ foo bar! baz
1427
+ a: b
1428
+ SASS
1429
+ foo bar! baz {
1430
+ a: b;
1431
+ }
1432
+ SCSS
1433
+ end
1434
+
1406
1435
  def test_placeholder_interoplation_conversion
1407
1436
  assert_renders(<<SASS, <<SCSS)
1408
1437
  $foo: foo
@@ -1523,7 +1552,6 @@ foo bar {
1523
1552
  SCSS
1524
1553
  end
1525
1554
 
1526
-
1527
1555
  ## Regression Tests
1528
1556
 
1529
1557
  def test_empty_lists
@@ -237,6 +237,32 @@ SASS
237
237
  CSS
238
238
  end
239
239
 
240
+ def test_subject
241
+ assert_equal(<<SASS, css2sass(<<CSS))
242
+ .foo
243
+ .bar!
244
+ .baz
245
+ a: b
246
+ .bip
247
+ c: d
248
+ .bar .bonk
249
+ e: f
250
+
251
+ .flip!
252
+ &.bar
253
+ a: b
254
+ &.baz
255
+ c: d
256
+ SASS
257
+ .foo .bar! .baz {a: b;}
258
+ .foo .bar! .bip {c: d;}
259
+ .foo .bar .bonk {e: f;}
260
+
261
+ .flip.bar! {a: b;}
262
+ .flip.baz! {c: d;}
263
+ CSS
264
+ end
265
+
240
266
  # Regressions
241
267
 
242
268
  def test_nesting_within_media
@@ -2716,7 +2716,7 @@ SASS
2716
2716
  end
2717
2717
 
2718
2718
  def test_comment_like_selector
2719
- assert_raise_message(Sass::SyntaxError, 'Invalid CSS after "": expected selector, was "/ foo"') {render(<<SASS)}
2719
+ assert_raise_message(Sass::SyntaxError, 'Invalid CSS after "/": expected identifier, was " foo"') {render(<<SASS)}
2720
2720
  / foo
2721
2721
  a: b
2722
2722
  SASS
@@ -414,6 +414,12 @@ SCSS
414
414
  assert_extends 'a ~ b c .c1', 'b c .c2 {@extend .c1}', 'a ~ b c .c1, a ~ b c .c2'
415
415
  end
416
416
 
417
+ def test_nested_extender_doesnt_find_common_selectors_around_reference_selector
418
+ assert_extends 'a /for/ b c .c1', 'a c .c2 {@extend .c1}', 'a /for/ b c .c1, a /for/ b a c .c2, a a /for/ b c .c2'
419
+ assert_extends 'a /for/ b c .c1', 'a b .c2 {@extend .c1}', 'a /for/ b c .c1, a a /for/ b c .c2'
420
+ assert_extends 'a /for/ b c .c1', 'b c .c2 {@extend .c1}', 'a /for/ b c .c1, a /for/ b c .c2'
421
+ end
422
+
417
423
  def test_nested_extender_with_early_child_selectors_doesnt_subseq_them
418
424
  assert_extends('.bip > .bap .foo', '.grip > .bap .bar {@extend .foo}',
419
425
  '.bip > .bap .foo, .bip > .bap .grip > .bap .bar, .grip > .bap .bip > .bap .bar')
@@ -443,7 +449,9 @@ CSS
443
449
  > .baz {@extend .bar}
444
450
  }
445
451
  SCSS
452
+ end
446
453
 
454
+ def test_nested_extender_with_early_child_selectors_doesnt_subseq_them
447
455
  assert_equal <<CSS, render(<<SCSS)
448
456
  .foo .bar, .foo .bip > .baz {
449
457
  a: b; }
@@ -1008,6 +1016,64 @@ CSS
1008
1016
  SCSS
1009
1017
  end
1010
1018
 
1019
+ def test_extend_with_subject_transfers_subject_to_extender
1020
+ assert_equal(<<CSS, render(<<SCSS))
1021
+ foo bar! baz, foo .bip .bap! baz, .bip foo .bap! baz {
1022
+ a: b; }
1023
+ CSS
1024
+ foo bar! baz {a: b}
1025
+ .bip .bap {@extend bar}
1026
+ SCSS
1027
+
1028
+ assert_equal(<<CSS, render(<<SCSS))
1029
+ foo.x bar.y! baz.z, foo.x .bip bar.bap! baz.z, .bip foo.x bar.bap! baz.z {
1030
+ a: b; }
1031
+ CSS
1032
+ foo.x bar.y! baz.z {a: b}
1033
+ .bip .bap {@extend .y}
1034
+ SCSS
1035
+ end
1036
+
1037
+ def test_extend_with_subject_retains_subject_on_target
1038
+ assert_equal(<<CSS, render(<<SCSS))
1039
+ .foo! .bar, .foo! .bip .bap, .bip .foo! .bap {
1040
+ a: b; }
1041
+ CSS
1042
+ .foo! .bar {a: b}
1043
+ .bip .bap {@extend .bar}
1044
+ SCSS
1045
+ end
1046
+
1047
+ def test_extend_with_subject_transfers_subject_to_target
1048
+ assert_equal(<<CSS, render(<<SCSS))
1049
+ a.foo .bar, .bip a.bap! .bar {
1050
+ a: b; }
1051
+ CSS
1052
+ a.foo .bar {a: b}
1053
+ .bip .bap! {@extend .foo}
1054
+ SCSS
1055
+ end
1056
+
1057
+ def test_extend_with_subject_retains_subject_on_extender
1058
+ assert_equal(<<CSS, render(<<SCSS))
1059
+ .foo .bar, .foo .bip! .bap, .bip! .foo .bap {
1060
+ a: b; }
1061
+ CSS
1062
+ .foo .bar {a: b}
1063
+ .bip! .bap {@extend .bar}
1064
+ SCSS
1065
+ end
1066
+
1067
+ def test_extend_with_subject_fails_with_conflicting_subject
1068
+ assert_equal(<<CSS, render(<<SCSS))
1069
+ x! .bar {
1070
+ a: b; }
1071
+ CSS
1072
+ x! .bar {a: b}
1073
+ y! .bap {@extend .bar}
1074
+ SCSS
1075
+ end
1076
+
1011
1077
  # Regression Tests
1012
1078
 
1013
1079
  def test_newline_near_combinator
@@ -336,6 +336,18 @@ class SassFunctionTest < Test::Unit::TestCase
336
336
  assert_error_message("12 is not a color for `alpha'", "alpha(12)")
337
337
  end
338
338
 
339
+ def test_opacity
340
+ assert_equal("1", evaluate("opacity(#123456)"))
341
+ assert_equal("0.34", evaluate("opacity(rgba(0, 1, 2, 0.34))"))
342
+ assert_equal("0", evaluate("opacity(hsla(0, 1, 2, 0))"))
343
+ assert_equal("0", evaluate("opacity($color: hsla(0, 1, 2, 0))"))
344
+ assert_equal("opacity(20%)", evaluate("opacity(20%)"))
345
+ end
346
+
347
+ def test_opacity_exception
348
+ assert_error_message("\"foo\" is not a color for `opacity'", "opacity(foo)")
349
+ end
350
+
339
351
  def test_opacify
340
352
  assert_equal("rgba(0, 0, 0, 0.75)", evaluate("opacify(rgba(0, 0, 0, 0.5), 0.25)"))
341
353
  assert_equal("rgba(0, 0, 0, 0.3)", evaluate("opacify(rgba(0, 0, 0, 0.2), 0.1)"))
@@ -435,6 +447,7 @@ class SassFunctionTest < Test::Unit::TestCase
435
447
  assert_equal("#88aa88", evaluate("saturate(#8a8, 0%)"))
436
448
  assert_equal("rgba(158, 63, 63, 0.5)", evaluate("saturate(rgba(136, 85, 85, 0.5), 20%)"))
437
449
  assert_equal("rgba(158, 63, 63, 0.5)", evaluate("saturate($color: rgba(136, 85, 85, 0.5), $amount: 20%)"))
450
+ assert_equal("saturate(50%)", evaluate("saturate(50%)"))
438
451
  end
439
452
 
440
453
  def test_saturate_tests_bounds
@@ -828,6 +841,7 @@ class SassFunctionTest < Test::Unit::TestCase
828
841
  def test_invert
829
842
  assert_equal("#112233", evaluate("invert(#edc)"))
830
843
  assert_equal("rgba(245, 235, 225, 0.5)", evaluate("invert(rgba(10, 20, 30, 0.5))"))
844
+ assert_equal("invert(20%)", evaluate("invert(20%)"))
831
845
  end
832
846
 
833
847
  def test_invert_tests_types
@@ -385,6 +385,16 @@ SASS
385
385
  assert_equal "false", resolve('(1 (2 3)) == (1 2 3)')
386
386
  assert_equal "false", resolve('((1, 2) (3, 4)) == (1, 2 3, 4)')
387
387
  assert_equal "false", resolve('(1 2 3) == (1, 2, 3)')
388
+
389
+ assert_equal "true", resolve('null == null')
390
+ assert_equal "false", resolve('"null" == null')
391
+ assert_equal "false", resolve('0 == null')
392
+ assert_equal "false", resolve('() == null')
393
+
394
+ assert_equal "false", resolve('null != null')
395
+ assert_equal "true", resolve('"null" != null')
396
+ assert_equal "true", resolve('0 != null')
397
+ assert_equal "true", resolve('() != null')
388
398
  end
389
399
 
390
400
  def test_operation_precedence
@@ -650,91 +650,140 @@ SCSS
650
650
 
651
651
  ## Selectors
652
652
 
653
- # Taken from http://www.w3.org/TR/css3-selectors/#selectors
653
+ # Taken from http://dev.w3.org/csswg/selectors4/#overview
654
654
  def test_summarized_selectors
655
655
  assert_selector_parses('*')
656
656
  assert_selector_parses('E')
657
+ assert_selector_parses('E:not(s)')
658
+ assert_selector_parses('E:not(s1, s2)')
659
+ assert_selector_parses('E:matches(s1, s2)')
660
+ assert_selector_parses('E.warning')
661
+ assert_selector_parses('E#myid')
657
662
  assert_selector_parses('E[foo]')
658
663
  assert_selector_parses('E[foo="bar"]')
664
+ assert_selector_parses('E[foo="bar" i]')
659
665
  assert_selector_parses('E[foo~="bar"]')
660
666
  assert_selector_parses('E[foo^="bar"]')
661
667
  assert_selector_parses('E[foo$="bar"]')
662
668
  assert_selector_parses('E[foo*="bar"]')
663
669
  assert_selector_parses('E[foo|="en"]')
664
- assert_selector_parses('E:root')
665
- assert_selector_parses('E:nth-child(n)')
666
- assert_selector_parses('E:nth-last-child(n)')
667
- assert_selector_parses('E:nth-of-type(n)')
668
- assert_selector_parses('E:nth-last-of-type(n)')
669
- assert_selector_parses('E:first-child')
670
- assert_selector_parses('E:last-child')
671
- assert_selector_parses('E:first-of-type')
672
- assert_selector_parses('E:last-of-type')
673
- assert_selector_parses('E:only-child')
674
- assert_selector_parses('E:only-of-type')
675
- assert_selector_parses('E:empty')
670
+ assert_selector_parses('E:dir(ltr)')
671
+ assert_selector_parses('E:lang(fr)')
672
+ assert_selector_parses('E:lang(zh, *-hant)')
673
+ assert_selector_parses('E:any-link')
676
674
  assert_selector_parses('E:link')
677
675
  assert_selector_parses('E:visited')
676
+ assert_selector_parses('E:local-link')
677
+ assert_selector_parses('E:local-link(0)')
678
+ assert_selector_parses('E:target')
679
+ assert_selector_parses('E:scope')
680
+ assert_selector_parses('E:current')
681
+ assert_selector_parses('E:current(s)')
682
+ assert_selector_parses('E:past')
683
+ assert_selector_parses('E:future')
678
684
  assert_selector_parses('E:active')
679
685
  assert_selector_parses('E:hover')
680
686
  assert_selector_parses('E:focus')
681
- assert_selector_parses('E:target')
682
- assert_selector_parses('E:lang(fr)')
683
687
  assert_selector_parses('E:enabled')
684
688
  assert_selector_parses('E:disabled')
685
689
  assert_selector_parses('E:checked')
686
- assert_selector_parses('E::first-line')
687
- assert_selector_parses('E::first-letter')
688
- assert_selector_parses('E::before')
689
- assert_selector_parses('E::after')
690
- assert_selector_parses('E.warning')
691
- assert_selector_parses('E#myid')
692
- assert_selector_parses('E:not(s)')
690
+ assert_selector_parses('E:indeterminate')
691
+ assert_selector_parses('E:default')
692
+ assert_selector_parses('E:in-range')
693
+ assert_selector_parses('E:out-of-range')
694
+ assert_selector_parses('E:required')
695
+ assert_selector_parses('E:optional')
696
+ assert_selector_parses('E:read-only')
697
+ assert_selector_parses('E:read-write')
698
+ assert_selector_parses('E:root')
699
+ assert_selector_parses('E:empty')
700
+ assert_selector_parses('E:first-child')
701
+ assert_selector_parses('E:nth-child(n)')
702
+ assert_selector_parses('E:last-child')
703
+ assert_selector_parses('E:nth-last-child(n)')
704
+ assert_selector_parses('E:only-child')
705
+ assert_selector_parses('E:first-of-type')
706
+ assert_selector_parses('E:nth-of-type(n)')
707
+ assert_selector_parses('E:last-of-type')
708
+ assert_selector_parses('E:nth-last-of-type(n)')
709
+ assert_selector_parses('E:only-of-type')
710
+ assert_selector_parses('E:nth-match(n of selector)')
711
+ assert_selector_parses('E:nth-last-match(n of selector)')
712
+ assert_selector_parses('E:column(selector)')
713
+ assert_selector_parses('E:nth-column(n)')
714
+ assert_selector_parses('E:nth-last-column(n)')
693
715
  assert_selector_parses('E F')
694
716
  assert_selector_parses('E > F')
695
717
  assert_selector_parses('E + F')
696
718
  assert_selector_parses('E ~ F')
719
+ assert_selector_parses('E /foo/ F')
720
+ assert_selector_parses('E! > F')
721
+
722
+ assert_selector_parses('E /ns|foo/ F')
723
+ assert_selector_parses('E /*|foo/ F')
697
724
  end
698
725
 
699
- # Taken from http://www.w3.org/TR/css3-selectors/#selectors,
700
- # but without the element names
701
- def test_lonely_selectors
726
+ # Taken from http://dev.w3.org/csswg/selectors4/#overview, but without element
727
+ # names.
728
+ def test_summarized_selectors
729
+ assert_selector_parses(':not(s)')
730
+ assert_selector_parses(':not(s1, s2)')
731
+ assert_selector_parses(':matches(s1, s2)')
732
+ assert_selector_parses('.warning')
733
+ assert_selector_parses('#myid')
702
734
  assert_selector_parses('[foo]')
703
735
  assert_selector_parses('[foo="bar"]')
736
+ assert_selector_parses('[foo="bar" i]')
704
737
  assert_selector_parses('[foo~="bar"]')
705
738
  assert_selector_parses('[foo^="bar"]')
706
739
  assert_selector_parses('[foo$="bar"]')
707
740
  assert_selector_parses('[foo*="bar"]')
708
741
  assert_selector_parses('[foo|="en"]')
709
- assert_selector_parses(':root')
710
- assert_selector_parses(':nth-child(n)')
711
- assert_selector_parses(':nth-last-child(n)')
712
- assert_selector_parses(':nth-of-type(n)')
713
- assert_selector_parses(':nth-last-of-type(n)')
714
- assert_selector_parses(':first-child')
715
- assert_selector_parses(':last-child')
716
- assert_selector_parses(':first-of-type')
717
- assert_selector_parses(':last-of-type')
718
- assert_selector_parses(':only-child')
719
- assert_selector_parses(':only-of-type')
720
- assert_selector_parses(':empty')
742
+ assert_selector_parses(':dir(ltr)')
743
+ assert_selector_parses(':lang(fr)')
744
+ assert_selector_parses(':lang(zh, *-hant)')
745
+ assert_selector_parses(':any-link')
721
746
  assert_selector_parses(':link')
722
747
  assert_selector_parses(':visited')
748
+ assert_selector_parses(':local-link')
749
+ assert_selector_parses(':local-link(0)')
750
+ assert_selector_parses(':target')
751
+ assert_selector_parses(':scope')
752
+ assert_selector_parses(':current')
753
+ assert_selector_parses(':current(s)')
754
+ assert_selector_parses(':past')
755
+ assert_selector_parses(':future')
723
756
  assert_selector_parses(':active')
724
757
  assert_selector_parses(':hover')
725
758
  assert_selector_parses(':focus')
726
- assert_selector_parses(':target')
727
- assert_selector_parses(':lang(fr)')
728
759
  assert_selector_parses(':enabled')
729
760
  assert_selector_parses(':disabled')
730
761
  assert_selector_parses(':checked')
731
- assert_selector_parses('::first-line')
732
- assert_selector_parses('::first-letter')
733
- assert_selector_parses('::before')
734
- assert_selector_parses('::after')
735
- assert_selector_parses('.warning')
736
- assert_selector_parses('#myid')
737
- assert_selector_parses(':not(s)')
762
+ assert_selector_parses(':indeterminate')
763
+ assert_selector_parses(':default')
764
+ assert_selector_parses(':in-range')
765
+ assert_selector_parses(':out-of-range')
766
+ assert_selector_parses(':required')
767
+ assert_selector_parses(':optional')
768
+ assert_selector_parses(':read-only')
769
+ assert_selector_parses(':read-write')
770
+ assert_selector_parses(':root')
771
+ assert_selector_parses(':empty')
772
+ assert_selector_parses(':first-child')
773
+ assert_selector_parses(':nth-child(n)')
774
+ assert_selector_parses(':last-child')
775
+ assert_selector_parses(':nth-last-child(n)')
776
+ assert_selector_parses(':only-child')
777
+ assert_selector_parses(':first-of-type')
778
+ assert_selector_parses(':nth-of-type(n)')
779
+ assert_selector_parses(':last-of-type')
780
+ assert_selector_parses(':nth-last-of-type(n)')
781
+ assert_selector_parses(':only-of-type')
782
+ assert_selector_parses(':nth-match(n of selector)')
783
+ assert_selector_parses(':nth-last-match(n of selector)')
784
+ assert_selector_parses(':column(selector)')
785
+ assert_selector_parses(':nth-column(n)')
786
+ assert_selector_parses(':nth-last-column(n)')
738
787
  end
739
788
 
740
789
  def test_attribute_selectors_with_identifiers
@@ -771,36 +820,41 @@ CSS
771
820
  SCSS
772
821
  end
773
822
 
774
- def test_negation_selectors
775
- assert_selector_parses(':not(foo|bar)')
776
- assert_selector_parses(':not(*|bar)')
823
+ def test_selectors_containing_selectors
824
+ assert_selector_can_contain_selectors(':not(<sel>)')
825
+ assert_selector_can_contain_selectors(':current(<sel>)')
826
+ assert_selector_can_contain_selectors(':nth-match(n of <sel>)')
827
+ assert_selector_can_contain_selectors(':nth-last-match(n of <sel>)')
828
+ assert_selector_can_contain_selectors(':column(<sel>)')
829
+ assert_selector_can_contain_selectors(':-moz-any(<sel>)')
830
+ end
831
+
832
+ def assert_selector_can_contain_selectors(sel)
833
+ try = lambda {|subsel| assert_selector_parses(sel.gsub('<sel>', subsel))}
834
+
835
+ try['foo|bar']
836
+ try['*|bar']
777
837
 
778
- assert_selector_parses(':not(foo|*)')
779
- assert_selector_parses(':not(*|*)')
838
+ try['foo|*']
839
+ try['*|*']
780
840
 
781
- assert_selector_parses(':not(#blah)')
782
- assert_selector_parses(':not(.blah)')
841
+ try['#blah']
842
+ try['.blah']
783
843
 
784
- assert_selector_parses(':not([foo])')
785
- assert_selector_parses(':not([foo^="bar"])')
786
- assert_selector_parses(':not([baz|foo~="bar"])')
844
+ try['[foo]']
845
+ try['[foo^="bar"]']
846
+ try['[baz|foo~="bar"]']
787
847
 
788
- assert_selector_parses(':not(:hover)')
789
- assert_selector_parses(':not(:nth-child(2n + 3))')
848
+ try[':hover']
849
+ try[':nth-child(2n + 3)']
790
850
 
791
- # Not technically allowed, but what the heck
792
- assert_selector_parses(':not(:not(#foo))')
793
- assert_selector_parses(':not(a#foo.bar)')
794
- assert_selector_parses(':not(#foo .bar > baz)')
795
- assert_selector_parses(':not(h1, h2, h3)')
796
- end
851
+ try['h1, h2, h3']
852
+ try['#foo, bar, [baz]']
797
853
 
798
- def test_any_selector
799
- assert_selector_parses(':-moz-any(h1, h2, h3)')
800
- assert_selector_parses(':-moz-any(.foo)')
801
- assert_selector_parses(':-moz-any(foo bar, .baz > .bang)')
802
- assert_selector_parses(':-webkit-any(foo bar, .baz > .bang)')
803
- assert_selector_parses(':any(foo bar, .baz > .bang)')
854
+ # Not technically allowed for most selectors, but what the heck
855
+ try[':not(#foo)']
856
+ try['a#foo.bar']
857
+ try['#foo .bar > baz']
804
858
  end
805
859
 
806
860
  def test_namespaced_selectors
@@ -517,6 +517,22 @@ foo {
517
517
  SCSS
518
518
  end
519
519
 
520
+ def test_parent_selector_with_subject
521
+ assert_equal <<CSS, render(<<SCSS)
522
+ bar foo.baz! .bip {
523
+ a: b; }
524
+
525
+ bar foo bar.baz! .bip {
526
+ c: d; }
527
+ CSS
528
+ foo {
529
+ bar &.baz! .bip {a: b}}
530
+
531
+ foo bar {
532
+ bar &.baz! .bip {c: d}}
533
+ SCSS
534
+ end
535
+
520
536
  ## Namespace Properties
521
537
 
522
538
  def test_namespace_properties
@@ -871,6 +887,29 @@ div { -foo-\#{$a}-\#{$b}-foo: foo }
871
887
  SCSS
872
888
  end
873
889
 
890
+ def test_selector_interpolation_in_reference_combinator
891
+ assert_equal <<CSS, render(<<SCSS)
892
+ .foo /a/ .bar /b|c/ .baz {
893
+ a: b; }
894
+ CSS
895
+ $a: a;
896
+ $b: b;
897
+ $c: c;
898
+ .foo /\#{$a}/ .bar /\#{$b}|\#{$c}/ .baz {a: b}
899
+ SCSS
900
+ end
901
+
902
+ def test_parent_selector_with_parent_and_subject
903
+ assert_equal <<CSS, render(<<SCSS)
904
+ bar foo.baz! .bip {
905
+ c: d; }
906
+ CSS
907
+ $subject: "!";
908
+ foo {
909
+ bar &.baz\#{$subject} .bip {c: d}}
910
+ SCSS
911
+ end
912
+
874
913
  def test_basic_prop_name_interpolation
875
914
  assert_equal <<CSS, render(<<SCSS)
876
915
  foo {
@@ -1243,6 +1282,15 @@ SCSS
1243
1282
 
1244
1283
  # Regression
1245
1284
 
1285
+ def test_reference_combinator_with_parent_ref
1286
+ assert_equal <<CSS, render(<<SCSS)
1287
+ a /foo/ b {
1288
+ c: d; }
1289
+ CSS
1290
+ a {& /foo/ b {c: d}}
1291
+ SCSS
1292
+ end
1293
+
1246
1294
  def test_prop_name_interpolation_after_hyphen
1247
1295
  assert_equal <<CSS, render(<<SCSS)
1248
1296
  a {
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sass
3
3
  version: !ruby/object:Gem::Version
4
- hash: 592302835
4
+ hash: 592302361
5
5
  prerelease: 6
6
6
  segments:
7
7
  - 3
8
8
  - 2
9
9
  - 0
10
10
  - alpha
11
- - 247
12
- version: 3.2.0.alpha.247
11
+ - 258
12
+ version: 3.2.0.alpha.258
13
13
  platform: ruby
14
14
  authors:
15
15
  - Nathan Weizenbaum
@@ -19,7 +19,7 @@ autorequire:
19
19
  bindir: bin
20
20
  cert_chain: []
21
21
 
22
- date: 2012-06-15 00:00:00 -04:00
22
+ date: 2012-06-29 00:00:00 -04:00
23
23
  default_executable:
24
24
  dependencies:
25
25
  - !ruby/object:Gem::Dependency
@@ -154,7 +154,6 @@ files:
154
154
  - lib/sass/tree/content_node.rb
155
155
  - lib/sass/tree/css_import_node.rb
156
156
  - lib/sass/tree/variable_node.rb
157
- - lib/sass/tree/warn_node.rb
158
157
  - lib/sass/tree/visitors/base.rb
159
158
  - lib/sass/tree/visitors/check_nesting.rb
160
159
  - lib/sass/tree/visitors/convert.rb
@@ -164,6 +163,7 @@ files:
164
163
  - lib/sass/tree/visitors/perform.rb
165
164
  - lib/sass/tree/visitors/set_options.rb
166
165
  - lib/sass/tree/visitors/to_css.rb
166
+ - lib/sass/tree/warn_node.rb
167
167
  - lib/sass/tree/while_node.rb
168
168
  - lib/sass/tree/supports_node.rb
169
169
  - lib/sass/tree/trace_node.rb