haml 3.1.3 → 3.1.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of haml might be problematic. Click here for more details.

Files changed (134) hide show
  1. data/Rakefile +42 -17
  2. data/VERSION +1 -1
  3. data/lib/haml/compiler.rb +3 -3
  4. data/lib/haml/helpers/action_view_mods.rb +4 -3
  5. data/lib/haml/template.rb +3 -1
  6. data/test/gemfiles/Gemfile.rails-2.0.x +8 -0
  7. data/test/gemfiles/Gemfile.rails-2.0.x.lock +38 -0
  8. data/test/gemfiles/Gemfile.rails-2.1.x +8 -0
  9. data/test/gemfiles/Gemfile.rails-2.1.x.lock +38 -0
  10. data/test/gemfiles/Gemfile.rails-2.2.x +8 -0
  11. data/test/gemfiles/Gemfile.rails-2.2.x.lock +38 -0
  12. data/test/gemfiles/Gemfile.rails-2.3.x +8 -0
  13. data/test/gemfiles/Gemfile.rails-2.3.x.lock +40 -0
  14. data/test/gemfiles/Gemfile.rails-3.0.x +8 -0
  15. data/test/gemfiles/Gemfile.rails-3.0.x.lock +85 -0
  16. data/test/gemfiles/Gemfile.rails-3.1.x +8 -0
  17. data/test/gemfiles/Gemfile.rails-3.1.x.lock +98 -0
  18. data/test/gemfiles/Gemfile.rails-xss-2.3.x +9 -0
  19. data/test/gemfiles/Gemfile.rails-xss-2.3.x.lock +42 -0
  20. data/test/haml/engine_test.rb +19 -0
  21. data/test/haml/html2haml_test.rb +1 -1
  22. data/test/haml/template_test.rb +20 -2
  23. data/test/haml/templates/partial_layout.haml +4 -1
  24. data/test/linked_rails.rb +4 -4
  25. data/vendor/sass/VERSION +1 -1
  26. data/vendor/sass/doc-src/SASS_CHANGELOG.md +115 -2
  27. data/vendor/sass/doc-src/SASS_REFERENCE.md +12 -4
  28. data/vendor/sass/lib/sass.rb +1 -0
  29. data/vendor/sass/lib/sass/cache_stores/base.rb +3 -1
  30. data/vendor/sass/lib/sass/cache_stores/filesystem.rb +2 -0
  31. data/vendor/sass/lib/sass/css.rb +2 -1
  32. data/vendor/sass/lib/sass/engine.rb +39 -23
  33. data/vendor/sass/lib/sass/environment.rb +11 -0
  34. data/vendor/sass/lib/sass/exec.rb +14 -1
  35. data/vendor/sass/lib/sass/importers/base.rb +2 -1
  36. data/vendor/sass/lib/sass/importers/filesystem.rb +18 -13
  37. data/vendor/sass/lib/sass/less.rb +2 -2
  38. data/vendor/sass/lib/sass/logger.rb +15 -0
  39. data/vendor/sass/lib/sass/logger/base.rb +32 -0
  40. data/vendor/sass/lib/sass/logger/log_level.rb +49 -0
  41. data/vendor/sass/lib/sass/plugin.rb +4 -8
  42. data/vendor/sass/lib/sass/plugin/compiler.rb +42 -17
  43. data/vendor/sass/lib/sass/plugin/configuration.rb +0 -2
  44. data/vendor/sass/lib/sass/railtie.rb +1 -1
  45. data/vendor/sass/lib/sass/script/funcall.rb +14 -1
  46. data/vendor/sass/lib/sass/script/functions.rb +44 -1
  47. data/vendor/sass/lib/sass/script/interpolation.rb +9 -0
  48. data/vendor/sass/lib/sass/script/lexer.rb +6 -1
  49. data/vendor/sass/lib/sass/script/list.rb +7 -0
  50. data/vendor/sass/lib/sass/script/literal.rb +5 -0
  51. data/vendor/sass/lib/sass/script/node.rb +8 -0
  52. data/vendor/sass/lib/sass/script/number.rb +28 -5
  53. data/vendor/sass/lib/sass/script/operation.rb +8 -0
  54. data/vendor/sass/lib/sass/script/parser.rb +12 -5
  55. data/vendor/sass/lib/sass/script/string_interpolation.rb +9 -0
  56. data/vendor/sass/lib/sass/script/unary_operation.rb +7 -0
  57. data/vendor/sass/lib/sass/script/variable.rb +5 -0
  58. data/vendor/sass/lib/sass/scss/parser.rb +78 -38
  59. data/vendor/sass/lib/sass/scss/rx.rb +2 -1
  60. data/vendor/sass/lib/sass/scss/static_parser.rb +2 -2
  61. data/vendor/sass/lib/sass/shared.rb +1 -1
  62. data/vendor/sass/lib/sass/tree/comment_node.rb +24 -11
  63. data/vendor/sass/lib/sass/tree/debug_node.rb +1 -1
  64. data/vendor/sass/lib/sass/tree/each_node.rb +1 -1
  65. data/vendor/sass/lib/sass/tree/extend_node.rb +1 -1
  66. data/vendor/sass/lib/sass/tree/for_node.rb +2 -2
  67. data/vendor/sass/lib/sass/tree/function_node.rb +1 -1
  68. data/vendor/sass/lib/sass/tree/if_node.rb +1 -14
  69. data/vendor/sass/lib/sass/tree/mixin_def_node.rb +1 -1
  70. data/vendor/sass/lib/sass/tree/mixin_node.rb +2 -2
  71. data/vendor/sass/lib/sass/tree/node.rb +2 -5
  72. data/vendor/sass/lib/sass/tree/prop_node.rb +2 -9
  73. data/vendor/sass/lib/sass/tree/return_node.rb +1 -1
  74. data/vendor/sass/lib/sass/tree/rule_node.rb +9 -2
  75. data/vendor/sass/lib/sass/tree/variable_node.rb +1 -1
  76. data/vendor/sass/lib/sass/tree/visitors/check_nesting.rb +17 -18
  77. data/vendor/sass/lib/sass/tree/visitors/convert.rb +10 -5
  78. data/vendor/sass/lib/sass/tree/visitors/deep_copy.rb +87 -0
  79. data/vendor/sass/lib/sass/tree/visitors/perform.rb +50 -19
  80. data/vendor/sass/lib/sass/tree/visitors/set_options.rb +97 -0
  81. data/vendor/sass/lib/sass/tree/visitors/to_css.rb +9 -15
  82. data/vendor/sass/lib/sass/tree/warn_node.rb +1 -1
  83. data/vendor/sass/lib/sass/tree/while_node.rb +1 -1
  84. data/vendor/sass/lib/sass/util.rb +58 -6
  85. data/vendor/sass/sass.gemspec +2 -1
  86. data/vendor/sass/test/Gemfile +4 -0
  87. data/vendor/sass/test/Gemfile.lock +19 -0
  88. data/vendor/sass/test/sass/cache_test.rb +15 -0
  89. data/vendor/sass/test/sass/conversion_test.rb +2 -6
  90. data/vendor/sass/test/sass/css2sass_test.rb +9 -0
  91. data/vendor/sass/test/sass/engine_test.rb +124 -26
  92. data/vendor/sass/test/sass/fixtures/test_staleness_check_across_importers.css +1 -0
  93. data/vendor/sass/test/sass/fixtures/test_staleness_check_across_importers.scss +1 -0
  94. data/vendor/sass/test/sass/functions_test.rb +13 -0
  95. data/vendor/sass/test/sass/importer_test.rb +110 -0
  96. data/vendor/sass/test/sass/logger_test.rb +58 -0
  97. data/vendor/sass/test/sass/plugin_test.rb +16 -13
  98. data/vendor/sass/test/sass/script_conversion_test.rb +2 -0
  99. data/vendor/sass/test/sass/script_test.rb +18 -0
  100. data/vendor/sass/test/sass/scss/css_test.rb +7 -1
  101. data/vendor/sass/test/sass/scss/scss_test.rb +37 -13
  102. data/vendor/sass/test/sass/templates/bork5.sass +3 -0
  103. data/vendor/sass/test/sass/templates/nested_bork5.sass +2 -0
  104. data/vendor/sass/test/sass/test_helper.rb +1 -1
  105. data/vendor/sass/test/sass/util_test.rb +12 -0
  106. data/vendor/sass/vendor/fssm/Gemfile +3 -0
  107. data/vendor/sass/vendor/fssm/LICENSE +1 -1
  108. data/vendor/sass/vendor/fssm/README.markdown +55 -27
  109. data/vendor/sass/vendor/fssm/Rakefile +6 -54
  110. data/vendor/sass/vendor/fssm/example.rb +6 -3
  111. data/vendor/sass/vendor/fssm/fssm.gemspec +17 -70
  112. data/vendor/sass/vendor/fssm/lib/fssm.rb +7 -3
  113. data/vendor/sass/vendor/fssm/lib/fssm/backends/fsevents.rb +1 -1
  114. data/vendor/sass/vendor/fssm/lib/fssm/backends/inotify.rb +2 -2
  115. data/vendor/sass/vendor/fssm/lib/fssm/backends/polling.rb +2 -2
  116. data/vendor/sass/vendor/fssm/lib/fssm/backends/rbfsevent.rb +42 -0
  117. data/vendor/sass/vendor/fssm/lib/fssm/backends/rubycocoa/fsevents.rb +10 -10
  118. data/vendor/sass/vendor/fssm/lib/fssm/monitor.rb +19 -9
  119. data/vendor/sass/vendor/fssm/lib/fssm/path.rb +24 -21
  120. data/vendor/sass/vendor/fssm/lib/fssm/pathname.rb +13 -479
  121. data/vendor/sass/vendor/fssm/lib/fssm/state/directory.rb +29 -11
  122. data/vendor/sass/vendor/fssm/lib/fssm/state/file.rb +1 -1
  123. data/vendor/sass/vendor/fssm/lib/fssm/support.rb +41 -12
  124. data/vendor/sass/vendor/fssm/lib/fssm/tree.rb +6 -6
  125. data/vendor/sass/vendor/fssm/lib/fssm/version.rb +3 -0
  126. data/vendor/sass/vendor/fssm/profile/prof-cache.rb +3 -3
  127. data/vendor/sass/vendor/fssm/profile/prof-pathname-rubinius.rb +35 -0
  128. data/vendor/sass/vendor/fssm/profile/prof-pathname.rb +7 -7
  129. data/vendor/sass/vendor/fssm/spec/count_down_latch.rb +151 -0
  130. data/vendor/sass/vendor/fssm/spec/monitor_spec.rb +202 -0
  131. data/vendor/sass/vendor/fssm/spec/path_spec.rb +36 -15
  132. data/vendor/sass/vendor/fssm/spec/spec_helper.rb +6 -6
  133. metadata +36 -5
  134. data/vendor/sass/vendor/fssm/VERSION.yml +0 -5
