Loading lib/jsduck/ast.rb +44 −71 Original line number Diff line number Diff line Loading @@ -2,6 +2,7 @@ require "jsduck/serializer" require "jsduck/evaluator" require "jsduck/function_ast" require "jsduck/ext_patterns" require "jsduck/ast_node" module JsDuck Loading Loading @@ -47,91 +48,91 @@ module JsDuck # # { :tagname => :method, :name => "foo", ... } # def detect(ast) ast = ast || {} def detect(node) ast = AstNode.new(node) exp = expression?(ast) ? ast["expression"] : nil var = var?(ast) ? ast["declarations"][0] : nil exp = ast.expression_statement? ? ast["expression"] : nil var = ast.variable_declaration? ? ast["declarations"][0] : nil # Ext.define("Class", {}) if exp && ext_define?(exp) make_class(to_value(exp["arguments"][0]), exp) if exp && exp.ext_define? make_class(exp["arguments"][0].to_value, exp.raw) # Ext.override(Class, {}) elsif exp && ext_override?(exp) make_class("", exp) elsif exp && exp.ext_override? make_class("", exp.raw) # foo = Ext.extend(Parent, {}) elsif exp && assignment?(exp) && ext_extend?(exp["right"]) make_class(to_s(exp["left"]), exp["right"]) elsif exp && exp.assignment_expression? && exp["right"].ext_extend? make_class(exp["left"].to_s, exp["right"].raw) # Foo = ... elsif exp && assignment?(exp) && class_name?(to_s(exp["left"])) make_class(to_s(exp["left"]), exp["right"]) elsif exp && exp.assignment_expression? && class_name?(exp["left"].to_s) make_class(exp["left"].to_s, exp["right"].raw) # var foo = Ext.extend(Parent, {}) elsif var && var["init"] && ext_extend?(var["init"]) make_class(to_s(var["id"]), var["init"]) elsif var && var["init"].ext_extend? make_class(var["id"].to_s, var["init"].raw) # var Foo = ... elsif var && class_name?(to_s(var["id"])) make_class(to_s(var["id"]), var["right"]) elsif var && class_name?(var["id"].to_s) make_class(var["id"].to_s, var["right"].raw) # function Foo() {} elsif function?(ast) && class_name?(to_s(ast["id"])) make_class(to_s(ast["id"])) elsif ast.function? && class_name?(ast["id"].to_s) make_class(ast["id"].to_s) # { ... } elsif object?(ast) make_class("", ast) elsif ast.object_expression? make_class("", ast.raw) # function foo() {} elsif function?(ast) make_method(to_s(ast["id"]), ast) elsif ast.function? make_method(ast["id"].to_s, ast.raw) # foo = function() {} elsif exp && assignment?(exp) && function?(exp["right"]) make_method(to_s(exp["left"]), exp["right"]) elsif exp && exp.assignment_expression? && exp["right"].function? make_method(exp["left"].to_s, exp["right"].raw) # var foo = function() {} elsif var && var["init"] && function?(var["init"]) make_method(to_s(var["id"]), var["init"]) elsif var && var["init"] && var["init"].function? make_method(var["id"].to_s, var["init"].raw) # (function() {}) elsif exp && function?(exp) make_method(exp["id"] ? to_s(exp["id"]) : "", exp) elsif exp && exp.function? make_method(exp["id"].to_s || "", exp.raw) # foo: function() {} elsif property?(ast) && function?(ast["value"]) make_method(key_value(ast["key"]), ast["value"]) elsif ast.property? && ast["value"].function? make_method(key_value(ast["key"].raw), ast["value"].raw) # this.fireEvent("foo", ...) elsif exp && fire_event?(exp) make_event(to_value(exp["arguments"][0])) elsif exp && exp.fire_event? make_event(exp["arguments"][0].to_value) # foo = ... elsif exp && assignment?(exp) make_property(to_s(exp["left"]), exp["right"]) elsif exp && exp.assignment_expression? make_property(exp["left"].to_s, exp["right"].raw) # var foo = ... elsif var make_property(to_s(var["id"]), var["init"]) make_property(var["id"].to_s, var["init"].raw) # foo: ... elsif property?(ast) make_property(key_value(ast["key"]), ast["value"]) elsif ast.property? make_property(key_value(ast["key"].raw), ast["value"].raw) # foo; elsif exp && ident?(exp) make_property(to_s(exp)) elsif exp && exp.identifier? make_property(exp.to_s) # "foo" (inside some expression) elsif string?(ast) make_property(to_value(ast)) elsif ast.string? make_property(ast.to_value) # "foo"; (as a statement of it's own) elsif exp && string?(exp) make_property(to_value(exp)) elsif exp && exp.string? make_property(exp.to_value) else make_property() Loading @@ -140,18 +141,10 @@ module JsDuck private def expression?(ast) ast["type"] == "ExpressionStatement" end def call?(ast) ast["type"] == "CallExpression" end def assignment?(ast) ast["type"] == "AssignmentExpression" end def ext_define?(ast) call?(ast) && ext_pattern?("Ext.define", ast["callee"]) end Loading @@ -176,26 +169,6 @@ module JsDuck ExtPatterns.matches?(pattern, to_s(ast)) end def fire_event?(ast) call?(ast) && to_s(ast["callee"]) == "this.fireEvent" end def var?(ast) ast["type"] == "VariableDeclaration" end def property?(ast) ast["type"] == "Property" end def ident?(ast) ast["type"] == "Identifier" end def string?(ast) ast["type"] == "Literal" && ast["value"].is_a?(String) end def object?(ast) ast["type"] == "ObjectExpression" end Loading lib/jsduck/ast_node.rb +101 −50 Original line number Diff line number Diff line Loading @@ -9,65 +9,30 @@ module JsDuck class AstNode # Initialized with a AST Hash from Esprima. def initialize(node) @node = node end def expression? @node["type"] == "ExpressionStatement" end def call? @node["type"] == "CallExpression" end def assignment?(ast) @node["type"] == "AssignmentExpression" end def function?(ast) @node["type"] == "FunctionDeclaration" || @node["type"] == "FunctionExpression" || empty_fn? end def empty_fn?(ast) @node["type"] == "MemberExpression" && ext_pattern?("Ext.emptyFn") end def ext_pattern?(pattern) @ext_patterns.matches?(pattern, to_s) end def fire_event?(ast) call? && child("callee").to_s == "this.fireEvent" end def var?(ast) @node["type"] == "VariableDeclaration" end def property?(ast) @node["type"] == "Property" end def ident?(ast) @node["type"] == "Identifier" end def string?(ast) @node["type"] == "Literal" && @node["value"].is_a?(String) end def object?(ast) @node["type"] == "ObjectExpression" @node = node || {} end # Returns a child AST node as AstNode class. def child(name) AstNode.new(@node[name]) end # Shorthand for #child method def [](name) child(name) end # Returns the raw Exprima AST node this class wraps. def raw @node end # Serializes the node into string def to_s begin Serializer.new.to_s(@node) rescue nil end end # Evaluates the node into basic JavaScript value. Loading @@ -79,6 +44,7 @@ module JsDuck end end # Returns the type of node value. def value_type v = to_value if v.is_a?(String) Loading @@ -98,6 +64,91 @@ module JsDuck end end # Tests for higher level types which don't correspond directly to # Esprima AST types. def function? function_declaration? || function_expression? || ext_empty_fn? end def fire_event? call_expression? && child("callee").to_s == "this.fireEvent" end def string? literal? && @node["value"].is_a?(String) end # Checks dependent on Ext namespace, # which may not always be "Ext" but also something user-defined. def ext_empty_fn? member_expression? && ext_pattern?("Ext.emptyFn") end def ext_define? call_expression? && child("callee").ext_pattern?("Ext.define") end def ext_extend? call_expression? && child("callee").ext_pattern?("Ext.extend") end def ext_override? call_expression? && child("callee").ext_pattern?("Ext.override") end def ext_pattern?(pattern) ExtPatterns.matches?(pattern, to_s) end # Simple shorthands for testing the type of node # These have one-to-one mapping to Esprima node types. def call_expression? @node["type"] == "CallExpression" end def assignment_expression? @node["type"] == "AssignmentExpression" end def object_expression? @node["type"] == "ObjectExpression" end def function_expression? @node["type"] == "FunctionExpression" end def member_expression? @node["type"] == "MemberExpression" end def expression_statement? @node["type"] == "ExpressionStatement" end def variable_declaration? @node["type"] == "VariableDeclaration" end def function_declaration? @node["type"] == "FunctionDeclaration" end def property? @node["type"] == "Property" end def identifier? @node["type"] == "Identifier" end def literal? @node["type"] == "Literal" end end end lib/jsduck/serializer.rb +1 −1 Original line number Diff line number Diff line Loading @@ -159,7 +159,7 @@ module JsDuck ast["raw"] else throw "Unknown node type: "+ast["type"] throw "Unknown node type: " + (ast["type"] || "nil") end end Loading Loading
lib/jsduck/ast.rb +44 −71 Original line number Diff line number Diff line Loading @@ -2,6 +2,7 @@ require "jsduck/serializer" require "jsduck/evaluator" require "jsduck/function_ast" require "jsduck/ext_patterns" require "jsduck/ast_node" module JsDuck Loading Loading @@ -47,91 +48,91 @@ module JsDuck # # { :tagname => :method, :name => "foo", ... } # def detect(ast) ast = ast || {} def detect(node) ast = AstNode.new(node) exp = expression?(ast) ? ast["expression"] : nil var = var?(ast) ? ast["declarations"][0] : nil exp = ast.expression_statement? ? ast["expression"] : nil var = ast.variable_declaration? ? ast["declarations"][0] : nil # Ext.define("Class", {}) if exp && ext_define?(exp) make_class(to_value(exp["arguments"][0]), exp) if exp && exp.ext_define? make_class(exp["arguments"][0].to_value, exp.raw) # Ext.override(Class, {}) elsif exp && ext_override?(exp) make_class("", exp) elsif exp && exp.ext_override? make_class("", exp.raw) # foo = Ext.extend(Parent, {}) elsif exp && assignment?(exp) && ext_extend?(exp["right"]) make_class(to_s(exp["left"]), exp["right"]) elsif exp && exp.assignment_expression? && exp["right"].ext_extend? make_class(exp["left"].to_s, exp["right"].raw) # Foo = ... elsif exp && assignment?(exp) && class_name?(to_s(exp["left"])) make_class(to_s(exp["left"]), exp["right"]) elsif exp && exp.assignment_expression? && class_name?(exp["left"].to_s) make_class(exp["left"].to_s, exp["right"].raw) # var foo = Ext.extend(Parent, {}) elsif var && var["init"] && ext_extend?(var["init"]) make_class(to_s(var["id"]), var["init"]) elsif var && var["init"].ext_extend? make_class(var["id"].to_s, var["init"].raw) # var Foo = ... elsif var && class_name?(to_s(var["id"])) make_class(to_s(var["id"]), var["right"]) elsif var && class_name?(var["id"].to_s) make_class(var["id"].to_s, var["right"].raw) # function Foo() {} elsif function?(ast) && class_name?(to_s(ast["id"])) make_class(to_s(ast["id"])) elsif ast.function? && class_name?(ast["id"].to_s) make_class(ast["id"].to_s) # { ... } elsif object?(ast) make_class("", ast) elsif ast.object_expression? make_class("", ast.raw) # function foo() {} elsif function?(ast) make_method(to_s(ast["id"]), ast) elsif ast.function? make_method(ast["id"].to_s, ast.raw) # foo = function() {} elsif exp && assignment?(exp) && function?(exp["right"]) make_method(to_s(exp["left"]), exp["right"]) elsif exp && exp.assignment_expression? && exp["right"].function? make_method(exp["left"].to_s, exp["right"].raw) # var foo = function() {} elsif var && var["init"] && function?(var["init"]) make_method(to_s(var["id"]), var["init"]) elsif var && var["init"] && var["init"].function? make_method(var["id"].to_s, var["init"].raw) # (function() {}) elsif exp && function?(exp) make_method(exp["id"] ? to_s(exp["id"]) : "", exp) elsif exp && exp.function? make_method(exp["id"].to_s || "", exp.raw) # foo: function() {} elsif property?(ast) && function?(ast["value"]) make_method(key_value(ast["key"]), ast["value"]) elsif ast.property? && ast["value"].function? make_method(key_value(ast["key"].raw), ast["value"].raw) # this.fireEvent("foo", ...) elsif exp && fire_event?(exp) make_event(to_value(exp["arguments"][0])) elsif exp && exp.fire_event? make_event(exp["arguments"][0].to_value) # foo = ... elsif exp && assignment?(exp) make_property(to_s(exp["left"]), exp["right"]) elsif exp && exp.assignment_expression? make_property(exp["left"].to_s, exp["right"].raw) # var foo = ... elsif var make_property(to_s(var["id"]), var["init"]) make_property(var["id"].to_s, var["init"].raw) # foo: ... elsif property?(ast) make_property(key_value(ast["key"]), ast["value"]) elsif ast.property? make_property(key_value(ast["key"].raw), ast["value"].raw) # foo; elsif exp && ident?(exp) make_property(to_s(exp)) elsif exp && exp.identifier? make_property(exp.to_s) # "foo" (inside some expression) elsif string?(ast) make_property(to_value(ast)) elsif ast.string? make_property(ast.to_value) # "foo"; (as a statement of it's own) elsif exp && string?(exp) make_property(to_value(exp)) elsif exp && exp.string? make_property(exp.to_value) else make_property() Loading @@ -140,18 +141,10 @@ module JsDuck private def expression?(ast) ast["type"] == "ExpressionStatement" end def call?(ast) ast["type"] == "CallExpression" end def assignment?(ast) ast["type"] == "AssignmentExpression" end def ext_define?(ast) call?(ast) && ext_pattern?("Ext.define", ast["callee"]) end Loading @@ -176,26 +169,6 @@ module JsDuck ExtPatterns.matches?(pattern, to_s(ast)) end def fire_event?(ast) call?(ast) && to_s(ast["callee"]) == "this.fireEvent" end def var?(ast) ast["type"] == "VariableDeclaration" end def property?(ast) ast["type"] == "Property" end def ident?(ast) ast["type"] == "Identifier" end def string?(ast) ast["type"] == "Literal" && ast["value"].is_a?(String) end def object?(ast) ast["type"] == "ObjectExpression" end Loading
lib/jsduck/ast_node.rb +101 −50 Original line number Diff line number Diff line Loading @@ -9,65 +9,30 @@ module JsDuck class AstNode # Initialized with a AST Hash from Esprima. def initialize(node) @node = node end def expression? @node["type"] == "ExpressionStatement" end def call? @node["type"] == "CallExpression" end def assignment?(ast) @node["type"] == "AssignmentExpression" end def function?(ast) @node["type"] == "FunctionDeclaration" || @node["type"] == "FunctionExpression" || empty_fn? end def empty_fn?(ast) @node["type"] == "MemberExpression" && ext_pattern?("Ext.emptyFn") end def ext_pattern?(pattern) @ext_patterns.matches?(pattern, to_s) end def fire_event?(ast) call? && child("callee").to_s == "this.fireEvent" end def var?(ast) @node["type"] == "VariableDeclaration" end def property?(ast) @node["type"] == "Property" end def ident?(ast) @node["type"] == "Identifier" end def string?(ast) @node["type"] == "Literal" && @node["value"].is_a?(String) end def object?(ast) @node["type"] == "ObjectExpression" @node = node || {} end # Returns a child AST node as AstNode class. def child(name) AstNode.new(@node[name]) end # Shorthand for #child method def [](name) child(name) end # Returns the raw Exprima AST node this class wraps. def raw @node end # Serializes the node into string def to_s begin Serializer.new.to_s(@node) rescue nil end end # Evaluates the node into basic JavaScript value. Loading @@ -79,6 +44,7 @@ module JsDuck end end # Returns the type of node value. def value_type v = to_value if v.is_a?(String) Loading @@ -98,6 +64,91 @@ module JsDuck end end # Tests for higher level types which don't correspond directly to # Esprima AST types. def function? function_declaration? || function_expression? || ext_empty_fn? end def fire_event? call_expression? && child("callee").to_s == "this.fireEvent" end def string? literal? && @node["value"].is_a?(String) end # Checks dependent on Ext namespace, # which may not always be "Ext" but also something user-defined. def ext_empty_fn? member_expression? && ext_pattern?("Ext.emptyFn") end def ext_define? call_expression? && child("callee").ext_pattern?("Ext.define") end def ext_extend? call_expression? && child("callee").ext_pattern?("Ext.extend") end def ext_override? call_expression? && child("callee").ext_pattern?("Ext.override") end def ext_pattern?(pattern) ExtPatterns.matches?(pattern, to_s) end # Simple shorthands for testing the type of node # These have one-to-one mapping to Esprima node types. def call_expression? @node["type"] == "CallExpression" end def assignment_expression? @node["type"] == "AssignmentExpression" end def object_expression? @node["type"] == "ObjectExpression" end def function_expression? @node["type"] == "FunctionExpression" end def member_expression? @node["type"] == "MemberExpression" end def expression_statement? @node["type"] == "ExpressionStatement" end def variable_declaration? @node["type"] == "VariableDeclaration" end def function_declaration? @node["type"] == "FunctionDeclaration" end def property? @node["type"] == "Property" end def identifier? @node["type"] == "Identifier" end def literal? @node["type"] == "Literal" end end end
lib/jsduck/serializer.rb +1 −1 Original line number Diff line number Diff line Loading @@ -159,7 +159,7 @@ module JsDuck ast["raw"] else throw "Unknown node type: "+ast["type"] throw "Unknown node type: " + (ast["type"] || "nil") end end Loading