haml-edge 2.3.93 → 2.3.94

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.
@@ -8,16 +8,16 @@ module Sass
8
8
  class Lexer
9
9
  # A struct containing information about an individual token.
10
10
  #
11
- # `type`: [{Symbol}]
11
+ # `type`: \[{Symbol}\]
12
12
  # : The type of token.
13
13
  #
14
- # `value`: [{Object}]
14
+ # `value`: \[{Object}\]
15
15
  # : The Ruby object corresponding to the value of the token.
16
16
  #
17
- # `line`: [{Fixnum}]
17
+ # `line`: \[{Fixnum}\]
18
18
  # : The line of the source file on which the token appears.
19
19
  #
20
- # `offset`: [{Fixnum}]
20
+ # `offset`: \[{Fixnum}\]
21
21
  # : The number of bytes into the line the SassScript token appeared.
22
22
  Token = Struct.new(:type, :value, :line, :offset)
23
23
 
@@ -55,7 +55,7 @@ module Sass
55
55
  :variable => /!([\w-]+)/,
56
56
  :ident => /(\\.|[^\s\\+*\/%(),=!])+/,
57
57
  :number => /(-)?(?:(\d*\.\d+)|(\d+))([a-zA-Z%]+)?/,
58
- :color => /\##{"([0-9a-fA-F]{1,2})" * 3}|(#{Color::HTML4_COLORS.keys.join("|")})(?!\()/,
58
+ :color => /\##{"([0-9a-fA-F]{1,2})" * 3}|(#{Color::HTML4_COLORS.keys.join("|")})(?![^\s+*\/%),=!])/,
59
59
  :bool => /(true|false)\b/,
