Loading lib/jsduck/batch_processor.rb +2 −0 Original line number Diff line number Diff line Loading @@ -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' Loading Loading @@ -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 Loading lib/jsduck/js/ast.rb +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" Loading Loading @@ -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 Loading @@ -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, Loading 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 lib/jsduck/js/method_calls.rb 0 → 100644 +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 lib/jsduck/js/node.rb +29 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
lib/jsduck/batch_processor.rb +2 −0 Original line number Diff line number Diff line Loading @@ -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' Loading Loading @@ -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 Loading
lib/jsduck/js/ast.rb +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" Loading Loading @@ -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 Loading @@ -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, Loading
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
lib/jsduck/js/method_calls.rb 0 → 100644 +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
lib/jsduck/js/node.rb +29 −0 Original line number Diff line number Diff line Loading @@ -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