@@ -6,7 +6,7 @@ module Sass
6
6
  class ReturnNode < Node
7
7
  # The expression to return.
8
8
  # @type [Script::Node]
9
- attr_reader :expr
9
+ attr_accessor :expr
10
10
 
11
11
  # @param expr [Script::Node] The expression to return
12
12
  def initialize(expr)
@@ -50,6 +50,13 @@ module Sass::Tree
50
50
  # @return [Boolean]
51
51
  attr_accessor :group_end
52
52
 
53
+ # The stack trace.
54
+ # This is only readable in a CSS tree as it is written during the perform step
55
+ # and only when the :trace_selectors option is set.
56
+ #
57
+ # @return [Array<String>]
58
+ attr_accessor :stack_trace
59
+
53
60
  # @param rule [Array<String, Sass::Script::Node>]
54
61
  # The CSS rule. See \{#rule}
55
62
  def initialize(rule)
@@ -121,8 +128,8 @@ module Sass::Tree
121
128
  if @rule.all? {|t| t.kind_of?(String)}
122
129
  # We don't use real filename/line info because we don't have it yet.
123
130
  # When we get it, we'll set it on the parsed rules if possible.
124
- parser = Sass::SCSS::StaticParser.new(@rule.join.strip, 1)
125
- @parsed_rules = parser.parse_selector('') rescue nil
131
+ parser = Sass::SCSS::StaticParser.new(@rule.join.strip, '', 1)
132
+ @parsed_rules = parser.parse_selector rescue nil
126
133
  end
