sass 3.3.0.alpha.229 → 3.3.0.alpha.231
Sign up to get free protection for your applications and to get access to all the features.
- data/REVISION +1 -1
- data/VERSION +1 -1
- data/VERSION_DATE +1 -1
- data/lib/sass/engine.rb +1 -0
- data/lib/sass/script/value/list.rb +14 -0
- data/lib/sass/stack.rb +111 -0
- data/lib/sass/tree/visitors/perform.rb +41 -54
- metadata +5 -4
data/REVISION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
4b12122cb838c1c8b2488b2c0bb3f252d261de2a
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.3.0.alpha.
|
1
|
+
3.3.0.alpha.231
|
data/VERSION_DATE
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
23 August 2013 23:13:38 GMT
|
data/lib/sass/engine.rb
CHANGED
@@ -42,6 +42,20 @@ module Sass::Script::Value
|
|
42
42
|
return value.reject {|e| e.is_a?(Null) || e.is_a?(List) && e.value.empty?}.map {|e| e.to_s(opts)}.join(sep_str)
|
43
43
|
end
|
44
44
|
|
45
|
+
# @see Value#to_sass
|
46
|
+
def to_sass(opts = {})
|
47
|
+
return "()" if value.empty?
|
48
|
+
precedence = Sass::Script::Parser.precedence_of(separator)
|
49
|
+
value.reject {|e| e.is_a?(Null)}.map do |v|
|
50
|
+
if v.is_a?(List) && Sass::Script::Parser.precedence_of(v.separator) <= precedence ||
|
51
|
+
separator == :space && v.is_a?(UnaryOperation) && (v.operator == :minus || v.operator == :plus)
|
52
|
+
"(#{v.to_sass(opts)})"
|
53
|
+
else
|
54
|
+
v.to_sass(opts)
|
55
|
+
end
|
56
|
+
end.join(sep_str(nil))
|
57
|
+
end
|
58
|
+
|
45
59
|
# @see Value#inspect
|
46
60
|
def inspect
|
47
61
|
"(#{value.map {|e| e.inspect}.join(sep_str(nil))})"
|
data/lib/sass/stack.rb
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
module Sass
|
2
|
+
# A class representing the stack when compiling a Sass file.
|
3
|
+
class Stack
|
4
|
+
# TODO: use this to generate stack information for Sass::SyntaxErrors.
|
5
|
+
|
6
|
+
# A single stack frame.
|
7
|
+
class Frame
|
8
|
+
# The filename of the file in which this stack frame was created.
|
9
|
+
#
|
10
|
+
# @return [String]
|
11
|
+
attr_reader :filename
|
12
|
+
|
13
|
+
# The line number on which this stack frame was created.
|
14
|
+
#
|
15
|
+
# @return [String]
|
16
|
+
attr_reader :line
|
17
|
+
|
18
|
+
# The type of this stack frame. This can be `:import`, `:mixin`, or
|
19
|
+
# `:base`.
|
20
|
+
#
|
21
|
+
# `:base` indicates that this is the bottom-most frame, meaning that it
|
22
|
+
# represents a single line of code rather than a nested context. The stack
|
23
|
+
# will only ever have one base frame, and it will always be the most
|
24
|
+
# deeply-nested frame.
|
25
|
+
#
|
26
|
+
# @return [Symbol?]
|
27
|
+
attr_reader :type
|
28
|
+
|
29
|
+
# The name of the stack frame. For mixin frames, this is the mixin name;
|
30
|
+
# otherwise, it's `nil`.
|
31
|
+
#
|
32
|
+
# @return [String?]
|
33
|
+
attr_reader :name
|
34
|
+
|
35
|
+
def initialize(filename, line, type, name = nil)
|
36
|
+
@filename = filename
|
37
|
+
@line = line
|
38
|
+
@type = type
|
39
|
+
@name = name
|
40
|
+
end
|
41
|
+
|
42
|
+
# Whether this frame represents an import.
|
43
|
+
#
|
44
|
+
# @return [Boolean]
|
45
|
+
def is_import?
|
46
|
+
type == :import
|
47
|
+
end
|
48
|
+
|
49
|
+
# Whether this frame represents a mixin.
|
50
|
+
#
|
51
|
+
# @return [Boolean]
|
52
|
+
def is_mixin?
|
53
|
+
type == :mixin
|
54
|
+
end
|
55
|
+
|
56
|
+
# Whether this is the base frame.
|
57
|
+
#
|
58
|
+
# @return [Boolean]
|
59
|
+
def is_base?
|
60
|
+
type == :base
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# The stack frames. The last frame is the most deeply-nested.
|
65
|
+
#
|
66
|
+
# @return [Array<Frame>]
|
67
|
+
attr_reader :frames
|
68
|
+
|
69
|
+
def initialize
|
70
|
+
@frames = []
|
71
|
+
end
|
72
|
+
|
73
|
+
# Pushes a base frame onto the stack.
|
74
|
+
#
|
75
|
+
# @param filename [String] See \{Frame#filename}.
|
76
|
+
# @param line [String] See \{Frame#line}.
|
77
|
+
# @yield [] A block in which the new frame is on the stack.
|
78
|
+
def with_base(filename, line)
|
79
|
+
with_frame(filename, line, :base) {yield}
|
80
|
+
end
|
81
|
+
|
82
|
+
# Pushes an import frame onto the stack.
|
83
|
+
#
|
84
|
+
# @param filename [String] See \{Frame#filename}.
|
85
|
+
# @param line [String] See \{Frame#line}.
|
86
|
+
# @yield [] A block in which the new frame is on the stack.
|
87
|
+
def with_import(filename, line)
|
88
|
+
with_frame(filename, line, :import) {yield}
|
89
|
+
end
|
90
|
+
|
91
|
+
# Pushes a mixin frame onto the stack.
|
92
|
+
#
|
93
|
+
# @param filename [String] See \{Frame#filename}.
|
94
|
+
# @param line [String] See \{Frame#line}.
|
95
|
+
# @param name [String] See \{Frame#name}.
|
96
|
+
# @yield [] A block in which the new frame is on the stack.
|
97
|
+
def with_mixin(filename, line, name)
|
98
|
+
with_frame(filename, line, :mixin, name) {yield}
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
def with_frame(filename, line, type, name = nil)
|
104
|
+
@frames.pop if @frames.last && @frames.last.type == :base
|
105
|
+
@frames.push(Frame.new(filename, line, type, name))
|
106
|
+
yield
|
107
|
+
ensure
|
108
|
+
@frames.pop unless type == :base && @frames.last && @frames.last.type != :base
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -91,13 +91,12 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
|
|
91
91
|
|
92
92
|
def initialize(env)
|
93
93
|
@environment = env
|
94
|
-
|
95
|
-
@stack = []
|
94
|
+
@stack = Sass::Stack.new
|
96
95
|
end
|
97
96
|
|
98
97
|
# If an exception is raised, this adds proper metadata to the backtrace.
|
99
98
|
def visit(node)
|
100
|
-
super(node.dup)
|
99
|
+
@stack.with_base(node.filename, node.line) {super(node.dup)}
|
101
100
|
rescue Sass::SyntaxError => e
|
102
101
|
e.modify_backtrace(:filename => node.filename, :line => node.line)
|
103
102
|
raise e
|
@@ -221,21 +220,22 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
|
|
221
220
|
return resolved_node
|
222
221
|
end
|
223
222
|
file = node.imported_file
|
224
|
-
|
223
|
+
if @stack.frames.any? {|f| f.is_import? && f.filename == file.options[:filename]}
|
224
|
+
handle_import_loop!(node)
|
225
|
+
end
|
225
226
|
|
226
227
|
begin
|
227
|
-
@stack.
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
228
|
+
@stack.with_import(node.filename, node.line) do
|
229
|
+
root = file.to_tree
|
230
|
+
Sass::Tree::Visitors::CheckNesting.visit(root)
|
231
|
+
node.children = root.children.map {|c| visit(c)}.flatten
|
232
|
+
node
|
233
|
+
end
|
232
234
|
rescue Sass::SyntaxError => e
|
233
235
|
e.modify_backtrace(:filename => node.imported_file.options[:filename])
|
234
236
|
e.add_backtrace(:filename => node.filename, :line => node.line)
|
235
237
|
raise e
|
236
238
|
end
|
237
|
-
ensure
|
238
|
-
@stack.pop unless path
|
239
239
|
end
|
240
240
|
|
241
241
|
# Loads a mixin into the environment.
|
@@ -249,27 +249,28 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
|
|
249
249
|
# Runs a mixin.
|
250
250
|
def visit_mixin(node)
|
251
251
|
include_loop = true
|
252
|
-
handle_include_loop!(node) if @stack.any? {|
|
252
|
+
handle_include_loop!(node) if @stack.frames.any? {|f| f.is_mixin? && f.name == node.name}
|
253
253
|
include_loop = false
|
254
254
|
|
255
|
-
@stack.
|
256
|
-
|
255
|
+
@stack.with_mixin(node.filename, node.line, node.name) do
|
256
|
+
raise Sass::SyntaxError.new("Undefined mixin '#{node.name}'.") unless mixin = @environment.mixin(node.name)
|
257
257
|
|
258
|
-
|
259
|
-
|
260
|
-
|
258
|
+
if node.children.any? && !mixin.has_content
|
259
|
+
raise Sass::SyntaxError.new(%Q{Mixin "#{node.name}" does not accept a content block.})
|
260
|
+
end
|
261
261
|
|
262
|
-
|
263
|
-
|
264
|
-
|
262
|
+
args = node.args.map {|a| a.perform(@environment)}
|
263
|
+
keywords = Sass::Util.map_hash(node.keywords) {|k, v| [k, v.perform(@environment)]}
|
264
|
+
splat = node.splat.perform(@environment) if node.splat
|
265
265
|
|
266
|
-
|
267
|
-
|
268
|
-
|
266
|
+
self.class.perform_arguments(mixin, args, keywords, splat) do |env|
|
267
|
+
env.caller = Sass::Environment.new(@environment)
|
268
|
+
env.content = node.children if node.has_children
|
269
269
|
|
270
|
-
|
271
|
-
|
272
|
-
|
270
|
+
trace_node = Sass::Tree::TraceNode.from_node(node.name, node)
|
271
|
+
with_environment(env) {trace_node.children = mixin.tree.map {|c| visit(c)}.flatten}
|
272
|
+
trace_node
|
273
|
+
end
|
273
274
|
end
|
274
275
|
rescue Sass::SyntaxError => e
|
275
276
|
unless include_loop
|
@@ -277,22 +278,19 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
|
|
277
278
|
e.add_backtrace(:line => node.line)
|
278
279
|
end
|
279
280
|
raise e
|
280
|
-
ensure
|
281
|
-
@stack.pop unless include_loop
|
282
281
|
end
|
283
282
|
|
284
283
|
def visit_content(node)
|
285
284
|
return [] unless content = @environment.content
|
286
|
-
@stack.
|
287
|
-
|
288
|
-
|
289
|
-
|
285
|
+
@stack.with_mixin(node.filename, node.line, '@content') do
|
286
|
+
trace_node = Sass::Tree::TraceNode.from_node('@content', node)
|
287
|
+
with_environment(@environment.caller) {trace_node.children = content.map {|c| visit(c.dup)}.flatten}
|
288
|
+
trace_node
|
289
|
+
end
|
290
290
|
rescue Sass::SyntaxError => e
|
291
291
|
e.modify_backtrace(:mixin => '@content', :line => node.line)
|
292
292
|
e.add_backtrace(:line => node.line)
|
293
293
|
raise e
|
294
|
-
ensure
|
295
|
-
@stack.pop if content
|
296
294
|
end
|
297
295
|
|
298
296
|
# Runs any SassScript that may be embedded in a property.
|
@@ -317,11 +315,7 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
|
|
317
315
|
parser = Sass::SCSS::StaticParser.new(run_interp(node.rule),
|
318
316
|
node.filename, node.options[:importer], node.line)
|
319
317
|
node.parsed_rules ||= parser.parse_selector
|
320
|
-
if node.options[:trace_selectors]
|
321
|
-
@stack.push(:filename => node.filename, :line => node.line)
|
322
|
-
node.stack_trace = stack_trace
|
323
|
-
@stack.pop
|
324
|
-
end
|
318
|
+
node.stack_trace = stack_trace if node.options[:trace_selectors]
|
325
319
|
yield
|
326
320
|
end
|
327
321
|
|
@@ -341,15 +335,12 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
|
|
341
335
|
|
342
336
|
# Prints the expression to STDERR with a stylesheet trace.
|
343
337
|
def visit_warn(node)
|
344
|
-
@stack.push(:filename => node.filename, :line => node.line)
|
345
338
|
res = node.expr.perform(@environment)
|
346
339
|
res = res.value if res.is_a?(Sass::Script::Value::String)
|
347
340
|
msg = "WARNING: #{res}\n "
|
348
341
|
msg << stack_trace.join("\n ") << "\n"
|
349
342
|
Sass::Util.sass_warn msg
|
350
343
|
[]
|
351
|
-
ensure
|
352
|
-
@stack.pop
|
353
344
|
end
|
354
345
|
|
355
346
|
# Runs the child nodes until the continuation expression becomes false.
|
@@ -392,16 +383,12 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
|
|
392
383
|
private
|
393
384
|
|
394
385
|
def stack_trace
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
msg << " of #{entry[:filename] || "an unknown file"}"
|
401
|
-
msg << ", in `#{entry[:caller]}'" if entry[:caller]
|
402
|
-
trace << msg
|
386
|
+
Sass::Util.enum_with_index(Sass::Util.enum_cons(@stack.frames.reverse + [nil], 2)).
|
387
|
+
map do |(frame, caller), i|
|
388
|
+
"#{i == 0 ? "on" : "from"} line #{frame.line}" +
|
389
|
+
" of #{frame.filename || "an unknown file"}" +
|
390
|
+
(caller && caller.name ? ", in `#{caller.name}'" : "")
|
403
391
|
end
|
404
|
-
trace
|
405
392
|
end
|
406
393
|
|
407
394
|
def run_interp_no_strip(text)
|
@@ -421,8 +408,8 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
|
|
421
408
|
def handle_include_loop!(node)
|
422
409
|
msg = "An @include loop has been found:"
|
423
410
|
content_count = 0
|
424
|
-
mixins = @stack.reverse.map {|
|
425
|
-
if
|
411
|
+
mixins = @stack.frames.select {|f| f.is_mixin?}.reverse.map {|f| f.name}.select do |name|
|
412
|
+
if name == '@content'
|
426
413
|
content_count += 1
|
427
414
|
false
|
428
415
|
elsif content_count > 0
|
@@ -444,7 +431,7 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
|
|
444
431
|
|
445
432
|
def handle_import_loop!(node)
|
446
433
|
msg = "An @import loop has been found:"
|
447
|
-
files = @stack.map {|
|
434
|
+
files = @stack.frames.select {|f| f.is_import?}.map {|f| f.filename}.compact
|
448
435
|
if node.filename == node.imported_file.options[:filename]
|
449
436
|
raise Sass::SyntaxError.new("#{msg} #{node.filename} imports itself")
|
450
437
|
end
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sass
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 592302787
|
5
5
|
prerelease: 6
|
6
6
|
segments:
|
7
7
|
- 3
|
8
8
|
- 3
|
9
9
|
- 0
|
10
10
|
- alpha
|
11
|
-
-
|
12
|
-
version: 3.3.0.alpha.
|
11
|
+
- 231
|
12
|
+
version: 3.3.0.alpha.231
|
13
13
|
platform: ruby
|
14
14
|
authors:
|
15
15
|
- Nathan Weizenbaum
|
@@ -19,7 +19,7 @@ autorequire:
|
|
19
19
|
bindir: bin
|
20
20
|
cert_chain: []
|
21
21
|
|
22
|
-
date: 2013-08-
|
22
|
+
date: 2013-08-23 00:00:00 -04:00
|
23
23
|
default_executable:
|
24
24
|
dependencies:
|
25
25
|
- !ruby/object:Gem::Dependency
|
@@ -192,6 +192,7 @@ files:
|
|
192
192
|
- lib/sass/tree/visitors/to_css.rb
|
193
193
|
- lib/sass/tree/warn_node.rb
|
194
194
|
- lib/sass/tree/while_node.rb
|
195
|
+
- lib/sass/stack.rb
|
195
196
|
- lib/sass/util/multibyte_string_scanner.rb
|
196
197
|
- lib/sass/util/normalized_map.rb
|
197
198
|
- lib/sass/util/ordered_hash.rb
|