sass 3.1.0.alpha.48 → 3.1.0.alpha.49
Sign up to get free protection for your applications and to get access to all the features.
- 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,278 @@
|
|
1
|
+
# A visitor for converting a dynamic Sass tree into a static Sass tree.
|
2
|
+
class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
|
3
|
+
protected
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@environment = Sass::Environment.new
|
7
|
+
end
|
8
|
+
|
9
|
+
# If an exception is raised, this add proper metadata to the backtrace.
|
10
|
+
def visit(node)
|
11
|
+
super(node.dup)
|
12
|
+
rescue Sass::SyntaxError => e
|
13
|
+
e.modify_backtrace(:filename => node.filename, :line => node.line)
|
14
|
+
raise e
|
15
|
+
end
|
16
|
+
|
17
|
+
# Keeps track of the current environment.
|
18
|
+
def visit_children(parent)
|
19
|
+
with_environment Sass::Environment.new(@environment) do
|
20
|
+
parent.children = super.flatten
|
21
|
+
parent.children.each {|c| parent.check_child! c}
|
22
|
+
parent
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Runs a block of code with the current environment replaced with the given one.
|
27
|
+
#
|
28
|
+
# @param env [Sass::Environment] The new environment for the duration of the block.
|
29
|
+
# @yield A block in which the environment is set to `env`.
|
30
|
+
# @return [Object] The return value of the block.
|
31
|
+
def with_environment(env)
|
32
|
+
old_env, @environment = @environment, env
|
33
|
+
yield
|
34
|
+
ensure
|
35
|
+
@environment = old_env
|
36
|
+
end
|
37
|
+
|
38
|
+
# Sets the options on the environment if this is the top-level root.
|
39
|
+
def visit_root(node)
|
40
|
+
@environment.options = node.options if @environment.options.nil? || @environment.options.empty?
|
41
|
+
yield
|
42
|
+
rescue Sass::SyntaxError => e
|
43
|
+
e.sass_template ||= node.template
|
44
|
+
raise e
|
45
|
+
end
|
46
|
+
|
47
|
+
# Removes this node from the tree if it's a silent comment.
|
48
|
+
def visit_comment(node)
|
49
|
+
node.silent ? [] : node
|
50
|
+
end
|
51
|
+
|
52
|
+
# Prints the expression to STDERR.
|
53
|
+
def visit_debug(node)
|
54
|
+
res = node.expr.perform(@environment)
|
55
|
+
res = res.value if res.is_a?(Sass::Script::String)
|
56
|
+
if node.filename
|
57
|
+
$stderr.puts "#{node.filename}:#{node.line} DEBUG: #{res}"
|
58
|
+
else
|
59
|
+
$stderr.puts "Line #{node.line} DEBUG: #{res}"
|
60
|
+
end
|
61
|
+
[]
|
62
|
+
end
|
63
|
+
|
64
|
+
# Runs the child nodes once for each value in the list.
|
65
|
+
def visit_each(node)
|
66
|
+
list = node.list.perform(@environment)
|
67
|
+
|
68
|
+
with_environment Sass::Environment.new(@environment) do
|
69
|
+
list.to_a.map do |v|
|
70
|
+
@environment.set_local_var(node.var, v)
|
71
|
+
node.children.map {|c| visit(c)}
|
72
|
+
end.flatten
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Runs SassScript interpolation in the selector,
|
77
|
+
# and then parses the result into a {Sass::Selector::CommaSequence}.
|
78
|
+
def visit_extend(node)
|
79
|
+
parser = Sass::SCSS::CssParser.new(run_interp(node.selector), node.line)
|
80
|
+
node.resolved_selector = parser.parse_selector(node.filename)
|
81
|
+
node
|
82
|
+
end
|
83
|
+
|
84
|
+
# Runs the child nodes once for each time through the loop, varying the variable each time.
|
85
|
+
def visit_for(node)
|
86
|
+
from = node.from.perform(@environment)
|
87
|
+
to = node.to.perform(@environment)
|
88
|
+
from.assert_int!
|
89
|
+
to.assert_int!
|
90
|
+
|
91
|
+
to = to.coerce(from.numerator_units, from.denominator_units)
|
92
|
+
range = Range.new(from.to_i, to.to_i, node.exclusive)
|
93
|
+
|
94
|
+
with_environment Sass::Environment.new(@environment) do
|
95
|
+
range.map do |i|
|
96
|
+
@environment.set_local_var(node.var,
|
97
|
+
Sass::Script::Number.new(i, from.numerator_units, from.denominator_units))
|
98
|
+
node.children.map {|c| visit(c)}
|
99
|
+
end.flatten
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Runs the child nodes if the conditional expression is true;
|
104
|
+
# otherwise, tries the else nodes.
|
105
|
+
def visit_if(node)
|
106
|
+
if node.expr.nil? || node.expr.perform(@environment).to_bool
|
107
|
+
yield
|
108
|
+
node.children
|
109
|
+
elsif node.else
|
110
|
+
visit(node.else)
|
111
|
+
else
|
112
|
+
[]
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Returns a static DirectiveNode if this is importing a CSS file,
|
117
|
+
# or parses and includes the imported Sass file.
|
118
|
+
def visit_import(node)
|
119
|
+
if path = node.css_import?
|
120
|
+
return Sass::Tree::DirectiveNode.new("@import url(#{path})")
|
121
|
+
end
|
122
|
+
|
123
|
+
@environment.push_frame(:filename => node.filename, :line => node.line)
|
124
|
+
root = node.imported_file.to_tree
|
125
|
+
node.children = root.children.map {|c| visit(c)}.flatten
|
126
|
+
node
|
127
|
+
rescue Sass::SyntaxError => e
|
128
|
+
e.modify_backtrace(:filename => node.imported_file.options[:filename])
|
129
|
+
e.add_backtrace(:filename => node.filename, :line => node.line)
|
130
|
+
raise e
|
131
|
+
ensure
|
132
|
+
@environment.pop_frame
|
133
|
+
end
|
134
|
+
|
135
|
+
# Loads a mixin into the environment.
|
136
|
+
def visit_mixindef(node)
|
137
|
+
@environment.set_mixin(node.name,
|
138
|
+
Sass::Mixin.new(node.name, node.args, @environment, node.children))
|
139
|
+
[]
|
140
|
+
end
|
141
|
+
|
142
|
+
# Runs a mixin.
|
143
|
+
def visit_mixin(node)
|
144
|
+
handle_include_loop!(node) if @environment.mixins_in_use.include?(node.name)
|
145
|
+
|
146
|
+
original_env = @environment
|
147
|
+
original_env.push_frame(:filename => node.filename, :line => node.line)
|
148
|
+
original_env.prepare_frame(:mixin => node.name)
|
149
|
+
raise Sass::SyntaxError.new("Undefined mixin '#{node.name}'.") unless mixin = @environment.mixin(node.name)
|
150
|
+
|
151
|
+
passed_args = node.args.dup
|
152
|
+
passed_keywords = node.keywords.dup
|
153
|
+
|
154
|
+
raise Sass::SyntaxError.new(<<END.gsub("\n", "")) if mixin.args.size < passed_args.size
|
155
|
+
Mixin #{node.name} takes #{mixin.args.size} argument#{'s' if mixin.args.size != 1}
|
156
|
+
but #{node.args.size} #{node.args.size == 1 ? 'was' : 'were'} passed.
|
157
|
+
END
|
158
|
+
|
159
|
+
passed_keywords.each do |name, value|
|
160
|
+
# TODO: Make this fast
|
161
|
+
unless mixin.args.find {|(var, default)| var.underscored_name == name}
|
162
|
+
raise Sass::SyntaxError.new("Mixin #{node.name} doesn't have an argument named $#{name}")
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
environment = mixin.args.zip(passed_args).
|
167
|
+
inject(Sass::Environment.new(mixin.environment)) do |env, ((var, default), value)|
|
168
|
+
env.set_local_var(var.name,
|
169
|
+
if value
|
170
|
+
value.perform(@environment)
|
171
|
+
elsif kv = passed_keywords[var.underscored_name]
|
172
|
+
kv.perform(env)
|
173
|
+
elsif default
|
174
|
+
val = default.perform(env)
|
175
|
+
if default.context == :equals && val.is_a?(Sass::Script::String)
|
176
|
+
val = Sass::Script::String.new(val.value)
|
177
|
+
end
|
178
|
+
val
|
179
|
+
end)
|
180
|
+
raise Sass::SyntaxError.new("Mixin #{node.name} is missing parameter #{var.inspect}.") unless env.var(var.name)
|
181
|
+
env
|
182
|
+
end
|
183
|
+
|
184
|
+
with_environment(environment) {node.children = mixin.tree.map {|c| visit(c)}.flatten}
|
185
|
+
node
|
186
|
+
rescue Sass::SyntaxError => e
|
187
|
+
if original_env # Don't add backtrace info if this is an @include loop
|
188
|
+
e.modify_backtrace(:mixin => node.name, :line => node.line)
|
189
|
+
e.add_backtrace(:line => node.line)
|
190
|
+
end
|
191
|
+
raise e
|
192
|
+
ensure
|
193
|
+
original_env.pop_frame if original_env
|
194
|
+
end
|
195
|
+
|
196
|
+
# Runs any SassScript that may be embedded in a property.
|
197
|
+
def visit_prop(node)
|
198
|
+
node.resolved_name = run_interp(node.name)
|
199
|
+
val = node.value.perform(@environment)
|
200
|
+
node.resolved_value =
|
201
|
+
if node.value.context == :equals && val.is_a?(Sass::Script::String)
|
202
|
+
val.value
|
203
|
+
else
|
204
|
+
val.to_s
|
205
|
+
end
|
206
|
+
yield
|
207
|
+
end
|
208
|
+
|
209
|
+
# Runs SassScript interpolation in the selector,
|
210
|
+
# and then parses the result into a {Sass::Selector::CommaSequence}.
|
211
|
+
def visit_rule(node)
|
212
|
+
parser = Sass::SCSS::StaticParser.new(run_interp(node.rule), node.line)
|
213
|
+
node.parsed_rules = parser.parse_selector(node.filename)
|
214
|
+
yield
|
215
|
+
end
|
216
|
+
|
217
|
+
# Loads the new variable value into the environment.
|
218
|
+
def visit_variable(node)
|
219
|
+
return [] if node.guarded && !@environment.var(node.name).nil?
|
220
|
+
val = node.expr.perform(@environment)
|
221
|
+
val = Sass::Script::String.new(val.value) if node.expr.context == :equals && val.is_a?(Sass::Script::String)
|
222
|
+
@environment.set_var(node.name, val)
|
223
|
+
[]
|
224
|
+
end
|
225
|
+
|
226
|
+
# Prints the expression to STDERR with a stylesheet trace.
|
227
|
+
def visit_warn(node)
|
228
|
+
@environment.push_frame(:filename => node.filename, :line => node.line)
|
229
|
+
res = node.expr.perform(@environment)
|
230
|
+
res = res.value if res.is_a?(Sass::Script::String)
|
231
|
+
msg = "WARNING: #{res}\n"
|
232
|
+
@environment.stack.reverse.each_with_index do |entry, i|
|
233
|
+
msg << " #{i == 0 ? "on" : "from"} line #{entry[:line]}" <<
|
234
|
+
" of #{entry[:filename] || "an unknown file"}"
|
235
|
+
msg << ", in `#{entry[:mixin]}'" if entry[:mixin]
|
236
|
+
msg << "\n"
|
237
|
+
end
|
238
|
+
Sass::Util.sass_warn msg
|
239
|
+
[]
|
240
|
+
ensure
|
241
|
+
@environment.pop_frame
|
242
|
+
end
|
243
|
+
|
244
|
+
# Runs the child nodes until the continuation expression becomes false.
|
245
|
+
def visit_while(node)
|
246
|
+
children = []
|
247
|
+
with_environment Sass::Environment.new(@environment) do
|
248
|
+
children += node.children.map {|c| visit(c)} while node.expr.perform(@environment).to_bool
|
249
|
+
end
|
250
|
+
children.flatten
|
251
|
+
end
|
252
|
+
|
253
|
+
private
|
254
|
+
|
255
|
+
def run_interp(text)
|
256
|
+
text.map do |r|
|
257
|
+
next r if r.is_a?(String)
|
258
|
+
val = r.perform(@environment)
|
259
|
+
# Interpolated strings should never render with quotes
|
260
|
+
next val.value if val.is_a?(Sass::Script::String)
|
261
|
+
val.to_s
|
262
|
+
end.join.strip
|
263
|
+
end
|
264
|
+
|
265
|
+
def handle_include_loop!(node)
|
266
|
+
msg = "An @include loop has been found:"
|
267
|
+
mixins = @environment.stack.map {|s| s[:mixin]}.compact
|
268
|
+
if mixins.size == 2 && mixins[0] == mixins[1]
|
269
|
+
raise Sass::SyntaxError.new("#{msg} #{node.name} includes itself")
|
270
|
+
end
|
271
|
+
|
272
|
+
mixins << node.name
|
273
|
+
msg << "\n" << Sass::Util.enum_cons(mixins, 2).map do |m1, m2|
|
274
|
+
" #{m1} includes #{m2}"
|
275
|
+
end.join("\n")
|
276
|
+
raise Sass::SyntaxError.new(msg)
|
277
|
+
end
|
278
|
+
end
|
@@ -0,0 +1,200 @@
|
|
1
|
+
# A visitor for converting a Sass tree into CSS.
|
2
|
+
class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
|
3
|
+
protected
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@tabs = 0
|
7
|
+
end
|
8
|
+
|
9
|
+
def visit(node)
|
10
|
+
super
|
11
|
+
rescue Sass::SyntaxError => e
|
12
|
+
e.modify_backtrace(:filename => node.filename, :line => node.line)
|
13
|
+
raise e
|
14
|
+
end
|
15
|
+
|
16
|
+
def with_tabs(tabs)
|
17
|
+
old_tabs, @tabs = @tabs, tabs
|
18
|
+
yield
|
19
|
+
ensure
|
20
|
+
@tabs = old_tabs
|
21
|
+
end
|
22
|
+
|
23
|
+
def visit_root(node)
|
24
|
+
result = String.new
|
25
|
+
node.children.each do |child|
|
26
|
+
next if child.invisible?
|
27
|
+
child_str = visit(child)
|
28
|
+
result << child_str + (node.style == :compressed ? '' : "\n")
|
29
|
+
end
|
30
|
+
result.rstrip!
|
31
|
+
return "" if result.empty?
|
32
|
+
result << "\n"
|
33
|
+
unless Sass::Util.ruby1_8? || result.ascii_only?
|
34
|
+
if node.children.first.is_a?(Sass::Tree::CharsetNode)
|
35
|
+
begin
|
36
|
+
encoding = node.children.first.name
|
37
|
+
# Default to big-endian encoding, because we have to decide somehow
|
38
|
+
encoding << 'BE' if encoding =~ /\Autf-(16|32)\Z/i
|
39
|
+
result = result.encode(Encoding.find(encoding))
|
40
|
+
rescue EncodingError
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
result = "@charset \"#{result.encoding.name}\";#{
|
45
|
+
node.style == :compressed ? '' : "\n"
|
46
|
+
}".encode(result.encoding) + result
|
47
|
+
end
|
48
|
+
result
|
49
|
+
rescue Sass::SyntaxError => e
|
50
|
+
e.sass_template ||= node.template
|
51
|
+
raise e
|
52
|
+
end
|
53
|
+
|
54
|
+
def visit_charset(node)
|
55
|
+
"@charset \"#{node.name}\";"
|
56
|
+
end
|
57
|
+
|
58
|
+
def visit_comment(node)
|
59
|
+
return if node.invisible?
|
60
|
+
spaces = (' ' * [@tabs - node.value[/^ */].size, 0].max)
|
61
|
+
|
62
|
+
content = node.value.gsub(/^/, spaces)
|
63
|
+
content.gsub!(/\n +(\* *(?!\/))?/, ' ') if node.style == :compact
|
64
|
+
content
|
65
|
+
end
|
66
|
+
|
67
|
+
def visit_directive(node)
|
68
|
+
return node.value + ";" unless node.has_children
|
69
|
+
return node.value + " {}" if node.children.empty?
|
70
|
+
result = if node.style == :compressed
|
71
|
+
"#{node.value}{"
|
72
|
+
else
|
73
|
+
"#{' ' * @tabs}#{node.value} {" + (node.style == :compact ? ' ' : "\n")
|
74
|
+
end
|
75
|
+
was_prop = false
|
76
|
+
first = true
|
77
|
+
node.children.each do |child|
|
78
|
+
next if child.invisible?
|
79
|
+
if node.style == :compact
|
80
|
+
if child.is_a?(Sass::Tree::PropNode)
|
81
|
+
with_tabs(first || was_prop ? 0 : @tabs + 1) {result << visit(child) << ' '}
|
82
|
+
else
|
83
|
+
result[-1] = "\n" if was_prop
|
84
|
+
rendered = with_tabs(@tabs + 1) {visit(child).dup}
|
85
|
+
rendered = rendered.lstrip if first
|
86
|
+
result << rendered.rstrip + "\n"
|
87
|
+
end
|
88
|
+
was_prop = child.is_a?(Sass::Tree::PropNode)
|
89
|
+
first = false
|
90
|
+
elsif node.style == :compressed
|
91
|
+
result << (was_prop ? ";" : "") << with_tabs(0) {visit(child)}
|
92
|
+
was_prop = child.is_a?(Sass::Tree::PropNode)
|
93
|
+
else
|
94
|
+
result << with_tabs(@tabs + 1) {visit(child)} + "\n"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
result.rstrip + if node.style == :compressed
|
98
|
+
"}"
|
99
|
+
else
|
100
|
+
(node.style == :expanded ? "\n" : " ") + "}\n"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def visit_media(node)
|
105
|
+
str = with_tabs(@tabs + node.tabs) {visit_directive(node)}
|
106
|
+
str.gsub!(/\n\Z/, '') unless node.style == :compressed || node.group_end
|
107
|
+
str
|
108
|
+
end
|
109
|
+
|
110
|
+
def visit_prop(node)
|
111
|
+
tab_str = ' ' * (@tabs + node.tabs)
|
112
|
+
if node.style == :compressed
|
113
|
+
"#{tab_str}#{node.resolved_name}:#{node.resolved_value}"
|
114
|
+
else
|
115
|
+
"#{tab_str}#{node.resolved_name}: #{node.resolved_value};"
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def visit_rule(node)
|
120
|
+
with_tabs(@tabs + node.tabs) do
|
121
|
+
rule_separator = node.style == :compressed ? ',' : ', '
|
122
|
+
line_separator =
|
123
|
+
case node.style
|
124
|
+
when :nested, :expanded; "\n"
|
125
|
+
when :compressed; ""
|
126
|
+
else; " "
|
127
|
+
end
|
128
|
+
rule_indent = ' ' * @tabs
|
129
|
+
per_rule_indent, total_indent = [:nested, :expanded].include?(node.style) ? [rule_indent, ''] : ['', rule_indent]
|
130
|
+
|
131
|
+
total_rule = total_indent + node.resolved_rules.members.
|
132
|
+
map {|seq| seq.to_a.join.gsub(/([^,])\n/m, node.style == :compressed ? '\1 ' : "\\1\n")}.
|
133
|
+
join(rule_separator).split("\n").map do |line|
|
134
|
+
per_rule_indent + line.strip
|
135
|
+
end.join(line_separator)
|
136
|
+
|
137
|
+
to_return = ''
|
138
|
+
old_spaces = ' ' * @tabs
|
139
|
+
spaces = ' ' * (@tabs + 1)
|
140
|
+
if node.style != :compressed
|
141
|
+
if node.options[:debug_info]
|
142
|
+
to_return << visit(debug_info_rule(node.debug_info, node.options)) << "\n"
|
143
|
+
elsif node.options[:line_comments]
|
144
|
+
to_return << "#{old_spaces}/* line #{node.line}"
|
145
|
+
|
146
|
+
if node.filename
|
147
|
+
relative_filename = if node.options[:css_filename]
|
148
|
+
begin
|
149
|
+
Pathname.new(node.filename).relative_path_from(
|
150
|
+
Pathname.new(File.dirname(node.options[:css_filename]))).to_s
|
151
|
+
rescue ArgumentError
|
152
|
+
nil
|
153
|
+
end
|
154
|
+
end
|
155
|
+
relative_filename ||= node.filename
|
156
|
+
to_return << ", #{relative_filename}"
|
157
|
+
end
|
158
|
+
|
159
|
+
to_return << " */\n"
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
if node.style == :compact
|
164
|
+
properties = with_tabs(0) {node.children.map {|a| visit(a)}.join(' ')}
|
165
|
+
to_return << "#{total_rule} { #{properties} }#{"\n" if node.group_end}"
|
166
|
+
elsif node.style == :compressed
|
167
|
+
properties = with_tabs(0) {node.children.map {|a| visit(a)}.join(';')}
|
168
|
+
to_return << "#{total_rule}{#{properties}}"
|
169
|
+
else
|
170
|
+
properties = with_tabs(@tabs + 1) {node.children.map {|a| visit(a)}.join("\n")}
|
171
|
+
end_props = (node.style == :expanded ? "\n" + old_spaces : ' ')
|
172
|
+
to_return << "#{total_rule} {\n#{properties}#{end_props}}#{"\n" if node.group_end}"
|
173
|
+
end
|
174
|
+
|
175
|
+
to_return
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
private
|
180
|
+
|
181
|
+
def debug_info_rule(debug_info, options)
|
182
|
+
node = Sass::Tree::DirectiveNode.new("@media -sass-debug-info")
|
183
|
+
debug_info.map {|k, v| [k.to_s, v.to_s]}.sort.each do |k, v|
|
184
|
+
rule = Sass::Tree::RuleNode.new([""])
|
185
|
+
rule.resolved_rules = Sass::Selector::CommaSequence.new(
|
186
|
+
[Sass::Selector::Sequence.new(
|
187
|
+
[Sass::Selector::SimpleSequence.new(
|
188
|
+
[Sass::Selector::Element.new(k.to_s.gsub(/[^\w-]/, "\\\\\\0"), nil)])
|
189
|
+
])
|
190
|
+
])
|
191
|
+
prop = Sass::Tree::PropNode.new([""], "", :new)
|
192
|
+
prop.resolved_name = "font-family"
|
193
|
+
prop.resolved_value = Sass::SCSS::RX.escape_ident(v.to_s)
|
194
|
+
rule << prop
|
195
|
+
node << rule
|
196
|
+
end
|
197
|
+
node.options = options.merge(:debug_info => false, :line_comments => false, :style => :compressed)
|
198
|
+
node
|
199
|
+
end
|
200
|
+
end
|