syntax_tree 2.5.0 → 2.6.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 +14 -1
- data/Gemfile.lock +1 -1
- data/README.md +48 -2
- data/Rakefile +5 -20
- data/lib/syntax_tree/formatter/trailing_comma.rb +13 -0
- data/lib/syntax_tree/formatter.rb +7 -1
- data/lib/syntax_tree/node.rb +123 -12
- 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 +8 -0
- data/lib/syntax_tree/visitor.rb +3 -0
- metadata +8 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f3d700916c1fab01ddc92117fd2b99c26b699df9e03f06b83eafa1415167ef7d
|
4
|
+
data.tar.gz: f5499912fe7bf422b44360bf66ce3f7e74145f3a2cc3ef5668e20fc97bd61948
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e287bcace78e800140ce6b30044a684587e8514f7f0b4c8a57f7b4f3926717a96eb966828e42325a44c1af23715cc602c3cb327dcab27d5390b0353b6a595744
|
7
|
+
data.tar.gz: 7cb34f0d9d423b3129033f04dc543d1bb9b19e62dcc7a9a140eb5c3a3159caaf389746930d15e6556df753e10f0651e38ab5e4db95bad63737836e14f14a86c1
|
data/.github/workflows/main.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -6,6 +6,18 @@ 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.6.0] - 2022-05-16
|
10
|
+
|
11
|
+
### Added
|
12
|
+
|
13
|
+
- [#74](https://github.com/ruby-syntax-tree/syntax_tree/pull/74) - Add Rake test to run check and format commands.
|
14
|
+
- [#83](https://github.com/ruby-syntax-tree/syntax_tree/pull/83) - Add a trailing commas plugin.
|
15
|
+
- [#84](https://github.com/ruby-syntax-tree/syntax_tree/pull/84) - Handle lambda block-local variables.
|
16
|
+
|
17
|
+
### Changed
|
18
|
+
|
19
|
+
- [#85](https://github.com/ruby-syntax-tree/syntax_tree/pull/85) - Better handle trailing operators on command calls.
|
20
|
+
|
9
21
|
## [2.5.0] - 2022-05-13
|
10
22
|
|
11
23
|
### Added
|
@@ -224,7 +236,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
|
|
224
236
|
|
225
237
|
- 🎉 Initial release! 🎉
|
226
238
|
|
227
|
-
[unreleased]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.
|
239
|
+
[unreleased]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.6.0...HEAD
|
240
|
+
[2.6.0]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.5.0...v2.6.0
|
228
241
|
[2.5.0]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.4.1...v2.5.0
|
229
242
|
[2.4.1]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.4.0...v2.4.1
|
230
243
|
[2.4.0]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.3.1...v2.4.0
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -37,7 +37,10 @@ It is built with only standard library dependencies. It additionally ships with
|
|
37
37
|
- [textDocument/inlayHints](#textdocumentinlayhints)
|
38
38
|
- [syntaxTree/visualizing](#syntaxtreevisualizing)
|
39
39
|
- [Plugins](#plugins)
|
40
|
+
- [Configuration](#configuration)
|
41
|
+
- [Languages](#languages)
|
40
42
|
- [Integration](#integration)
|
43
|
+
- [Rake](#rake)
|
41
44
|
- [RuboCop](#rubocop)
|
42
45
|
- [VSCode](#vscode)
|
43
46
|
- [Contributing](#contributing)
|
@@ -223,7 +226,7 @@ This function takes an input string containing Ruby code and returns the syntax
|
|
223
226
|
|
224
227
|
### SyntaxTree.format(source)
|
225
228
|
|
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.
|
229
|
+
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
230
|
|
228
231
|
## Nodes
|
229
232
|
|
@@ -408,9 +411,12 @@ You can register additional configuration and additional languages that can flow
|
|
408
411
|
|
409
412
|
### Configuration
|
410
413
|
|
411
|
-
To register additional configuration, define a file somewhere in your load path named `syntax_tree/my_plugin
|
414
|
+
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
415
|
|
413
416
|
* `plugin/single_quotes` - This will change all of your string literals to use single quotes instead of the default double quotes.
|
417
|
+
* `plugin/trailing_comma` - This will put trailing commas into multiline array literals, hash literals, and method calls that can support trailing commas.
|
418
|
+
|
419
|
+
If you're using Syntax Tree as a library, you should require those files directly.
|
414
420
|
|
415
421
|
### Languages
|
416
422
|
|
@@ -436,6 +442,46 @@ Below are listed all of the "official" language plugins hosted under the same Gi
|
|
436
442
|
|
437
443
|
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
444
|
|
445
|
+
### Rake
|
446
|
+
|
447
|
+
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`:
|
448
|
+
|
449
|
+
```ruby
|
450
|
+
require "syntax_tree/rake_tasks"
|
451
|
+
SyntaxTree::Rake::CheckTask.new
|
452
|
+
SyntaxTree::Rake::WriteTask.new
|
453
|
+
```
|
454
|
+
|
455
|
+
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.
|
456
|
+
|
457
|
+
#### `name`
|
458
|
+
|
459
|
+
If you'd like to change the default name of the rake task, you can pass that as the first argument, as in:
|
460
|
+
|
461
|
+
```ruby
|
462
|
+
SyntaxTree::Rake::WriteTask.new(:format)
|
463
|
+
```
|
464
|
+
|
465
|
+
#### `source_files`
|
466
|
+
|
467
|
+
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:
|
468
|
+
|
469
|
+
```ruby
|
470
|
+
SyntaxTree::Rake::WriteTask.new do |t|
|
471
|
+
t.source_files = FileList[%w[Gemfile Rakefile lib/**/*.rb test/**/*.rb]]
|
472
|
+
end
|
473
|
+
```
|
474
|
+
|
475
|
+
#### `plugins`
|
476
|
+
|
477
|
+
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:
|
478
|
+
|
479
|
+
```ruby
|
480
|
+
SyntaxTree::Rake::WriteTask.new do |t|
|
481
|
+
t.plugins = ["plugin/single_quotes"]
|
482
|
+
end
|
483
|
+
```
|
484
|
+
|
439
485
|
### RuboCop
|
440
486
|
|
441
487
|
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 }
|
@@ -7,7 +7,12 @@ module SyntaxTree
|
|
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)
|
data/lib/syntax_tree/node.rb
CHANGED
@@ -597,10 +597,30 @@ module SyntaxTree
|
|
597
597
|
q.indent do
|
598
598
|
q.breakable("")
|
599
599
|
q.format(arguments)
|
600
|
+
q.if_break { q.text(",") } if q.trailing_comma? && trailing_comma?
|
600
601
|
end
|
601
602
|
q.breakable("")
|
602
603
|
end
|
603
604
|
end
|
605
|
+
|
606
|
+
private
|
607
|
+
|
608
|
+
def trailing_comma?
|
609
|
+
case arguments
|
610
|
+
in Args[parts: [*, ArgBlock]]
|
611
|
+
# If the last argument is a block, then we can't put a trailing comma
|
612
|
+
# after it without resulting in a syntax error.
|
613
|
+
false
|
614
|
+
in Args[parts: [Command | CommandCall]]
|
615
|
+
# If the only argument is a command or command call, then a trailing
|
616
|
+
# comma would be parsed as part of that expression instead of on this
|
617
|
+
# one, so we don't want to add a trailing comma.
|
618
|
+
false
|
619
|
+
else
|
620
|
+
# Otherwise, we should be okay to add a trailing comma.
|
621
|
+
true
|
622
|
+
end
|
623
|
+
end
|
604
624
|
end
|
605
625
|
|
606
626
|
# Args represents a list of arguments being passed to a method call or array
|
@@ -859,6 +879,7 @@ module SyntaxTree
|
|
859
879
|
end
|
860
880
|
|
861
881
|
q.seplist(contents.parts, separator) { |part| q.format(part) }
|
882
|
+
q.if_break { q.text(",") } if q.trailing_comma?
|
862
883
|
end
|
863
884
|
q.breakable("")
|
864
885
|
end
|
@@ -954,6 +975,7 @@ module SyntaxTree
|
|
954
975
|
q.indent do
|
955
976
|
q.breakable("")
|
956
977
|
q.format(contents)
|
978
|
+
q.if_break { q.text(",") } if q.trailing_comma?
|
957
979
|
end
|
958
980
|
end
|
959
981
|
|
@@ -3030,8 +3052,20 @@ module SyntaxTree
|
|
3030
3052
|
doc =
|
3031
3053
|
q.nest(0) do
|
3032
3054
|
q.format(receiver)
|
3033
|
-
|
3034
|
-
|
3055
|
+
|
3056
|
+
# If there are leading comments on the message then we know we have
|
3057
|
+
# a newline in the source that is forcing these things apart. In
|
3058
|
+
# this case we will have to use a trailing operator.
|
3059
|
+
if message.comments.any?(&:leading?)
|
3060
|
+
q.format(CallOperatorFormatter.new(operator), stackable: false)
|
3061
|
+
q.indent do
|
3062
|
+
q.breakable("")
|
3063
|
+
q.format(message)
|
3064
|
+
end
|
3065
|
+
else
|
3066
|
+
q.format(CallOperatorFormatter.new(operator), stackable: false)
|
3067
|
+
q.format(message)
|
3068
|
+
end
|
3035
3069
|
end
|
3036
3070
|
|
3037
3071
|
case arguments
|
@@ -4751,6 +4785,7 @@ module SyntaxTree
|
|
4751
4785
|
q.indent do
|
4752
4786
|
q.breakable
|
4753
4787
|
q.seplist(assocs) { |assoc| q.format(assoc) }
|
4788
|
+
q.if_break { q.text(",") } if q.trailing_comma?
|
4754
4789
|
end
|
4755
4790
|
q.breakable
|
4756
4791
|
end
|
@@ -5877,7 +5912,7 @@ module SyntaxTree
|
|
5877
5912
|
# ->(value) { value * 2 }
|
5878
5913
|
#
|
5879
5914
|
class Lambda < Node
|
5880
|
-
# [
|
5915
|
+
# [LambdaVar | Paren] the parameter declaration for this lambda
|
5881
5916
|
attr_reader :params
|
5882
5917
|
|
5883
5918
|
# [BodyStmt | Statements] the expressions to be executed in this lambda
|
@@ -5932,24 +5967,100 @@ module SyntaxTree
|
|
5932
5967
|
node.is_a?(Command) || node.is_a?(CommandCall)
|
5933
5968
|
end
|
5934
5969
|
|
5935
|
-
|
5936
|
-
|
5970
|
+
if force_parens
|
5971
|
+
q.text("{")
|
5972
|
+
|
5973
|
+
unless statements.empty?
|
5974
|
+
q.indent do
|
5975
|
+
q.breakable
|
5976
|
+
q.format(statements)
|
5977
|
+
end
|
5978
|
+
q.breakable
|
5979
|
+
end
|
5980
|
+
|
5981
|
+
q.text("}")
|
5982
|
+
else
|
5983
|
+
q.text("do")
|
5984
|
+
|
5985
|
+
unless statements.empty?
|
5986
|
+
q.indent do
|
5987
|
+
q.breakable
|
5988
|
+
q.format(statements)
|
5989
|
+
end
|
5990
|
+
end
|
5991
|
+
|
5937
5992
|
q.breakable
|
5938
|
-
q.
|
5993
|
+
q.text("end")
|
5939
5994
|
end
|
5940
|
-
|
5941
|
-
q.breakable
|
5942
|
-
q.text(force_parens ? "}" : "end")
|
5943
5995
|
end
|
5944
5996
|
.if_flat do
|
5945
|
-
q.text("{
|
5946
|
-
|
5947
|
-
|
5997
|
+
q.text("{")
|
5998
|
+
|
5999
|
+
unless statements.empty?
|
6000
|
+
q.text(" ")
|
6001
|
+
q.format(statements)
|
6002
|
+
q.text(" ")
|
6003
|
+
end
|
6004
|
+
|
6005
|
+
q.text("}")
|
5948
6006
|
end
|
5949
6007
|
end
|
5950
6008
|
end
|
5951
6009
|
end
|
5952
6010
|
|
6011
|
+
# LambdaVar represents the parameters being declared for a lambda. Effectively
|
6012
|
+
# this node is everything contained within the parentheses. This includes all
|
6013
|
+
# of the various parameter types, as well as block-local variable
|
6014
|
+
# declarations.
|
6015
|
+
#
|
6016
|
+
# -> (positional, optional = value, keyword:, █ local) do
|
6017
|
+
# end
|
6018
|
+
#
|
6019
|
+
class LambdaVar < Node
|
6020
|
+
# [Params] the parameters being declared with the block
|
6021
|
+
attr_reader :params
|
6022
|
+
|
6023
|
+
# [Array[ Ident ]] the list of block-local variable declarations
|
6024
|
+
attr_reader :locals
|
6025
|
+
|
6026
|
+
# [Array[ Comment | EmbDoc ]] the comments attached to this node
|
6027
|
+
attr_reader :comments
|
6028
|
+
|
6029
|
+
def initialize(params:, locals:, location:, comments: [])
|
6030
|
+
@params = params
|
6031
|
+
@locals = locals
|
6032
|
+
@location = location
|
6033
|
+
@comments = comments
|
6034
|
+
end
|
6035
|
+
|
6036
|
+
def accept(visitor)
|
6037
|
+
visitor.visit_lambda_var(self)
|
6038
|
+
end
|
6039
|
+
|
6040
|
+
def child_nodes
|
6041
|
+
[params, *locals]
|
6042
|
+
end
|
6043
|
+
|
6044
|
+
alias deconstruct child_nodes
|
6045
|
+
|
6046
|
+
def deconstruct_keys(_keys)
|
6047
|
+
{ params: params, locals: locals, location: location, comments: comments }
|
6048
|
+
end
|
6049
|
+
|
6050
|
+
def empty?
|
6051
|
+
params.empty? && locals.empty?
|
6052
|
+
end
|
6053
|
+
|
6054
|
+
def format(q)
|
6055
|
+
q.format(params)
|
6056
|
+
|
6057
|
+
if locals.any?
|
6058
|
+
q.text("; ")
|
6059
|
+
q.seplist(locals, -> { q.text(", ") }) { |local| q.format(local) }
|
6060
|
+
end
|
6061
|
+
end
|
6062
|
+
end
|
6063
|
+
|
5953
6064
|
# LBrace represents the use of a left brace, i.e., {.
|
5954
6065
|
class LBrace < Node
|
5955
6066
|
# [String] the left brace
|
data/lib/syntax_tree/parser.rb
CHANGED
@@ -1940,6 +1940,41 @@ module SyntaxTree
|
|
1940
1940
|
token.location.start_char > beginning.location.start_char
|
1941
1941
|
end
|
1942
1942
|
|
1943
|
+
# We need to do some special mapping here. Since ripper doesn't support
|
1944
|
+
# capturing lambda var until 3.2, we need to normalize all of that here.
|
1945
|
+
params =
|
1946
|
+
case params
|
1947
|
+
in Paren[contents: Params]
|
1948
|
+
# In this case we've gotten to the <3.2 parentheses wrapping a set of
|
1949
|
+
# parameters case. Here we need to manually scan for lambda locals.
|
1950
|
+
range = (params.location.start_char + 1)...params.location.end_char
|
1951
|
+
locals = lambda_locals(source[range])
|
1952
|
+
|
1953
|
+
location = params.contents.location
|
1954
|
+
location = location.to(locals.last.location) if locals.any?
|
1955
|
+
|
1956
|
+
Paren.new(
|
1957
|
+
lparen: params.lparen,
|
1958
|
+
contents:
|
1959
|
+
LambdaVar.new(
|
1960
|
+
params: params.contents,
|
1961
|
+
locals: locals,
|
1962
|
+
location: location
|
1963
|
+
),
|
1964
|
+
location: params.location,
|
1965
|
+
comments: params.comments
|
1966
|
+
)
|
1967
|
+
in Params
|
1968
|
+
# In this case we've gotten to the <3.2 plain set of parameters. In
|
1969
|
+
# this case there cannot be lambda locals, so we will wrap the
|
1970
|
+
# parameters into a lambda var that has no locals.
|
1971
|
+
LambdaVar.new(params: params, locals: [], location: params.location)
|
1972
|
+
in LambdaVar
|
1973
|
+
# In this case we've gotten to 3.2+ lambda var. In this case we don't
|
1974
|
+
# need to do anything and can just the value as given.
|
1975
|
+
params
|
1976
|
+
end
|
1977
|
+
|
1943
1978
|
if braces
|
1944
1979
|
opening = find_token(TLamBeg)
|
1945
1980
|
closing = find_token(RBrace)
|
@@ -1962,6 +1997,83 @@ module SyntaxTree
|
|
1962
1997
|
)
|
1963
1998
|
end
|
1964
1999
|
|
2000
|
+
# :call-seq:
|
2001
|
+
# on_lambda_var: (Params params, Array[ Ident ] locals) -> LambdaVar
|
2002
|
+
def on_lambda_var(params, locals)
|
2003
|
+
location = params.location
|
2004
|
+
location = location.to(locals.last.location) if locals.any?
|
2005
|
+
|
2006
|
+
LambdaVar.new(params: params, locals: locals || [], location: location)
|
2007
|
+
end
|
2008
|
+
|
2009
|
+
# Ripper doesn't support capturing lambda local variables until 3.2. To
|
2010
|
+
# mitigate this, we have to parse that code for ourselves. We use the range
|
2011
|
+
# from the parentheses to find where we _should_ be looking. Then we check
|
2012
|
+
# if the resulting tokens match a pattern that we determine means that the
|
2013
|
+
# declaration has block-local variables. Once it does, we parse those out
|
2014
|
+
# and convert them into Ident nodes.
|
2015
|
+
def lambda_locals(source)
|
2016
|
+
tokens = Ripper.lex(source)
|
2017
|
+
|
2018
|
+
# First, check that we have a semi-colon. If we do, then we can start to
|
2019
|
+
# parse the tokens _after_ the semicolon.
|
2020
|
+
index = tokens.rindex { |token| token[1] == :on_semicolon }
|
2021
|
+
return [] unless index
|
2022
|
+
|
2023
|
+
# Next, map over the tokens and convert them into Ident nodes. Bail out
|
2024
|
+
# midway through if we encounter a token we didn't expect. Basically we're
|
2025
|
+
# making our own mini-parser here. To do that we'll walk through a small
|
2026
|
+
# state machine:
|
2027
|
+
#
|
2028
|
+
# ┌────────┐ ┌────────┐ ┌─────────┐
|
2029
|
+
# │ │ │ │ │┌───────┐│
|
2030
|
+
# ──> │ item │ ─── ident ──> │ next │ ─── rparen ──> ││ final ││
|
2031
|
+
# │ │ <── comma ─── │ │ │└───────┘│
|
2032
|
+
# └────────┘ └────────┘ └─────────┘
|
2033
|
+
# │ ^ │ ^
|
2034
|
+
# └──┘ └──┘
|
2035
|
+
# ignored_nl, sp nl, sp
|
2036
|
+
#
|
2037
|
+
state = :item
|
2038
|
+
transitions = {
|
2039
|
+
item: {
|
2040
|
+
on_ignored_nl: :item,
|
2041
|
+
on_sp: :item,
|
2042
|
+
on_ident: :next
|
2043
|
+
},
|
2044
|
+
next: {
|
2045
|
+
on_nl: :next,
|
2046
|
+
on_sp: :next,
|
2047
|
+
on_comma: :item,
|
2048
|
+
on_rparen: :final
|
2049
|
+
},
|
2050
|
+
final: {
|
2051
|
+
}
|
2052
|
+
}
|
2053
|
+
|
2054
|
+
tokens[(index + 1)..].each_with_object([]) do |token, locals|
|
2055
|
+
(lineno, column), type, value, = token
|
2056
|
+
|
2057
|
+
# Make the state transition for the parser. If there isn't a transition
|
2058
|
+
# from the current state to a new state for this type, then we're in a
|
2059
|
+
# pattern that isn't actually locals. In that case we can return [].
|
2060
|
+
state = transitions[state].fetch(type) { return [] }
|
2061
|
+
|
2062
|
+
# If we hit an identifier, then add it to our list.
|
2063
|
+
next if type != :on_ident
|
2064
|
+
|
2065
|
+
location =
|
2066
|
+
Location.token(
|
2067
|
+
line: lineno,
|
2068
|
+
char: line_counts[lineno - 1][column],
|
2069
|
+
column: column,
|
2070
|
+
size: value.size
|
2071
|
+
)
|
2072
|
+
|
2073
|
+
locals << Ident.new(value: value, location: location)
|
2074
|
+
end
|
2075
|
+
end
|
2076
|
+
|
1965
2077
|
# :call-seq:
|
1966
2078
|
# on_lbrace: (String value) -> LBrace
|
1967
2079
|
def on_lbrace(value)
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rake"
|
4
|
+
require "rake/tasklib"
|
5
|
+
|
6
|
+
require "syntax_tree"
|
7
|
+
require "syntax_tree/cli"
|
8
|
+
|
9
|
+
module SyntaxTree
|
10
|
+
module Rake
|
11
|
+
# A Rake task that runs check on a set of source files.
|
12
|
+
#
|
13
|
+
# Example:
|
14
|
+
#
|
15
|
+
# require 'syntax_tree/rake/check_task'
|
16
|
+
#
|
17
|
+
# SyntaxTree::Rake::CheckTask.new do |t|
|
18
|
+
# t.source_files = '{app,config,lib}/**/*.rb'
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# This will create task that can be run with:
|
22
|
+
#
|
23
|
+
# rake stree_check
|
24
|
+
#
|
25
|
+
class CheckTask < ::Rake::TaskLib
|
26
|
+
# Name of the task.
|
27
|
+
# Defaults to :"stree:check".
|
28
|
+
attr_accessor :name
|
29
|
+
|
30
|
+
# Glob pattern to match source files.
|
31
|
+
# Defaults to 'lib/**/*.rb'.
|
32
|
+
attr_accessor :source_files
|
33
|
+
|
34
|
+
# The set of plugins to require.
|
35
|
+
# Defaults to [].
|
36
|
+
attr_accessor :plugins
|
37
|
+
|
38
|
+
def initialize(
|
39
|
+
name = :"stree:check",
|
40
|
+
source_files = ::Rake::FileList["lib/**/*.rb"],
|
41
|
+
plugins = []
|
42
|
+
)
|
43
|
+
@name = name
|
44
|
+
@source_files = source_files
|
45
|
+
@plugins = plugins
|
46
|
+
|
47
|
+
yield self if block_given?
|
48
|
+
define_task
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def define_task
|
54
|
+
desc "Runs `stree check` over source files"
|
55
|
+
task(name) { run_task }
|
56
|
+
end
|
57
|
+
|
58
|
+
def run_task
|
59
|
+
arguments = ["check"]
|
60
|
+
arguments << "--plugins=#{plugins.join(",")}" if plugins.any?
|
61
|
+
|
62
|
+
SyntaxTree::CLI.run(arguments + Array(source_files))
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rake"
|
4
|
+
require "rake/tasklib"
|
5
|
+
|
6
|
+
require "syntax_tree"
|
7
|
+
require "syntax_tree/cli"
|
8
|
+
|
9
|
+
module SyntaxTree
|
10
|
+
module Rake
|
11
|
+
# A Rake task that runs format on a set of source files.
|
12
|
+
#
|
13
|
+
# Example:
|
14
|
+
#
|
15
|
+
# require 'syntax_tree/rake/write_task'
|
16
|
+
#
|
17
|
+
# SyntaxTree::Rake::WriteTask.new do |t|
|
18
|
+
# t.source_files = '{app,config,lib}/**/*.rb'
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# This will create task that can be run with:
|
22
|
+
#
|
23
|
+
# rake stree_write
|
24
|
+
#
|
25
|
+
class WriteTask < ::Rake::TaskLib
|
26
|
+
# Name of the task.
|
27
|
+
# Defaults to :"stree:write".
|
28
|
+
attr_accessor :name
|
29
|
+
|
30
|
+
# Glob pattern to match source files.
|
31
|
+
# Defaults to 'lib/**/*.rb'.
|
32
|
+
attr_accessor :source_files
|
33
|
+
|
34
|
+
# The set of plugins to require.
|
35
|
+
# Defaults to [].
|
36
|
+
attr_accessor :plugins
|
37
|
+
|
38
|
+
def initialize(
|
39
|
+
name = :"stree:write",
|
40
|
+
source_files = ::Rake::FileList["lib/**/*.rb"],
|
41
|
+
plugins = []
|
42
|
+
)
|
43
|
+
@name = name
|
44
|
+
@source_files = source_files
|
45
|
+
@plugins = plugins
|
46
|
+
|
47
|
+
yield self if block_given?
|
48
|
+
define_task
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def define_task
|
54
|
+
desc "Runs `stree write` over source files"
|
55
|
+
task(name) { run_task }
|
56
|
+
end
|
57
|
+
|
58
|
+
def run_task
|
59
|
+
arguments = ["write"]
|
60
|
+
arguments << "--plugins=#{plugins.join(",")}" if plugins.any?
|
61
|
+
|
62
|
+
SyntaxTree::CLI.run(arguments + Array(source_files))
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
data/lib/syntax_tree/version.rb
CHANGED
@@ -586,6 +586,14 @@ module SyntaxTree
|
|
586
586
|
end
|
587
587
|
end
|
588
588
|
|
589
|
+
def visit_lambda_var(node)
|
590
|
+
node(node, "lambda_var") do
|
591
|
+
field("params", node.params)
|
592
|
+
list("locals", node.locals) if node.locals.any?
|
593
|
+
comments(node)
|
594
|
+
end
|
595
|
+
end
|
596
|
+
|
589
597
|
def visit_lbrace(node)
|
590
598
|
visit_token(node, "lbrace")
|
591
599
|
end
|
data/lib/syntax_tree/visitor.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: syntax_tree
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kevin Newton
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-05-
|
11
|
+
date: 2022-05-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: prettier_print
|
@@ -124,11 +124,16 @@ files:
|
|
124
124
|
- lib/syntax_tree/cli.rb
|
125
125
|
- lib/syntax_tree/formatter.rb
|
126
126
|
- lib/syntax_tree/formatter/single_quotes.rb
|
127
|
+
- lib/syntax_tree/formatter/trailing_comma.rb
|
127
128
|
- lib/syntax_tree/language_server.rb
|
128
129
|
- lib/syntax_tree/language_server/inlay_hints.rb
|
129
130
|
- lib/syntax_tree/node.rb
|
130
131
|
- lib/syntax_tree/parser.rb
|
131
132
|
- lib/syntax_tree/plugin/single_quotes.rb
|
133
|
+
- lib/syntax_tree/plugin/trailing_comma.rb
|
134
|
+
- lib/syntax_tree/rake/check_task.rb
|
135
|
+
- lib/syntax_tree/rake/write_task.rb
|
136
|
+
- lib/syntax_tree/rake_tasks.rb
|
132
137
|
- lib/syntax_tree/version.rb
|
133
138
|
- lib/syntax_tree/visitor.rb
|
134
139
|
- lib/syntax_tree/visitor/field_visitor.rb
|
@@ -156,7 +161,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
156
161
|
- !ruby/object:Gem::Version
|
157
162
|
version: '0'
|
158
163
|
requirements: []
|
159
|
-
rubygems_version: 3.
|
164
|
+
rubygems_version: 3.4.0.dev
|
160
165
|
signing_key:
|
161
166
|
specification_version: 4
|
162
167
|
summary: A parser based on ripper
|