Class: JsDuck::Js::Node

Inherits:
Object
  • Object
show all
Defined in:
lib/jsduck/js/node.rb

Overview

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

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(node) ⇒ Node

Initialized with a AST Hash from Esprima.



22
23
24
# File 'lib/jsduck/js/node.rb', line 22

def initialize(node)
  @node = node || {}
end

Class Method Details

.create(node) ⇒ Object

Factor method that creates either Node or NodeArray.



13
14
15
16
17
18
19
# 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

Instance Method Details

#[](name) ⇒ Object

Shorthand for #child method



31
32
33
# File 'lib/jsduck/js/node.rb', line 31

def [](name)
  child(name)
end

#array_expression?Boolean

Returns:

  • (Boolean)


201
202
203
# File 'lib/jsduck/js/node.rb', line 201

def array_expression?
  @node["type"] == "ArrayExpression"
end

#assignment_expression?Boolean

Returns:

  • (Boolean)


193
194
195
# File 'lib/jsduck/js/node.rb', line 193

def assignment_expression?
  @node["type"] == "AssignmentExpression"
end

#bodyObject

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.



98
99
100
101
102
103
104
105
106
107
108
109
110
# 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?Boolean

Simple shorthands for testing the type of node These have one-to-one mapping to Esprima node types.

Returns:

  • (Boolean)


189
190
191
# File 'lib/jsduck/js/node.rb', line 189

def call_expression?
  @node["type"] == "CallExpression"
end

#child(name) ⇒ Object

Returns a child AST node as Node class.



27
28
29
# File 'lib/jsduck/js/node.rb', line 27

def child(name)
  Js::Node.create(@node[name])
end

#define_property?Boolean

Returns:

  • (Boolean)


155
156
157
# File 'lib/jsduck/js/node.rb', line 155

def define_property?
  call_expression? && child("callee").to_s == "Object.defineProperty"
end

#each_propertyObject

Iterates over keys and values in ObjectExpression. The keys are turned into strings, but values are left as is for further processing.



115
116
117
118
119
120
121
# 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?Boolean

Returns:

  • (Boolean)


213
214
215
# File 'lib/jsduck/js/node.rb', line 213

def expression_statement?
  @node["type"] == "ExpressionStatement"
end

#ext_define?Boolean

Returns:

  • (Boolean)


170
171
172
# File 'lib/jsduck/js/node.rb', line 170

def ext_define?
  call_expression? && child("callee").ext_pattern?("Ext.define")
end

#ext_empty_fn?Boolean

Checks dependent on Ext namespace, which may not always be “Ext” but also something user-defined.

Returns:

  • (Boolean)


166
167
168
# File 'lib/jsduck/js/node.rb', line 166

def ext_empty_fn?
  member_expression? && ext_pattern?("Ext.emptyFn")
end

#ext_extend?Boolean

Returns:

  • (Boolean)


174
175
176
# File 'lib/jsduck/js/node.rb', line 174

def ext_extend?
  call_expression? && child("callee").ext_pattern?("Ext.extend")
end

#ext_override?Boolean

Returns:

  • (Boolean)


178
179
180
# File 'lib/jsduck/js/node.rb', line 178

def ext_override?
  call_expression? && child("callee").ext_pattern?("Ext.override")
end

#ext_pattern?(pattern) ⇒ Boolean

Returns:

  • (Boolean)


182
183
184
# File 'lib/jsduck/js/node.rb', line 182

def ext_pattern?(pattern)
  Js::ExtPatterns.matches?(pattern, to_s)
end

#fire_event?Boolean

Returns:

  • (Boolean)


151
152
153
# File 'lib/jsduck/js/node.rb', line 151

def fire_event?
  call_expression? && child("callee").to_s == "this.fireEvent"
end

#function?Boolean

Tests for higher level types which don’t correspond directly to Esprima AST types.

Returns:

  • (Boolean)


147
148
149
# File 'lib/jsduck/js/node.rb', line 147

def function?
  function_declaration? || function_expression? || ext_empty_fn?
end

#function_declaration?Boolean

Returns:

  • (Boolean)


221
222
223
# File 'lib/jsduck/js/node.rb', line 221

def function_declaration?
  @node["type"] == "FunctionDeclaration"
end

#function_expression?Boolean

Returns:

  • (Boolean)


205
206
207
# File 'lib/jsduck/js/node.rb', line 205

def function_expression?
  @node["type"] == "FunctionExpression"
end

#identifier?Boolean

Returns:

  • (Boolean)


229
230
231
# File 'lib/jsduck/js/node.rb', line 229

def identifier?
  @node["type"] == "Identifier"
end

#key_valueObject

Converts object expression property key to string value



59
60
61
# File 'lib/jsduck/js/node.rb', line 59

def key_value
  Js::Evaluator.new.key_value(@node)
end

#linenrObject

Returns line number in parsed source where the Node resides.



137
138
139
140
141
142
# File 'lib/jsduck/js/node.rb', line 137

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?Boolean

Returns:

  • (Boolean)


233
234
235
# File 'lib/jsduck/js/node.rb', line 233

def literal?
  @node["type"] == "Literal"
end

#member_expression?Boolean

Returns:

  • (Boolean)


209
210
211
# File 'lib/jsduck/js/node.rb', line 209

def member_expression?
  @node["type"] == "MemberExpression"
end

#object_descriptor(descriptor_key) ⇒ Object

Returns value of a given field from Object.defineProperty call descriptor object.



125
126
127
128
129
130
131
132
133
134
# 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?Boolean

Returns:

  • (Boolean)


197
198
199
# File 'lib/jsduck/js/node.rb', line 197

def object_expression?
  @node["type"] == "ObjectExpression"
end

#property?Boolean

Returns:

  • (Boolean)


225
226
227
# File 'lib/jsduck/js/node.rb', line 225

def property?
  @node["type"] == "Property"
end

#rawObject

Returns the raw Exprima AST node this class wraps.



36
37
38
# File 'lib/jsduck/js/node.rb', line 36

def raw
  @node
end

#string?Boolean

Returns:

  • (Boolean)


159
160
161
# File 'lib/jsduck/js/node.rb', line 159

def string?
  literal? && @node["value"].is_a?(String)
end

#to_sObject

Serializes the node into string



41
42
43
44
45
46
47
# File 'lib/jsduck/js/node.rb', line 41

def to_s
  begin
    Js::Serializer.new.to_s(@node)
  rescue
    nil
  end
end

#to_valueObject

Evaluates the node into basic JavaScript value.



50
51
52
53
54
55
56
# File 'lib/jsduck/js/node.rb', line 50

def to_value
  begin
    Js::Evaluator.new.to_value(@node)
  rescue
    nil
  end
end

#typeObject

Returns the type of node.



84
85
86
# File 'lib/jsduck/js/node.rb', line 84

def type
  @node["type"]
end

#value_typeObject

Returns the type of node value.



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# 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?Boolean

Returns:

  • (Boolean)


217
218
219
# File 'lib/jsduck/js/node.rb', line 217

def variable_declaration?
  @node["type"] == "VariableDeclaration"
end