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 collapse

MERGEABLE_DIRECTIVES =
[Sass::Tree::MediaNode]

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.



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/sass/tree/visitors/cssize.rb', line 125

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 |member|
      if !member.members.last.is_a?(Sass::Selector::SimpleSequence)
        raise Sass::SyntaxError.new("#{member} can't extend: invalid selector")
      end

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

  []
end

#visit_import(node) (protected)

Modifies exception backtraces to include the imported file.



152
153
154
155
156
157
158
159
# File 'lib/sass/tree/visitors/cssize.rb', line 152

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.



163
164
165
166
167
168
169
# File 'lib/sass/tree/visitors/cssize.rb', line 163

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.



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

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)

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



208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
# File 'lib/sass/tree/visitors/cssize.rb', line 208

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.



172
173
174
175
# File 'lib/sass/tree/visitors/cssize.rb', line 172

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.



178
179
180
181
182
183
184
185
# File 'lib/sass/tree/visitors/cssize.rb', line 178

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.



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/sass/tree/visitors/cssize.rb', line 43

def with_parent(parent)
  if parent.is_a?(Sass::Tree::DirectiveNode)
    if MERGEABLE_DIRECTIVES.any? {|klass| parent.is_a?(klass)}
      old_parent_directive = @parent_directives.pop
    end
    @parent_directives.push parent
  end

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