Class: JsxRosetta::AST::Node

Inherits:
Object
  • Object
show all
Defined in:
lib/jsx_rosetta/ast/node.rb

Overview

Base class for every Babel-shaped AST node. Wraps the raw JSON hash and provides:

* Field access via `node[:opening_element]` (snake_case symbols or
  camelCase strings — both resolve to the same field).
* Source location accessors (`loc`, `range`, `start_pos`, `end_pos`).
* Tree traversal via `each_child` / `walk`.
* Pattern-matching support via `deconstruct_keys`.

Specific Babel node types may register subclasses that add named accessors (e.g. JSXElement#opening_element). Unknown types fall through to the generic Node class so the parser doesn’t crash on ESNext additions.

Constant Summary collapse

TYPE_REGISTRY =

rubocop:disable Style/MutableConstant

{}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(raw) ⇒ Node

Returns a new instance of Node.



44
45
46
# File 'lib/jsx_rosetta/ast/node.rb', line 44

def initialize(raw)
  @raw = raw
end

Instance Attribute Details

#rawObject (readonly)

Returns the value of attribute raw.



22
23
24
# File 'lib/jsx_rosetta/ast/node.rb', line 22

def raw
  @raw
end

Class Method Details

.register(*type_names) ⇒ Object



24
25
26
# File 'lib/jsx_rosetta/ast/node.rb', line 24

def self.register(*type_names)
  type_names.each { |name| TYPE_REGISTRY[name] = self }
end

.wrap(value) ⇒ Object



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/jsx_rosetta/ast/node.rb', line 28

def self.wrap(value)
  case value
  when Hash
    if value.key?("type")
      klass = TYPE_REGISTRY.fetch(value["type"], Node)
      klass.new(value)
    else
      value
    end
  when Array
    value.map { |element| wrap(element) }
  else
    value
  end
end

Instance Method Details

#==(other) ⇒ Object Also known as: eql?



119
120
121
# File 'lib/jsx_rosetta/ast/node.rb', line 119

def ==(other)
  other.is_a?(Node) && other.raw == @raw
end

#[](key) ⇒ Object

Field access. Accepts snake_case symbols/strings (translated to camelCase) and camelCase strings (used verbatim).



70
71
72
73
74
75
76
# File 'lib/jsx_rosetta/ast/node.rb', line 70

def [](key)
  raw_key = key.to_s
  return Node.wrap(@raw[raw_key]) if @raw.key?(raw_key)

  camel_key = Inflector.camelize(raw_key)
  Node.wrap(@raw[camel_key])
end

#childrenObject



92
93
94
# File 'lib/jsx_rosetta/ast/node.rb', line 92

def children
  each_child.to_a
end

#deconstruct_keys(keys) ⇒ Object

Pattern-matching support. Returns a hash with snake_case symbol keys; values are wrapped (Node instances or arrays of Node/raw values).



105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/jsx_rosetta/ast/node.rb', line 105

def deconstruct_keys(keys)
  if keys.nil?
    @raw.each_with_object({}) do |(k, v), out|
      out[Inflector.underscore(k).to_sym] = Node.wrap(v)
    end
  else
    keys.each_with_object({}) do |key, out|
      camel_key = Inflector.camelize(key.to_s)
      actual_key = @raw.key?(key.to_s) ? key.to_s : camel_key
      out[key] = Node.wrap(@raw[actual_key]) if @raw.key?(actual_key)
    end
  end
end

#dig(*keys) ⇒ Object



78
79
80
81
82
83
84
# File 'lib/jsx_rosetta/ast/node.rb', line 78

def dig(*keys)
  keys.reduce(self) do |current, key|
    break nil if current.nil?

    current[key]
  end
end

#each_child(&block) ⇒ Object



86
87
88
89
90
# File 'lib/jsx_rosetta/ast/node.rb', line 86

def each_child(&block)
  return enum_for(:each_child) unless block

  @raw.each_value { |value| yield_descendant_nodes(value, &block) }
end

#end_posObject



64
65
66
# File 'lib/jsx_rosetta/ast/node.rb', line 64

def end_pos
  @raw["end"]
end

#hashObject



124
125
126
# File 'lib/jsx_rosetta/ast/node.rb', line 124

def hash
  @raw.hash
end

#inspectObject



128
129
130
# File 'lib/jsx_rosetta/ast/node.rb', line 128

def inspect
  "#<#{self.class.name || "JsxRosetta::AST::Node"} type=#{type.inspect} loc=#{loc_summary}>"
end

#locObject



52
53
54
# File 'lib/jsx_rosetta/ast/node.rb', line 52

def loc
  @raw["loc"]
end

#rangeObject



56
57
58
# File 'lib/jsx_rosetta/ast/node.rb', line 56

def range
  @raw["range"]
end

#start_posObject



60
61
62
# File 'lib/jsx_rosetta/ast/node.rb', line 60

def start_pos
  @raw["start"]
end

#typeObject



48
49
50
# File 'lib/jsx_rosetta/ast/node.rb', line 48

def type
  @raw["type"]
end

#walk {|_self| ... } ⇒ Object

Yields:

  • (_self)

Yield Parameters:



96
97
98
99
100
101
# File 'lib/jsx_rosetta/ast/node.rb', line 96

def walk(&block)
  return enum_for(:walk) unless block

  yield self
  each_child { |child| child.walk(&block) }
end