oreorenasass 3.4.4 → 3.4.5
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 +4 -4
- data/MIT-LICENSE +1 -1
- data/README.md +50 -70
- data/Rakefile +5 -26
- data/VERSION +1 -1
- data/VERSION_NAME +1 -1
- data/bin/sass +1 -1
- data/bin/scss +1 -1
- data/lib/sass.rb +12 -19
- data/lib/sass/cache_stores/base.rb +2 -2
- data/lib/sass/cache_stores/chain.rb +1 -2
- data/lib/sass/cache_stores/filesystem.rb +5 -1
- data/lib/sass/cache_stores/memory.rb +1 -1
- data/lib/sass/cache_stores/null.rb +2 -2
- data/lib/sass/callbacks.rb +0 -1
- data/lib/sass/css.rb +13 -11
- data/lib/sass/engine.rb +173 -424
- data/lib/sass/environment.rb +58 -148
- data/lib/sass/error.rb +14 -11
- data/lib/sass/exec.rb +703 -5
- data/lib/sass/importers/base.rb +6 -49
- data/lib/sass/importers/filesystem.rb +19 -44
- data/lib/sass/logger.rb +4 -1
- data/lib/sass/logger/base.rb +4 -2
- data/lib/sass/logger/log_level.rb +7 -3
- data/lib/sass/media.rb +23 -20
- data/lib/sass/plugin.rb +7 -7
- data/lib/sass/plugin/compiler.rb +145 -304
- data/lib/sass/plugin/configuration.rb +23 -18
- data/lib/sass/plugin/merb.rb +1 -1
- data/lib/sass/plugin/staleness_checker.rb +3 -3
- data/lib/sass/repl.rb +3 -3
- data/lib/sass/script.rb +8 -35
- data/lib/sass/script/{value/arg_list.rb → arg_list.rb} +25 -9
- data/lib/sass/script/bool.rb +18 -0
- data/lib/sass/script/color.rb +606 -0
- data/lib/sass/script/css_lexer.rb +4 -8
- data/lib/sass/script/css_parser.rb +2 -5
- data/lib/sass/script/funcall.rb +245 -0
- data/lib/sass/script/functions.rb +408 -1491
- data/lib/sass/script/interpolation.rb +79 -0
- data/lib/sass/script/lexer.rb +68 -172
- data/lib/sass/script/list.rb +85 -0
- data/lib/sass/script/literal.rb +221 -0
- data/lib/sass/script/{tree/node.rb → node.rb} +12 -22
- data/lib/sass/script/{value/null.rb → null.rb} +7 -14
- data/lib/sass/script/{value/number.rb → number.rb} +75 -152
- data/lib/sass/script/{tree/operation.rb → operation.rb} +24 -17
- data/lib/sass/script/parser.rb +110 -245
- data/lib/sass/script/string.rb +51 -0
- data/lib/sass/script/{tree/string_interpolation.rb → string_interpolation.rb} +4 -5
- data/lib/sass/script/{tree/unary_operation.rb → unary_operation.rb} +6 -6
- data/lib/sass/script/variable.rb +58 -0
- data/lib/sass/scss/css_parser.rb +3 -9
- data/lib/sass/scss/parser.rb +421 -450
- data/lib/sass/scss/rx.rb +11 -19
- data/lib/sass/scss/static_parser.rb +7 -321
- data/lib/sass/selector.rb +194 -68
- data/lib/sass/selector/abstract_sequence.rb +14 -29
- data/lib/sass/selector/comma_sequence.rb +25 -108
- data/lib/sass/selector/sequence.rb +66 -159
- data/lib/sass/selector/simple.rb +25 -23
- data/lib/sass/selector/simple_sequence.rb +63 -173
- data/lib/sass/shared.rb +1 -1
- data/lib/sass/supports.rb +15 -13
- data/lib/sass/tree/charset_node.rb +1 -1
- data/lib/sass/tree/comment_node.rb +3 -3
- data/lib/sass/tree/css_import_node.rb +11 -11
- data/lib/sass/tree/debug_node.rb +2 -2
- data/lib/sass/tree/directive_node.rb +4 -21
- data/lib/sass/tree/each_node.rb +8 -8
- data/lib/sass/tree/extend_node.rb +7 -14
- data/lib/sass/tree/for_node.rb +4 -4
- data/lib/sass/tree/function_node.rb +4 -9
- data/lib/sass/tree/if_node.rb +1 -1
- data/lib/sass/tree/import_node.rb +5 -4
- data/lib/sass/tree/media_node.rb +14 -4
- data/lib/sass/tree/mixin_def_node.rb +4 -4
- data/lib/sass/tree/mixin_node.rb +8 -21
- data/lib/sass/tree/node.rb +12 -54
- data/lib/sass/tree/prop_node.rb +20 -39
- data/lib/sass/tree/return_node.rb +2 -3
- data/lib/sass/tree/root_node.rb +3 -19
- data/lib/sass/tree/rule_node.rb +22 -35
- data/lib/sass/tree/supports_node.rb +13 -0
- data/lib/sass/tree/trace_node.rb +1 -2
- data/lib/sass/tree/variable_node.rb +3 -9
- data/lib/sass/tree/visitors/base.rb +8 -5
- data/lib/sass/tree/visitors/check_nesting.rb +19 -49
- data/lib/sass/tree/visitors/convert.rb +56 -74
- data/lib/sass/tree/visitors/cssize.rb +74 -202
- data/lib/sass/tree/visitors/deep_copy.rb +5 -10
- data/lib/sass/tree/visitors/extend.rb +7 -7
- data/lib/sass/tree/visitors/perform.rb +185 -278
- data/lib/sass/tree/visitors/set_options.rb +6 -20
- data/lib/sass/tree/visitors/to_css.rb +81 -234
- data/lib/sass/tree/warn_node.rb +2 -2
- data/lib/sass/tree/while_node.rb +2 -2
- data/lib/sass/util.rb +152 -522
- data/lib/sass/util/multibyte_string_scanner.rb +0 -2
- data/lib/sass/util/subset_map.rb +3 -4
- data/lib/sass/util/test.rb +1 -0
- data/lib/sass/version.rb +22 -20
- data/test/Gemfile +3 -0
- data/test/Gemfile.lock +10 -0
- data/test/sass/cache_test.rb +20 -62
- data/test/sass/callbacks_test.rb +1 -1
- data/test/sass/conversion_test.rb +2 -296
- data/test/sass/css2sass_test.rb +4 -23
- data/test/sass/engine_test.rb +354 -411
- data/test/sass/exec_test.rb +2 -2
- data/test/sass/extend_test.rb +145 -324
- data/test/sass/functions_test.rb +86 -873
- data/test/sass/importer_test.rb +21 -241
- data/test/sass/logger_test.rb +1 -1
- data/test/sass/more_results/more_import.css +1 -1
- data/test/sass/plugin_test.rb +26 -16
- 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 +3 -3
- data/test/sass/results/scss_import.css +1 -1
- data/test/sass/script_conversion_test.rb +7 -36
- data/test/sass/script_test.rb +53 -485
- data/test/sass/scss/css_test.rb +28 -143
- data/test/sass/scss/rx_test.rb +4 -4
- data/test/sass/scss/scss_test.rb +325 -2119
- data/test/sass/templates/scss_import.scss +1 -2
- data/test/sass/test_helper.rb +1 -1
- data/test/sass/util/multibyte_string_scanner_test.rb +1 -1
- data/test/sass/util/subset_map_test.rb +2 -2
- data/test/sass/util_test.rb +1 -86
- data/test/test_helper.rb +8 -37
- metadata +19 -66
- data/lib/sass/exec/base.rb +0 -187
- data/lib/sass/exec/sass_convert.rb +0 -264
- data/lib/sass/exec/sass_scss.rb +0 -424
- data/lib/sass/features.rb +0 -47
- data/lib/sass/script/tree.rb +0 -16
- data/lib/sass/script/tree/funcall.rb +0 -306
- data/lib/sass/script/tree/interpolation.rb +0 -118
- data/lib/sass/script/tree/list_literal.rb +0 -77
- data/lib/sass/script/tree/literal.rb +0 -45
- data/lib/sass/script/tree/map_literal.rb +0 -64
- data/lib/sass/script/tree/selector.rb +0 -26
- data/lib/sass/script/tree/variable.rb +0 -57
- data/lib/sass/script/value.rb +0 -11
- data/lib/sass/script/value/base.rb +0 -240
- data/lib/sass/script/value/bool.rb +0 -35
- data/lib/sass/script/value/color.rb +0 -680
- data/lib/sass/script/value/helpers.rb +0 -262
- data/lib/sass/script/value/list.rb +0 -113
- data/lib/sass/script/value/map.rb +0 -70
- data/lib/sass/script/value/string.rb +0 -97
- data/lib/sass/selector/pseudo.rb +0 -256
- data/lib/sass/source/map.rb +0 -210
- data/lib/sass/source/position.rb +0 -39
- data/lib/sass/source/range.rb +0 -41
- data/lib/sass/stack.rb +0 -120
- data/lib/sass/tree/at_root_node.rb +0 -83
- data/lib/sass/tree/error_node.rb +0 -18
- data/lib/sass/tree/keyframe_rule_node.rb +0 -15
- data/lib/sass/util/cross_platform_random.rb +0 -19
- data/lib/sass/util/normalized_map.rb +0 -130
- data/lib/sass/util/ordered_hash.rb +0 -192
- data/test/sass/compiler_test.rb +0 -232
- data/test/sass/encoding_test.rb +0 -219
- data/test/sass/source_map_test.rb +0 -977
- data/test/sass/superselector_test.rb +0 -191
- data/test/sass/util/normalized_map_test.rb +0 -51
- data/test/sass/value_helpers_test.rb +0 -179
@@ -23,11 +23,7 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base
|
|
23
23
|
def visit_children(parent)
|
24
24
|
@tabs += 1
|
25
25
|
return @format == :sass ? "\n" : " {}\n" if parent.children.empty?
|
26
|
-
|
27
|
-
"\n" + super.join.rstrip + "\n"
|
28
|
-
else
|
29
|
-
" {\n" + super.join.rstrip + "\n#{ @tab_chars * (@tabs - 1)}}\n"
|
30
|
-
end
|
26
|
+
(@format == :sass ? "\n" : " {\n") + super.join.rstrip + (@format == :sass ? "\n" : "\n#{ @tab_chars * (@tabs-1)}}\n")
|
31
27
|
ensure
|
32
28
|
@tabs -= 1
|
33
29
|
end
|
@@ -56,7 +52,7 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base
|
|
56
52
|
|
57
53
|
def visit_comment(node)
|
58
54
|
value = interp_to_src(node.value)
|
59
|
-
if @format == :sass
|
55
|
+
content = if @format == :sass
|
60
56
|
content = value.gsub(/\*\/$/, '').rstrip
|
61
57
|
if content =~ /\A[ \t]/
|
62
58
|
# Re-indent SCSS comments like this:
|
@@ -67,27 +63,31 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base
|
|
67
63
|
content.sub!(/\A([ \t]*)\/\*/, '/*\1')
|
68
64
|
end
|
69
65
|
|
70
|
-
|
71
|
-
content.
|
72
|
-
|
73
|
-
sep = node.type == :silent ? "\n//" : "\n *"
|
74
|
-
if spaces >= 2
|
75
|
-
content.gsub!(/\n /, sep)
|
66
|
+
content =
|
67
|
+
unless content.include?("\n")
|
68
|
+
content
|
76
69
|
else
|
77
|
-
content.gsub!(/\n
|
70
|
+
content.gsub!(/\n( \*|\/\/)/, "\n ")
|
71
|
+
spaces = content.scan(/\n( *)/).map {|s| s.first.size}.min
|
72
|
+
sep = node.type == :silent ? "\n//" : "\n *"
|
73
|
+
if spaces >= 2
|
74
|
+
content.gsub(/\n /, sep)
|
75
|
+
else
|
76
|
+
content.gsub(/\n#{' ' * spaces}/, sep)
|
77
|
+
end
|
78
78
|
end
|
79
|
-
end
|
80
79
|
|
81
80
|
content.gsub!(/\A\/\*/, '//') if node.type == :silent
|
82
81
|
content.gsub!(/^/, tab_str)
|
83
|
-
content
|
82
|
+
content.rstrip + "\n"
|
84
83
|
else
|
85
84
|
spaces = (@tab_chars * [@tabs - value[/^ */].size, 0].max)
|
86
85
|
content = if node.type == :silent
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
86
|
+
value.gsub(/^[\/ ]\*/, '//').gsub(/ *\*\/$/, '')
|
87
|
+
else
|
88
|
+
value
|
89
|
+
end.gsub(/^/, spaces) + "\n"
|
90
|
+
content
|
91
91
|
end
|
92
92
|
content
|
93
93
|
end
|
@@ -96,25 +96,19 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base
|
|
96
96
|
"#{tab_str}@debug #{node.expr.to_sass(@options)}#{semi}\n"
|
97
97
|
end
|
98
98
|
|
99
|
-
def visit_error(node)
|
100
|
-
"#{tab_str}@error #{node.expr.to_sass(@options)}#{semi}\n"
|
101
|
-
end
|
102
|
-
|
103
99
|
def visit_directive(node)
|
104
100
|
res = "#{tab_str}#{interp_to_src(node.value)}"
|
105
|
-
res.gsub!(/^@import \#\{(.*)\}([^}]*)$/, '@import \1\2')
|
101
|
+
res.gsub!(/^@import \#\{(.*)\}([^}]*)$/, '@import \1\2');
|
106
102
|
return res + "#{semi}\n" unless node.has_children
|
107
103
|
res + yield + "\n"
|
108
104
|
end
|
109
105
|
|
110
106
|
def visit_each(node)
|
111
|
-
|
112
|
-
"#{tab_str}@each #{vars} in #{node.list.to_sass(@options)}#{yield}"
|
107
|
+
"#{tab_str}@each $#{dasherize(node.var)} in #{node.list.to_sass(@options)}#{yield}"
|
113
108
|
end
|
114
109
|
|
115
110
|
def visit_extend(node)
|
116
|
-
"#{tab_str}@extend #{selector_to_src(node.selector).lstrip}#{semi}"
|
117
|
-
"#{" !optional" if node.optional?}\n"
|
111
|
+
"#{tab_str}@extend #{selector_to_src(node.selector).lstrip}#{semi}#{" !optional" if node.optional?}\n"
|
118
112
|
end
|
119
113
|
|
120
114
|
def visit_for(node)
|
@@ -136,12 +130,9 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base
|
|
136
130
|
|
137
131
|
def visit_if(node)
|
138
132
|
name =
|
139
|
-
if !@is_else
|
140
|
-
|
141
|
-
|
142
|
-
"else if"
|
143
|
-
else
|
144
|
-
"else"
|
133
|
+
if !@is_else; "if"
|
134
|
+
elsif node.expr; "else if"
|
135
|
+
else; "else"
|
145
136
|
end
|
146
137
|
@is_else = false
|
147
138
|
str = "#{tab_str}@#{name}"
|
@@ -160,7 +151,7 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base
|
|
160
151
|
end
|
161
152
|
|
162
153
|
def visit_media(node)
|
163
|
-
"#{tab_str}@media #{
|
154
|
+
"#{tab_str}@media #{media_interp_to_src(node.query)}#{yield}"
|
164
155
|
end
|
165
156
|
|
166
157
|
def visit_supports(node)
|
@@ -168,7 +159,7 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base
|
|
168
159
|
end
|
169
160
|
|
170
161
|
def visit_cssimport(node)
|
171
|
-
if node.uri.is_a?(Sass::Script::
|
162
|
+
if node.uri.is_a?(Sass::Script::Node)
|
172
163
|
str = "#{tab_str}@import #{node.uri.to_sass(@options)}"
|
173
164
|
else
|
174
165
|
str = "#{tab_str}@import #{node.uri}"
|
@@ -205,24 +196,21 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base
|
|
205
196
|
def visit_mixin(node)
|
206
197
|
arg_to_sass = lambda do |arg|
|
207
198
|
sass = arg.to_sass(@options)
|
208
|
-
sass = "(#{sass})" if arg.is_a?(Sass::Script::
|
199
|
+
sass = "(#{sass})" if arg.is_a?(Sass::Script::List) && arg.separator == :comma
|
209
200
|
sass
|
210
201
|
end
|
211
202
|
|
212
203
|
unless node.args.empty? && node.keywords.empty? && node.splat.nil?
|
213
|
-
args = node.args.map(&arg_to_sass)
|
214
|
-
keywords = Sass::Util.hash_to_a(node.keywords
|
215
|
-
map {|k, v| "$#{dasherize(k)}: #{arg_to_sass[v]}"}
|
216
|
-
|
204
|
+
args = node.args.map(&arg_to_sass).join(", ")
|
205
|
+
keywords = Sass::Util.hash_to_a(node.keywords).
|
206
|
+
map {|k, v| "$#{dasherize(k)}: #{arg_to_sass[v]}"}.join(', ')
|
217
207
|
if node.splat
|
218
|
-
splat =
|
219
|
-
|
208
|
+
splat = (args.empty? && keywords.empty?) ? "" : ", "
|
209
|
+
splat = "#{splat}#{arg_to_sass[node.splat]}..."
|
220
210
|
end
|
221
|
-
|
222
|
-
arglist = "(#{[args, splat, keywords, kwarg_splat].flatten.compact.join(', ')})"
|
211
|
+
arglist = "(#{args}#{', ' unless args.empty? || keywords.empty?}#{keywords}#{splat})"
|
223
212
|
end
|
224
|
-
"#{tab_str}#{@format == :sass ? '+' : '@include '}"
|
225
|
-
"#{dasherize(node.name)}#{arglist}#{node.has_children ? yield : semi}\n"
|
213
|
+
"#{tab_str}#{@format == :sass ? '+' : '@include '}#{dasherize(node.name)}#{arglist}#{node.has_children ? yield : semi}\n"
|
226
214
|
end
|
227
215
|
|
228
216
|
def visit_content(node)
|
@@ -240,13 +228,12 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base
|
|
240
228
|
end
|
241
229
|
|
242
230
|
def visit_rule(node)
|
243
|
-
rule = node.parsed_rules ? [node.parsed_rules.to_s] : node.rule
|
244
231
|
if @format == :sass
|
245
|
-
name = selector_to_sass(rule)
|
232
|
+
name = selector_to_sass(node.rule)
|
246
233
|
name = "\\" + name if name[0] == ?:
|
247
234
|
name.gsub(/^/, tab_str) + yield
|
248
235
|
elsif @format == :scss
|
249
|
-
name = selector_to_scss(rule)
|
236
|
+
name = selector_to_scss(node.rule)
|
250
237
|
res = name + yield
|
251
238
|
if node.children.last.is_a?(Sass::Tree::CommentNode) && node.children.last.type == :silent
|
252
239
|
res.slice!(-3..-1)
|
@@ -257,8 +244,7 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base
|
|
257
244
|
end
|
258
245
|
|
259
246
|
def visit_variable(node)
|
260
|
-
"#{tab_str}$#{dasherize(node.name)}: #{node.expr.to_sass(@options)}"
|
261
|
-
"#{' !global' if node.global}#{' !default' if node.guarded}#{semi}\n"
|
247
|
+
"#{tab_str}$#{dasherize(node.name)}: #{node.expr.to_sass(@options)}#{' !default' if node.guarded}#{semi}\n"
|
262
248
|
end
|
263
249
|
|
264
250
|
def visit_warn(node)
|
@@ -269,33 +255,29 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base
|
|
269
255
|
"#{tab_str}@while #{node.expr.to_sass(@options)}#{yield}"
|
270
256
|
end
|
271
257
|
|
272
|
-
def visit_atroot(node)
|
273
|
-
if node.query
|
274
|
-
"#{tab_str}@at-root #{query_interp_to_src(node.query)}#{yield}"
|
275
|
-
elsif node.children.length == 1 && node.children.first.is_a?(Sass::Tree::RuleNode)
|
276
|
-
rule = node.children.first
|
277
|
-
"#{tab_str}@at-root #{selector_to_src(rule.rule)}#{visit_children(rule)}"
|
278
|
-
else
|
279
|
-
"#{tab_str}@at-root#{yield}"
|
280
|
-
end
|
281
|
-
end
|
282
|
-
|
283
258
|
private
|
284
259
|
|
285
260
|
def interp_to_src(interp)
|
286
|
-
interp.map
|
261
|
+
interp.map do |r|
|
262
|
+
next r if r.is_a?(String)
|
263
|
+
"\#{#{r.to_sass(@options)}}"
|
264
|
+
end.join
|
287
265
|
end
|
288
266
|
|
289
267
|
# Like interp_to_src, but removes the unnecessary `#{}` around the keys and
|
290
|
-
# values in
|
291
|
-
def
|
292
|
-
interp
|
293
|
-
next
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
268
|
+
# values in media expressions.
|
269
|
+
def media_interp_to_src(interp)
|
270
|
+
Sass::Util.enum_with_index(interp).map do |r, i|
|
271
|
+
next r if r.is_a?(String)
|
272
|
+
before, after = interp[i-1], interp[i+1]
|
273
|
+
if before.is_a?(String) && after.is_a?(String) &&
|
274
|
+
((before[-1] == ?( && after[0] == ?:) ||
|
275
|
+
(before =~ /:\s*/ && after[0] == ?)))
|
276
|
+
r.to_sass(@options)
|
277
|
+
else
|
278
|
+
"\#{#{r.to_sass(@options)}}"
|
279
|
+
end
|
280
|
+
end.join
|
299
281
|
end
|
300
282
|
|
301
283
|
def selector_to_src(sel)
|
@@ -307,7 +289,7 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base
|
|
307
289
|
if r.is_a?(String)
|
308
290
|
r.gsub(/(,)?([ \t]*)\n\s*/) {$1 ? "#{$1}#{$2}\n" : " "}
|
309
291
|
else
|
310
|
-
r.to_sass(@options)
|
292
|
+
"\#{#{r.to_sass(@options)}}"
|
311
293
|
end
|
312
294
|
end.join
|
313
295
|
end
|
@@ -9,12 +9,10 @@ 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
|
-
|
13
|
-
@parents.last
|
14
|
-
end
|
12
|
+
attr_reader :parent
|
15
13
|
|
16
14
|
def initialize
|
17
|
-
@
|
15
|
+
@parent_directives = []
|
18
16
|
@extends = Sass::Util::SubsetMap.new
|
19
17
|
end
|
20
18
|
|
@@ -29,19 +27,12 @@ class Sass::Tree::Visitors::Cssize < Sass::Tree::Visitors::Base
|
|
29
27
|
# Keeps track of the current parent node.
|
30
28
|
def visit_children(parent)
|
31
29
|
with_parent parent do
|
32
|
-
parent.children =
|
30
|
+
parent.children = super.flatten
|
33
31
|
parent
|
34
32
|
end
|
35
33
|
end
|
36
34
|
|
37
|
-
|
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
|
35
|
+
MERGEABLE_DIRECTIVES = [Sass::Tree::MediaNode]
|
45
36
|
|
46
37
|
# Runs a block of code with the current parent node
|
47
38
|
# replaced with the given node.
|
@@ -50,10 +41,19 @@ class Sass::Tree::Visitors::Cssize < Sass::Tree::Visitors::Base
|
|
50
41
|
# @yield A block in which the parent is set to `parent`.
|
51
42
|
# @return [Object] The return value of the block.
|
52
43
|
def with_parent(parent)
|
53
|
-
|
44
|
+
if parent.is_a?(Sass::Tree::DirectiveNode)
|
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
|
54
52
|
yield
|
55
53
|
ensure
|
56
|
-
@
|
54
|
+
@parent_directives.pop if parent.is_a?(Sass::Tree::DirectiveNode)
|
55
|
+
@parent_directives.push old_parent_directive if old_parent_directive
|
56
|
+
@parent = old_parent
|
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,23 +123,61 @@ 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
|
-
|
127
|
-
|
126
|
+
node.resolved_selector.members.each do |seq|
|
127
|
+
if seq.members.size > 1
|
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
|
+
|
128
148
|
[]
|
129
149
|
end
|
130
150
|
|
131
151
|
# Modifies exception backtraces to include the imported file.
|
132
152
|
def visit_import(node)
|
133
|
-
|
153
|
+
# Don't use #visit_children to avoid adding the import node to the list of parents.
|
154
|
+
node.children.map {|c| visit(c)}.flatten
|
134
155
|
rescue Sass::SyntaxError => e
|
135
156
|
e.modify_backtrace(:filename => node.children.first.filename)
|
136
157
|
e.add_backtrace(:filename => node.filename, :line => node.line)
|
137
158
|
raise e
|
138
159
|
end
|
139
160
|
|
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
|
+
|
140
177
|
# Asserts that all the traced children are valid in their new location.
|
141
178
|
def visit_trace(node)
|
142
|
-
|
179
|
+
# Don't use #visit_children to avoid adding the trace node to the list of parents.
|
180
|
+
node.children.map {|c| visit(c)}.flatten
|
143
181
|
rescue Sass::SyntaxError => e
|
144
182
|
e.modify_backtrace(:mixin => node.name, :filename => node.filename, :line => node.line)
|
145
183
|
e.add_backtrace(:filename => node.filename, :line => node.line)
|
@@ -165,38 +203,17 @@ class Sass::Tree::Visitors::Cssize < Sass::Tree::Visitors::Base
|
|
165
203
|
result
|
166
204
|
end
|
167
205
|
|
168
|
-
|
169
|
-
|
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
|
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}.
|
206
|
+
# Resolves parent references and nested selectors,
|
207
|
+
# and updates the indentation of the rule node based on the nesting level.
|
195
208
|
def visit_rule(node)
|
209
|
+
parent_resolved_rules = parent.is_a?(Sass::Tree::RuleNode) ? parent.resolved_rules : nil
|
210
|
+
# It's possible for resolved_rules to be set if we've duplicated this node during @media bubbling
|
211
|
+
node.resolved_rules ||= node.parsed_rules.resolve_parent_refs(parent_resolved_rules)
|
212
|
+
|
196
213
|
yield
|
197
214
|
|
198
|
-
rules = node.children.select {|c|
|
199
|
-
props = node.children.reject {|c|
|
215
|
+
rules = node.children.select {|c| c.is_a?(Sass::Tree::RuleNode) || c.bubbles?}
|
216
|
+
props = node.children.reject {|c| c.is_a?(Sass::Tree::RuleNode) || c.bubbles? || c.invisible?}
|
200
217
|
|
201
218
|
unless props.empty?
|
202
219
|
node.children = props
|
@@ -204,166 +221,21 @@ class Sass::Tree::Visitors::Cssize < Sass::Tree::Visitors::Base
|
|
204
221
|
rules.unshift(node)
|
205
222
|
end
|
206
223
|
|
207
|
-
rules =
|
208
|
-
unless parent.is_a?(Sass::Tree::RuleNode) || rules.empty? || !bubblable?(rules.last)
|
209
|
-
rules.last.group_end = true
|
210
|
-
end
|
211
|
-
rules
|
212
|
-
end
|
213
|
-
|
214
|
-
def visit_keyframerule(node)
|
215
|
-
return node unless node.has_children
|
216
|
-
|
217
|
-
yield
|
218
|
-
|
219
|
-
debubble(node.children, node)
|
220
|
-
end
|
224
|
+
rules.last.group_end = true unless parent.is_a?(Sass::Tree::RuleNode) || rules.empty?
|
221
225
|
|
222
|
-
|
223
|
-
def visit_directive(node)
|
224
|
-
return node unless node.has_children
|
225
|
-
return bubble(node) if parent.is_a?(Sass::Tree::RuleNode)
|
226
|
-
|
227
|
-
yield
|
228
|
-
|
229
|
-
# Since we don't know if the mere presence of an unknown directive may be
|
230
|
-
# important, we should keep an empty version around even if all the contents
|
231
|
-
# are removed via @at-root. However, if the contents are just bubbled out,
|
232
|
-
# we don't need to do so.
|
233
|
-
directive_exists = node.children.any? do |child|
|
234
|
-
next true unless child.is_a?(Bubble)
|
235
|
-
next false unless child.node.is_a?(Sass::Tree::DirectiveNode)
|
236
|
-
child.node.resolved_value == node.resolved_value
|
237
|
-
end
|
238
|
-
|
239
|
-
# We know empty @keyframes directives do nothing.
|
240
|
-
if directive_exists || node.name == '@keyframes'
|
241
|
-
[]
|
242
|
-
else
|
243
|
-
empty_node = node.dup
|
244
|
-
empty_node.children = []
|
245
|
-
[empty_node]
|
246
|
-
end + debubble(node.children, node)
|
247
|
-
end
|
248
|
-
|
249
|
-
# Bubbles the `@media` directive up through RuleNodes
|
250
|
-
# and merges it with other `@media` directives.
|
251
|
-
def visit_media(node)
|
252
|
-
return bubble(node) if parent.is_a?(Sass::Tree::RuleNode)
|
253
|
-
return Bubble.new(node) if parent.is_a?(Sass::Tree::MediaNode)
|
254
|
-
|
255
|
-
yield
|
256
|
-
|
257
|
-
debubble(node.children, node) do |child|
|
258
|
-
next child unless child.is_a?(Sass::Tree::MediaNode)
|
259
|
-
# Copies of `node` can be bubbled, and we don't want to merge it with its
|
260
|
-
# own query.
|
261
|
-
next child if child.resolved_query == node.resolved_query
|
262
|
-
next child if child.resolved_query = child.resolved_query.merge(node.resolved_query)
|
263
|
-
end
|
264
|
-
end
|
265
|
-
|
266
|
-
# Bubbles the `@supports` directive up through RuleNodes.
|
267
|
-
def visit_supports(node)
|
268
|
-
return node unless node.has_children
|
269
|
-
return bubble(node) if parent.is_a?(Sass::Tree::RuleNode)
|
270
|
-
|
271
|
-
yield
|
272
|
-
|
273
|
-
debubble(node.children, node)
|
226
|
+
rules
|
274
227
|
end
|
275
228
|
|
276
229
|
private
|
277
230
|
|
278
|
-
# "Bubbles" `node` one level by copying the parent and wrapping `node`'s
|
279
|
-
# children with it.
|
280
|
-
#
|
281
|
-
# @param node [Sass::Tree::Node].
|
282
|
-
# @return [Bubble]
|
283
231
|
def bubble(node)
|
232
|
+
return unless parent.is_a?(Sass::Tree::RuleNode)
|
284
233
|
new_rule = parent.dup
|
285
234
|
new_rule.children = node.children
|
286
|
-
node.children =
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
# values.
|
292
|
-
#
|
293
|
-
# If `parent` is passed, it's copied and used as the parent node for the
|
294
|
-
# nested portions of `children`.
|
295
|
-
#
|
296
|
-
# @param children [List<Sass::Tree::Node, Bubble>]
|
297
|
-
# @param parent [Sass::Tree::Node]
|
298
|
-
# @yield [node] An optional block for processing bubbled nodes. Each bubbled
|
299
|
-
# node will be passed to this block.
|
300
|
-
# @yieldparam node [Sass::Tree::Node] A bubbled node.
|
301
|
-
# @yieldreturn [Sass::Tree::Node?] A node to use in place of the bubbled node.
|
302
|
-
# This can be the node itself, or `nil` to indicate that the node should be
|
303
|
-
# omitted.
|
304
|
-
# @return [List<Sass::Tree::Node, Bubble>]
|
305
|
-
def debubble(children, parent = nil)
|
306
|
-
# Keep track of the previous parent so that we don't divide `parent`
|
307
|
-
# unnecessarily if the `@at-root` doesn't produce any new nodes (e.g.
|
308
|
-
# `@at-root {@extend %foo}`).
|
309
|
-
previous_parent = nil
|
310
|
-
|
311
|
-
Sass::Util.slice_by(children) {|c| c.is_a?(Bubble)}.map do |(is_bubble, slice)|
|
312
|
-
unless is_bubble
|
313
|
-
next slice unless parent
|
314
|
-
if previous_parent
|
315
|
-
previous_parent.children.push(*slice)
|
316
|
-
next []
|
317
|
-
else
|
318
|
-
previous_parent = new_parent = parent.dup
|
319
|
-
new_parent.children = slice
|
320
|
-
next new_parent
|
321
|
-
end
|
322
|
-
end
|
323
|
-
|
324
|
-
slice.map do |bubble|
|
325
|
-
next unless (node = block_given? ? yield(bubble.node) : bubble.node)
|
326
|
-
node.tabs += bubble.tabs
|
327
|
-
node.group_end = bubble.group_end
|
328
|
-
results = [visit(node)].flatten
|
329
|
-
previous_parent = nil unless results.empty?
|
330
|
-
results
|
331
|
-
end.compact
|
332
|
-
end.flatten
|
333
|
-
end
|
334
|
-
|
335
|
-
# Returns whether or not a node can be bubbled up through the syntax tree.
|
336
|
-
#
|
337
|
-
# @param node [Sass::Tree::Node]
|
338
|
-
# @return [Boolean]
|
339
|
-
def bubblable?(node)
|
340
|
-
node.is_a?(Sass::Tree::RuleNode) || node.bubbles?
|
341
|
-
end
|
342
|
-
|
343
|
-
# A wrapper class for a node that indicates to the parent that it should
|
344
|
-
# treat the wrapped node as a sibling rather than a child.
|
345
|
-
#
|
346
|
-
# Nodes should be wrapped before they're passed to \{Cssize.visit}. They will
|
347
|
-
# be automatically visited upon calling \{#pop}.
|
348
|
-
#
|
349
|
-
# This duck types as a [Sass::Tree::Node] for the purposes of
|
350
|
-
# tree-manipulation operations.
|
351
|
-
class Bubble
|
352
|
-
attr_accessor :node
|
353
|
-
attr_accessor :tabs
|
354
|
-
attr_accessor :group_end
|
355
|
-
|
356
|
-
def initialize(node)
|
357
|
-
@node = node
|
358
|
-
@tabs = 0
|
359
|
-
end
|
360
|
-
|
361
|
-
def bubbles?
|
362
|
-
true
|
363
|
-
end
|
364
|
-
|
365
|
-
def inspect
|
366
|
-
"(Bubble #{node.inspect})"
|
367
|
-
end
|
235
|
+
node.children = with_parent(node) {Array(visit(new_rule))}
|
236
|
+
# If the last child is actually the end of the group,
|
237
|
+
# the parent's cssize will set it properly
|
238
|
+
node.children.last.group_end = false unless node.children.empty?
|
239
|
+
true
|
368
240
|
end
|
369
241
|
end
|