sass 3.2.19 → 3.4.25
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardopts +3 -1
- data/CODE_OF_CONDUCT.md +10 -0
- data/CONTRIBUTING.md +148 -0
- data/MIT-LICENSE +1 -1
- data/README.md +87 -61
- data/Rakefile +119 -15
- data/VERSION +1 -1
- data/VERSION_DATE +1 -1
- data/VERSION_NAME +1 -1
- data/bin/sass +1 -1
- data/bin/scss +1 -1
- data/extra/sass-spec-ref.sh +32 -0
- data/extra/update_watch.rb +1 -1
- data/lib/sass/cache_stores/base.rb +2 -2
- data/lib/sass/cache_stores/chain.rb +2 -1
- data/lib/sass/cache_stores/filesystem.rb +8 -12
- data/lib/sass/cache_stores/memory.rb +5 -6
- data/lib/sass/cache_stores/null.rb +2 -2
- data/lib/sass/callbacks.rb +3 -2
- data/lib/sass/css.rb +22 -23
- data/lib/sass/deprecation.rb +55 -0
- data/lib/sass/engine.rb +487 -191
- data/lib/sass/environment.rb +172 -58
- data/lib/sass/error.rb +21 -24
- data/lib/sass/exec/base.rb +199 -0
- data/lib/sass/exec/sass_convert.rb +283 -0
- data/lib/sass/exec/sass_scss.rb +440 -0
- data/lib/sass/exec.rb +5 -703
- data/lib/sass/features.rb +47 -0
- data/lib/sass/importers/base.rb +50 -7
- data/lib/sass/importers/deprecated_path.rb +51 -0
- data/lib/sass/importers/filesystem.rb +54 -21
- data/lib/sass/importers.rb +1 -0
- data/lib/sass/logger/base.rb +9 -5
- data/lib/sass/logger/delayed.rb +50 -0
- data/lib/sass/logger/log_level.rb +3 -7
- data/lib/sass/logger.rb +9 -7
- data/lib/sass/media.rb +20 -23
- data/lib/sass/plugin/compiler.rb +321 -145
- data/lib/sass/plugin/configuration.rb +45 -34
- data/lib/sass/plugin/merb.rb +3 -3
- data/lib/sass/plugin/rack.rb +3 -3
- data/lib/sass/plugin/rails.rb +1 -1
- data/lib/sass/plugin/staleness_checker.rb +6 -6
- data/lib/sass/plugin.rb +9 -8
- data/lib/sass/repl.rb +3 -3
- data/lib/sass/script/css_lexer.rb +8 -4
- data/lib/sass/script/css_parser.rb +4 -2
- data/lib/sass/script/css_variable_warning.rb +52 -0
- data/lib/sass/script/functions.rb +1583 -433
- data/lib/sass/script/lexer.rb +198 -79
- data/lib/sass/script/parser.rb +463 -133
- data/lib/sass/script/tree/funcall.rb +313 -0
- data/lib/sass/script/tree/interpolation.rb +223 -0
- data/lib/sass/script/tree/list_literal.rb +104 -0
- data/lib/sass/script/tree/literal.rb +49 -0
- data/lib/sass/script/tree/map_literal.rb +64 -0
- data/lib/sass/script/{node.rb → tree/node.rb} +42 -14
- data/lib/sass/script/tree/operation.rb +156 -0
- data/lib/sass/script/tree/selector.rb +26 -0
- data/lib/sass/script/tree/string_interpolation.rb +125 -0
- data/lib/sass/script/{unary_operation.rb → tree/unary_operation.rb} +6 -6
- 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} +9 -25
- data/lib/sass/script/value/base.rb +241 -0
- data/lib/sass/script/value/bool.rb +35 -0
- data/lib/sass/script/value/color.rb +698 -0
- data/lib/sass/script/value/helpers.rb +272 -0
- data/lib/sass/script/value/list.rb +113 -0
- data/lib/sass/script/value/map.rb +70 -0
- data/lib/sass/script/{null.rb → value/null.rb} +14 -7
- data/lib/sass/script/{number.rb → value/number.rb} +196 -86
- data/lib/sass/script/value/string.rb +138 -0
- data/lib/sass/script/value.rb +11 -0
- data/lib/sass/script.rb +38 -11
- data/lib/sass/scss/css_parser.rb +25 -5
- data/lib/sass/scss/parser.rb +532 -458
- data/lib/sass/scss/rx.rb +21 -14
- data/lib/sass/scss/static_parser.rb +328 -9
- data/lib/sass/scss.rb +0 -2
- data/lib/sass/selector/abstract_sequence.rb +36 -19
- data/lib/sass/selector/comma_sequence.rb +125 -26
- data/lib/sass/selector/pseudo.rb +266 -0
- data/lib/sass/selector/sequence.rb +200 -71
- data/lib/sass/selector/simple.rb +30 -32
- data/lib/sass/selector/simple_sequence.rb +193 -64
- data/lib/sass/selector.rb +65 -194
- data/lib/sass/shared.rb +2 -2
- data/lib/sass/source/map.rb +213 -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 +19 -23
- data/lib/sass/tree/at_root_node.rb +83 -0
- data/lib/sass/tree/charset_node.rb +1 -1
- data/lib/sass/tree/comment_node.rb +4 -4
- data/lib/sass/tree/css_import_node.rb +19 -11
- data/lib/sass/tree/debug_node.rb +2 -2
- data/lib/sass/tree/directive_node.rb +21 -4
- data/lib/sass/tree/each_node.rb +8 -8
- data/lib/sass/tree/error_node.rb +18 -0
- data/lib/sass/tree/extend_node.rb +14 -7
- data/lib/sass/tree/for_node.rb +4 -4
- data/lib/sass/tree/function_node.rb +14 -4
- data/lib/sass/tree/if_node.rb +1 -1
- data/lib/sass/tree/import_node.rb +10 -10
- data/lib/sass/tree/keyframe_rule_node.rb +15 -0
- 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 +59 -15
- data/lib/sass/tree/prop_node.rb +42 -24
- 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 +49 -26
- 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 +5 -8
- data/lib/sass/tree/visitors/check_nesting.rb +62 -36
- data/lib/sass/tree/visitors/convert.rb +111 -76
- data/lib/sass/tree/visitors/cssize.rb +206 -74
- data/lib/sass/tree/visitors/deep_copy.rb +11 -6
- data/lib/sass/tree/visitors/extend.rb +19 -17
- data/lib/sass/tree/visitors/perform.rb +308 -190
- data/lib/sass/tree/visitors/set_options.rb +21 -7
- data/lib/sass/tree/visitors/to_css.rb +273 -92
- data/lib/sass/tree/warn_node.rb +2 -2
- data/lib/sass/tree/while_node.rb +2 -2
- data/lib/sass/util/cross_platform_random.rb +19 -0
- data/lib/sass/util/normalized_map.rb +129 -0
- data/lib/sass/util/ordered_hash.rb +192 -0
- data/lib/sass/util/subset_map.rb +5 -5
- data/lib/sass/util/test.rb +0 -1
- data/lib/sass/util.rb +620 -193
- data/lib/sass/version.rb +22 -24
- data/lib/sass.rb +27 -13
- data/test/sass/cache_test.rb +62 -20
- data/test/sass/callbacks_test.rb +1 -1
- data/test/sass/compiler_test.rb +236 -0
- data/test/sass/conversion_test.rb +472 -44
- data/test/sass/css2sass_test.rb +73 -5
- data/test/sass/css_variable_test.rb +132 -0
- data/test/sass/encoding_test.rb +219 -0
- data/test/sass/engine_test.rb +618 -415
- data/test/sass/exec_test.rb +12 -2
- data/test/sass/extend_test.rb +419 -168
- data/test/sass/functions_test.rb +931 -93
- data/test/sass/importer_test.rb +250 -21
- data/test/sass/logger_test.rb +1 -1
- data/test/sass/more_results/more_import.css +1 -1
- data/test/sass/more_templates/more1.sass +10 -10
- data/test/sass/more_templates/more_import.sass +2 -2
- data/test/sass/plugin_test.rb +26 -34
- data/test/sass/results/compact.css +1 -1
- data/test/sass/results/complex.css +4 -4
- data/test/sass/results/expanded.css +1 -1
- data/test/sass/results/import.css +1 -1
- data/test/sass/results/import_charset_ibm866.css +2 -2
- data/test/sass/results/mixins.css +17 -17
- data/test/sass/results/nested.css +1 -1
- data/test/sass/results/parent_ref.css +2 -2
- data/test/sass/results/script.css +5 -5
- data/test/sass/results/scss_import.css +1 -1
- data/test/sass/script_conversion_test.rb +97 -39
- data/test/sass/script_test.rb +911 -102
- data/test/sass/scss/css_test.rb +215 -34
- data/test/sass/scss/rx_test.rb +8 -4
- data/test/sass/scss/scss_test.rb +2424 -325
- data/test/sass/source_map_test.rb +1055 -0
- data/test/sass/superselector_test.rb +210 -0
- data/test/sass/templates/_partial.sass +1 -1
- data/test/sass/templates/basic.sass +10 -10
- data/test/sass/templates/bork1.sass +1 -1
- data/test/sass/templates/bork5.sass +1 -1
- data/test/sass/templates/compact.sass +10 -10
- data/test/sass/templates/complex.sass +187 -187
- data/test/sass/templates/compressed.sass +10 -10
- data/test/sass/templates/expanded.sass +10 -10
- data/test/sass/templates/import.sass +2 -2
- data/test/sass/templates/importee.sass +3 -3
- data/test/sass/templates/mixins.sass +22 -22
- data/test/sass/templates/multiline.sass +4 -4
- data/test/sass/templates/nested.sass +13 -13
- data/test/sass/templates/parent_ref.sass +12 -12
- data/test/sass/templates/script.sass +70 -70
- data/test/sass/templates/scss_import.scss +2 -1
- data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +1 -1
- data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +2 -2
- data/test/sass/templates/subdir/subdir.sass +3 -3
- data/test/sass/templates/units.sass +10 -10
- data/test/sass/test_helper.rb +1 -1
- data/test/sass/util/multibyte_string_scanner_test.rb +11 -3
- data/test/sass/util/normalized_map_test.rb +51 -0
- data/test/sass/util/subset_map_test.rb +2 -2
- data/test/sass/util_test.rb +99 -43
- data/test/sass/value_helpers_test.rb +179 -0
- data/test/sass-spec.yml +3 -0
- data/test/test_helper.rb +42 -12
- data/vendor/listen/CHANGELOG.md +1 -228
- data/vendor/listen/Gemfile +5 -15
- data/vendor/listen/README.md +111 -77
- data/vendor/listen/Rakefile +0 -42
- data/vendor/listen/lib/listen/adapter.rb +195 -82
- data/vendor/listen/lib/listen/adapters/bsd.rb +27 -64
- data/vendor/listen/lib/listen/adapters/darwin.rb +21 -58
- data/vendor/listen/lib/listen/adapters/linux.rb +23 -55
- data/vendor/listen/lib/listen/adapters/polling.rb +25 -34
- data/vendor/listen/lib/listen/adapters/windows.rb +50 -46
- data/vendor/listen/lib/listen/directory_record.rb +96 -61
- data/vendor/listen/lib/listen/listener.rb +135 -37
- data/vendor/listen/lib/listen/turnstile.rb +9 -5
- data/vendor/listen/lib/listen/version.rb +1 -1
- data/vendor/listen/lib/listen.rb +33 -19
- data/vendor/listen/listen.gemspec +6 -0
- data/vendor/listen/spec/listen/adapter_spec.rb +43 -77
- data/vendor/listen/spec/listen/adapters/polling_spec.rb +8 -8
- data/vendor/listen/spec/listen/directory_record_spec.rb +81 -56
- data/vendor/listen/spec/listen/listener_spec.rb +128 -39
- data/vendor/listen/spec/listen_spec.rb +15 -21
- data/vendor/listen/spec/spec_helper.rb +4 -0
- data/vendor/listen/spec/support/adapter_helper.rb +52 -15
- data/vendor/listen/spec/support/directory_record_helper.rb +7 -5
- data/vendor/listen/spec/support/listeners_helper.rb +30 -7
- metadata +161 -111
- data/CONTRIBUTING +0 -3
- data/lib/sass/script/bool.rb +0 -18
- data/lib/sass/script/color.rb +0 -606
- data/lib/sass/script/funcall.rb +0 -245
- data/lib/sass/script/interpolation.rb +0 -79
- data/lib/sass/script/list.rb +0 -85
- data/lib/sass/script/literal.rb +0 -221
- data/lib/sass/script/operation.rb +0 -110
- data/lib/sass/script/string.rb +0 -51
- data/lib/sass/script/string_interpolation.rb +0 -103
- data/lib/sass/script/variable.rb +0 -58
- data/lib/sass/scss/script_lexer.rb +0 -15
- data/lib/sass/scss/script_parser.rb +0 -25
- data/test/Gemfile +0 -3
- data/test/Gemfile.lock +0 -10
- data/vendor/listen/lib/listen/dependency_manager.rb +0 -126
- data/vendor/listen/lib/listen/multi_listener.rb +0 -143
- data/vendor/listen/spec/listen/dependency_manager_spec.rb +0 -107
- data/vendor/listen/spec/listen/multi_listener_spec.rb +0 -174
@@ -9,10 +9,12 @@ class Sass::Tree::Visitors::Cssize < Sass::Tree::Visitors::Base
|
|
9
9
|
|
10
10
|
# Returns the immediate parent of the current node.
|
11
11
|
# @return [Tree::Node]
|
12
|
-
|
12
|
+
def parent
|
13
|
+
@parents.last
|
14
|
+
end
|
13
15
|
|
14
16
|
def initialize
|
15
|
-
@
|
17
|
+
@parents = []
|
16
18
|
@extends = Sass::Util::SubsetMap.new
|
17
19
|
end
|
18
20
|
|
@@ -27,12 +29,19 @@ class Sass::Tree::Visitors::Cssize < Sass::Tree::Visitors::Base
|
|
27
29
|
# Keeps track of the current parent node.
|
28
30
|
def visit_children(parent)
|
29
31
|
with_parent parent do
|
30
|
-
parent.children =
|
32
|
+
parent.children = visit_children_without_parent(parent)
|
31
33
|
parent
|
32
34
|
end
|
33
35
|
end
|
34
36
|
|
35
|
-
|
37
|
+
# Like {#visit\_children}, but doesn't set {#parent}.
|
38
|
+
#
|
39
|
+
# @param node [Sass::Tree::Node]
|
40
|
+
# @return [Array<Sass::Tree::Node>] the flattened results of
|
41
|
+
# visiting all the children of `node`
|
42
|
+
def visit_children_without_parent(node)
|
43
|
+
node.children.map {|c| visit(c)}.flatten
|
44
|
+
end
|
36
45
|
|
37
46
|
# Runs a block of code with the current parent node
|
38
47
|
# replaced with the given node.
|
@@ -41,19 +50,10 @@ class Sass::Tree::Visitors::Cssize < Sass::Tree::Visitors::Base
|
|
41
50
|
# @yield A block in which the parent is set to `parent`.
|
42
51
|
# @return [Object] The return value of the block.
|
43
52
|
def with_parent(parent)
|
44
|
-
|
45
|
-
if MERGEABLE_DIRECTIVES.any? {|klass| parent.is_a?(klass)}
|
46
|
-
old_parent_directive = @parent_directives.pop
|
47
|
-
end
|
48
|
-
@parent_directives.push parent
|
49
|
-
end
|
50
|
-
|
51
|
-
old_parent, @parent = @parent, parent
|
53
|
+
@parents.push parent
|
52
54
|
yield
|
53
55
|
ensure
|
54
|
-
@
|
55
|
-
@parent_directives.push old_parent_directive if old_parent_directive
|
56
|
-
@parent = old_parent
|
56
|
+
@parents.pop
|
57
57
|
end
|
58
58
|
|
59
59
|
# In Ruby 1.8, ensures that there's only one `@charset` directive
|
@@ -106,7 +106,7 @@ class Sass::Tree::Visitors::Cssize < Sass::Tree::Visitors::Base
|
|
106
106
|
end
|
107
107
|
|
108
108
|
# A simple struct wrapping up information about a single `@extend` instance. A
|
109
|
-
# single
|
109
|
+
# single {ExtendNode} can have multiple Extends if either the parent node or
|
110
110
|
# the extended selector is a comma sequence.
|
111
111
|
#
|
112
112
|
# @attr extender [Sass::Selector::Sequence]
|
@@ -123,61 +123,23 @@ class Sass::Tree::Visitors::Cssize < Sass::Tree::Visitors::Base
|
|
123
123
|
|
124
124
|
# Registers an extension in the `@extends` subset map.
|
125
125
|
def visit_extend(node)
|
126
|
-
node.resolved_selector
|
127
|
-
|
128
|
-
raise Sass::SyntaxError.new("Can't extend #{seq.to_a.join}: can't extend nested selectors")
|
129
|
-
end
|
130
|
-
|
131
|
-
sseq = seq.members.first
|
132
|
-
if !sseq.is_a?(Sass::Selector::SimpleSequence)
|
133
|
-
raise Sass::SyntaxError.new("Can't extend #{seq.to_a.join}: invalid selector")
|
134
|
-
elsif sseq.members.any? {|ss| ss.is_a?(Sass::Selector::Parent)}
|
135
|
-
raise Sass::SyntaxError.new("Can't extend #{seq.to_a.join}: can't extend parent selectors")
|
136
|
-
end
|
137
|
-
|
138
|
-
sel = sseq.members
|
139
|
-
parent.resolved_rules.members.each do |member|
|
140
|
-
if !member.members.last.is_a?(Sass::Selector::SimpleSequence)
|
141
|
-
raise Sass::SyntaxError.new("#{member} can't extend: invalid selector")
|
142
|
-
end
|
143
|
-
|
144
|
-
@extends[sel] = Extend.new(member, sel, node, @parent_directives.dup, :not_found)
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
126
|
+
parent.resolved_rules.populate_extends(@extends, node.resolved_selector, node,
|
127
|
+
@parents.select {|p| p.is_a?(Sass::Tree::DirectiveNode)})
|
148
128
|
[]
|
149
129
|
end
|
150
130
|
|
151
131
|
# Modifies exception backtraces to include the imported file.
|
152
132
|
def visit_import(node)
|
153
|
-
|
154
|
-
node.children.map {|c| visit(c)}.flatten
|
133
|
+
visit_children_without_parent(node)
|
155
134
|
rescue Sass::SyntaxError => e
|
156
135
|
e.modify_backtrace(:filename => node.children.first.filename)
|
157
136
|
e.add_backtrace(:filename => node.filename, :line => node.line)
|
158
137
|
raise e
|
159
138
|
end
|
160
139
|
|
161
|
-
# Bubbles the `@media` directive up through RuleNodes
|
162
|
-
# and merges it with other `@media` directives.
|
163
|
-
def visit_media(node)
|
164
|
-
yield unless bubble(node)
|
165
|
-
media = node.children.select {|c| c.is_a?(Sass::Tree::MediaNode)}
|
166
|
-
node.children.reject! {|c| c.is_a?(Sass::Tree::MediaNode)}
|
167
|
-
media = media.select {|n| n.resolved_query = n.resolved_query.merge(node.resolved_query)}
|
168
|
-
(node.children.empty? ? [] : [node]) + media
|
169
|
-
end
|
170
|
-
|
171
|
-
# Bubbles the `@supports` directive up through RuleNodes.
|
172
|
-
def visit_supports(node)
|
173
|
-
yield unless bubble(node)
|
174
|
-
node
|
175
|
-
end
|
176
|
-
|
177
140
|
# Asserts that all the traced children are valid in their new location.
|
178
141
|
def visit_trace(node)
|
179
|
-
|
180
|
-
node.children.map {|c| visit(c)}.flatten
|
142
|
+
visit_children_without_parent(node)
|
181
143
|
rescue Sass::SyntaxError => e
|
182
144
|
e.modify_backtrace(:mixin => node.name, :filename => node.filename, :line => node.line)
|
183
145
|
e.add_backtrace(:filename => node.filename, :line => node.line)
|
@@ -203,17 +165,38 @@ class Sass::Tree::Visitors::Cssize < Sass::Tree::Visitors::Base
|
|
203
165
|
result
|
204
166
|
end
|
205
167
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
168
|
+
def visit_atroot(node)
|
169
|
+
# If there aren't any more directives or rules that this @at-root needs to
|
170
|
+
# exclude, we can get rid of it and just evaluate the children.
|
171
|
+
if @parents.none? {|n| node.exclude_node?(n)}
|
172
|
+
results = visit_children_without_parent(node)
|
173
|
+
results.each {|c| c.tabs += node.tabs if bubblable?(c)}
|
174
|
+
if !results.empty? && bubblable?(results.last)
|
175
|
+
results.last.group_end = node.group_end
|
176
|
+
end
|
177
|
+
return results
|
178
|
+
end
|
179
|
+
|
180
|
+
# If this @at-root excludes the immediate parent, return it as-is so that it
|
181
|
+
# can be bubbled up by the parent node.
|
182
|
+
return Bubble.new(node) if node.exclude_node?(parent)
|
183
|
+
|
184
|
+
# Otherwise, duplicate the current parent and move it into the @at-root
|
185
|
+
# node. As above, returning an @at-root node signals to the parent directive
|
186
|
+
# that it should be bubbled upwards.
|
187
|
+
bubble(node)
|
188
|
+
end
|
212
189
|
|
190
|
+
# The following directives are visible and have children. This means they need
|
191
|
+
# to be able to handle bubbling up nodes such as @at-root and @media.
|
192
|
+
|
193
|
+
# Updates the indentation of the rule node based on the nesting
|
194
|
+
# level. The selectors were resolved in {Perform}.
|
195
|
+
def visit_rule(node)
|
213
196
|
yield
|
214
197
|
|
215
|
-
rules = node.children.select {|c|
|
216
|
-
props = node.children.reject {|c|
|
198
|
+
rules = node.children.select {|c| bubblable?(c)}
|
199
|
+
props = node.children.reject {|c| bubblable?(c) || c.invisible?}
|
217
200
|
|
218
201
|
unless props.empty?
|
219
202
|
node.children = props
|
@@ -221,21 +204,170 @@ class Sass::Tree::Visitors::Cssize < Sass::Tree::Visitors::Base
|
|
221
204
|
rules.unshift(node)
|
222
205
|
end
|
223
206
|
|
224
|
-
rules
|
225
|
-
|
207
|
+
rules = debubble(rules)
|
208
|
+
unless parent.is_a?(Sass::Tree::RuleNode) || rules.empty? || !bubblable?(rules.last)
|
209
|
+
rules.last.group_end = true
|
210
|
+
end
|
226
211
|
rules
|
227
212
|
end
|
228
213
|
|
214
|
+
def visit_keyframerule(node)
|
215
|
+
return node unless node.has_children
|
216
|
+
|
217
|
+
yield
|
218
|
+
|
219
|
+
debubble(node.children, node)
|
220
|
+
end
|
221
|
+
|
222
|
+
# Bubbles a directive up through RuleNodes.
|
223
|
+
def visit_directive(node)
|
224
|
+
return node unless node.has_children
|
225
|
+
if parent.is_a?(Sass::Tree::RuleNode)
|
226
|
+
# @keyframes shouldn't include the rule nodes, so we manually create a
|
227
|
+
# bubble that doesn't have the parent's contents for them.
|
228
|
+
return node.normalized_name == '@keyframes' ? Bubble.new(node) : bubble(node)
|
229
|
+
end
|
230
|
+
|
231
|
+
yield
|
232
|
+
|
233
|
+
# Since we don't know if the mere presence of an unknown directive may be
|
234
|
+
# important, we should keep an empty version around even if all the contents
|
235
|
+
# are removed via @at-root. However, if the contents are just bubbled out,
|
236
|
+
# we don't need to do so.
|
237
|
+
directive_exists = node.children.any? do |child|
|
238
|
+
next true unless child.is_a?(Bubble)
|
239
|
+
next false unless child.node.is_a?(Sass::Tree::DirectiveNode)
|
240
|
+
child.node.resolved_value == node.resolved_value
|
241
|
+
end
|
242
|
+
|
243
|
+
# We know empty @keyframes directives do nothing.
|
244
|
+
if directive_exists || node.name == '@keyframes'
|
245
|
+
[]
|
246
|
+
else
|
247
|
+
empty_node = node.dup
|
248
|
+
empty_node.children = []
|
249
|
+
[empty_node]
|
250
|
+
end + debubble(node.children, node)
|
251
|
+
end
|
252
|
+
|
253
|
+
# Bubbles the `@media` directive up through RuleNodes
|
254
|
+
# and merges it with other `@media` directives.
|
255
|
+
def visit_media(node)
|
256
|
+
return bubble(node) if parent.is_a?(Sass::Tree::RuleNode)
|
257
|
+
return Bubble.new(node) if parent.is_a?(Sass::Tree::MediaNode)
|
258
|
+
|
259
|
+
yield
|
260
|
+
|
261
|
+
debubble(node.children, node) do |child|
|
262
|
+
next child unless child.is_a?(Sass::Tree::MediaNode)
|
263
|
+
# Copies of `node` can be bubbled, and we don't want to merge it with its
|
264
|
+
# own query.
|
265
|
+
next child if child.resolved_query == node.resolved_query
|
266
|
+
next child if child.resolved_query = child.resolved_query.merge(node.resolved_query)
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
# Bubbles the `@supports` directive up through RuleNodes.
|
271
|
+
def visit_supports(node)
|
272
|
+
return node unless node.has_children
|
273
|
+
return bubble(node) if parent.is_a?(Sass::Tree::RuleNode)
|
274
|
+
|
275
|
+
yield
|
276
|
+
|
277
|
+
debubble(node.children, node)
|
278
|
+
end
|
279
|
+
|
229
280
|
private
|
230
281
|
|
282
|
+
# "Bubbles" `node` one level by copying the parent and wrapping `node`'s
|
283
|
+
# children with it.
|
284
|
+
#
|
285
|
+
# @param node [Sass::Tree::Node].
|
286
|
+
# @return [Bubble]
|
231
287
|
def bubble(node)
|
232
|
-
return unless parent.is_a?(Sass::Tree::RuleNode)
|
233
288
|
new_rule = parent.dup
|
234
289
|
new_rule.children = node.children
|
235
|
-
node.children =
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
290
|
+
node.children = [new_rule]
|
291
|
+
Bubble.new(node)
|
292
|
+
end
|
293
|
+
|
294
|
+
# Pops all bubbles in `children` and intersperses the results with the other
|
295
|
+
# values.
|
296
|
+
#
|
297
|
+
# If `parent` is passed, it's copied and used as the parent node for the
|
298
|
+
# nested portions of `children`.
|
299
|
+
#
|
300
|
+
# @param children [List<Sass::Tree::Node, Bubble>]
|
301
|
+
# @param parent [Sass::Tree::Node]
|
302
|
+
# @yield [node] An optional block for processing bubbled nodes. Each bubbled
|
303
|
+
# node will be passed to this block.
|
304
|
+
# @yieldparam node [Sass::Tree::Node] A bubbled node.
|
305
|
+
# @yieldreturn [Sass::Tree::Node?] A node to use in place of the bubbled node.
|
306
|
+
# This can be the node itself, or `nil` to indicate that the node should be
|
307
|
+
# omitted.
|
308
|
+
# @return [List<Sass::Tree::Node, Bubble>]
|
309
|
+
def debubble(children, parent = nil)
|
310
|
+
# Keep track of the previous parent so that we don't divide `parent`
|
311
|
+
# unnecessarily if the `@at-root` doesn't produce any new nodes (e.g.
|
312
|
+
# `@at-root {@extend %foo}`).
|
313
|
+
previous_parent = nil
|
314
|
+
|
315
|
+
Sass::Util.slice_by(children) {|c| c.is_a?(Bubble)}.map do |(is_bubble, slice)|
|
316
|
+
unless is_bubble
|
317
|
+
next slice unless parent
|
318
|
+
if previous_parent
|
319
|
+
previous_parent.children.push(*slice)
|
320
|
+
next []
|
321
|
+
else
|
322
|
+
previous_parent = new_parent = parent.dup
|
323
|
+
new_parent.children = slice
|
324
|
+
next new_parent
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
slice.map do |bubble|
|
329
|
+
next unless (node = block_given? ? yield(bubble.node) : bubble.node)
|
330
|
+
node.tabs += bubble.tabs
|
331
|
+
node.group_end = bubble.group_end
|
332
|
+
results = [visit(node)].flatten
|
333
|
+
previous_parent = nil unless results.empty?
|
334
|
+
results
|
335
|
+
end.compact
|
336
|
+
end.flatten
|
337
|
+
end
|
338
|
+
|
339
|
+
# Returns whether or not a node can be bubbled up through the syntax tree.
|
340
|
+
#
|
341
|
+
# @param node [Sass::Tree::Node]
|
342
|
+
# @return [Boolean]
|
343
|
+
def bubblable?(node)
|
344
|
+
node.is_a?(Sass::Tree::RuleNode) || node.bubbles?
|
345
|
+
end
|
346
|
+
|
347
|
+
# A wrapper class for a node that indicates to the parent that it should
|
348
|
+
# treat the wrapped node as a sibling rather than a child.
|
349
|
+
#
|
350
|
+
# Nodes should be wrapped before they're passed to \{Cssize.visit}. They will
|
351
|
+
# be automatically visited upon calling \{#pop}.
|
352
|
+
#
|
353
|
+
# This duck types as a [Sass::Tree::Node] for the purposes of
|
354
|
+
# tree-manipulation operations.
|
355
|
+
class Bubble
|
356
|
+
attr_accessor :node
|
357
|
+
attr_accessor :tabs
|
358
|
+
attr_accessor :group_end
|
359
|
+
|
360
|
+
def initialize(node)
|
361
|
+
@node = node
|
362
|
+
@tabs = 0
|
363
|
+
end
|
364
|
+
|
365
|
+
def bubbles?
|
366
|
+
true
|
367
|
+
end
|
368
|
+
|
369
|
+
def inspect
|
370
|
+
"(Bubble #{node.inspect})"
|
371
|
+
end
|
240
372
|
end
|
241
373
|
end
|
@@ -16,13 +16,18 @@ class Sass::Tree::Visitors::DeepCopy < Sass::Tree::Visitors::Base
|
|
16
16
|
yield
|
17
17
|
end
|
18
18
|
|
19
|
+
def visit_error(node)
|
20
|
+
node.expr = node.expr.deep_copy
|
21
|
+
yield
|
22
|
+
end
|
23
|
+
|
19
24
|
def visit_each(node)
|
20
25
|
node.list = node.list.deep_copy
|
21
26
|
yield
|
22
27
|
end
|
23
28
|
|
24
29
|
def visit_extend(node)
|
25
|
-
node.selector = node.selector.map {|c| c.is_a?(Sass::Script::Node) ? c.deep_copy : c}
|
30
|
+
node.selector = node.selector.map {|c| c.is_a?(Sass::Script::Tree::Node) ? c.deep_copy : c}
|
26
31
|
yield
|
27
32
|
end
|
28
33
|
|
@@ -50,12 +55,12 @@ class Sass::Tree::Visitors::DeepCopy < Sass::Tree::Visitors::Base
|
|
50
55
|
|
51
56
|
def visit_mixin(node)
|
52
57
|
node.args = node.args.map {|a| a.deep_copy}
|
53
|
-
node.keywords = Hash[node.keywords.map {|k, v| [k, v.deep_copy]}]
|
58
|
+
node.keywords = Sass::Util::NormalizedMap.new(Hash[node.keywords.map {|k, v| [k, v.deep_copy]}])
|
54
59
|
yield
|
55
60
|
end
|
56
61
|
|
57
62
|
def visit_prop(node)
|
58
|
-
node.name = node.name.map {|c| c.is_a?(Sass::Script::Node) ? c.deep_copy : c}
|
63
|
+
node.name = node.name.map {|c| c.is_a?(Sass::Script::Tree::Node) ? c.deep_copy : c}
|
59
64
|
node.value = node.value.deep_copy
|
60
65
|
yield
|
61
66
|
end
|
@@ -66,7 +71,7 @@ class Sass::Tree::Visitors::DeepCopy < Sass::Tree::Visitors::Base
|
|
66
71
|
end
|
67
72
|
|
68
73
|
def visit_rule(node)
|
69
|
-
node.rule = node.rule.map {|c| c.is_a?(Sass::Script::Node) ? c.deep_copy : c}
|
74
|
+
node.rule = node.rule.map {|c| c.is_a?(Sass::Script::Tree::Node) ? c.deep_copy : c}
|
70
75
|
yield
|
71
76
|
end
|
72
77
|
|
@@ -86,12 +91,12 @@ class Sass::Tree::Visitors::DeepCopy < Sass::Tree::Visitors::Base
|
|
86
91
|
end
|
87
92
|
|
88
93
|
def visit_directive(node)
|
89
|
-
node.value = node.value.map {|c| c.is_a?(Sass::Script::Node) ? c.deep_copy : c}
|
94
|
+
node.value = node.value.map {|c| c.is_a?(Sass::Script::Tree::Node) ? c.deep_copy : c}
|
90
95
|
yield
|
91
96
|
end
|
92
97
|
|
93
98
|
def visit_media(node)
|
94
|
-
node.query = node.query.map {|c| c.is_a?(Sass::Script::Node) ? c.deep_copy : c}
|
99
|
+
node.query = node.query.map {|c| c.is_a?(Sass::Script::Tree::Node) ? c.deep_copy : c}
|
95
100
|
yield
|
96
101
|
end
|
97
102
|
|
@@ -44,25 +44,27 @@ class Sass::Tree::Visitors::Extend < Sass::Tree::Visitors::Base
|
|
44
44
|
node.resolved_rules = node.resolved_rules.do_extend(@extends, @parent_directives)
|
45
45
|
end
|
46
46
|
|
47
|
-
|
47
|
+
class << self
|
48
|
+
private
|
48
49
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
50
|
+
def check_extends_fired!(extends)
|
51
|
+
extends.each_value do |ex|
|
52
|
+
next if ex.result == :succeeded || ex.node.optional?
|
53
|
+
message = "\"#{ex.extender}\" failed to @extend \"#{ex.target.join}\"."
|
54
|
+
reason =
|
55
|
+
if ex.result == :not_found
|
56
|
+
"The selector \"#{ex.target.join}\" was not found."
|
57
|
+
else
|
58
|
+
"No selectors matching \"#{ex.target.join}\" could be unified with \"#{ex.extender}\"."
|
59
|
+
end
|
59
60
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
61
|
+
# TODO(nweiz): this should use the Sass stack trace of the extend node.
|
62
|
+
raise Sass::SyntaxError.new(<<MESSAGE, :filename => ex.node.filename, :line => ex.node.line)
|
63
|
+
#{message}
|
64
|
+
#{reason}
|
65
|
+
Use "@extend #{ex.target.join} !optional" if the extend should be able to fail.
|
66
|
+
MESSAGE
|
67
|
+
end
|
66
68
|
end
|
67
69
|
end
|
68
70
|
end
|