127
134
  end
128
135
  end
@@ -10,7 +10,7 @@ module Sass
10
10
 
11
11
  # The parse tree for the variable value.
12
12
  # @return [Script::Node]
13
- attr_reader :expr
13
+ attr_accessor :expr
14
14
 
15
15
  # Whether this is a guarded variable assignment (`!default`).
16
16
  # @return [Boolean]
@@ -17,11 +17,11 @@ class Sass::Tree::Visitors::CheckNesting < Sass::Tree::Visitors::Base
17
17
  raise e
18
18
  end
19
19
 
20
- PARENT_CLASSES = [ Sass::Tree::EachNode, Sass::Tree::ForNode, Sass::Tree::IfNode,
21
- Sass::Tree::ImportNode, Sass::Tree::MixinNode, Sass::Tree::WhileNode]
20
+ CONTROL_NODES = [Sass::Tree::EachNode, Sass::Tree::ForNode, Sass::Tree::IfNode, Sass::Tree::WhileNode]
21
+ SCRIPT_NODES = [Sass::Tree::ImportNode, Sass::Tree::MixinNode] + CONTROL_NODES
22
22
  def visit_children(parent)
23
23
  old_parent = @parent
24
- @parent = parent unless is_any_of?(parent, PARENT_CLASSES)
24
+ @parent = parent unless is_any_of?(parent, SCRIPT_NODES)
25
25
  old_real_parent, @real_parent = @real_parent, parent
