sass 3.3.0.alpha.247 → 3.3.0.alpha.252
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 +1 -1
- data/VERSION +1 -1
- data/VERSION_DATE +1 -1
- data/lib/sass/engine.rb +133 -100
- data/lib/sass/environment.rb +16 -0
- data/lib/sass/script/lexer.rb +11 -2
- data/lib/sass/script/parser.rb +6 -1
- data/lib/sass/script/tree.rb +1 -0
- data/lib/sass/script/tree/funcall.rb +4 -2
- data/lib/sass/script/tree/selector.rb +29 -0
- data/lib/sass/script/value/arg_list.rb +0 -5
- data/lib/sass/scss/parser.rb +8 -1
- data/lib/sass/tree/at_root_node.rb +15 -0
- data/lib/sass/tree/visitors/convert.rb +9 -0
- data/lib/sass/tree/visitors/cssize.rb +4 -0
- data/lib/sass/tree/visitors/perform.rb +5 -1
- data/lib/sass/tree/visitors/to_css.rb +13 -7
- data/test/sass/conversion_test.rb +36 -0
- data/test/sass/engine_test.rb +23 -0
- data/test/sass/script_conversion_test.rb +4 -0
- data/test/sass/script_test.rb +27 -0
- data/test/sass/scss/scss_test.rb +296 -0
- metadata +11 -9
data/REVISION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
9490465245da8b2913346590c6f0974d1ad039cf
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.3.0.alpha.
|
1
|
+
3.3.0.alpha.252
|
data/VERSION_DATE
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
12 September 2013 19:42:11 GMT
|
data/lib/sass/engine.rb
CHANGED
@@ -29,6 +29,7 @@ require 'sass/tree/debug_node'
|
|
29
29
|
require 'sass/tree/warn_node'
|
30
30
|
require 'sass/tree/import_node'
|
31
31
|
require 'sass/tree/charset_node'
|
32
|
+
require 'sass/tree/at_root_node'
|
32
33
|
require 'sass/tree/visitors/base'
|
33
34
|
require 'sass/tree/visitors/perform'
|
34
35
|
require 'sass/tree/visitors/cssize'
|
@@ -761,109 +762,133 @@ WARNING
|
|
761
762
|
end
|
762
763
|
end
|
763
764
|
|
765
|
+
DIRECTIVES = Set[:mixin, :include, :function, :return, :debug, :warn, :for,
|
766
|
+
:each, :while, :if, :else, :extend, :import, :media, :charset, :content,
|
767
|
+
:at_root]
|
768
|
+
|
764
769
|
def parse_directive(parent, line, root)
|
765
770
|
directive, whitespace, value = line.text[1..-1].split(/(\s+)/, 2)
|
766
771
|
offset = directive.size + whitespace.size + 1 if whitespace
|
767
772
|
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
parse_import(line, value, offset)
|
773
|
-
when 'mixin'
|
774
|
-
parse_mixin_definition(line)
|
775
|
-
when 'content'
|
776
|
-
parse_content_directive(line)
|
777
|
-
when 'include'
|
778
|
-
parse_mixin_include(line, root)
|
779
|
-
when 'function'
|
780
|
-
parse_function(line, root)
|
781
|
-
when 'for'
|
782
|
-
parse_for(line, root, value)
|
783
|
-
when 'each'
|
784
|
-
parse_each(line, root, value)
|
785
|
-
when 'else'
|
786
|
-
parse_else(parent, line, value)
|
787
|
-
when 'while'
|
788
|
-
raise SyntaxError.new("Invalid while directive '@while': expected expression.") unless value
|
789
|
-
Tree::WhileNode.new(parse_script(value, :offset => offset))
|
790
|
-
when 'if'
|
791
|
-
raise SyntaxError.new("Invalid if directive '@if': expected expression.") unless value
|
792
|
-
Tree::IfNode.new(parse_script(value, :offset => offset))
|
793
|
-
when 'debug'
|
794
|
-
raise SyntaxError.new("Invalid debug directive '@debug': expected expression.") unless value
|
795
|
-
raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath debug directives.",
|
796
|
-
:line => @line + 1) unless line.children.empty?
|
797
|
-
offset = line.offset + line.text.index(value).to_i
|
798
|
-
Tree::DebugNode.new(parse_script(value, :offset => offset))
|
799
|
-
when 'extend'
|
800
|
-
raise SyntaxError.new("Invalid extend directive '@extend': expected expression.") unless value
|
801
|
-
raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath extend directives.",
|
802
|
-
:line => @line + 1) unless line.children.empty?
|
803
|
-
optional = !!value.gsub!(/\s+#{Sass::SCSS::RX::OPTIONAL}$/, '')
|
804
|
-
offset = line.offset + line.text.index(value).to_i
|
805
|
-
interp_parsed = parse_interp(value, offset)
|
806
|
-
selector_range = Sass::Source::Range.new(
|
807
|
-
Sass::Source::Position.new(@line, to_parser_offset(offset)),
|
808
|
-
Sass::Source::Position.new(@line, to_parser_offset(line.offset) + line.text.length),
|
809
|
-
@options[:filename], @options[:importer]
|
810
|
-
)
|
811
|
-
Tree::ExtendNode.new(interp_parsed, optional, selector_range)
|
812
|
-
when 'warn'
|
813
|
-
raise SyntaxError.new("Invalid warn directive '@warn': expected expression.") unless value
|
814
|
-
raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath warn directives.",
|
815
|
-
:line => @line + 1) unless line.children.empty?
|
816
|
-
offset = line.offset + line.text.index(value).to_i
|
817
|
-
Tree::WarnNode.new(parse_script(value, :offset => offset))
|
818
|
-
when 'return'
|
819
|
-
raise SyntaxError.new("Invalid @return: expected expression.") unless value
|
820
|
-
raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath return directives.",
|
821
|
-
:line => @line + 1) unless line.children.empty?
|
822
|
-
offset = line.offset + line.text.index(value).to_i
|
823
|
-
Tree::ReturnNode.new(parse_script(value, :offset => offset))
|
824
|
-
when 'charset'
|
825
|
-
name = value && value[/\A(["'])(.*)\1\Z/, 2] #"
|
826
|
-
raise SyntaxError.new("Invalid charset directive '@charset': expected string.") unless name
|
827
|
-
raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath charset directives.",
|
828
|
-
:line => @line + 1) unless line.children.empty?
|
829
|
-
Tree::CharsetNode.new(name)
|
830
|
-
when 'media'
|
831
|
-
parser = Sass::SCSS::Parser.new(value,
|
832
|
-
@options[:filename], @options[:importer],
|
833
|
-
@line, to_parser_offset(@offset))
|
834
|
-
# -1 includes the '@' into the range.
|
835
|
-
offset = line.offset + line.text.index(directive).to_i - 1
|
836
|
-
parsed_media_query_list = parser.parse_media_query_list.to_a
|
837
|
-
node = Tree::MediaNode.new(parsed_media_query_list)
|
838
|
-
node.source_range = Sass::Source::Range.new(
|
839
|
-
Sass::Source::Position.new(@line, to_parser_offset(offset)),
|
840
|
-
Sass::Source::Position.new(@line, to_parser_offset(line.offset) + line.text.length),
|
841
|
-
@options[:filename], @options[:importer])
|
842
|
-
node
|
843
|
-
else
|
844
|
-
unprefixed_directive = directive.gsub(/^-[a-z0-9]+-/i, '')
|
845
|
-
if unprefixed_directive == 'supports'
|
846
|
-
parser = Sass::SCSS::Parser.new(value, @options[:filename], @line)
|
847
|
-
return Tree::SupportsNode.new(directive, parser.parse_supports_condition)
|
848
|
-
end
|
773
|
+
directive_name = directive.gsub('-', '_').to_sym
|
774
|
+
if DIRECTIVES.include?(directive_name)
|
775
|
+
return send("parse_#{directive_name}_directive", parent, line, root, value, offset)
|
776
|
+
end
|
849
777
|
|
850
|
-
|
851
|
-
|
778
|
+
unprefixed_directive = directive.gsub(/^-[a-z0-9]+-/i, '')
|
779
|
+
if unprefixed_directive == 'supports'
|
780
|
+
parser = Sass::SCSS::Parser.new(value, @options[:filename], @line)
|
781
|
+
return Tree::SupportsNode.new(directive, parser.parse_supports_condition)
|
852
782
|
end
|
783
|
+
|
784
|
+
return Tree::DirectiveNode.new(
|
785
|
+
value.nil? ? ["@#{directive}"] : ["@#{directive} "] + parse_interp(value, offset))
|
786
|
+
end
|
787
|
+
|
788
|
+
def parse_while_directive(parent, line, root, value, offset)
|
789
|
+
raise SyntaxError.new("Invalid while directive '@while': expected expression.") unless value
|
790
|
+
Tree::WhileNode.new(parse_script(value, :offset => offset))
|
791
|
+
end
|
792
|
+
|
793
|
+
def parse_if_directive(parent, line, root, value, offset)
|
794
|
+
raise SyntaxError.new("Invalid if directive '@if': expected expression.") unless value
|
795
|
+
Tree::IfNode.new(parse_script(value, :offset => offset))
|
796
|
+
end
|
797
|
+
|
798
|
+
def parse_debug_directive(parent, line, root, value, offset)
|
799
|
+
raise SyntaxError.new("Invalid debug directive '@debug': expected expression.") unless value
|
800
|
+
raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath debug directives.",
|
801
|
+
:line => @line + 1) unless line.children.empty?
|
802
|
+
offset = line.offset + line.text.index(value).to_i
|
803
|
+
Tree::DebugNode.new(parse_script(value, :offset => offset))
|
804
|
+
end
|
805
|
+
|
806
|
+
def parse_extend_directive(parent, line, root, value, offset)
|
807
|
+
raise SyntaxError.new("Invalid extend directive '@extend': expected expression.") unless value
|
808
|
+
raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath extend directives.",
|
809
|
+
:line => @line + 1) unless line.children.empty?
|
810
|
+
optional = !!value.gsub!(/\s+#{Sass::SCSS::RX::OPTIONAL}$/, '')
|
811
|
+
offset = line.offset + line.text.index(value).to_i
|
812
|
+
interp_parsed = parse_interp(value, offset)
|
813
|
+
selector_range = Sass::Source::Range.new(
|
814
|
+
Sass::Source::Position.new(@line, to_parser_offset(offset)),
|
815
|
+
Sass::Source::Position.new(@line, to_parser_offset(line.offset) + line.text.length),
|
816
|
+
@options[:filename], @options[:importer]
|
817
|
+
)
|
818
|
+
Tree::ExtendNode.new(interp_parsed, optional, selector_range)
|
853
819
|
end
|
854
820
|
|
855
|
-
def
|
856
|
-
|
821
|
+
def parse_warn_directive(parent, line, root, value, offset)
|
822
|
+
raise SyntaxError.new("Invalid warn directive '@warn': expected expression.") unless value
|
823
|
+
raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath warn directives.",
|
824
|
+
:line => @line + 1) unless line.children.empty?
|
825
|
+
offset = line.offset + line.text.index(value).to_i
|
826
|
+
Tree::WarnNode.new(parse_script(value, :offset => offset))
|
827
|
+
end
|
828
|
+
|
829
|
+
def parse_return_directive(parent, line, root, value, offset)
|
830
|
+
raise SyntaxError.new("Invalid @return: expected expression.") unless value
|
831
|
+
raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath return directives.",
|
832
|
+
:line => @line + 1) unless line.children.empty?
|
833
|
+
offset = line.offset + line.text.index(value).to_i
|
834
|
+
Tree::ReturnNode.new(parse_script(value, :offset => offset))
|
835
|
+
end
|
836
|
+
|
837
|
+
def parse_charset_directive(parent, line, root, value, offset)
|
838
|
+
name = value && value[/\A(["'])(.*)\1\Z/, 2] #"
|
839
|
+
raise SyntaxError.new("Invalid charset directive '@charset': expected string.") unless name
|
840
|
+
raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath charset directives.",
|
841
|
+
:line => @line + 1) unless line.children.empty?
|
842
|
+
Tree::CharsetNode.new(name)
|
843
|
+
end
|
844
|
+
|
845
|
+
def parse_media_directive(parent, line, root, value, offset)
|
846
|
+
parser = Sass::SCSS::Parser.new(value,
|
847
|
+
@options[:filename], @options[:importer],
|
848
|
+
@line, to_parser_offset(@offset))
|
849
|
+
offset = line.offset + line.text.index('media').to_i - 1
|
850
|
+
parsed_media_query_list = parser.parse_media_query_list.to_a
|
851
|
+
node = Tree::MediaNode.new(parsed_media_query_list)
|
852
|
+
node.source_range = Sass::Source::Range.new(
|
853
|
+
Sass::Source::Position.new(@line, to_parser_offset(offset)),
|
854
|
+
Sass::Source::Position.new(@line, to_parser_offset(line.offset) + line.text.length),
|
855
|
+
@options[:filename], @options[:importer])
|
856
|
+
node
|
857
|
+
end
|
858
|
+
|
859
|
+
def parse_at_root_directive(parent, line, root, value, offset)
|
860
|
+
at_root_node = Sass::Tree::AtRootNode.new
|
861
|
+
return at_root_node unless value
|
862
|
+
|
863
|
+
parsed = parse_interp(value, offset)
|
864
|
+
selector_range = Sass::Source::Range.new(
|
865
|
+
Sass::Source::Position.new(@line, to_parser_offset(offset)),
|
866
|
+
Sass::Source::Position.new(@line, to_parser_offset(line.offset) + line.text.length),
|
867
|
+
@options[:filename], @options[:importer])
|
868
|
+
rule_node = Tree::RuleNode.new(parsed, full_line_range(line))
|
869
|
+
|
870
|
+
# The caller expects to automatically add children to the returned node
|
871
|
+
# and we want it to add children to the rule node instead, so we
|
872
|
+
# manually handle the wiring here and return nil so the caller doesn't
|
873
|
+
# duplicate our efforts.
|
874
|
+
append_children(rule_node, line.children, false)
|
875
|
+
at_root_node << rule_node
|
876
|
+
parent << at_root_node
|
877
|
+
nil
|
878
|
+
end
|
879
|
+
|
880
|
+
def parse_for_directive(parent, line, root, value, offset)
|
881
|
+
var, from_expr, to_name, to_expr = value.scan(/^([^\s]+)\s+from\s+(.+)\s+(to|through)\s+(.+)$/).first
|
857
882
|
|
858
883
|
if var.nil? # scan failed, try to figure out why for error message
|
859
|
-
if
|
884
|
+
if value !~ /^[^\s]+/
|
860
885
|
expected = "variable name"
|
861
|
-
elsif
|
886
|
+
elsif value !~ /^[^\s]+\s+from\s+.+/
|
862
887
|
expected = "'from <expr>'"
|
863
888
|
else
|
864
889
|
expected = "'to <expr>' or 'through <expr>'"
|
865
890
|
end
|
866
|
-
raise SyntaxError.new("Invalid for directive '@for #{
|
891
|
+
raise SyntaxError.new("Invalid for directive '@for #{value}': expected #{expected}.")
|
867
892
|
end
|
868
893
|
raise SyntaxError.new("Invalid variable \"#{var}\".") unless var =~ Script::VALIDATE
|
869
894
|
|
@@ -873,16 +898,16 @@ WARNING
|
|
873
898
|
Tree::ForNode.new(var, parsed_from, parsed_to, to_name == 'to')
|
874
899
|
end
|
875
900
|
|
876
|
-
def
|
877
|
-
vars, list_expr =
|
901
|
+
def parse_each_directive(parent, line, root, value, offset)
|
902
|
+
vars, list_expr = value.scan(/^([^\s]+(?:\s*,\s*[^\s]+)*)\s+in\s+(.+)$/).first
|
878
903
|
|
879
904
|
if vars.nil? # scan failed, try to figure out why for error message
|
880
|
-
if
|
905
|
+
if value !~ /^[^\s]+/
|
881
906
|
expected = "variable name"
|
882
|
-
elsif
|
907
|
+
elsif value !~ /^[^\s]+(?:\s*,\s*[^\s]+)*[^\s]+\s+from\s+.+/
|
883
908
|
expected = "'in <expr>'"
|
884
909
|
end
|
885
|
-
raise SyntaxError.new("Invalid each directive '@each #{
|
910
|
+
raise SyntaxError.new("Invalid each directive '@each #{value}': expected #{expected}.")
|
886
911
|
end
|
887
912
|
|
888
913
|
vars = vars.split(',').map do |var|
|
@@ -895,13 +920,13 @@ WARNING
|
|
895
920
|
Tree::EachNode.new(vars, parsed_list)
|
896
921
|
end
|
897
922
|
|
898
|
-
def
|
923
|
+
def parse_else_directive(parent, line, root, value, offset)
|
899
924
|
previous = parent.children.last
|
900
925
|
raise SyntaxError.new("@else must come after @if.") unless previous.is_a?(Tree::IfNode)
|
901
926
|
|
902
|
-
if
|
903
|
-
if
|
904
|
-
raise SyntaxError.new("Invalid else directive '@else #{
|
927
|
+
if value
|
928
|
+
if value !~ /^if\s+(.+)/
|
929
|
+
raise SyntaxError.new("Invalid else directive '@else #{value}': expected 'if <expr>'.")
|
905
930
|
end
|
906
931
|
expr = parse_script($1, :offset => line.offset + line.text.index($1))
|
907
932
|
end
|
@@ -912,7 +937,7 @@ WARNING
|
|
912
937
|
nil
|
913
938
|
end
|
914
939
|
|
915
|
-
def
|
940
|
+
def parse_import_directive(parent, line, root, value, offset)
|
916
941
|
raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath import directives.",
|
917
942
|
:line => @line + 1) unless line.children.empty?
|
918
943
|
|
@@ -1001,6 +1026,10 @@ WARNING
|
|
1001
1026
|
node
|
1002
1027
|
end
|
1003
1028
|
|
1029
|
+
def parse_mixin_directive(parent, line, root, value, offset)
|
1030
|
+
parse_mixin_definition(line)
|
1031
|
+
end
|
1032
|
+
|
1004
1033
|
MIXIN_DEF_RE = /^(?:=|@mixin)\s*(#{Sass::SCSS::RX::IDENT})(.*)$/
|
1005
1034
|
def parse_mixin_definition(line)
|
1006
1035
|
name, arg_string = line.text.scan(MIXIN_DEF_RE).first
|
@@ -1013,7 +1042,7 @@ WARNING
|
|
1013
1042
|
end
|
1014
1043
|
|
1015
1044
|
CONTENT_RE = /^@content\s*(.+)?$/
|
1016
|
-
def parse_content_directive(line)
|
1045
|
+
def parse_content_directive(parent, line, root, value, offset)
|
1017
1046
|
trailing = line.text.scan(CONTENT_RE).first.first
|
1018
1047
|
raise SyntaxError.new("Invalid content directive. Trailing characters found: \"#{trailing}\".") unless trailing.nil?
|
1019
1048
|
raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath @content directives.",
|
@@ -1021,6 +1050,10 @@ WARNING
|
|
1021
1050
|
Tree::ContentNode.new
|
1022
1051
|
end
|
1023
1052
|
|
1053
|
+
def parse_include_directive(parent, line, root, value, offset)
|
1054
|
+
parse_mixin_include(line, root)
|
1055
|
+
end
|
1056
|
+
|
1024
1057
|
MIXIN_INCLUDE_RE = /^(?:\+|@include)\s*(#{Sass::SCSS::RX::IDENT})(.*)$/
|
1025
1058
|
def parse_mixin_include(line, root)
|
1026
1059
|
name, arg_string = line.text.scan(MIXIN_INCLUDE_RE).first
|
@@ -1033,7 +1066,7 @@ WARNING
|
|
1033
1066
|
end
|
1034
1067
|
|
1035
1068
|
FUNCTION_RE = /^@function\s*(#{Sass::SCSS::RX::IDENT})(.*)$/
|
1036
|
-
def
|
1069
|
+
def parse_function_directive(parent, line, root, value, offset)
|
1037
1070
|
name, arg_string = line.text.scan(FUNCTION_RE).first
|
1038
1071
|
raise SyntaxError.new("Invalid function definition \"#{line.text}\".") if name.nil?
|
1039
1072
|
|
data/lib/sass/environment.rb
CHANGED
@@ -21,6 +21,7 @@ module Sass
|
|
21
21
|
attr_reader :options
|
22
22
|
attr_writer :caller
|
23
23
|
attr_writer :content
|
24
|
+
attr_writer :selector
|
24
25
|
|
25
26
|
# @param options [{Symbol => Object}] The options hash. See
|
26
27
|
# {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
|
@@ -44,6 +45,21 @@ module Sass
|
|
44
45
|
@content || (@parent && @parent.content)
|
45
46
|
end
|
46
47
|
|
48
|
+
# The selector for the current CSS rule, or nil if there is no
|
49
|
+
# current CSS rule.
|
50
|
+
#
|
51
|
+
# @return [Selector::CommaSequence?] The current selector, with any
|
52
|
+
# nesting fully resolved.
|
53
|
+
def selector
|
54
|
+
parent_selector = caller ? caller.selector : (@parent && @parent.selector)
|
55
|
+
return parent_selector unless @selector
|
56
|
+
return @selector.resolve_parent_refs(parent_selector) if parent_selector
|
57
|
+
return @selector
|
58
|
+
end
|
59
|
+
|
60
|
+
# The top-level Environment object.
|
61
|
+
#
|
62
|
+
# @return [Environment]
|
47
63
|
def global_env
|
48
64
|
@global_env ||= parent.nil? ? self : parent.global_env
|
49
65
|
end
|
data/lib/sass/script/lexer.rb
CHANGED
@@ -95,6 +95,7 @@ module Sass
|
|
95
95
|
:color => HEXCOLOR,
|
96
96
|
:bool => /(true|false)\b/,
|
97
97
|
:null => /null\b/,
|
98
|
+
:selector => /&/,
|
98
99
|
:ident_op => %r{(#{Regexp.union(*IDENT_OP_NAMES.map{|s| Regexp.new(Regexp.escape(s) + "(?!#{NMCHAR}|\Z)")})})},
|
99
100
|
:op => %r{(#{Regexp.union(*OP_NAMES)})},
|
100
101
|
}
|
@@ -241,8 +242,8 @@ module Sass
|
|
241
242
|
end
|
242
243
|
|
243
244
|
variable || string(:double, false) || string(:single, false) || number ||
|
244
|
-
color || bool || null || string(:uri, false) ||
|
245
|
-
special_fun || special_val || ident_op || ident || op
|
245
|
+
color || bool || null || selector || string(:uri, false) ||
|
246
|
+
raw(UNICODERANGE) || special_fun || special_val || ident_op || ident || op
|
246
247
|
end
|
247
248
|
|
248
249
|
def variable
|
@@ -307,6 +308,14 @@ MESSAGE
|
|
307
308
|
[:null, script_null]
|
308
309
|
end
|
309
310
|
|
311
|
+
def selector
|
312
|
+
start_pos = source_position
|
313
|
+
return unless scan(REGULAR_EXPRESSIONS[:selector])
|
314
|
+
script_selector = Script::Tree::Selector.new
|
315
|
+
script_selector.source_range = range(start_pos)
|
316
|
+
[:selector, script_selector]
|
317
|
+
end
|
318
|
+
|
310
319
|
def special_fun
|
311
320
|
return unless str1 = scan(/((-[\w-]+-)?(calc|element)|expression|progid:[a-z\.]*)\(/i)
|
312
321
|
str2, _ = Sass::Shared.balance(@scanner, ?(, ?), 1)
|
data/lib/sass/script/parser.rb
CHANGED
@@ -494,12 +494,17 @@ RUBY
|
|
494
494
|
end
|
495
495
|
|
496
496
|
def number
|
497
|
-
return
|
497
|
+
return selector unless tok = try_tok(:number)
|
498
498
|
num = tok.value
|
499
499
|
num.original = num.to_s unless @in_parens
|
500
500
|
literal_node(num, tok.source_range.start_pos)
|
501
501
|
end
|
502
502
|
|
503
|
+
def selector
|
504
|
+
return literal unless tok = try_tok(:selector)
|
505
|
+
node(tok.value, tok.source_range.start_pos)
|
506
|
+
end
|
507
|
+
|
503
508
|
def literal
|
504
509
|
(t = try_tok(:color, :bool, :null)) && (return literal_node(t.value, t.source_range))
|
505
510
|
end
|
data/lib/sass/script/tree.rb
CHANGED
@@ -102,7 +102,7 @@ module Sass::Script::Tree
|
|
102
102
|
splat = @splat.perform(environment) if @splat
|
103
103
|
if fn = environment.function(@name)
|
104
104
|
keywords = Sass::Util.map_hash(@keywords) {|k, v| [k, v.perform(environment)]}
|
105
|
-
return perform_sass_fn(fn, args, keywords, splat)
|
105
|
+
return perform_sass_fn(fn, args, keywords, splat, environment)
|
106
106
|
end
|
107
107
|
|
108
108
|
ruby_name = @name.tr('-', '_')
|
@@ -232,8 +232,10 @@ module Sass::Script::Tree
|
|
232
232
|
args
|
233
233
|
end
|
234
234
|
|
235
|
-
def perform_sass_fn(function, args, keywords, splat)
|
235
|
+
def perform_sass_fn(function, args, keywords, splat, environment)
|
236
236
|
Sass::Tree::Visitors::Perform.perform_arguments(function, args, keywords, splat) do |env|
|
237
|
+
env.caller = Sass::Environment.new(environment)
|
238
|
+
|
237
239
|
val = catch :_sass_return do
|
238
240
|
function.tree.each {|c| Sass::Tree::Visitors::Perform.visit(c, env)}
|
239
241
|
raise Sass::SyntaxError.new("Function #{@name} finished without @return")
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Sass::Script::Tree
|
2
|
+
# A SassScript node that will resolve to the current selector.
|
3
|
+
class Selector < Node
|
4
|
+
def initialize; end
|
5
|
+
|
6
|
+
def children
|
7
|
+
[]
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_sass(opts = {})
|
11
|
+
'&'
|
12
|
+
end
|
13
|
+
|
14
|
+
def deep_copy
|
15
|
+
self.dup
|
16
|
+
end
|
17
|
+
|
18
|
+
protected
|
19
|
+
|
20
|
+
def _perform(environment)
|
21
|
+
return opts(Sass::Script::Value::Null.new) unless selector = environment.selector
|
22
|
+
opts(Sass::Script::Value::List.new(selector.members.map do |seq|
|
23
|
+
Sass::Script::Value::List.new(seq.members.map do |component|
|
24
|
+
Sass::Script::Value::String.new(component.to_s)
|
25
|
+
end, :space)
|
26
|
+
end, :comma))
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/sass/scss/parser.rb
CHANGED
@@ -154,7 +154,7 @@ module Sass
|
|
154
154
|
|
155
155
|
DIRECTIVES = Set[:mixin, :include, :function, :return, :debug, :warn, :for,
|
156
156
|
:each, :while, :if, :else, :extend, :import, :media, :charset, :content,
|
157
|
-
:_moz_document]
|
157
|
+
:_moz_document, :at_root]
|
158
158
|
|
159
159
|
PREFIXED_DIRECTIVES = Set[:supports]
|
160
160
|
|
@@ -471,6 +471,13 @@ module Sass
|
|
471
471
|
val
|
472
472
|
end
|
473
473
|
|
474
|
+
def at_root_directive(start_pos)
|
475
|
+
at_root_node = node(Sass::Tree::AtRootNode.new, start_pos)
|
476
|
+
return block(at_root_node, :stylesheet) unless rule_node = ruleset
|
477
|
+
at_root_node << rule_node
|
478
|
+
return at_root_node
|
479
|
+
end
|
480
|
+
|
474
481
|
# http://www.w3.org/TR/css3-conditional/
|
475
482
|
def supports_directive(name, start_pos)
|
476
483
|
condition = expr!(:supports_condition)
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Sass
|
2
|
+
module Tree
|
3
|
+
# A dynamic node representing an `@at-root` directive.
|
4
|
+
#
|
5
|
+
# An `@at-root` directive with a selector is converted to an \{AtRootNode}
|
6
|
+
# containing a \{RuleNode} at parse time.
|
7
|
+
#
|
8
|
+
# @see Sass::Tree
|
9
|
+
class AtRootNode < Node
|
10
|
+
def bubbles?
|
11
|
+
true
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -256,6 +256,15 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base
|
|
256
256
|
"#{tab_str}@while #{node.expr.to_sass(@options)}#{yield}"
|
257
257
|
end
|
258
258
|
|
259
|
+
def visit_atroot(node)
|
260
|
+
if node.children.length == 1 && node.children.first.is_a?(Sass::Tree::RuleNode)
|
261
|
+
rule = node.children.first
|
262
|
+
"#{tab_str}@at-root #{selector_to_src(rule.rule)}#{visit_children(rule)}"
|
263
|
+
else
|
264
|
+
"#{tab_str}@at-root#{yield}"
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
259
268
|
private
|
260
269
|
|
261
270
|
def interp_to_src(interp)
|
@@ -322,7 +322,11 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
|
|
322
322
|
node.filename, node.options[:importer], node.line)
|
323
323
|
node.parsed_rules ||= parser.parse_selector
|
324
324
|
node.stack_trace = @environment.stack.to_s if node.options[:trace_selectors]
|
325
|
-
|
325
|
+
with_environment Sass::Environment.new(@environment, node.options) do
|
326
|
+
@environment.selector = node.parsed_rules
|
327
|
+
node.children = node.children.map {|c| visit(c)}.flatten
|
328
|
+
end
|
329
|
+
node
|
326
330
|
end
|
327
331
|
|
328
332
|
# Loads the new variable value into the environment.
|
@@ -116,7 +116,12 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
|
|
116
116
|
node.children.each do |child|
|
117
117
|
next if child.invisible?
|
118
118
|
visit(child)
|
119
|
-
|
119
|
+
unless node.style == :compressed
|
120
|
+
output "\n"
|
121
|
+
if child.is_a?(Sass::Tree::DirectiveNode) && child.has_children && !child.bubbles?
|
122
|
+
output "\n"
|
123
|
+
end
|
124
|
+
end
|
120
125
|
end
|
121
126
|
rstrip!
|
122
127
|
return "" if @result.empty?
|
@@ -210,18 +215,19 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
|
|
210
215
|
end
|
211
216
|
end
|
212
217
|
rstrip!
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
+
if node.style == :expanded
|
219
|
+
output("\n#{tab_str}")
|
220
|
+
elsif node.style != :compressed
|
221
|
+
output(" ")
|
222
|
+
end
|
223
|
+
output("}")
|
218
224
|
ensure
|
219
225
|
@in_directive = was_in_directive
|
220
226
|
end
|
221
227
|
|
222
228
|
def visit_media(node)
|
223
229
|
with_tabs(@tabs + node.tabs) {visit_directive(node)}
|
224
|
-
|
230
|
+
output("\n") if node.group_end
|
225
231
|
end
|
226
232
|
|
227
233
|
def visit_supports(node)
|
@@ -1648,6 +1648,42 @@ SASS
|
|
1648
1648
|
SCSS
|
1649
1649
|
end
|
1650
1650
|
|
1651
|
+
def test_at_root
|
1652
|
+
assert_scss_to_sass <<SASS, <<SCSS
|
1653
|
+
.foo
|
1654
|
+
@at-root
|
1655
|
+
.bar
|
1656
|
+
a: b
|
1657
|
+
.baz
|
1658
|
+
c: d
|
1659
|
+
SASS
|
1660
|
+
.foo {
|
1661
|
+
@at-root {
|
1662
|
+
.bar {
|
1663
|
+
a: b;
|
1664
|
+
}
|
1665
|
+
.baz {
|
1666
|
+
c: d;
|
1667
|
+
}
|
1668
|
+
}
|
1669
|
+
}
|
1670
|
+
SCSS
|
1671
|
+
end
|
1672
|
+
|
1673
|
+
def test_at_root_with_selector
|
1674
|
+
assert_scss_to_sass <<SASS, <<SCSS
|
1675
|
+
.foo
|
1676
|
+
@at-root .bar
|
1677
|
+
a: b
|
1678
|
+
SASS
|
1679
|
+
.foo {
|
1680
|
+
@at-root .bar {
|
1681
|
+
a: b;
|
1682
|
+
}
|
1683
|
+
}
|
1684
|
+
SCSS
|
1685
|
+
end
|
1686
|
+
|
1651
1687
|
## Regression Tests
|
1652
1688
|
|
1653
1689
|
def test_list_in_args
|
data/test/sass/engine_test.rb
CHANGED
@@ -2453,6 +2453,29 @@ $val: 20
|
|
2453
2453
|
SASS
|
2454
2454
|
end
|
2455
2455
|
|
2456
|
+
def test_at_root
|
2457
|
+
assert_equal <<CSS, render(<<SASS)
|
2458
|
+
.bar {
|
2459
|
+
a: b; }
|
2460
|
+
CSS
|
2461
|
+
.foo
|
2462
|
+
@at-root
|
2463
|
+
.bar
|
2464
|
+
a: b
|
2465
|
+
SASS
|
2466
|
+
end
|
2467
|
+
|
2468
|
+
def test_at_root_with_selector
|
2469
|
+
assert_equal <<CSS, render(<<SASS)
|
2470
|
+
.bar {
|
2471
|
+
a: b; }
|
2472
|
+
CSS
|
2473
|
+
.foo
|
2474
|
+
@at-root .bar
|
2475
|
+
a: b
|
2476
|
+
SASS
|
2477
|
+
end
|
2478
|
+
|
2456
2479
|
# Regression tests
|
2457
2480
|
|
2458
2481
|
def test_list_separator_with_arg_list
|
@@ -99,6 +99,10 @@ class SassScriptConversionTest < Test::Unit::TestCase
|
|
99
99
|
assert_renders "(foo: (bar, baz), bip: bop)"
|
100
100
|
end
|
101
101
|
|
102
|
+
def test_selector
|
103
|
+
assert_renders "&"
|
104
|
+
end
|
105
|
+
|
102
106
|
def self.test_precedence(outer, inner)
|
103
107
|
op_outer = Sass::Script::Lexer::OPERATORS_REVERSE[outer]
|
104
108
|
op_inner = Sass::Script::Lexer::OPERATORS_REVERSE[inner]
|
data/test/sass/script_test.rb
CHANGED
@@ -552,6 +552,27 @@ SASS
|
|
552
552
|
assert_equal "true", resolve("$ie or $undef", {}, env('ie' => Sass::Script::Value::Bool.new(true)))
|
553
553
|
end
|
554
554
|
|
555
|
+
def test_selector
|
556
|
+
env = Sass::Environment.new
|
557
|
+
assert_equal "true", resolve("& == null", {}, env)
|
558
|
+
|
559
|
+
env.selector = selector('.foo.bar .baz.bang, .bip.bop')
|
560
|
+
assert_equal ".foo.bar .baz.bang, .bip.bop", resolve("&", {}, env)
|
561
|
+
assert_equal ".foo.bar .baz.bang", resolve("nth(&, 1)", {}, env)
|
562
|
+
assert_equal ".bip.bop", resolve("nth(&, 2)", {}, env)
|
563
|
+
assert_equal ".foo.bar", resolve("nth(nth(&, 1), 1)", {}, env)
|
564
|
+
assert_equal ".baz.bang", resolve("nth(nth(&, 1), 2)", {}, env)
|
565
|
+
assert_equal ".bip.bop", resolve("nth(nth(&, 2), 1)", {}, env)
|
566
|
+
assert_equal "string", resolve("type-of(nth(nth(&, 1), 1))", {}, env)
|
567
|
+
|
568
|
+
env.selector = selector('.foo > .bar')
|
569
|
+
assert_equal ".foo > .bar", resolve("&", {}, env)
|
570
|
+
assert_equal ".foo > .bar", resolve("nth(&, 1)", {}, env)
|
571
|
+
assert_equal ".foo", resolve("nth(nth(&, 1), 1)", {}, env)
|
572
|
+
assert_equal ">", resolve("nth(nth(&, 1), 2)", {}, env)
|
573
|
+
assert_equal ".bar", resolve("nth(nth(&, 1), 3)", {}, env)
|
574
|
+
end
|
575
|
+
|
555
576
|
# Regression Tests
|
556
577
|
|
557
578
|
def test_funcall_has_higher_precedence_than_color_name
|
@@ -645,6 +666,12 @@ SASS
|
|
645
666
|
env
|
646
667
|
end
|
647
668
|
|
669
|
+
def selector(str)
|
670
|
+
parser = Sass::SCSS::StaticParser.new(
|
671
|
+
str, filename_for_test, Sass::Importers::Filesystem.new('.'))
|
672
|
+
parser.parse_selector
|
673
|
+
end
|
674
|
+
|
648
675
|
def test_number_printing
|
649
676
|
assert_equal "1", eval("1")
|
650
677
|
assert_equal "1", eval("1.0")
|
data/test/sass/scss/scss_test.rb
CHANGED
@@ -1526,6 +1526,251 @@ baz {b: foo()}
|
|
1526
1526
|
SCSS
|
1527
1527
|
end
|
1528
1528
|
|
1529
|
+
## @at-root
|
1530
|
+
|
1531
|
+
def test_simple_at_root
|
1532
|
+
assert_equal <<CSS, render(<<SCSS)
|
1533
|
+
.bar {
|
1534
|
+
a: b; }
|
1535
|
+
CSS
|
1536
|
+
.foo {
|
1537
|
+
@at-root {
|
1538
|
+
.bar {a: b}
|
1539
|
+
}
|
1540
|
+
}
|
1541
|
+
SCSS
|
1542
|
+
end
|
1543
|
+
|
1544
|
+
def test_at_root_with_selector
|
1545
|
+
assert_equal <<CSS, render(<<SCSS)
|
1546
|
+
.bar {
|
1547
|
+
a: b; }
|
1548
|
+
CSS
|
1549
|
+
.foo {
|
1550
|
+
@at-root .bar {a: b}
|
1551
|
+
}
|
1552
|
+
SCSS
|
1553
|
+
end
|
1554
|
+
|
1555
|
+
def test_at_root_in_mixin
|
1556
|
+
assert_equal <<CSS, render(<<SCSS)
|
1557
|
+
.bar {
|
1558
|
+
a: b; }
|
1559
|
+
CSS
|
1560
|
+
@mixin bar {
|
1561
|
+
@at-root .bar {a: b}
|
1562
|
+
}
|
1563
|
+
|
1564
|
+
.foo {
|
1565
|
+
@include bar;
|
1566
|
+
}
|
1567
|
+
SCSS
|
1568
|
+
end
|
1569
|
+
|
1570
|
+
def test_at_root_in_media
|
1571
|
+
assert_equal <<CSS, render(<<SCSS)
|
1572
|
+
@media screen {
|
1573
|
+
.bar {
|
1574
|
+
a: b; } }
|
1575
|
+
CSS
|
1576
|
+
@media screen {
|
1577
|
+
.foo {
|
1578
|
+
@at-root .bar {a: b}
|
1579
|
+
}
|
1580
|
+
}
|
1581
|
+
SCSS
|
1582
|
+
end
|
1583
|
+
|
1584
|
+
def test_at_root_in_bubbled_media
|
1585
|
+
assert_equal <<CSS, render(<<SCSS)
|
1586
|
+
@media screen {
|
1587
|
+
.bar {
|
1588
|
+
a: b; } }
|
1589
|
+
CSS
|
1590
|
+
.foo {
|
1591
|
+
@media screen {
|
1592
|
+
@at-root .bar {a: b}
|
1593
|
+
}
|
1594
|
+
}
|
1595
|
+
SCSS
|
1596
|
+
end
|
1597
|
+
|
1598
|
+
def test_at_root_in_unknown_directive
|
1599
|
+
assert_equal <<CSS, render(<<SCSS)
|
1600
|
+
@fblthp {
|
1601
|
+
.bar {
|
1602
|
+
a: b; } }
|
1603
|
+
CSS
|
1604
|
+
@fblthp {
|
1605
|
+
.foo {
|
1606
|
+
@at-root .bar {a: b}
|
1607
|
+
}
|
1608
|
+
}
|
1609
|
+
SCSS
|
1610
|
+
end
|
1611
|
+
|
1612
|
+
def test_at_root_in_nested_unknown_directive
|
1613
|
+
assert_equal <<CSS, render(<<SCSS)
|
1614
|
+
.foo {
|
1615
|
+
@fblthp {
|
1616
|
+
.bar {
|
1617
|
+
a: b; } } }
|
1618
|
+
CSS
|
1619
|
+
.foo {
|
1620
|
+
@fblthp {
|
1621
|
+
@at-root .bar {a: b}
|
1622
|
+
}
|
1623
|
+
}
|
1624
|
+
SCSS
|
1625
|
+
end
|
1626
|
+
|
1627
|
+
## Selector Script
|
1628
|
+
|
1629
|
+
def test_selector_script
|
1630
|
+
assert_equal(<<CSS, render(<<SCSS))
|
1631
|
+
.foo .bar {
|
1632
|
+
content: ".foo .bar"; }
|
1633
|
+
CSS
|
1634
|
+
.foo .bar {
|
1635
|
+
content: "\#{&}";
|
1636
|
+
}
|
1637
|
+
SCSS
|
1638
|
+
end
|
1639
|
+
|
1640
|
+
def test_nested_selector_script
|
1641
|
+
assert_equal(<<CSS, render(<<SCSS))
|
1642
|
+
.foo .bar {
|
1643
|
+
content: ".foo .bar"; }
|
1644
|
+
CSS
|
1645
|
+
.foo {
|
1646
|
+
.bar {
|
1647
|
+
content: "\#{&}";
|
1648
|
+
}
|
1649
|
+
}
|
1650
|
+
SCSS
|
1651
|
+
end
|
1652
|
+
|
1653
|
+
def test_nested_selector_script_with_outer_comma_selector
|
1654
|
+
assert_equal(<<CSS, render(<<SCSS))
|
1655
|
+
.foo .baz, .bar .baz {
|
1656
|
+
content: ".foo .baz, .bar .baz"; }
|
1657
|
+
CSS
|
1658
|
+
.foo, .bar {
|
1659
|
+
.baz {
|
1660
|
+
content: "\#{&}";
|
1661
|
+
}
|
1662
|
+
}
|
1663
|
+
SCSS
|
1664
|
+
end
|
1665
|
+
|
1666
|
+
def test_nested_selector_script_with_inner_comma_selector
|
1667
|
+
assert_equal(<<CSS, render(<<SCSS))
|
1668
|
+
.foo .bar, .foo .baz {
|
1669
|
+
content: ".foo .bar, .foo .baz"; }
|
1670
|
+
CSS
|
1671
|
+
.foo {
|
1672
|
+
.bar, .baz {
|
1673
|
+
content: "\#{&}";
|
1674
|
+
}
|
1675
|
+
}
|
1676
|
+
SCSS
|
1677
|
+
end
|
1678
|
+
|
1679
|
+
def test_selector_script_through_mixin
|
1680
|
+
assert_equal(<<CSS, render(<<SCSS))
|
1681
|
+
.foo {
|
1682
|
+
content: ".foo"; }
|
1683
|
+
CSS
|
1684
|
+
@mixin mixin {
|
1685
|
+
content: "\#{&}";
|
1686
|
+
}
|
1687
|
+
|
1688
|
+
.foo {
|
1689
|
+
@include mixin;
|
1690
|
+
}
|
1691
|
+
SCSS
|
1692
|
+
end
|
1693
|
+
|
1694
|
+
def test_selector_script_through_content
|
1695
|
+
assert_equal(<<CSS, render(<<SCSS))
|
1696
|
+
.foo {
|
1697
|
+
content: ".foo"; }
|
1698
|
+
CSS
|
1699
|
+
@mixin mixin {
|
1700
|
+
@content;
|
1701
|
+
}
|
1702
|
+
|
1703
|
+
.foo {
|
1704
|
+
@include mixin {
|
1705
|
+
content: "\#{&}";
|
1706
|
+
}
|
1707
|
+
}
|
1708
|
+
SCSS
|
1709
|
+
end
|
1710
|
+
|
1711
|
+
def test_selector_script_through_function
|
1712
|
+
assert_equal(<<CSS, render(<<SCSS))
|
1713
|
+
.foo {
|
1714
|
+
content: ".foo"; }
|
1715
|
+
CSS
|
1716
|
+
@function fn() {
|
1717
|
+
@return "\#{&}";
|
1718
|
+
}
|
1719
|
+
|
1720
|
+
.foo {
|
1721
|
+
content: fn();
|
1722
|
+
}
|
1723
|
+
SCSS
|
1724
|
+
end
|
1725
|
+
|
1726
|
+
def test_selector_script_through_media
|
1727
|
+
assert_equal(<<CSS, render(<<SCSS))
|
1728
|
+
.foo {
|
1729
|
+
content: "outer"; }
|
1730
|
+
@media screen {
|
1731
|
+
.foo .bar {
|
1732
|
+
content: ".foo .bar"; } }
|
1733
|
+
CSS
|
1734
|
+
.foo {
|
1735
|
+
content: "outer";
|
1736
|
+
@media screen {
|
1737
|
+
.bar {
|
1738
|
+
content: "\#{&}";
|
1739
|
+
}
|
1740
|
+
}
|
1741
|
+
}
|
1742
|
+
SCSS
|
1743
|
+
end
|
1744
|
+
|
1745
|
+
def test_selector_script_save_and_reuse
|
1746
|
+
assert_equal(<<CSS, render(<<SCSS))
|
1747
|
+
.bar {
|
1748
|
+
content: ".foo"; }
|
1749
|
+
CSS
|
1750
|
+
$var: null;
|
1751
|
+
.foo {
|
1752
|
+
$var: &;
|
1753
|
+
}
|
1754
|
+
|
1755
|
+
.bar {
|
1756
|
+
content: "\#{$var}";
|
1757
|
+
}
|
1758
|
+
SCSS
|
1759
|
+
end
|
1760
|
+
|
1761
|
+
def test_selector_script_with_at_root
|
1762
|
+
assert_equal(<<CSS, render(<<SCSS))
|
1763
|
+
.foo-bar {
|
1764
|
+
a: b; }
|
1765
|
+
CSS
|
1766
|
+
.foo {
|
1767
|
+
@at-root \#{&}-bar {
|
1768
|
+
a: b;
|
1769
|
+
}
|
1770
|
+
}
|
1771
|
+
SCSS
|
1772
|
+
end
|
1773
|
+
|
1529
1774
|
## Errors
|
1530
1775
|
|
1531
1776
|
def test_nested_mixin_def_is_scoped
|
@@ -1736,6 +1981,57 @@ SCSS
|
|
1736
1981
|
|
1737
1982
|
# Regression
|
1738
1983
|
|
1984
|
+
def test_nested_unknown_directive
|
1985
|
+
assert_equal(<<CSS, render(<<SCSS, :style => :nested))
|
1986
|
+
.foo {
|
1987
|
+
@fblthp {
|
1988
|
+
.bar {
|
1989
|
+
a: b; } } }
|
1990
|
+
CSS
|
1991
|
+
.foo {
|
1992
|
+
@fblthp {
|
1993
|
+
.bar {a: b}
|
1994
|
+
}
|
1995
|
+
}
|
1996
|
+
SCSS
|
1997
|
+
|
1998
|
+
assert_equal(<<CSS, render(<<SCSS, :style => :compressed))
|
1999
|
+
.foo{@fblthp{.bar{a:b}}}
|
2000
|
+
CSS
|
2001
|
+
.foo {
|
2002
|
+
@fblthp {
|
2003
|
+
.bar {a: b}
|
2004
|
+
}
|
2005
|
+
}
|
2006
|
+
SCSS
|
2007
|
+
|
2008
|
+
assert_equal(<<CSS, render(<<SCSS, :style => :compact))
|
2009
|
+
.foo { @fblthp { .bar { a: b; } } }
|
2010
|
+
CSS
|
2011
|
+
.foo {
|
2012
|
+
@fblthp {
|
2013
|
+
.bar {a: b}
|
2014
|
+
}
|
2015
|
+
}
|
2016
|
+
SCSS
|
2017
|
+
|
2018
|
+
assert_equal(<<CSS, render(<<SCSS, :style => :expanded))
|
2019
|
+
.foo {
|
2020
|
+
@fblthp {
|
2021
|
+
.bar {
|
2022
|
+
a: b;
|
2023
|
+
}
|
2024
|
+
}
|
2025
|
+
}
|
2026
|
+
CSS
|
2027
|
+
.foo {
|
2028
|
+
@fblthp {
|
2029
|
+
.bar {a: b}
|
2030
|
+
}
|
2031
|
+
}
|
2032
|
+
SCSS
|
2033
|
+
end
|
2034
|
+
|
1739
2035
|
def test_loud_comment_in_compressed_mode
|
1740
2036
|
assert_equal(<<CSS, render(<<SCSS))
|
1741
2037
|
/*! foo */
|
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:
|
4
|
+
hash: 592302837
|
5
5
|
prerelease: 6
|
6
6
|
segments:
|
7
7
|
- 3
|
8
8
|
- 3
|
9
9
|
- 0
|
10
10
|
- alpha
|
11
|
-
-
|
12
|
-
version: 3.3.0.alpha.
|
11
|
+
- 252
|
12
|
+
version: 3.3.0.alpha.252
|
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: 2013-09-
|
22
|
+
date: 2013-09-12 00:00:00 -04:00
|
23
23
|
default_executable:
|
24
24
|
dependencies:
|
25
25
|
- !ruby/object:Gem::Dependency
|
@@ -129,6 +129,7 @@ files:
|
|
129
129
|
- lib/sass/script/tree/map_literal.rb
|
130
130
|
- lib/sass/script/tree/node.rb
|
131
131
|
- lib/sass/script/tree/operation.rb
|
132
|
+
- lib/sass/script/tree/selector.rb
|
132
133
|
- lib/sass/script/tree/string_interpolation.rb
|
133
134
|
- lib/sass/script/tree/unary_operation.rb
|
134
135
|
- lib/sass/script/tree/variable.rb
|
@@ -158,18 +159,18 @@ files:
|
|
158
159
|
- lib/sass/shared.rb
|
159
160
|
- lib/sass/supports.rb
|
160
161
|
- lib/sass/version.rb
|
161
|
-
- lib/sass/tree/charset_node.rb
|
162
162
|
- lib/sass/tree/comment_node.rb
|
163
|
+
- lib/sass/tree/charset_node.rb
|
164
|
+
- lib/sass/tree/debug_node.rb
|
163
165
|
- lib/sass/tree/content_node.rb
|
164
166
|
- lib/sass/tree/css_import_node.rb
|
165
|
-
- lib/sass/tree/debug_node.rb
|
166
167
|
- lib/sass/tree/directive_node.rb
|
167
168
|
- lib/sass/tree/each_node.rb
|
168
169
|
- lib/sass/tree/extend_node.rb
|
169
170
|
- lib/sass/tree/for_node.rb
|
170
171
|
- lib/sass/tree/function_node.rb
|
171
|
-
- lib/sass/tree/if_node.rb
|
172
172
|
- lib/sass/tree/import_node.rb
|
173
|
+
- lib/sass/tree/if_node.rb
|
173
174
|
- lib/sass/tree/media_node.rb
|
174
175
|
- lib/sass/tree/mixin_def_node.rb
|
175
176
|
- lib/sass/tree/mixin_node.rb
|
@@ -178,9 +179,10 @@ files:
|
|
178
179
|
- lib/sass/tree/return_node.rb
|
179
180
|
- lib/sass/tree/root_node.rb
|
180
181
|
- lib/sass/tree/rule_node.rb
|
181
|
-
- lib/sass/tree/supports_node.rb
|
182
182
|
- lib/sass/tree/trace_node.rb
|
183
|
+
- lib/sass/tree/supports_node.rb
|
183
184
|
- lib/sass/tree/variable_node.rb
|
185
|
+
- lib/sass/tree/warn_node.rb
|
184
186
|
- lib/sass/tree/visitors/base.rb
|
185
187
|
- lib/sass/tree/visitors/check_nesting.rb
|
186
188
|
- lib/sass/tree/visitors/convert.rb
|
@@ -190,8 +192,8 @@ files:
|
|
190
192
|
- lib/sass/tree/visitors/perform.rb
|
191
193
|
- lib/sass/tree/visitors/set_options.rb
|
192
194
|
- lib/sass/tree/visitors/to_css.rb
|
193
|
-
- lib/sass/tree/warn_node.rb
|
194
195
|
- lib/sass/tree/while_node.rb
|
196
|
+
- lib/sass/tree/at_root_node.rb
|
195
197
|
- lib/sass/source/map.rb
|
196
198
|
- lib/sass/source/position.rb
|
197
199
|
- lib/sass/source/range.rb
|