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,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
|