Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Switch parser over to prism
  • Loading branch information
kddnewton committed Oct 30, 2025
commit 2b8545c21b6b391c6c0f504e6e0392143d414cb8
1 change: 0 additions & 1 deletion .gitattributes

This file was deleted.

17 changes: 8 additions & 9 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,20 @@ jobs:
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- macos-latest
- windows-latest
ruby:
- '2.7.0'
- '3.0'
- '3.1'
- '3.2'
- '3.3'
- '3.4'
- truffleruby-head
exclude:
- os: windows-latest
ruby: truffleruby-head
name: CI
runs-on: ubuntu-latest
env:
CI: true
# TESTOPTS: --verbose
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@master
- uses: ruby/setup-ruby@v1
Expand All @@ -34,8 +35,6 @@ jobs:
check:
name: Check
runs-on: ubuntu-latest
env:
CI: true
steps:
- uses: actions/checkout@master
- uses: ruby/setup-ruby@v1
Expand Down
16 changes: 14 additions & 2 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ AllCops:
DisplayStyleGuide: true
NewCops: enable
SuggestExtensions: false
TargetRubyVersion: 2.7
TargetRubyVersion: 3.2
Exclude:
- '{.git,.github,.ruby-lsp,bin,coverage,doc,pkg,sorbet,spec,test/fixtures,vendor,tmp}/**/*'
- test.rb
Expand All @@ -14,7 +14,7 @@ Gemspec/DevelopmentDependencies:
Enabled: false

Layout/LineLength:
Max: 80
Max: 100

Lint/AmbiguousBlockAssociation:
Enabled: false
Expand Down Expand Up @@ -70,6 +70,9 @@ Naming/MethodName:
Naming/MethodParameterName:
Enabled: false

Naming/PredicateMethod:
Enabled: false

Naming/RescuedExceptionsVariableName:
PreferredName: error

Expand All @@ -79,12 +82,18 @@ Naming/VariableNumber:
Security/Eval:
Enabled: false

Style/AccessModifierDeclarations:
Enabled: false

Style/AccessorGrouping:
Enabled: false

Style/Alias:
Enabled: false

Style/BlockDelimiters:
Enabled: false

Style/CaseEquality:
Enabled: false

Expand Down Expand Up @@ -151,6 +160,9 @@ Style/Next:
Style/NumericPredicate:
Enabled: false

Style/OptionalBooleanParameter:
Enabled: false

Style/ParallelAssignment:
Enabled: false

Expand Down
6 changes: 5 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@ source "https://rubygems.org"

gemspec

gem "fiddle"
gem "bundler"
gem "minitest"
gem "rake"
gem "rubocop"
gem "simplecov"
19 changes: 7 additions & 12 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,21 @@ PATH
remote: .
specs:
syntax_tree (6.3.0)
prettier_print (>= 1.2.0)
prism

GEM
remote: https://rubygems.org/
specs:
ast (2.4.3)
docile (1.4.1)
fiddle (1.1.8)
json (2.15.1)
json (2.15.2)
language_server-protocol (3.17.0.5)
lint_roller (1.1.0)
minitest (5.26.0)
parallel (1.27.0)
parser (3.3.9.0)
parser (3.3.10.0)
ast (~> 2.4.1)
racc
prettier_print (1.2.1)
prism (1.6.0)
racc (1.8.1)
rainbow (3.1.1)
Expand All @@ -43,27 +41,24 @@ GEM
docile (~> 1.1)
simplecov-html (~> 0.11)
simplecov_json_formatter (~> 0.1)
simplecov-html (0.13.1)
simplecov-html (0.13.2)
simplecov_json_formatter (0.1.4)
unicode-display_width (3.2.0)
unicode-emoji (~> 4.1)
unicode-emoji (4.1.0)

PLATFORMS
arm64-darwin-21
ruby
x86_64-darwin-19
x86_64-darwin-21
arm64-darwin-23
x64-mingw-ucrt
x86_64-linux

DEPENDENCIES
bundler
fiddle
minitest
rake
rubocop
simplecov
syntax_tree!

BUNDLED WITH
2.3.6
2.4.19
78 changes: 21 additions & 57 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@
<img alt="Syntax Tree" height="400px" src="./doc/logo.svg">
</div>

# SyntaxTree
# Syntax Tree

