Class: Sass::Tree::Visitors::Cssize

Inherits:
Base
  • Object
show all
Defined in:
lib/sass/tree/visitors/cssize.rb

Overview

A visitor for converting a static Sass tree into a static CSS tree.

Defined Under Namespace

Classes: Bubble, Extend

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Base

node_name, #visit_if

Constructor Details

#initializeCssize (protected)

Returns a new instance of Cssize



16
17
18
19
# File 'lib/sass/tree/visitors/cssize.rb', line 16

def initialize
  @parents = []
  @extends = Sass::Util::SubsetMap.new
end

Class Method Details

.visit(root) ⇒ (Tree::Node, Sass::Util::SubsetMap)

Returns The resulting tree of static nodes and the extensions defined for this tree

Parameters:

  • root (Tree::Node)

    The root node of the tree to visit.

Returns:



6
# File 'lib/sass/tree/visitors/cssize.rb', line 6

def self.visit(root); super; end

Instance Method Details

#parentTree::Node (protected)

Returns the immediate parent of the current node.

Returns:



12
13
14
# File 'lib/sass/tree/visitors/cssize.rb', line 12

def parent
  @parents.last
end

#visit(node) (protected)

If an exception is raised, this adds proper metadata to the backtrace.



22
23
24
25
26
27
# File 'lib/sass/tree/visitors/cssize.rb', line 22

def visit(node)
  super(node)
rescue Sass::SyntaxError => e
  e.modify_backtrace(:filename => node.filename, :line => node.line)
  raise e
end

#visit_atroot(node) (protected)



168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/sass/tree/visitors/cssize.rb', line 168

def visit_atroot(node)
  # If there aren't any more directives or rules that this @at-root needs to
  # exclude, we can get rid of it and just evaluate the children.
  if @parents.none? {|n| node.exclude_node?(n)}
    results = visit_children_without_parent(node)
    results.each {|c| c.tabs += node.tabs if bubblable?(c)}
    if !results.empty? && bubblable?(results.last)
      results.last.group_end = node.group_end
    end
    return results
  end

  # If this @at-root excludes the immediate parent, return it as-is so that it
  # can be bubbled up by the parent node.
  return Bubble.new(node) if node.exclude_node?(parent)

  # Otherwise, duplicate the current parent and move it into the @at-root
  # node. As above, returning an @at-root node signals to the parent directive
  # that it should be bubbled upwards.
  bubble(node)
end

#visit_children(parent) (protected)

Keeps track of the current parent node.



30
31
32
33
34
35
# File 'lib/sass/tree/visitors/cssize.rb', line 30

def visit_children(parent)
  with_parent parent do
    parent.children = visit_children_without_parent(parent)
    parent
  end
end

#visit_children_without_parent(node) ⇒ Array<Sass::Tree::Node> (protected)

Like #visit_children, but doesn't set #parent.

Parameters:

Returns:

  • (Array<Sass::Tree::Node>)

    the flattened results of visiting all the children of node



42
43
44
# File 'lib/sass/tree/visitors/cssize.rb', line 42

def visit_children_without_parent(node)
  node.children.map {|c| visit(c)}.flatten
end

#visit_directive(node) (protected)

Bubbles a directive up through RuleNodes.



223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
# File 'lib/sass/tree/visitors/cssize.rb', line 223

def visit_directive(node)
  return node unless node.has_children
  if parent.is_a?(Sass::Tree::RuleNode)
    # @keyframes shouldn't include the rule nodes, so we manually create a
    # bubble that doesn't have the parent's contents for them.
    return node.normalized_name == '@keyframes' ? Bubble.new(node) : bubble(node)
  end

  yield

  # Since we don't know if the mere presence of an unknown directive may be
  # important, we should keep an empty version around even if all the contents
  # are removed via @at-root. However, if the contents are just bubbled out,
  # we don't need to do so.
  directive_exists = node.children.any? do |child|
    next true unless child.is_a?(Bubble)
    next false unless child.node.is_a?(Sass::Tree::DirectiveNode)
    child.node.resolved_value == node.resolved_value
  end

  # We know empty @keyframes directives do nothing.
  if directive_exists || node.name == '@keyframes'
    []
  else
    empty_node = node.dup
    empty_node.children = []
    [empty_node]
  end + debubble(node.children, node)
end

#visit_extend(node) (protected)

Registers an extension in the @extends subset map.



125
126
127
128
129
# File 'lib/sass/tree/visitors/cssize.rb', line 125

def visit_extend(node)
  parent.resolved_rules.populate_extends(@extends, node.resolved_selector, node,
    @parents.select {|p| p.is_a?(Sass::Tree::DirectiveNode)})
  []
end

#visit_import(node) (protected)

Modifies exception backtraces to include the imported file.



132
133
134
135
136
137
138
# File 'lib/sass/tree/visitors/cssize.rb', line 132

def visit_import(node)
  visit_children_without_parent(node)
rescue Sass::SyntaxError => e
  e.modify_backtrace(:filename => node.children.first.filename)
  e.add_backtrace(:filename => node.filename, :line => node.line)
  raise e
end

