tree_stand 0.1.6 → 0.2.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: 7d9ecce5098c654a026b3f08bd8e5dc0a87b696d5e56102f11a40540a7b45d72
4
- data.tar.gz: 41b5bc8b68fb82183e1d641e735fa9083365c5077402193cbf2128c026b1140e
3
+ metadata.gz: 957ff5fd108366dc0b3c0ec05c821a8d207930a4ccf291e1092d26e373a0f4da
4
+ data.tar.gz: fce8cce29e6d558ee447f2afcdf9c83dd276521c0261ec99be93dea8c456b9b1
5
5
  SHA512:
6
- metadata.gz: e1a91dcfa898f9341ed7d8493204cec0ff1170b157e8598226a41858faa96de9f4df45b6e1e449c5c817b3edc7b44efa9bfb7bbfae6a1f4a031580ff0663a0e3
7
- data.tar.gz: 23cc338e725309b833f1b9200101f191772798e3a85d1610c41237522096a7454013fcf6252de8b161c62f7831a263f2ec94603aff4be47739b4a78cc4fdcedc
6
+ metadata.gz: 0f87824f3b009cb8d6993e25cd9b44c2ba645bcf253ef88771b12307a37190a8cb3e405836baea363344763c71cfd3be1bf5c53dd10c69bdfbd66fad1dfdd62d
7
+ data.tar.gz: 25b6b852ff81d122a61d8c74fa94e2e4cde20918ca1b0323b7dbda2e30666d534c8f4acaf736c5298b1de09a6491a819f44badeab3d2ec0a13c56a5e9e46c7ef
data/.gitattributes ADDED
@@ -0,0 +1 @@
1
+ sorbet/rbi/** linguist-generated
@@ -15,15 +15,11 @@ jobs:
15
15
  entry:
16
16
  - { ruby: 3.0 }
17
17
  - { ruby: 3.1 }
18
+ - { ruby: 3.2 }
18
19
  name: test (${{ matrix.entry.ruby }})
19
20
  steps:
20
21
  - uses: actions/checkout@v3
21
22
 
22
- - uses: actions/checkout@v3
23
- with:
24
- repository: DerekStride/tree-sitter-sql
25
- path: tmp/tree-sitter-sql
26
-
27
23
  - uses: ruby/setup-ruby@v1
28
24
  with:
29
25
  ruby-version: ${{ matrix.entry.ruby }}
@@ -33,12 +29,8 @@ jobs:
33
29
  key: ${{ runner.os }}-gems-${{ hashFiles('Gemfile') }}
34
30
  restore-keys: ${{ runner.os }}-gems-
35
31
 
36
- - uses: actions/setup-node@v3
37
- with:
38
- node-version: 16
39
- - run: npm install tree-sitter-cli
40
-
41
- - run: sudo apt-get install -y libtree-sitter-dev make gcc
32
+ - run: sudo apt-get install -y libtree-sitter-dev
42
33
  - run: bundle install --jobs=3 --retry=3 --path=vendor/bundle
43
34
  - run: bin/setup
35
+ - run: bundle exec srb tc
44
36
  - run: bundle exec rake
data/.yardopts ADDED
@@ -0,0 +1,6 @@
1
+ --plugin sorbet
2
+ -
3
+ README.md
4
+ CONTRIBUTING.md
5
+ CODE_OF_CONDUCT.md
6
+ LICENSE.txt
data/CONTRIBUTING.md CHANGED
@@ -19,6 +19,12 @@ bin/setup
19
19
  bundle exec rake test
20
20
  ```
21
21
 
22
+ ### Typechecking
23
+
24
+ ```
25
+ bundle exec srb tc
26
+ ```
27
+
22
28
  ### Documentation
23
29
 
24
30
  To run the documentation server, execute the following command and open [localhost:8808](http://localhost:8808).
data/Gemfile CHANGED
@@ -2,4 +2,16 @@ source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'tree_sitter', git: 'https://github.com/Faveod/ruby-tree-sitter'
5
+ group :development, :test do
6
+ gem "bundler", "~> 2.3"
7
+ gem "debug", "~> 1.7", require: false
8
+ gem "rake", "~> 13.0"
9
+ gem 'tapioca', "~> 0.11.1", require: false
10
+ gem "yard", "~> 0.9.28"
11
+ end
12
+
13
+ group :test do
14
+ gem "minitest", "~> 5.17"
15
+ gem "minitest-reporters", "~> 1.5"
16
+ gem "minitest-focus", "~> 1.3"
17
+ end
data/README.md CHANGED
@@ -20,7 +20,7 @@ See the [documentation](https://shopify.github.io/tree_stand) for supported feat
20
20
 
21
21
  ### Setting Up a Parser
22
22
 
23
- TreeStand do not help with compiling individual parsers. However, once you compile a parser and generate a shared
23
+ TreeStand does not help with compiling individual parsers. However, once you compile a parser and generate a shared
24
24
  object (`.so`) or a dynamic library (`.dylib`) you can tell TreeStand where to find them and pass the parser filename
25
25
  to `TreeStand::Parser::new`.
26
26
 
@@ -48,10 +48,12 @@ The underlying objects are accessible via a `ts_` prefixed attribute, e.g. `ts_p
48
48
 
49
49
  Bug reports and pull requests are welcome on GitHub at https://github.com/Shopify/tree_stand. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
50
50
 
51
+ See [CONTRIBUTING.md](https://github.com/Shopify/tree_stand/blob/main/CONTRIBUTING.md) for documentation on how to set up the project for development.
52
+
51
53
  ## License
52
54
 
53
55
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
54
56
 
55
57
  ## Code of Conduct
56
58
 
57
- Everyone interacting in the TreeStand project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/Shopify/tree_stand/blob/master/CODE_OF_CONDUCT.md).
59
+ Everyone interacting in the TreeStand project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/Shopify/tree_stand/blob/main/CODE_OF_CONDUCT.md).
data/bin/console CHANGED
@@ -11,12 +11,12 @@ end
11
11
 
12
12
  ivars_to_add = <<~RUBY
13
13
  @parser = TreeStand::Parser.new("math")
14
- @tree = @parser.parse_string(nil, "1 + x")
14
+ @tree = @parser.parse_string("1 + x")
15
15
  RUBY
16
16
 
17
17
  eval(ivars_to_add)
18
18
  puts("available ivars:")
19
19
  puts(ivars_to_add)
20
20
 
21
- require "pry"
22
- Pry.start
21
+ require "irb"
22
+ IRB.start(__FILE__)
data/bin/setup CHANGED
@@ -13,7 +13,6 @@ fi
13
13
 
14
14
  cd tmp/tree-sitter-math
15
15
 
16
- npm install
17
16
  mkdir -p target
18
17
  gcc -shared -o target/parser.so -fPIC src/parser.c -I./src
19
18
 
data/bin/tapioca ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'tapioca' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
12
+
13
+ bundle_binstub = File.expand_path("bundle", __dir__)
14
+
15
+ if File.file?(bundle_binstub)
16
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
17
+ load(bundle_binstub)
18
+ else
19
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
20
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
21
+ end
22
+ end
23
+
24
+ require "rubygems"
25
+ require "bundler/setup"
26
+
27
+ load Gem.bin_path("tapioca", "tapioca")
@@ -1,10 +1,15 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
1
4
  module TreeStand
2
- # An experimental class to modify the AST. I re-runs the query on the
5
+ # An experimental class to modify the AST. It re-runs the query on the
3
6
  # modified document every loop to ensure that the match is still valid.
4
7
  # @see TreeStand::Tree
5
8
  # @api experimental
6
9
  class AstModifier
7
- # @param tree [TreeStand::Tree]
10
+ extend T::Sig
11
+
12
+ sig { params(tree: TreeStand::Tree).void }
8
13
  def initialize(tree)
9
14
  @tree = tree
10
15
  end
@@ -1,8 +1,13 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
1
4
  module TreeStand
2
5
  # Global configuration for the gem.
3
6
  # @api private
4
7
  class Config
5
- # @return [String]
8
+ extend T::Sig
9
+
10
+ sig { returns(String) }
6
11
  attr_accessor :parser_path
7
12
  end
8
13
  end
@@ -1,9 +1,13 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
1
4
  module TreeStand
2
5
  # Wrapper around a TreeSitter node and provides convient
3
6
  # methods that are missing on the original node. This class
4
7
  # overrides the `method_missing` method to delegate to a nodes
5
8
  # named children.
6
9
  class Node
10
+ extend T::Sig
7
11
  extend Forwardable
8
12
  include Enumerable
9
13
 
@@ -17,20 +21,13 @@ module TreeStand
17
21
  :error?,
18
22
  )
19
23
 
20
- # @return [TreeStand::Tree]
24
+ sig { returns(TreeStand::Tree) }
21
25
  attr_reader :tree
22
- # @return [TreeSitter::Node]
26
+ sig { returns(TreeSitter::Node) }
23
27
  attr_reader :ts_node
24
28
 
25
- # @!method to_a
26
- # @example
27
- # node.text # => "3 * 4"
28
- # node.to_a.map(&:text) # => ["3", "*", "4"]
29
- # node.children.map(&:text) # => ["3", "*", "4"]
30
- # @return [Array<TreeStand::Node>]
31
- alias_method :children, :to_a
32
-
33
29
  # @api private
30
+ sig { params(tree: TreeStand::Tree, ts_node: TreeSitter::Node).void }
34
31
  def initialize(tree, ts_node)
35
32
  @tree = tree
36
33
  @ts_node = ts_node
@@ -53,9 +50,7 @@ module TreeStand
53
50
  # tree.root_node.query(<<~QUERY)
54
51
  # (identifier) @identifier
55
52
  # QUERY
56
- #
57
- # @param query_string [String]
58
- # @return [Array<Hash<String, TreeStand::Node>>]
53
+ sig { params(query_string: String).returns(T::Array[T::Hash[String, TreeStand::Node]]) }
59
54
  def query(query_string)
60
55
  ts_query = TreeSitter::Query.new(@tree.parser.ts_language, query_string)
61
56
  ts_cursor = TreeSitter::QueryCursor.exec(ts_query, ts_node)
@@ -81,8 +76,7 @@ module TreeStand
81
76
  #
82
77
  # @see #find_node!
83
78
  # @see #query
84
- # @param query_string [String]
85
- # @return [TreeStand::Node, nil]
79
+ sig { params(query_string: String).returns(T.nilable(TreeStand::Node)) }
86
80
  def find_node(query_string)
87
81
  query(query_string).first&.values&.first
88
82
  end
@@ -91,14 +85,13 @@ module TreeStand
91
85
  # {TreeStand::NodeNotFound} error.
92
86
  #
93
87
  # @see #find_node
94
- # @param query_string [String]
95
- # @return [TreeStand::Node]
96
88
  # @raise [TreeStand::NodeNotFound]
89
+ sig { params(query_string: String).returns(TreeStand::Node) }
97
90
  def find_node!(query_string)
98
91
  find_node(query_string) || raise(TreeStand::NodeNotFound)
99
92
  end
100
93
 
101
- # @return [TreeStand::Range]
94
+ sig { returns(TreeStand::Range) }
102
95
  def range
103
96
  TreeStand::Range.new(
104
97
  start_byte: @ts_node.start_byte,
@@ -122,13 +115,19 @@ module TreeStand
122
115
  # node.map(&:text) # => ["3", "*", "4"]
123
116
  #
124
117
  # @yieldparam child [TreeStand::Node]
125
- # @return [Enumerator]
118
+ sig do
119
+ override
120
+ .params(block: T.nilable(T.proc.params(node: TreeStand::Node).returns(BasicObject)))
121
+ .returns(T::Enumerator[TreeStand::Node])
122
+ end
126
123
  def each(&block)
127
- Enumerator.new do |yielder|
124
+ enumerator = Enumerator.new do |yielder|
128
125
  @ts_node.each do |child|
129
126
  yielder << TreeStand::Node.new(@tree, child)
130
127
  end
131
- end.each(&block)
128
+ end
129
+ enumerator.each(&block) if block_given?
130
+ enumerator
132
131
  end
133
132
 
134
133
  # (see TreeStand::Visitors::TreeWalker)
@@ -137,32 +136,44 @@ module TreeStand
137
136
  # @example Check the subtree for error nodes
138
137
  # node.walk.any? { |node| node.type == :error }
139
138
  #
140
- # @yieldparam node [TreeStand::Node]
141
- # @return [Enumerator]
142
- #
143
139
  # @see TreeStand::Visitors::TreeWalker
140
+ #
141
+ # @yieldparam node [TreeStand::Node]
142
+ sig do
143
+ params(block: T.nilable(T.proc.params(node: TreeStand::Node).returns(BasicObject)))
144
+ .returns(T::Enumerator[TreeStand::Node])
145
+ end
144
146
  def walk(&block)
145
- Enumerator.new do |yielder|
147
+ enumerator = Enumerator.new do |yielder|
146
148
  Visitors::TreeWalker.new(self) do |child|
147
149
  yielder << child
148
150
  end.visit
149
- end.each(&block)
151
+ end
152
+ enumerator.each(&block) if block_given?
153
+ enumerator
150
154
  end
151
155
 
152
156
  # @example
153
157
  # node.text # => "4"
154
158
  # node.parent.text # => "3 * 4"
155
159
  # node.parent.parent.text # => "1 + 3 * 4"
156
- # @return [TreeStand::Node]
160
+ sig { returns(TreeStand::Node) }
157
161
  def parent
158
162
  TreeStand::Node.new(@tree, @ts_node.parent)
159
163
  end
160
164
 
161
- # A convience method for getting the text of the node. Each {TreeStand::Node}
165
+ # @example
166
+ # node.text # => "3 * 4"
167
+ # node.to_a.map(&:text) # => ["3", "*", "4"]
168
+ # node.children.map(&:text) # => ["3", "*", "4"]
169
+ sig { returns(T::Array[TreeStand::Node]) }
170
+ def children = to_a
171
+
172
+ # A convenience method for getting the text of the node. Each {TreeStand::Node}
162
173
  # wraps the parent {TreeStand::Tree #tree} and has access to the source document.
163
- # @return [String]
174
+ sig { returns(String) }
164
175
  def text
165
- @tree.document[@ts_node.start_byte...@ts_node.end_byte]
176
+ T.must(@tree.document[@ts_node.start_byte...@ts_node.end_byte])
166
177
  end
167
178
 
168
179
  # This class overrides the `method_missing` method to delegate to the
@@ -183,26 +194,21 @@ module TreeStand
183
194
  # @raise [NoMethodError]
184
195
  def method_missing(method, *args, &block)
185
196
  return super unless @fields.include?(method.to_s)
186
- TreeStand::Node.new(@tree, @ts_node.public_send(method, *args, &block))
197
+ TreeStand::Node.new(@tree, T.unsafe(@ts_node).public_send(method, *args, &block))
187
198
  end
188
199
 
189
- # @param other [Object]
190
- # @return [bool]
200
+ sig { params(other: Object).returns(T::Boolean) }
191
201
  def ==(other)
192
202
  return false unless other.is_a?(TreeStand::Node)
193
203
 
194
- range == other.range &&
195
- type == other.type &&
196
- text == other.text
204
+ T.must(range == other.range && type == other.type && text == other.text)
197
205
  end
198
206
 
199
207
  # (see TreeStand::Utils::Printer)
200
208
  # Backed by {TreeStand::Utils::Printer}.
201
209
  #
202
- # @param pp [PP]
203
- # @return [void]
204
- #
205
210
  # @see TreeStand::Utils::Printer
211
+ sig { params(pp: PP).void }
206
212
  def pretty_print(pp)
207
213
  Utils::Printer.new(ralign: 80).print(self, io: pp.output)
208
214
  end
@@ -1,3 +1,6 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
1
4
  module TreeStand
2
5
  # Wrapper around the TreeSitter parser. It looks up the parser by filename in
3
6
  # the configured parsers directory.
@@ -12,12 +15,15 @@ module TreeStand
12
15
  # # Looks for a parser in `path/to/parser/folder/ruby.{so,dylib}`
13
16
  # ruby_parser = TreeStand::Parser.new("ruby")
14
17
  class Parser
15
- # @return [TreeSitter::Language]
18
+ extend T::Sig
19
+
20
+ sig { returns(TreeSitter::Language) }
16
21
  attr_reader :ts_language
17
- # @return [TreeSitter::Parser]
22
+ sig { returns(TreeSitter::Parser) }
18
23
  attr_reader :ts_parser
19
24
 
20
25
  # @param language [String]
26
+ sig { params(language: String).void }
21
27
  def initialize(language)
22
28
  @language_string = language
23
29
  @ts_language = TreeSitter::Language.load(
@@ -33,8 +39,7 @@ module TreeStand
33
39
  # @param tree [TreeStand::Tree, nil] providing the old tree will allow the
34
40
  # parser to take advantage of incremental parsing and improve performance
35
41
  # by re-useing nodes from the old tree.
36
- # @param document [String]
37
- # @return [TreeStand::Tree]
42
+ sig { params(document: String, tree: T.nilable(TreeStand::Tree)).returns(TreeStand::Tree) }
38
43
  def parse_string(document, tree: nil)
39
44
  # @todo There's a bug with passing a non-nil tree
40
45
  ts_tree = @ts_parser.parse_string(nil, document)
@@ -47,6 +52,7 @@ module TreeStand
47
52
  #
48
53
  # @see #parse_string
49
54
  # @raise [TreeStand::InvalidDocument]
55
+ sig { params(document: String, tree: T.nilable(TreeStand::Tree)).returns(TreeStand::Tree) }
50
56
  def parse_string!(document, tree: nil)
51
57
  tree = parse_string(document, tree: tree)
52
58
  return tree unless tree.any?(&:error?)
@@ -1,6 +1,11 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
1
4
  module TreeStand
2
5
  # Wrapper around a TreeSitter range. This is mainly used to compare ranges.
3
6
  class Range
7
+ extend T::Sig
8
+
4
9
  # Point is a Struct containing the row and column from a TreeSitter point.
5
10
  # TreeStand uses this to compare points.
6
11
  # @!attribute [rw] row
@@ -9,16 +14,24 @@ module TreeStand
9
14
  # @return [Integer]
10
15
  Point = Struct.new(:row, :column)
11
16
 
12
- # @return [Integer]
17
+ sig { returns(Integer) }
13
18
  attr_reader :start_byte
14
- # @return [Integer]
19
+ sig { returns(Integer) }
15
20
  attr_reader :end_byte
16
- # @return [TreeStand::Range::Point]
21
+ sig { returns(TreeStand::Range::Point) }
17
22
  attr_reader :start_point
18
- # @return [TreeStand::Range::Point]
23
+ sig { returns(TreeStand::Range::Point) }
19
24
  attr_reader :end_point
20
25
 
21
26
  # @api private
27
+ sig do
28
+ params(
29
+ start_byte: Integer,
30
+ end_byte: Integer,
31
+ start_point: T.any(TreeStand::Range::Point, TreeSitter::Point),
32
+ end_point: T.any(TreeStand::Range::Point, TreeSitter::Point),
33
+ ).void
34
+ end
22
35
  def initialize(start_byte:, end_byte:, start_point:, end_point:)
23
36
  @start_byte = start_byte
24
37
  @end_byte = end_byte
@@ -26,8 +39,7 @@ module TreeStand
26
39
  @end_point = Point.new(end_point.row, end_point.column)
27
40
  end
28
41
 
29
- # @param other [Object]
30
- # @return [bool]
42
+ sig { params(other: Object).returns(T::Boolean) }
31
43
  def ==(other)
32
44
  return false unless other.is_a?(TreeStand::Range)
33
45
 
@@ -1,3 +1,6 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
1
4
  module TreeStand
2
5
  # Wrapper around a TreeSitter tree.
3
6
  #
@@ -22,25 +25,29 @@ module TreeStand
22
25
  # This is not always possible and depends on the edits you make, beware that
23
26
  # the tree will be different after each edit and this approach may cause bugs.
24
27
  class Tree
28
+ extend T::Sig
25
29
  extend Forwardable
26
30
  include Enumerable
27
31
 
28
- # @return [String]
32
+ sig { returns(String) }
29
33
  attr_reader :document
30
- # @return [TreeSitter::Tree]
34
+ sig { returns(TreeSitter::Tree) }
31
35
  attr_reader :ts_tree
32
- # @return [TreeStand::Parser]
36
+ sig { returns(TreeStand::Parser) }
33
37
  attr_reader :parser
34
38
 
35
39
  # @!method query(query_string)
40
+ # (see TreeStand::Node#query)
36
41
  # @note This is a convenience method that calls {TreeStand::Node#query} on
37
42
  # {#root_node}.
38
43
  #
39
44
  # @!method find_node(query_string)
45
+ # (see TreeStand::Node#find_node)
40
46
  # @note This is a convenience method that calls {TreeStand::Node#find_node} on
41
47
  # {#root_node}.
42
48
  #
43
49
  # @!method find_node!(query_string)
50
+ # (see TreeStand::Node#find_node!)
44
51
  # @note This is a convenience method that calls {TreeStand::Node#find_node!} on
45
52
  # {#root_node}.
46
53
  #
@@ -69,13 +76,14 @@ module TreeStand
69
76
  alias_method :each, :walk
70
77
 
71
78
  # @api private
79
+ sig { params(parser: TreeStand::Parser, tree: TreeSitter::Tree, document: String).void }
72
80
  def initialize(parser, tree, document)
73
81
  @parser = parser
74
82
  @ts_tree = tree
75
83
  @document = document
76
84
  end
77
85
 
78
- # @return [TreeStand::Node]
86
+ sig { returns(TreeStand::Node) }
79
87
  def root_node
80
88
  TreeStand::Node.new(self, @ts_tree.root_node)
81
89
  end
@@ -83,9 +91,7 @@ module TreeStand
83
91
  # This method replaces the section of the document specified by range and
84
92
  # replaces it with the provided text. Then it will reparse the document and
85
93
  # update the tree!
86
- # @param range [TreeStand::Range]
87
- # @param replacement [String]
88
- # @return [void]
94
+ sig { params(range: TreeStand::Range, replacement: String).void }
89
95
  def edit!(range, replacement)
90
96
  new_document = +""
91
97
  new_document << @document[0...range.start_byte]
@@ -96,8 +102,7 @@ module TreeStand
96
102
 
97
103
  # This method deletes the section of the document specified by range. Then
98
104
  # it will reparse the document and update the tree!
99
- # @param range [TreeStand::Range]
100
- # @return [void]
105
+ sig { params(range: TreeStand::Range).void }
101
106
  def delete!(range)
102
107
  new_document = +""
103
108
  new_document << @document[0...range.start_byte]
@@ -1,3 +1,6 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
1
4
  module TreeStand
2
5
  # A collection of useful methods for working with syntax trees.
3
6
  module Utils
@@ -11,26 +14,26 @@ module TreeStand
11
14
  # # ("+") | +
12
15
  # # right: (variable))) | x
13
16
  class Printer
14
- # @param ralign [Integer] the right alignment for the text column.
17
+ extend T::Sig
18
+
19
+ # @param ralign the right alignment for the text column.
20
+ sig { params(ralign: Integer).void }
15
21
  def initialize(ralign:)
16
22
  @ralign = ralign
17
23
  end
18
24
 
19
25
  # (see TreeStand::Utils::Printer)
20
- #
21
- # @param node [TreeStand::Node]
22
- # @param io [IO]
23
- # @return [IO]
26
+ sig { params(node: TreeStand::Node, io: T.any(IO, StringIO, String)).returns(T.any(IO, StringIO, String)) }
24
27
  def print(node, io: StringIO.new)
25
28
  lines = pretty_output_lines(node)
26
29
 
27
30
  lines.each do |line|
28
31
  if line.text.empty?
29
- io.puts line.sexpr
32
+ io << line.sexpr << "\n"
30
33
  next
31
34
  end
32
35
 
33
- io.puts "#{line.sexpr}#{" " * (@ralign - line.sexpr.size)}| #{line.text}"
36
+ io << "#{line.sexpr}#{" " * (@ralign - line.sexpr.size)}| #{line.text}\n"
34
37
  end
35
38
 
36
39
  io
@@ -48,7 +51,7 @@ module TreeStand
48
51
  return [Line.new("#{indent}#{prefix}#{ts_node}", node.text)]
49
52
  end
50
53
 
51
- lines = [Line.new("#{indent}#{prefix}(#{ts_node.type}", "")]
54
+ lines = T.let([Line.new("#{indent}#{prefix}(#{ts_node.type}", "")], T::Array[Line])
52
55
 
53
56
  node.each.with_index do |child, index|
54
57
  lines += if field_name = ts_node.field_name_for_child(index)
@@ -62,7 +65,7 @@ module TreeStand
62
65
  end
63
66
  end
64
67
 
65
- lines.last.sexpr << ")"
68
+ T.must(lines.last).sexpr << ")"
66
69
  lines
67
70
  end
68
71
  end
@@ -1,4 +1,7 @@
1
+ # frozen_string_literal: true
2
+ # typed: strong
3
+
1
4
  module TreeStand
2
5
  # The current version of the gem.
3
- VERSION = "0.1.6"
6
+ VERSION = "0.2.0"
4
7
  end