[![Build Status](https://github.com/ruby-syntax-tree/syntax_tree/actions/workflows/main.yml/badge.svg)](https://github.com/ruby-syntax-tree/syntax_tree/actions/workflows/main.yml)
[![Gem Version](https://img.shields.io/gem/v/syntax_tree.svg)](https://rubygems.org/gems/syntax_tree)

Syntax Tree is a suite of tools built on top of the internal CRuby parser. It provides the ability to generate a syntax tree from source, as well as the tools necessary to inspect and manipulate that syntax tree. It can be used to build formatters, linters, language servers, and more.

It is built with only standard library dependencies. It additionally ships with a plugin system so that you can build your own syntax trees from other languages and incorporate these tools.
Syntax Tree is fast Ruby parser built on top of the [prism](https://github.com/ruby/prism) Ruby parser. It is built with only standard library dependencies.

- [Installation](#installation)
- [CLI](#cli)
Expand All @@ -19,11 +17,9 @@ It is built with only standard library dependencies. It additionally ships with
- [Configuration](#configuration)
- [Globbing](#globbing)
- [Language server](#language-server)
- [textDocument/formatting](#textdocumentformatting)
- [Customization](#customization)
- [Ignoring code](#ignoring-code)
- [Plugins](#plugins)
- [Languages](#languages)
- [Integration](#integration)
- [Rake](#rake)
- [RuboCop](#rubocop)
Expand Down Expand Up @@ -144,16 +140,28 @@ stree write --ignore-files='db/**/*.rb' '**/*.rb'

### Configuration

Any of the above CLI commands can also read configuration options from a `.streerc` file in the directory where the commands are executed.
All of the above commands accept additional configuration options. Those are:

- `--print-width=?` - The print width is the suggested line length that should be used when formatting the source. Note that this is not a hard limit like a linter. Instead, it is used as a guideline for how long lines _should_ be. For example, if you have the following code:

```ruby
foo do
bar
end
```

In this case, the formatter will see that the block fits into the print width and will rewrite it using the `{}` syntax. This will actually make the line longer than originally written. This is why it is helpful to think of it as a suggestion, rather than a limit.
- `--preferred-quote=?` - The quote to use for string and character literals. This can be either `"` or `'`. It is "preferred" because in the case that the formatter encounters a string that contains interpolation or certain escape sequences, it will not attempt to change the quote style to avoid accidentally changing the semantic meaning of the code.
- `--[no-]trailing-comma` - Whether or not to add trailing commas to multiline array literals, hash literals, and method calls that can support trailing commas.

This should be a text file with each argument on a separate line.
Any of the above CLI commands can also read configuration options from a `.streerc` file in the directory where the commands are executed. This should be a text file with each argument on a separate line.

```txt
--print-width=100
--plugins=plugin/trailing_comma
--trailing-comma
```

If this file is present, it will _always_ be used for CLI commands. You can also pass options from the command line as in the examples above. The options in the `.streerc` file are passed to the CLI first, then the arguments from the command line. In the case of exclusive options (e.g. `--print-width`), this means that the command line options override what's in the config file. In the case of options that can take multiple inputs (e.g. `--plugins`), the effect is additive. That is, the plugins passed from the command line will be loaded _in addition to_ the plugins in the config file.
If this file is present, it will _always_ be used for CLI commands. The options in the `.streerc` file are passed to the CLI first, then the arguments from the command line. In the case of exclusive options (e.g. `--print-width`), this means that the command line options override what's in the config file. In the case of options that can take multiple inputs (e.g. `--plugins`), the effect is additive. That is, the plugins passed from the command line will be loaded _in addition to_ the plugins in the config file.

### Globbing

Expand Down Expand Up @@ -220,32 +228,8 @@ To register plugins, define a file somewhere in your load path named `syntax_tre

* `plugin/single_quotes` - This will change all of your string literals to use single quotes instead of the default double quotes.
* `plugin/trailing_comma` - This will put trailing commas into multiline array literals, hash literals, and method calls that can support trailing commas.
* `plugin/disable_auto_ternary` - This will prevent the automatic conversion of `if ... else` to ternary expressions.

If you're using Syntax Tree as a library, you can require those files directly or manually pass those options to the formatter initializer through the `SyntaxTree::Formatter::Options` class.

### Languages

To register a new language, call:

```ruby
SyntaxTree.register_handler(".mylang", MyLanguage)
```

In this case, whenever the CLI encounters a filepath that ends with the given extension, it will invoke methods on `MyLanguage` instead of `SyntaxTree` itself. To make sure your object conforms to each of the necessary APIs, it should implement:

* `MyLanguage.read(filepath)` - usually this is just an alias to `File.read(filepath)`, but if you need anything else that hook is here.
* `MyLanguage.parse(source)` - this should return the syntax tree corresponding to the given source. Those objects should implement the `pretty_print` interface.
* `MyLanguage.format(source)` - this should return the formatted version of the given source.

Below are listed all of the "official" language plugins hosted under the same GitHub organization, which can be used as references for how to implement other plugins.

* [bf](https://github.com/ruby-syntax-tree/syntax_tree-bf) for the [brainf*** language](https://esolangs.org/wiki/Brainfuck).
* [css](https://github.com/ruby-syntax-tree/syntax_tree-css) for the [CSS stylesheet language](https://www.w3.org/Style/CSS/).
* [haml](https://github.com/ruby-syntax-tree/syntax_tree-haml) for the [Haml template language](https://haml.info/).
* [json](https://github.com/ruby-syntax-tree/syntax_tree-json) for the [JSON notation language](https://www.json.org/).
* [rbs](https://github.com/ruby-syntax-tree/syntax_tree-rbs) for the [RBS type language](https://github.com/ruby/rbs).
* [xml](https://github.com/ruby-syntax-tree/syntax_tree-xml) for the [XML markup language](https://www.w3.org/XML/).
If you're using Syntax Tree as a library, you can require those files directly or manually pass those options to the formatter initializer through the `SyntaxTree::Options` class.

## Integration

Expand All @@ -256,12 +240,12 @@ Syntax Tree's goal is to seamlessly integrate into your workflow. To this end, i
Syntax Tree ships with the ability to define [rake](https://github.com/ruby/rake) tasks that will trigger runs of the CLI. To define them in your application, add the following configuration to your `Rakefile`:

```ruby
require "syntax_tree/rake_tasks"
require "syntax_tree/rake"
SyntaxTree::Rake::CheckTask.new
SyntaxTree::Rake::WriteTask.new
```

These calls will define `rake stree:check` and `rake stree:write` (equivalent to calling `stree check` and `stree write` with the CLI respectively). You can configure them by either passing arguments to the `new` method or by using a block.
These calls will define `rake stree:check` and `rake stree:write` (equivalent to calling `stree check` and `stree write` with the CLI respectively). You can configure them by either passing arguments to the `new` method or by using a block. In addition to the regular configuration options used for the formatter, there are a few additional options specific to the rake tasks.

#### `name`

Expand Down Expand Up @@ -292,26 +276,6 @@ SyntaxTree::Rake::WriteTask.new do |t|
end
```

#### `print_width`

If you want to use a different print width from the default (80), you can pass that to the `print_width` field, as in:

```ruby
SyntaxTree::Rake::WriteTask.new do |t|
t.print_width = 100
end
```

#### `plugins`

If you're running Syntax Tree with plugins (either your own or the pre-built ones), you can pass that to the `plugins` field, as in:

```ruby
SyntaxTree::Rake::WriteTask.new do |t|
t.plugins = ["plugin/single_quotes"]
end
```

### RuboCop

RuboCop and Syntax Tree serve different purposes, but there is overlap with some of RuboCop's functionality. Syntax Tree provides a RuboCop configuration file to disable rules that are redundant with Syntax Tree. To use this configuration file, add the following snippet to the top of your project's `.rubocop.yml`:
Expand Down
20 changes: 2 additions & 18 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

require "bundler/gem_tasks"
require "rake/testtask"
require "syntax_tree/rake_tasks"
require "syntax_tree/rake"

Rake::TestTask.new(:test) do |t|
t.libs << "test"
Expand All @@ -14,23 +14,7 @@ task default: :test

configure = ->(task) do
task.source_files =
FileList[
%w[
Gemfile
Rakefile
syntax_tree.gemspec
lib/**/*.rb
tasks/*.rake
test/*.rb
]
]

# Since Syntax Tree supports back to Ruby 2.7.0, we need to make sure that we
# format our code such that it's compatible with that version. This actually
# has very little effect on the output, the only change at the moment is that
# Ruby < 2.7.3 didn't allow a newline before the closing brace of a hash
# pattern.
task.target_ruby_version = Gem::Version.new("2.7.0")
FileList[%w[Gemfile Rakefile syntax_tree.gemspec lib/**/*.rb tasks/*.rake test/*.rb]]
end

SyntaxTree::Rake::CheckTask.new(&configure)
Expand Down
42 changes: 0 additions & 42 deletions bin/bench

This file was deleted.

4 changes: 2 additions & 2 deletions bin/profile
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ require "bundler/inline"
gemfile do
source "https://rubygems.org"
gem "stackprof"
gem "prettier_print"
gem "prism"
end

$:.unshift(File.expand_path("../lib", __dir__))
require "syntax_tree"

StackProf.run(mode: :cpu, out: "tmp/profile.dump", raw: true) do
Dir[File.join(RbConfig::CONFIG["libdir"], "**/*.rb")].each do |filepath|
SyntaxTree.format(SyntaxTree.read(filepath))
SyntaxTree.format_file(filepath)
end
end

Expand Down
Loading