class Sass::Tree::Visitors::Cssize - sass-3.2.19 Documentation

# class Sass::Tree::Visitors::Cssize

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

### Constants

Extend

  A simple struct wrapping up information about a single `@extend` instance. A single [ExtendNode] can have multiple Extends if either the parent node or the extended selector is a comma sequence.

  @attr extender [Sass::Selector::Sequence]

      The selector of the CSS rule containing the `@extend`.

  @attr target [Array<Sass::Selector::Simple>] The selector being `@extend`ed. @attr node [Sass::Tree::ExtendNode] The node that produced this extend. @attr directives [Array<Sass::Tree::DirectiveNode>]

      The directives containing the `@extend`.

  @attr result [Symbol]

      The result of this extend. One of `:not_found` (the target doesn't exist
      in the document), `:failed_to_unify` (the target exists but cannot be
      unified with the extender), or `:succeeded`.

MERGEABLE_DIRECTIVES

### Attributes

parent[R]

Returns the immediate parent of the current node. @return [Tree::Node]

### Public Class Methods

new() click to toggle source

    # File lib/sass/tree/visitors/cssize.rb, line 14
    def initialize
      @parent_directives = []
      @extends = Sass::Util::SubsetMap.new
    end

visit(root) click to toggle source

@param root [Tree::Node] The root node of the tree to visit. @return [(Tree::Node, Sass::Util::SubsetMap)] The resulting tree of static nodes

    *and* the extensions defined for this tree

Calls superclass method Sass::Tree::Visitors::Base.visit

    # File lib/sass/tree/visitors/cssize.rb, line 6
    def self.visit(root); super; end

### Protected Instance Methods

visit(node) click to toggle source

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

Calls superclass method Sass::Tree::Visitors::Base.visit

    # 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) click to toggle source

Keeps track of the current parent node.

Calls superclass method Sass::Tree::Visitors::Base#visit_children

    # 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) click to toggle source

Registers an extension in the `@extends` subset map.

    # 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) click to toggle source

Modifies exception backtraces to include the imported file.

    # 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) { || ... } click to toggle source

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

    # 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) { || ... } click to toggle source

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

    # 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) { || ... } click to toggle source

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

@return [(Tree::Node, Sass::Util::SubsetMap)] The resulting tree of static nodes

    *and* the extensions defined for this tree

    # 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) { || ... } click to toggle source

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

    # 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) { || ... } click to toggle source

Bubbles the `@supports` directive up through RuleNodes.

    # File lib/sass/tree/visitors/cssize.rb, line 172
    def visit_supports(node)
      yield unless bubble(node)
      node
    end

visit_trace(node) click to toggle source

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

    # 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) { || ... } click to toggle source

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

@param parent [Tree::Node] The new parent for the duration of the block. @yield A block in which the parent is set to `parent`. @return [Object] The return value of the block.

    # 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

### Private Instance Methods

bubble(node) click to toggle source

    # File lib/sass/tree/visitors/cssize.rb, line 231
    def bubble(node)
      return unless parent.is_a?(Sass::Tree::RuleNode)
      new_rule = parent.dup
      new_rule.children = node.children
      node.children = with_parent(node) {Array(visit(new_rule))}
      # If the last child is actually the end of the group,
      # the parent's cssize will set it properly
      node.children.last.group_end = false unless node.children.empty?
      true
    end