Commit 4c175471 authored by Rene Saarsoo's avatar Rene Saarsoo
Browse files

Merge branch 'fires' into doc-tags

parents 3b9929f4 8b52608c
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@ require 'jsduck/process/overrides'
require 'jsduck/process/inherit_doc'
require 'jsduck/process/versions'
require 'jsduck/process/return_values'
require 'jsduck/process/fires'
require 'jsduck/process/lint'
require 'jsduck/process/circular_deps'

@@ -68,6 +69,7 @@ module JsDuck
      Process::InheritDoc.new(relations).process_all!
      Process::Versions.new(relations, opts).process_all!
      Process::ReturnValues.new(relations).process_all!
      Process::Fires.new(relations).process_all!
      Process::Lint.new(relations).process_all!
      relations
    end
+20 −0
Original line number Diff line number Diff line
require "jsduck/js/function"
require "jsduck/js/fires"
require "jsduck/js/method_calls"
require "jsduck/js/node"
require "jsduck/tag_registry"

@@ -316,6 +318,8 @@ module JsDuck
          :name => name,
          :params => empty_array_to_nil(make_params(ast)),
          :chainable => chainable?(ast) && name != "constructor",
          :fires => empty_array_to_nil(detect_fires(ast)),
          :method_calls => empty_array_to_nil(detect_method_calls(ast)),
        }
      end

@@ -339,6 +343,22 @@ module JsDuck
        end
      end

      def detect_fires(ast)
        if ast.function? && !ast.ext_empty_fn?
          Js::Fires.detect(ast)
        else
          []
        end
      end

      def detect_method_calls(ast)
        if ast.function? && !ast.ext_empty_fn?
          Js::MethodCalls.detect(ast)
        else
          []
        end
      end

      def make_event(name)
        return {
          :tagname => :event,

lib/jsduck/js/fires.rb

0 → 100644
+42 −0
Original line number Diff line number Diff line
require "jsduck/util/singleton"
require "jsduck/js/scoped_traverser"

module JsDuck
  module Js

    # Looks the AST of a FunctionDeclaration or FunctionExpression for
    # uses of this.fireEvent().
    class Fires
      include Util::Singleton

      # Returns array of event names fired by the given function.
      # When no events fired, empty array is returned.
      def detect(function_node)
        @traverser = Js::ScopedTraverser.new

        events = []
        @traverser.traverse(function_node["body"]) do |node|
          if fire_event?(node)
            events << node["arguments"][0].to_value
          end
        end

        events.sort.uniq
      end

      private

      # True when node is this.fireEvent("name") call.
      # Also true for me.fireEvent() when me == this.
      def fire_event?(node)
        node.call_expression? &&
          node["callee"].member_expression? &&
          @traverser.this?(node["callee"]["object"].to_s) &&
          node["callee"]["property"].to_s == "fireEvent" &&
          node["arguments"].length > 0 &&
          node["arguments"][0].value_type == "String"
      end

    end
  end
end
+40 −0
Original line number Diff line number Diff line
require "jsduck/util/singleton"
require "jsduck/js/scoped_traverser"

module JsDuck
  module Js

    # Looks the AST of a FunctionDeclaration or FunctionExpression for
    # calls to methods of the owner class.
    class MethodCalls
      include Util::Singleton

      # Returns array of method names called by the given function.
      # When no methods called, empty array is returned.
      def detect(function_node)
        @traverser = Js::ScopedTraverser.new

        methods = []
        @traverser.traverse(function_node["body"]) do |node|
          if method_call?(node)
            methods << node["callee"]["property"].to_s
          end
        end

        methods.sort.uniq
      end

      private

      # True when node is this.someMethod() call.
      # Also true for me.someMethod() when me == this.
      def method_call?(node)
        node.call_expression? &&
          node["callee"].member_expression? &&
          node["callee"].raw["computed"] == false &&
          @traverser.this?(node["callee"]["object"].to_s)
      end

    end
  end
end
+29 −0
Original line number Diff line number Diff line
@@ -80,6 +80,35 @@ module JsDuck
        end
      end

      # Returns the type of node.
      def type
        @node["type"]
      end

      # Extracts all sub-statements and sub-expressions from AST node.
      # Without looking at the type of node, we just take all the
      # sub-hashes and -arrays.
      #
      # A downside of this simple algorithm is that the statements can
      # end up in different order than they are in source code.  For
      # example the IfStatement has three parts in the following
      # order: "test", "consequent", "alternate": But because we're
      # looping over a hash, they might end up in a totally different
      # order.
      def body
        body = []
        @node.each_pair do |key, value|
          if key == "type" || key == "range"
            # ignore
          elsif value.is_a?(Array)
            body.concat(value.map {|v| Js::Node.create(v) })
          elsif value.is_a?(Hash)
            body << Js::Node.create(value)
          end
        end
        body
      end

      # Iterates over keys and values in ObjectExpression.  The keys
      # are turned into strings, but values are left as is for further
      # processing.
Loading