Class: Json::Merge::NodeWrapper

Inherits:
Ast::Merge::NodeWrapperBase
  • Object
show all
Defined in:
lib/json/merge/node_wrapper.rb

Overview

Wraps TreeHaver nodes with comment associations, line information, and signatures.
This provides a unified interface for working with JSON AST nodes during merging.

Inherits common functionality from Ast::Merge::NodeWrapperBase:

  • Source context (lines, source, comments)
  • Line info extraction
  • Basic methods: #type, #type?, #text, #content, #signature

Examples:

Basic usage

parser = TreeHaver::Parser.new
parser.language = TreeHaver::Language.json
tree = parser.parse(source)
wrapper = NodeWrapper.new(tree.root_node, lines: source.lines, source: source)
wrapper.signature # => [:object, ...]

See Also:

  • Ast::Merge::NodeWrapperBase

Instance Method Summary collapse

Instance Method Details

#array?Boolean

Check if this is a JSON array

Returns:

  • (Boolean)


30
31
32
# File 'lib/json/merge/node_wrapper.rb', line 30

def array?
  @node.type.to_s == "array"
end

#boolean?Boolean

Check if this is a JSON boolean (true/false)

Returns:

  • (Boolean)


48
49
50
# File 'lib/json/merge/node_wrapper.rb', line 48

def boolean?
  %w[true false].include?(@node.type.to_s)
end

#closing_bracketString?

Get the closing bracket character for this container

Returns:

  • (String, nil)


195
196
197
198
199
200
# File 'lib/json/merge/node_wrapper.rb', line 195

def closing_bracket
  return "}" if object?
  return "]" if array?

  nil
end

#closing_lineString?

Get the closing line for a container node (the line with } or ])
Returns the full line content including any leading whitespace

Returns:

  • (String, nil)


178
179
180
181
182
# File 'lib/json/merge/node_wrapper.rb', line 178

def closing_line
  return unless container? && @end_line

  @lines[@end_line - 1]
end

#comment?Boolean

Check if this is a comment

Returns:

  • (Boolean)


66
67
68
# File 'lib/json/merge/node_wrapper.rb', line 66

def comment?
  @node.type.to_s == "comment"
end

#container?Boolean

Check if this node is a container (has mergeable children)

Returns:

  • (Boolean)


149
150
151
# File 'lib/json/merge/node_wrapper.rb', line 149

def container?
  object? || array?
end

#elementsArray<NodeWrapper>

Get array elements if this is an array

Returns:



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/json/merge/node_wrapper.rb', line 115

def elements
  return [] unless array?

  result = []
  @node.each do |child|
    child_type = child.type.to_s
    # Skip punctuation and comments
    next if child_type == "comment"
    next if child_type == ","
    next if child_type == "["
    next if child_type == "]"

    result << NodeWrapper.new(child, lines: @lines, source: @source)
  end
  result
end

#find_child_by_field(field_name) ⇒ TreeSitter::Node?

Find a child by field name

Parameters:

  • field_name (String)

    Field name to look for

Returns:

  • (TreeSitter::Node, nil)


205
206
207
208
209
# File 'lib/json/merge/node_wrapper.rb', line 205

def find_child_by_field(field_name)
  return unless @node.respond_to?(:child_by_field_name)

  @node.child_by_field_name(field_name)
end

#find_child_by_type(type_name) ⇒ TreeSitter::Node?

Find a child by type

Parameters:

  • type_name (String)

    Type name to look for

Returns:

  • (TreeSitter::Node, nil)


214
215
216
217
218
219
220
221
# File 'lib/json/merge/node_wrapper.rb', line 214

def find_child_by_type(type_name)
  return unless @node.respond_to?(:each)

  @node.each do |child|
    return child if child.type.to_s == type_name
  end
  nil
end

#key_nameString?

Get the key name if this is a pair node

Returns:

  • (String, nil)


72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/json/merge/node_wrapper.rb', line 72

def key_name
  return unless pair?

  # In JSON tree-sitter, pair has key and value children
  key_node = find_child_by_field("key")

  return unless key_node

  # Key is typically a string, extract its content without quotes using byte positions
  key_text = node_text(key_node)
  # Remove surrounding quotes if present
  key_text&.gsub(/\A"|"\z/, "")
end

#mergeable_childrenArray<NodeWrapper>

Get mergeable children - the semantically meaningful children for tree merging
For objects, returns pairs. For arrays, returns elements.
For other node types, returns empty array (leaf nodes).

Returns:



136
137
138
139
140
141
142
143
144
145
# File 'lib/json/merge/node_wrapper.rb', line 136

def mergeable_children
  case type
  when :object
    pairs
  when :array
    elements
  else
    []
  end
end

#null?Boolean

Check if this is a JSON null

Returns:

  • (Boolean)


54
55
56
# File 'lib/json/merge/node_wrapper.rb', line 54

def null?
  @node.type.to_s == "null"
end

#number?Boolean

Check if this is a JSON number

Returns:

  • (Boolean)


42
43
44
# File 'lib/json/merge/node_wrapper.rb', line 42

def number?
  @node.type.to_s == "number"
end

#object?Boolean

Check if this is a JSON object

Returns:

  • (Boolean)


24
25
26
# File 'lib/json/merge/node_wrapper.rb', line 24

def object?
  @node.type.to_s == "object"
end

#opening_bracketString?

Get the opening bracket character for this container

Returns:

  • (String, nil)


186
187
188
189
190
191
# File 'lib/json/merge/node_wrapper.rb', line 186

def opening_bracket
  return "{" if object?
  return "[" if array?

  nil
end

#opening_lineString?

Get the opening line for a container node (the line with { or [)
Returns the full line content including any leading whitespace

Returns:

  • (String, nil)


169
170
171
172
173
# File 'lib/json/merge/node_wrapper.rb', line 169

def opening_line
  return unless container? && @start_line

  @lines[@start_line - 1]
end

#pair?Boolean

Check if this is a key-value pair

Returns:

  • (Boolean)


60
61
62
# File 'lib/json/merge/node_wrapper.rb', line 60

def pair?
  @node.type.to_s == "pair"
end

#pairsArray<NodeWrapper>

Get key-value pairs if this is an object

Returns:



100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/json/merge/node_wrapper.rb', line 100

def pairs
  return [] unless object?

  result = []
  @node.each do |child|
    next if child.type.to_s == "comment"
    next unless child.type.to_s == "pair"

    result << NodeWrapper.new(child, lines: @lines, source: @source)
  end
  result
end

#root_level_container?Boolean

Check if this is a root-level container (direct child of document)
Root-level containers get a generic signature so they always match.

Returns:

  • (Boolean)


156
157
158
159
160
161
162
163
164
# File 'lib/json/merge/node_wrapper.rb', line 156

def root_level_container?
  return false unless container?

  # Check if parent is a document node
  parent_node = @node.parent if @node.respond_to?(:parent)
  return false unless parent_node

  parent_node.type.to_s == "document"
end

#string?Boolean

Check if this is a JSON string

Returns:

  • (Boolean)


36
37
38
# File 'lib/json/merge/node_wrapper.rb', line 36

def string?
  @node.type.to_s == "string"
end

#value_nodeNodeWrapper?

Get the value node if this is a pair

Returns:



88
89
90
91
92
93
94
95
96
# File 'lib/json/merge/node_wrapper.rb', line 88

def value_node
  return unless pair?

  value = find_child_by_field("value")

  return unless value

  NodeWrapper.new(value, lines: @lines, source: @source)
end