Loading lib/jsduck/ast.rb +1 −1 Original line number Diff line number Diff line Loading @@ -407,7 +407,7 @@ module JsDuck end def chainable?(ast) FunctionAst.new.returns(ast) == "this" FunctionAst.chainable?(ast) end def make_property(name=nil, ast=nil, tagname=:property) Loading lib/jsduck/function_ast.rb +14 −8 Original line number Diff line number Diff line require "singleton" require "jsduck/serializer" require "jsduck/evaluator" Loading @@ -5,12 +6,21 @@ module JsDuck # Analyzes the AST of a FunctionDeclaration or FunctionExpression. class FunctionAst # Detects from function body what the function returns. def returns(ast) include Singleton # True when function always finishes by returning this. False # doesn't neccessarily mean that the function doesn't return this # - rather it means our static analyzes wasn't able to determine # what the function returns. def self.chainable?(ast) FunctionAst.instance.chainable?(ast) end def chainable?(ast) if ast && function?(ast) body_returns(ast["body"]["body"]) else nil false end end Loading @@ -23,11 +33,7 @@ module JsDuck def body_returns(body) body = skip_non_control_flow_statements(body) if body.length > 0 && return_this?(body[0]) "this" else nil end return body.length > 0 && return_this?(body[0]) end def return_this?(ast) Loading spec/function_ast_spec.rb +8 −8 Original line number Diff line number Diff line Loading @@ -2,29 +2,29 @@ require "jsduck/js_parser" require "jsduck/function_ast" describe "JsDuck::FunctionAst#returns" do def returns(string) def chainable?(string) node = JsDuck::JsParser.new(string).parse[0] return JsDuck::FunctionAst.new.returns(node[:code]) return JsDuck::FunctionAst.chainable?(node[:code]) end it "fails when no AST given at all" do returns("/** */").should == nil chainable?("/** */").should == false end it "fails when no function AST given" do returns("/** */ Ext.emptyFn;").should == nil chainable?("/** */ Ext.emptyFn;").should == false end it "fails when body has no return statement." do returns("/** */ function foo() {}").should == nil chainable?("/** */ function foo() {}").should == false end it "returns this when single return this statement in body" do returns("/** */ function foo() {return this;}").should == "this" chainable?("/** */ function foo() {return this;}").should == true end it "returns this when return this after a few expression statements" do returns(<<-EOJS).should == "this" chainable?(<<-EOJS).should == true /** */ function foo() { doSomething(); Loading @@ -36,7 +36,7 @@ describe "JsDuck::FunctionAst#returns" do end it "returns this when return this after a few declarations" do returns(<<-EOJS).should == "this" chainable?(<<-EOJS).should == true /** */ function foo() { var x = 10; Loading Loading
lib/jsduck/ast.rb +1 −1 Original line number Diff line number Diff line Loading @@ -407,7 +407,7 @@ module JsDuck end def chainable?(ast) FunctionAst.new.returns(ast) == "this" FunctionAst.chainable?(ast) end def make_property(name=nil, ast=nil, tagname=:property) Loading
lib/jsduck/function_ast.rb +14 −8 Original line number Diff line number Diff line require "singleton" require "jsduck/serializer" require "jsduck/evaluator" Loading @@ -5,12 +6,21 @@ module JsDuck # Analyzes the AST of a FunctionDeclaration or FunctionExpression. class FunctionAst # Detects from function body what the function returns. def returns(ast) include Singleton # True when function always finishes by returning this. False # doesn't neccessarily mean that the function doesn't return this # - rather it means our static analyzes wasn't able to determine # what the function returns. def self.chainable?(ast) FunctionAst.instance.chainable?(ast) end def chainable?(ast) if ast && function?(ast) body_returns(ast["body"]["body"]) else nil false end end Loading @@ -23,11 +33,7 @@ module JsDuck def body_returns(body) body = skip_non_control_flow_statements(body) if body.length > 0 && return_this?(body[0]) "this" else nil end return body.length > 0 && return_this?(body[0]) end def return_this?(ast) Loading
spec/function_ast_spec.rb +8 −8 Original line number Diff line number Diff line Loading @@ -2,29 +2,29 @@ require "jsduck/js_parser" require "jsduck/function_ast" describe "JsDuck::FunctionAst#returns" do def returns(string) def chainable?(string) node = JsDuck::JsParser.new(string).parse[0] return JsDuck::FunctionAst.new.returns(node[:code]) return JsDuck::FunctionAst.chainable?(node[:code]) end it "fails when no AST given at all" do returns("/** */").should == nil chainable?("/** */").should == false end it "fails when no function AST given" do returns("/** */ Ext.emptyFn;").should == nil chainable?("/** */ Ext.emptyFn;").should == false end it "fails when body has no return statement." do returns("/** */ function foo() {}").should == nil chainable?("/** */ function foo() {}").should == false end it "returns this when single return this statement in body" do returns("/** */ function foo() {return this;}").should == "this" chainable?("/** */ function foo() {return this;}").should == true end it "returns this when return this after a few expression statements" do returns(<<-EOJS).should == "this" chainable?(<<-EOJS).should == true /** */ function foo() { doSomething(); Loading @@ -36,7 +36,7 @@ describe "JsDuck::FunctionAst#returns" do end it "returns this when return this after a few declarations" do returns(<<-EOJS).should == "this" chainable?(<<-EOJS).should == true /** */ function foo() { var x = 10; Loading