Class: TreeHaver::Base::Comment

Inherits:
Object
  • Object
show all
Defined in:
lib/tree_haver/base/comment.rb

Overview

Base class for backend comment wrappers.

This defines the parser-facing contract for normalized comment wrappers in TreeHaver. Backends that can expose comment objects should subclass this and implement text/type/location accessors using their native parser data.

Direct Known Subclasses

TreeHaver::Backends::Prism::Comment

Constant Summary collapse

ATTACHMENT_HINTS =
%i[leading inline trailing].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(comment, source: nil, attachment_hint: nil) ⇒ Comment

Returns a new instance of Comment.



25
26
27
28
29
# File 'lib/tree_haver/base/comment.rb', line 25

def initialize(comment, source: nil, attachment_hint: nil)
  @inner_comment = comment
  @source = source
  @attachment_hint = normalize_attachment_hint(attachment_hint)
end

Instance Attribute Details

#attachment_hintSymbol? (readonly)

Optional parser-provided attachment hint.

Returns:

  • (Symbol, nil)


23
24
25
# File 'lib/tree_haver/base/comment.rb', line 23

def attachment_hint
  @attachment_hint
end

#inner_commentObject (readonly)

The underlying backend-specific comment object.

Returns:

  • (Object)


15
16
17
# File 'lib/tree_haver/base/comment.rb', line 15

def inner_comment
  @inner_comment
end

#sourceString? (readonly)

The source text used for fallback range extraction.

Returns:

  • (String, nil)


19
20
21
# File 'lib/tree_haver/base/comment.rb', line 19

def source
  @source
end

Instance Method Details

#at_file_end?Boolean

Whether this comment ends at the final line of the available source.

Returns:

  • (Boolean)


213
214
215
216
217
# File 'lib/tree_haver/base/comment.rb', line 213

def at_file_end?
  return false if source_lines.none?

  end_line >= source_lines.length
end

#at_file_start?Boolean

Whether this comment starts at the first line of the available source.

Returns:

  • (Boolean)


206
207
208
# File 'lib/tree_haver/base/comment.rb', line 206

def at_file_start?
  start_line == 1
end

#attachment_hint?Boolean

Whether this comment has a parser-provided attachment hint.

Returns:

  • (Boolean)


152
153
154
# File 'lib/tree_haver/base/comment.rb', line 152

def attachment_hint?
  !attachment_hint.nil?
end

#blank_line_count_afterInteger

Return the count of immediately following blank source lines.

Returns:

  • (Integer)


273
274
275
# File 'lib/tree_haver/base/comment.rb', line 273

def blank_line_count_after
  blank_lines_after.length
end

#blank_line_count_beforeInteger

Return the count of immediately preceding blank source lines.

Returns:

  • (Integer)


266
267
268
# File 'lib/tree_haver/base/comment.rb', line 266

def blank_line_count_before
  blank_lines_before.length
end

#blank_lines_afterArray<String>

Return the contiguous blank source lines immediately after this comment.

Returns:

  • (Array<String>)


246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
# File 'lib/tree_haver/base/comment.rb', line 246

def blank_lines_after
  return [] if at_file_end?

  line_num = end_line + 1
  blanks = []

  while line_num <= source_lines.length
    line = source_line(line_num)
    break unless line && line.strip.empty?

    blanks << line
    line_num += 1
  end

  blanks
end

#blank_lines_beforeArray<String>

Return the contiguous blank source lines immediately before this comment.

This is parser-facing layout metadata. It does not decide ownership; it simply exposes spacing adjacent to the comment so merge layers can reason about floating vs attached behavior without rescanning source text.

Returns:

  • (Array<String>)


226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'lib/tree_haver/base/comment.rb', line 226

def blank_lines_before
  return [] if at_file_start?

  line_num = start_line - 1
  blanks = []

  while line_num >= 1
    line = source_line(line_num)
    break unless line && line.strip.empty?

    blanks.unshift(line)
    line_num -= 1
  end

  blanks
end

#block?Boolean

Whether this comment uses a block-comment style.

Returns:

  • (Boolean)


138
139
140
# File 'lib/tree_haver/base/comment.rb', line 138

def block?
  style == :block
end

#body_textString

Get the comment body with outer delimiters removed when possible.

Backends with richer native comment models should override this when they can provide a more semantically accurate body than simple delimiter trimming.

Returns:

  • (String)


103
104
105
# File 'lib/tree_haver/base/comment.rb', line 103

def body_text
  extract_body_text(text.to_s)
end

#closing_delimiterString?

Get the closing delimiter for the comment, when applicable.

This is typically nil for line comments.

Returns:

  • (String, nil)


92
93
94
# File 'lib/tree_haver/base/comment.rb', line 92

def closing_delimiter
  nil
end

#delimiter_metadataHash{Symbol => String, nil}

Get delimiter/body metadata in one normalized hash.

Returns:

  • (Hash{Symbol => String, nil})


