xass 0.1.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/.yardopts +11 -0
- data/CONTRIBUTING +3 -0
- data/MIT-LICENSE +20 -0
- data/README.md +201 -0
- data/Rakefile +349 -0
- data/VERSION +1 -0
- data/VERSION_NAME +1 -0
- data/bin/push +13 -0
- data/bin/sass +13 -0
- data/bin/sass-convert +12 -0
- data/bin/scss +13 -0
- data/extra/update_watch.rb +13 -0
- data/init.rb +18 -0
- data/lib/sass/cache_stores/base.rb +88 -0
- data/lib/sass/cache_stores/chain.rb +33 -0
- data/lib/sass/cache_stores/filesystem.rb +64 -0
- data/lib/sass/cache_stores/memory.rb +47 -0
- data/lib/sass/cache_stores/null.rb +25 -0
- data/lib/sass/cache_stores.rb +15 -0
- data/lib/sass/callbacks.rb +66 -0
- data/lib/sass/css.rb +409 -0
- data/lib/sass/engine.rb +930 -0
- data/lib/sass/environment.rb +101 -0
- data/lib/sass/error.rb +201 -0
- data/lib/sass/exec.rb +707 -0
- data/lib/sass/importers/base.rb +139 -0
- data/lib/sass/importers/filesystem.rb +186 -0
- data/lib/sass/importers.rb +22 -0
- data/lib/sass/logger/base.rb +32 -0
- data/lib/sass/logger/log_level.rb +49 -0
- data/lib/sass/logger.rb +15 -0
- data/lib/sass/media.rb +213 -0
- data/lib/sass/plugin/compiler.rb +406 -0
- data/lib/sass/plugin/configuration.rb +123 -0
- data/lib/sass/plugin/generic.rb +15 -0
- data/lib/sass/plugin/merb.rb +48 -0
- data/lib/sass/plugin/rack.rb +60 -0
- data/lib/sass/plugin/rails.rb +47 -0
- data/lib/sass/plugin/staleness_checker.rb +199 -0
- data/lib/sass/plugin.rb +133 -0
- data/lib/sass/railtie.rb +10 -0
- data/lib/sass/repl.rb +57 -0
- data/lib/sass/root.rb +7 -0
- data/lib/sass/script/arg_list.rb +52 -0
- data/lib/sass/script/bool.rb +18 -0
- data/lib/sass/script/color.rb +606 -0
- data/lib/sass/script/css_lexer.rb +29 -0
- data/lib/sass/script/css_parser.rb +31 -0
- data/lib/sass/script/funcall.rb +245 -0
- data/lib/sass/script/functions.rb +1543 -0
- data/lib/sass/script/interpolation.rb +79 -0
- data/lib/sass/script/lexer.rb +345 -0
- data/lib/sass/script/list.rb +85 -0
- data/lib/sass/script/literal.rb +221 -0
- data/lib/sass/script/node.rb +99 -0
- data/lib/sass/script/null.rb +37 -0
- data/lib/sass/script/number.rb +453 -0
- data/lib/sass/script/operation.rb +110 -0
- data/lib/sass/script/parser.rb +502 -0
- data/lib/sass/script/string.rb +51 -0
- data/lib/sass/script/string_interpolation.rb +103 -0
- data/lib/sass/script/unary_operation.rb +69 -0
- data/lib/sass/script/variable.rb +58 -0
- data/lib/sass/script.rb +39 -0
- data/lib/sass/scss/css_parser.rb +36 -0
- data/lib/sass/scss/parser.rb +1180 -0
- data/lib/sass/scss/rx.rb +133 -0
- data/lib/sass/scss/script_lexer.rb +15 -0
- data/lib/sass/scss/script_parser.rb +25 -0
- data/lib/sass/scss/static_parser.rb +54 -0
- data/lib/sass/scss.rb +16 -0
- data/lib/sass/selector/abstract_sequence.rb +94 -0
- data/lib/sass/selector/comma_sequence.rb +92 -0
- data/lib/sass/selector/sequence.rb +507 -0
- data/lib/sass/selector/simple.rb +119 -0
- data/lib/sass/selector/simple_sequence.rb +215 -0
- data/lib/sass/selector.rb +452 -0
- data/lib/sass/shared.rb +76 -0
- data/lib/sass/supports.rb +229 -0
- data/lib/sass/tree/charset_node.rb +22 -0
- data/lib/sass/tree/comment_node.rb +82 -0
- 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 +18 -0
- data/lib/sass/tree/directive_node.rb +42 -0
- data/lib/sass/tree/each_node.rb +24 -0
- data/lib/sass/tree/extend_node.rb +36 -0
- data/lib/sass/tree/for_node.rb +36 -0
- data/lib/sass/tree/function_node.rb +34 -0
- data/lib/sass/tree/if_node.rb +52 -0
- data/lib/sass/tree/import_node.rb +75 -0
- data/lib/sass/tree/media_node.rb +58 -0
- data/lib/sass/tree/mixin_def_node.rb +38 -0
- data/lib/sass/tree/mixin_node.rb +39 -0
- data/lib/sass/tree/node.rb +196 -0
- data/lib/sass/tree/prop_node.rb +152 -0
- data/lib/sass/tree/return_node.rb +18 -0
- data/lib/sass/tree/root_node.rb +78 -0
- data/lib/sass/tree/rule_node.rb +132 -0
- data/lib/sass/tree/supports_node.rb +51 -0
- data/lib/sass/tree/trace_node.rb +32 -0
- data/lib/sass/tree/variable_node.rb +30 -0
- data/lib/sass/tree/visitors/base.rb +75 -0
- data/lib/sass/tree/visitors/check_nesting.rb +147 -0
- data/lib/sass/tree/visitors/convert.rb +316 -0
- data/lib/sass/tree/visitors/cssize.rb +241 -0
- 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 +446 -0
- data/lib/sass/tree/visitors/set_options.rb +125 -0
- data/lib/sass/tree/visitors/to_css.rb +228 -0
- data/lib/sass/tree/warn_node.rb +18 -0
- data/lib/sass/tree/while_node.rb +18 -0
- data/lib/sass/util/multibyte_string_scanner.rb +155 -0
- data/lib/sass/util/subset_map.rb +109 -0
- data/lib/sass/util/test.rb +10 -0
- data/lib/sass/util.rb +948 -0
- data/lib/sass/version.rb +126 -0
- data/lib/sass.rb +95 -0
- data/rails/init.rb +1 -0
- data/test/Gemfile +3 -0
- data/test/Gemfile.lock +10 -0
- data/test/sass/cache_test.rb +89 -0
- data/test/sass/callbacks_test.rb +61 -0
- data/test/sass/conversion_test.rb +1760 -0
- data/test/sass/css2sass_test.rb +458 -0
- data/test/sass/data/hsl-rgb.txt +319 -0
- data/test/sass/engine_test.rb +3244 -0
- data/test/sass/exec_test.rb +86 -0
- data/test/sass/extend_test.rb +1482 -0
- 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 +1139 -0
- data/test/sass/importer_test.rb +192 -0
- data/test/sass/logger_test.rb +58 -0
- data/test/sass/mock_importer.rb +49 -0
- data/test/sass/more_results/more1.css +9 -0
- data/test/sass/more_results/more1_with_line_comments.css +26 -0
- data/test/sass/more_results/more_import.css +29 -0
- data/test/sass/more_templates/_more_partial.sass +2 -0
- data/test/sass/more_templates/more1.sass +23 -0
- data/test/sass/more_templates/more_import.sass +11 -0
- data/test/sass/plugin_test.rb +564 -0
- data/test/sass/results/alt.css +4 -0
- data/test/sass/results/basic.css +9 -0
- data/test/sass/results/cached_import_option.css +3 -0
- data/test/sass/results/compact.css +5 -0
- data/test/sass/results/complex.css +86 -0
- data/test/sass/results/compressed.css +1 -0
- data/test/sass/results/expanded.css +19 -0
- data/test/sass/results/filename_fn.css +3 -0
- data/test/sass/results/if.css +3 -0
- data/test/sass/results/import.css +31 -0
- data/test/sass/results/import_charset.css +5 -0
- data/test/sass/results/import_charset_1_8.css +5 -0
- data/test/sass/results/import_charset_ibm866.css +5 -0
- data/test/sass/results/import_content.css +1 -0
- data/test/sass/results/line_numbers.css +49 -0
- data/test/sass/results/mixins.css +95 -0
- data/test/sass/results/multiline.css +24 -0
- data/test/sass/results/nested.css +22 -0
- data/test/sass/results/options.css +1 -0
- data/test/sass/results/parent_ref.css +13 -0
- data/test/sass/results/script.css +16 -0
- data/test/sass/results/scss_import.css +31 -0
- data/test/sass/results/scss_importee.css +2 -0
- data/test/sass/results/subdir/nested_subdir/nested_subdir.css +1 -0
- data/test/sass/results/subdir/subdir.css +3 -0
- data/test/sass/results/units.css +11 -0
- data/test/sass/results/warn.css +0 -0
- data/test/sass/results/warn_imported.css +0 -0
- data/test/sass/script_conversion_test.rb +299 -0
- data/test/sass/script_test.rb +622 -0
- data/test/sass/scss/css_test.rb +1100 -0
- data/test/sass/scss/rx_test.rb +156 -0
- data/test/sass/scss/scss_test.rb +2106 -0
- data/test/sass/scss/test_helper.rb +37 -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_charset_ibm866.sass +4 -0
- data/test/sass/templates/_imported_charset_utf8.sass +4 -0
- data/test/sass/templates/_imported_content.sass +3 -0
- data/test/sass/templates/_partial.sass +2 -0
- data/test/sass/templates/_same_name_different_partiality.scss +1 -0
- data/test/sass/templates/alt.sass +16 -0
- data/test/sass/templates/basic.sass +23 -0
- data/test/sass/templates/bork1.sass +2 -0
- data/test/sass/templates/bork2.sass +2 -0
- data/test/sass/templates/bork3.sass +2 -0
- data/test/sass/templates/bork4.sass +2 -0
- data/test/sass/templates/bork5.sass +3 -0
- data/test/sass/templates/cached_import_option.scss +3 -0
- data/test/sass/templates/compact.sass +17 -0
- data/test/sass/templates/complex.sass +305 -0
- data/test/sass/templates/compressed.sass +15 -0
- data/test/sass/templates/double_import_loop1.sass +1 -0
- data/test/sass/templates/expanded.sass +17 -0
- data/test/sass/templates/filename_fn.scss +18 -0
- data/test/sass/templates/if.sass +11 -0
- data/test/sass/templates/import.sass +12 -0
- data/test/sass/templates/import_charset.sass +9 -0
- data/test/sass/templates/import_charset_1_8.sass +6 -0
- data/test/sass/templates/import_charset_ibm866.sass +11 -0
- data/test/sass/templates/import_content.sass +4 -0
- data/test/sass/templates/importee.less +2 -0
- data/test/sass/templates/importee.sass +19 -0
- data/test/sass/templates/line_numbers.sass +13 -0
- data/test/sass/templates/mixin_bork.sass +5 -0
- data/test/sass/templates/mixins.sass +76 -0
- data/test/sass/templates/multiline.sass +20 -0
- data/test/sass/templates/nested.sass +25 -0
- data/test/sass/templates/nested_bork1.sass +2 -0
- data/test/sass/templates/nested_bork2.sass +2 -0
- data/test/sass/templates/nested_bork3.sass +2 -0
- data/test/sass/templates/nested_bork4.sass +2 -0
- data/test/sass/templates/nested_import.sass +2 -0
- data/test/sass/templates/nested_mixin_bork.sass +6 -0
- data/test/sass/templates/options.sass +2 -0
- data/test/sass/templates/parent_ref.sass +25 -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/script.sass +101 -0
- data/test/sass/templates/scss_import.scss +11 -0
- data/test/sass/templates/scss_importee.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/templates/subdir/nested_subdir/_nested_partial.sass +2 -0
- data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +3 -0
- data/test/sass/templates/subdir/subdir.sass +6 -0
- data/test/sass/templates/units.sass +11 -0
- data/test/sass/templates/warn.sass +3 -0
- data/test/sass/templates/warn_imported.sass +4 -0
- data/test/sass/test_helper.rb +8 -0
- data/test/sass/util/multibyte_string_scanner_test.rb +147 -0
- data/test/sass/util/subset_map_test.rb +91 -0
- data/test/sass/util_test.rb +382 -0
- data/test/test_helper.rb +80 -0
- metadata +354 -0
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
module Sass
|
|
2
|
+
module Selector
|
|
3
|
+
# A unseparated sequence of selectors
|
|
4
|
+
# that all apply to a single element.
|
|
5
|
+
# For example, `.foo#bar[attr=baz]` is a simple sequence
|
|
6
|
+
# of the selectors `.foo`, `#bar`, and `[attr=baz]`.
|
|
7
|
+
class SimpleSequence < AbstractSequence
|
|
8
|
+
# The array of individual selectors.
|
|
9
|
+
#
|
|
10
|
+
# @return [Array<Simple>]
|
|
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 {#do_extend} process.
|
|
25
|
+
#
|
|
26
|
+
# @return {Set<Sequence>}
|
|
27
|
+
attr_accessor :sources
|
|
28
|
+
|
|
29
|
+
# @see \{#subject?}
|
|
30
|
+
attr_writer :subject
|
|
31
|
+
|
|
32
|
+
# Returns the element or universal selector in this sequence,
|
|
33
|
+
# if it exists.
|
|
34
|
+
#
|
|
35
|
+
# @return [Element, Universal, nil]
|
|
36
|
+
def base
|
|
37
|
+
@base ||= (members.first if members.first.is_a?(Element) || members.first.is_a?(Universal))
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def pseudo_elements
|
|
41
|
+
@pseudo_elements ||= (members - [base]).
|
|
42
|
+
select {|sel| sel.is_a?(Pseudo) && sel.type == :element}
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Returns the non-base, non-pseudo-class selectors in this sequence.
|
|
46
|
+
#
|
|
47
|
+
# @return [Set<Simple>]
|
|
48
|
+
def rest
|
|
49
|
+
@rest ||= Set.new(members - [base] - pseudo_elements)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Whether or not this compound selector is the subject of the parent
|
|
53
|
+
# selector; that is, whether it is prepended with `$` and represents the
|
|
54
|
+
# actual element that will be selected.
|
|
55
|
+
#
|
|
56
|
+
# @return [Boolean]
|
|
57
|
+
def subject?
|
|
58
|
+
@subject
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# @param selectors [Array<Simple>] See \{#members}
|
|
62
|
+
# @param subject [Boolean] See \{#subject?}
|
|
63
|
+
# @param sources [Set<Sequence>]
|
|
64
|
+
def initialize(selectors, subject, sources = Set.new)
|
|
65
|
+
@members = selectors
|
|
66
|
+
@subject = subject
|
|
67
|
+
@sources = sources
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Resolves the {Parent} selectors within this selector
|
|
71
|
+
# by replacing them with the given parent selector,
|
|
72
|
+
# handling commas appropriately.
|
|
73
|
+
#
|
|
74
|
+
# @param super_seq [Sequence] The parent selector sequence
|
|
75
|
+
# @return [Array<SimpleSequence>] This selector, with parent references resolved.
|
|
76
|
+
# This is an array because the parent selector is itself a {Sequence}
|
|
77
|
+
# @raise [Sass::SyntaxError] If a parent selector is invalid
|
|
78
|
+
def resolve_parent_refs(super_seq)
|
|
79
|
+
# Parent selector only appears as the first selector in the sequence
|
|
80
|
+
return [self] unless @members.first.is_a?(Parent)
|
|
81
|
+
|
|
82
|
+
members = super_seq.members.dup
|
|
83
|
+
newline = members.pop if members.last == "\n"
|
|
84
|
+
return members if @members.size == 1
|
|
85
|
+
unless members.last.is_a?(SimpleSequence)
|
|
86
|
+
raise Sass::SyntaxError.new("Invalid parent selector: " + super_seq.to_a.join)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
members[0...-1] +
|
|
90
|
+
[SimpleSequence.new(members.last.members + @members[1..-1], subject?)] +
|
|
91
|
+
[newline].compact
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Non-destrucively extends this selector with the extensions specified in a hash
|
|
95
|
+
# (which should come from {Sass::Tree::Visitors::Cssize}).
|
|
96
|
+
#
|
|
97
|
+
# @overload def do_extend(extends, parent_directives)
|
|
98
|
+
# @param extends [{Selector::Simple =>
|
|
99
|
+
# Sass::Tree::Visitors::Cssize::Extend}]
|
|
100
|
+
# The extensions to perform on this selector
|
|
101
|
+
# @param parent_directives [Array<Sass::Tree::DirectiveNode>]
|
|
102
|
+
# The directives containing this selector.
|
|
103
|
+
# @return [Array<Sequence>] A list of selectors generated
|
|
104
|
+
# by extending this selector with `extends`.
|
|
105
|
+
# @see CommaSequence#do_extend
|
|
106
|
+
def do_extend(extends, parent_directives, seen = Set.new)
|
|
107
|
+
Sass::Util.group_by_to_a(extends.get(members.to_set)) {|ex, _| ex.extender}.map do |seq, group|
|
|
108
|
+
sels = group.map {|_, s| s}.flatten
|
|
109
|
+
# If A {@extend B} and C {...},
|
|
110
|
+
# seq is A, sels is B, and self is C
|
|
111
|
+
|
|
112
|
+
self_without_sel = Sass::Util.array_minus(self.members, sels)
|
|
113
|
+
group.each {|e, _| e.result = :failed_to_unify unless e.result == :succeeded}
|
|
114
|
+
next unless unified = seq.members.last.unify(self_without_sel, subject?)
|
|
115
|
+
group.each {|e, _| e.result = :succeeded}
|
|
116
|
+
next if group.map {|e, _| check_directives_match!(e, parent_directives)}.none?
|
|
117
|
+
new_seq = Sequence.new(seq.members[0...-1] + [unified])
|
|
118
|
+
new_seq.add_sources!(sources + [seq])
|
|
119
|
+
[sels, new_seq]
|
|
120
|
+
end.compact.map do |sels, seq|
|
|
121
|
+
seen.include?(sels) ? [] : seq.do_extend(extends, parent_directives, seen + [sels])
|
|
122
|
+
end.flatten.uniq
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Unifies this selector with another {SimpleSequence}'s {SimpleSequence#members members array},
|
|
126
|
+
# returning another `SimpleSequence`
|
|
127
|
+
# that matches both this selector and the input selector.
|
|
128
|
+
#
|
|
129
|
+
# @param sels [Array<Simple>] A {SimpleSequence}'s {SimpleSequence#members members array}
|
|
130
|
+
# @param subject [Boolean] Whether the {SimpleSequence} being merged is a subject.
|
|
131
|
+
# @return [SimpleSequence, nil] A {SimpleSequence} matching both `sels` and this selector,
|
|
132
|
+
# or `nil` if this is impossible (e.g. unifying `#foo` and `#bar`)
|
|
133
|
+
# @raise [Sass::SyntaxError] If this selector cannot be unified.
|
|
134
|
+
# This will only ever occur when a dynamic selector,
|
|
135
|
+
# such as {Parent} or {Interpolation}, is used in unification.
|
|
136
|
+
# Since these selectors should be resolved
|
|
137
|
+
# by the time extension and unification happen,
|
|
138
|
+
# this exception will only ever be raised as a result of programmer error
|
|
139
|
+
def unify(sels, other_subject)
|
|
140
|
+
return unless sseq = members.inject(sels) do |member, sel|
|
|
141
|
+
return unless member
|
|
142
|
+
sel.unify(member)
|
|
143
|
+
end
|
|
144
|
+
SimpleSequence.new(sseq, other_subject || subject?)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Returns whether or not this selector matches all elements
|
|
148
|
+
# that the given selector matches (as well as possibly more).
|
|
149
|
+
#
|
|
150
|
+
# @example
|
|
151
|
+
# (.foo).superselector?(.foo.bar) #=> true
|
|
152
|
+
# (.foo).superselector?(.bar) #=> false
|
|
153
|
+
# @param sseq [SimpleSequence]
|
|
154
|
+
# @return [Boolean]
|
|
155
|
+
def superselector?(sseq)
|
|
156
|
+
(base.nil? || base.eql?(sseq.base)) &&
|
|
157
|
+
pseudo_elements.eql?(sseq.pseudo_elements) &&
|
|
158
|
+
rest.subset?(sseq.rest)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# @see Simple#to_a
|
|
162
|
+
def to_a
|
|
163
|
+
res = @members.map {|sel| sel.to_a}.flatten
|
|
164
|
+
res << '!' if subject?
|
|
165
|
+
res
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# Returns a string representation of the sequence.
|
|
169
|
+
# This is basically the selector string.
|
|
170
|
+
#
|
|
171
|
+
# @return [String]
|
|
172
|
+
def inspect
|
|
173
|
+
members.map {|m| m.inspect}.join
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# Return a copy of this simple sequence with `sources` merged into the
|
|
177
|
+
# {#sources} set.
|
|
178
|
+
#
|
|
179
|
+
# @param sources [Set<Sequence>]
|
|
180
|
+
# @return [SimpleSequence]
|
|
181
|
+
def with_more_sources(sources)
|
|
182
|
+
sseq = dup
|
|
183
|
+
sseq.members = members.dup
|
|
184
|
+
sseq.sources = self.sources | sources
|
|
185
|
+
sseq
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
private
|
|
189
|
+
|
|
190
|
+
def check_directives_match!(extend, parent_directives)
|
|
191
|
+
dirs1 = extend.directives.map {|d| d.resolved_value}
|
|
192
|
+
dirs2 = parent_directives.map {|d| d.resolved_value}
|
|
193
|
+
return true if Sass::Util.subsequence?(dirs1, dirs2)
|
|
194
|
+
|
|
195
|
+
Sass::Util.sass_warn <<WARNING
|
|
196
|
+
DEPRECATION WARNING on line #{extend.node.line}#{" of #{extend.node.filename}" if extend.node.filename}:
|
|
197
|
+
@extending an outer selector from within #{extend.directives.last.name} is deprecated.
|
|
198
|
+
You may only @extend selectors within the same directive.
|
|
199
|
+
This will be an error in Sass 3.3.
|
|
200
|
+
It can only work once @extend is supported natively in the browser.
|
|
201
|
+
WARNING
|
|
202
|
+
return false
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def _hash
|
|
206
|
+
[base, Sass::Util.set_hash(rest)].hash
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def _eql?(other)
|
|
210
|
+
other.base.eql?(self.base) && other.pseudo_elements == pseudo_elements &&
|
|
211
|
+
Sass::Util.set_eql?(other.rest, self.rest) && other.subject? == self.subject?
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
end
|
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
require 'sass/selector/simple'
|
|
2
|
+
require 'sass/selector/abstract_sequence'
|
|
3
|
+
require 'sass/selector/comma_sequence'
|
|
4
|
+
require 'sass/selector/sequence'
|
|
5
|
+
require 'sass/selector/simple_sequence'
|
|
6
|
+
|
|
7
|
+
module Sass
|
|
8
|
+
# A namespace for nodes in the parse tree for selectors.
|
|
9
|
+
#
|
|
10
|
+
# {CommaSequence} is the toplevel seelctor,
|
|
11
|
+
# representing a comma-separated sequence of {Sequence}s,
|
|
12
|
+
# such as `foo bar, baz bang`.
|
|
13
|
+
# {Sequence} is the next level,
|
|
14
|
+
# representing {SimpleSequence}s separated by combinators (e.g. descendant or child),
|
|
15
|
+
# such as `foo bar` or `foo > bar baz`.
|
|
16
|
+
# {SimpleSequence} is a sequence of selectors that all apply to a single element,
|
|
17
|
+
# such as `foo.bar[attr=val]`.
|
|
18
|
+
# Finally, {Simple} is the superclass of the simplest selectors,
|
|
19
|
+
# such as `.foo` or `#bar`.
|
|
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
|
+
#
|
|
25
|
+
# @type [Fixnum]
|
|
26
|
+
SPECIFICITY_BASE = 1_000
|
|
27
|
+
|
|
28
|
+
# A parent-referencing selector (`&` in Sass).
|
|
29
|
+
# The function of this is to be replaced by the parent selector
|
|
30
|
+
# in the nested hierarchy.
|
|
31
|
+
class Parent < Simple
|
|
32
|
+
# @see Selector#to_a
|
|
33
|
+
def to_a
|
|
34
|
+
["&"]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Always raises an exception.
|
|
38
|
+
#
|
|
39
|
+
# @raise [Sass::SyntaxError] Parent selectors should be resolved before unification
|
|
40
|
+
# @see Selector#unify
|
|
41
|
+
def unify(sels)
|
|
42
|
+
raise Sass::SyntaxError.new("[BUG] Cannot unify parent selectors.")
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# A class selector (e.g. `.foo`).
|
|
47
|
+
class Class < Simple
|
|
48
|
+
# The class name.
|
|
49
|
+
#
|
|
50
|
+
# @return [Array<String, Sass::Script::Node>]
|
|
51
|
+
attr_reader :name
|
|
52
|
+
|
|
53
|
+
# @param name [Array<String, Sass::Script::Node>] The class name
|
|
54
|
+
def initialize(name)
|
|
55
|
+
@name = name
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# @see Selector#to_a
|
|
59
|
+
def to_a
|
|
60
|
+
[".", *@name]
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# @see AbstractSequence#specificity
|
|
64
|
+
def specificity
|
|
65
|
+
SPECIFICITY_BASE
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# An id selector (e.g. `#foo`).
|
|
70
|
+
class Id < Simple
|
|
71
|
+
# The id name.
|
|
72
|
+
#
|
|
73
|
+
# @return [Array<String, Sass::Script::Node>]
|
|
74
|
+
attr_reader :name
|
|
75
|
+
|
|
76
|
+
# @param name [Array<String, Sass::Script::Node>] The id name
|
|
77
|
+
def initialize(name)
|
|
78
|
+
@name = name
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# @see Selector#to_a
|
|
82
|
+
def to_a
|
|
83
|
+
["#", *@name]
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Returns `nil` if `sels` contains an {Id} selector
|
|
87
|
+
# with a different name than this one.
|
|
88
|
+
#
|
|
89
|
+
# @see Selector#unify
|
|
90
|
+
def unify(sels)
|
|
91
|
+
return if sels.any? {|sel2| sel2.is_a?(Id) && self.name != sel2.name}
|
|
92
|
+
super
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# @see AbstractSequence#specificity
|
|
96
|
+
def specificity
|
|
97
|
+
SPECIFICITY_BASE**2
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# A placeholder selector (e.g. `%foo`).
|
|
102
|
+
# This exists to be replaced via `@extend`.
|
|
103
|
+
# Rulesets using this selector will not be printed, but can be extended.
|
|
104
|
+
# Otherwise, this acts just like a class selector.
|
|
105
|
+
class Placeholder < Simple
|
|
106
|
+
# The placeholder name.
|
|
107
|
+
#
|
|
108
|
+
# @return [Array<String, Sass::Script::Node>]
|
|
109
|
+
attr_reader :name
|
|
110
|
+
|
|
111
|
+
# @param name [Array<String, Sass::Script::Node>] The placeholder name
|
|
112
|
+
def initialize(name)
|
|
113
|
+
@name = name
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# @see Selector#to_a
|
|
117
|
+
def to_a
|
|
118
|
+
["%", *@name]
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# @see AbstractSequence#specificity
|
|
122
|
+
def specificity
|
|
123
|
+
SPECIFICITY_BASE
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# A universal selector (`*` in CSS).
|
|
128
|
+
class Universal < Simple
|
|
129
|
+
# The selector namespace.
|
|
130
|
+
# `nil` means the default namespace,
|
|
131
|
+
# `[""]` means no namespace,
|
|
132
|
+
# `["*"]` means any namespace.
|
|
133
|
+
#
|
|
134
|
+
# @return [Array<String, Sass::Script::Node>, nil]
|
|
135
|
+
attr_reader :namespace
|
|
136
|
+
|
|
137
|
+
# @param namespace [Array<String, Sass::Script::Node>, nil] See \{#namespace}
|
|
138
|
+
def initialize(namespace)
|
|
139
|
+
@namespace = namespace
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# @see Selector#to_a
|
|
143
|
+
def to_a
|
|
144
|
+
@namespace ? @namespace + ["|*"] : ["*"]
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Unification of a universal selector is somewhat complicated,
|
|
148
|
+
# especially when a namespace is specified.
|
|
149
|
+
# If there is no namespace specified
|
|
150
|
+
# or any namespace is specified (namespace `"*"`),
|
|
151
|
+
# then `sel` is returned without change
|
|
152
|
+
# (unless it's empty, in which case `"*"` is required).
|
|
153
|
+
#
|
|
154
|
+
# If a namespace is specified
|
|
155
|
+
# but `sel` does not specify a namespace,
|
|
156
|
+
# then the given namespace is applied to `sel`,
|
|
157
|
+
# either by adding this {Universal} selector
|
|
158
|
+
# or applying this namespace to an existing {Element} selector.
|
|
159
|
+
#
|
|
160
|
+
# If both this selector *and* `sel` specify namespaces,
|
|
161
|
+
# those namespaces are unified via {Simple#unify_namespaces}
|
|
162
|
+
# and the unified namespace is used, if possible.
|
|
163
|
+
#
|
|
164
|
+
# @todo There are lots of cases that this documentation specifies;
|
|
165
|
+
# make sure we thoroughly test **all of them**.
|
|
166
|
+
# @todo Keep track of whether a default namespace has been declared
|
|
167
|
+
# and handle namespace-unspecified selectors accordingly.
|
|
168
|
+
# @todo If any branch of a CommaSequence ends up being just `"*"`,
|
|
169
|
+
# then all other branches should be eliminated
|
|
170
|
+
#
|
|
171
|
+
# @see Selector#unify
|
|
172
|
+
def unify(sels)
|
|
173
|
+
name =
|
|
174
|
+
case sels.first
|
|
175
|
+
when Universal; :universal
|
|
176
|
+
when Element; sels.first.name
|
|
177
|
+
else
|
|
178
|
+
return [self] + sels unless namespace.nil? || namespace == ['*']
|
|
179
|
+
return sels unless sels.empty?
|
|
180
|
+
return [self]
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
ns, accept = unify_namespaces(namespace, sels.first.namespace)
|
|
184
|
+
return unless accept
|
|
185
|
+
[name == :universal ? Universal.new(ns) : Element.new(name, ns)] + sels[1..-1]
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# @see AbstractSequence#specificity
|
|
189
|
+
def specificity
|
|
190
|
+
0
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# An element selector (e.g. `h1`).
|
|
195
|
+
class Element < Simple
|
|
196
|
+
# The element name.
|
|
197
|
+
#
|
|
198
|
+
# @return [Array<String, Sass::Script::Node>]
|
|
199
|
+
attr_reader :name
|
|
200
|
+
|
|
201
|
+
# The selector namespace.
|
|
202
|
+
# `nil` means the default namespace,
|
|
203
|
+
# `[""]` means no namespace,
|
|
204
|
+
# `["*"]` means any namespace.
|
|
205
|
+
#
|
|
206
|
+
# @return [Array<String, Sass::Script::Node>, nil]
|
|
207
|
+
attr_reader :namespace
|
|
208
|
+
|
|
209
|
+
# @param name [Array<String, Sass::Script::Node>] The element name
|
|
210
|
+
# @param namespace [Array<String, Sass::Script::Node>, nil] See \{#namespace}
|
|
211
|
+
def initialize(name, namespace)
|
|
212
|
+
@name = name
|
|
213
|
+
@namespace = namespace
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
# @see Selector#to_a
|
|
217
|
+
def to_a
|
|
218
|
+
@namespace ? @namespace + ["|"] + @name : @name
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
# Unification of an element selector is somewhat complicated,
|
|
222
|
+
# especially when a namespace is specified.
|
|
223
|
+
# First, if `sel` contains another {Element} with a different \{#name},
|
|
224
|
+
# then the selectors can't be unified and `nil` is returned.
|
|
225
|
+
#
|
|
226
|
+
# Otherwise, if `sel` doesn't specify a namespace,
|
|
227
|
+
# or it specifies any namespace (via `"*"`),
|
|
228
|
+
# then it's returned with this element selector
|
|
229
|
+
# (e.g. `.foo` becomes `a.foo` or `svg|a.foo`).
|
|
230
|
+
# Similarly, if this selector doesn't specify a namespace,
|
|
231
|
+
# the namespace from `sel` is used.
|
|
232
|
+
#
|
|
233
|
+
# If both this selector *and* `sel` specify namespaces,
|
|
234
|
+
# those namespaces are unified via {Simple#unify_namespaces}
|
|
235
|
+
# and the unified namespace is used, if possible.
|
|
236
|
+
#
|
|
237
|
+
# @todo There are lots of cases that this documentation specifies;
|
|
238
|
+
# make sure we thoroughly test **all of them**.
|
|
239
|
+
# @todo Keep track of whether a default namespace has been declared
|
|
240
|
+
# and handle namespace-unspecified selectors accordingly.
|
|
241
|
+
#
|
|
242
|
+
# @see Selector#unify
|
|
243
|
+
def unify(sels)
|
|
244
|
+
case sels.first
|
|
245
|
+
when Universal;
|
|
246
|
+
when Element; return unless name == sels.first.name
|
|
247
|
+
else return [self] + sels
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
ns, accept = unify_namespaces(namespace, sels.first.namespace)
|
|
251
|
+
return unless accept
|
|
252
|
+
[Element.new(name, ns)] + sels[1..-1]
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
# @see AbstractSequence#specificity
|
|
256
|
+
def specificity
|
|
257
|
+
1
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
# Selector interpolation (`#{}` in Sass).
|
|
262
|
+
class Interpolation < Simple
|
|
263
|
+
# The script to run.
|
|
264
|
+
#
|
|
265
|
+
# @return [Sass::Script::Node]
|
|
266
|
+
attr_reader :script
|
|
267
|
+
|
|
268
|
+
# @param script [Sass::Script::Node] The script to run
|
|
269
|
+
def initialize(script)
|
|
270
|
+
@script = script
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
# @see Selector#to_a
|
|
274
|
+
def to_a
|
|
275
|
+
[@script]
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
# Always raises an exception.
|
|
279
|
+
#
|
|
280
|
+
# @raise [Sass::SyntaxError] Interpolation selectors should be resolved before unification
|
|
281
|
+
# @see Selector#unify
|
|
282
|
+
def unify(sels)
|
|
283
|
+
raise Sass::SyntaxError.new("[BUG] Cannot unify interpolation selectors.")
|
|
284
|
+
end
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
# An attribute selector (e.g. `[href^="http://"]`).
|
|
288
|
+
class Attribute < Simple
|
|
289
|
+
# The attribute name.
|
|
290
|
+
#
|
|
291
|
+
# @return [Array<String, Sass::Script::Node>]
|
|
292
|
+
attr_reader :name
|
|
293
|
+
|
|
294
|
+
# The attribute namespace.
|
|
295
|
+
# `nil` means the default namespace,
|
|
296
|
+
# `[""]` means no namespace,
|
|
297
|
+
# `["*"]` means any namespace.
|
|
298
|
+
#
|
|
299
|
+
# @return [Array<String, Sass::Script::Node>, nil]
|
|
300
|
+
attr_reader :namespace
|
|
301
|
+
|
|
302
|
+
# The matching operator, e.g. `"="` or `"^="`.
|
|
303
|
+
#
|
|
304
|
+
# @return [String]
|
|
305
|
+
attr_reader :operator
|
|
306
|
+
|
|
307
|
+
# The right-hand side of the operator.
|
|
308
|
+
#
|
|
309
|
+
# @return [Array<String, Sass::Script::Node>]
|
|
310
|
+
attr_reader :value
|
|
311
|
+
|
|
312
|
+
# Flags for the attribute selector (e.g. `i`).
|
|
313
|
+
#
|
|
314
|
+
# @return [Array<String, Sass::Script::Node>]
|
|
315
|
+
attr_reader :flags
|
|
316
|
+
|
|
317
|
+
# @param name [Array<String, Sass::Script::Node>] The attribute name
|
|
318
|
+
# @param namespace [Array<String, Sass::Script::Node>, nil] See \{#namespace}
|
|
319
|
+
# @param operator [String] The matching operator, e.g. `"="` or `"^="`
|
|
320
|
+
# @param value [Array<String, Sass::Script::Node>] See \{#value}
|
|
321
|
+
# @param value [Array<String, Sass::Script::Node>] See \{#flags}
|
|
322
|
+
def initialize(name, namespace, operator, value, flags)
|
|
323
|
+
@name = name
|
|
324
|
+
@namespace = namespace
|
|
325
|
+
@operator = operator
|
|
326
|
+
@value = value
|
|
327
|
+
@flags = flags
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
# @see Selector#to_a
|
|
331
|
+
def to_a
|
|
332
|
+
res = ["["]
|
|
333
|
+
res.concat(@namespace) << "|" if @namespace
|
|
334
|
+
res.concat @name
|
|
335
|
+
(res << @operator).concat @value if @value
|
|
336
|
+
(res << " ").concat @flags if @flags
|
|
337
|
+
res << "]"
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
# @see AbstractSequence#specificity
|
|
341
|
+
def specificity
|
|
342
|
+
SPECIFICITY_BASE
|
|
343
|
+
end
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
# A pseudoclass (e.g. `:visited`) or pseudoelement (e.g. `::first-line`) selector.
|
|
347
|
+
# It can have arguments (e.g. `:nth-child(2n+1)`).
|
|
348
|
+
class Pseudo < Simple
|
|
349
|
+
# Some psuedo-class-syntax selectors are actually considered
|
|
350
|
+
# pseudo-elements and must be treated differently. This is a list of such
|
|
351
|
+
# selectors
|
|
352
|
+
#
|
|
353
|
+
# @return [Array<String>]
|
|
354
|
+
ACTUALLY_ELEMENTS = %w[after before first-line first-letter]
|
|
355
|
+
|
|
356
|
+
# Like \{#type}, but returns the type of selector this looks like, rather
|
|
357
|
+
# than the type it is semantically. This only differs from type for
|
|
358
|
+
# selectors in \{ACTUALLY\_ELEMENTS}.
|
|
359
|
+
#
|
|
360
|
+
# @return [Symbol]
|
|
361
|
+
attr_reader :syntactic_type
|
|
362
|
+
|
|
363
|
+
# The name of the selector.
|
|
364
|
+
#
|
|
365
|
+
# @return [Array<String, Sass::Script::Node>]
|
|
366
|
+
attr_reader :name
|
|
367
|
+
|
|
368
|
+
# The argument to the selector,
|
|
369
|
+
# or `nil` if no argument was given.
|
|
370
|
+
#
|
|
371
|
+
# This may include SassScript nodes that will be run during resolution.
|
|
372
|
+
# Note that this should not include SassScript nodes
|
|
373
|
+
# after resolution has taken place.
|
|
374
|
+
#
|
|
375
|
+
# @return [Array<String, Sass::Script::Node>, nil]
|
|
376
|
+
attr_reader :arg
|
|
377
|
+
|
|
378
|
+
# @param type [Symbol] See \{#type}
|
|
379
|
+
# @param name [Array<String, Sass::Script::Node>] The name of the selector
|
|
380
|
+
# @param arg [nil, Array<String, Sass::Script::Node>] The argument to the selector,
|
|
381
|
+
# or nil if no argument was given
|
|
382
|
+
def initialize(type, name, arg)
|
|
383
|
+
@syntactic_type = type
|
|
384
|
+
@name = name
|
|
385
|
+
@arg = arg
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
# The type of the selector. `:class` if this is a pseudoclass selector,
|
|
389
|
+
# `:element` if it's a pseudoelement.
|
|
390
|
+
#
|
|
391
|
+
# @return [Symbol]
|
|
392
|
+
def type
|
|
393
|
+
ACTUALLY_ELEMENTS.include?(name.first) ? :element : syntactic_type
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
# @see Selector#to_a
|
|
397
|
+
def to_a
|
|
398
|
+
res = [syntactic_type == :class ? ":" : "::"] + @name
|
|
399
|
+
(res << "(").concat(Sass::Util.strip_string_array(@arg)) << ")" if @arg
|
|
400
|
+
res
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
# Returns `nil` if this is a pseudoelement selector
|
|
404
|
+
# and `sels` contains a pseudoelement selector different than this one.
|
|
405
|
+
#
|
|
406
|
+
# @see Selector#unify
|
|
407
|
+
def unify(sels)
|
|
408
|
+
return if type == :element && sels.any? do |sel|
|
|
409
|
+
sel.is_a?(Pseudo) && sel.type == :element &&
|
|
410
|
+
(sel.name != self.name || sel.arg != self.arg)
|
|
411
|
+
end
|
|
412
|
+
super
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
# @see AbstractSequence#specificity
|
|
416
|
+
def specificity
|
|
417
|
+
type == :class ? SPECIFICITY_BASE : 1
|
|
418
|
+
end
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
# A pseudoclass selector whose argument is itself a selector
|
|
422
|
+
# (e.g. `:not(.foo)` or `:-moz-all(.foo, .bar)`).
|
|
423
|
+
class SelectorPseudoClass < Simple
|
|
424
|
+
# The name of the pseudoclass.
|
|
425
|
+
#
|
|
426
|
+
# @return [String]
|
|
427
|
+
attr_reader :name
|
|
428
|
+
|
|
429
|
+
# The selector argument.
|
|
430
|
+
#
|
|
431
|
+
# @return [Selector::Sequence]
|
|
432
|
+
attr_reader :selector
|
|
433
|
+
|
|
434
|
+
# @param [String] The name of the pseudoclass
|
|
435
|
+
# @param [Selector::CommaSequence] The selector argument
|
|
436
|
+
def initialize(name, selector)
|
|
437
|
+
@name = name
|
|
438
|
+
@selector = selector
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
# @see Selector#to_a
|
|
442
|
+
def to_a
|
|
443
|
+
[":", @name, "("] + @selector.to_a + [")"]
|
|
444
|
+
end
|
|
445
|
+
|
|
446
|
+
# @see AbstractSequence#specificity
|
|
447
|
+
def specificity
|
|
448
|
+
SPECIFICITY_BASE
|
|
449
|
+
end
|
|
450
|
+
end
|
|
451
|
+
end
|
|
452
|
+
end
|