require 'sass/tree/node' module Sass::Tree # A static node representing a mixin include. # When in a static tree, the sole purpose is to wrap exceptions # to add the mixin to the backtrace. # # @see Sass::Tree class MixinNode < Node # @see Node#options= def options=(opts) super @args.each {|a| a.context = :equals} if opts[:sass2] end # @param name [String] The name of the mixin # @param args [Array] The arguments to the mixin def initialize(name, args) @name = name @args = args super() end # @see Node#cssize def cssize(extends, parent = nil) _cssize(extends, parent) # Pass on the parent even if it's not a MixinNode end protected # Returns an error message if the given child node is invalid, # and false otherwise. # # {ExtendNode}s are valid within {MixinNode}s. # # @param child [Tree::Node] A potential child node # @return [Boolean, String] Whether or not the child node is valid, # as well as the error message to display if it is invalid def invalid_child?(child) super unless child.is_a?(ExtendNode) end # @see Node#to_src def to_src(tabs, opts, fmt) args = '(' + @args.map {|a| a.to_sass(opts)}.join(", ") + ')' unless @args.empty? "#{' ' * tabs}#{fmt == :sass ? '+' : '@include '}#{dasherize(@name, opts)}#{args}#{semi fmt}\n" end # @see Node#_cssize def _cssize(extends, parent) children.map do |c| parent.check_child! c c.cssize(extends, parent) end.flatten rescue Sass::SyntaxError => e e.modify_backtrace(:mixin => @name, :filename => filename, :line => line) e.add_backtrace(:filename => filename, :line => line) raise e end # Runs the mixin. # # @param environment [Sass::Environment] The lexical environment containing # variable and mixin values # @raise [Sass::SyntaxError] if there is no mixin with the given name # @raise [Sass::SyntaxError] if an incorrect number of arguments was passed # @see Sass::Tree def perform!(environment) handle_include_loop!(environment) if environment.mixins_in_use.include?(@name) original_env = environment original_env.push_frame(:filename => filename, :line => line) original_env.prepare_frame(:mixin => @name) raise Sass::SyntaxError.new("Undefined mixin '#{@name}'.") unless mixin = environment.mixin(@name) raise Sass::SyntaxError.new(< e if original_env # Don't add backtrace info if this is an @include loop e.modify_backtrace(:mixin => @name, :line => @line) e.add_backtrace(:line => @line) end raise e ensure original_env.pop_frame if original_env end private def handle_include_loop!(environment) msg = "An @include loop has been found:" mixins = environment.stack.map {|s| s[:mixin]}.compact if mixins.size == 2 && mixins[0] == mixins[1] raise Sass::SyntaxError.new("#{msg} #{@name} includes itself") end mixins << @name msg << "\n" << Sass::Util.enum_cons(mixins, 2).map do |m1, m2| " #{m1} includes #{m2}" end.join("\n") raise Sass::SyntaxError.new(msg) end end end