sass 3.2.7 → 3.3.0.rc.1
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/MIT-LICENSE +2 -2
- data/README.md +14 -2
- data/Rakefile +25 -1
- data/VERSION +1 -1
- data/VERSION_DATE +1 -1
- data/VERSION_NAME +1 -1
- data/lib/sass/cache_stores/base.rb +4 -2
- data/lib/sass/cache_stores/chain.rb +2 -1
- data/lib/sass/cache_stores/filesystem.rb +2 -6
- data/lib/sass/cache_stores/memory.rb +1 -1
- data/lib/sass/cache_stores/null.rb +2 -2
- data/lib/sass/callbacks.rb +1 -0
- data/lib/sass/css.rb +10 -10
- data/lib/sass/engine.rb +403 -150
- data/lib/sass/environment.rb +136 -57
- data/lib/sass/error.rb +7 -7
- data/lib/sass/exec.rb +123 -39
- data/lib/sass/features.rb +41 -0
- data/lib/sass/importers/base.rb +33 -2
- data/lib/sass/importers/deprecated_path.rb +45 -0
- data/lib/sass/importers/filesystem.rb +25 -14
- data/lib/sass/importers.rb +1 -0
- data/lib/sass/logger/base.rb +3 -3
- data/lib/sass/logger/log_level.rb +4 -6
- data/lib/sass/media.rb +19 -19
- data/lib/sass/plugin/compiler.rb +141 -101
- data/lib/sass/plugin/configuration.rb +18 -22
- data/lib/sass/plugin/merb.rb +1 -1
- data/lib/sass/plugin/staleness_checker.rb +24 -8
- data/lib/sass/plugin.rb +4 -2
- data/lib/sass/repl.rb +3 -3
- data/lib/sass/script/css_lexer.rb +9 -4
- data/lib/sass/script/css_parser.rb +6 -2
- data/lib/sass/script/functions.rb +1343 -590
- data/lib/sass/script/lexer.rb +84 -52
- data/lib/sass/script/parser.rb +217 -97
- data/lib/sass/script/tree/funcall.rb +290 -0
- data/lib/sass/script/{interpolation.rb → tree/interpolation.rb} +34 -13
- data/lib/sass/script/tree/list_literal.rb +80 -0
- data/lib/sass/script/tree/literal.rb +47 -0
- data/lib/sass/script/tree/map_literal.rb +64 -0
- data/lib/sass/script/{node.rb → tree/node.rb} +22 -12
- data/lib/sass/script/{operation.rb → tree/operation.rb} +17 -25
- data/lib/sass/script/tree/selector.rb +30 -0
- data/lib/sass/script/{string_interpolation.rb → tree/string_interpolation.rb} +5 -4
- data/lib/sass/script/{unary_operation.rb → tree/unary_operation.rb} +14 -9
- data/lib/sass/script/tree/variable.rb +57 -0
- data/lib/sass/script/tree.rb +16 -0
- data/lib/sass/script/{arg_list.rb → value/arg_list.rb} +4 -24
- data/lib/sass/script/value/base.rb +248 -0
- data/lib/sass/script/value/bool.rb +36 -0
- data/lib/sass/script/{color.rb → value/color.rb} +239 -195
- data/lib/sass/script/value/helpers.rb +155 -0
- data/lib/sass/script/value/list.rb +119 -0
- data/lib/sass/script/value/map.rb +70 -0
- data/lib/sass/script/value/null.rb +45 -0
- data/lib/sass/script/{number.rb → value/number.rb} +91 -65
- data/lib/sass/script/{string.rb → value/string.rb} +9 -11
- data/lib/sass/script/value.rb +11 -0
- data/lib/sass/script.rb +35 -8
- data/lib/sass/scss/css_parser.rb +2 -1
- data/lib/sass/scss/parser.rb +338 -170
- data/lib/sass/scss/rx.rb +5 -6
- data/lib/sass/scss/script_lexer.rb +1 -0
- data/lib/sass/scss/script_parser.rb +1 -0
- data/lib/sass/scss/static_parser.rb +23 -6
- data/lib/sass/selector/abstract_sequence.rb +2 -2
- data/lib/sass/selector/comma_sequence.rb +21 -16
- data/lib/sass/selector/sequence.rb +60 -34
- data/lib/sass/selector/simple.rb +11 -12
- data/lib/sass/selector/simple_sequence.rb +55 -33
- data/lib/sass/selector.rb +52 -48
- data/lib/sass/source/map.rb +211 -0
- data/lib/sass/source/position.rb +39 -0
- data/lib/sass/source/range.rb +41 -0
- data/lib/sass/stack.rb +120 -0
- data/lib/sass/supports.rb +12 -13
- data/lib/sass/tree/at_root_node.rb +82 -0
- data/lib/sass/tree/comment_node.rb +3 -3
- data/lib/sass/tree/css_import_node.rb +11 -11
- data/lib/sass/tree/debug_node.rb +2 -2
- data/lib/sass/tree/directive_node.rb +13 -2
- data/lib/sass/tree/each_node.rb +8 -8
- data/lib/sass/tree/extend_node.rb +13 -6
- data/lib/sass/tree/for_node.rb +4 -4
- data/lib/sass/tree/function_node.rb +5 -4
- data/lib/sass/tree/if_node.rb +1 -1
- data/lib/sass/tree/import_node.rb +4 -5
- data/lib/sass/tree/media_node.rb +4 -14
- data/lib/sass/tree/mixin_def_node.rb +4 -4
- data/lib/sass/tree/mixin_node.rb +21 -8
- data/lib/sass/tree/node.rb +29 -12
- data/lib/sass/tree/prop_node.rb +38 -18
- data/lib/sass/tree/return_node.rb +3 -2
- data/lib/sass/tree/root_node.rb +19 -3
- data/lib/sass/tree/rule_node.rb +25 -17
- data/lib/sass/tree/supports_node.rb +0 -13
- data/lib/sass/tree/trace_node.rb +2 -1
- data/lib/sass/tree/variable_node.rb +9 -3
- data/lib/sass/tree/visitors/base.rb +6 -6
- data/lib/sass/tree/visitors/check_nesting.rb +12 -9
- data/lib/sass/tree/visitors/convert.rb +63 -38
- data/lib/sass/tree/visitors/cssize.rb +63 -23
- data/lib/sass/tree/visitors/deep_copy.rb +6 -5
- data/lib/sass/tree/visitors/extend.rb +7 -7
- data/lib/sass/tree/visitors/perform.rb +256 -151
- data/lib/sass/tree/visitors/set_options.rb +6 -6
- data/lib/sass/tree/visitors/to_css.rb +231 -81
- data/lib/sass/tree/warn_node.rb +2 -2
- data/lib/sass/tree/while_node.rb +2 -2
- data/lib/sass/util/multibyte_string_scanner.rb +2 -0
- data/lib/sass/util/normalized_map.rb +65 -0
- data/lib/sass/util/ordered_hash.rb +188 -0
- data/lib/sass/util/subset_map.rb +3 -2
- data/lib/sass/util/test.rb +9 -0
- data/lib/sass/util.rb +220 -34
- data/lib/sass/version.rb +9 -9
- data/lib/sass.rb +14 -7
- data/test/sass/compiler_test.rb +213 -0
- data/test/sass/conversion_test.rb +235 -9
- data/test/sass/engine_test.rb +230 -60
- data/test/sass/exec_test.rb +86 -0
- data/test/sass/extend_test.rb +215 -147
- data/test/sass/functions_test.rb +584 -99
- data/test/sass/importer_test.rb +165 -17
- data/test/sass/plugin_test.rb +19 -13
- data/test/sass/script_conversion_test.rb +40 -0
- data/test/sass/script_test.rb +231 -21
- data/test/sass/scss/css_test.rb +14 -5
- data/test/sass/scss/scss_test.rb +1266 -66
- data/test/sass/source_map_test.rb +879 -0
- data/test/sass/templates/bork5.sass +3 -0
- data/test/sass/util/normalized_map_test.rb +30 -0
- data/test/sass/util_test.rb +90 -0
- data/test/sass/value_helpers_test.rb +181 -0
- data/test/test_helper.rb +7 -2
- metadata +316 -291
- data/lib/sass/script/bool.rb +0 -18
- data/lib/sass/script/funcall.rb +0 -231
- data/lib/sass/script/list.rb +0 -84
- data/lib/sass/script/literal.rb +0 -239
- data/lib/sass/script/null.rb +0 -34
- data/lib/sass/script/variable.rb +0 -58
- data/test/Gemfile +0 -3
- data/vendor/listen/CHANGELOG.md +0 -221
- data/vendor/listen/CONTRIBUTING.md +0 -38
- data/vendor/listen/Gemfile +0 -30
- data/vendor/listen/Guardfile +0 -8
- data/vendor/listen/LICENSE +0 -20
- data/vendor/listen/README.md +0 -315
- data/vendor/listen/Rakefile +0 -47
- data/vendor/listen/Vagrantfile +0 -96
- data/vendor/listen/lib/listen/adapter.rb +0 -214
- data/vendor/listen/lib/listen/adapters/bsd.rb +0 -112
- data/vendor/listen/lib/listen/adapters/darwin.rb +0 -85
- data/vendor/listen/lib/listen/adapters/linux.rb +0 -113
- data/vendor/listen/lib/listen/adapters/polling.rb +0 -67
- data/vendor/listen/lib/listen/adapters/windows.rb +0 -87
- data/vendor/listen/lib/listen/dependency_manager.rb +0 -126
- data/vendor/listen/lib/listen/directory_record.rb +0 -371
- data/vendor/listen/lib/listen/listener.rb +0 -225
- data/vendor/listen/lib/listen/multi_listener.rb +0 -143
- data/vendor/listen/lib/listen/turnstile.rb +0 -28
- data/vendor/listen/lib/listen/version.rb +0 -3
- data/vendor/listen/lib/listen.rb +0 -40
- data/vendor/listen/listen.gemspec +0 -22
- data/vendor/listen/spec/listen/adapter_spec.rb +0 -183
- data/vendor/listen/spec/listen/adapters/bsd_spec.rb +0 -36
- data/vendor/listen/spec/listen/adapters/darwin_spec.rb +0 -37
- data/vendor/listen/spec/listen/adapters/linux_spec.rb +0 -47
- data/vendor/listen/spec/listen/adapters/polling_spec.rb +0 -68
- data/vendor/listen/spec/listen/adapters/windows_spec.rb +0 -30
- data/vendor/listen/spec/listen/dependency_manager_spec.rb +0 -107
- data/vendor/listen/spec/listen/directory_record_spec.rb +0 -1225
- data/vendor/listen/spec/listen/listener_spec.rb +0 -169
- data/vendor/listen/spec/listen/multi_listener_spec.rb +0 -174
- data/vendor/listen/spec/listen/turnstile_spec.rb +0 -56
- data/vendor/listen/spec/listen_spec.rb +0 -73
- data/vendor/listen/spec/spec_helper.rb +0 -21
- data/vendor/listen/spec/support/adapter_helper.rb +0 -629
- data/vendor/listen/spec/support/directory_record_helper.rb +0 -55
- data/vendor/listen/spec/support/fixtures_helper.rb +0 -29
- data/vendor/listen/spec/support/listeners_helper.rb +0 -156
- data/vendor/listen/spec/support/platform_helper.rb +0 -15
data/lib/sass/scss/rx.rb
CHANGED
|
@@ -22,7 +22,7 @@ module Sass
|
|
|
22
22
|
out << escape_char(value.slice!(0...1))
|
|
23
23
|
end
|
|
24
24
|
out << value.gsub(/[^a-zA-Z0-9_-]/) {|c| escape_char c}
|
|
25
|
-
|
|
25
|
+
out
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
# Escapes a single character for a CSS identifier.
|
|
@@ -32,7 +32,7 @@ module Sass
|
|
|
32
32
|
# @private
|
|
33
33
|
def self.escape_char(c)
|
|
34
34
|
return "\\%06x" % Sass::Util.ord(c) unless c =~ /[ -\/:-~]/
|
|
35
|
-
|
|
35
|
+
"\\#{c}"
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
# Creates a Regexp from a plain text string,
|
|
@@ -80,8 +80,8 @@ module Sass
|
|
|
80
80
|
|
|
81
81
|
S = /[ \t\r\n\f]+/
|
|
82
82
|
|
|
83
|
-
COMMENT =
|
|
84
|
-
SINGLE_LINE_COMMENT =
|
|
83
|
+
COMMENT = %r{/\*[^*]*\*+(?:[^/][^*]*\*+)*/}
|
|
84
|
+
SINGLE_LINE_COMMENT = %r{//.*(\n[ \t]*//.*)*}
|
|
85
85
|
|
|
86
86
|
CDO = quote("<!--")
|
|
87
87
|
CDC = quote("-->")
|
|
@@ -94,7 +94,6 @@ module Sass
|
|
|
94
94
|
HASH = /##{NAME}/
|
|
95
95
|
|
|
96
96
|
IMPORTANT = /!#{W}important/i
|
|
97
|
-
DEFAULT = /!#{W}default/i
|
|
98
97
|
|
|
99
98
|
NUMBER = /#{NUM}(?:#{IDENT}|%)?/
|
|
100
99
|
|
|
@@ -127,7 +126,7 @@ module Sass
|
|
|
127
126
|
|
|
128
127
|
STATIC_COMPONENT = /#{IDENT}|#{STRING_NOINTERP}|#{HEXCOLOR}|[+-]?#{NUMBER}|\!important/i
|
|
129
128
|
STATIC_VALUE = /#{STATIC_COMPONENT}(\s*[\s,\/]\s*#{STATIC_COMPONENT})*([;}])/i
|
|
130
|
-
STATIC_SELECTOR = /(#{NMCHAR}|[ \t]|[,>+*]|[:#.]#{NMSTART}){
|
|
129
|
+
STATIC_SELECTOR = /(#{NMCHAR}|[ \t]|[,>+*]|[:#.]#{NMSTART}){1,50}([{])/i
|
|
131
130
|
end
|
|
132
131
|
end
|
|
133
132
|
end
|
|
@@ -24,11 +24,28 @@ module Sass
|
|
|
24
24
|
seq
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
+
# Parses a static at-root query.
|
|
28
|
+
#
|
|
29
|
+
# @return [(Symbol, Array<String>)] The type of the query
|
|
30
|
+
# (`:with` or `:without`) and the values that are being filtered.
|
|
31
|
+
# @raise [Sass::SyntaxError] if there's a syntax error in the query,
|
|
32
|
+
# or if it doesn't take up the entire input string.
|
|
33
|
+
def parse_static_at_root_query
|
|
34
|
+
init_scanner!
|
|
35
|
+
tok!(/\(/); ss
|
|
36
|
+
type = tok!(/\b(without|with)\b/).to_sym; ss
|
|
37
|
+
tok!(/:/); ss
|
|
38
|
+
directives = expr!(:at_root_directive_list); ss
|
|
39
|
+
tok!(/\)/)
|
|
40
|
+
expected("@at-root query list") unless @scanner.eos?
|
|
41
|
+
return type, directives
|
|
42
|
+
end
|
|
43
|
+
|
|
27
44
|
private
|
|
28
45
|
|
|
29
46
|
def moz_document_function
|
|
30
|
-
|
|
31
|
-
|
|
47
|
+
val = tok(URI) || tok(URL_PREFIX) || tok(DOMAIN) || function(!:allow_var)
|
|
48
|
+
return unless val
|
|
32
49
|
ss
|
|
33
50
|
[val]
|
|
34
51
|
end
|
|
@@ -37,12 +54,12 @@ module Sass
|
|
|
37
54
|
def script_value; nil; end
|
|
38
55
|
def interpolation; nil; end
|
|
39
56
|
def var_expr; nil; end
|
|
40
|
-
def interp_string; s = tok(STRING)
|
|
41
|
-
def interp_uri; s = tok(URI)
|
|
42
|
-
def interp_ident(ident = IDENT); s = tok(ident)
|
|
57
|
+
def interp_string; (s = tok(STRING)) && [s]; end
|
|
58
|
+
def interp_uri; (s = tok(URI)) && [s]; end
|
|
59
|
+
def interp_ident(ident = IDENT); (s = tok(ident)) && [s]; end
|
|
43
60
|
def use_css_import?; true; end
|
|
44
61
|
|
|
45
|
-
def special_directive(name)
|
|
62
|
+
def special_directive(name, start_pos)
|
|
46
63
|
return unless %w[media import charset -moz-document].include?(name)
|
|
47
64
|
super
|
|
48
65
|
end
|
|
@@ -55,7 +55,7 @@ module Sass
|
|
|
55
55
|
# @param other [Object] The object to test equality against
|
|
56
56
|
# @return [Boolean] Whether or not this is equal to `other`
|
|
57
57
|
def eql?(other)
|
|
58
|
-
other.class == self.class && other.hash ==
|
|
58
|
+
other.class == self.class && other.hash == hash && _eql?(other)
|
|
59
59
|
end
|
|
60
60
|
alias_method :==, :eql?
|
|
61
61
|
|
|
@@ -71,7 +71,7 @@ module Sass
|
|
|
71
71
|
#
|
|
72
72
|
# @return [String]
|
|
73
73
|
def to_s
|
|
74
|
-
to_a.map {|e| e.is_a?(Sass::Script::Node) ? "\#{#{e.to_sass}}" : e}.join
|
|
74
|
+
to_a.map {|e| e.is_a?(Sass::Script::Tree::Node) ? "\#{#{e.to_sass}}" : e}.join
|
|
75
75
|
end
|
|
76
76
|
|
|
77
77
|
# Returns the specificity of the selector as an integer. The base is given
|
|
@@ -18,23 +18,28 @@ module Sass
|
|
|
18
18
|
# handling commas appropriately.
|
|
19
19
|
#
|
|
20
20
|
# @param super_cseq [CommaSequence] The parent selector
|
|
21
|
+
# @param implicit_parent [Boolean] Whether the the parent
|
|
22
|
+
# selector should automatically be prepended to the resolved
|
|
23
|
+
# selector if it contains no parent refs.
|
|
21
24
|
# @return [CommaSequence] This selector, with parent references resolved
|
|
22
25
|
# @raise [Sass::SyntaxError] If a parent selector is invalid
|
|
23
|
-
def resolve_parent_refs(super_cseq)
|
|
26
|
+
def resolve_parent_refs(super_cseq, implicit_parent = true)
|
|
24
27
|
if super_cseq.nil?
|
|
25
28
|
if @members.any? do |sel|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
|
34
|
+
raise Sass::SyntaxError.new(
|
|
35
|
+
"Base-level rules cannot contain the parent-selector-referencing character '&'.")
|
|
31
36
|
end
|
|
32
37
|
return self
|
|
33
38
|
end
|
|
34
39
|
|
|
35
40
|
CommaSequence.new(
|
|
36
41
|
super_cseq.members.map do |super_seq|
|
|
37
|
-
@members.map {|seq| seq.resolve_parent_refs(super_seq)}
|
|
42
|
+
@members.map {|seq| seq.resolve_parent_refs(super_seq, implicit_parent)}
|
|
38
43
|
end.flatten)
|
|
39
44
|
end
|
|
40
45
|
|
|
@@ -53,14 +58,14 @@ module Sass
|
|
|
53
58
|
# with extensions made according to `extends`
|
|
54
59
|
def do_extend(extends, parent_directives)
|
|
55
60
|
CommaSequence.new(members.map do |seq|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
extended = seq.do_extend(extends, parent_directives)
|
|
62
|
+
# First Law of Extend: the result of extending a selector should
|
|
63
|
+
# always contain the base selector.
|
|
64
|
+
#
|
|
65
|
+
# See https://github.com/nex3/sass/issues/324.
|
|
66
|
+
extended.unshift seq unless seq.has_placeholder? || extended.include?(seq)
|
|
67
|
+
extended
|
|
68
|
+
end.flatten)
|
|
64
69
|
end
|
|
65
70
|
|
|
66
71
|
# Returns a string representation of the sequence.
|
|
@@ -85,7 +90,7 @@ module Sass
|
|
|
85
90
|
end
|
|
86
91
|
|
|
87
92
|
def _eql?(other)
|
|
88
|
-
other.class == self.class && other.members.eql?(
|
|
93
|
+
other.class == self.class && other.members.eql?(members)
|
|
89
94
|
end
|
|
90
95
|
end
|
|
91
96
|
end
|
|
@@ -33,7 +33,8 @@ module Sass
|
|
|
33
33
|
# @return [Array<SimpleSequence, String|Array<Sass::Tree::Node, String>>]
|
|
34
34
|
attr_reader :members
|
|
35
35
|
|
|
36
|
-
# @param seqs_and_ops [Array<SimpleSequence, String|Array<Sass::Tree::Node, String>>]
|
|
36
|
+
# @param seqs_and_ops [Array<SimpleSequence, String|Array<Sass::Tree::Node, String>>]
|
|
37
|
+
# See \{#members}
|
|
37
38
|
def initialize(seqs_and_ops)
|
|
38
39
|
@members = seqs_and_ops
|
|
39
40
|
end
|
|
@@ -43,14 +44,20 @@ module Sass
|
|
|
43
44
|
# handling commas appropriately.
|
|
44
45
|
#
|
|
45
46
|
# @param super_seq [Sequence] The parent selector sequence
|
|
47
|
+
# @param implicit_parent [Boolean] Whether the the parent
|
|
48
|
+
# selector should automatically be prepended to the resolved
|
|
49
|
+
# selector if it contains no parent refs.
|
|
46
50
|
# @return [Sequence] This selector, with parent references resolved
|
|
47
51
|
# @raise [Sass::SyntaxError] If a parent selector is invalid
|
|
48
|
-
def resolve_parent_refs(super_seq)
|
|
52
|
+
def resolve_parent_refs(super_seq, implicit_parent)
|
|
49
53
|
members = @members.dup
|
|
50
54
|
nl = (members.first == "\n" && members.shift)
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
55
|
+
contains_parent_ref = members.any? do |seq_or_op|
|
|
56
|
+
seq_or_op.is_a?(SimpleSequence) && seq_or_op.members.first.is_a?(Parent)
|
|
57
|
+
end
|
|
58
|
+
return self if !implicit_parent && !contains_parent_ref
|
|
59
|
+
|
|
60
|
+
unless contains_parent_ref
|
|
54
61
|
old_members, members = members, []
|
|
55
62
|
members << nl if nl
|
|
56
63
|
members << SimpleSequence.new([Parent.new], false)
|
|
@@ -105,7 +112,9 @@ module Sass
|
|
|
105
112
|
|
|
106
113
|
# @see Simple#to_a
|
|
107
114
|
def to_a
|
|
108
|
-
ary = @members.map
|
|
115
|
+
ary = @members.map do |seq_or_op|
|
|
116
|
+
seq_or_op.is_a?(SimpleSequence) ? seq_or_op.to_a : seq_or_op
|
|
117
|
+
end
|
|
109
118
|
Sass::Util.intersperse(ary, " ").flatten.compact
|
|
110
119
|
end
|
|
111
120
|
|
|
@@ -133,7 +142,8 @@ module Sass
|
|
|
133
142
|
# this conceptually expands into `.D .C, .D (.A .B)`,
|
|
134
143
|
# and this function translates `.D (.A .B)` into `.D .A .B, .A.D .B, .D .A .B`.
|
|
135
144
|
#
|
|
136
|
-
# @param path [Array<Array<SimpleSequence or String>>]
|
|
145
|
+
# @param path [Array<Array<SimpleSequence or String>>]
|
|
146
|
+
# A list of parenthesized selector groups.
|
|
137
147
|
# @return [Array<Array<SimpleSequence or String>>] A list of fully-expanded selectors.
|
|
138
148
|
def weave(path)
|
|
139
149
|
# This function works by moving through the selector path left-to-right,
|
|
@@ -145,12 +155,14 @@ module Sass
|
|
|
145
155
|
until afters.empty?
|
|
146
156
|
current = afters.shift.dup
|
|
147
157
|
last_current = [current.pop]
|
|
148
|
-
befores
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
158
|
+
befores.map! do |before|
|
|
159
|
+
sub = subweave(before, current)
|
|
160
|
+
next [] unless sub
|
|
161
|
+
sub.map {|seqs| seqs + last_current}
|
|
162
|
+
end
|
|
163
|
+
befores = Sass::Util.flatten(befores, 1)
|
|
152
164
|
end
|
|
153
|
-
|
|
165
|
+
befores
|
|
154
166
|
end
|
|
155
167
|
|
|
156
168
|
# This interweaves two lists of selectors,
|
|
@@ -176,8 +188,10 @@ module Sass
|
|
|
176
188
|
return [seq1] if seq2.empty?
|
|
177
189
|
|
|
178
190
|
seq1, seq2 = seq1.dup, seq2.dup
|
|
179
|
-
|
|
180
|
-
return unless
|
|
191
|
+
init = merge_initial_ops(seq1, seq2)
|
|
192
|
+
return unless init
|
|
193
|
+
fin = merge_final_ops(seq1, seq2)
|
|
194
|
+
return unless fin
|
|
181
195
|
seq1 = group_selectors(seq1)
|
|
182
196
|
seq2 = group_selectors(seq2)
|
|
183
197
|
lcs = Sass::Util.lcs(seq2, seq1) do |s1, s2|
|
|
@@ -222,7 +236,7 @@ module Sass
|
|
|
222
236
|
# merged successfully
|
|
223
237
|
lcs = Sass::Util.lcs(ops1, ops2)
|
|
224
238
|
return unless lcs == ops1 || lcs == ops2
|
|
225
|
-
|
|
239
|
+
(newline ? ["\n"] : []) + (ops1.size > ops2.size ? ops1 : ops2)
|
|
226
240
|
end
|
|
227
241
|
|
|
228
242
|
# Extracts final selector combinators (`"+"`, `">"`, `"~"`) and the
|
|
@@ -238,6 +252,8 @@ module Sass
|
|
|
238
252
|
# be nil. Otherwise, this will contained the merged selector. Array
|
|
239
253
|
# elements are [Sass::Util#paths]-style options; conceptually, an "or"
|
|
240
254
|
# of multiple selectors.
|
|
255
|
+
# @comment
|
|
256
|
+
# rubocop:disable MethodLength
|
|
241
257
|
def merge_final_ops(seq1, seq2, res = [])
|
|
242
258
|
ops1, ops2 = [], []
|
|
243
259
|
ops1 << seq1.pop while seq1.last.is_a?(String)
|
|
@@ -255,7 +271,7 @@ module Sass
|
|
|
255
271
|
# is a supersequence of the other, use that, otherwise give up.
|
|
256
272
|
lcs = Sass::Util.lcs(ops1, ops2)
|
|
257
273
|
return unless lcs == ops1 || lcs == ops2
|
|
258
|
-
res.unshift
|
|
274
|
+
res.unshift(*(ops1.size > ops2.size ? ops1 : ops2).reverse)
|
|
259
275
|
return res
|
|
260
276
|
end
|
|
261
277
|
|
|
@@ -301,7 +317,8 @@ module Sass
|
|
|
301
317
|
res.unshift sel1, op1
|
|
302
318
|
seq2.push sel2, op2
|
|
303
319
|
elsif op1 == op2
|
|
304
|
-
|
|
320
|
+
merged = sel1.unify(sel2.members, sel2.subject?)
|
|
321
|
+
return unless merged
|
|
305
322
|
res.unshift merged, op1
|
|
306
323
|
else
|
|
307
324
|
# Unknown selector combinators can't be unified
|
|
@@ -318,6 +335,8 @@ module Sass
|
|
|
318
335
|
return merge_final_ops(seq1, seq2, res)
|
|
319
336
|
end
|
|
320
337
|
end
|
|
338
|
+
# @comment
|
|
339
|
+
# rubocop:enable MethodLength
|
|
321
340
|
|
|
322
341
|
# Takes initial subsequences of `seq1` and `seq2` and returns all
|
|
323
342
|
# orderings of those subsequences. The initial subsequences are determined
|
|
@@ -369,7 +388,7 @@ module Sass
|
|
|
369
388
|
end while !tail.empty? && head.last.is_a?(String) || tail.first.is_a?(String)
|
|
370
389
|
newseq << head
|
|
371
390
|
end
|
|
372
|
-
|
|
391
|
+
newseq
|
|
373
392
|
end
|
|
374
393
|
|
|
375
394
|
# Given two selector sequences, returns whether `seq1` is a
|
|
@@ -398,15 +417,15 @@ module Sass
|
|
|
398
417
|
return unless si
|
|
399
418
|
|
|
400
419
|
if seq1[1].is_a?(String)
|
|
401
|
-
return unless seq2[si+1].is_a?(String)
|
|
420
|
+
return unless seq2[si + 1].is_a?(String)
|
|
402
421
|
# .foo ~ .bar is a superselector of .foo + .bar
|
|
403
|
-
return unless seq1[1] == "~" ? seq2[si+1] != ">" : seq1[1] == seq2[si+1]
|
|
404
|
-
return _superselector?(seq1[2..-1], seq2[si+2..-1])
|
|
405
|
-
elsif seq2[si+1].is_a?(String)
|
|
406
|
-
return unless seq2[si+1] == ">"
|
|
407
|
-
return _superselector?(seq1[1..-1], seq2[si+2..-1])
|
|
422
|
+
return unless seq1[1] == "~" ? seq2[si + 1] != ">" : seq1[1] == seq2[si + 1]
|
|
423
|
+
return _superselector?(seq1[2..-1], seq2[si + 2..-1])
|
|
424
|
+
elsif seq2[si + 1].is_a?(String)
|
|
425
|
+
return unless seq2[si + 1] == ">"
|
|
426
|
+
return _superselector?(seq1[1..-1], seq2[si + 2..-1])
|
|
408
427
|
else
|
|
409
|
-
return _superselector?(seq1[1..-1], seq2[si+1..-1])
|
|
428
|
+
return _superselector?(seq1[1..-1], seq2[si + 1..-1])
|
|
410
429
|
end
|
|
411
430
|
end
|
|
412
431
|
|
|
@@ -421,7 +440,8 @@ module Sass
|
|
|
421
440
|
# @param seq2 [Array<SimpleSequence or String>]
|
|
422
441
|
# @return [Boolean]
|
|
423
442
|
def parent_superselector?(seq1, seq2)
|
|
424
|
-
base = Sass::Selector::SimpleSequence.new([Sass::Selector::Placeholder.new('<temp>')],
|
|
443
|
+
base = Sass::Selector::SimpleSequence.new([Sass::Selector::Placeholder.new('<temp>')],
|
|
444
|
+
false)
|
|
425
445
|
_superselector?(seq1 + [base], seq2 + [base])
|
|
426
446
|
end
|
|
427
447
|
|
|
@@ -437,26 +457,32 @@ module Sass
|
|
|
437
457
|
# @param seqses [Array<Array<Array<SimpleSequence or String>>>]
|
|
438
458
|
# @return [Array<Array<Array<SimpleSequence or String>>>]
|
|
439
459
|
def trim(seqses)
|
|
440
|
-
# Avoid truly horrific quadratic behavior.
|
|
460
|
+
# Avoid truly horrific quadratic behavior. TODO: I think there
|
|
441
461
|
# may be a way to get perfect trimming without going quadratic.
|
|
442
462
|
return seqses if seqses.size > 100
|
|
463
|
+
|
|
464
|
+
# Keep the results in a separate array so we can be sure we aren't
|
|
465
|
+
# comparing against an already-trimmed selector. This ensures that two
|
|
466
|
+
# identical selectors don't mutually trim one another.
|
|
467
|
+
result = seqses.dup
|
|
468
|
+
|
|
443
469
|
# This is n^2 on the sequences, but only comparing between
|
|
444
470
|
# separate sequences should limit the quadratic behavior.
|
|
445
|
-
seqses.
|
|
446
|
-
seqs1.reject do |seq1|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
seqses.any? do |seqs2|
|
|
471
|
+
seqses.each_with_index do |seqs1, i|
|
|
472
|
+
result[i] = seqs1.reject do |seq1|
|
|
473
|
+
max_spec = _sources(seq1).map {|seq| seq.specificity}.max || 0
|
|
474
|
+
result.any? do |seqs2|
|
|
450
475
|
next if seqs1.equal?(seqs2)
|
|
451
476
|
# Second Law of Extend: the specificity of a generated selector
|
|
452
477
|
# should never be less than the specificity of the extending
|
|
453
478
|
# selector.
|
|
454
479
|
#
|
|
455
480
|
# See https://github.com/nex3/sass/issues/324.
|
|
456
|
-
seqs2.any? {|seq2| _specificity(seq2) >=
|
|
481
|
+
seqs2.any? {|seq2| _specificity(seq2) >= max_spec && _superselector?(seq2, seq1)}
|
|
457
482
|
end
|
|
458
483
|
end
|
|
459
484
|
end
|
|
485
|
+
result
|
|
460
486
|
end
|
|
461
487
|
|
|
462
488
|
def _hash
|
|
@@ -464,7 +490,7 @@ module Sass
|
|
|
464
490
|
end
|
|
465
491
|
|
|
466
492
|
def _eql?(other)
|
|
467
|
-
other.members.reject {|m| m == "\n"}.eql?(
|
|
493
|
+
other.members.reject {|m| m == "\n"}.eql?(members.reject {|m| m == "\n"})
|
|
468
494
|
end
|
|
469
495
|
|
|
470
496
|
private
|
data/lib/sass/selector/simple.rb
CHANGED
|
@@ -14,13 +14,12 @@ module Sass
|
|
|
14
14
|
# @return [String, nil]
|
|
15
15
|
attr_accessor :filename
|
|
16
16
|
|
|
17
|
-
# Returns a representation of the node
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
# this will be the string representation of this node.
|
|
17
|
+
# Returns a representation of the node as an array of strings and
|
|
18
|
+
# potentially {Sass::Script::Tree::Node}s (if there's interpolation in the
|
|
19
|
+
# selector). When the interpolation is resolved and the strings are joined
|
|
20
|
+
# together, this will be the string representation of this node.
|
|
22
21
|
#
|
|
23
|
-
# @return [Array<String, Sass::Script::Node>]
|
|
22
|
+
# @return [Array<String, Sass::Script::Tree::Node>]
|
|
24
23
|
def to_a
|
|
25
24
|
Sass::Util.abstract(self)
|
|
26
25
|
end
|
|
@@ -30,7 +29,7 @@ module Sass
|
|
|
30
29
|
#
|
|
31
30
|
# @return [String]
|
|
32
31
|
def inspect
|
|
33
|
-
to_a.map {|e| e.is_a?(Sass::Script::Node) ? "\#{#{e.to_sass}}" : e}.join
|
|
32
|
+
to_a.map {|e| e.is_a?(Sass::Script::Tree::Node) ? "\#{#{e.to_sass}}" : e}.join
|
|
34
33
|
end
|
|
35
34
|
|
|
36
35
|
# @see \{#inspect}
|
|
@@ -59,7 +58,7 @@ module Sass
|
|
|
59
58
|
# @param other [Object] The object to test equality against
|
|
60
59
|
# @return [Boolean] Whether or not this is equal to `other`
|
|
61
60
|
def eql?(other)
|
|
62
|
-
other.class == self.class && other.hash ==
|
|
61
|
+
other.class == self.class && other.hash == hash && other.to_a.eql?(to_a)
|
|
63
62
|
end
|
|
64
63
|
alias_method :==, :eql?
|
|
65
64
|
|
|
@@ -84,13 +83,13 @@ module Sass
|
|
|
84
83
|
return sels if sels.any? {|sel2| eql?(sel2)}
|
|
85
84
|
sels_with_ix = Sass::Util.enum_with_index(sels)
|
|
86
85
|
_, i =
|
|
87
|
-
if
|
|
88
|
-
sels_with_ix.find {|sel, _| sel.is_a?(Pseudo) && (sels.last.
|
|
86
|
+
if is_a?(Pseudo) || is_a?(SelectorPseudoClass)
|
|
87
|
+
sels_with_ix.find {|sel, _| sel.is_a?(Pseudo) && (sels.last.type == :element)}
|
|
89
88
|
else
|
|
90
89
|
sels_with_ix.find {|sel, _| sel.is_a?(Pseudo) || sel.is_a?(SelectorPseudoClass)}
|
|
91
90
|
end
|
|
92
91
|
return sels + [self] unless i
|
|
93
|
-
|
|
92
|
+
sels[0...i] + [self] + sels[i..-1]
|
|
94
93
|
end
|
|
95
94
|
|
|
96
95
|
protected
|
|
@@ -112,7 +111,7 @@ module Sass
|
|
|
112
111
|
return nil, false unless ns1 == ns2 || ns1.nil? || ns1 == ['*'] || ns2.nil? || ns2 == ['*']
|
|
113
112
|
return ns2, true if ns1 == ['*']
|
|
114
113
|
return ns1, true if ns2 == ['*']
|
|
115
|
-
|
|
114
|
+
[ns1 || ns2, true]
|
|
116
115
|
end
|
|
117
116
|
end
|
|
118
117
|
end
|
|
@@ -21,11 +21,16 @@ module Sass
|
|
|
21
21
|
# and the generated selector `c.foo.bar.baz` has `{b.bar, c.baz}` as its
|
|
22
22
|
# `sources` set.
|
|
23
23
|
#
|
|
24
|
-
# This is populated during the {#do_extend} process.
|
|
24
|
+
# This is populated during the {Sequence#do_extend} process.
|
|
25
25
|
#
|
|
26
26
|
# @return {Set<Sequence>}
|
|
27
27
|
attr_accessor :sources
|
|
28
28
|
|
|
29
|
+
# This sequence source range.
|
|
30
|
+
#
|
|
31
|
+
# @return [Sass::Source::Range]
|
|
32
|
+
attr_accessor :source_range
|
|
33
|
+
|
|
29
34
|
# @see \{#subject?}
|
|
30
35
|
attr_writer :subject
|
|
31
36
|
|
|
@@ -37,11 +42,16 @@ module Sass
|
|
|
37
42
|
@base ||= (members.first if members.first.is_a?(Element) || members.first.is_a?(Universal))
|
|
38
43
|
end
|
|
39
44
|
|
|
40
|
-
|
|
45
|
+
def pseudo_elements
|
|
46
|
+
@pseudo_elements ||= (members - [base]).
|
|
47
|
+
select {|sel| sel.is_a?(Pseudo) && sel.type == :element}
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Returns the non-base, non-pseudo-class selectors in this sequence.
|
|
41
51
|
#
|
|
42
52
|
# @return [Set<Simple>]
|
|
43
53
|
def rest
|
|
44
|
-
@rest ||= Set.new(
|
|
54
|
+
@rest ||= Set.new(members - [base] - pseudo_elements)
|
|
45
55
|
end
|
|
46
56
|
|
|
47
57
|
# Whether or not this compound selector is the subject of the parent
|
|
@@ -55,11 +65,12 @@ module Sass
|
|
|
55
65
|
|
|
56
66
|
# @param selectors [Array<Simple>] See \{#members}
|
|
57
67
|
# @param subject [Boolean] See \{#subject?}
|
|
58
|
-
# @param
|
|
59
|
-
def initialize(selectors, subject,
|
|
68
|
+
# @param source_range [Sass::Source::Range]
|
|
69
|
+
def initialize(selectors, subject, source_range = nil)
|
|
60
70
|
@members = selectors
|
|
61
71
|
@subject = subject
|
|
62
|
-
@sources =
|
|
72
|
+
@sources = Set.new
|
|
73
|
+
@source_range = source_range
|
|
63
74
|
end
|
|
64
75
|
|
|
65
76
|
# Resolves the {Parent} selectors within this selector
|
|
@@ -96,30 +107,37 @@ module Sass
|
|
|
96
107
|
# by extending this selector with `extends`.
|
|
97
108
|
# @see CommaSequence#do_extend
|
|
98
109
|
def do_extend(extends, parent_directives, seen = Set.new)
|
|
99
|
-
Sass::Util.group_by_to_a(extends.get(members.to_set)) {|ex, _| ex.extender}
|
|
110
|
+
groups = Sass::Util.group_by_to_a(extends.get(members.to_set)) {|ex, _| ex.extender}
|
|
111
|
+
groups.map! do |seq, group|
|
|
100
112
|
sels = group.map {|_, s| s}.flatten
|
|
101
113
|
# If A {@extend B} and C {...},
|
|
102
114
|
# seq is A, sels is B, and self is C
|
|
103
115
|
|
|
104
|
-
self_without_sel = Sass::Util.array_minus(
|
|
116
|
+
self_without_sel = Sass::Util.array_minus(members, sels)
|
|
105
117
|
group.each {|e, _| e.result = :failed_to_unify unless e.result == :succeeded}
|
|
106
|
-
|
|
118
|
+
unified = seq.members.last.unify(self_without_sel, subject?)
|
|
119
|
+
next unless unified
|
|
107
120
|
group.each {|e, _| e.result = :succeeded}
|
|
108
|
-
|
|
121
|
+
group.each {|e, _| check_directives_match!(e, parent_directives)}
|
|
109
122
|
new_seq = Sequence.new(seq.members[0...-1] + [unified])
|
|
110
123
|
new_seq.add_sources!(sources + [seq])
|
|
111
124
|
[sels, new_seq]
|
|
112
|
-
end
|
|
125
|
+
end
|
|
126
|
+
groups.compact!
|
|
127
|
+
groups.map! do |sels, seq|
|
|
113
128
|
seen.include?(sels) ? [] : seq.do_extend(extends, parent_directives, seen + [sels])
|
|
114
|
-
end
|
|
129
|
+
end
|
|
130
|
+
groups.flatten!
|
|
131
|
+
groups.uniq!
|
|
132
|
+
groups
|
|
115
133
|
end
|
|
116
134
|
|
|
117
|
-
# Unifies this selector with another {SimpleSequence}'s
|
|
118
|
-
# returning another `SimpleSequence`
|
|
135
|
+
# Unifies this selector with another {SimpleSequence}'s
|
|
136
|
+
# {SimpleSequence#members members array}, returning another `SimpleSequence`
|
|
119
137
|
# that matches both this selector and the input selector.
|
|
120
138
|
#
|
|
121
139
|
# @param sels [Array<Simple>] A {SimpleSequence}'s {SimpleSequence#members members array}
|
|
122
|
-
# @param
|
|
140
|
+
# @param other_subject [Boolean] Whether the other {SimpleSequence} being merged is a subject.
|
|
123
141
|
# @return [SimpleSequence, nil] A {SimpleSequence} matching both `sels` and this selector,
|
|
124
142
|
# or `nil` if this is impossible (e.g. unifying `#foo` and `#bar`)
|
|
125
143
|
# @raise [Sass::SyntaxError] If this selector cannot be unified.
|
|
@@ -129,10 +147,11 @@ module Sass
|
|
|
129
147
|
# by the time extension and unification happen,
|
|
130
148
|
# this exception will only ever be raised as a result of programmer error
|
|
131
149
|
def unify(sels, other_subject)
|
|
132
|
-
|
|
133
|
-
return unless
|
|
134
|
-
sel.unify(
|
|
150
|
+
sseq = members.inject(sels) do |member, sel|
|
|
151
|
+
return unless member
|
|
152
|
+
sel.unify(member)
|
|
135
153
|
end
|
|
154
|
+
return unless sseq
|
|
136
155
|
SimpleSequence.new(sseq, other_subject || subject?)
|
|
137
156
|
end
|
|
138
157
|
|
|
@@ -145,7 +164,9 @@ module Sass
|
|
|
145
164
|
# @param sseq [SimpleSequence]
|
|
146
165
|
# @return [Boolean]
|
|
147
166
|
def superselector?(sseq)
|
|
148
|
-
(base.nil? || base.eql?(sseq.base)) &&
|
|
167
|
+
(base.nil? || base.eql?(sseq.base)) &&
|
|
168
|
+
pseudo_elements.eql?(sseq.pseudo_elements) &&
|
|
169
|
+
rest.subset?(sseq.rest)
|
|
149
170
|
end
|
|
150
171
|
|
|
151
172
|
# @see Simple#to_a
|
|
@@ -164,14 +185,14 @@ module Sass
|
|
|
164
185
|
end
|
|
165
186
|
|
|
166
187
|
# Return a copy of this simple sequence with `sources` merged into the
|
|
167
|
-
# {#sources} set.
|
|
188
|
+
# {SimpleSequence#sources} set.
|
|
168
189
|
#
|
|
169
190
|
# @param sources [Set<Sequence>]
|
|
170
191
|
# @return [SimpleSequence]
|
|
171
192
|
def with_more_sources(sources)
|
|
172
193
|
sseq = dup
|
|
173
194
|
sseq.members = members.dup
|
|
174
|
-
sseq.sources.
|
|
195
|
+
sseq.sources = self.sources | sources
|
|
175
196
|
sseq
|
|
176
197
|
end
|
|
177
198
|
|
|
@@ -180,16 +201,17 @@ module Sass
|
|
|
180
201
|
def check_directives_match!(extend, parent_directives)
|
|
181
202
|
dirs1 = extend.directives.map {|d| d.resolved_value}
|
|
182
203
|
dirs2 = parent_directives.map {|d| d.resolved_value}
|
|
183
|
-
return
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
204
|
+
return if Sass::Util.subsequence?(dirs1, dirs2)
|
|
205
|
+
line = extend.node.line
|
|
206
|
+
filename = extend.node.filename
|
|
207
|
+
|
|
208
|
+
# TODO(nweiz): this should use the Sass stack trace of the extend node,
|
|
209
|
+
# not the selector.
|
|
210
|
+
raise Sass::SyntaxError.new(<<MESSAGE)
|
|
211
|
+
You may not @extend an outer selector from within #{extend.directives.last.name}.
|
|
212
|
+
You may only @extend selectors within the same directive.
|
|
213
|
+
From "@extend #{extend.target.join(', ')}" on line #{line}#{" of #{filename}" if filename}.
|
|
214
|
+
MESSAGE
|
|
193
215
|
end
|
|
194
216
|
|
|
195
217
|
def _hash
|
|
@@ -197,8 +219,8 @@ WARNING
|
|
|
197
219
|
end
|
|
198
220
|
|
|
199
221
|
def _eql?(other)
|
|
200
|
-
other.base.eql?(
|
|
201
|
-
other.subject? ==
|
|
222
|
+
other.base.eql?(base) && other.pseudo_elements == pseudo_elements &&
|
|
223
|
+
Sass::Util.set_eql?(other.rest, rest) && other.subject? == subject?
|
|
202
224
|
end
|
|
203
225
|
end
|
|
204
226
|
end
|