parlour 3.0.0 → 5.0.0.beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/bug-report.md +0 -0
  3. data/.github/ISSUE_TEMPLATE/feature-request.md +0 -0
  4. data/.gitignore +1 -1
  5. data/.parlour +5 -0
  6. data/.rspec +0 -0
  7. data/.travis.yml +0 -0
  8. data/CHANGELOG.md +57 -0
  9. data/CODE_OF_CONDUCT.md +0 -0
  10. data/Gemfile +0 -0
  11. data/LICENSE.txt +0 -0
  12. data/README.md +233 -19
  13. data/Rakefile +0 -0
  14. data/exe/parlour +109 -4
  15. data/lib/parlour.rb +27 -1
  16. data/lib/parlour/conflict_resolver.rb +31 -9
  17. data/lib/parlour/conversion/converter.rb +34 -0
  18. data/lib/parlour/conversion/rbi_to_rbs.rb +223 -0
  19. data/lib/parlour/debugging.rb +0 -0
  20. data/lib/parlour/detached_rbi_generator.rb +1 -6
  21. data/lib/parlour/detached_rbs_generator.rb +25 -0
  22. data/lib/parlour/generator.rb +34 -0
  23. data/lib/parlour/kernel_hack.rb +0 -0
  24. data/lib/parlour/options.rb +71 -0
  25. data/lib/parlour/parse_error.rb +0 -0
  26. data/lib/parlour/plugin.rb +1 -1
  27. data/lib/parlour/rbi_generator.rb +24 -37
  28. data/lib/parlour/rbi_generator/arbitrary.rb +5 -2
  29. data/lib/parlour/rbi_generator/attribute.rb +14 -5
  30. data/lib/parlour/rbi_generator/class_namespace.rb +8 -3
  31. data/lib/parlour/rbi_generator/constant.rb +28 -8
  32. data/lib/parlour/rbi_generator/enum_class_namespace.rb +8 -3
  33. data/lib/parlour/rbi_generator/extend.rb +5 -2
  34. data/lib/parlour/rbi_generator/include.rb +5 -2
  35. data/lib/parlour/rbi_generator/method.rb +15 -10
  36. data/lib/parlour/rbi_generator/module_namespace.rb +7 -2
  37. data/lib/parlour/rbi_generator/namespace.rb +68 -18
  38. data/lib/parlour/rbi_generator/parameter.rb +13 -7
  39. data/lib/parlour/rbi_generator/rbi_object.rb +19 -78
  40. data/lib/parlour/rbi_generator/struct_class_namespace.rb +9 -2
  41. data/lib/parlour/rbi_generator/struct_prop.rb +12 -9
  42. data/lib/parlour/rbi_generator/type_alias.rb +101 -0
  43. data/lib/parlour/rbs_generator.rb +24 -0
  44. data/lib/parlour/rbs_generator/arbitrary.rb +92 -0
  45. data/lib/parlour/rbs_generator/attribute.rb +82 -0
  46. data/lib/parlour/rbs_generator/block.rb +49 -0
  47. data/lib/parlour/rbs_generator/class_namespace.rb +106 -0
  48. data/lib/parlour/rbs_generator/constant.rb +95 -0
  49. data/lib/parlour/rbs_generator/extend.rb +92 -0
  50. data/lib/parlour/rbs_generator/include.rb +92 -0
  51. data/lib/parlour/rbs_generator/interface_namespace.rb +34 -0
  52. data/lib/parlour/rbs_generator/method.rb +146 -0
  53. data/lib/parlour/rbs_generator/method_signature.rb +104 -0
  54. data/lib/parlour/rbs_generator/module_namespace.rb +35 -0
  55. data/lib/parlour/rbs_generator/namespace.rb +627 -0
  56. data/lib/parlour/rbs_generator/parameter.rb +146 -0
  57. data/lib/parlour/rbs_generator/rbs_object.rb +78 -0
  58. data/lib/parlour/rbs_generator/type_alias.rb +96 -0
  59. data/lib/parlour/type_loader.rb +25 -12
  60. data/lib/parlour/type_parser.rb +174 -17
  61. data/lib/parlour/typed_object.rb +87 -0
  62. data/lib/parlour/types.rb +539 -0
  63. data/lib/parlour/version.rb +1 -1
  64. data/parlour.gemspec +1 -1
  65. data/plugin_examples/foobar_plugin.rb +0 -0
  66. data/rbi/parlour.rbi +1856 -0
  67. metadata +35 -10
  68. data/lib/parlour/rbi_generator/options.rb +0 -74
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1e2b9021c22592632f30a0a51c17cfbf3838c18061638297e9437c1dd34b5c9f
4
- data.tar.gz: 337e2ea6d8212e6c2d16d2f8f5577b16bfd1c8ffa41197fad70f9dc7c51620b5
3
+ metadata.gz: 9c9fa581e9b41195e54a4716df7926d1beb225c47871ff39d2f08fb0fa462aeb
4
+ data.tar.gz: 1aa333b0896df783baefa79d87fdbda732dea8676b85e89b7d76de607716658c
5
5
  SHA512:
6
- metadata.gz: 22e0196918f8214827f9904e45fff8689f4609ec71683ad4aca36c8eb75593e19f5d0ec4e5a5e034afdca1d3bdf7f0d9482bfb24b0e3e667553c13b5cb5b65a6
7
- data.tar.gz: 2b322d3dcdce74985b2104a8d8beb8ac0a7b6b4de1bcc8af7288d5334d715765285cba032017c7ab6e5dccde045b284dd8056e57515e13f32f319de26fdc0666
6
+ metadata.gz: 30486957baea0d7b30f827483ca69fbf589bd55039bedbcee6ea4f6258c0601612d191818a547569b32fe2e805dd29e34f27a46005eb3d5586dd7cb3462f7fb2
7
+ data.tar.gz: ed021b13ea01c171852be2d4892ba1042bc7dbf747e3413881e7d9c674553dea82337172c986dfec8ec78bfbed2be5519b6a091e2f3cd19f142797f54e35689e
File without changes
File without changes
data/.gitignore CHANGED
@@ -8,7 +8,7 @@
8
8
  /tmp/
9
9
  Gemfile.lock
10
10
  /.vscode
11
- /sorbte/rbi/hidden-definitions/errors.txt
11
+ /sorbet/rbi/hidden-definitions/errors.txt
12
12
 
13
13
  # rspec failure tracking
14
14
  .rspec_status
@@ -0,0 +1,5 @@
1
+ excluded_paths:
2
+ - lib/parlour/kernel_hack.rb
3
+
4
+ excluded_modules:
5
+ - Parlour::DetachedRbiGenerator
data/.rspec CHANGED
File without changes
File without changes
@@ -3,6 +3,63 @@ All notable changes to this project will be documented in this file.
3
3
 
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
5
5
 
6
+ ## [5.0.0.beta.3] - 2020-09-15
7
+ ### Changed
8
+ - Changed the RBS keyword warning to come from "RBS generation" rather than
9
+ "Type generalization"
10
+ - Added many more of RBS' keywords which are detected and prefixed with an
11
+ underscore to avoid syntax errors
12
+
13
+ ## [5.0.0.beta.2] - 2020-09-14
14
+ ### Added
15
+ - Added `Types::Type#describe` for simple text descriptions of types
16
+ - Added `Types::Self` for RBI's `T.self_type` or RBS' `self`
17
+
18
+ ### Fixed
19
+ - Fixed `RbiGenerator::Namespace#create_method`'s `returns:` kwarg only
20
+ accepting String types
21
+ - Fixed lack of spacing between argument lists and blocks in RBS
22
+ - Fixed RBS attributes not having comments
23
+
24
+ ## [5.0.0.beta.1] - 2020-09-13
25
+ ### Added
26
+ - Added RBS generation support! This includes:
27
+ - The new `RbsGenerator` class
28
+ - `RbsObject` and a set of subclasses representing different RBS components
29
+ - Added the `Types` module, which is used to describe types agnostic of the
30
+ underlying type system
31
+ - Added `RbiGenerator::Namespace#generalize_from_rbi!` to convert RBI string
32
+ types into `Types` types
33
+ - **Specifying types as strings is still currently supported, but may be
34
+ phased out in future, and should be avoided in new projects**.
35
+ - Added conversion from RBI to RBS type trees
36
+ - Added a couple of classes to deduplicate functionality between type systems:
37
+ - `TypedObject`, which `RbiObject` and `RbsObject` both inherit from
38
+ - `Generator`, which `RbiGenerator` and `RbsGenerator` both inherit from
39
+ - Added RBI type aliases
40
+
41
+ ### Changed
42
+ - `Parlour::RbiGenerator::Options` is now `Parlour::Options`. An alias exists
43
+ for now, but **`Parlour::RbiGenerator::Options` is deprecated** and could be
44
+ removed in future versions.
45
+ - Updated README and gem metadata to refer to Parlour as a type information
46
+ generator, rather than just an RBI generator
47
+
48
+ ## [4.0.1] - 2020-08-05
49
+ ### Fixed
50
+ - Fixed duplicate includes and extends.
51
+ - Fixed the block return type for `#resolve_conflicts` not being nilable.
52
+
53
+ ## [4.0.0] - 2020-05-23
54
+ ### Added
55
+ - Parlour now defaults to loading the current project when running its command
56
+ line tool, allowing it to be used as a "`sig` extractor" when run without
57
+ plugins! **Breaking if you invoke Parlour from its command line tool** - to
58
+ revert to the old behaviour of having nothing loaded into the root namespace
59
+ initially, add `parser: false` to your `.parlour` file.
60
+ - Generating constants in an eigenclass context (`class << self`) is now
61
+ supported.
62
+
6
63
  ## [3.0.0] - 2020-05-15