26
26
  super
27
27
  ensure
@@ -48,9 +48,9 @@ class Sass::Tree::Visitors::CheckNesting < Sass::Tree::Visitors::Base
48
48
  "@charset may only be used at the root of a document." unless parent.is_a?(Sass::Tree::RootNode)
49
49
  end
50
50
 
51
- INVALID_EXTEND_PARENTS = [Sass::Tree::RuleNode, Sass::Tree::MixinDefNode]
51
+ VALID_EXTEND_PARENTS = [Sass::Tree::RuleNode, Sass::Tree::MixinDefNode]
52
52
  def invalid_extend_parent?(parent, child)
53
- unless is_any_of?(parent, INVALID_EXTEND_PARENTS)
53
+ unless is_any_of?(parent, VALID_EXTEND_PARENTS)
54
54
  "Extend directives may only be used within rules."
55
55
  end
56
56
  end
@@ -59,23 +59,22 @@ class Sass::Tree::Visitors::CheckNesting < Sass::Tree::Visitors::Base
59
59
  "Functions may only be defined at the root of a document." unless parent.is_a?(Sass::Tree::RootNode)
60
60
  end
61
61
 
62
- INVALID_FUNCTION_CHILDREN = [
63
- Sass::Tree::CommentNode, Sass::Tree::DebugNode, Sass::Tree::EachNode,
64
- Sass::Tree::ForNode, Sass::Tree::IfNode, Sass::Tree::ReturnNode,
65
- Sass::Tree::VariableNode, Sass::Tree::WarnNode, Sass::Tree::WhileNode
66
- ]
62
+ VALID_FUNCTION_CHILDREN = [
63
+ Sass::Tree::CommentNode, Sass::Tree::DebugNode, Sass::Tree::ReturnNode,
64
+ Sass::Tree::VariableNode, Sass::Tree::WarnNode
65
+ ] + CONTROL_NODES
67
66
  def invalid_function_child?(parent, child)
