syntax_tree 2.4.1 → 2.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +1 -1
- data/CHANGELOG.md +37 -1
- data/Gemfile +0 -2
- data/Gemfile.lock +5 -3
- data/README.md +63 -2
- data/Rakefile +5 -20
- data/lib/syntax_tree/basic_visitor.rb +74 -0
- data/lib/syntax_tree/formatter/trailing_comma.rb +13 -0
- data/lib/syntax_tree/formatter.rb +8 -2
- data/lib/syntax_tree/node.rb +174 -118
- data/lib/syntax_tree/parser.rb +112 -0
- data/lib/syntax_tree/plugin/trailing_comma.rb +4 -0
- data/lib/syntax_tree/rake/check_task.rb +66 -0
- data/lib/syntax_tree/rake/write_task.rb +66 -0
- data/lib/syntax_tree/rake_tasks.rb +4 -0
- data/lib/syntax_tree/version.rb +1 -1
- data/lib/syntax_tree/visitor/field_visitor.rb +9 -3
- data/lib/syntax_tree/visitor/match_visitor.rb +2 -2
- data/lib/syntax_tree/visitor.rb +4 -66
- data/lib/syntax_tree.rb +5 -27
- data/syntax_tree.gemspec +3 -0
- metadata +36 -3
- data/lib/syntax_tree/prettyprint.rb +0 -1159
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 126d8e2e86fc77aeab82d0130da3ed5d20b85ecbfb6cfd84ea4056f48c9c5cb9
|
4
|
+
data.tar.gz: c7abdbc2427c75561ae5e08b55345ecce65c4ff4cf6c5b6c02151734f9e54f5c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0b06e13f4f4ff47b250a5423e3e47de324c77ca4cd965539a040edc0b02b4aa9e78367cd5a8a5fad504f80dea82029798e8001d82eddf042e745b6080041a389
|
7
|
+
data.tar.gz: '0910deb51a5d6a458530923f5014b02030092b957f056e6339ef252ab6cb951014f738e2443d44d28e836dbb399567f934ac21b1b26e8ea75ddb8782475f4647'
|
data/.github/workflows/main.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -6,6 +6,39 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
|
|
6
6
|
|
7
7
|
## [Unreleased]
|
8
8
|
|
9
|
+
## [2.7.0] - 2022-05-19
|
10
|
+
|
11
|
+
### Added
|
12
|
+
|
13
|
+
- [#88](https://github.com/ruby-syntax-tree/syntax_tree/pull/88) - Provide a `SyntaxTree::BasicVisitor` that has no visit methods implemented.
|
14
|
+
|
15
|
+
### Changed
|
16
|
+
|
17
|
+
- [#90](https://github.com/ruby-syntax-tree/syntax_tree/pull/90) - Provide better formatting for `SyntaxTree::AryPtn` when its nested inside a `SyntaxTree::RAssign`.
|
18
|
+
|
19
|
+
## [2.6.0] - 2022-05-16
|
20
|
+
|
21
|
+
### Added
|
22
|
+
|
23
|
+
- [#74](https://github.com/ruby-syntax-tree/syntax_tree/pull/74) - Add Rake test to run check and format commands.
|
24
|
+
- [#83](https://github.com/ruby-syntax-tree/syntax_tree/pull/83) - Add a trailing commas plugin.
|
25
|
+
- [#84](https://github.com/ruby-syntax-tree/syntax_tree/pull/84) - Handle lambda block-local variables.
|
26
|
+
|
27
|
+
### Changed
|
28
|
+
|
29
|
+
- [#85](https://github.com/ruby-syntax-tree/syntax_tree/pull/85) - Better handle trailing operators on command calls.
|
30
|
+
|
31
|
+
## [2.5.0] - 2022-05-13
|
32
|
+
|
33
|
+
### Added
|
34
|
+
|
35
|
+
- [#79](https://github.com/ruby-syntax-tree/syntax_tree/pull/79) - Support an optional `maxwidth` second argument to `SyntaxTree.format`.
|
36
|
+
|
37
|
+
### Changed
|
38
|
+
|
39
|
+
- [#77](https://github.com/ruby-syntax-tree/syntax_tree/pull/77) - Correct the pattern for checking if a dynamic symbol can be converted into a label as a hash key.
|
40
|
+
- [#72](https://github.com/ruby-syntax-tree/syntax_tree/pull/72) - Disallow conditionals with `not` without parentheses in the predicate from turning into a ternary.
|
41
|
+
|
9
42
|
## [2.4.1] - 2022-05-10
|
10
43
|
|
11
44
|
- [#73](https://github.com/ruby-syntax-tree/syntax_tree/pull/73) - Fix nested hash patterns from accidentally adding a `then` to their output.
|
@@ -213,7 +246,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
|
|
213
246
|
|
214
247
|
- 🎉 Initial release! 🎉
|
215
248
|
|
216
|
-
[unreleased]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.
|
249
|
+
[unreleased]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.7.0...HEAD
|
250
|
+
[2.7.0]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.6.0...v2.7.0
|
251
|
+
[2.6.0]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.5.0...v2.6.0
|
252
|
+
[2.5.0]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.4.1...v2.5.0
|
217
253
|
[2.4.1]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.4.0...v2.4.1
|
218
254
|
[2.4.0]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.3.1...v2.4.0
|
219
255
|
[2.3.1]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.3.0...v2.3.1
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
syntax_tree (2.
|
4
|
+
syntax_tree (2.7.0)
|
5
|
+
prettier_print
|
5
6
|
|
6
7
|
GEM
|
7
8
|
remote: https://rubygems.org/
|
@@ -12,11 +13,12 @@ GEM
|
|
12
13
|
parallel (1.22.1)
|
13
14
|
parser (3.1.2.0)
|
14
15
|
ast (~> 2.4.1)
|
16
|
+
prettier_print (0.1.0)
|
15
17
|
rainbow (3.1.1)
|
16
18
|
rake (13.0.6)
|
17
|
-
regexp_parser (2.
|
19
|
+
regexp_parser (2.4.0)
|
18
20
|
rexml (3.2.5)
|
19
|
-
rubocop (1.29.
|
21
|
+
rubocop (1.29.1)
|
20
22
|
parallel (~> 1.10)
|
21
23
|
parser (>= 3.1.0.0)
|
22
24
|
rainbow (>= 2.2.2, < 4.0)
|
data/README.md
CHANGED
@@ -32,12 +32,16 @@ It is built with only standard library dependencies. It additionally ships with
|
|
32
32
|
- [construct_keys](#construct_keys)
|
33
33
|
- [Visitor](#visitor)
|
34
34
|
- [visit_method](#visit_method)
|
35
|
+
- [BasicVisitor](#basicvisitor)
|
35
36
|
- [Language server](#language-server)
|
36
37
|
- [textDocument/formatting](#textdocumentformatting)
|
37
38
|
- [textDocument/inlayHints](#textdocumentinlayhints)
|
38
39
|
- [syntaxTree/visualizing](#syntaxtreevisualizing)
|
39
40
|
- [Plugins](#plugins)
|
41
|
+
- [Configuration](#configuration)
|
42
|
+
- [Languages](#languages)
|
40
43
|
- [Integration](#integration)
|
44
|
+
- [Rake](#rake)
|
41
45
|
- [RuboCop](#rubocop)
|
42
46
|
- [VSCode](#vscode)
|
43
47
|
- [Contributing](#contributing)
|
@@ -223,7 +227,7 @@ This function takes an input string containing Ruby code and returns the syntax
|
|
223
227
|
|
224
228
|
### SyntaxTree.format(source)
|
225
229
|
|
226
|
-
This function takes an input string containing Ruby code, parses it into its underlying syntax tree, and formats it back out to a string.
|
230
|
+
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`.
|
227
231
|
|
228
232
|
## Nodes
|
229
233
|
|
@@ -370,6 +374,20 @@ Did you mean? visit_binary
|
|
370
374
|
from bin/console:8:in `<main>'
|
371
375
|
```
|
372
376
|
|
377
|
+
### BasicVisitor
|
378
|
+
|
379
|
+
When you're defining your own visitor, by default it will walk down the tree even if you don't define `visit_*` methods. This is to ensure you can define a subset of the necessary methods in order to only interact with the nodes you're interested in. If you'd like to change this default to instead raise an error if you visit a node you haven't explicitly handled, you can instead inherit from `BasicVisitor`.
|
380
|
+
|
381
|
+
```ruby
|
382
|
+
class MyVisitor < SyntaxTree::BasicVisitor
|
383
|
+
def visit_int(node)
|
384
|
+
# ...
|
385
|
+
end
|
386
|
+
end
|
387
|
+
```
|
388
|
+
|
389
|
+
The visitor defined above will error out unless it's only visiting a `SyntaxTree::Int` node. This is useful in a couple of ways, e.g., if you're trying to define a visitor to handle the whole tree but it's currently a work-in-progress.
|
390
|
+
|
373
391
|
## Language server
|
374
392
|
|
375
393
|
Syntax Tree additionally ships with a language server conforming to the [language server protocol](https://microsoft.github.io/language-server-protocol/). It can be invoked through the CLI by running:
|
@@ -408,9 +426,12 @@ You can register additional configuration and additional languages that can flow
|
|
408
426
|
|
409
427
|
### Configuration
|
410
428
|
|
411
|
-
To register additional configuration, define a file somewhere in your load path named `syntax_tree/my_plugin
|
429
|
+
To register additional configuration, define a file somewhere in your load path named `syntax_tree/my_plugin`. Then when invoking the CLI, you will pass `--plugins=my_plugin`. To require multiple, separate them by a comma. In this way, you can modify Syntax Tree however you would like. Some plugins ship with Syntax Tree itself. They are:
|
412
430
|
|
413
431
|
* `plugin/single_quotes` - This will change all of your string literals to use single quotes instead of the default double quotes.
|
432
|
+
* `plugin/trailing_comma` - This will put trailing commas into multiline array literals, hash literals, and method calls that can support trailing commas.
|
433
|
+
|
434
|
+
If you're using Syntax Tree as a library, you should require those files directly.
|
414
435
|
|
415
436
|
### Languages
|
416
437
|
|
@@ -436,6 +457,46 @@ Below are listed all of the "official" language plugins hosted under the same Gi
|
|
436
457
|
|
437
458
|
Syntax Tree's goal is to seemlessly integrate into your workflow. To this end, it provides a couple of additional tools beyond the CLI and the Ruby library.
|
438
459
|
|
460
|
+
### Rake
|
461
|
+
|
462
|
+
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`:
|
463
|
+
|
464
|
+
```ruby
|
465
|
+
require "syntax_tree/rake_tasks"
|
466
|
+
SyntaxTree::Rake::CheckTask.new
|
467
|
+
SyntaxTree::Rake::WriteTask.new
|
468
|
+
```
|
469
|
+
|
470
|
+
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.
|
471
|
+
|
472
|
+
#### `name`
|
473
|
+
|
474
|
+
If you'd like to change the default name of the rake task, you can pass that as the first argument, as in:
|
475
|
+
|
476
|
+
```ruby
|
477
|
+
SyntaxTree::Rake::WriteTask.new(:format)
|
478
|
+
```
|
479
|
+
|
480
|
+
#### `source_files`
|
481
|
+
|
482
|
+
If you wanted to configure Syntax Tree to check or write different files than the default (`lib/**/*.rb`), you can set the `source_files` field, as in:
|
483
|
+
|
484
|
+
```ruby
|
485
|
+
SyntaxTree::Rake::WriteTask.new do |t|
|
486
|
+
t.source_files = FileList[%w[Gemfile Rakefile lib/**/*.rb test/**/*.rb]]
|
487
|
+
end
|
488
|
+
```
|
489
|
+
|
490
|
+
#### `plugins`
|
491
|
+
|
492
|
+
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:
|
493
|
+
|
494
|
+
```ruby
|
495
|
+
SyntaxTree::Rake::WriteTask.new do |t|
|
496
|
+
t.plugins = ["plugin/single_quotes"]
|
497
|
+
end
|
498
|
+
```
|
499
|
+
|
439
500
|
### RuboCop
|
440
501
|
|
441
502
|
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`:
|
data/Rakefile
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require "bundler/gem_tasks"
|
4
4
|
require "rake/testtask"
|
5
|
+
require "syntax_tree/rake_tasks"
|
5
6
|
|
6
7
|
Rake::TestTask.new(:test) do |t|
|
7
8
|
t.libs << "test"
|
@@ -11,24 +12,8 @@ end
|
|
11
12
|
|
12
13
|
task default: :test
|
13
14
|
|
14
|
-
|
15
|
-
Gemfile
|
16
|
-
Rakefile
|
17
|
-
syntax_tree.gemspec
|
18
|
-
lib/**/*.rb
|
19
|
-
test/*.rb
|
20
|
-
].freeze
|
15
|
+
SOURCE_FILES =
|
16
|
+
FileList[%w[Gemfile Rakefile syntax_tree.gemspec lib/**/*.rb test/*.rb]]
|
21
17
|
|
22
|
-
|
23
|
-
|
24
|
-
require "syntax_tree"
|
25
|
-
require "syntax_tree/cli"
|
26
|
-
end
|
27
|
-
|
28
|
-
task check: :syntax_tree do
|
29
|
-
exit SyntaxTree::CLI.run(["check"] + FILEPATHS)
|
30
|
-
end
|
31
|
-
|
32
|
-
task format: :syntax_tree do
|
33
|
-
exit SyntaxTree::CLI.run(["write"] + FILEPATHS)
|
34
|
-
end
|
18
|
+
SyntaxTree::Rake::CheckTask.new { |t| t.source_files = SOURCE_FILES }
|
19
|
+
SyntaxTree::Rake::WriteTask.new { |t| t.source_files = SOURCE_FILES }
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SyntaxTree
|
4
|
+
# BasicVisitor is the parent class of the Visitor class that provides the
|
5
|
+
# ability to walk down the tree. It does not define any handlers, so you
|
6
|
+
# should extend this class if you want your visitor to raise an error if you
|
7
|
+
# attempt to visit a node that you don't handle.
|
8
|
+
class BasicVisitor
|
9
|
+
# This is raised when you use the Visitor.visit_method method and it fails.
|
10
|
+
# It is correctable to through DidYouMean.
|
11
|
+
class VisitMethodError < StandardError
|
12
|
+
attr_reader :visit_method
|
13
|
+
|
14
|
+
def initialize(visit_method)
|
15
|
+
@visit_method = visit_method
|
16
|
+
super("Invalid visit method: #{visit_method}")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# This class is used by DidYouMean to offer corrections to invalid visit
|
21
|
+
# method names.
|
22
|
+
class VisitMethodChecker
|
23
|
+
attr_reader :visit_method
|
24
|
+
|
25
|
+
def initialize(error)
|
26
|
+
@visit_method = error.visit_method
|
27
|
+
end
|
28
|
+
|
29
|
+
def corrections
|
30
|
+
@corrections ||=
|
31
|
+
DidYouMean::SpellChecker.new(
|
32
|
+
dictionary: Visitor.visit_methods
|
33
|
+
).correct(visit_method)
|
34
|
+
end
|
35
|
+
|
36
|
+
DidYouMean.correct_error(VisitMethodError, self)
|
37
|
+
end
|
38
|
+
|
39
|
+
class << self
|
40
|
+
# This method is here to help folks write visitors.
|
41
|
+
#
|
42
|
+
# It's not always easy to ensure you're writing the correct method name in
|
43
|
+
# the visitor since it's perfectly valid to define methods that don't
|
44
|
+
# override these parent methods.
|
45
|
+
#
|
46
|
+
# If you use this method, you can ensure you're writing the correct method
|
47
|
+
# name. It will raise an error if the visit method you're defining isn't
|
48
|
+
# actually a method on the parent visitor.
|
49
|
+
def visit_method(method_name)
|
50
|
+
return if visit_methods.include?(method_name)
|
51
|
+
|
52
|
+
raise VisitMethodError, method_name
|
53
|
+
end
|
54
|
+
|
55
|
+
# This is the list of all of the valid visit methods.
|
56
|
+
def visit_methods
|
57
|
+
@visit_methods ||=
|
58
|
+
Visitor.instance_methods.grep(/^visit_(?!child_nodes)/)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def visit(node)
|
63
|
+
node&.accept(self)
|
64
|
+
end
|
65
|
+
|
66
|
+
def visit_all(nodes)
|
67
|
+
nodes.map { |node| visit(node) }
|
68
|
+
end
|
69
|
+
|
70
|
+
def visit_child_nodes(node)
|
71
|
+
visit_all(node.child_nodes)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -3,11 +3,16 @@
|
|
3
3
|
module SyntaxTree
|
4
4
|
# A slightly enhanced PP that knows how to format recursively including
|
5
5
|
# comments.
|
6
|
-
class Formatter <
|
6
|
+
class Formatter < PrettierPrint
|
7
7
|
COMMENT_PRIORITY = 1
|
8
8
|
HEREDOC_PRIORITY = 2
|
9
9
|
|
10
|
-
attr_reader :source, :stack
|
10
|
+
attr_reader :source, :stack
|
11
|
+
|
12
|
+
# These options are overridden in plugins to we need to make sure they are
|
13
|
+
# available here.
|
14
|
+
attr_reader :quote, :trailing_comma
|
15
|
+
alias trailing_comma? trailing_comma
|
11
16
|
|
12
17
|
def initialize(source, ...)
|
13
18
|
super(...)
|
@@ -15,6 +20,7 @@ module SyntaxTree
|
|
15
20
|
@source = source
|
16
21
|
@stack = []
|
17
22
|
@quote = "\""
|
23
|
+
@trailing_comma = false
|
18
24
|
end
|
19
25
|
|
20
26
|
def self.format(source, node)
|