Class: Bash::Merge::FileAnalysis

Inherits:
Object
  • Object
show all
Includes:
Ast::Merge::FileAnalyzable
Defined in:
lib/bash/merge/file_analysis.rb

Overview

Analyzes Bash script structure, extracting nodes, comments, and freeze blocks. This is the main analysis class that prepares Bash content for merging.

Examples:

Basic usage

analysis = FileAnalysis.new(bash_source)
analysis.valid? # => true
analysis.nodes # => [NodeWrapper, FreezeNodeBase, ...]
analysis.freeze_blocks # => [FreezeNodeBase, ...]

Constant Summary collapse

DEFAULT_FREEZE_TOKEN =

Default freeze token for identifying freeze blocks

"bash-merge"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(source, freeze_token: DEFAULT_FREEZE_TOKEN, signature_generator: nil, parser_path: nil, **options) ⇒ FileAnalysis

Initialize file analysis



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/bash/merge/file_analysis.rb', line 45

def initialize(source, freeze_token: DEFAULT_FREEZE_TOKEN, signature_generator: nil, parser_path: nil, **options)
  @source = source
  @lines = source.lines.map(&:chomp)
  @freeze_token = freeze_token
  @signature_generator = signature_generator
  @parser_path = parser_path || self.class.find_parser_path
  @errors = []
  # **options captures any additional parameters (e.g., node_typing) for forward compatibility

  # Initialize comment tracking
  @comment_tracker = CommentTracker.new(source)

  # Parse the Bash script
  DebugLogger.time("FileAnalysis#parse_bash") { parse_bash }

  # Extract freeze blocks and integrate with nodes
  @freeze_blocks = extract_freeze_blocks
  @nodes = integrate_nodes_and_freeze_blocks

  DebugLogger.debug("FileAnalysis initialized", {
    signature_generator: signature_generator ? "custom" : "default",
    nodes_count: @nodes.size,
    freeze_blocks: @freeze_blocks.size,
    valid: valid?,
  })
end

Instance Attribute Details

#astTreeHaver::Tree? (readonly)



23
24
25
# File 'lib/bash/merge/file_analysis.rb', line 23

def ast
  @ast
end

#comment_trackerCommentTracker (readonly)



20
21
22
# File 'lib/bash/merge/file_analysis.rb', line 20

def comment_tracker
  @comment_tracker
end

#errorsArray (readonly)



26
27
28
# File 'lib/bash/merge/file_analysis.rb', line 26

def errors
  @errors
end

Class Method Details

.find_parser_pathString?

Find the parser library path using TreeHaver::GrammarFinder

Raises:

  • (TreeHaver::NotAvailable)

    if ENV is set to invalid path



33
34
35
# File 'lib/bash/merge/file_analysis.rb', line 33

def find_parser_path
  TreeHaver::GrammarFinder.new(:bash).find_library_path
end

Instance Method Details

#fallthrough_node?(value) ⇒ Boolean

Override to detect tree-sitter nodes for signature generator fallthrough



106
107
108
# File 'lib/bash/merge/file_analysis.rb', line 106

def fallthrough_node?(value)
  value.is_a?(NodeWrapper) || value.is_a?(FreezeNode) || super
end

#freeze_block_at(line_num) ⇒ FreezeNode?

Get the freeze block containing the given line.



99
100
101
# File 'lib/bash/merge/file_analysis.rb', line 99

def freeze_block_at(line_num)
  @freeze_blocks.find { |fb| fb.location.cover?(line_num) }
end

#in_freeze_block?(line_num) ⇒ Boolean

Check if a line is within a freeze block.



91
92
93
# File 'lib/bash/merge/file_analysis.rb', line 91

def in_freeze_block?(line_num)
  @freeze_blocks.any? { |fb| fb.location.cover?(line_num) }
end

#root_nodeNodeWrapper?

Get the root node of the parse tree



112
113
114
115
116
# File 'lib/bash/merge/file_analysis.rb', line 112

def root_node
  return unless valid?

  NodeWrapper.new(@ast.root_node, lines: @lines, source: @source)
end

#statementsArray<NodeWrapper, FreezeNodeBase> Also known as: nodes

The base module uses ‘statements’ - provide both names for compatibility



80
81
82
# File 'lib/bash/merge/file_analysis.rb', line 80

def statements
  @nodes ||= []
end

#top_level_statementsArray<NodeWrapper>

Get top-level statements from the script



120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/bash/merge/file_analysis.rb', line 120

def top_level_statements
  return [] unless valid?

  root = @ast.root_node
  return [] unless root

  statements = []
  root.each do |child|
    next if child.type.to_s == "comment" # Comments handled separately

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

#valid?Boolean

Check if parse was successful



74
75
76
# File 'lib/bash/merge/file_analysis.rb', line 74

def valid?
  @errors.empty? && !@ast.nil?
end