60
60
  :op => %r{(#{Regexp.union(*OP_NAMES.map{|s| Regexp.new(Regexp.escape(s) + (s =~ /\w$/ ? '(?:\b|$)' : ''))})})}
61
61
  }
@@ -46,9 +46,9 @@ module Sass::Tree
46
46
  if was_prop
47
47
  result[-1] = "\n"
48
48
  end
49
- rendered = child.to_s(tabs + 1)
50
- rendered.lstrip! if first
51
- result << rendered
49
+ rendered = child.to_s(tabs + 1).dup
50
+ rendered = rendered.lstrip if first
51
+ result << rendered.rstrip + "\n"
52
52
  end
53
53
  was_prop = child.is_a?(PropNode)
54
54
  first = false
@@ -14,24 +14,35 @@ module Sass
14
14
 
15
15
  protected
16
16
 
17
- # Computes the CSS for the imported file.
18
- #
19
- # @param args [Array] Ignored
20
- def _to_s(*args)
21
- @to_s ||= (style == :compressed ? super.strip : super)
17
+ # @see Node#_cssize
18
+ def _cssize(*args)
19
+ super.children
22
20
  rescue Sass::SyntaxError => e
23
21
  e.modify_backtrace(:filename => children.first.filename)
24
22
  e.add_backtrace(:filename => @filename, :line => @line)
25
23
  raise e
26
24
  end
27
25
 
28
- # Parses the imported file
29
- # and runs the dynamic Sass for it.
26
+ # Returns a static DirectiveNode if this is importing a CSS file,
27
+ # or parses and includes the imported Sass file.
30
28
  #
31
29
  # @param environment [Sass::Environment] The lexical environment containing
32
30
  # variable and mixin values
33
- def perform!(environment)
34
- return unless full_filename = import
31
+ def _perform(environment)
32
+ full_filename = import
33
+ return DirectiveNode.new("@import url(#{full_filename})") if full_filename =~ /\.css$/
34
+
35
+ node = dup
36
+ node.perform!(environment, full_filename)
37
+ node
38
+ end
39
+
40
+ # Parses the imported file and runs the dynamic Sass for it.
41
+ #
42
+ # @param environment [Sass::Environment] The lexical environment containing
43
+ # variable and mixin values
44
+ # @param full_filename [String] The full path to the Sass file to import
45
+ def perform!(environment, full_filename)
35
46
  root = Sass::Files.tree_for(full_filename, @options)
36
47
  @template = root.template
37
48
  self.children = root.children
@@ -51,18 +62,9 @@ module Sass
51
62
  end
52
63
 
53
64
  def import
54
- begin
55
- full_filename = Sass::Files.find_file_to_import(@imported_filename, import_paths)
56
- rescue Exception => e
57
- raise SyntaxError.new(e.message, :line => self.line, :filename => @filename)
58
- end
59
-
60
- if full_filename =~ /\.css$/
61
- @to_s = "@import url(#{full_filename});"
62
- return false
63
- end
64
-
65
- return full_filename
65
+ Sass::Files.find_file_to_import(@imported_filename, import_paths)
66
+ rescue Exception => e
67
+ raise SyntaxError.new(e.message, :line => self.line, :filename => @filename)
66
68
  end
67
69
  end
68
70
  end
@@ -1,7 +1,9 @@
1
1
  require 'sass/tree/node'
2
2
 
3
3
  module Sass::Tree
4
- # A dynamic node representing a mixin include.
4
+ # A static node representing a mixin include.
5
+ # When in a static tree, the sole purpose is to wrap exceptions
6
+ # to add the mixin to the backtrace.
5
7
  #
6
8
  # @see Sass::Tree
7
9
  class MixinNode < Node
@@ -13,17 +15,30 @@ module Sass::Tree
13
15
  super()
14
16
  end
15
17
 
18
+ # @see Node#cssize
19
+ def cssize(parent = nil)
20
+ _cssize(parent) # Pass on the parent even if it's not a MixinNode
21
+ end
22
+
16
23
  protected
17
24
 
25
+ # @see Node#_cssize
26
+ def _cssize(parent)
27
+ children.map {|c| c.cssize(parent)}.flatten
28
+ rescue Sass::SyntaxError => e
29
+ e.modify_backtrace(:mixin => @name, :line => line)
30
+ e.add_backtrace(:filename => filename, :line => line)
31
+ raise e
32
+ end
33
+
18
34
  # Runs the mixin.
19
35
  #
20
36
  # @param environment [Sass::Environment] The lexical environment containing
21
37
  # variable and mixin values
22
- # @return [Array<Tree::Node>] The resulting static nodes
23
38
  # @raise [Sass::SyntaxError] if there is no mixin with the given name
24
39
  # @raise [Sass::SyntaxError] if an incorrect number of arguments was passed
25
40
  # @see Sass::Tree
26
- def _perform(environment)
41
+ def perform!(environment)
27
42
  raise Sass::SyntaxError.new("Undefined mixin '#{@name}'.") unless mixin = environment.mixin(@name)
28
43
 
29
44
  raise Sass::SyntaxError.new(<<END.gsub("\n", "")) if mixin.args.size < @args.size
@@ -42,7 +57,12 @@ END
42
57
  raise Sass::SyntaxError.new("Mixin #{@name} is missing parameter #{var.inspect}.") unless env.var(var.name)
43
58
  env
44
59
  end
45
- mixin.tree.map {|c| c.perform(environment)}.flatten
60
+
61
+ self.children = mixin.tree.map {|c| c.perform(environment)}.flatten
62
+ rescue Sass::SyntaxError => e
63
+ e.modify_backtrace(:mixin => @name, :line => @line)
64
+ e.add_backtrace(:line => @line)
65
+ raise e
46
66
  end
47
67
  end
48
68
  end
@@ -1,19 +1,28 @@
1
1
  module Sass
2
2
  # A namespace for nodes in the Sass parse tree.
3
3
  #
4
- # The Sass parse tree has two states.
5
- # When it's first parsed, it has nodes for mixin definitions
6
- # and for loops and so forth,
4
+ # The Sass parse tree has three states: dynamic, static Sass, and static CSS.
5
+ #
6
+ # When it's first parsed, a Sass document is in the dynamic state.
7
+ # It has nodes for mixin definitions and `@for` loops and so forth,
7
8
  # in addition to nodes for CSS rules and properties.
9
+ # Nodes that only appear in this state are called **dynamic nodes**.
8
10
  #
9
- # However, {Tree::Node#perform} returns a different sort of tree.
10
- # This tree maps more closely to the resulting CSS document
11
- # than it does to the original Sass document.
12
- # It still has nodes for CSS rules and properties,
11
+ # {Tree::Node#perform} returns a static Sass tree, which is different.
12
+ # It still has nodes for CSS rules and properties
13
13
  # but it doesn't have any dynamic-generation-related nodes.
14
+ # The nodes in this state are in the same structure as the Sass document:
15
+ # rules and properties are nested beneath one another.
16
+ # Nodes that can be in this state or in the dynamic state
17
+ # are called **static nodes**.
18
+ #
19
+ # {Tree::Node#cssize} then returns a static CSS tree.
20
+ # This is like a static Sass tree,
21
+ # but the structure exactly mirrors that of the generated CSS.
22
+ # Rules and properties can't be nested beneath one another in this state.
14
23
  #
15
- # Nodes that only appear in the pre-perform state are called **dynamic nodes**;
16
- # those that appear in both states are called **static nodes**.
24
+ # Finally, {Tree::Node#to_s} can be called on a static CSS tree
25
+ # to get the actual CSS code as a string.
17
26
  module Tree
18
27
  # The abstract superclass of all parse-tree nodes.
19
28
  class Node
@@ -99,7 +108,7 @@ module Sass
99
108
  # @see #perform
100
109
  # @see #to_s
101
110
  def render
102
- perform(Environment.new).to_s
111
+ perform(Environment.new).cssize.to_s
103
112
  end
104
113
 
105
114
  # True if \{#to\_s} will return `nil`;
@@ -116,15 +125,15 @@ module Sass
116
125
  @options[:style]
117
126
  end
118
127
 
119
- # Computes the CSS corresponding to this Sass tree.
128
+ # Computes the CSS corresponding to this static CSS tree.
120
129
  #
130
+ # \{#to_s} shouldn't be overridden directly; instead, override \{#\_to\_s}.
121
131
  # Only static-node subclasses need to implement \{#to\_s}.
122
132
  #
123
133
  # This may return `nil`, but it will only do so if \{#invisible?} is true.
124
134
  #
125
135
  # @param args [Array] Passed on to \{#\_to\_s}
126
136
  # @return [String, nil] The resulting CSS
127
- # @raise [Sass::SyntaxError] if some element of the tree is invalid
128
137
  # @see Sass::Tree
129
138
  def to_s(*args)
130
139
  _to_s(*args)
@@ -133,15 +142,31 @@ module Sass
133
142
  raise e
134
143
  end
135
144
 
136
- # Runs the dynamic Sass code:
145
+ # Converts a static Sass tree (e.g. the output of \{#perform})
146
+ # into a static CSS tree.
147
+ #
148
+ # \{#cssize} shouldn't be overridden directly;
149
+ # instead, override \{#\_cssize} or \{#cssize!}.
150
+ #
151
+ # @param parent [Node, nil] The parent node of this node.
152
+ # This should only be non-nil if the parent is the same class as this node
153
+ # @return [Tree::Node] The resulting tree of static nodes
154
+ # @raise [Sass::SyntaxError] if some element of the tree is invalid
155
+ # @see Sass::Tree
156
+ def cssize(parent = nil)
157
+ _cssize((parent if parent.class == self.class))
158
+ rescue Sass::SyntaxError => e
159
+ e.modify_backtrace(:filename => filename, :line => line)
160
+ raise e
161
+ end
162
+
163
+ # Converts a dynamic tree into a static Sass tree.
164
+ # That is, runs the dynamic Sass code:
137
165
  # mixins, variables, control directives, and so forth.
138
166
  # This doesn't modify this node or any of its children.
139
167
  #
140
168
  # \{#perform} shouldn't be overridden directly;
141
- # if you want to return a new node (or list of nodes),
142
- # override \{#\_perform};
143
- # if you want to destructively modify this node,
144
- # override \{#perform!}.
169
+ # instead, override \{#\_perform} or \{#perform!}.
145
170
  #
146
171
  # @param environment [Sass::Environment] The lexical environment containing
147
172
  # variable and mixin values
@@ -159,15 +184,46 @@ module Sass
159
184
 
160
185
  # Computes the CSS corresponding to this particular Sass node.
161
186
  #
187
+ # This method should never raise {Sass::SyntaxError}s.
188
+ # Such errors will not be properly annotated with Sass backtrace information.
189
+ # All error conditions should be checked in earlier transformations,
190
+ # such as \{#cssize} and \{#perform}.
191
+ #
162
192
  # @param args [Array] ignored
163
193
  # @return [String, nil] The resulting CSS
164
- # @raise [Sass::SyntaxError] if some element of the tree is invalid
165
194
  # @see #to_s
166
195
  # @see Sass::Tree
167
196
  def _to_s
168
197
  raise NotImplementedError.new("All static-node subclasses of Sass::Tree::Node must override #_to_s or #to_s.")
169
198
  end
170
199
 
200
+ # Converts this static Sass node into a static CSS node,
201
+ # returning the new node.
202
+ # This doesn't modify this node or any of its children.
203
+ #
204
+ # @param parent [Node, nil] The parent node of this node.
205
+ # This should only be non-nil if the parent is the same class as this node
206
+ # @return [Tree::Node, Array<Tree::Node>] The resulting static CSS nodes
207
+ # @raise [Sass::SyntaxError] if some element of the tree is invalid
208
+ # @see #cssize
209
+ # @see Sass::Tree
210
+ def _cssize(parent)
211
+ node = dup
212
+ node.cssize!(parent)
213
+ node
214
+ end
215
+
216
+ # Destructively converts this static Sass node into a static CSS node.
217
+ # This *does* modify this node,
218
+ # but will be run non-destructively by \{#\_cssize\}.
219
+ #
220
+ # @param parent [Node, nil] The parent node of this node.
221
+ # This should only be non-nil if the parent is the same class as this node
222
+ # @see #cssize
223
+ def cssize!(parent)
224
+ self.children = children.map {|c| c.cssize(self)}.flatten
225
+ end
226
+
171
227
  # Runs any dynamic Sass code in this particular node.
172
228
  # This doesn't modify this node or any of its children.
173
229
  #
@@ -18,13 +18,13 @@ module Sass::Tree
18
18
  # relative to a normal property.
19
19
  # This is only greater than 0 in the case that:
20
20
  #
21
- # * This node is in a static tree
21
+ # * This node is in a CSS tree
22
22
  # * The style is :nested
23
23
  # * This is a child property of another property
24
24
  # * The parent property has a value, and thus will be rendered
25
25
  #
26
26
  # @return [Fixnum]
27
- attr_accessor :indentation
27
+ attr_accessor :tabs
28
28
 
29
29
  # @param name [String] See \{#name}
30
30
  # @param value [String] See \{#value}
@@ -33,7 +33,7 @@ module Sass::Tree
33
33
  def initialize(name, value, prop_syntax)
34
34
  @name = name
35
35
  @value = value
36
- @indentation = 0
36
+ @tabs = 0
37
37
  @prop_syntax = prop_syntax
38
38
  super()
39
39
  end
@@ -63,34 +63,37 @@ module Sass::Tree
63
63
  #
64
64
  # @param tabs [Fixnum] The level of indentation for the CSS
65
65
  # @return [String] The resulting CSS
66
- # @raise [Sass::SyntaxError] if the property uses invalid syntax
67
66
  def _to_s(tabs)
68
- if @options[:property_syntax] == :old && @prop_syntax == :new
69
- raise Sass::SyntaxError.new("Illegal property syntax: can't use new syntax when :property_syntax => :old is set.")
70
- elsif @options[:property_syntax] == :new && @prop_syntax == :old
71
- raise Sass::SyntaxError.new("Illegal property syntax: can't use old syntax when :property_syntax => :new is set.")
72
- elsif value[-1] == ?;
73
- raise Sass::SyntaxError.new("Invalid property: #{declaration.dump} (no \";\" required at end-of-line).")
74
- elsif value.empty?
75
- raise Sass::SyntaxError.new("Invalid property: #{declaration.dump} (no value)." +
76
- pseudo_class_selector_message)
77
- end
78
-
79
- to_return = ' ' * (tabs - 1 + indentation) + name + ":" +
67
+ to_return = ' ' * (tabs - 1 + self.tabs) + name + ":" +
80
68
  (style == :compressed ? '' : ' ') + value + (style == :compressed ? "" : ";")
81
69
  end
82
70
 
83
- # Returns this node's fully-resolved child properties, and/or this node.
71
+ # Converts nested properties into flat properties.
84
72
  #
85
- # @param environment [Sass::Environment] The lexical environment containing
86
- # variable and mixin values
87
- def _perform(environment)
73
+ # @param parent [PropNode, nil] The parent node of this node,
74
+ # or nil if the parent isn't a {PropNode}
75
+ # @raise [Sass::SyntaxError] if the property uses invalid syntax
76
+ def _cssize(parent)
88
77
  node = super
89
78
  result = node.children.dup
90
- result.unshift(node) if !node.value.empty? || node.children.empty?
79
+ if !node.value.empty? || node.children.empty?
80
+ node.send(:check!)
81
+ result.unshift(node)
82
+ end
91
83
  result
92
84
  end
93
85
 
86
+ # Updates the name and indentation of this node based on the parent name
87
+ # and nesting level.
88
+ #
89
+ # @param parent [PropNode, nil] The parent node of this node,
90
+ # or nil if the parent isn't a {PropNode}
91
+ def cssize!(parent)
92
+ self.name = "#{parent.name}-#{name}" if parent
93
+ self.tabs = parent.tabs + (parent.value.empty? ? 0 : 1) if parent && style == :nested
94
+ super
95
+ end
96
+
94
97
  # Runs any SassScript that may be embedded in the property,
95
98
  # and invludes the parent property, if any.
96
99
  #
@@ -100,12 +103,6 @@ module Sass::Tree
100
103
  @name = interpolate(@name, environment)
101
104
  @value = @value.is_a?(String) ? interpolate(@value, environment) : @value.perform(environment).to_s
102
105
  super
103
- # Once we've called super, the child nodes have been dup'ed
104
- # so we can destructively modify them
105
- children.select {|c| c.is_a?(PropNode)}.each do |c|
106
- c.name = "#{name}-#{c.name}"
107
- c.indentation += 1 if style == :nested && !@value.empty?
108
- end
109
106
  end
110
107
 
111
108
  # Returns an error message if the given child node is invalid,
@@ -122,6 +119,19 @@ module Sass::Tree
122
119
 
123
120
  private
124
121
 
122
+ def check!
123
+ if @options[:property_syntax] == :old && @prop_syntax == :new
124
+ raise Sass::SyntaxError.new("Illegal property syntax: can't use new syntax when :property_syntax => :old is set.")
125
+ elsif @options[:property_syntax] == :new && @prop_syntax == :old
126
+ raise Sass::SyntaxError.new("Illegal property syntax: can't use old syntax when :property_syntax => :new is set.")
127
+ elsif value[-1] == ?;
128
+ raise Sass::SyntaxError.new("Invalid property: #{declaration.dump} (no \";\" required at end-of-line).")
129
+ elsif value.empty?
130
+ raise Sass::SyntaxError.new("Invalid property: #{declaration.dump} (no value)." +
131
+ pseudo_class_selector_message)
132
+ end
133
+ end
134
+
125
135
  def declaration
126
136
  (@prop_syntax == :new ? "#{name}: #{value}" : ":#{name} #{value}").strip
127
137
  end
@@ -13,7 +13,7 @@ module Sass
13
13
  @template = template
14
14
  end
15
15
 
16
- # @see \{Node#to\_s}
16
+ # @see Node#to_s
17
17
  def to_s(*args)
18
18
  super
19
19
  rescue Sass::SyntaxError => e
@@ -21,7 +21,7 @@ module Sass
21
21
  raise e
22
22
  end
23
23
 
24
- # @see \{Node#perform}
24
+ # @see Node#perform
25
25
  def perform(environment)
26
26
  environment.options = @options if environment.options.nil? || environment.options.empty?
27
27
  super
@@ -30,23 +30,38 @@ module Sass
30
30
  raise e
31
31
  end
32
32
 
33
+ # @see Node#cssize
34
+ def cssize(*args)
35
+ super
36
+ rescue Sass::SyntaxError => e
37
+ e.sass_template = @template
38
+ raise e
39
+ end
40
+
33
41
  protected
34
42
 
43
+ # Destructively converts this static Sass node into a static CSS node,
44
+ # and checks that there are no properties at root level.
45
+ #
46
+ # @param parent [Node, nil] The parent node of this node.
47
+ # This should only be non-nil if the parent is the same class as this node
48
+ # @see Node#cssize!
49
+ def cssize!(parent)
50
+ super
51
+ return unless child = children.find {|c| c.is_a?(PropNode)}
52
+ message = "Properties aren't allowed at the root of a document." +
53
+ child.pseudo_class_selector_message
54
+ raise Sass::SyntaxError.new(message, :line => child.line)
55
+ end
56
+
35
57
  # Computes the CSS corresponding to this Sass tree.
36
58
  #
37
59
  # @param args [Array] ignored
38
60
  # @return [String] The resulting CSS
39
- # @raise [Sass::SyntaxError] if some element of the tree is invalid
40
61
  # @see Sass::Tree
41
62
  def _to_s(*args)
42
63
  result = String.new
43
64
  children.each do |child|
44
- if child.is_a? PropNode
45
- message = "Properties aren't allowed at the root of a document." +
46
- child.pseudo_class_selector_message
47
- raise Sass::SyntaxError.new(message, :line => child.line)
48
- end
49
-
50
65
  next if child.invisible?
51
66
  child_str = child.to_s(1)
52
67
  result << child_str + (style == :compressed ? '' : "\n")