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: Extend

Constant Summary

Constants inherited from Base

Base::NODE_NAME_RE

Instance Attribute Summary collapse

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.



14
15
16
17
# File 'lib/sass/tree/visitors/cssize.rb', line 14

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

Instance Attribute Details

#parentTree::Node (readonly, protected)

Returns the immediate parent of the current node.

Returns:



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

def parent
  @parent
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

#visit(node) (protected)

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



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

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

#visit_children(parent) (protected)

Keeps track of the current parent node.



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

def visit_children(parent)
  with_parent parent do
    parent.children = super.flatten
    parent
  end
end

#visit_extend(node) (protected)

Registers an extension in the @extends subset map.



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/sass/tree/visitors/cssize.rb', line 104

def visit_extend(node)
  node.resolved_selector.members.each do |seq|
    if seq.members.size > 1
      raise Sass::SyntaxError.new("Can't extend #{seq.to_a.join}: can't extend nested selectors")
    end

    sseq = seq.members.first
    if !sseq.is_a?(Sass::Selector::SimpleSequence)
      raise Sass::SyntaxError.new("Can't extend #{seq.to_a.join}: invalid selector")
    elsif sseq.members.any? {|ss| ss.is_a?(Sass::Selector::Parent)}
      raise Sass::SyntaxError.new("Can't extend #{seq.to_a.join}: can't extend parent selectors")
    end

    sel = sseq.members
    parent.resolved_rules.members.each do |seq|
      if !seq.members.last.is_a?(Sass::Selector::SimpleSequence)
        raise Sass::SyntaxError.new("#{seq} can't extend: invalid selector")
      end

      @extends[sel] = Extend.new(seq, sel, node, @parent_directives.dup, :not_found)
    end
  end

  []
end

#visit_import(node) (protected)

Modifies exception backtraces to include the imported file.



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

def visit_import(node)
  # Don't use #visit_children to avoid adding the import node to the list of parents.
  node.children.map {|c| visit(c)}.flatten
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_media(node) (protected)

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



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

def visit_media(node)
  yield unless bubble(node)
  media = node.children.select {|c| c.is_a?(Sass::Tree::MediaNode)}
  node.children.reject! {|c| c.is_a?(Sass::Tree::MediaNode)}
  media = media.select {|n| n.resolved_query = n.resolved_query.merge(node.resolved_query)}
  (node.children.empty? ? [] : [node]) + media
end

#visit_prop(node) (protected)

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



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

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:



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/sass/tree/visitors/cssize.rb', line 55

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 = Sass::Util.extract!(node.children) do |c|
      c.is_a?(Sass::Tree::DirectiveNode) && !c.is_a?(Sass::Tree::MediaNode) &&
        c.resolved_value =~ /^@import /i
    end
    charset_and_index = Sass::Util.ruby1_8? &&
      node.children.each_with_index.find {|c, _| c.is_a?(Sass::Tree::CharsetNode)}
    if charset_and_index
      index = charset_and_index.last
      node.children = node.children[0..index] + imports + node.children[index+1..-1]
    else
      node.children = imports + node.children
    end
  end

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

#visit_rule(node) (protected)

Resolves parent references and nested selectors, and updates the indentation of the rule node based on the nesting level.



187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/sass/tree/visitors/cssize.rb', line 187

def visit_rule(node)
  parent_resolved_rules = parent.is_a?(Sass::Tree::RuleNode) ? parent.resolved_rules : nil
  # It's possible for resolved_rules to be set if we've duplicated this node during @media bubbling
  node.resolved_rules ||= node.parsed_rules.resolve_parent_refs(parent_resolved_rules)

  yield

  rules = node.children.select {|c| c.is_a?(Sass::Tree::RuleNode) || c.bubbles?}
  props = node.children.reject {|c| c.is_a?(Sass::Tree::RuleNode) || c.bubbles? || c.invisible?}

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

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

  rules
end

#visit_supports(node) (protected)

Bubbles the @supports directive up through RuleNodes.



151
152
153
154
# File 'lib/sass/tree/visitors/cssize.rb', line 151

def visit_supports(node)
  yield unless bubble(node)
  node
end

#visit_trace(node) (protected)

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



157
158
159
160
161
162
163
164
# File 'lib/sass/tree/visitors/cssize.rb', line 157

def visit_trace(node)
  # Don't use #visit_children to avoid adding the trace node to the list of parents.
  node.children.map {|c| visit(c)}.flatten
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.



41
42
43
44
45
46
47
48
# File 'lib/sass/tree/visitors/cssize.rb', line 41

def with_parent(parent)
  @parent_directives.push parent if parent.is_a?(Sass::Tree::DirectiveNode)
  old_parent, @parent = @parent, parent
  yield
ensure
  @parent_directives.pop if parent.is_a?(Sass::Tree::DirectiveNode)
  @parent = old_parent
end