### Install Syntax Tree Gem Source: https://github.com/ruby-syntax-tree/syntax_tree/blob/main/README.md Install the gem globally for command-line usage. ```sh gem install syntax_tree ``` -------------------------------- ### AST Output Example Source: https://github.com/ruby-syntax-tree/syntax_tree/blob/main/README.md Example output of the `stree ast` command for a simple expression. ```text (program (statements (binary (int "1") + (int "1")))) ``` -------------------------------- ### ArithmeticVisitor Source: https://github.com/ruby-syntax-tree/syntax_tree/blob/main/README.md An example visitor class demonstrating how to traverse the syntax tree and perform operations on specific node types, such as finding arithmetic operations between integers. ```APIDOC ## Visitor Pattern ### Description If you want to operate over a set of nodes in the tree but don't want to walk the tree manually, the `Visitor` class makes it easy. `SyntaxTree::Visitor` is an implementation of the double dispatch visitor pattern. It works by the user defining visit methods that process nodes in the tree, which then call back to other visit methods to continue the descent. ### Example Usage ```ruby class ArithmeticVisitor < SyntaxTree::Visitor def visit_binary(node) if node in { left: SyntaxTree::Int, operator: :+ | :- | :* | :/, right: SyntaxTree::Int } puts "The result is: #{node.left.value.to_i.public_send(node.operator, node.right.value.to_i)}" end end end visitor = ArithmeticVisitor.new visitor.visit(SyntaxTree.parse("1 + 1")) ``` ### Response Example ```ruby # Outputs the result of the arithmetic operation. # The result is: 2 ``` ``` -------------------------------- ### Start language server with stree lsp Source: https://context7.com/ruby-syntax-tree/syntax_tree/llms.txt Starts an LSP-compliant language server over stdin/stdout. This enables features like formatting and inlay hints in compatible editors. ```sh stree lsp # Connects via stdin/stdout. Configure in your editor: # neovim (nvim-lspconfig), VSCode (vscode-syntax-tree extension), # Vim (dense-analysis/ale), Emacs (emacs-format-all-the-code) ``` -------------------------------- ### Run CLI with Gem Bundle Source: https://github.com/ruby-syntax-tree/syntax_tree/blob/main/README.md Execute the stree CLI when the gem is installed in your project's bundle. ```sh bundle exec stree version ``` -------------------------------- ### Build AST Nodes Programmatically with `SyntaxTree::DSL` Source: https://context7.com/ruby-syntax-tree/syntax_tree/llms.txt Include `SyntaxTree::DSL` to get shorthand constructor methods for every node type. This is useful for creating synthetic trees in codemods or tests. ```ruby require "syntax_tree" require "syntax_tree/dsl" include SyntaxTree::DSL # Build `1 + 2` programmatically expr = Binary( Int("1"), :+, Int("2") ) pp expr # (binary (int "1") + (int "2")) # Build a full method definition node method_node = DefNode( nil, # target (nil = instance method) nil, # operator Ident("greet"), Params([], [], nil, [], [], nil, nil), BodyStmt( Statements([Command(Ident("puts"), Args([Ident("name")]), nil)]), nil, nil, nil, nil ) ) pp method_node ``` -------------------------------- ### Transform AST with `SyntaxTree::MutationVisitor` Source: https://context7.com/ruby-syntax-tree/syntax_tree/llms.txt `MutationVisitor` walks the tree, copies each node, then applies registered mutation callbacks that match a given pattern. This example renames all calls to `old_method` to `new_method`. ```ruby require "syntax_tree" # Rename all calls to `old_method` → `new_method` visitor = SyntaxTree::MutationVisitor.new visitor.mutate('CallNode[message: Ident[value: "old_method"]]') do |node| new_name = node.message.copy(value: "new_method") node.copy(message: new_name) end source = "obj.old_method(1, 2)" program = SyntaxTree.parse(source) mutated = program.accept(visitor) puts SyntaxTree::Formatter.format(source, mutated) # => obj.new_method(1, 2) ``` -------------------------------- ### Count Method Definitions with `SyntaxTree::Visitor` Source: https://context7.com/ruby-syntax-tree/syntax_tree/llms.txt Subclass `Visitor` and define `visit_*` methods for specific node types. Unhandled nodes are automatically visited. This example counts all method definitions and their names. ```ruby require "syntax_tree" # Count all method definitions and their names class MethodCounter < SyntaxTree::Visitor attr_reader :methods def initialize @methods = [] end visit_method def visit_def(node) @methods << node.name.value super # continue descending to find nested defs end end source = File.read("lib/my_app.rb") program = SyntaxTree.parse(source) counter = MethodCounter.new counter.visit(program) puts counter.methods.inspect # => ["initialize", "call", "format", ...] ``` -------------------------------- ### Index Definitions in Ruby Source Source: https://context7.com/ruby-syntax-tree/syntax_tree/llms.txt Use `SyntaxTree.index` to get a flat array of definitions (classes, modules, methods, constants) from Ruby source code, including their names, nesting, locations, and comments. ```ruby source = <<~RUBY # Top-level utility module Utils # Formats a greeting def self.greet(name) "Hello, #{name}" end class Formatter def format(str) str.strip end end end RUBY entries = SyntaxTree.index(source) entries.each do |entry| case entry in SyntaxTree::Index::ModuleDefinition[name:, location:] puts "Module #{name} at line #{location.line}" in SyntaxTree::Index::SingletonMethodDefinition[name:, location:] puts "Singleton method .#{name} at line #{location.line}" in SyntaxTree::Index::MethodDefinition[name:, nesting:, location:] puts "Method ##{name} in #{nesting.flatten.join('::')} at line #{location.line}" in SyntaxTree::Index::ClassDefinition[name:, superclass:] puts "Class #{name} (superclass: #{superclass})" end end # Module Utils at line 2 # Singleton method .greet at line 4 # Class Formatter at line 9 # Method #format in Utils::Formatter at line 10 ``` -------------------------------- ### Index Definitions in Ruby File Source: https://context7.com/ruby-syntax-tree/syntax_tree/llms.txt Use `SyntaxTree.index_file` to get indexed definitions from a Ruby file. This is a convenience wrapper around `SyntaxTree.index` that reads the file automatically. ```ruby entries = SyntaxTree.index_file("lib/my_app.rb") methods = entries.select { |e| e.is_a?(SyntaxTree::Index::MethodDefinition) } puts methods.map(&:name) ``` -------------------------------- ### Register Plugins with CLI Source: https://github.com/ruby-syntax-tree/syntax_tree/blob/main/README.md Pass a comma-delimited list of plugin names to the `--plugins` option when invoking the CLI to customize Syntax Tree's behavior. The CLI will require these files. ```sh --plugins=my_plugin ``` -------------------------------- ### Enumerate direct children of a node Source: https://context7.com/ruby-syntax-tree/syntax_tree/llms.txt Use the `#child_nodes` method on a node to get an array of its direct children. This is useful for recursive manual walks of the syntax tree. ```ruby program = SyntaxTree.parse("1 + 2 * 3") binary = program.statements.body.first # (binary ...) binary.child_nodes # => [SyntaxTree::Int("1"), SyntaxTree::Op(:+), SyntaxTree::Binary(...)] # Recursive manual walk def walk(node, depth = 0) puts " " * depth + node.class.name.split("::").last node.child_nodes.each { |child| walk(child, depth + 1) } end walk(program) ``` -------------------------------- ### Create a MutationVisitor Source: https://context7.com/ruby-syntax-tree/syntax_tree/llms.txt Use `SyntaxTree.mutation` as a shorthand for `SyntaxTree::MutationVisitor.new` to create a visitor that modifies the syntax tree. Yields a new `MutationVisitor` to the block and returns it. ```ruby # Wrap all if-predicates that contain assignments in parentheses visitor = SyntaxTree.mutation do |v| v.mutate("IfNode[predicate: Assign | OpAssign]") do |node| predicate = SyntaxTree::Paren.new( lparen: SyntaxTree::LParen.new(value: "(", location: node.location), contents: node.predicate, location: node.location ) node.copy(predicate: predicate) end end source = "if a = 1; puts a; end" program = SyntaxTree.parse(source) mutated = program.accept(visitor) puts SyntaxTree::Formatter.format(source, mutated) ``` -------------------------------- ### CLI Configuration with .streerc Source: https://github.com/ruby-syntax-tree/syntax_tree/blob/main/README.md Specify CLI arguments in a .streerc file for consistent command execution. Options in this file are applied first, and command-line arguments override them. ```txt --print-width=100 --plugins=plugin/trailing_comma ``` -------------------------------- ### Generate AST for a File Source: https://github.com/ruby-syntax-tree/syntax_tree/blob/main/README.md Prints a textual representation of the syntax tree for a given Ruby file. ```sh stree ast path/to/file.rb ``` -------------------------------- ### Define Visit Method with Syntax Tree Source: https://github.com/ruby-syntax-tree/syntax_tree/blob/main/README.md Use `visit_method` to ensure that defined visitor methods are valid. This check is performed once when the file is required, raising an error for typos or non-existent methods. ```ruby class ArithmeticVisitor < SyntaxTree::Visitor visit_method def visit_binary(node) # ... end end ``` -------------------------------- ### Pretty Print Syntax Tree Nodes Source: https://github.com/ruby-syntax-tree/syntax_tree/blob/main/README.md Outputs a human-readable representation of the syntax tree using the `pp` library. Primarily for debugging and inspection. ```ruby pp SyntaxTree.parse("1 + 1") # (program (statements (binary (int "1") + (int "1")))) ``` -------------------------------- ### SyntaxTree.format_file(filepath, maxwidth, base_indentation, options:) Source: https://context7.com/ruby-syntax-tree/syntax_tree/llms.txt Reads a Ruby file, formats its content, and returns the formatted content as a string without modifying the original file. ```APIDOC ## SyntaxTree.format_file(filepath, maxwidth, base_indentation, options:) ### Description Reads a file and returns its formatted content as a string without modifying the file. ### Method `SyntaxTree.format_file(filepath, maxwidth = 80, base_indentation = 0, options: SyntaxTree::Formatter::Options.new)` ### Parameters - **filepath** (String) - The path to the Ruby file to format. - **maxwidth** (Integer, optional) - The maximum width for formatting. Defaults to 80. - **base_indentation** (Integer, optional) - The base indentation level. Defaults to 0. - **options** (SyntaxTree::Formatter::Options, optional) - An object with formatting options. ### Request Example ```ruby formatted = SyntaxTree.format_file("lib/my_app.rb", 100) File.write("lib/my_app.rb", formatted) ``` ### Response #### Success Response - **formatted_content** (String) - The formatted content of the file. ### Response Example ```ruby # formatted would be a string containing the formatted Ruby code. ``` ``` -------------------------------- ### SyntaxTree.format(source, maxwidth, base_indentation, options:) Source: https://context7.com/ruby-syntax-tree/syntax_tree/llms.txt Parses Ruby source code from a string and returns the formatted string. Allows customization of width, indentation, and formatting options. ```APIDOC ## SyntaxTree.format(source, maxwidth, base_indentation, options:) ### Description Parses and formats a source string. Returns the formatted string. `maxwidth` defaults to `80`; `base_indentation` defaults to `0`. ### Method `SyntaxTree.format(source, maxwidth = 80, base_indentation = 0, options: SyntaxTree::Formatter::Options.new) ### Parameters - **source** (String) - The Ruby source code to format. - **maxwidth** (Integer, optional) - The maximum width for formatting. Defaults to 80. - **base_indentation** (Integer, optional) - The base indentation level. Defaults to 0. - **options** (SyntaxTree::Formatter::Options, optional) - An object with formatting options like quote style and trailing commas. ### Request Example ```ruby require "syntax_tree" ugly = "def foo(x,y,z); x+y+z; end" puts SyntaxTree.format(ugly) # Custom width puts SyntaxTree.format(ugly, 40) # With options object opts = SyntaxTree::Formatter::Options.new( quote: "'", # single quotes trailing_comma: true, # trailing commas in multi-line disable_auto_ternary: false ) puts SyntaxTree.format(ugly, 80, 0, options: opts) ``` ### Response #### Success Response - **formatted_string** (String) - The formatted Ruby source code. ### Response Example ```ruby # def foo(x, y, z) # x + y + z # end ``` ``` -------------------------------- ### Check Formatting Success Message Source: https://github.com/ruby-syntax-tree/syntax_tree/blob/main/README.md Output when all files match the expected format. ```text All files matched expected format. ``` -------------------------------- ### Configure RuboCop with Syntax Tree Source: https://github.com/ruby-syntax-tree/syntax_tree/blob/main/README.md Integrate Syntax Tree's RuboCop configuration by adding `inherit_gem` to your `.rubocop.yml` file. This disables redundant rules. ```yaml inherit_gem: syntax_tree: config/rubocop.yml ``` -------------------------------- ### Format and write Ruby code back to files Source: https://github.com/ruby-syntax-tree/syntax_tree/blob/main/README.md Formats the listed Ruby files and writes the formatted content back to the source files, overwriting the originals. Use version control. The `--print-width` option controls formatting width, and `--ignore-files` can exclude specific files or globs. ```sh stree write path/to/file.rb ``` ```sh stree write --print-width=100 path/to/file.rb ``` ```sh stree write --ignore-files='db/**/*.rb' '**/*.rb' ``` -------------------------------- ### Define Multiple Visit Methods with Syntax Tree Source: https://github.com/ruby-syntax-tree/syntax_tree/blob/main/README.md Use `visit_methods` to validate multiple visitor methods defined within a block. This provides a convenient way to check all methods at once without runtime overhead. ```ruby class ArithmeticVisitor < SyntaxTree::Visitor visit_methods do def visit_binary(node) # ... end def visit_int(node) # ... end end end ``` -------------------------------- ### Guard Against Typos with `Visitor.visit_method` and `Visitor.visit_methods` Source: https://context7.com/ruby-syntax-tree/syntax_tree/llms.txt These class-level macros validate that the method name you are defining is a real `visit_*` method, raising `VisitMethodError` at load time if it is not. Use `visit_method` for single methods and `visit_methods` for blocks of methods. ```ruby class SafeVisitor < SyntaxTree::Visitor # Single-method guard visit_method def visit_binary(node) puts node.operator super end # Block guard — all defs inside are checked visit_methods do def visit_int(node) puts "Int: #{node.value}" end def visit_float(node) puts "Float: #{node.value}" end # def visit_intger(node) # => VisitMethodError: Invalid visit method: visit_intger # # Did you mean? visit_int end end visitor = SafeVisitor.new visitor.visit(SyntaxTree.parse("1 + 2.5")) # Int: 1 # Float: 2.5 ``` -------------------------------- ### Loading Built-in Formatter Plugins Source: https://context7.com/ruby-syntax-tree/syntax_tree/llms.txt Load formatter plugins via the CLI, require statements, or an Options object for library usage. ```ruby # Load via CLI # stree format --plugins=plugin/single_quotes,plugin/trailing_comma lib/**/*.rb ``` ```ruby # Load via require (for library usage) require "syntax_tree/plugin/single_quotes" # use '' instead of "" require "syntax_tree/plugin/trailing_comma" # add trailing commas in multi-line require "syntax_tree/plugin/disable_auto_ternary" # keep if/else as-is ``` ```ruby # Load via Options object opts = SyntaxTree::Formatter::Options.new( quote: "'", trailing_comma: true, disable_auto_ternary: true ) puts SyntaxTree.format(source, 80, 0, options: opts) ``` -------------------------------- ### Print AST with stree ast Source: https://context7.com/ruby-syntax-tree/syntax_tree/llms.txt Prints a compact, pretty-printed representation of the full syntax tree for a Ruby file or from standard input. ```sh stree ast lib/my_file.rb ``` ```sh echo "1 + 1" | stree ast ``` ```sh stree ast -e "1 + 1" # => (program (statements (binary (int "1") + (int "1")))) ``` -------------------------------- ### SyntaxTree.mutation(&block) Source: https://context7.com/ruby-syntax-tree/syntax_tree/llms.txt Creates and yields a new `MutationVisitor` to a block, providing a shorthand for `SyntaxTree::MutationVisitor.new`. ```APIDOC ## SyntaxTree.mutation(&block) ### Description Creates a `MutationVisitor` and yields it to the block. This is a shorthand for `SyntaxTree::MutationVisitor.new`. ### Method `SyntaxTree.mutation(&block)` ### Parameters #### Block - **block** (Proc) - Required - A block that receives a `MutationVisitor` instance. ### Request Example ```ruby visitor = SyntaxTree.mutation do |v| v.mutate("IfNode[predicate: Assign | OpAssign]") do |node| predicate = SyntaxTree::Paren.new( lparen: SyntaxTree::LParen.new(value: "(", location: node.location), contents: node.predicate, location: node.location ) node.copy(predicate: predicate) end end source = "if a = 1; puts a; end" program = SyntaxTree.parse(source) mutated = program.accept(visitor) puts SyntaxTree::Formatter.format(source, mutated) ``` ``` -------------------------------- ### SyntaxTree.index Source: https://github.com/ruby-syntax-tree/syntax_tree/blob/main/README.md Indexes Ruby code to return a list of class, module, and method declarations, including associated comments. ```APIDOC ## SyntaxTree.index(source) ### Description This function takes an input string containing Ruby code and returns a list of all of the class declarations, module declarations, and method definitions within a file. Each of the entries also has access to its associated comments. This is useful for generating documentation or index information for a file to support something like go-to-definition. ### Method `SyntaxTree.index` ### Parameters #### Request Body - **source** (string) - Required - A string containing Ruby code. ``` -------------------------------- ### Display Implicit Parentheses with Inlay Hints Source: https://github.com/ruby-syntax-tree/syntax_tree/blob/main/README.md The language server can provide inlay hints to clarify code execution order, such as adding implicit parentheses to show operator precedence. ```ruby 1 + 2 * 3 ``` -------------------------------- ### Pattern matching on nodes Source: https://context7.com/ruby-syntax-tree/syntax_tree/llms.txt Demonstrates how to use Ruby's built-in deconstruct syntax for pattern matching on AST nodes. ```APIDOC ## Pattern matching on nodes ### Description All nodes support Ruby's built-in `=>` deconstruct syntax for pattern matching. ### Request Example ```ruby program = SyntaxTree.parse("1 + 1") # Loose pattern program => { statements: { body: [binary] } } binary # => (binary ...) # Strict typed pattern program => SyntaxTree::Program[ statements: SyntaxTree::Statements[ body: [SyntaxTree::Binary[left:, operator:, right:]] ] ] puts "#{left.value} #{operator} #{right.value}" # => 1 + 1 ``` ``` -------------------------------- ### Format Ruby File Source: https://context7.com/ruby-syntax-tree/syntax_tree/llms.txt Use `SyntaxTree.format_file` to read a file, format its content, and return the formatted string without modifying the original file. ```ruby formatted = SyntaxTree.format_file("lib/my_app.rb", 100) File.write("lib/my_app.rb", formatted) ``` -------------------------------- ### Search Ruby File Source: https://context7.com/ruby-syntax-tree/syntax_tree/llms.txt Use `SyntaxTree.search_file` as a convenience wrapper to search a Ruby file for nodes matching a query pattern, automatically handling file reading. ```ruby SyntaxTree.search_file("lib/my_app.rb", "DefNode") do |node| puts "Method: #{node.name.value} (line #{node.location.start_line})" end ``` -------------------------------- ### Check File Formatting Source: https://github.com/ruby-syntax-tree/syntax_tree/blob/main/README.md Ensures a Ruby file matches the expected format, useful for CI/git hooks. ```sh stree check path/to/file.rb ``` -------------------------------- ### Register a language plugin handler Source: https://context7.com/ruby-syntax-tree/syntax_tree/llms.txt Register a custom handler object for a file extension using `SyntaxTree.register_handler`. The handler must implement `.read`, `.parse`, and `.format` methods. ```ruby # Register a custom language handler module MyLang def self.read(filepath) = File.read(filepath) def self.parse(source) = MyLang::Parser.new(source).parse def self.format(source) = MyLang::Formatter.new(source).format end SyntaxTree.register_handler(".mylang", MyLang) # Now the CLI commands work with .mylang files: # stree format path/to/file.mylang # stree check path/to/file.mylang ``` -------------------------------- ### Verify formatting with stree check Source: https://context7.com/ruby-syntax-tree/syntax_tree/llms.txt Checks if files match the expected formatting and exits with a non-zero status if any file does not. Suitable for CI and pre-commit hooks. Can specify a custom print width. ```sh stree check 'lib/**/*.rb' # All files matched expected format. ``` ```sh stree check --print-width=100 'lib/**/*.rb' # [warn] lib/my_file.rb # The listed files did not match the expected format. ``` -------------------------------- ### SyntaxTree.index(source) Source: https://context7.com/ruby-syntax-tree/syntax_tree/llms.txt Indexes the Ruby source code to extract definitions of classes, modules, methods, and constants, returning a flat array of index entries. ```APIDOC ## SyntaxTree.index(source) ### Description Returns a flat array of `ClassDefinition`, `ModuleDefinition`, `MethodDefinition`, `SingletonMethodDefinition`, `AliasMethodDefinition`, and `ConstantDefinition` entries with their names, nesting, locations, and associated comments. ### Method `SyntaxTree.index(source)` ### Parameters - **source** (String) - The Ruby source code to index. ### Request Example ```ruby source = <<~RUBY # Top-level utility module Utils # Formats a greeting def self.greet(name) "Hello, #{name}" end class Formatter def format(str) str.strip end end end RUBY entries = SyntaxTree.index(source) entries.each do |entry| case entry in SyntaxTree::Index::ModuleDefinition[name:, location:] puts "Module #{name} at line #{location.line}" in SyntaxTree::Index::SingletonMethodDefinition[name:, location:] puts "Singleton method .#{name} at line #{location.line}" in SyntaxTree::Index::MethodDefinition[name:, nesting:, location:] puts "Method ##{name} in #{nesting.flatten.join('::')} at line #{location.line}" in SyntaxTree::Index::ClassDefinition[name:, superclass:] puts "Class #{name} (superclass: #{superclass})" end end ``` ### Response #### Success Response - **entries** (Array) - An array of index entries, each representing a definition found in the source code. ### Response Example ```ruby # Module Utils at line 2 # Singleton method .greet at line 4 # Class Formatter at line 9 # Method #format in Utils::Formatter at line 10 ``` ``` -------------------------------- ### SyntaxTree.index_file(filepath) Source: https://context7.com/ruby-syntax-tree/syntax_tree/llms.txt Indexes a Ruby file by reading its content and extracting definitions of classes, modules, methods, and constants. ```APIDOC ## SyntaxTree.index_file(filepath) ### Description Reads a file and returns a flat array of index entries for classes, modules, methods, and constants. ### Method `SyntaxTree.index_file(filepath)` ### Parameters - **filepath** (String) - The path to the Ruby file to index. ### Request Example ```ruby entries = SyntaxTree.index_file("lib/my_app.rb") methods = entries.select { |e| e.is_a?(SyntaxTree::Index::MethodDefinition) } puts methods.map(&:name) ``` ### Response #### Success Response - **entries** (Array) - An array of index entries found in the specified file. ### Response Example ```ruby # An array of SyntaxTree::Index::* objects. ``` ``` -------------------------------- ### SyntaxTree.search_file(filepath, query, &block) Source: https://context7.com/ruby-syntax-tree/syntax_tree/llms.txt A convenience method that reads a file, parses it, and then searches the resulting AST for nodes matching the query pattern. ```APIDOC ## SyntaxTree.search_file(filepath, query, &block) ### Description Convenience wrapper around `search` that reads the file automatically. ### Method `SyntaxTree.search_file(filepath, query)` ### Parameters - **filepath** (String) - The path to the Ruby file to read, parse, and search. - **query** (String) - A pattern string (Ruby `in`-clause syntax) to match nodes. - **&block** (Block) - A block that will be executed for each matching node. ### Request Example ```ruby SyntaxTree.search_file("lib/my_app.rb", "DefNode") do |node| puts "Method: #{node.name.value} (line #{node.location.start_line})" end ``` ### Response #### Success Response - **Yields** - Each matching AST node found in the file is yielded to the block. ### Response Example ```ruby # Output depends on the file content and query. ``` ``` -------------------------------- ### SyntaxTree.read(filepath) Source: https://context7.com/ruby-syntax-tree/syntax_tree/llms.txt Reads a file and correctly handles Ruby encoding magic comments like `# encoding: ...` or `# -*- coding: ...`. ```APIDOC ## SyntaxTree.read(filepath) ### Description Reads a file respecting Ruby-level encoding magic comments (`# encoding: ...`). ### Method `SyntaxTree.read(filepath)` ### Parameters #### Path Parameters - **filepath** (String) - Required - The path to the file to read. ### Request Example ```ruby source = SyntaxTree.read("lib/my_file.rb") ``` ``` -------------------------------- ### Track Local Variables with WithScope Visitor Source: https://github.com/ruby-syntax-tree/syntax_tree/blob/main/README.md Include the `WithScope` module in your visitor to automatically manage local variables and arguments within scopes. Use `current_scope.find_local` to locate definitions and usages. ```ruby class MyVisitor < Visitor prepend WithScope def visit_ident(node) # find_local will return a Local for any local variables or arguments # present in the current environment or nil if the identifier is not a local local = current_scope.find_local(node) puts local.type # the type of the local (:variable or :argument) puts local.definitions # the array of locations where this local is defined puts local.usages # the array of locations where this local occurs end end ``` -------------------------------- ### Invoke Syntax Tree Language Server Source: https://github.com/ruby-syntax-tree/syntax_tree/blob/main/README.md Run the Syntax Tree language server from the CLI using the `stree lsp` command. This server provides features like code formatting and inlay hints. ```sh stree lsp ``` -------------------------------- ### Strict Visiting with `SyntaxTree::BasicVisitor` Source: https://context7.com/ruby-syntax-tree/syntax_tree/llms.txt Inheriting from `BasicVisitor` causes the visitor to raise an error if it encounters a node type for which no `visit_*` method is defined. This is useful for ensuring all node types are handled. ```ruby # A visitor that ONLY handles Int nodes — will error on anything else class IntOnlyVisitor < SyntaxTree::BasicVisitor def visit_int(node) puts "Found int: #{node.value}" end end visitor = IntOnlyVisitor.new # OK — only Int nodes in this tree visitor.visit(SyntaxTree.parse("42")) # Found int: 42 # Raises — encounters Program/Statements/Binary/etc. # visitor.visit(SyntaxTree.parse("1 + 2")) ``` -------------------------------- ### Track Scope with `SyntaxTree::WithScope` Source: https://context7.com/ruby-syntax-tree/syntax_tree/llms.txt Include `WithScope` in a visitor to automatically maintain scope information as the tree is walked. Access it via `current_scope` to find local variables, their types, definitions, and usages. ```ruby require "syntax_tree" require "syntax_tree/with_scope" class ScopeAnalyzer < SyntaxTree::Visitor include SyntaxTree::WithScope def visit_ident(node) local = current_scope.find_local(node.value) return unless local type = local.type # :argument or :variable defs = local.definitions # Array of Location uses = local.usages # Array of Location puts "#{node.value}: #{type}, #{defs.length} def(s), #{uses.length} use(s)" super end end source = <<~RUBY def calculate(x, y) result = x + y result * 2 end RUBY analyzer = ScopeAnalyzer.new analyzer.visit(SyntaxTree.parse(source)) # x: argument, 1 def(s), 1 use(s) # y: argument, 1 def(s), 1 use(s) # result: variable, 1 def(s), 1 use(s) ``` -------------------------------- ### Add Syntax Tree to Gemfile Source: https://github.com/ruby-syntax-tree/syntax_tree/blob/main/README.md Add the gem to your application's Gemfile for library usage. ```ruby gem "syntax_tree" ``` -------------------------------- ### SyntaxTree.format Source: https://github.com/ruby-syntax-tree/syntax_tree/blob/main/README.md Parses Ruby code, formats it, and returns the formatted string. Optionally specifies the maximum print width. ```APIDOC ## SyntaxTree.format(source, width = 80) ### Description This function takes an input string containing Ruby code, parses it into its underlying syntax tree, and formats it back out to a string. You can optionally pass a second argument to this method as well that is the maximum width to print. It defaults to `80`. ### Method `SyntaxTree.format` ### Parameters #### Request Body - **source** (string) - Required - A string containing Ruby code. - **width** (integer) - Optional - The maximum width for formatting. Defaults to 80. ``` -------------------------------- ### Rake Integration for Syntax Tree Tasks Source: https://context7.com/ruby-syntax-tree/syntax_tree/llms.txt Add formatting tasks to your Rakefile using `SyntaxTree::Rake::CheckTask` and `SyntaxTree::Rake::WriteTask`. `CheckTask` maps to `rake stree:check`; `WriteTask` maps to `rake stree:write`. ```ruby # Rakefile require "syntax_tree/rake_tasks" # Default configuration (checks/writes lib/**/*.rb) SyntaxTree::Rake::CheckTask.new SyntaxTree::Rake::WriteTask.new ``` -------------------------------- ### Format and overwrite files with stree write Source: https://context7.com/ruby-syntax-tree/syntax_tree/llms.txt Formats Ruby files in-place. Supports glob patterns for selecting files and options to ignore specific paths or set a custom print width. ```sh stree write 'lib/**/*.rb' 'test/**/*.rb' ``` ```sh stree write --ignore-files='db/**/*.rb' '**/*.rb' ``` ```sh stree write --print-width=120 'lib/**/*.rb' ``` -------------------------------- ### SyntaxTree.register_handler(extension, handler) Source: https://context7.com/ruby-syntax-tree/syntax_tree/llms.txt Registers a handler object for a given file extension. The handler must implement `.read`, `.parse`, and `.format` methods. ```APIDOC ## SyntaxTree.register_handler(extension, handler) ### Description Registers a handler object for a specific file extension. The provided handler must implement `.read`, `.parse`, and `.format` methods. ### Method `SyntaxTree.register_handler(extension, handler)` ### Parameters #### Path Parameters - **extension** (String) - Required - The file extension to register the handler for (e.g., ".mylang"). - **handler** (Object) - Required - The handler object that implements `.read`, `.parse`, and `.format`. ### Request Example ```ruby module MyLang def self.read(filepath) = File.read(filepath) def self.parse(source) = MyLang::Parser.new(source).parse def self.format(source) = MyLang::Formatter.new(source).format end SyntaxTree.register_handler(".mylang", MyLang) ``` ``` -------------------------------- ### Format Ruby Source String Source: https://context7.com/ruby-syntax-tree/syntax_tree/llms.txt Use `SyntaxTree.format` to parse and format a Ruby source string. Customize `maxwidth` and `base_indentation`. Options can be passed via a `SyntaxTree::Formatter::Options` object. ```ruby require "syntax_tree" ugly = "def foo(x,y,z); x+y+z; end" puts SyntaxTree.format(ugly) # def foo(x, y, z) # x + y + z # end # Custom width puts SyntaxTree.format(ugly, 40) # With options object opts = SyntaxTree::Formatter::Options.new( quote: "'", # single quotes trailing_comma: true, # trailing commas in multi-line disable_auto_ternary: false ) puts SyntaxTree.format(ugly, 80, 0, options: opts) ``` -------------------------------- ### Format a node directly using Formatter Source: https://context7.com/ruby-syntax-tree/syntax_tree/llms.txt Use `SyntaxTree::Formatter.format(source, node)` as a class-level shortcut to format any already-parsed node without going through `SyntaxTree.format`. Requires the original source string. ```ruby source = "x=1;y=2" program = SyntaxTree.parse(source) node = program.statements.body.first # first Assign puts SyntaxTree::Formatter.format(source, node) # => x = 1 ``` -------------------------------- ### Implement Custom Visitor for Syntax Tree Traversal Source: https://github.com/ruby-syntax-tree/syntax_tree/blob/main/README.md Defines a custom visitor class to operate on specific nodes within the syntax tree without manual traversal. Useful for analyzing or transforming the tree. ```ruby class ArithmeticVisitor < SyntaxTree::Visitor def visit_binary(node) if node in { left: SyntaxTree::Int, operator: :+ | :- | :* | :/, right: SyntaxTree::Int } puts "The result is: #{node.left.value.to_i.public_send(node.operator, node.right.value.to_i)}" end end end visitor = ArithmeticVisitor.new visitor.visit(SyntaxTree.parse("1 + 1")) ``` -------------------------------- ### format Source: https://github.com/ruby-syntax-tree/syntax_tree/blob/main/README.md Formats the node's content nicely using a provided formatter object. This method is part of the `pretty_print` gem compatibility and is typically used indirectly via `SyntaxTree.format`. ```APIDOC ## format(q) ### Description Every node responds to `format`, which formats the content nicely. The API mirrors that used by the `pretty_print` gem in that it accepts a formatter object and calls methods on it to generate its own internal representation of the text that will be outputted. Because of this, it's easier to not use this API directly and instead to call `SyntaxTree.format`. You _can_ however use this directly if you create the formatter yourself, as in: ### Parameters - **q** (Object) - A formatter object with methods like `visit_` and `flush`. ### Request Example ```ruby source = "1+1" program = SyntaxTree.parse(source) program => { statements: { body: [binary] } } formatter = SyntaxTree::Formatter.new(source, []) binary.format(formatter) formatter.flush formatter.output.join ``` ### Response Example ```ruby # Returns the formatted source code string. # "1 + 1" ``` ``` -------------------------------- ### Inherit from BasicVisitor for Strict Node Handling Source: https://github.com/ruby-syntax-tree/syntax_tree/blob/main/README.md Inherit from `BasicVisitor` to raise an error when visiting a node that has not been explicitly handled. This is useful for ensuring all nodes are processed or for work-in-progress visitors. ```ruby class MyVisitor < SyntaxTree::BasicVisitor def visit_int(node) # ... end end ``` -------------------------------- ### SyntaxTree.parse_file(filepath) Source: https://context7.com/ruby-syntax-tree/syntax_tree/llms.txt Reads and parses a Ruby file, respecting magic encoding comments, and returns the root AST node. ```APIDOC ## SyntaxTree.parse_file(filepath) ### Description Reads and parses a file, respecting Ruby magic encoding comments. ### Method `SyntaxTree.parse_file(filepath)` ### Parameters - **filepath** (String) - The path to the Ruby file to parse. ### Request Example ```ruby program = SyntaxTree.parse_file("lib/my_app.rb") program.statements.body.each do |node| puts "#{node.class}: line #{node.location.start_line}" end ``` ### Response #### Success Response - **program** (`SyntaxTree::Program` or `nil`) - The root AST node of the parsed file or nil if parsing failed. ### Response Example ```ruby # program would be a SyntaxTree::Program node ``` ``` -------------------------------- ### Mutate Syntax Tree with MutationVisitor Source: https://github.com/ruby-syntax-tree/syntax_tree/blob/main/README.md Use `MutationVisitor` to modify the syntax tree. Define mutations using patterns and a block that returns a modified node. The `#mutate` method is used to specify these transformations. ```ruby # Create a new visitor visitor = SyntaxTree::MutationVisitor.new # Specify that it should mutate If nodes with assignments in their predicates visitor.mutate("IfNode[predicate: Assign | OpAssign]") do |node| # Get the existing If's predicate node predicate = node.predicate # Create a new predicate node that wraps the existing predicate node # in parentheses predicate = SyntaxTree::Paren.new( lparen: SyntaxTree::LParen.default, contents: predicate, location: predicate.location ) # Return a copy of this node with the new predicate node.copy(predicate: predicate) end source = "if a = 1; end" program = SyntaxTree.parse(source) SyntaxTree::Formatter.format(source, program) # => "if a = 1\nend\n" SyntaxTree::Formatter.format(source, program.accept(visitor)) # => "if (a = 1)\nend\n" ``` -------------------------------- ### Pattern Matching on Syntax Tree Nodes (Minimal Constraints) Source: https://github.com/ruby-syntax-tree/syntax_tree/blob/main/README.md Uses Ruby's built-in pattern matching to extract information from the syntax tree with minimal type constraints. ```ruby program = SyntaxTree.parse("1 + 1") program => { statements: { body: [binary] } } binary # => (binary (int "1") :+ (int "1")) ``` -------------------------------- ### construct_keys Source: https://github.com/ruby-syntax-tree/syntax_tree/blob/main/README.md Returns a Ruby pattern-matching expression string that can be used to match the current node. Primarily intended for use in tooling and CLI applications. ```APIDOC ## construct_keys ### Description Every node responds to `construct_keys`, which will return a string that contains a Ruby pattern-matching expression that could be used to match against the current node. It's meant to be used in tooling and through the CLI mostly. ### Request Example ```ruby program = SyntaxTree.parse("1 + 1") puts program.construct_keys ``` ### Response Example ```ruby # Returns a string representing the pattern matching expression for the node. # SyntaxTree::Program[ # statements: SyntaxTree::Statements[ # body: [ # SyntaxTree::Binary[ # left: SyntaxTree::Int[value: "1"], # operator: :+, # right: SyntaxTree::Int[value: "1"] # ] # ] # ] # ] ``` ``` -------------------------------- ### SyntaxTree.read Source: https://github.com/ruby-syntax-tree/syntax_tree/blob/main/README.md Reads the content of a file, considering Ruby-level file encoding. ```APIDOC ## SyntaxTree.read(filepath) ### Description This function takes a filepath and returns a string associated with the content of that file. It is similar in functionality to `File.read`, except that it takes into account Ruby-level file encoding (through magic comments at the top of the file). ### Method `SyntaxTree.read` ### Parameters #### Path Parameters - **filepath** (string) - Required - The path to the file to read. ``` -------------------------------- ### Read file with correct encoding Source: https://context7.com/ruby-syntax-tree/syntax_tree/llms.txt Use `SyntaxTree.read` to read a file, ensuring correct handling of Ruby-level encoding magic comments. ```ruby source = SyntaxTree.read("lib/my_file.rb") # Correctly handles: # encoding: utf-8 or # -*- coding: utf-8 -*- ``` -------------------------------- ### Node#construct_keys Source: https://context7.com/ruby-syntax-tree/syntax_tree/llms.txt Generates a string representing a Ruby pattern-match expression that can be used to match the current node. ```APIDOC ## Node#construct_keys ### Description Generates a string containing a Ruby pattern-match expression that matches the current node. This is useful for creating search queries within the AST. ### Method `Node#construct_keys` ### Response #### Success Response (String) - Returns a string representing the pattern-match expression for the node. ### Request Example ```ruby program = SyntaxTree.parse("foo.bar(42)") puts program.construct_keys # SyntaxTree::Program[ # statements: SyntaxTree::Statements[ # body: [ # SyntaxTree::CallNode[ # receiver: SyntaxTree::VCall[value: SyntaxTree::Ident[value: "foo"]], # message: SyntaxTree::Ident[value: "bar"], # arguments: SyntaxTree::ArgParen[...] # ] # ] # ] # ] ``` ``` -------------------------------- ### Custom Rake Task for Formatting Source: https://context7.com/ruby-syntax-tree/syntax_tree/llms.txt Define a custom Rake task to specify source files, ignored files, print width, and plugins for formatting. ```ruby SyntaxTree::Rake::WriteTask.new(:format) do |t| t.source_files = FileList["{app,config,lib,test}/**/*.rb", "Gemfile", "Rakefile"] t.ignore_files = "db/**/*.rb" t.print_width = 100 t.plugins = ["plugin/trailing_comma", "plugin/single_quotes"] end ``` -------------------------------- ### Register Custom Language Handler Source: https://github.com/ruby-syntax-tree/syntax_tree/blob/main/README.md Register a handler for a new language by providing a file extension and a handler object. The handler object must implement `read`, `parse`, and `format` methods. ```ruby SyntaxTree.register_handler(".mylang", MyLanguage) ``` -------------------------------- ### Formatter.format(source, node, base_indentation) Source: https://context7.com/ruby-syntax-tree/syntax_tree/llms.txt Formats an already-parsed AST node directly, serving as a shortcut for `SyntaxTree.format`. ```APIDOC ## Formatter.format(source, node, base_indentation) ### Description Provides a class-level shortcut to format any already-parsed node directly, without needing to go through `SyntaxTree.format`. ### Method `SyntaxTree::Formatter.format(source, node, base_indentation = 0)` ### Parameters #### Path Parameters - **source** (String) - Required - The original source code string. - **node** (Node) - Required - The AST node to format. - **base_indentation** (Integer) - Optional - The base indentation level for formatting. Defaults to 0. ### Response #### Success Response (String) - Returns the formatted source code string. ### Request Example ```ruby source = "x=1;y=2" program = SyntaxTree.parse(source) node = program.statements.body.first # first Assign puts SyntaxTree::Formatter.format(source, node) # => x = 1 ``` ``` -------------------------------- ### SyntaxTree.format_node(source, node, maxwidth, base_indentation, options:) Source: https://context7.com/ruby-syntax-tree/syntax_tree/llms.txt Formats a single AST node from an already parsed tree, returning the formatted string representation of that node. ```APIDOC ## SyntaxTree.format_node(source, node, maxwidth, base_indentation, options:) ### Description Formats any individual node from an already-parsed tree. Useful for targeted formatting without re-parsing. ### Method `SyntaxTree.format_node(source, node, maxwidth = 80, base_indentation = 0, options: SyntaxTree::Formatter::Options.new)` ### Parameters - **source** (String) - The original source code string from which the node was parsed. - **node** (SyntaxTreeNode) - The specific AST node to format. - **maxwidth** (Integer, optional) - The maximum width for formatting. Defaults to 80. - **base_indentation** (Integer, optional) - The base indentation level. Defaults to 0. - **options** (SyntaxTree::Formatter::Options, optional) - An object with formatting options. ### Request Example ```ruby source = "1+2+3" program = SyntaxTree.parse(source) binary = program.statements.body.first puts SyntaxTree.format_node(source, binary) ``` ### Response #### Success Response - **formatted_node_string** (String) - The formatted string representation of the AST node. ### Response Example ```ruby # => 1 + 2 + 3 ``` ``` -------------------------------- ### Check Formatting with Custom Print Width Source: https://github.com/ruby-syntax-tree/syntax_tree/blob/main/README.md Specify a custom print width for the formatting check. ```sh stree check --print-width=100 path/to/file.rb ``` -------------------------------- ### CLI File Globbing with Exclusions Source: https://github.com/ruby-syntax-tree/syntax_tree/blob/main/README.md Employ Ruby-specific globbing syntax to include all Ruby files except 'schema.rb' when using the 'stree write' command. ```sh stree write "**/{[!schema]*,*}.rb" ``` -------------------------------- ### SyntaxTree.parse(source) Source: https://context7.com/ruby-syntax-tree/syntax_tree/llms.txt Parses an input string of Ruby source code and returns the root SyntaxTree::Program node. Returns nil if there is a parse error. ```APIDOC ## SyntaxTree.parse(source) ### Description Parses an input string and returns the root `SyntaxTree::Program` node, or `nil` if there is a parse error. ### Method `SyntaxTree.parse(source)` ### Parameters - **source** (String) - The Ruby source code to parse. ### Request Example ```ruby require "syntax_tree" program = SyntaxTree.parse(<<~RUBY) def greet(name) puts "Hello, #{name}!" end RUBY program.class ``` ### Response #### Success Response - **program** (`SyntaxTree::Program` or `nil`) - The root AST node or nil if parsing failed. ### Response Example ```ruby # program.class would return SyntaxTree::Program ``` ``` -------------------------------- ### SyntaxTree.search(source, query, &block) Source: https://context7.com/ruby-syntax-tree/syntax_tree/llms.txt Searches the parsed AST of a Ruby source string for nodes matching a given query pattern and yields each match. ```APIDOC ## SyntaxTree.search(source, query, &block) ### Description Searches the parsed tree of `source` for nodes matching the given `query` (a Ruby `in`-clause pattern string) and yields each match. ### Method `SyntaxTree.search(source, query)` ### Parameters - **source** (String) - The Ruby source code to parse and search. - **query** (String) - A pattern string (Ruby `in`-clause syntax) to match nodes. - **&block** (Block) - A block that will be executed for each matching node. ### Request Example ```ruby source = File.read("lib/my_app.rb") # Find all integer literals SyntaxTree.search(source, "Int") do |node| puts "Found integer #{node.value.inspect} at line #{node.location.start_line}" end # Find all method calls named 'puts' SyntaxTree.search(source, 'CallNode[message: Ident[value: "puts"]]') do |node| puts "puts call at line #{node.location.start_line}" end # Use the enumerator form matches = SyntaxTree.search(source, "StringLiteral").to_a puts "Found #{matches.length} string literals" ``` ### Response #### Success Response - **Yields** - Each matching AST node is yielded to the block. ### Response Example ```ruby # Output depends on the source code and query. ``` ```