class JsDuck::Js::Node

Wraps around AST node returned from Esprima, providing methods for investigating it.

Public Class Methods

create(node) click to toggle source

Factor method that creates either Node or NodeArray.

# File lib/jsduck/js/node.rb, line 13
def self.create(node)
  if node.is_a? Array
    Js::NodeArray.new(node)
  else
    Js::Node.new(node)
  end
end
new(node) click to toggle source

Initialized with a AST Hash from Esprima.

# File lib/jsduck/js/node.rb, line 22
def initialize(node)
  @node = node || {}
end

Public Instance Methods

[](name) click to toggle source

Shorthand for child method

# File lib/jsduck/js/node.rb, line 31
def [](name)
  child(name)
end
array_expression?() click to toggle source
# File lib/jsduck/js/node.rb, line 228
def array_expression?
  @node["type"] == "ArrayExpression"
end
assignment_expression?() click to toggle source
# File lib/jsduck/js/node.rb, line 220
def assignment_expression?
  @node["type"] == "AssignmentExpression"
end
block_statement?() click to toggle source
# File lib/jsduck/js/node.rb, line 155
def block_statement?
  @node["type"] == "BlockStatement"
end
body() click to toggle source

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
call_expression?() click to toggle source

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
child(name) click to toggle source

Returns a child AST node as Node class.

# File lib/jsduck/js/node.rb, line 27
def child(name)
  Js::Node.create(@node[name])
end
define_property?() click to toggle source
# File lib/jsduck/js/node.rb, line 182
def define_property?
  call_expression? && child("callee").to_s == "Object.defineProperty"
end
each_property() { |key_value, ast, ast| ... } click to toggle source

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
expression_statement?() click to toggle source
# File lib/jsduck/js/node.rb, line 240
def expression_statement?
  @node["type"] == "ExpressionStatement"
end
ext_define?() click to toggle source
# File lib/jsduck/js/node.rb, line 197
def ext_define?
  call_expression? && child("callee").ext_pattern?("Ext.define")
end
ext_empty_fn?() click to toggle source

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
ext_extend?() click to toggle source
# File lib/jsduck/js/node.rb, line 201
def ext_extend?
  call_expression? && child("callee").ext_pattern?("Ext.extend")
end
ext_override?() click to toggle source
# File lib/jsduck/js/node.rb, line 205
def ext_override?
  call_expression? && child("callee").ext_pattern?("Ext.override")
end
ext_pattern?(pattern) click to toggle source
# File lib/jsduck/js/node.rb, line 209
def ext_pattern?(pattern)
  Js::ExtPatterns.matches?(pattern, to_s)
end
fire_event?() click to toggle source
# File lib/jsduck/js/node.rb, line 178
def fire_event?
  call_expression? && child("callee").to_s == "this.fireEvent"
end
function?() click to toggle source

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
function_declaration?() click to toggle source
# File lib/jsduck/js/node.rb, line 248
def function_declaration?
  @node["type"] == "FunctionDeclaration"
end
function_expression?() click to toggle source
# File lib/jsduck/js/node.rb, line 232
def function_expression?
  @node["type"] == "FunctionExpression"
end
identifier?() click to toggle source
# File lib/jsduck/js/node.rb, line 256
def identifier?
  @node["type"] == "Identifier"
end
key_value() click to toggle source

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
linenr() click to toggle source

Returns line number in parsed source where the Node resides.

# File lib/jsduck/js/node.rb, line 164
def linenr
  # Get line number from third place at range array.
  # This third item exists in forked EsprimaJS at
  # https://github.com/nene/esprima/tree/linenr-in-range
  @node["range"][2]
end
literal?() click to toggle source
# File lib/jsduck/js/node.rb, line 260
def literal?
  @node["type"] == "Literal"
end
member_expression?() click to toggle source
# File lib/jsduck/js/node.rb, line 236
def member_expression?
  @node["type"] == "MemberExpression"
end
object_descriptor(descriptor_key) click to toggle source

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
object_expression?() click to toggle source
# File lib/jsduck/js/node.rb, line 224
def object_expression?
  @node["type"] == "ObjectExpression"
end
property?() click to toggle source
# File lib/jsduck/js/node.rb, line 252
def property?
  @node["type"] == "Property"
end
raw() click to toggle source

Returns the raw Exprima AST node this class wraps.

# File lib/jsduck/js/node.rb, line 36
def raw
  @node
end
return_statement?() click to toggle source
# File lib/jsduck/js/node.rb, line 159
def return_statement?
  @node["type"] == "ReturnStatement"
end
return_statement_expression() click to toggle source

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
string?() click to toggle source
# File lib/jsduck/js/node.rb, line 186
def string?
  literal? && @node["value"].is_a?(String)
end
to_s() click to toggle source

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
to_value() click to toggle source

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
type() click to toggle source

Returns the type of node.

# File lib/jsduck/js/node.rb, line 84
def type
  @node["type"]
end
value_type() click to toggle source

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
variable_declaration?() click to toggle source
# File lib/jsduck/js/node.rb, line 244
def variable_declaration?
  @node["type"] == "VariableDeclaration"
end