120
121
122
123
124
125
126
# File 'lib/tree_haver/base/comment.rb', line 120

def 
  {
    opening: opening_delimiter,
    closing: closing_delimiter,
    body: body_text
  }
end

#end_byteInteger

Get the end byte offset of the comment.

Returns:

  • (Integer)

Raises:

  • (NotImplementedError)


52
53
54
# File 'lib/tree_haver/base/comment.rb', line 52

def end_byte
  raise NotImplementedError, "#{self.class}#end_byte must be implemented"
end

#end_lineInteger

Get the 1-based end line.

Returns:

  • (Integer)


187
188
189
# File 'lib/tree_haver/base/comment.rb', line 187

def end_line
  end_point[:row] + 1
end

#end_pointHash{Symbol => Integer}

Get the end position (row/column, 0-based).

Returns:

  • (Hash{Symbol => Integer})


64
65
66
# File 'lib/tree_haver/base/comment.rb', line 64

def end_point
  { row: 0, column: 0 }
end

#inline?Boolean

Whether this comment is hinted as inline with its owner.

Returns:

  • (Boolean)


166
167
168
# File 'lib/tree_haver/base/comment.rb', line 166

def inline?
  attachment_hint == :inline
end

#inspectObject



277
278
279
# File 'lib/tree_haver/base/comment.rb', line 277

def inspect
  "#<#{self.class} type=#{type.inspect} range=#{start_byte}...#{end_byte}>"
end

#leading?Boolean

Whether this comment is hinted as leading its owner.

Returns:

  • (Boolean)


159
160
161
# File 'lib/tree_haver/base/comment.rb', line 159

def leading?
  attachment_hint == :leading
end

#line?Boolean

Whether this comment uses a line-comment style.

Returns:

  • (Boolean)


131
132
133
# File 'lib/tree_haver/base/comment.rb', line 131

def line?
  style == :line
end

#multiline?Boolean

Whether this comment spans multiple source lines.

Returns:

  • (Boolean)


145
146
147
# File 'lib/tree_haver/base/comment.rb', line 145

def multiline?
  start_line != end_line
end

#normalized_textString

Get a matching-friendly normalized comment body.

This strips leading and trailing whitespace from #body_text while preserving the raw rendered form in #text.

Returns:

  • (String)


113
114
115
# File 'lib/tree_haver/base/comment.rb', line 113

def normalized_text
  body_text.strip
end

#opening_delimiterString?

Get the opening delimiter for the comment, when the backend can provide it.

Examples:

  • # for hash comments
  • // for C-style line comments
  • <!-- for HTML/XML block comments

Returns:

  • (String, nil)


83
84
85
# File 'lib/tree_haver/base/comment.rb', line 83

def opening_delimiter
  nil
end

#source_positionHash{Symbol => Integer}

Get a normalized source-position hash.

Returns:

  • (Hash{Symbol => Integer})


194
195
196
197
198
199
200
201
# File 'lib/tree_haver/base/comment.rb', line 194

def source_position
  {
    start_line: start_line,
    end_line: end_line,
    start_column: start_point[:column],
    end_column: end_point[:column]
  }
end

#start_byteInteger

Get the start byte offset of the comment.

Returns:

  • (Integer)

Raises:

  • (NotImplementedError)


46
47
48
# File 'lib/tree_haver/base/comment.rb', line 46

def start_byte
  raise NotImplementedError, "#{self.class}#start_byte must be implemented"
end

#start_lineInteger

Get the 1-based start line.

Returns:

  • (Integer)


180
181
182
# File 'lib/tree_haver/base/comment.rb', line 180

def start_line
  start_point[:row] + 1
end

#start_pointHash{Symbol => Integer}

Get the start position (row/column, 0-based).

Returns:

  • (Hash{Symbol => Integer})


58
59
60
# File 'lib/tree_haver/base/comment.rb', line 58

def start_point
  { row: 0, column: 0 }
end

#styleSymbol?

Get the normalized delimiter style.

Returns:

  • (Symbol, nil)


71
72
73
# File 'lib/tree_haver/base/comment.rb', line 71

def style
  nil
end

#textString

Get the comment text including delimiters when appropriate.

Returns:

  • (String)

Raises:

  • (NotImplementedError)


40
41
42
# File 'lib/tree_haver/base/comment.rb', line 40

def text
  raise NotImplementedError, "#{self.class}#text must be implemented"
end

#trailing?Boolean

Whether this comment is hinted as trailing its owner.

Returns:

  • (Boolean)


173
174
175
# File 'lib/tree_haver/base/comment.rb', line 173

def trailing?
  attachment_hint == :trailing
end

#typeString

Get the normalized comment type. Examples: "inline_comment", "block_comment".

Returns:

  • (String)

Raises:

  • (NotImplementedError)


34
35
36
# File 'lib/tree_haver/base/comment.rb', line 34

def type
  raise NotImplementedError, "#{self.class}#type must be implemented"
end