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)


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

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

#assignment_expression?Boolean

Returns:

  • (Boolean)


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

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

#block_statement?Boolean

Returns:

  • (Boolean)


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

def block_statement?
  @node["type"] == "BlockStatement"
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)


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

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)


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

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)


240
241
242
# File 'lib/jsduck/js/node.rb', line 240

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

#ext_define?Boolean

Returns:

  • (Boolean)


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

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)


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

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

#ext_extend?Boolean

Returns:

  • (Boolean)


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

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

#ext_override?Boolean

Returns:

  • (Boolean)


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

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

#ext_pattern?(pattern) ⇒ Boolean

Returns:

  • (Boolean)


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

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

#fire_event?Boolean

Returns:

  • (Boolean)


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

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)


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

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

#function_declaration?Boolean

Returns:

  • (Boolean)


248
249
250
# File 'lib/jsduck/js/node.rb', line 248

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

#function_expression?Boolean

Returns:

  • (Boolean)


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

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

#identifier?Boolean

Returns:

  • (Boolean)


256
257
258
# File 'lib/jsduck/js/node.rb', line 256

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.



164
165
166
167
168
169
# 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?Boolean

Returns:

  • (Boolean)


260
261
262
# File 'lib/jsduck/js/node.rb', line 260

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

#member_expression?Boolean

Returns:

  • (Boolean)


236
237
238
# File 'lib/jsduck/js/node.rb', line 236

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)


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

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

#property?Boolean

Returns:

  • (Boolean)


252
253
254
# File 'lib/jsduck/js/node.rb', line 252

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

#return_statement?Boolean

Returns:

  • (Boolean)


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

def return_statement?
  @node["type"] == "ReturnStatement"
end

#return_statement_expressionObject

Returns the return statement’s expression for the current function expression.



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# 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?Boolean

Returns:

  • (Boolean)


186
187
188
# File 'lib/jsduck/js/node.rb', line 186

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)


244
245
246
# File 'lib/jsduck/js/node.rb', line 244

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