# class Sass::Tree::Visitors::CheckNesting

A visitor for checking that all nodes are properly nested.

### Constants

CONTROL_NODES
INVALID_IMPORT_PARENTS
SCRIPT_NODES
VALID_EXTEND_PARENTS
VALID_FUNCTION_CHILDREN
VALID_PROP_CHILDREN
VALID_PROP_PARENTS

### Public Class Methods

new() click to toggle source

    # File lib/sass/tree/visitors/check_nesting.rb, line 5
    def initialize
      @parents = []
      @parent = nil
      @current_mixin_def = nil
    end

### Protected Instance Methods

invalid_charset_parent?(parent, child) click to toggle source

    # File lib/sass/tree/visitors/check_nesting.rb, line 89
    def invalid_charset_parent?(parent, child)
      "@charset may only be used at the root of a document." unless parent.is_a?(Sass::Tree::RootNode)
    end

invalid_content_parent?(parent, child) click to toggle source

    # File lib/sass/tree/visitors/check_nesting.rb, line 80
    def invalid_content_parent?(parent, child)
      if @current_mixin_def
        @current_mixin_def.has_content = true
        nil
      else
        "@content may only be used within a mixin."
      end
    end

invalid_extend_parent?(parent, child) click to toggle source

    # File lib/sass/tree/visitors/check_nesting.rb, line 94
    def invalid_extend_parent?(parent, child)
      return if is_any_of?(parent, VALID_EXTEND_PARENTS)
      "Extend directives may only be used within rules."
    end

invalid_function_child?(parent, child) click to toggle source

    # File lib/sass/tree/visitors/check_nesting.rb, line 127
    def invalid_function_child?(parent, child)
      return if is_any_of?(child, VALID_FUNCTION_CHILDREN)
      "Functions can only contain variable declarations and control directives."
    end

invalid_function_parent?(parent, child) click to toggle source

    # File lib/sass/tree/visitors/check_nesting.rb, line 118
    def invalid_function_parent?(parent, child)
      return if (@parents.map {|p| p.class} & INVALID_IMPORT_PARENTS).empty?
      "Functions may not be defined within control directives or other mixins."
    end

invalid_import_parent?(parent, child) click to toggle source

    # File lib/sass/tree/visitors/check_nesting.rb, line 101
    def invalid_import_parent?(parent, child)
      unless (@parents.map {|p| p.class} & INVALID_IMPORT_PARENTS).empty?
        return "Import directives may not be used within control directives or mixins."
      end
      return if parent.is_a?(Sass::Tree::RootNode)
      return "CSS import directives may only be used at the root of a document." if child.css_import?
    rescue Sass::SyntaxError => e
      e.modify_backtrace(:filename => child.imported_file.options[:filename])
      e.add_backtrace(:filename => child.filename, :line => child.line)
      raise e
    end

invalid_mixindef_parent?(parent, child) click to toggle source

    # File lib/sass/tree/visitors/check_nesting.rb, line 113
    def invalid_mixindef_parent?(parent, child)
      return if (@parents.map {|p| p.class} & INVALID_IMPORT_PARENTS).empty?
      "Mixins may not be defined within control directives or other mixins."
    end

invalid_prop_child?(parent, child) click to toggle source

    # File lib/sass/tree/visitors/check_nesting.rb, line 135
    def invalid_prop_child?(parent, child)
      return if is_any_of?(child, VALID_PROP_CHILDREN)
      "Illegal nesting: Only properties may be nested beneath properties."
    end

invalid_prop_parent?(parent, child) click to toggle source

    # File lib/sass/tree/visitors/check_nesting.rb, line 142
    def invalid_prop_parent?(parent, child)
      return if is_any_of?(parent, VALID_PROP_PARENTS)
      "Properties are only allowed within rules, directives, mixin includes, or other properties." +
        child.pseudo_class_selector_message
    end

invalid_return_parent?(parent, child) click to toggle source

    # File lib/sass/tree/visitors/check_nesting.rb, line 148
    def invalid_return_parent?(parent, child)
      "@return may only be used within a function." unless parent.is_a?(Sass::Tree::FunctionNode)
    end

visit(node) click to toggle source
Calls superclass method Sass::Tree::Visitors::Base.visit

    # File lib/sass/tree/visitors/check_nesting.rb, line 11
    def visit(node)
      if (error = @parent && (
          try_send(@parent.class.invalid_child_method_name, @parent, node) ||
          try_send(node.class.invalid_parent_method_name, @parent, node)))
        raise Sass::SyntaxError.new(error)
      end
      super
    rescue Sass::SyntaxError => e
      e.modify_backtrace(:filename => node.filename, :line => node.line)
      raise e
    end

visit_children(parent) click to toggle source
Calls superclass method Sass::Tree::Visitors::Base#visit_children

    # File lib/sass/tree/visitors/check_nesting.rb, line 26
    def visit_children(parent)
      old_parent = @parent

      # When checking a static tree, resolve at-roots to be sure they won't send
      # nodes where they don't belong.
      if parent.is_a?(Sass::Tree::AtRootNode) && parent.resolved_value
        old_parents = @parents
        @parents = @parents.reject {|p| parent.exclude_node?(p)}
        @parent = @parents.reverse.each_with_index.
          find {|p, i| !transparent_parent?(p, @parents[-i - 2])}.first

        begin
          return super
        ensure
          @parents = old_parents
          @parent = old_parent
        end
      end

      unless transparent_parent?(parent, old_parent)
        @parent = parent
      end

      @parents.push parent
      begin
        super
      ensure
        @parent = old_parent
        @parents.pop
      end
    end

visit_import(node) { || ... } click to toggle source

    # File lib/sass/tree/visitors/check_nesting.rb, line 65
    def visit_import(node)
      yield
    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_mixindef(node) { || ... } click to toggle source

    # File lib/sass/tree/visitors/check_nesting.rb, line 73
    def visit_mixindef(node)
      @current_mixin_def, old_mixin_def = node, @current_mixin_def
      yield
    ensure
      @current_mixin_def = old_mixin_def
    end

visit_root(node) { || ... } click to toggle source

    # File lib/sass/tree/visitors/check_nesting.rb, line 58
    def visit_root(node)
      yield
    rescue Sass::SyntaxError => e
      e.sass_template ||= node.template
      raise e
    end

### Private Instance Methods

is_any_of?(val, classes) click to toggle source

    # File lib/sass/tree/visitors/check_nesting.rb, line 162
    def is_any_of?(val, classes)
      classes.each do |c|
        return true if val.is_a?(c)
      end
      false
    end

transparent_parent?(parent, grandparent) click to toggle source

Whether `parent` should be assigned to `@parent`.

    # File lib/sass/tree/visitors/check_nesting.rb, line 155
    def transparent_parent?(parent, grandparent)
      is_any_of?(parent, SCRIPT_NODES) ||
        (parent.bubbles? &&
         !grandparent.is_a?(Sass::Tree::RootNode) &&
         !grandparent.is_a?(Sass::Tree::AtRootNode))
    end

try_send(method, *args) click to toggle source

    # File lib/sass/tree/visitors/check_nesting.rb, line 169
    def try_send(method, *args)
      return unless respond_to?(method, true)
      send(method, *args)
    end