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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3b1505fca44f379d951132dafb8122a2591fe46607c8402d096bab67bd53d0a3
4
- data.tar.gz: 0d58e60b6779ec1acd22ca776f3610f290c4b048cc1bf41b425f9c5a74e80db8
3
+ metadata.gz: f3d700916c1fab01ddc92117fd2b99c26b699df9e03f06b83eafa1415167ef7d
4
+ data.tar.gz: f5499912fe7bf422b44360bf66ce3f7e74145f3a2cc3ef5668e20fc97bd61948
5
5
  SHA512:
6
- metadata.gz: 42d4dea2571b21b3cf877a129f0a840f30125eb918c558b25b5bc303c915bb758b731151cdf2cfb6e70e92cbc4957d915095d1284312529675fec71f3a6af3a7
7
- data.tar.gz: 5178b395ddcfdcf795c18f7c986e86a12f6ca2bdec871792de2c21220dffc7c2a2238a02926cece3021635f42859ab5084ba4dba21932ce7f1791c2a17a5bc49
6
+ metadata.gz: e287bcace78e800140ce6b30044a684587e8514f7f0b4c8a57f7b4f3926717a96eb966828e42325a44c1af23715cc602c3cb327dcab27d5390b0353b6a595744
7
+ data.tar.gz: 7cb34f0d9d423b3129033f04dc543d1bb9b19e62dcc7a9a140eb5c3a3159caaf389746930d15e6556df753e10f0651e38ab5e4db95bad63737836e14f14a86c1
@@ -38,7 +38,7 @@ jobs:
38
38
  ruby-version: '3.1'
39
39
  - name: Check
40
40
  run: |
41
- bundle exec rake check
41
+ bundle exec rake stree:check
42
42
  bundle exec rubocop
43
43
 
44
44
  automerge:
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.5.0...HEAD
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
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- syntax_tree (2.5.0)
4
+ syntax_tree (2.6.0)
5
5
  prettier_print
6
6
 
7
7
  GEM
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` directory. Then when invoking the CLI, you will pass `--plugins=my_plugin`. That will get required. In this way, you can modify Syntax Tree however you would like. Some plugins ship with Syntax Tree itself. They are:
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
- FILEPATHS = %w[
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
- task :syntax_tree do
23
- $:.unshift File.expand_path("lib", __dir__)
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,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SyntaxTree
4
+ class Formatter
5
+ # This module overrides the trailing_comma? method on the formatter to
6
+ # return true.
7
+ module TrailingComma
8
+ def trailing_comma?
9
+ true
10
+ end
11
+ end
12
+ end
13
+ end
@@ -7,7 +7,12 @@ module SyntaxTree
7
7
  COMMENT_PRIORITY = 1
8
8
  HEREDOC_PRIORITY = 2
9
9
 
10
- attr_reader :source, :stack, :quote
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)
@@ -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
- q.format(CallOperatorFormatter.new(operator), stackable: false)
3034
- q.format(message)
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
- # [Params | Paren] the parameter declaration for this lambda
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
- q.text(force_parens ? "{" : "do")
5936
- q.indent do
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.format(statements)
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
- q.format(statements)
5947
- q.text(" }")
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:, &block; 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
@@ -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,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "syntax_tree/formatter/trailing_comma"
4
+ SyntaxTree::Formatter.prepend(SyntaxTree::Formatter::TrailingComma)
@@ -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
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "rake/check_task"
4
+ require_relative "rake/write_task"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SyntaxTree
4
- VERSION = "2.5.0"
4
+ VERSION = "2.6.0"
5
5
  end
@@ -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
@@ -301,6 +301,9 @@ module SyntaxTree
301
301
  # Visit a Lambda node.
302
302
  alias visit_lambda visit_child_nodes
303
303
 
304
+ # Visit a LambdaVar node.
305
+ alias visit_lambda_var visit_child_nodes
306
+
304
307
  # Visit a LBrace node.
305
308
  alias visit_lbrace visit_child_nodes
306
309
 
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.5.0
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-14 00:00:00.000000000 Z
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.3.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