class JsDuck::Js::Node
Wraps around AST node returned from Esprima, providing methods for investigating it.
Public Class Methods
Initialized with a AST Hash from Esprima.
# File lib/jsduck/js/node.rb, line 22 def initialize(node) @node = node || {} end
Public Instance Methods
Shorthand for child
method
# File lib/jsduck/js/node.rb, line 31 def [](name) child(name) end
# File lib/jsduck/js/node.rb, line 228 def array_expression? @node["type"] == "ArrayExpression" end
# File lib/jsduck/js/node.rb, line 220 def assignment_expression? @node["type"] == "AssignmentExpression" end
# File lib/jsduck/js/node.rb, line 155 def block_statement? @node["type"] == "BlockStatement" 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.
# File lib/jsduck/js/node.rb, line 98 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
Simple shorthands for testing the type of node These have one-to-one mapping to Esprima node types.
# File lib/jsduck/js/node.rb, line 216 def call_expression? @node["type"] == "CallExpression" end
# File lib/jsduck/js/node.rb, line 182 def define_property? call_expression? && child("callee").to_s == "Object.defineProperty" end
Iterates over keys and values in ObjectExpression. The keys are turned into strings, but values are left as is for further processing.
# File lib/jsduck/js/node.rb, line 115 def each_property return unless object_expression? child("properties").each do |ast| yield(ast["key"].key_value, ast["value"], ast) end end
# File lib/jsduck/js/node.rb, line 240 def expression_statement? @node["type"] == "ExpressionStatement" end
# File lib/jsduck/js/node.rb, line 197 def ext_define? call_expression? && child("callee").ext_pattern?("Ext.define") end
Checks dependent on Ext namespace, which may not always be “Ext” but also something user-defined.
# File lib/jsduck/js/node.rb, line 193 def ext_empty_fn? member_expression? && ext_pattern?("Ext.emptyFn") end
# File lib/jsduck/js/node.rb, line 201 def ext_extend? call_expression? && child("callee").ext_pattern?("Ext.extend") end
# File lib/jsduck/js/node.rb, line 205 def ext_override? call_expression? && child("callee").ext_pattern?("Ext.override") end
# File lib/jsduck/js/node.rb, line 209 def ext_pattern?(pattern) Js::ExtPatterns.matches?(pattern, to_s) end
# File lib/jsduck/js/node.rb, line 178 def fire_event? call_expression? && child("callee").to_s == "this.fireEvent" end
Tests for higher level types which don't correspond directly to Esprima AST types.
# File lib/jsduck/js/node.rb, line 174 def function? function_declaration? || function_expression? || ext_empty_fn? end
# File lib/jsduck/js/node.rb, line 248 def function_declaration? @node["type"] == "FunctionDeclaration" end
# File lib/jsduck/js/node.rb, line 232 def function_expression? @node["type"] == "FunctionExpression" end
# File lib/jsduck/js/node.rb, line 256 def identifier? @node["type"] == "Identifier" end
Converts object expression property key to string value
# File lib/jsduck/js/node.rb, line 59 def key_value Js::Evaluator.new.key_value(@node) end
# File lib/jsduck/js/node.rb, line 260 def literal? @node["type"] == "Literal" end
# File lib/jsduck/js/node.rb, line 236 def member_expression? @node["type"] == "MemberExpression" end
Returns
value of a given field from Object.defineProperty call descriptor object.
# File lib/jsduck/js/node.rb, line 125 def object_descriptor(descriptor_key) return unless define_property? descriptor = child("arguments")[2] descriptor.each_property do |key, value, prop| return value if key == descriptor_key end return nil end
# File lib/jsduck/js/node.rb, line 224 def object_expression? @node["type"] == "ObjectExpression" end
# File lib/jsduck/js/node.rb, line 252 def property? @node["type"] == "Property" end
Returns
the raw Exprima AST node this class wraps.
# File lib/jsduck/js/node.rb, line 36 def raw @node end
# File lib/jsduck/js/node.rb, line 159 def return_statement? @node["type"] == "ReturnStatement" end
Returns
the return statement's expression for the current function expression.
# File lib/jsduck/js/node.rb, line 138 def return_statement_expression return unless function_expression? node = child("body") if node.block_statement? node["body"].each do |node| if node.return_statement? node = node["argument"] return node.object_expression? ? node : nil end end end return nil end
# File lib/jsduck/js/node.rb, line 186 def string? literal? && @node["value"].is_a?(String) end
Serializes the node into string
# File lib/jsduck/js/node.rb, line 41 def to_s begin Js::Serializer.new.to_s(@node) rescue nil end end
Evaluates the node into basic JavaScript value.
# File lib/jsduck/js/node.rb, line 50 def to_value begin Js::Evaluator.new.to_value(@node) rescue nil end end
Returns
the type of node.
# File lib/jsduck/js/node.rb, line 84 def type @node["type"] end
Returns
the type of node value.
# File lib/jsduck/js/node.rb, line 64 def value_type v = to_value if v.is_a?(String) "String" elsif v.is_a?(Numeric) "Number" elsif v.is_a?(TrueClass) || v.is_a?(FalseClass) "Boolean" elsif v.is_a?(Array) "Array" elsif v.is_a?(Hash) "Object" elsif v == :regexp "RegExp" else nil end end
# File lib/jsduck/js/node.rb, line 244 def variable_declaration? @node["type"] == "VariableDeclaration" end