68
- unless is_any_of?(child, INVALID_FUNCTION_CHILDREN)
67
+ unless is_any_of?(child, VALID_FUNCTION_CHILDREN)
69
68
  "Functions can only contain variable declarations and control directives."
70
69
  end
71
70
  end
72
71
 
73
- INVALID_IMPORT_PARENTS = [
72
+ VALID_IMPORT_PARENTS = [
74
73
  Sass::Tree::IfNode, Sass::Tree::ForNode, Sass::Tree::WhileNode,
75
74
  Sass::Tree::EachNode, Sass::Tree::MixinDefNode
76
75
  ]
77
76
  def invalid_import_parent?(parent, child)
78
- if is_any_of?(@real_parent, INVALID_IMPORT_PARENTS)
77
+ if is_any_of?(@real_parent, VALID_IMPORT_PARENTS)
79
78
  return "Import directives may not be used within control directives or mixins."
80
79
  end
81
80
  return if parent.is_a?(Sass::Tree::RootNode)
@@ -98,17 +97,17 @@ class Sass::Tree::Visitors::CheckNesting < Sass::Tree::Visitors::Base
98
97
  "Mixins may only be defined at the root of a document." unless parent.is_a?(Sass::Tree::RootNode)
99
98
  end
100
99
 
101
- INVALID_PROP_CHILDREN = [Sass::Tree::CommentNode, Sass::Tree::PropNode]
100
+ VALID_PROP_CHILDREN = [Sass::Tree::CommentNode, Sass::Tree::PropNode, Sass::Tree::MixinNode] + CONTROL_NODES
102
101
  def invalid_prop_child?(parent, child)
103
- unless is_any_of?(child, INVALID_PROP_CHILDREN)
102
+ unless is_any_of?(child, VALID_PROP_CHILDREN)
104
103
  "Illegal nesting: Only properties may be nested beneath properties."
105
104
  end
106
105
  end
107
106
 
108
- INVALID_PROP_PARENTS = [Sass::Tree::RuleNode, Sass::Tree::PropNode,
109
- Sass::Tree::MixinDefNode, Sass::Tree::DirectiveNode]
107
+ VALID_PROP_PARENTS = [Sass::Tree::RuleNode, Sass::Tree::PropNode,
108
+ Sass::Tree::MixinDefNode, Sass::Tree::DirectiveNode]
110
109
  def invalid_prop_parent?(parent, child)
111
- unless is_any_of?(parent, INVALID_PROP_PARENTS)
110
+ unless is_any_of?(parent, VALID_PROP_PARENTS)
112
111
  "Properties are only allowed within rules, directives, or other properties." + child.pseudo_class_selector_message
113
112
  end
114
113
  end
@@ -32,7 +32,7 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base
32
32
  visit(child) +
33
33
  if nxt &&
34
34
  (child.is_a?(Sass::Tree::CommentNode) &&
35
- child.line + child.value.count("\n") + 1 == nxt.line) ||
35
+ child.line + child.lines + 1 == nxt.line) ||
36
36
  (child.is_a?(Sass::Tree::ImportNode) && nxt.is_a?(Sass::Tree::ImportNode) &&
37
37
  child.line + 1 == nxt.line) ||