7
64
  ### Added
8
65
  - `T::Struct` classes can now be generated and parsed.
File without changes
data/Gemfile CHANGED
File without changes
File without changes
data/README.md CHANGED
@@ -3,39 +3,77 @@
3
3
  [![Build Status](https://travis-ci.org/AaronC81/parlour.svg?branch=master)](https://travis-ci.org/AaronC81/parlour)
4
4
  ![Gem](https://img.shields.io/gem/v/parlour.svg)
5
5
 
6
- Parlour is an RBI generator, merger and parser for Sorbet. It consists of three
7
- key parts:
6
+ Parlour is a Ruby type information generator, merger and parser, supporting both
7
+ **Sorbet RBI files and Ruby 3/Steep RBS files**. It consists of three key parts:
8
8
 
9
- - The generator, which outputs beautifully formatted RBI files, created using
10
- an intuitive DSL.
9
+ - The generator, which outputs beautifully formatted RBI/RBS files, created
10
+ using an intuitive DSL.
11
11
 
12
12
  - The plugin/build system, which allows multiple Parlour plugins to generate
13
13
  RBIs for the same codebase. These are combined automatically as much as
14
14
  possible, but any other conflicts can be resolved manually through prompts.
15
15
 
16
- - The parser, which can read an RBI and convert it back into a tree of
17
- generator objects.
16
+ - The parser (currently RBI-only), which can read an RBI and convert it back
17
+ into a tree of generator objects.
18
18
 
19
19
  ## Why should I use this?
20
20
 
21
- - Parlour enables **much easier creation of RBI generators**, as formatting
22
- is all handled for you, and you don't need to write your own CLI.
21
+ - Parlour enables **much easier creation of RBI/RBS generators**, as
22
+ formatting is all handled for you, and you don't need to write your own CLI.
23
23
 
24
24
  - You can **use many plugins together seamlessly**, running them all with a
25
25
  single command and consolidating all of their definitions into a single
26
- RBI output file.
26
+ output file.
27
27
 
28
28
  - You can **effortlessly build tools which need to access types within an RBI**;
29
- no need to write your own parser!
29
+ no need to write your own parser!
30
+
31
+ - You can **generate RBI/RBS to ship with your gem** for consuming projects to
32
+ use ([see "RBIs within gems" in Sorbet's
33
+ docs](https://sorbet.org/docs/rbi#rbis-within-gems)).
30
34
 
31
35
  Please [**read the wiki**](https://github.com/AaronC81/parlour/wiki) to get
32
36
  started!
33
37
 
34
- ## Creating RBIs
38
+ ## Feature Support
39
+
40
+ | Feature | RBI | RBS |
41
+ |---------|-----|-----|
42
+ | **GENERATION** | | |
43
+ | Classes | ✅ | ⚠️ (missing `extension`) |
44
+ | Modules | ✅ | ⚠️ (missing `extension`) |
45
+ | Interfaces | ✅ | ✅ |
46
+ | Attributes | ✅ | ✅ |
47
+ | Methods | ✅ | ✅ |
48
+ | Overloaded methods | ❌* | ✅ |
49
+ | Structs | ✅ | ✅† |
50
+ | Enums | ✅ | ✅† |
51
+ | Generation with plugins | ✅ | ❌ |
52
+ | **MANIPULATION** | | |
53
+ | Parsing | ✅ | ❌ |
54
+ | Merging | ✅ | ❌ |
55
+
56
+ - ✅ - Well supported
57
+ - ⚠️ - Some missing features
58
+ - ❌ - Not currently supported
59
+
60
+ - \* Only supported in stdlib types anyway
61
+ - † Not natively supported; available as a one-way conversion from RBI
62
+
63
+ ## Creating Type Information
35
64
 
36
- ### Using just the generator
65
+ Each file format has its own type information generator class, so there are two
66
+ different generators you can use: `RbiGenerator` and `RbsGenerator`. Both
67
+ generators are similar to use, however they provide different object types and
68
+ parameters to match the functionality of their underlying type systems.
37
69
 
38
- Here's a quick example of how you can generate an RBI:
70
+ You can also convert your type information between formats; see
71
+ [converting between formats](#converting-between-formats).
72
+
73
+ ### Using Just the Generator
74
+
75
+ Here's a quick example of how you can generate some type information. Here
76
+ we'll generate an RBI using the `RbiGenerator` classes:
39
77
 
40
78
  ```ruby
41
79
  require 'parlour'
@@ -69,11 +107,50 @@ module A
69
107
  end
70
108
  ```
71
109
 
72
- ### Writing a plugin
110
+ Using the RBS generator looks similar, but has an intermediary
111
+ `MethodSignature` class to support RBS' method overloading:
112
+
113
+ ```ruby
114
+ require 'parlour'
115
+
116
+ generator = Parlour::RbsGenerator.new
117
+ generator.root.create_module('A') do |a|
118
+ a.create_class('Foo') do |foo|
119
+ foo.create_method('add_two_integers', [
120
+ Parlour::RbsGenerator::MethodSignature.new(
121
+ [
122
+ Parlour::RbsGenerator::Parameter.new('a', type: 'Integer'),
123
+ Parlour::RbsGenerator::Parameter.new('b', type: 'Integer')
124
+ ],
125
+ 'Integer'
126
+ )
127
+ ])
128
+ end
129
+
130
+ a.create_class('Bar', superclass: 'Foo')
131
+ end
132
+
133
+ generator.rbs # => Our RBS as a string
134
+ ```
135
+
136
+ This generates an equivalent RBS file:
137
+
138
+ ```ruby
139
+ module A
140
+ class Foo
141
+ def add_two_integers: (Integer a, Integer b) -> Integer
142
+ end
143
+
144
+ class Bar < Foo
145
+ end
146
+ end
147
+ ```
148
+
149
+ ### Writing a Plugin
73
150
  Plugins are better than using the generator alone, as your plugin can be
74
- combined with others to produce larger RBIs without conflicts.
151
+ combined with others to produce larger files without conflicts.
75
152
 
76
- We could write the above example as a plugin like this:
153
+ We could write the above example as an RBI plugin like this:
77
154
 
78
155
  ```ruby
79
156
  require 'parlour'
@@ -104,7 +181,8 @@ called `plugin.rb`, then using this `.parlour` file and then running `parlour`
104
181
  would save the RBI into `output.rbi`:
105
182
 
106
183
  ```yaml
107
- output_file: output.rbi
184
+ output_file:
185
+ rbi: output.rbi
108
186
 
109
187
  relative_requires:
110
188
  - plugin.rb
@@ -128,7 +206,8 @@ You can also use plugins from gems. If that plugin was published as a gem called
128
206
  `parlour-gem`:
129
207
 
130
208
  ```yaml
131
- output_file: output.rbi
209
+ output_file:
210
+ rbi: output.rbi
132
211
 
133
212
  requires:
134
213
  - parlour-gem
@@ -140,7 +219,8 @@ plugins:
140
219
  The real power of this is the ability to use many plugins at once:
141
220
 
142
221
  ```yaml
143
- output_file: output.rbi
222
+ output_file:
223
+ rbi: output.rbi
144
224
 
145
225
  requires:
146
226
  - gem1
@@ -153,6 +233,92 @@ plugins:
153
233
  Gem3::Plugin: {}
154
234
  ```
155
235
 
236
+ Currently, only plugins which generate RBI files are supported. However, you can
237
+ use [Parlour's type conversion](#converting-between-formats) to convert the RBI
238
+ types into RBS types:
239
+
240
+ ```yaml
241
+ output_file:
242
+ rbi: output.rbi
243
+ rbs: output.rbs
244
+ ```
245
+
246
+ ## Using Types
247
+
248
+ The most important part of your type information is the types themselves, which
249
+ you'll be specifying for method parameters, method returns, and attributes.
250
+ These include simple types like `String`, up to more complex types like
251
+ "an array of elements which are one of `Integer`, `String`, or nil".
252
+
253
+ There are two ways to represent these types in Parlour:
254
+
255
+ 1. As **generalized types**; that is, instances of classes in the
256
+ `Parlour::Types` namespace. This is the **recommended way**, as it is
257
+ format-agnostic and can be compiled to RBI or RBS. For more information
258
+ about these types and how to use them, see
259
+ [this wiki page](https://github.com/AaronC81/parlour/wiki/The-Types-namespace).
260
+
261
+ 2. As **strings of code** written in the format that your type system expects.
262
+ The given strings are directly inserted into the final type file. These types
263
+ are **not portable across formats**, and as such are
264
+ **not recommended and may be phased out** in the future.
265
+
266
+ Currently most type values within Parlour are typed as `Types::TypeLike`,
267
+ which accepts a `String` or a `Types::Type` subclass.
268
+
269
+ ```ruby
270
+ include Parlour
271
+
272
+ # Two ways to express an attribute called 'example', which is:
273
+ # an array of nilable strings or integers
274
+
275
+ # 1. With generalised types - type is agnostic to the underlying type system
276
+ root.create_attr_accessor('example', type:
277
+ Types::Array.new(
278
+ Types::Nilable.new(
279
+ Types::Union.new(['String', 'Integer'])
280
+ )
281
+ )
282
+ )
283
+
284
+ # 2. With string types - format depends on type system
285
+ # If using RBI...
286
+ root.create_attr_accessor('example', type:
287
+ 'T::Array[T.nilable(T.any(String, Integer))]'
288
+ )
289
+ # If using RBS...
290
+ root.create_attr_accessor('example', type:
291
+ 'Array[?(String | Integer)]'
292
+ )
293
+ ```
294
+
295
+ ### Generalizing String Types
296
+
297
+ If you have loaded an RBI project or created a structure of nodes on an
298
+ `RbiGenerator`, you can use `#generalize_from_rbi!` on your root namespace
299
+ to attempt to permanently convert the RBI string types into generalized types:
300
+
301
+ ```ruby
302
+ # Build up an RBI tree with string types
303
+ root.create_attr_accessor('example', type:
304
+ 'T::Array[T.nilable(T.any(String, Integer))]'
305
+ )
306
+
307
+ # Generalize it
308
+ root.generalize_from_rbi!
309
+
310
+ # Take a look at our generalized type!
311
+ pp root.children.first.type
312
+ # => #<Parlour::Types::Array:0x0000557cdcebfdf8
313
+ # @element=
314
+ # #<Parlour::Types::Nilable:0x0000557cdcef8c70
315
+ # @type=
316
+ # #<Parlour::Types::Union:0x0000557cdcea0a70
317
+ # @types=
318
+ # [#<Parlour::Types::Raw:0x0000557cdcea1920 @str="String">,
319
+ # #<Parlour::Types::Raw:0x0000557cdcea0ae8 @str="Integer">]>>>
320
+ ```
321
+
156
322
  ## Parsing RBIs
157
323
 
158
324
  You can either parse individual RBI files, or point Parlour to the root of a
@@ -174,6 +340,54 @@ Parlour::TypeLoader.load_project('root/of/the/project')
174
340
  The structure of the returned object trees is identical to those you would
175
341
  create when generating an RBI, built of instances of `RbiObject` subclasses.
176
342
 
343
+ ## Generating RBI for a Gem
344
+
345
+ Include `parlour` as a development_dependency in your `.gemspec`:
346
+
347
+ ```ruby
348
+ spec.add_development_dependency 'parlour'
349
+ ```
350
+
351
+ Run Parlour from the command line:
352
+
353
+ ```ruby
354
+ bundle exec parlour
355
+ ```
356
+
357
+ Parlour is configured to use sane defaults assuming a standard gem structure
358
+ to generate an RBI that Sorbet will automatically find when your gem is included
359
+ as a dependency. If you require more advanced configuration you can add a
360
+ `.parlour` YAML file in the root of your project (see this project's `.parlour`
361
+ file as an example).
362
+
363
+ To disable the parsing step entire and just run plugins you can set `parser: false`
364
+ in your `.parlour` file.
365
+
366
+ ## Converting Between Formats
367
+
368
+ _For more information, see the [wiki page](https://github.com/AaronC81/parlour/wiki/Converting-between-RBI-and-RBS)._
369
+
370
+ Currently, only RBI to RBS conversion is supported, and if you've used string
371
+ types (or are using a freshly-loaded project) you
372
+ **must [generalize them](#generalizing-string-types) first**.
373
+
374
+ Then, all you need to do is create an `RbsGenerator` (which the converter will
375
+ add your converted types to) and a `Conversion::RbiToRbs` instance (which
376
+ performs the conversion). Then you can convert each object at your
377
+ `RbiGenerator`'s root namespace:
378
+
379
+ ```ruby
380
+ rbi_gen = Parlour::RbiGenerator.new
381
+ # Then, after populating the RbiGenerator with types...
382
+
383
+ # Create an RbsGenerator and a converter
384
+ rbs_gen = Parlour::RbsGenerator.new
385
+ converter = Parlour::Conversion::RbiToRbs.new(rbs_gen)
386
+
387
+ # Convert each item at the root of the RbiGenerator and it to the root of the RbsGenerator
388
+ converter.convert_all(rbi_gen.root, rbs_gen.root)
389
+ ```
390
+
177
391
  ## Parlour Plugins
178
392
 
179
393
  _Have you written an awesome Parlour plugin? Please submit a PR to add it to this list!_
data/Rakefile CHANGED
File without changes
@@ -16,15 +16,67 @@ command :run do |c|
16
16
  c.description = 'Generates an RBI file from your .parlour file'
17
17
 
18
18
  c.action do |args, options|
19
- configuration = keys_to_symbols(YAML.load_file(File.join(Dir.pwd, '.parlour')))
19
+ working_dir = Dir.pwd
20
+ config_filename = File.join(working_dir, '.parlour')
20
21
 
21
- raise 'you must specify output_file in your .parlour file' unless configuration[:output_file]
22
+ if File.exists?(config_filename)
23
+ configuration = keys_to_symbols(YAML.load_file(config_filename))
24
+ else
25
+ configuration = {}
26
+ end
27
+
28
+ # Output file
29
+ if configuration[:output_file].is_a?(String)
30
+ assumed_format = \
31
+ if configuration[:output_file].end_with?('.rbi')
32
+ :rbi
33
+ elsif configuration[:output_file].end_with?('.rbs')
34
+ :rbs
35
+ else
36
+ raise 'invalid output file; please specify an RBI or RBS file'
37
+ end
38
+
39
+ unless $VERBOSE.nil?
40
+ print Rainbow("Parlour warning: ").yellow.dark.bold
41
+ print Rainbow("CLI: ").magenta.bright.bold
42
+ puts "Specifying output_file in .parlour as a string is deprecated."
43
+ puts "For now, generating an #{assumed_format.to_s.upcase} file based on the file extension."
44
+ puts "Please update your .parlour to use the new form:"
45
+ puts " output_file:"
46
+ puts " #{assumed_format}: #{configuration[:output_file]}"
47
+ end
48
+ configuration[:output_file] = {
49
+ assumed_format => configuration[:output_file]
50
+ }
51
+ end
52
+ configuration[:output_file] ||= {
53
+ rbi: "rbi/#{File.basename(working_dir)}.rbi"
54
+ }
22
55
 
23
56
  # Style defaults
24
57
  configuration[:style] ||= {}
25
58
  configuration[:style][:tab_size] ||= 2
26
59
  configuration[:style][:break_params] ||= 4
27
60
 
61
+ # Parser defaults, set explicitly to false to not run parser
62
+ if configuration[:parser] != false
63
+ configuration[:parser] ||= {}
64
+
65
+ # Input/Output defaults
66
+ configuration[:parser][:root] ||= '.'
67
+
68
+ # Included/Excluded path defaults
69
+ configuration[:parser][:included_paths] ||= ['lib']
70
+ configuration[:parser][:excluded_paths] ||= ['sorbet', 'spec']
71
+
72
+ # Defaults can be overridden but we always want to exclude the output file
73
+ configuration[:parser][:excluded_paths] << configuration[:output_file][:rbi]
74
+ end
75
+
76
+ # Included/Excluded module defaults
77
+ configuration[:included_modules] ||= []
78
+ configuration[:excluded_modules] ||= []
79
+
28
80
  # Require defaults
29
81
  configuration[:requires] ||= []
30
82
  configuration[:relative_requires] ||= []
@@ -53,6 +105,15 @@ command :run do |c|
53
105
  break_params: configuration[:style][:break_params],
54
106
  tab_size: configuration[:style][:tab_size]
55
107
  )
108
+
109
+ if configuration[:parser]
110
+ Parlour::TypeLoader.load_project(
111
+ configuration[:parser][:root],
112
+ inclusions: configuration[:parser][:included_paths],
113
+ exclusions: configuration[:parser][:excluded_paths],
114
+ generator: gen,
115
+ )
116
+ end
56
117
  Parlour::Plugin.run_plugins(plugin_instances, gen)
57
118
 
58
119
  # Run a pass of the conflict resolver
@@ -74,6 +135,14 @@ command :run do |c|
74
135
  choice == 0 ? nil : candidates[choice - 1]
75
136
  end
76
137
 
138
+ if !configuration[:included_modules].empty? || !configuration[:excluded_modules].empty?
139
+ remove_unwanted_modules(
140
+ gen.root,
141
+ included_modules: configuration[:included_modules],
142
+ excluded_modules: configuration[:excluded_modules],
143
+ )
144
+ end
145
+
77
146
  # Figure out strictness levels
78
147
  requested_strictness_levels = plugin_instances.map do |plugin|
79
148
  s = plugin.strictness&.to_s
@@ -97,8 +166,23 @@ command :run do |c|
97
166
  end
98
167
  end
99
168
 
100
- # Write the final RBI
101
- File.write(configuration[:output_file], gen.rbi(strictness))
169
+ # Write the final files
170
+ if configuration[:output_file][:rbi]
171
+ FileUtils.mkdir_p(File.dirname(configuration[:output_file][:rbi]))
172
+ File.write(configuration[:output_file][:rbi], gen.rbi(strictness))
173
+ end
174
+ if configuration[:output_file][:rbs]
175
+ gen.root.generalize_from_rbi!
176
+ rbs_gen = Parlour::RbsGenerator.new
177
+
178
+ converter = Parlour::Conversion::RbiToRbs.new(rbs_gen)
179
+ gen.root.children.each do |child|
180
+ converter.convert_object(child, rbs_gen.root)
181
+ end
182
+
183
+ FileUtils.mkdir_p(File.dirname(configuration[:output_file][:rbs]))
184
+ File.write(configuration[:output_file][:rbs], rbs_gen.rbs)
185
+ end
102
186
  end
103
187
  end
104
188
 
@@ -122,3 +206,24 @@ def keys_to_symbols(hash)
122
206
  ]
123
207
  end.to_h
124
208
  end
209
+
210
+ def remove_unwanted_modules(root, included_modules:, excluded_modules:, prefix: nil)
211
+ root.children.select! do |child|
212
+ module_name = "#{prefix}#{child.name}"
213
+
214
+ if child.respond_to?(:children)
215
+ remove_unwanted_modules(
216
+ child,
217
+ included_modules: included_modules,
218
+ excluded_modules: excluded_modules,
219
+ prefix: "#{module_name}::",
220
+ )
221
+ has_included_children = !child.children.empty?
222
+ end
223
+
224
+ included = included_modules.empty? ? true : included_modules.any? { |m| module_name.start_with?(m) }
225
+ excluded = excluded_modules.empty? ? false : excluded_modules.any? { |m| module_name.start_with?(m) }
226
+
227
+ (included || has_included_children) && !excluded
228
+ end
229
+ end