#visit_keyframerule(node) (protected)



214
215
216
217
218
219
220
# File 'lib/sass/tree/visitors/cssize.rb', line 214

def visit_keyframerule(node)
  return node unless node.has_children

  yield

  debubble(node.children, node)
end

#visit_media(node) (protected)

Bubbles the @media directive up through RuleNodes and merges it with other @media directives.



255
256
257
258
259
260
261
262
263
264
265
266
267
268
# File 'lib/sass/tree/visitors/cssize.rb', line 255

def visit_media(node)
  return bubble(node) if parent.is_a?(Sass::Tree::RuleNode)
  return Bubble.new(node) if parent.is_a?(Sass::Tree::MediaNode)

  yield

  debubble(node.children, node) do |child|
    next child unless child.is_a?(Sass::Tree::MediaNode)
    # Copies of `node` can be bubbled, and we don't want to merge it with its
    # own query.
    next child if child.resolved_query == node.resolved_query
    next child if child.resolved_query = child.resolved_query.merge(node.resolved_query)
  end
end

#visit_prop(node) (protected)

Converts nested properties into flat properties and updates the indentation of the prop node based on the nesting level.



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/sass/tree/visitors/cssize.rb', line 151

def visit_prop(node)
  if parent.is_a?(Sass::Tree::PropNode)
    node.resolved_name = "#{parent.resolved_name}-#{node.resolved_name}"
    node.tabs = parent.tabs + (parent.resolved_value.empty? ? 0 : 1) if node.style == :nested
  end

  yield

  result = node.children.dup
  if !node.resolved_value.empty? || node.children.empty?
    node.send(:check!)
    result.unshift(node)
  end

  result
end

#visit_root(node) ⇒ (Tree::Node, Sass::Util::SubsetMap) (protected)

In Ruby 1.8, ensures that there's only one @charset directive and that it's at the top of the document.

Returns:



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/sass/tree/visitors/cssize.rb', line 64

def visit_root(node)
  yield

  if parent.nil?
    # In Ruby 1.9 we can make all @charset nodes invisible
    # and infer the final @charset from the encoding of the final string.
    if Sass::Util.ruby1_8?
      charset = node.children.find {|c| c.is_a?(Sass::Tree::CharsetNode)}
      node.children.reject! {|c| c.is_a?(Sass::Tree::CharsetNode)}
      node.children.unshift charset if charset
    end

    imports_to_move = []
    import_limit = nil
    i = -1
    node.children.reject! do |n|
      i += 1
      if import_limit
        next false unless n.is_a?(Sass::Tree::CssImportNode)
        imports_to_move << n
        next true
      end

      if !n.is_a?(Sass::Tree::CommentNode) &&
          !n.is_a?(Sass::Tree::CharsetNode) &&
          !n.is_a?(Sass::Tree::CssImportNode)
        import_limit = i
      end

      false
    end

    if import_limit
      node.children = node.children[0...import_limit] + imports_to_move +
        node.children[import_limit..-1]
    end
  end

  return node, @extends
rescue Sass::SyntaxError => e
  e.sass_template ||= node.template
  raise e
end

#visit_rule(node) (protected)

Updates the indentation of the rule node based on the nesting level. The selectors were resolved in Perform.



195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/sass/tree/visitors/cssize.rb', line 195

def visit_rule(node)
  yield

  rules = node.children.select {|c| bubblable?(c)}
  props = node.children.reject {|c| bubblable?(c) || c.invisible?}

  unless props.empty?
    node.children = props
    rules.each {|r| r.tabs += 1} if node.style == :nested
    rules.unshift(node)
  end

  rules = debubble(rules)
  unless parent.is_a?(Sass::Tree::RuleNode) || rules.empty? || !bubblable?(rules.last)
    rules.last.group_end = true
  end
  rules
end

#visit_supports(node) (protected)

Bubbles the @supports directive up through RuleNodes.



271
272
273
274
275
276
277
278
# File 'lib/sass/tree/visitors/cssize.rb', line 271

def visit_supports(node)
  return node unless node.has_children
  return bubble(node) if parent.is_a?(Sass::Tree::RuleNode)

  yield

  debubble(node.children, node)
end

#visit_trace(node) (protected)

Asserts that all the traced children are valid in their new location.



141
142
143
144
145
146
147
# File 'lib/sass/tree/visitors/cssize.rb', line 141

def visit_trace(node)
  visit_children_without_parent(node)
rescue Sass::SyntaxError => e
  e.modify_backtrace(:mixin => node.name, :filename => node.filename, :line => node.line)
  e.add_backtrace(:filename => node.filename, :line => node.line)
  raise e
end

#with_parent(parent) { ... } ⇒ Object (protected)

Runs a block of code with the current parent node replaced with the given node.

Parameters:

  • parent (Tree::Node)

    The new parent for the duration of the block.

Yields:

  • A block in which the parent is set to parent.

Returns:

  • (Object)

    The return value of the block.



52
53
54
55
56
57
# File 'lib/sass/tree/visitors/cssize.rb', line 52

def with_parent(parent)
  @parents.push parent
  yield
ensure
  @parents.pop
end