Module: Jade::AST::Node

Defined in:
lib/jade/ast/node.rb

Constant Summary collapse

BOILERPLATE_FIELDS =

Boilerplate added by Nodes.define alongside the AST-specific fields. Excluded from child traversal so we don’t iterate the ‘range` Range as integers or descend into comment metadata.

%i[
  range symbol id
  leading_comments trailing_comments dangling_comments
  trailing_comma
].freeze
@@_next_id =
0

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.next_idObject



15
16
17
# File 'lib/jade/ast/node.rb', line 15

def self.next_id
  @@_next_id += 1
end

Instance Method Details

#find_at(offset) ⇒ Object

Deepest descendant whose range covers ‘offset`, or self if no child matches. Returns nil if this node’s range is missing or doesn’t cover the offset.



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

def find_at(offset)
  find_at_path(offset).last
end

#find_at_path(offset) ⇒ Object

Path of nested nodes from self down to the deepest descendant covering ‘offset`. Empty if self doesn’t cover. Use this when you need to consult ancestors — e.g. hover on ‘String` inside `String.length(…)` needs the surrounding QualifiedAccess, not the raw ConstructorReference.



31
32
33
34
35
36
37
38
39
40
41
# File 'lib/jade/ast/node.rb', line 31

def find_at_path(offset)
  return [] unless range&.cover?(offset)

  (members - BOILERPLATE_FIELDS)
    .flat_map { public_send(it) }
    .flat_map { it.is_a?(Array) ? it : [it] }
    .filter_map { it.is_a?(Node) ? it.find_at_path(offset) : nil }
    .reject(&:empty?)
    .first
    .then { [self] + (it || []) }
end