sass 3.1.0.alpha.48 → 3.1.0.alpha.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/EDGE_GEM_VERSION +1 -1
- data/VERSION +1 -1
- data/lib/sass/engine.rb +5 -0
- data/lib/sass/selector/comma_sequence.rb +2 -3
- data/lib/sass/selector/sequence.rb +2 -3
- data/lib/sass/selector/simple_sequence.rb +2 -3
- data/lib/sass/tree/charset_node.rb +0 -15
- data/lib/sass/tree/comment_node.rb +0 -72
- data/lib/sass/tree/debug_node.rb +4 -22
- data/lib/sass/tree/directive_node.rb +0 -52
- data/lib/sass/tree/each_node.rb +8 -24
- data/lib/sass/tree/extend_node.rb +12 -48
- data/lib/sass/tree/for_node.rb +20 -39
- data/lib/sass/tree/if_node.rb +7 -32
- data/lib/sass/tree/import_node.rb +0 -56
- data/lib/sass/tree/media_node.rb +0 -43
- data/lib/sass/tree/mixin_def_node.rb +12 -33
- data/lib/sass/tree/mixin_node.rb +14 -106
- data/lib/sass/tree/node.rb +12 -249
- data/lib/sass/tree/prop_node.rb +15 -78
- data/lib/sass/tree/root_node.rb +1 -121
- data/lib/sass/tree/rule_node.rb +1 -157
- data/lib/sass/tree/variable_node.rb +14 -23
- data/lib/sass/tree/visitors/base.rb +64 -0
- data/lib/sass/tree/visitors/convert.rb +234 -0
- data/lib/sass/tree/visitors/cssize.rb +177 -0
- data/lib/sass/tree/visitors/perform.rb +278 -0
- data/lib/sass/tree/visitors/to_css.rb +200 -0
- data/lib/sass/tree/warn_node.rb +4 -28
- data/lib/sass/tree/while_node.rb +5 -23
- metadata +19 -14
@@ -0,0 +1,64 @@
|
|
1
|
+
# Visitors are used to traverse the Sass parse tree.
|
2
|
+
# Visitors should extend {Visitors::Base},
|
3
|
+
# which provides a small amount of scaffolding for traversal.
|
4
|
+
module Sass::Tree::Visitors
|
5
|
+
# The abstract base class for Sass visitors.
|
6
|
+
# Visitors should extend this class,
|
7
|
+
# then implement `visit_*` methods for each node they care about
|
8
|
+
# (e.g. `visit_rule` for {RuleNode} or `visit_for` for {FileNode}).
|
9
|
+
# These methods take the node in question as argument.
|
10
|
+
# They may `yield` to visit the child nodes of the current node.
|
11
|
+
#
|
12
|
+
# *Note*: due to the unusual nature of {Sass::Tree::IfNode},
|
13
|
+
# special care must be taken to ensure that it is properly handled.
|
14
|
+
# In particular, there is no built-in scaffolding
|
15
|
+
# for dealing with the return value of `@else` nodes.
|
16
|
+
#
|
17
|
+
# @abstract
|
18
|
+
class Base
|
19
|
+
# Runs the visitor on a tree.
|
20
|
+
#
|
21
|
+
# @param root [Tree::Node] The root node of the Sass tree.
|
22
|
+
# @return [Object] The return value of \{#visit} for the root node.
|
23
|
+
def self.visit(root)
|
24
|
+
new.send(:visit, root)
|
25
|
+
end
|
26
|
+
|
27
|
+
protected
|
28
|
+
|
29
|
+
# Runs the visitor on the given node.
|
30
|
+
# This can be overridden by subclasses that need to do something for each node.
|
31
|
+
#
|
32
|
+
# @param node [Tree::Node] The node to visit.
|
33
|
+
# @return [Object] The return value of the `visit_*` method for this node.
|
34
|
+
def visit(node)
|
35
|
+
method = "visit_#{node.class.name.gsub(/.*::(.*?)Node$/, '\\1').downcase}"
|
36
|
+
if self.respond_to?(method)
|
37
|
+
self.send(method, node) {visit_children(node)}
|
38
|
+
else
|
39
|
+
visit_children(node)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Visit the child nodes for a given node.
|
44
|
+
# This can be overridden by subclasses that need to do something
|
45
|
+
# with the child nodes' return values.
|
46
|
+
#
|
47
|
+
# This method is run when `visit_*` methods `yield`,
|
48
|
+
# and its return value is returned from the `yield`.
|
49
|
+
#
|
50
|
+
# @param parent [Tree::Node] The parent node of the children to visit.
|
51
|
+
# @return [Array<Object>] The return values of the `visit_*` methods for the children.
|
52
|
+
def visit_children(parent)
|
53
|
+
parent.children.map {|c| visit(c)}
|
54
|
+
end
|
55
|
+
|
56
|
+
# `yield`s, then runs the visitor on the `@else` clause if the node has one.
|
57
|
+
# This exists to ensure that the contents of the `@else` clause get visited.
|
58
|
+
def visit_if(node)
|
59
|
+
yield
|
60
|
+
visit(node.else) if node.else
|
61
|
+
node
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,234 @@
|
|
1
|
+
# A visitor for converting a Sass tree into a source string.
|
2
|
+
class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base
|
3
|
+
# Runs the visitor on a tree.
|
4
|
+
#
|
5
|
+
# @param root [Tree::Node] The root node of the Sass tree.
|
6
|
+
# @param options [{Symbol => Object}] An options hash (see {Sass::CSS#initialize}).
|
7
|
+
# @param format [Symbol] `:sass` or `:scss`.
|
8
|
+
# @return [String] The Sass or SCSS source for the tree.
|
9
|
+
def self.visit(root, options, format)
|
10
|
+
new(options, format).send(:visit, root)
|
11
|
+
end
|
12
|
+
|
13
|
+
protected
|
14
|
+
|
15
|
+
def initialize(options, format)
|
16
|
+
@options = options
|
17
|
+
@format = format
|
18
|
+
@tabs = 0
|
19
|
+
end
|
20
|
+
|
21
|
+
def visit_children(parent)
|
22
|
+
@tabs += 1
|
23
|
+
return @format == :sass ? "\n" : " {}\n" if parent.children.empty?
|
24
|
+
(@format == :sass ? "\n" : " {\n") + super.join.rstrip + (@format == :sass ? "\n" : " }\n")
|
25
|
+
ensure
|
26
|
+
@tabs -= 1
|
27
|
+
end
|
28
|
+
|
29
|
+
# Ensures proper spacing between top-level nodes.
|
30
|
+
def visit_root(node)
|
31
|
+
Sass::Util.enum_cons(node.children + [nil], 2).map do |child, nxt|
|
32
|
+
visit(child) +
|
33
|
+
if nxt &&
|
34
|
+
(child.is_a?(Sass::Tree::CommentNode) &&
|
35
|
+
child.line + child.value.count("\n") + 1 == nxt.line) ||
|
36
|
+
(child.is_a?(Sass::Tree::ImportNode) && nxt.is_a?(Sass::Tree::ImportNode) &&
|
37
|
+
child.line + 1 == nxt.line) ||
|
38
|
+
(child.is_a?(Sass::Tree::VariableNode) && nxt.is_a?(Sass::Tree::VariableNode) &&
|
39
|
+
child.line + 1 == nxt.line)
|
40
|
+
""
|
41
|
+
else
|
42
|
+
"\n"
|
43
|
+
end
|
44
|
+
end.join.rstrip + "\n"
|
45
|
+
end
|
46
|
+
|
47
|
+
def visit_charset(node)
|
48
|
+
"#{tab_str}@charset \"#{node.name}\"#{semi}\n"
|
49
|
+
end
|
50
|
+
|
51
|
+
def visit_comment(node)
|
52
|
+
if @format == :sass
|
53
|
+
content = node.value.gsub(/\*\/$/, '').rstrip
|
54
|
+
if content =~ /\A[ \t]/
|
55
|
+
# Re-indent SCSS comments like this:
|
56
|
+
# /* foo
|
57
|
+
# bar
|
58
|
+
# baz */
|
59
|
+
content.gsub!(/^/, ' ')
|
60
|
+
content.sub!(/\A([ \t]*)\/\*/, '/*\1')
|
61
|
+
end
|
62
|
+
|
63
|
+
content =
|
64
|
+
unless content.include?("\n")
|
65
|
+
content
|
66
|
+
else
|
67
|
+
content.gsub!(/\n( \*|\/\/)/, "\n ")
|
68
|
+
spaces = content.scan(/\n( *)/).map {|s| s.first.size}.min
|
69
|
+
sep = node.silent ? "\n//" : "\n *"
|
70
|
+
if spaces >= 2
|
71
|
+
content.gsub(/\n /, sep)
|
72
|
+
else
|
73
|
+
content.gsub(/\n#{' ' * spaces}/, sep)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
content.gsub!(/\A\/\*/, '//') if node.silent
|
78
|
+
content.gsub!(/^/, tab_str)
|
79
|
+
content.rstrip + "\n"
|
80
|
+
else
|
81
|
+
spaces = (' ' * [@tabs - node.value[/^ */].size, 0].max)
|
82
|
+
if node.silent
|
83
|
+
node.value.gsub(/^[\/ ]\*/, '//').gsub(/ *\*\/$/, '')
|
84
|
+
else
|
85
|
+
node.value
|
86
|
+
end.gsub(/^/, spaces) + "\n"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def visit_debug(node)
|
91
|
+
"#{tab_str}@debug #{node.expr.to_sass(@options)}#{semi}\n"
|
92
|
+
end
|
93
|
+
|
94
|
+
def visit_directive(node)
|
95
|
+
res = "#{tab_str}#{node.value}"
|
96
|
+
return res + "#{semi}\n" unless node.has_children
|
97
|
+
res + yield + "\n"
|
98
|
+
end
|
99
|
+
|
100
|
+
def visit_each(node)
|
101
|
+
"#{tab_str}@each $#{dasherize(node.var)} in #{node.list.to_sass(@options)}#{yield}"
|
102
|
+
end
|
103
|
+
|
104
|
+
def visit_extend(node)
|
105
|
+
"#{tab_str}@extend #{selector_to_src(node.selector).lstrip}#{semi}\n"
|
106
|
+
end
|
107
|
+
|
108
|
+
def visit_for(node)
|
109
|
+
"#{tab_str}@for $#{dasherize(node.var)} from #{node.from.to_sass(@options)} " +
|
110
|
+
"#{node.exclusive ? "to" : "through"} #{node.to.to_sass(@options)}#{yield}"
|
111
|
+
end
|
112
|
+
|
113
|
+
def visit_if(node)
|
114
|
+
name =
|
115
|
+
if !@is_else; "if"
|
116
|
+
elsif node.expr; "else if"
|
117
|
+
else; "else"
|
118
|
+
end
|
119
|
+
str = "#{tab_str}@#{name}"
|
120
|
+
str << " #{node.expr.to_sass(@options)}" if node.expr
|
121
|
+
str << yield
|
122
|
+
@is_else = true
|
123
|
+
str << visit(node.else) if node.else
|
124
|
+
str
|
125
|
+
ensure
|
126
|
+
@is_else = false
|
127
|
+
end
|
128
|
+
|
129
|
+
def visit_import(node)
|
130
|
+
quote = @format == :scss ? '"' : ''
|
131
|
+
"#{tab_str}@import #{quote}#{node.imported_filename}#{quote}#{semi}\n"
|
132
|
+
end
|
133
|
+
|
134
|
+
def visit_media(node)
|
135
|
+
"#{tab_str}@media #{node.query}#{yield}"
|
136
|
+
end
|
137
|
+
|
138
|
+
def visit_mixindef(node)
|
139
|
+
args =
|
140
|
+
if node.args.empty?
|
141
|
+
""
|
142
|
+
else
|
143
|
+
'(' + node.args.map do |v, d|
|
144
|
+
if d
|
145
|
+
"#{v.to_sass(@options)}: #{d.to_sass(@options)}"
|
146
|
+
else
|
147
|
+
v.to_sass(@options)
|
148
|
+
end
|
149
|
+
end.join(", ") + ')'
|
150
|
+
end
|
151
|
+
|
152
|
+
"#{tab_str}#{@format == :sass ? '=' : '@mixin '}#{dasherize(node.name)}#{args}#{yield}"
|
153
|
+
end
|
154
|
+
|
155
|
+
def visit_mixin(node)
|
156
|
+
unless node.args.empty? && node.keywords.empty?
|
157
|
+
args = node.args.map {|a| a.to_sass(@options)}.join(", ")
|
158
|
+
keywords = node.keywords.map {|k, v| "$#{dasherize(k)}: #{v.to_sass(@options)}"}.join(', ')
|
159
|
+
arglist = "(#{args}#{', ' unless args.empty? || keywords.empty?}#{keywords})"
|
160
|
+
end
|
161
|
+
"#{tab_str}#{@format == :sass ? '+' : '@include '}#{dasherize(node.name)}#{arglist}#{semi}\n"
|
162
|
+
end
|
163
|
+
|
164
|
+
def visit_prop(node)
|
165
|
+
res = tab_str + node.declaration(@options, @format)
|
166
|
+
return res + semi + "\n" if node.children.empty?
|
167
|
+
res + yield.rstrip + semi + "\n"
|
168
|
+
end
|
169
|
+
|
170
|
+
def visit_rule(node)
|
171
|
+
if @format == :sass
|
172
|
+
name = selector_to_sass(node.rule)
|
173
|
+
name = "\\" + name if name[0] == ?:
|
174
|
+
name.gsub(/^/, tab_str) + yield
|
175
|
+
elsif @format == :scss
|
176
|
+
name = selector_to_scss(node.rule)
|
177
|
+
res = name + yield
|
178
|
+
if node.children.last.is_a?(Sass::Tree::CommentNode) && node.children.last.silent
|
179
|
+
res.slice!(-3..-1)
|
180
|
+
res << "\n" << tab_str << "}\n"
|
181
|
+
end
|
182
|
+
res
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def visit_variable(node)
|
187
|
+
"#{tab_str}$#{dasherize(node.name)}: #{node.expr.to_sass(@options)}#{' !default' if node.guarded}#{semi}\n"
|
188
|
+
end
|
189
|
+
|
190
|
+
def visit_warn(node)
|
191
|
+
"#{tab_str}@warn #{node.expr.to_sass(@options)}#{semi}\n"
|
192
|
+
end
|
193
|
+
|
194
|
+
def visit_while(node)
|
195
|
+
"#{tab_str}@while #{node.expr.to_sass(@options)}#{yield}"
|
196
|
+
end
|
197
|
+
|
198
|
+
private
|
199
|
+
|
200
|
+
def selector_to_src(sel)
|
201
|
+
@format == :sass ? selector_to_sass(sel) : selector_to_scss(sel)
|
202
|
+
end
|
203
|
+
|
204
|
+
def selector_to_sass(sel)
|
205
|
+
sel.map do |r|
|
206
|
+
if r.is_a?(String)
|
207
|
+
r.gsub(/(,[ \t]*)?\n\s*/) {$1 ? $1 + "\n" : " "}
|
208
|
+
else
|
209
|
+
"\#{#{r.to_sass(@options)}}"
|
210
|
+
end
|
211
|
+
end.join
|
212
|
+
end
|
213
|
+
|
214
|
+
def selector_to_scss(sel)
|
215
|
+
sel.map {|r| r.is_a?(String) ? r : "\#{#{r.to_sass(@options)}}"}.
|
216
|
+
join.gsub(/^[ \t]*/, tab_str)
|
217
|
+
end
|
218
|
+
|
219
|
+
def semi
|
220
|
+
@format == :sass ? "" : ";"
|
221
|
+
end
|
222
|
+
|
223
|
+
def tab_str
|
224
|
+
' ' * @tabs
|
225
|
+
end
|
226
|
+
|
227
|
+
def dasherize(s)
|
228
|
+
if @options[:dasherize]
|
229
|
+
s.gsub('_', '-')
|
230
|
+
else
|
231
|
+
s
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
@@ -0,0 +1,177 @@
|
|
1
|
+
# A visitor for converting a static Sass tree into a static CSS tree.
|
2
|
+
class Sass::Tree::Visitors::Cssize < Sass::Tree::Visitors::Base
|
3
|
+
# @param root [Tree::Node] The root node of the tree to visit.
|
4
|
+
# @return [(Tree::Node, Sass::Util::SubsetMap)] The resulting tree of static nodes
|
5
|
+
# *and* the extensions defined for this tree
|
6
|
+
def self.visit(root); super; end
|
7
|
+
|
8
|
+
protected
|
9
|
+
|
10
|
+
# Returns the immediate parent of the current node.
|
11
|
+
# @return [Tree::Node]
|
12
|
+
attr_reader :parent
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@extends = Sass::Util::SubsetMap.new
|
16
|
+
end
|
17
|
+
|
18
|
+
# If an exception is raised, this adds proper metadata to the backtrace.
|
19
|
+
def visit(node)
|
20
|
+
super(node.dup)
|
21
|
+
rescue Sass::SyntaxError => e
|
22
|
+
e.modify_backtrace(:filename => node.filename, :line => node.line)
|
23
|
+
raise e
|
24
|
+
end
|
25
|
+
|
26
|
+
# Keeps track of the current parent node.
|
27
|
+
def visit_children(parent)
|
28
|
+
with_parent parent do
|
29
|
+
parent.children = super.flatten
|
30
|
+
parent
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Runs a block of code with the current parent node
|
35
|
+
# replaced with the given node.
|
36
|
+
#
|
37
|
+
# @param parent [Tree::Node] The new parent for the duration of the block.
|
38
|
+
# @yield A block in which the parent is set to `parent`.
|
39
|
+
# @return [Object] The return value of the block.
|
40
|
+
def with_parent(parent)
|
41
|
+
old_parent, @parent = @parent, parent
|
42
|
+
yield
|
43
|
+
ensure
|
44
|
+
@parent = old_parent
|
45
|
+
end
|
46
|
+
|
47
|
+
# In Ruby 1.8, ensures that there's only one `@charset` directive
|
48
|
+
# and that it's at the top of the document.
|
49
|
+
#
|
50
|
+
# @return [(Tree::Node, Sass::Util::SubsetMap)] The resulting tree of static nodes
|
51
|
+
# *and* the extensions defined for this tree
|
52
|
+
def visit_root(node)
|
53
|
+
yield
|
54
|
+
|
55
|
+
# In Ruby 1.9 we can make all @charset nodes invisible
|
56
|
+
# and infer the final @charset from the encoding of the final string.
|
57
|
+
if Sass::Util.ruby1_8? && parent.nil?
|
58
|
+
charset = node.children.find {|c| c.is_a?(Sass::Tree::CharsetNode)}
|
59
|
+
node.children.reject! {|c| c.is_a?(Sass::Tree::CharsetNode)}
|
60
|
+
node.children.unshift charset if charset
|
61
|
+
end
|
62
|
+
|
63
|
+
return node, @extends
|
64
|
+
rescue Sass::SyntaxError => e
|
65
|
+
e.sass_template ||= node.template
|
66
|
+
raise e
|
67
|
+
end
|
68
|
+
|
69
|
+
# Registers an extension in the `@extends` subset map.
|
70
|
+
def visit_extend(node)
|
71
|
+
node.resolved_selector.members.each do |seq|
|
72
|
+
if seq.members.size > 1
|
73
|
+
raise Sass::SyntaxError.new("Can't extend #{seq.to_a.join}: can't extend nested selectors")
|
74
|
+
end
|
75
|
+
|
76
|
+
sseq = seq.members.first
|
77
|
+
if !sseq.is_a?(Sass::Selector::SimpleSequence)
|
78
|
+
raise Sass::SyntaxError.new("Can't extend #{seq.to_a.join}: invalid selector")
|
79
|
+
end
|
80
|
+
|
81
|
+
sel = sseq.members
|
82
|
+
parent.resolved_rules.members.each do |seq|
|
83
|
+
if !seq.members.last.is_a?(Sass::Selector::SimpleSequence)
|
84
|
+
raise Sass::SyntaxError.new("#{seq} can't extend: invalid selector")
|
85
|
+
end
|
86
|
+
|
87
|
+
@extends[sel] = seq
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
[]
|
92
|
+
end
|
93
|
+
|
94
|
+
# Modifies exception backtraces to include the imported file.
|
95
|
+
def visit_import(node)
|
96
|
+
yield
|
97
|
+
node.children
|
98
|
+
rescue Sass::SyntaxError => e
|
99
|
+
e.modify_backtrace(:filename => node.children.first.filename)
|
100
|
+
e.add_backtrace(:filename => node.filename, :line => node.line)
|
101
|
+
raise e
|
102
|
+
end
|
103
|
+
|
104
|
+
# Bubbles the `@media` directive up through RuleNodes
|
105
|
+
# and merges it with other `@media` directives.
|
106
|
+
def visit_media(node)
|
107
|
+
if parent.is_a?(Sass::Tree::RuleNode)
|
108
|
+
new_rule = parent.dup
|
109
|
+
new_rule.children = node.children
|
110
|
+
node.children = with_parent(node) {Array(visit(new_rule))}
|
111
|
+
# If the last child is actually the end of the group,
|
112
|
+
# the parent's cssize will set it properly
|
113
|
+
node.children.last.group_end = false unless node.children.empty?
|
114
|
+
else
|
115
|
+
yield
|
116
|
+
end
|
117
|
+
|
118
|
+
media = node.children.select {|c| c.is_a?(Sass::Tree::MediaNode)}
|
119
|
+
node.children.reject! {|c| c.is_a?(Sass::Tree::MediaNode)}
|
120
|
+
media.each {|n| n.query = "#{node.query} and #{n.query}"}
|
121
|
+
(node.children.empty? ? [] : [node]) + media
|
122
|
+
end
|
123
|
+
|
124
|
+
# Asserts that all the mixin's children are valid in their new location.
|
125
|
+
def visit_mixin(node)
|
126
|
+
node.children.map do |c|
|
127
|
+
parent.check_child! c
|
128
|
+
# Don't use #visit_children to avoid adding the mixin node to the list of parents.
|
129
|
+
visit(c)
|
130
|
+
end.flatten
|
131
|
+
rescue Sass::SyntaxError => e
|
132
|
+
e.modify_backtrace(:mixin => node.name, :filename => node.filename, :line => node.line)
|
133
|
+
e.add_backtrace(:filename => node.filename, :line => node.line)
|
134
|
+
raise e
|
135
|
+
end
|
136
|
+
|
137
|
+
# Converts nested properties into flat properties
|
138
|
+
# and updates the indentation of the prop node based on the nesting level.
|
139
|
+
def visit_prop(node)
|
140
|
+
if parent.is_a?(Sass::Tree::PropNode)
|
141
|
+
node.resolved_name = "#{parent.resolved_name}-#{node.resolved_name}"
|
142
|
+
node.tabs = parent.tabs + (parent.resolved_value.empty? ? 0 : 1) if node.style == :nested
|
143
|
+
end
|
144
|
+
|
145
|
+
yield
|
146
|
+
|
147
|
+
if !node.resolved_value.empty? || node.children.empty?
|
148
|
+
node.send(:check!)
|
149
|
+
node.children.unshift(node)
|
150
|
+
end
|
151
|
+
|
152
|
+
node.children
|
153
|
+
end
|
154
|
+
|
155
|
+
# Resolves parent references and nested selectors,
|
156
|
+
# and updates the indentation of the rule node based on the nesting level.
|
157
|
+
def visit_rule(node)
|
158
|
+
parent_resolved_rules = parent.is_a?(Sass::Tree::RuleNode) ? parent.resolved_rules : nil
|
159
|
+
# It's possible for resolved_rules to be set if we've duplicated this node during @media bubbling
|
160
|
+
node.resolved_rules ||= node.parsed_rules.resolve_parent_refs(parent_resolved_rules)
|
161
|
+
|
162
|
+
yield
|
163
|
+
|
164
|
+
rules = node.children.select {|c| c.is_a?(Sass::Tree::RuleNode) || c.is_a?(Sass::Tree::MediaNode)}
|
165
|
+
props = node.children.reject {|c| c.is_a?(Sass::Tree::RuleNode) || c.is_a?(Sass::Tree::MediaNode) || c.invisible?}
|
166
|
+
|
167
|
+
unless props.empty?
|
168
|
+
node.children = props
|
169
|
+
rules.each {|r| r.tabs += 1} if node.style == :nested
|
170
|
+
rules.unshift(node)
|
171
|
+
end
|
172
|
+
|
173
|
+
rules.last.group_end = true unless parent.is_a?(Sass::Tree::RuleNode) || rules.empty?
|
174
|
+
|
175
|
+
rules
|
176
|
+
end
|
177
|
+
end
|