sass 3.1.0 → 3.3.0
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.
- checksums.yaml +7 -0
- data/CONTRIBUTING +1 -1
- data/MIT-LICENSE +2 -2
- data/README.md +29 -17
- data/Rakefile +43 -9
- data/VERSION +1 -1
- data/VERSION_DATE +1 -0
- data/VERSION_NAME +1 -1
- data/bin/sass +6 -1
- data/bin/sass-convert +6 -1
- data/bin/scss +6 -1
- data/ext/mkrf_conf.rb +27 -0
- data/lib/sass/cache_stores/base.rb +7 -3
- data/lib/sass/cache_stores/chain.rb +3 -2
- data/lib/sass/cache_stores/filesystem.rb +5 -7
- data/lib/sass/cache_stores/memory.rb +1 -1
- data/lib/sass/cache_stores/null.rb +2 -2
- data/lib/sass/callbacks.rb +2 -1
- data/lib/sass/css.rb +168 -53
- data/lib/sass/engine.rb +502 -174
- data/lib/sass/environment.rb +151 -111
- data/lib/sass/error.rb +7 -7
- data/lib/sass/exec.rb +176 -60
- data/lib/sass/features.rb +40 -0
- data/lib/sass/importers/base.rb +46 -7
- data/lib/sass/importers/deprecated_path.rb +51 -0
- data/lib/sass/importers/filesystem.rb +113 -30
- data/lib/sass/importers.rb +1 -0
- data/lib/sass/logger/base.rb +30 -0
- data/lib/sass/logger/log_level.rb +45 -0
- data/lib/sass/logger.rb +12 -0
- data/lib/sass/media.rb +213 -0
- data/lib/sass/plugin/compiler.rb +194 -104
- data/lib/sass/plugin/configuration.rb +18 -25
- data/lib/sass/plugin/merb.rb +1 -1
- data/lib/sass/plugin/staleness_checker.rb +37 -11
- data/lib/sass/plugin.rb +10 -13
- data/lib/sass/railtie.rb +2 -1
- data/lib/sass/repl.rb +5 -6
- data/lib/sass/script/css_lexer.rb +8 -4
- data/lib/sass/script/css_parser.rb +5 -2
- data/lib/sass/script/functions.rb +1547 -618
- data/lib/sass/script/lexer.rb +122 -72
- data/lib/sass/script/parser.rb +304 -135
- data/lib/sass/script/tree/funcall.rb +306 -0
- data/lib/sass/script/{interpolation.rb → tree/interpolation.rb} +43 -13
- data/lib/sass/script/tree/list_literal.rb +77 -0
- data/lib/sass/script/tree/literal.rb +45 -0
- data/lib/sass/script/tree/map_literal.rb +64 -0
- data/lib/sass/script/{node.rb → tree/node.rb} +30 -12
- data/lib/sass/script/{operation.rb → tree/operation.rb} +33 -21
- data/lib/sass/script/{string_interpolation.rb → tree/string_interpolation.rb} +14 -4
- data/lib/sass/script/{unary_operation.rb → tree/unary_operation.rb} +21 -9
- data/lib/sass/script/tree/variable.rb +57 -0
- data/lib/sass/script/tree.rb +15 -0
- data/lib/sass/script/value/arg_list.rb +36 -0
- data/lib/sass/script/value/base.rb +238 -0
- data/lib/sass/script/value/bool.rb +40 -0
- data/lib/sass/script/{color.rb → value/color.rb} +256 -74
- data/lib/sass/script/value/deprecated_false.rb +55 -0
- data/lib/sass/script/value/helpers.rb +155 -0
- data/lib/sass/script/value/list.rb +128 -0
- data/lib/sass/script/value/map.rb +70 -0
- data/lib/sass/script/value/null.rb +49 -0
- data/lib/sass/script/{number.rb → value/number.rb} +115 -62
- data/lib/sass/script/{string.rb → value/string.rb} +9 -11
- data/lib/sass/script/value.rb +12 -0
- data/lib/sass/script.rb +35 -9
- data/lib/sass/scss/css_parser.rb +2 -12
- data/lib/sass/scss/parser.rb +657 -230
- data/lib/sass/scss/rx.rb +17 -12
- data/lib/sass/scss/static_parser.rb +37 -6
- data/lib/sass/scss.rb +0 -1
- data/lib/sass/selector/abstract_sequence.rb +35 -3
- data/lib/sass/selector/comma_sequence.rb +29 -14
- data/lib/sass/selector/sequence.rb +371 -74
- data/lib/sass/selector/simple.rb +28 -13
- data/lib/sass/selector/simple_sequence.rb +163 -36
- data/lib/sass/selector.rb +138 -36
- data/lib/sass/shared.rb +3 -5
- data/lib/sass/source/map.rb +196 -0
- data/lib/sass/source/position.rb +39 -0
- data/lib/sass/source/range.rb +41 -0
- data/lib/sass/stack.rb +126 -0
- data/lib/sass/supports.rb +228 -0
- data/lib/sass/tree/at_root_node.rb +82 -0
- data/lib/sass/tree/comment_node.rb +34 -29
- data/lib/sass/tree/content_node.rb +9 -0
- data/lib/sass/tree/css_import_node.rb +60 -0
- data/lib/sass/tree/debug_node.rb +3 -3
- data/lib/sass/tree/directive_node.rb +33 -3
- data/lib/sass/tree/each_node.rb +9 -9
- data/lib/sass/tree/extend_node.rb +20 -6
- data/lib/sass/tree/for_node.rb +6 -6
- data/lib/sass/tree/function_node.rb +12 -4
- data/lib/sass/tree/if_node.rb +2 -15
- data/lib/sass/tree/import_node.rb +11 -5
- data/lib/sass/tree/media_node.rb +27 -11
- data/lib/sass/tree/mixin_def_node.rb +15 -4
- data/lib/sass/tree/mixin_node.rb +27 -7
- data/lib/sass/tree/node.rb +69 -35
- data/lib/sass/tree/prop_node.rb +47 -31
- data/lib/sass/tree/return_node.rb +4 -3
- data/lib/sass/tree/root_node.rb +20 -4
- data/lib/sass/tree/rule_node.rb +37 -26
- data/lib/sass/tree/supports_node.rb +38 -0
- data/lib/sass/tree/trace_node.rb +33 -0
- data/lib/sass/tree/variable_node.rb +10 -4
- data/lib/sass/tree/visitors/base.rb +5 -8
- data/lib/sass/tree/visitors/check_nesting.rb +67 -52
- data/lib/sass/tree/visitors/convert.rb +134 -53
- data/lib/sass/tree/visitors/cssize.rb +245 -51
- data/lib/sass/tree/visitors/deep_copy.rb +102 -0
- data/lib/sass/tree/visitors/extend.rb +68 -0
- data/lib/sass/tree/visitors/perform.rb +331 -105
- data/lib/sass/tree/visitors/set_options.rb +125 -0
- data/lib/sass/tree/visitors/to_css.rb +259 -95
- data/lib/sass/tree/warn_node.rb +3 -3
- data/lib/sass/tree/while_node.rb +3 -3
- data/lib/sass/util/cross_platform_random.rb +19 -0
- data/lib/sass/util/multibyte_string_scanner.rb +157 -0
- data/lib/sass/util/normalized_map.rb +130 -0
- data/lib/sass/util/ordered_hash.rb +192 -0
- data/lib/sass/util/subset_map.rb +11 -2
- data/lib/sass/util/test.rb +9 -0
- data/lib/sass/util.rb +565 -39
- data/lib/sass/version.rb +27 -15
- data/lib/sass.rb +39 -4
- data/test/sass/cache_test.rb +15 -0
- data/test/sass/compiler_test.rb +223 -0
- data/test/sass/conversion_test.rb +901 -107
- data/test/sass/css2sass_test.rb +94 -0
- data/test/sass/engine_test.rb +1059 -164
- data/test/sass/exec_test.rb +86 -0
- data/test/sass/extend_test.rb +933 -837
- data/test/sass/fixtures/test_staleness_check_across_importers.css +1 -0
- data/test/sass/fixtures/test_staleness_check_across_importers.scss +1 -0
- data/test/sass/functions_test.rb +995 -136
- data/test/sass/importer_test.rb +338 -18
- data/test/sass/logger_test.rb +58 -0
- data/test/sass/more_results/more_import.css +2 -2
- data/test/sass/plugin_test.rb +114 -30
- data/test/sass/results/cached_import_option.css +3 -0
- data/test/sass/results/filename_fn.css +3 -0
- data/test/sass/results/import.css +2 -2
- data/test/sass/results/import_charset.css +1 -0
- data/test/sass/results/import_charset_1_8.css +1 -0
- data/test/sass/results/import_charset_ibm866.css +1 -0
- data/test/sass/results/import_content.css +1 -0
- data/test/sass/results/script.css +1 -1
- data/test/sass/results/scss_import.css +2 -2
- data/test/sass/results/units.css +2 -2
- data/test/sass/script_conversion_test.rb +43 -1
- data/test/sass/script_test.rb +380 -36
- data/test/sass/scss/css_test.rb +257 -75
- data/test/sass/scss/scss_test.rb +2322 -110
- data/test/sass/source_map_test.rb +887 -0
- data/test/sass/templates/_cached_import_option_partial.scss +1 -0
- data/test/sass/templates/_double_import_loop2.sass +1 -0
- data/test/sass/templates/_filename_fn_import.scss +11 -0
- data/test/sass/templates/_imported_content.sass +3 -0
- data/test/sass/templates/_same_name_different_partiality.scss +1 -0
- data/test/sass/templates/bork5.sass +3 -0
- data/test/sass/templates/cached_import_option.scss +3 -0
- data/test/sass/templates/double_import_loop1.sass +1 -0
- data/test/sass/templates/filename_fn.scss +18 -0
- data/test/sass/templates/import_charset.sass +2 -0
- data/test/sass/templates/import_charset_1_8.sass +2 -0
- data/test/sass/templates/import_charset_ibm866.sass +2 -0
- data/test/sass/templates/import_content.sass +4 -0
- data/test/sass/templates/same_name_different_ext.sass +2 -0
- data/test/sass/templates/same_name_different_ext.scss +1 -0
- data/test/sass/templates/same_name_different_partiality.scss +1 -0
- data/test/sass/templates/single_import_loop.sass +1 -0
- data/test/sass/templates/subdir/import_up1.scss +1 -0
- data/test/sass/templates/subdir/import_up2.scss +1 -0
- data/test/sass/test_helper.rb +1 -1
- data/test/sass/util/multibyte_string_scanner_test.rb +147 -0
- data/test/sass/util/normalized_map_test.rb +51 -0
- data/test/sass/util_test.rb +183 -0
- data/test/sass/value_helpers_test.rb +181 -0
- data/test/test_helper.rb +45 -5
- data/vendor/listen/CHANGELOG.md +228 -0
- data/vendor/listen/CONTRIBUTING.md +38 -0
- data/vendor/listen/Gemfile +30 -0
- data/vendor/listen/Guardfile +8 -0
- data/vendor/{fssm → listen}/LICENSE +1 -1
- data/vendor/listen/README.md +315 -0
- data/vendor/listen/Rakefile +47 -0
- data/vendor/listen/Vagrantfile +96 -0
- data/vendor/listen/lib/listen/adapter.rb +214 -0
- data/vendor/listen/lib/listen/adapters/bsd.rb +112 -0
- data/vendor/listen/lib/listen/adapters/darwin.rb +85 -0
- data/vendor/listen/lib/listen/adapters/linux.rb +113 -0
- data/vendor/listen/lib/listen/adapters/polling.rb +67 -0
- data/vendor/listen/lib/listen/adapters/windows.rb +87 -0
- data/vendor/listen/lib/listen/dependency_manager.rb +126 -0
- data/vendor/listen/lib/listen/directory_record.rb +371 -0
- data/vendor/listen/lib/listen/listener.rb +225 -0
- data/vendor/listen/lib/listen/multi_listener.rb +143 -0
- data/vendor/listen/lib/listen/turnstile.rb +28 -0
- data/vendor/listen/lib/listen/version.rb +3 -0
- data/vendor/listen/lib/listen.rb +40 -0
- data/vendor/listen/listen.gemspec +22 -0
- data/vendor/listen/spec/listen/adapter_spec.rb +183 -0
- data/vendor/listen/spec/listen/adapters/bsd_spec.rb +36 -0
- data/vendor/listen/spec/listen/adapters/darwin_spec.rb +37 -0
- data/vendor/listen/spec/listen/adapters/linux_spec.rb +47 -0
- data/vendor/listen/spec/listen/adapters/polling_spec.rb +68 -0
- data/vendor/listen/spec/listen/adapters/windows_spec.rb +30 -0
- data/vendor/listen/spec/listen/dependency_manager_spec.rb +107 -0
- data/vendor/listen/spec/listen/directory_record_spec.rb +1225 -0
- data/vendor/listen/spec/listen/listener_spec.rb +169 -0
- data/vendor/listen/spec/listen/multi_listener_spec.rb +174 -0
- data/vendor/listen/spec/listen/turnstile_spec.rb +56 -0
- data/vendor/listen/spec/listen_spec.rb +73 -0
- data/vendor/listen/spec/spec_helper.rb +21 -0
- data/vendor/listen/spec/support/adapter_helper.rb +629 -0
- data/vendor/listen/spec/support/directory_record_helper.rb +55 -0
- data/vendor/listen/spec/support/fixtures_helper.rb +29 -0
- data/vendor/listen/spec/support/listeners_helper.rb +156 -0
- data/vendor/listen/spec/support/platform_helper.rb +15 -0
- metadata +344 -271
- data/lib/sass/less.rb +0 -382
- data/lib/sass/script/bool.rb +0 -18
- data/lib/sass/script/funcall.rb +0 -162
- data/lib/sass/script/list.rb +0 -76
- data/lib/sass/script/literal.rb +0 -245
- data/lib/sass/script/variable.rb +0 -54
- data/lib/sass/scss/sass_parser.rb +0 -11
- data/test/sass/less_conversion_test.rb +0 -653
- data/vendor/fssm/README.markdown +0 -55
- data/vendor/fssm/Rakefile +0 -59
- data/vendor/fssm/VERSION.yml +0 -5
- data/vendor/fssm/example.rb +0 -9
- data/vendor/fssm/fssm.gemspec +0 -77
- data/vendor/fssm/lib/fssm/backends/fsevents.rb +0 -36
- data/vendor/fssm/lib/fssm/backends/inotify.rb +0 -26
- data/vendor/fssm/lib/fssm/backends/polling.rb +0 -25
- data/vendor/fssm/lib/fssm/backends/rubycocoa/fsevents.rb +0 -131
- data/vendor/fssm/lib/fssm/monitor.rb +0 -26
- data/vendor/fssm/lib/fssm/path.rb +0 -91
- data/vendor/fssm/lib/fssm/pathname.rb +0 -502
- data/vendor/fssm/lib/fssm/state/directory.rb +0 -57
- data/vendor/fssm/lib/fssm/state/file.rb +0 -24
- data/vendor/fssm/lib/fssm/support.rb +0 -63
- data/vendor/fssm/lib/fssm/tree.rb +0 -176
- data/vendor/fssm/lib/fssm.rb +0 -33
- data/vendor/fssm/profile/prof-cache.rb +0 -40
- data/vendor/fssm/profile/prof-fssm-pathname.html +0 -1231
- data/vendor/fssm/profile/prof-pathname.rb +0 -68
- data/vendor/fssm/profile/prof-plain-pathname.html +0 -988
- data/vendor/fssm/profile/prof.html +0 -2379
- data/vendor/fssm/spec/path_spec.rb +0 -75
- data/vendor/fssm/spec/root/duck/quack.txt +0 -0
- data/vendor/fssm/spec/root/file.css +0 -0
- data/vendor/fssm/spec/root/file.rb +0 -0
- data/vendor/fssm/spec/root/file.yml +0 -0
- data/vendor/fssm/spec/root/moo/cow.txt +0 -0
- data/vendor/fssm/spec/spec_helper.rb +0 -14
@@ -8,7 +8,31 @@ module Sass
|
|
8
8
|
# The array of individual selectors.
|
9
9
|
#
|
10
10
|
# @return [Array<Simple>]
|
11
|
-
|
11
|
+
attr_accessor :members
|
12
|
+
|
13
|
+
# The extending selectors that caused this selector sequence to be
|
14
|
+
# generated. For example:
|
15
|
+
#
|
16
|
+
# a.foo { ... }
|
17
|
+
# b.bar {@extend a}
|
18
|
+
# c.baz {@extend b}
|
19
|
+
#
|
20
|
+
# The generated selector `b.foo.bar` has `{b.bar}` as its `sources` set,
|
21
|
+
# and the generated selector `c.foo.bar.baz` has `{b.bar, c.baz}` as its
|
22
|
+
# `sources` set.
|
23
|
+
#
|
24
|
+
# This is populated during the {Sequence#do_extend} process.
|
25
|
+
#
|
26
|
+
# @return {Set<Sequence>}
|
27
|
+
attr_accessor :sources
|
28
|
+
|
29
|
+
# This sequence source range.
|
30
|
+
#
|
31
|
+
# @return [Sass::Source::Range]
|
32
|
+
attr_accessor :source_range
|
33
|
+
|
34
|
+
# @see \{#subject?}
|
35
|
+
attr_writer :subject
|
12
36
|
|
13
37
|
# Returns the element or universal selector in this sequence,
|
14
38
|
# if it exists.
|
@@ -18,67 +42,136 @@ module Sass
|
|
18
42
|
@base ||= (members.first if members.first.is_a?(Element) || members.first.is_a?(Universal))
|
19
43
|
end
|
20
44
|
|
21
|
-
|
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.
|
22
51
|
#
|
23
52
|
# @return [Set<Simple>]
|
24
53
|
def rest
|
25
|
-
@rest ||= Set.new(
|
54
|
+
@rest ||= Set.new(members - [base] - pseudo_elements)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Whether or not this compound selector is the subject of the parent
|
58
|
+
# selector; that is, whether it is prepended with `$` and represents the
|
59
|
+
# actual element that will be selected.
|
60
|
+
#
|
61
|
+
# @return [Boolean]
|
62
|
+
def subject?
|
63
|
+
@subject
|
26
64
|
end
|
27
65
|
|
28
66
|
# @param selectors [Array<Simple>] See \{#members}
|
29
|
-
|
67
|
+
# @param subject [Boolean] See \{#subject?}
|
68
|
+
# @param source_range [Sass::Source::Range]
|
69
|
+
def initialize(selectors, subject, source_range = nil)
|
30
70
|
@members = selectors
|
71
|
+
@subject = subject
|
72
|
+
@sources = Set.new
|
73
|
+
@source_range = source_range
|
31
74
|
end
|
32
75
|
|
33
76
|
# Resolves the {Parent} selectors within this selector
|
34
77
|
# by replacing them with the given parent selector,
|
35
78
|
# handling commas appropriately.
|
36
79
|
#
|
37
|
-
# @param
|
38
|
-
# @return [
|
39
|
-
# This is an array because the parent selector is itself a {Sequence}
|
80
|
+
# @param super_cseq [CommaSequence] The parent selector
|
81
|
+
# @return [CommaSequence] This selector, with parent references resolved
|
40
82
|
# @raise [Sass::SyntaxError] If a parent selector is invalid
|
41
|
-
def resolve_parent_refs(
|
83
|
+
def resolve_parent_refs(super_cseq)
|
42
84
|
# Parent selector only appears as the first selector in the sequence
|
43
|
-
|
44
|
-
|
45
|
-
return super_seq.members if @members.size == 1
|
46
|
-
unless super_seq.members.last.is_a?(SimpleSequence)
|
47
|
-
raise Sass::SyntaxError.new("Invalid parent selector: " + super_seq.to_a.join)
|
85
|
+
unless (parent = @members.first).is_a?(Parent)
|
86
|
+
return CommaSequence.new([Sequence.new([self])])
|
48
87
|
end
|
49
88
|
|
50
|
-
|
51
|
-
|
89
|
+
return super_cseq if @members.size == 1 && parent.suffix.empty?
|
90
|
+
|
91
|
+
CommaSequence.new(super_cseq.members.map do |super_seq|
|
92
|
+
members = super_seq.members.dup
|
93
|
+
newline = members.pop if members.last == "\n"
|
94
|
+
unless members.last.is_a?(SimpleSequence)
|
95
|
+
raise Sass::SyntaxError.new("Invalid parent selector for \"#{self}\": \"" +
|
96
|
+
super_seq.to_a.join + '"')
|
97
|
+
end
|
98
|
+
|
99
|
+
parent_sub = members.last.members
|
100
|
+
unless parent.suffix.empty?
|
101
|
+
parent_sub = parent_sub.dup
|
102
|
+
parent_sub[-1] = parent_sub.last.dup
|
103
|
+
case parent_sub.last
|
104
|
+
when Sass::Selector::Class, Sass::Selector::Id, Sass::Selector::Placeholder
|
105
|
+
parent_sub[-1] = parent_sub.last.class.new(parent_sub.last.name + parent.suffix)
|
106
|
+
when Sass::Selector::Element
|
107
|
+
parent_sub[-1] = parent_sub.last.class.new(
|
108
|
+
parent_sub.last.name + parent.suffix,
|
109
|
+
parent_sub.last.namespace)
|
110
|
+
when Sass::Selector::Pseudo
|
111
|
+
if parent_sub.last.arg
|
112
|
+
raise Sass::SyntaxError.new("Invalid parent selector for \"#{self}\": \"" +
|
113
|
+
super_seq.to_a.join + '"')
|
114
|
+
end
|
115
|
+
parent_sub[-1] = parent_sub.last.class.new(
|
116
|
+
parent_sub.last.type,
|
117
|
+
parent_sub.last.name + parent.suffix,
|
118
|
+
nil)
|
119
|
+
else
|
120
|
+
raise Sass::SyntaxError.new("Invalid parent selector for \"#{self}\": \"" +
|
121
|
+
super_seq.to_a.join + '"')
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
Sequence.new(members[0...-1] +
|
126
|
+
[SimpleSequence.new(parent_sub + @members[1..-1], subject?)] +
|
127
|
+
[newline].compact)
|
128
|
+
end)
|
52
129
|
end
|
53
130
|
|
54
131
|
# Non-destrucively extends this selector with the extensions specified in a hash
|
55
132
|
# (which should come from {Sass::Tree::Visitors::Cssize}).
|
56
133
|
#
|
57
|
-
# @overload def do_extend(extends)
|
58
|
-
# @param extends [{Selector::Simple =>
|
134
|
+
# @overload def do_extend(extends, parent_directives)
|
135
|
+
# @param extends [{Selector::Simple =>
|
136
|
+
# Sass::Tree::Visitors::Cssize::Extend}]
|
59
137
|
# The extensions to perform on this selector
|
138
|
+
# @param parent_directives [Array<Sass::Tree::DirectiveNode>]
|
139
|
+
# The directives containing this selector.
|
60
140
|
# @return [Array<Sequence>] A list of selectors generated
|
61
141
|
# by extending this selector with `extends`.
|
62
142
|
# @see CommaSequence#do_extend
|
63
|
-
def do_extend(extends, seen = Set.new)
|
64
|
-
|
143
|
+
def do_extend(extends, parent_directives, seen = Set.new)
|
144
|
+
groups = Sass::Util.group_by_to_a(extends[members.to_set]) {|ex| ex.extender}
|
145
|
+
groups.map! do |seq, group|
|
146
|
+
sels = group.map {|e| e.target}.flatten
|
65
147
|
# If A {@extend B} and C {...},
|
66
148
|
# seq is A, sels is B, and self is C
|
67
149
|
|
68
|
-
self_without_sel =
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
150
|
+
self_without_sel = Sass::Util.array_minus(members, sels)
|
151
|
+
group.each {|e| e.result = :failed_to_unify unless e.result == :succeeded}
|
152
|
+
unified = seq.members.last.unify(self_without_sel, subject?)
|
153
|
+
next unless unified
|
154
|
+
group.each {|e| e.result = :succeeded}
|
155
|
+
group.each {|e| check_directives_match!(e, parent_directives)}
|
156
|
+
new_seq = Sequence.new(seq.members[0...-1] + [unified])
|
157
|
+
new_seq.add_sources!(sources + [seq])
|
158
|
+
[sels, new_seq]
|
159
|
+
end
|
160
|
+
groups.compact!
|
161
|
+
groups.map! do |sels, seq|
|
162
|
+
seen.include?(sels) ? [] : seq.do_extend(extends, parent_directives, seen + [sels])
|
163
|
+
end
|
164
|
+
groups.flatten!
|
165
|
+
groups.uniq!
|
166
|
+
groups
|
75
167
|
end
|
76
168
|
|
77
|
-
# Unifies this selector with another {SimpleSequence}'s
|
78
|
-
# returning another `SimpleSequence`
|
169
|
+
# Unifies this selector with another {SimpleSequence}'s
|
170
|
+
# {SimpleSequence#members members array}, returning another `SimpleSequence`
|
79
171
|
# that matches both this selector and the input selector.
|
80
172
|
#
|
81
173
|
# @param sels [Array<Simple>] A {SimpleSequence}'s {SimpleSequence#members members array}
|
174
|
+
# @param other_subject [Boolean] Whether the other {SimpleSequence} being merged is a subject.
|
82
175
|
# @return [SimpleSequence, nil] A {SimpleSequence} matching both `sels` and this selector,
|
83
176
|
# or `nil` if this is impossible (e.g. unifying `#foo` and `#bar`)
|
84
177
|
# @raise [Sass::SyntaxError] If this selector cannot be unified.
|
@@ -87,12 +180,13 @@ module Sass
|
|
87
180
|
# Since these selectors should be resolved
|
88
181
|
# by the time extension and unification happen,
|
89
182
|
# this exception will only ever be raised as a result of programmer error
|
90
|
-
def unify(sels)
|
91
|
-
|
92
|
-
return unless
|
93
|
-
sel.unify(
|
183
|
+
def unify(sels, other_subject)
|
184
|
+
sseq = members.inject(sels) do |member, sel|
|
185
|
+
return unless member
|
186
|
+
sel.unify(member)
|
94
187
|
end
|
95
|
-
|
188
|
+
return unless sseq
|
189
|
+
SimpleSequence.new(sseq, other_subject || subject?)
|
96
190
|
end
|
97
191
|
|
98
192
|
# Returns whether or not this selector matches all elements
|
@@ -104,12 +198,16 @@ module Sass
|
|
104
198
|
# @param sseq [SimpleSequence]
|
105
199
|
# @return [Boolean]
|
106
200
|
def superselector?(sseq)
|
107
|
-
(base.nil? || base.eql?(sseq.base)) &&
|
201
|
+
(base.nil? || base.eql?(sseq.base)) &&
|
202
|
+
pseudo_elements.eql?(sseq.pseudo_elements) &&
|
203
|
+
rest.subset?(sseq.rest)
|
108
204
|
end
|
109
205
|
|
110
206
|
# @see Simple#to_a
|
111
207
|
def to_a
|
112
|
-
@members.map {|sel| sel.to_a}.flatten
|
208
|
+
res = @members.map {|sel| sel.to_a}.flatten
|
209
|
+
res << '!' if subject?
|
210
|
+
res
|
113
211
|
end
|
114
212
|
|
115
213
|
# Returns a string representation of the sequence.
|
@@ -120,14 +218,43 @@ module Sass
|
|
120
218
|
members.map {|m| m.inspect}.join
|
121
219
|
end
|
122
220
|
|
221
|
+
# Return a copy of this simple sequence with `sources` merged into the
|
222
|
+
# {SimpleSequence#sources} set.
|
223
|
+
#
|
224
|
+
# @param sources [Set<Sequence>]
|
225
|
+
# @return [SimpleSequence]
|
226
|
+
def with_more_sources(sources)
|
227
|
+
sseq = dup
|
228
|
+
sseq.members = members.dup
|
229
|
+
sseq.sources = self.sources | sources
|
230
|
+
sseq
|
231
|
+
end
|
232
|
+
|
123
233
|
private
|
124
234
|
|
235
|
+
def check_directives_match!(extend, parent_directives)
|
236
|
+
dirs1 = extend.directives.map {|d| d.resolved_value}
|
237
|
+
dirs2 = parent_directives.map {|d| d.resolved_value}
|
238
|
+
return if Sass::Util.subsequence?(dirs1, dirs2)
|
239
|
+
line = extend.node.line
|
240
|
+
filename = extend.node.filename
|
241
|
+
|
242
|
+
# TODO(nweiz): this should use the Sass stack trace of the extend node,
|
243
|
+
# not the selector.
|
244
|
+
raise Sass::SyntaxError.new(<<MESSAGE)
|
245
|
+
You may not @extend an outer selector from within #{extend.directives.last.name}.
|
246
|
+
You may only @extend selectors within the same directive.
|
247
|
+
From "@extend #{extend.target.join(', ')}" on line #{line}#{" of #{filename}" if filename}.
|
248
|
+
MESSAGE
|
249
|
+
end
|
250
|
+
|
125
251
|
def _hash
|
126
252
|
[base, Sass::Util.set_hash(rest)].hash
|
127
253
|
end
|
128
254
|
|
129
255
|
def _eql?(other)
|
130
|
-
other.base.eql?(
|
256
|
+
other.base.eql?(base) && other.pseudo_elements == pseudo_elements &&
|
257
|
+
Sass::Util.set_eql?(other.rest, rest) && other.subject? == subject?
|
131
258
|
end
|
132
259
|
end
|
133
260
|
end
|
data/lib/sass/selector.rb
CHANGED
@@ -18,13 +18,28 @@ module Sass
|
|
18
18
|
# Finally, {Simple} is the superclass of the simplest selectors,
|
19
19
|
# such as `.foo` or `#bar`.
|
20
20
|
module Selector
|
21
|
+
# The base used for calculating selector specificity. The spec says this
|
22
|
+
# should be "sufficiently high"; it's extremely unlikely that any single
|
23
|
+
# selector sequence will contain 1,000 simple selectors.
|
24
|
+
SPECIFICITY_BASE = 1_000
|
25
|
+
|
21
26
|
# A parent-referencing selector (`&` in Sass).
|
22
27
|
# The function of this is to be replaced by the parent selector
|
23
28
|
# in the nested hierarchy.
|
24
29
|
class Parent < Simple
|
30
|
+
# The identifier following the `&`. Often empty.
|
31
|
+
#
|
32
|
+
# @return [Array<String, Sass::Script::Tree::Node>]
|
33
|
+
attr_reader :suffix
|
34
|
+
|
35
|
+
# @param name [Array<String, Sass::Script::Tree::Node>] See \{#suffix}
|
36
|
+
def initialize(suffix = [])
|
37
|
+
@suffix = suffix
|
38
|
+
end
|
39
|
+
|
25
40
|
# @see Selector#to_a
|
26
41
|
def to_a
|
27
|
-
["&"]
|
42
|
+
["&", *@suffix]
|
28
43
|
end
|
29
44
|
|
30
45
|
# Always raises an exception.
|
@@ -40,10 +55,10 @@ module Sass
|
|
40
55
|
class Class < Simple
|
41
56
|
# The class name.
|
42
57
|
#
|
43
|
-
# @return [Array<String, Sass::Script::Node>]
|
58
|
+
# @return [Array<String, Sass::Script::Tree::Node>]
|
44
59
|
attr_reader :name
|
45
60
|
|
46
|
-
# @param name [Array<String, Sass::Script::Node>] The class name
|
61
|
+
# @param name [Array<String, Sass::Script::Tree::Node>] The class name
|
47
62
|
def initialize(name)
|
48
63
|
@name = name
|
49
64
|
end
|
@@ -52,16 +67,21 @@ module Sass
|
|
52
67
|
def to_a
|
53
68
|
[".", *@name]
|
54
69
|
end
|
70
|
+
|
71
|
+
# @see AbstractSequence#specificity
|
72
|
+
def specificity
|
73
|
+
SPECIFICITY_BASE
|
74
|
+
end
|
55
75
|
end
|
56
76
|
|
57
77
|
# An id selector (e.g. `#foo`).
|
58
78
|
class Id < Simple
|
59
79
|
# The id name.
|
60
80
|
#
|
61
|
-
# @return [Array<String, Sass::Script::Node>]
|
81
|
+
# @return [Array<String, Sass::Script::Tree::Node>]
|
62
82
|
attr_reader :name
|
63
83
|
|
64
|
-
# @param name [Array<String, Sass::Script::Node>] The id name
|
84
|
+
# @param name [Array<String, Sass::Script::Tree::Node>] The id name
|
65
85
|
def initialize(name)
|
66
86
|
@name = name
|
67
87
|
end
|
@@ -76,9 +96,40 @@ module Sass
|
|
76
96
|
#
|
77
97
|
# @see Selector#unify
|
78
98
|
def unify(sels)
|
79
|
-
return if sels.any? {|sel2| sel2.is_a?(Id) &&
|
99
|
+
return if sels.any? {|sel2| sel2.is_a?(Id) && name != sel2.name}
|
80
100
|
super
|
81
101
|
end
|
102
|
+
|
103
|
+
# @see AbstractSequence#specificity
|
104
|
+
def specificity
|
105
|
+
SPECIFICITY_BASE**2
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# A placeholder selector (e.g. `%foo`).
|
110
|
+
# This exists to be replaced via `@extend`.
|
111
|
+
# Rulesets using this selector will not be printed, but can be extended.
|
112
|
+
# Otherwise, this acts just like a class selector.
|
113
|
+
class Placeholder < Simple
|
114
|
+
# The placeholder name.
|
115
|
+
#
|
116
|
+
# @return [Array<String, Sass::Script::Tree::Node>]
|
117
|
+
attr_reader :name
|
118
|
+
|
119
|
+
# @param name [Array<String, Sass::Script::Tree::Node>] The placeholder name
|
120
|
+
def initialize(name)
|
121
|
+
@name = name
|
122
|
+
end
|
123
|
+
|
124
|
+
# @see Selector#to_a
|
125
|
+
def to_a
|
126
|
+
["%", *@name]
|
127
|
+
end
|
128
|
+
|
129
|
+
# @see AbstractSequence#specificity
|
130
|
+
def specificity
|
131
|
+
SPECIFICITY_BASE
|
132
|
+
end
|
82
133
|
end
|
83
134
|
|
84
135
|
# A universal selector (`*` in CSS).
|
@@ -88,10 +139,10 @@ module Sass
|
|
88
139
|
# `[""]` means no namespace,
|
89
140
|
# `["*"]` means any namespace.
|
90
141
|
#
|
91
|
-
# @return [Array<String, Sass::Script::Node>, nil]
|
142
|
+
# @return [Array<String, Sass::Script::Tree::Node>, nil]
|
92
143
|
attr_reader :namespace
|
93
144
|
|
94
|
-
# @param namespace [Array<String, Sass::Script::Node>, nil] See \{#namespace}
|
145
|
+
# @param namespace [Array<String, Sass::Script::Tree::Node>, nil] See \{#namespace}
|
95
146
|
def initialize(namespace)
|
96
147
|
@namespace = namespace
|
97
148
|
end
|
@@ -141,13 +192,18 @@ module Sass
|
|
141
192
|
return unless accept
|
142
193
|
[name == :universal ? Universal.new(ns) : Element.new(name, ns)] + sels[1..-1]
|
143
194
|
end
|
195
|
+
|
196
|
+
# @see AbstractSequence#specificity
|
197
|
+
def specificity
|
198
|
+
0
|
199
|
+
end
|
144
200
|
end
|
145
201
|
|
146
202
|
# An element selector (e.g. `h1`).
|
147
203
|
class Element < Simple
|
148
204
|
# The element name.
|
149
205
|
#
|
150
|
-
# @return [Array<String, Sass::Script::Node>]
|
206
|
+
# @return [Array<String, Sass::Script::Tree::Node>]
|
151
207
|
attr_reader :name
|
152
208
|
|
153
209
|
# The selector namespace.
|
@@ -155,11 +211,11 @@ module Sass
|
|
155
211
|
# `[""]` means no namespace,
|
156
212
|
# `["*"]` means any namespace.
|
157
213
|
#
|
158
|
-
# @return [Array<String, Sass::Script::Node>, nil]
|
214
|
+
# @return [Array<String, Sass::Script::Tree::Node>, nil]
|
159
215
|
attr_reader :namespace
|
160
216
|
|
161
|
-
# @param name [Array<String, Sass::Script::Node>] The element name
|
162
|
-
# @param namespace [Array<String, Sass::Script::Node>, nil] See \{#namespace}
|
217
|
+
# @param name [Array<String, Sass::Script::Tree::Node>] The element name
|
218
|
+
# @param namespace [Array<String, Sass::Script::Tree::Node>, nil] See \{#namespace}
|
163
219
|
def initialize(name, namespace)
|
164
220
|
@name = name
|
165
221
|
@namespace = namespace
|
@@ -203,16 +259,21 @@ module Sass
|
|
203
259
|
return unless accept
|
204
260
|
[Element.new(name, ns)] + sels[1..-1]
|
205
261
|
end
|
262
|
+
|
263
|
+
# @see AbstractSequence#specificity
|
264
|
+
def specificity
|
265
|
+
1
|
266
|
+
end
|
206
267
|
end
|
207
268
|
|
208
269
|
# Selector interpolation (`#{}` in Sass).
|
209
270
|
class Interpolation < Simple
|
210
271
|
# The script to run.
|
211
272
|
#
|
212
|
-
# @return [Sass::Script::Node]
|
273
|
+
# @return [Sass::Script::Tree::Node]
|
213
274
|
attr_reader :script
|
214
275
|
|
215
|
-
# @param script [Sass::Script::Node] The script to run
|
276
|
+
# @param script [Sass::Script::Tree::Node] The script to run
|
216
277
|
def initialize(script)
|
217
278
|
@script = script
|
218
279
|
end
|
@@ -235,7 +296,7 @@ module Sass
|
|
235
296
|
class Attribute < Simple
|
236
297
|
# The attribute name.
|
237
298
|
#
|
238
|
-
# @return [Array<String, Sass::Script::Node>]
|
299
|
+
# @return [Array<String, Sass::Script::Tree::Node>]
|
239
300
|
attr_reader :name
|
240
301
|
|
241
302
|
# The attribute namespace.
|
@@ -243,7 +304,7 @@ module Sass
|
|
243
304
|
# `[""]` means no namespace,
|
244
305
|
# `["*"]` means any namespace.
|
245
306
|
#
|
246
|
-
# @return [Array<String, Sass::Script::Node>, nil]
|
307
|
+
# @return [Array<String, Sass::Script::Tree::Node>, nil]
|
247
308
|
attr_reader :namespace
|
248
309
|
|
249
310
|
# The matching operator, e.g. `"="` or `"^="`.
|
@@ -253,18 +314,28 @@ module Sass
|
|
253
314
|
|
254
315
|
# The right-hand side of the operator.
|
255
316
|
#
|
256
|
-
# @return [Array<String, Sass::Script::Node>]
|
317
|
+
# @return [Array<String, Sass::Script::Tree::Node>]
|
257
318
|
attr_reader :value
|
258
319
|
|
259
|
-
#
|
260
|
-
#
|
320
|
+
# Flags for the attribute selector (e.g. `i`).
|
321
|
+
#
|
322
|
+
# @return [Array<String, Sass::Script::Tree::Node>]
|
323
|
+
attr_reader :flags
|
324
|
+
|
325
|
+
# @param name [Array<String, Sass::Script::Tree::Node>] The attribute name
|
326
|
+
# @param namespace [Array<String, Sass::Script::Tree::Node>, nil] See \{#namespace}
|
261
327
|
# @param operator [String] The matching operator, e.g. `"="` or `"^="`
|
262
|
-
# @param value [Array<String, Sass::Script::Node>] See \{#value}
|
263
|
-
|
328
|
+
# @param value [Array<String, Sass::Script::Tree::Node>] See \{#value}
|
329
|
+
# @param flags [Array<String, Sass::Script::Tree::Node>] See \{#flags}
|
330
|
+
# @comment
|
331
|
+
# rubocop:disable ParameterLists
|
332
|
+
def initialize(name, namespace, operator, value, flags)
|
333
|
+
# rubocop:enable ParameterLists
|
264
334
|
@name = name
|
265
335
|
@namespace = namespace
|
266
336
|
@operator = operator
|
267
337
|
@value = value
|
338
|
+
@flags = flags
|
268
339
|
end
|
269
340
|
|
270
341
|
# @see Selector#to_a
|
@@ -273,23 +344,36 @@ module Sass
|
|
273
344
|
res.concat(@namespace) << "|" if @namespace
|
274
345
|
res.concat @name
|
275
346
|
(res << @operator).concat @value if @value
|
347
|
+
(res << " ").concat @flags if @flags
|
276
348
|
res << "]"
|
277
349
|
end
|
350
|
+
|
351
|
+
# @see AbstractSequence#specificity
|
352
|
+
def specificity
|
353
|
+
SPECIFICITY_BASE
|
354
|
+
end
|
278
355
|
end
|
279
356
|
|
280
357
|
# A pseudoclass (e.g. `:visited`) or pseudoelement (e.g. `::first-line`) selector.
|
281
358
|
# It can have arguments (e.g. `:nth-child(2n+1)`).
|
282
359
|
class Pseudo < Simple
|
283
|
-
#
|
284
|
-
#
|
285
|
-
#
|
360
|
+
# Some psuedo-class-syntax selectors are actually considered
|
361
|
+
# pseudo-elements and must be treated differently. This is a list of such
|
362
|
+
# selectors
|
363
|
+
#
|
364
|
+
# @return [Array<String>]
|
365
|
+
ACTUALLY_ELEMENTS = %w[after before first-line first-letter]
|
366
|
+
|
367
|
+
# Like \{#type}, but returns the type of selector this looks like, rather
|
368
|
+
# than the type it is semantically. This only differs from type for
|
369
|
+
# selectors in \{ACTUALLY\_ELEMENTS}.
|
286
370
|
#
|
287
371
|
# @return [Symbol]
|
288
|
-
attr_reader :
|
372
|
+
attr_reader :syntactic_type
|
289
373
|
|
290
374
|
# The name of the selector.
|
291
375
|
#
|
292
|
-
# @return [Array<String, Sass::Script::Node>]
|
376
|
+
# @return [Array<String, Sass::Script::Tree::Node>]
|
293
377
|
attr_reader :name
|
294
378
|
|
295
379
|
# The argument to the selector,
|
@@ -299,37 +383,50 @@ module Sass
|
|
299
383
|
# Note that this should not include SassScript nodes
|
300
384
|
# after resolution has taken place.
|
301
385
|
#
|
302
|
-
# @return [Array<String, Sass::Script::Node>, nil]
|
386
|
+
# @return [Array<String, Sass::Script::Tree::Node>, nil]
|
303
387
|
attr_reader :arg
|
304
388
|
|
305
389
|
# @param type [Symbol] See \{#type}
|
306
|
-
# @param name [Array<String, Sass::Script::Node>] The name of the selector
|
307
|
-
# @param arg [nil, Array<String, Sass::Script::Node>] The argument to the selector,
|
390
|
+
# @param name [Array<String, Sass::Script::Tree::Node>] The name of the selector
|
391
|
+
# @param arg [nil, Array<String, Sass::Script::Tree::Node>] The argument to the selector,
|
308
392
|
# or nil if no argument was given
|
309
393
|
def initialize(type, name, arg)
|
310
|
-
@
|
394
|
+
@syntactic_type = type
|
311
395
|
@name = name
|
312
396
|
@arg = arg
|
313
397
|
end
|
314
398
|
|
399
|
+
# The type of the selector. `:class` if this is a pseudoclass selector,
|
400
|
+
# `:element` if it's a pseudoelement.
|
401
|
+
#
|
402
|
+
# @return [Symbol]
|
403
|
+
def type
|
404
|
+
ACTUALLY_ELEMENTS.include?(name.first) ? :element : syntactic_type
|
405
|
+
end
|
406
|
+
|
315
407
|
# @see Selector#to_a
|
316
408
|
def to_a
|
317
|
-
res = [
|
409
|
+
res = [syntactic_type == :class ? ":" : "::"] + @name
|
318
410
|
(res << "(").concat(Sass::Util.strip_string_array(@arg)) << ")" if @arg
|
319
411
|
res
|
320
412
|
end
|
321
413
|
|
322
|
-
# Returns `nil` if this is a
|
323
|
-
# and `sels` contains a
|
414
|
+
# Returns `nil` if this is a pseudoelement selector
|
415
|
+
# and `sels` contains a pseudoelement selector different than this one.
|
324
416
|
#
|
325
417
|
# @see Selector#unify
|
326
418
|
def unify(sels)
|
327
419
|
return if type == :element && sels.any? do |sel|
|
328
420
|
sel.is_a?(Pseudo) && sel.type == :element &&
|
329
|
-
(sel.name !=
|
421
|
+
(sel.name != name || sel.arg != arg)
|
330
422
|
end
|
331
423
|
super
|
332
424
|
end
|
425
|
+
|
426
|
+
# @see AbstractSequence#specificity
|
427
|
+
def specificity
|
428
|
+
type == :class ? SPECIFICITY_BASE : 1
|
429
|
+
end
|
333
430
|
end
|
334
431
|
|
335
432
|
# A pseudoclass selector whose argument is itself a selector
|
@@ -345,8 +442,8 @@ module Sass
|
|
345
442
|
# @return [Selector::Sequence]
|
346
443
|
attr_reader :selector
|
347
444
|
|
348
|
-
# @param [String] The name of the pseudoclass
|
349
|
-
# @param [Selector::
|
445
|
+
# @param name [String] The name of the pseudoclass
|
446
|
+
# @param selector [Selector::CommaSequence] The selector argument
|
350
447
|
def initialize(name, selector)
|
351
448
|
@name = name
|
352
449
|
@selector = selector
|
@@ -356,6 +453,11 @@ module Sass
|
|
356
453
|
def to_a
|
357
454
|
[":", @name, "("] + @selector.to_a + [")"]
|
358
455
|
end
|
456
|
+
|
457
|
+
# @see AbstractSequence#specificity
|
458
|
+
def specificity
|
459
|
+
SPECIFICITY_BASE
|
460
|
+
end
|
359
461
|
end
|
360
462
|
end
|
361
463
|
end
|
data/lib/sass/shared.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'strscan'
|
2
|
-
|
3
1
|
module Sass
|
4
2
|
# This module contains functionality that's shared between Haml and Sass.
|
5
3
|
module Shared
|
@@ -16,8 +14,8 @@ module Sass
|
|
16
14
|
# @yieldparam scan [StringScanner] The scanner scanning through the string
|
17
15
|
# @return [String] The text remaining in the scanner after all `#{`s have been processed
|
18
16
|
def handle_interpolation(str)
|
19
|
-
scan =
|
20
|
-
yield scan while scan.scan(/(.*?)(\\*)\#\{/)
|
17
|
+
scan = Sass::Util::MultibyteStringScanner.new(str)
|
18
|
+
yield scan while scan.scan(/(.*?)(\\*)\#\{/m)
|
21
19
|
scan.rest
|
22
20
|
end
|
23
21
|
|
@@ -40,7 +38,7 @@ module Sass
|
|
40
38
|
# `["Foo (Bar (Baz bang) bop)", " (Bang (bop bip))"]` in the example above.
|
41
39
|
def balance(scanner, start, finish, count = 0)
|
42
40
|
str = ''
|
43
|
-
scanner =
|
41
|
+
scanner = Sass::Util::MultibyteStringScanner.new(scanner) unless scanner.is_a? StringScanner
|
44
42
|
regexp = Regexp.new("(.*?)[\\#{start.chr}\\#{finish.chr}]", Regexp::MULTILINE)
|
45
43
|
while scanner.scan(regexp)
|
46
44
|
str << scanner.matched
|