38
38
  (child.is_a?(Sass::Tree::VariableNode) && nxt.is_a?(Sass::Tree::VariableNode) &&
@@ -49,8 +49,13 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base
49
49
  end
50
50
 
51
51
  def visit_comment(node)
52
+ value = node.value.map do |r|
53
+ next r if r.is_a?(String)
54
+ "\#{#{r.to_sass(@options)}}"
55
+ end.join
56
+
52
57
  content = if @format == :sass
53
- content = node.value.gsub(/\*\/$/, '').rstrip
58
+ content = value.gsub(/\*\/$/, '').rstrip
54
59
  if content =~ /\A[ \t]/
55
60
  # Re-indent SCSS comments like this:
56
61
  # /* foo
@@ -78,11 +83,11 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base
78
83
  content.gsub!(/^/, tab_str)
79
84
  content.rstrip + "\n"
80
85
  else
81
- spaces = (' ' * [@tabs - node.value[/^ */].size, 0].max)
86
+ spaces = (' ' * [@tabs - value[/^ */].size, 0].max)
82
87
  content = if node.silent
83
- node.value.gsub(/^[\/ ]\*/, '//').gsub(/ *\*\/$/, '')
88
+ value.gsub(/^[\/ ]\*/, '//').gsub(/ *\*\/$/, '')
84
89
  else
85
- node.value
90
+ value
86
91
  end.gsub(/^/, spaces) + "\n"
87
92
  content
88
93
  end
@@ -0,0 +1,87 @@
1
+ # A visitor for copying the full structure of a Sass tree.
2
+ class Sass::Tree::Visitors::DeepCopy < Sass::Tree::Visitors::Base
3
+ protected
4
+
5
+ def visit(node)
6
+ super(node.dup)
7
+ end
8
+
9
+ def visit_children(parent)
10
+ parent.children = parent.children.map {|c| visit(c)}
11
+ parent
12
+ end
13
+
14
+ def visit_debug(node)
15
+ node.expr = node.expr.deep_copy
16
+ yield
17
+ end
18
+
19
+ def visit_each(node)
20
+ node.list = node.list.deep_copy
21
+ yield
22
+ end
23
+
24
+ def visit_extend(node)
25
+ node.selector = node.selector.map {|c| c.is_a?(Sass::Script::Node) ? c.deep_copy : c}
26
+ yield
27
+ end
28
+
29
+ def visit_for(node)
30
+ node.from = node.from.deep_copy
31
+ node.to = node.to.deep_copy
32
+ yield
33
+ end
34
+
35
+ def visit_function(node)
36
+ node.args = node.args.map {|k, v| [k.deep_copy, v && v.deep_copy]}
37
+ yield
38
+ end
39
+
40
+ def visit_if(node)
41
+ node.expr = node.expr.deep_copy if node.expr
42
+ node.else = visit(node.else) if node.else
43
+ yield
44
+ end
45
+
46
+ def visit_mixindef(node)
47
+ node.args = node.args.map {|k, v| [k.deep_copy, v && v.deep_copy]}
48
+ yield
49
+ end
50
+
51
+ def visit_mixin(node)
52
+ node.args = node.args.map {|a| a.deep_copy}
53
+ node.keywords = Hash[node.keywords.map {|k, v| [k, v.deep_copy]}]
54
+ yield
55
+ end
56
+
57
+ def visit_prop(node)
58
+ node.name = node.name.map {|c| c.is_a?(Sass::Script::Node) ? c.deep_copy : c}
59
+ node.value = node.value.deep_copy
60
+ yield
61
+ end
62
+
63
+ def visit_return(node)
64
+ node.expr = node.expr.deep_copy
65
+ yield
66
+ end
67
+
68
+ def visit_rule(node)
69
+ node.rule = node.rule.map {|c| c.is_a?(Sass::Script::Node) ? c.deep_copy : c}
70
+ yield
71
+ end
72
+
73
+ def visit_variable(node)
74
+ node.expr = node.expr.deep_copy
75
+ yield
76
+ end
77
+
78
+ def visit_warn(node)
79
+ node.expr = node.expr.deep_copy
80
+ yield
81
+ end
82
+
83
+ def visit_while(node)
84
+ node.expr = node.expr.deep_copy
85
+ yield
86
+ end
87
+ end
@@ -53,12 +53,10 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
53
53
  # Removes this node from the tree if it's a silent comment.
54
54
  def visit_comment(node)
55
55
  return [] if node.invisible?
56
- if node.evaluated?
57
- node.value.gsub!(/(^|[^\\])\#\{([^}]*)\}/) do |md|
58
- $1+Sass::Script.parse($2, node.line, 0, node.options).perform(@environment).to_s
59
- end
60
- node.value = run_interp([Sass::Script::String.new(node.value)])
61
- end
56
+ check_for_loud_silent_comment node
57
+ check_for_comment_interp node
58
+ node.resolved_value = run_interp_no_strip(node.value)
59
+ node.resolved_value.gsub!(/\\([\\#])/, '\1')
62
60
  node
63
61
  end
64
62
 
@@ -89,8 +87,8 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
89
87
  # Runs SassScript interpolation in the selector,
90
88
  # and then parses the result into a {Sass::Selector::CommaSequence}.
91
89
  def visit_extend(node)
92
- parser = Sass::SCSS::CssParser.new(run_interp(node.selector), node.line)
93
- node.resolved_selector = parser.parse_selector(node.filename)
90
+ parser = Sass::SCSS::CssParser.new(run_interp(node.selector), node.filename, node.line)
91
+ node.resolved_selector = parser.parse_selector
94
92
  node
95
93
  end
96
94
 
@@ -142,6 +140,7 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
142
140
 
143
141
  @environment.push_frame(:filename => node.filename, :line => node.line)
144
142
  root = node.imported_file.to_tree
143
+ Sass::Tree::Visitors::CheckNesting.visit(root)
145
144
  node.children = root.children.map {|c| visit(c)}.flatten
146
145
  node
147
146
  rescue Sass::SyntaxError => e
@@ -225,8 +224,13 @@ END
225
224
  # Runs SassScript interpolation in the selector,
226
225
  # and then parses the result into a {Sass::Selector::CommaSequence}.
227
226
  def visit_rule(node)
228
- parser = Sass::SCSS::StaticParser.new(run_interp(node.rule), node.line)
229
- node.parsed_rules ||= parser.parse_selector(node.filename)
227
+ parser = Sass::SCSS::StaticParser.new(run_interp(node.rule), node.filename, node.line)
228
+ node.parsed_rules ||= parser.parse_selector
229
+ if node.options[:trace_selectors]
230
+ @environment.push_frame(:filename => node.filename, :line => node.line)
231
+ node.stack_trace = @environment.stack_trace
232
+ @environment.pop_frame
233
+ end
230
234
  yield
231
235
  end
232
236
 
@@ -243,13 +247,10 @@ END
243
247
  @environment.push_frame(:filename => node.filename, :line => node.line)
244
248
  res = node.expr.perform(@environment)
245
249
  res = res.value if res.is_a?(Sass::Script::String)
246
- msg = "WARNING: #{res}\n"
247
- @environment.stack.reverse.each_with_index do |entry, i|
248
- msg << " #{i == 0 ? "on" : "from"} line #{entry[:line]}" <<
249
- " of #{entry[:filename] || "an unknown file"}"
250
- msg << ", in `#{entry[:mixin]}'" if entry[:mixin]
251
- msg << "\n"
252
- end
250
+ msg = "WARNING: #{res}\n "
251
+ msg << @environment.stack_trace.join("\n ")
252
+ # JRuby doesn't automatically add a newline for #warn
253
+ msg << (RUBY_PLATFORM =~ /java/ ? "\n\n" : "\n")
253
254
  Sass::Util.sass_warn msg
254
255
  []
255
256
  ensure
@@ -275,14 +276,18 @@ END
275
276
 
276
277
  private
277
278
 
278
- def run_interp(text)
279
+ def run_interp_no_strip(text)
279
280
  text.map do |r|
280
281
  next r if r.is_a?(String)
281
282
  val = r.perform(@environment)
282
283
  # Interpolated strings should never render with quotes
283
284
  next val.value if val.is_a?(Sass::Script::String)
284
285
  val.to_s
285
- end.join.strip
286
+ end.join
287
+ end
288
+
289
+ def run_interp(text)
290
+ run_interp_no_strip(text).strip
286
291
  end
287
292
 
288
293
  def handle_include_loop!(node)
@@ -298,4 +303,30 @@ END
298
303
  end.join("\n")
299
304
  raise Sass::SyntaxError.new(msg)
300
305
  end
306
+
307
+ def check_for_loud_silent_comment(node)
308
+ return unless node.loud && node.silent
309
+ Sass::Util.sass_warn <<MESSAGE
310
+ WARNING:
311
+ On line #{node.line}#{" of '#{node.filename}'" if node.filename}
312
+ `//` comments will no longer be allowed to use the `!` flag in Sass 3.2.
313
+ Please change to `/*` comments.
314
+ MESSAGE
315
+ end
316
+
317
+ def check_for_comment_interp(node)
318
+ return if node.loud
319
+ node.value.each do |e|
320
+ next unless e.is_a?(String)
321
+ e.scan(/(\\*)#\{/) do |esc|
322
+ Sass::Util.sass_warn <<MESSAGE if esc.first.size.even?
323
+ WARNING:
324
+ On line #{node.line}#{" of '#{node.filename}'" if node.filename}
325
+ Comments will evaluate the contents of interpolations (\#{ ... }) in Sass 3.2.
326
+ Please escape the interpolation by adding a backslash before the `#`.
327
+ MESSAGE
328
+ return
329
+ end
330
+ end
331
+ end
301
332
  end
@@ -0,0 +1,97 @@
1
+ # A visitor for setting options on the Sass tree
2
+ class Sass::Tree::Visitors::SetOptions < Sass::Tree::Visitors::Base
3
+ # @param root [Tree::Node] The root node of the tree to visit.
4
+ # @param options [{Symbol => Object}] The options has to set.
5
+ def self.visit(root, options); new(options).send(:visit, root); end
6
+
7
+ protected
8
+
9
+ def initialize(options)
10
+ @options = options
11
+ end
12
+
13
+ def visit(node)
14
+ node.instance_variable_set('@options', @options)
15
+ super
16
+ end
17
+
18
+ def visit_debug(node)
19
+ node.expr.options = @options
20
+ yield
21
+ end
22
+
23
+ def visit_each(node)
24
+ node.list.options = @options
25
+ yield
26
+ end
27
+
28
+ def visit_extend(node)
29
+ node.selector.each {|c| c.options = @options if c.is_a?(Sass::Script::Node)}
30
+ yield
31
+ end
32
+
33
+ def visit_for(node)
34
+ node.from.options = @options
35
+ node.to.options = @options
36
+ yield
37
+ end
38
+
39
+ def visit_function(node)
40
+ node.args.each do |k, v|
41
+ k.options = @options
42
+ v.options = @options if v
43
+ end
44
+ yield
45
+ end
46
+
47
+ def visit_if(node)
48
+ node.expr.options = @options if node.expr
49
+ visit(node.else) if node.else
50
+ yield
51
+ end
52
+
53
+ def visit_mixindef(node)
54
+ node.args.each do |k, v|
55
+ k.options = @options
56
+ v.options = @options if v
57
+ end
58
+ yield
59
+ end
60
+
61
+ def visit_mixin(node)
62
+ node.args.each {|a| a.options = @options}
63
+ node.keywords.each {|k, v| v.options = @options}
64
+ yield
65
+ end
66
+
67
+ def visit_prop(node)
68
+ node.name.each {|c| c.options = @options if c.is_a?(Sass::Script::Node)}
69
+ node.value.options = @options
70
+ yield
71
+ end
72
+
73
+ def visit_return(node)
74
+ node.expr.options = @options
75
+ yield
76
+ end
77
+
78
+ def visit_rule(node)
79
+ node.rule.each {|c| c.options = @options if c.is_a?(Sass::Script::Node)}
80
+ yield
81
+ end
82
+
83
+ def visit_variable(node)
84
+ node.expr.options = @options
85
+ yield
86
+ end
87
+
88
+ def visit_warn(node)
89
+ node.expr.options = @options
90
+ yield
91
+ end
92
+
93
+ def visit_while(node)
94
+ node.expr.options = @options
95
+ yield
96
+ end
97
+ end