tapioca 0.16.9 → 0.17.7
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.
- checksums.yaml +4 -4
- data/README.md +21 -0
- data/exe/tapioca +6 -1
- data/lib/ruby_lsp/tapioca/addon.rb +73 -43
- data/lib/ruby_lsp/tapioca/run_gem_rbi_check.rb +43 -43
- data/lib/ruby_lsp/tapioca/server_addon.rb +13 -10
- data/lib/tapioca/bundler_ext/auto_require_hook.rb +6 -14
- data/lib/tapioca/cli.rb +16 -8
- data/lib/tapioca/commands/abstract_dsl.rb +39 -66
- data/lib/tapioca/commands/abstract_gem.rb +25 -46
- data/lib/tapioca/commands/annotations.rb +28 -34
- data/lib/tapioca/commands/check_shims.rb +6 -15
- data/lib/tapioca/commands/command.rb +12 -26
- data/lib/tapioca/commands/command_without_tracker.rb +2 -5
- data/lib/tapioca/commands/configure.rb +11 -16
- data/lib/tapioca/commands/dsl_compiler_list.rb +2 -1
- data/lib/tapioca/commands/dsl_generate.rb +2 -1
- data/lib/tapioca/commands/dsl_verify.rb +2 -1
- data/lib/tapioca/commands/gem_generate.rb +5 -9
- data/lib/tapioca/commands/gem_sync.rb +2 -1
- data/lib/tapioca/commands/gem_verify.rb +3 -2
- data/lib/tapioca/commands/require.rb +3 -7
- data/lib/tapioca/commands/todo.rb +6 -10
- data/lib/tapioca/dsl/compiler.rb +36 -63
- data/lib/tapioca/dsl/compilers/aasm.rb +33 -44
- data/lib/tapioca/dsl/compilers/action_controller_helpers.rb +8 -7
- data/lib/tapioca/dsl/compilers/action_mailer.rb +6 -5
- data/lib/tapioca/dsl/compilers/action_text.rb +6 -5
- data/lib/tapioca/dsl/compilers/active_job.rb +6 -10
- data/lib/tapioca/dsl/compilers/active_model_attributes.rb +10 -11
- data/lib/tapioca/dsl/compilers/active_model_secure_password.rb +5 -6
- data/lib/tapioca/dsl/compilers/active_model_validations_confirmation.rb +5 -12
- data/lib/tapioca/dsl/compilers/active_record_associations.rb +17 -44
- data/lib/tapioca/dsl/compilers/active_record_columns.rb +20 -26
- data/lib/tapioca/dsl/compilers/active_record_delegated_types.rb +9 -8
- data/lib/tapioca/dsl/compilers/active_record_enum.rb +7 -6
- data/lib/tapioca/dsl/compilers/active_record_fixtures.rb +54 -62
- data/lib/tapioca/dsl/compilers/active_record_relations.rb +148 -209
- data/lib/tapioca/dsl/compilers/active_record_scope.rb +8 -13
- data/lib/tapioca/dsl/compilers/active_record_secure_token.rb +5 -4
- data/lib/tapioca/dsl/compilers/active_record_store.rb +5 -4
- data/lib/tapioca/dsl/compilers/active_record_typed_store.rb +19 -28
- data/lib/tapioca/dsl/compilers/active_resource.rb +19 -21
- data/lib/tapioca/dsl/compilers/active_storage.rb +6 -14
- data/lib/tapioca/dsl/compilers/active_support_concern.rb +9 -8
- data/lib/tapioca/dsl/compilers/active_support_current_attributes.rb +8 -7
- data/lib/tapioca/dsl/compilers/active_support_time_ext.rb +5 -4
- data/lib/tapioca/dsl/compilers/config.rb +5 -4
- data/lib/tapioca/dsl/compilers/frozen_record.rb +7 -11
- data/lib/tapioca/dsl/compilers/graphql_input_object.rb +9 -10
- data/lib/tapioca/dsl/compilers/graphql_mutation.rb +6 -10
- data/lib/tapioca/dsl/compilers/identity_cache.rb +11 -39
- data/lib/tapioca/dsl/compilers/json_api_client_resource.rb +9 -18
- data/lib/tapioca/dsl/compilers/kredis.rb +7 -8
- data/lib/tapioca/dsl/compilers/mixed_in_class_attributes.rb +5 -4
- data/lib/tapioca/dsl/compilers/protobuf.rb +13 -26
- data/lib/tapioca/dsl/compilers/rails_generators.rb +9 -11
- data/lib/tapioca/dsl/compilers/sidekiq_worker.rb +23 -13
- data/lib/tapioca/dsl/compilers/smart_properties.rb +32 -38
- data/lib/tapioca/dsl/compilers/state_machines.rb +15 -26
- data/lib/tapioca/dsl/compilers/url_helpers.rb +10 -9
- data/lib/tapioca/dsl/compilers.rb +4 -7
- data/lib/tapioca/dsl/helpers/active_model_type_helper.rb +13 -16
- data/lib/tapioca/dsl/helpers/active_record_column_type_helper.rb +13 -28
- data/lib/tapioca/dsl/helpers/active_record_constants_helper.rb +19 -15
- data/lib/tapioca/dsl/helpers/graphql_type_helper.rb +5 -24
- data/lib/tapioca/dsl/pipeline.rb +30 -58
- data/lib/tapioca/executor.rb +6 -12
- data/lib/tapioca/gem/events.rb +24 -34
- data/lib/tapioca/gem/listeners/base.rb +7 -10
- data/lib/tapioca/gem/listeners/dynamic_mixins.rb +4 -2
- data/lib/tapioca/gem/listeners/foreign_constants.rb +5 -7
- data/lib/tapioca/gem/listeners/methods.rb +36 -47
- data/lib/tapioca/gem/listeners/mixins.rb +6 -18
- data/lib/tapioca/gem/listeners/remove_empty_payload_scopes.rb +4 -2
- data/lib/tapioca/gem/listeners/sorbet_enums.rb +4 -2
- data/lib/tapioca/gem/listeners/sorbet_helpers.rb +4 -2
- data/lib/tapioca/gem/listeners/sorbet_props.rb +4 -2
- data/lib/tapioca/gem/listeners/sorbet_required_ancestors.rb +4 -2
- data/lib/tapioca/gem/listeners/sorbet_signatures.rb +7 -5
- data/lib/tapioca/gem/listeners/sorbet_type_variables.rb +6 -4
- data/lib/tapioca/gem/listeners/source_location.rb +15 -8
- data/lib/tapioca/gem/listeners/subconstants.rb +5 -4
- data/lib/tapioca/gem/listeners/yard_doc.rb +30 -23
- data/lib/tapioca/gem/pipeline.rb +107 -91
- data/lib/tapioca/gem_info.rb +1 -1
- data/lib/tapioca/gemfile.rb +64 -73
- data/lib/tapioca/helpers/cli_helper.rb +4 -7
- data/lib/tapioca/helpers/config_helper.rb +17 -29
- data/lib/tapioca/helpers/env_helper.rb +2 -5
- data/lib/tapioca/helpers/gem_helper.rb +5 -5
- data/lib/tapioca/helpers/git_attributes.rb +3 -3
- data/lib/tapioca/helpers/rbi_files_helper.rb +76 -73
- data/lib/tapioca/helpers/rbi_helper.rb +14 -22
- data/lib/tapioca/helpers/sorbet_helper.rb +9 -18
- data/lib/tapioca/helpers/source_uri.rb +15 -25
- data/lib/tapioca/helpers/test/content.rb +7 -10
- data/lib/tapioca/helpers/test/dsl_compiler.rb +20 -33
- data/lib/tapioca/helpers/test/isolation.rb +10 -14
- data/lib/tapioca/helpers/test/template.rb +6 -11
- data/lib/tapioca/internal.rb +18 -8
- data/lib/tapioca/loaders/dsl.rb +11 -19
- data/lib/tapioca/loaders/gem.rb +6 -21
- data/lib/tapioca/loaders/loader.rb +21 -39
- data/lib/tapioca/rbi_ext/model.rb +12 -37
- data/lib/tapioca/rbi_formatter.rb +10 -19
- data/lib/tapioca/rbs/rewriter.rb +55 -0
- data/lib/tapioca/repo_index.rb +7 -9
- data/lib/tapioca/runtime/attached_class_of_32.rb +1 -1
- data/lib/tapioca/runtime/attached_class_of_legacy.rb +2 -5
- data/lib/tapioca/runtime/dynamic_mixin_compiler.rb +23 -23
- data/lib/tapioca/runtime/generic_type_registry.rb +13 -23
- data/lib/tapioca/runtime/reflection.rb +81 -60
- data/lib/tapioca/runtime/source_location.rb +44 -0
- data/lib/tapioca/runtime/trackers/autoload.rb +7 -9
- data/lib/tapioca/runtime/trackers/constant_definition.rb +18 -14
- data/lib/tapioca/runtime/trackers/method_definition.rb +65 -0
- data/lib/tapioca/runtime/trackers/mixin.rb +8 -11
- data/lib/tapioca/runtime/trackers/required_ancestor.rb +3 -3
- data/lib/tapioca/runtime/trackers/tracker.rb +3 -6
- data/lib/tapioca/runtime/trackers.rb +5 -8
- data/lib/tapioca/sorbet_ext/generic_name_patch.rb +9 -15
- data/lib/tapioca/sorbet_ext/name_patch.rb +2 -2
- data/lib/tapioca/sorbet_ext/proc_bind_patch.rb +1 -1
- data/lib/tapioca/static/requires_compiler.rb +6 -6
- data/lib/tapioca/static/symbol_loader.rb +14 -16
- data/lib/tapioca/static/symbol_table_parser.rb +8 -8
- data/lib/tapioca/version.rb +1 -1
- data/lib/tapioca.rb +22 -29
- metadata +27 -10
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d003e839857cc260e7b1ab86fd4a48d93efc53e4a43ac9ccac6c85d9a89e63a1
|
|
4
|
+
data.tar.gz: 900f2d0369802b0fac34f60c04e3c238cd68e439c1d6d60f4b9ed5d8c82770f0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz: '
|
|
6
|
+
metadata.gz: b2f68a283b2499203877730fb5f981ed1e6c09c686a6c3e59297bea18361b5dd2d1831581f7b3edce6cf38936819544feeeebe59b1747520738542b0ae606ffe
|
|
7
|
+
data.tar.gz: '09769a8ab2aac1763cadecd013c9979c58d750c052f94c26eccfcbbd0a7ca07e0cb027c18e3737e90b90e85d4bebfca2fb4e8e559fdd9c4a0dd472ce5e59ee77'
|
data/README.md
CHANGED
|
@@ -52,6 +52,9 @@ Tapioca makes it easy to work with [Sorbet](https://sorbet.org) in your codebase
|
|
|
52
52
|
* [Writing custom DSL extensions](#writing-custom-dsl-extensions)
|
|
53
53
|
* [RBI files for missing constants and methods](#rbi-files-for-missing-constants-and-methods)
|
|
54
54
|
* [Configuration](#configuration)
|
|
55
|
+
* [Editor Integration](#editor-integration)
|
|
56
|
+
* [Setup](#setup)
|
|
57
|
+
* [Features](#features)
|
|
55
58
|
* [Contributing](#contributing)
|
|
56
59
|
* [DSL compilers](#dsl-compilers)
|
|
57
60
|
* [License](#license)
|
|
@@ -395,6 +398,12 @@ Tapioca also supports pulling annotations from multiple sources:
|
|
|
395
398
|
$ bin/tapioca annotations --sources https://raw.githubusercontent.com/$USER/$REPO1/$BRANCH https://raw.githubusercontent.com/$USER/$REPO2/$BRANCH
|
|
396
399
|
```
|
|
397
400
|
|
|
401
|
+
You can also specify a local directory path to pull annotations from
|
|
402
|
+
|
|
403
|
+
```shell
|
|
404
|
+
$ bin/tapioca annotations --sources path/to/folder
|
|
405
|
+
```
|
|
406
|
+
|
|
398
407
|
#### Basic authentication
|
|
399
408
|
|
|
400
409
|
Private repositories can be used as sources by passing the option `--auth` with an authentication string. For Github, this string is `token $TOKEN` where `$TOKEN` is a [personal access token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token):
|
|
@@ -993,6 +1002,18 @@ annotations:
|
|
|
993
1002
|
```
|
|
994
1003
|
<!-- END_CONFIG_TEMPLATE -->
|
|
995
1004
|
|
|
1005
|
+
## Editor Integration
|
|
1006
|
+
|
|
1007
|
+
### Setup
|
|
1008
|
+
|
|
1009
|
+
Tapioca supports generating RBIs upon file changes through the [Ruby LSP's add-on system](https://shopify.github.io/ruby-lsp/#add-ons). It's enabled by default on VS Code using [Ruby LSP](https://shopify.github.io/ruby-lsp/#usage), and you can enable it for other editors by supplying the `enabledFeatureFlags` option in LSP configuration with a hash value of `"tapiocaAddon": true`.
|
|
1010
|
+
|
|
1011
|
+
If you'd like to disable the Tapioca add-on you can set `tapiocaAddon` to `false` in your LSP configuration. For VS Code this looks like `"rubyLsp.featureFlags": { "tapiocaAddon": false }` in your `settings.json`.
|
|
1012
|
+
|
|
1013
|
+
### Features
|
|
1014
|
+
- DSL RBI generation: When editing a Ruby file, Tapioca will execute `bin/tapioca dsl` with the constants found in your file, e.g. `bin/tapioca dsl MyClass`
|
|
1015
|
+
- Gem RBI generation: When changes are made to `Gemfile.lock`, Tapioca will execute `bin/tapioca gem` with the updated gem names, e.g. `bin/tapioca gem my_gem`
|
|
1016
|
+
|
|
996
1017
|
## Contributing
|
|
997
1018
|
|
|
998
1019
|
Bug reports and pull requests are welcome on GitHub at https://github.com/Shopify/tapioca. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](https://github.com/Shopify/tapioca/blob/main/CODE_OF_CONDUCT.md) code of conduct.
|
data/exe/tapioca
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# typed: strict
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
-
RubyLsp::Addon.depend_on_ruby_lsp!(">= 0.23.
|
|
4
|
+
RubyLsp::Addon.depend_on_ruby_lsp!(">= 0.23.10", "< 0.27")
|
|
5
5
|
|
|
6
6
|
begin
|
|
7
7
|
# The Tapioca add-on depends on the Rails add-on to add a runtime component to the runtime server. We can allow the
|
|
@@ -18,21 +18,20 @@ require "ruby_lsp/tapioca/run_gem_rbi_check"
|
|
|
18
18
|
module RubyLsp
|
|
19
19
|
module Tapioca
|
|
20
20
|
class Addon < ::RubyLsp::Addon
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
sig { void }
|
|
21
|
+
#: -> void
|
|
24
22
|
def initialize
|
|
25
23
|
super
|
|
26
24
|
|
|
27
|
-
@global_state =
|
|
28
|
-
@rails_runner_client =
|
|
29
|
-
@index =
|
|
30
|
-
@file_checksums =
|
|
31
|
-
@lockfile_diff =
|
|
32
|
-
@outgoing_queue =
|
|
25
|
+
@global_state = nil #: RubyLsp::GlobalState?
|
|
26
|
+
@rails_runner_client = Rails::NullClient.new #: RubyLsp::Rails::RunnerClient
|
|
27
|
+
@index = nil #: RubyIndexer::Index?
|
|
28
|
+
@file_checksums = {} #: Hash[String, String]
|
|
29
|
+
@lockfile_diff = nil #: String?
|
|
30
|
+
@outgoing_queue = nil #: Thread::Queue?
|
|
33
31
|
end
|
|
34
32
|
|
|
35
|
-
|
|
33
|
+
# @override
|
|
34
|
+
#: (RubyLsp::GlobalState global_state, Thread::Queue outgoing_queue) -> void
|
|
36
35
|
def activate(global_state, outgoing_queue)
|
|
37
36
|
@global_state = global_state
|
|
38
37
|
return unless @global_state.enabled_feature?(:tapiocaAddon)
|
|
@@ -43,7 +42,7 @@ module RubyLsp
|
|
|
43
42
|
# Get a handle to the Rails add-on's runtime client. The call to `rails_runner_client` will block this thread
|
|
44
43
|
# until the server has finished booting, but it will not block the main LSP. This has to happen inside of a
|
|
45
44
|
# thread
|
|
46
|
-
addon =
|
|
45
|
+
addon = ::RubyLsp::Addon.get("Ruby LSP Rails", ">= 0.4.0", "< 0.5") #: as ::RubyLsp::Rails::Addon
|
|
47
46
|
@rails_runner_client = addon.rails_runner_client
|
|
48
47
|
@outgoing_queue << Notification.window_log_message("Activating Tapioca add-on v#{version}")
|
|
49
48
|
@rails_runner_client.register_server_addon(File.expand_path("server_addon.rb", __dir__))
|
|
@@ -53,8 +52,11 @@ module RubyLsp
|
|
|
53
52
|
workspace_path: @global_state.workspace_path,
|
|
54
53
|
)
|
|
55
54
|
|
|
55
|
+
send_usage_telemetry("activated")
|
|
56
56
|
run_gem_rbi_check
|
|
57
57
|
rescue IncompatibleApiError
|
|
58
|
+
send_usage_telemetry("incompatible_api_error")
|
|
59
|
+
|
|
58
60
|
# The requested version for the Rails add-on no longer matches. We need to upgrade and fix the breaking
|
|
59
61
|
# changes
|
|
60
62
|
@outgoing_queue << Notification.window_log_message(
|
|
@@ -64,36 +66,39 @@ module RubyLsp
|
|
|
64
66
|
end
|
|
65
67
|
end
|
|
66
68
|
|
|
67
|
-
|
|
69
|
+
# @override
|
|
70
|
+
#: -> void
|
|
68
71
|
def deactivate
|
|
69
72
|
end
|
|
70
73
|
|
|
71
|
-
|
|
74
|
+
# @override
|
|
75
|
+
#: -> String
|
|
72
76
|
def name
|
|
73
77
|
"Tapioca"
|
|
74
78
|
end
|
|
75
79
|
|
|
76
|
-
|
|
80
|
+
# @override
|
|
81
|
+
#: -> String
|
|
77
82
|
def version
|
|
78
|
-
"0.1.
|
|
83
|
+
"0.1.3"
|
|
79
84
|
end
|
|
80
85
|
|
|
81
|
-
|
|
86
|
+
#: (Array[{uri: String, type: Integer}] changes) -> void
|
|
82
87
|
def workspace_did_change_watched_files(changes)
|
|
83
|
-
return unless
|
|
88
|
+
return unless @global_state&.enabled_feature?(:tapiocaAddon)
|
|
84
89
|
return unless @rails_runner_client.connected?
|
|
85
90
|
|
|
86
|
-
has_route_change =
|
|
87
|
-
has_fixtures_change =
|
|
88
|
-
needs_compiler_reload =
|
|
91
|
+
has_route_change = false #: bool
|
|
92
|
+
has_fixtures_change = false #: bool
|
|
93
|
+
needs_compiler_reload = false #: bool
|
|
94
|
+
index = @index #: as !nil
|
|
89
95
|
|
|
90
96
|
constants = changes.flat_map do |change|
|
|
91
|
-
path = URI(change[:uri]).to_standardized_path
|
|
92
|
-
next
|
|
93
|
-
next unless file_updated?(change, path)
|
|
97
|
+
path = URI(change[:uri]).to_standardized_path #: String?
|
|
98
|
+
next unless path && file_updated?(change, path)
|
|
94
99
|
|
|
95
|
-
if File.fnmatch
|
|
96
|
-
|
|
100
|
+
if File.fnmatch("**/fixtures/**/*.yml{,.erb}", path, File::FNM_PATHNAME | File::FNM_EXTGLOB)
|
|
101
|
+
has_fixtures_change = true
|
|
97
102
|
next
|
|
98
103
|
end
|
|
99
104
|
|
|
@@ -102,13 +107,14 @@ module RubyLsp
|
|
|
102
107
|
next
|
|
103
108
|
end
|
|
104
109
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
110
|
+
next if File.fnmatch?("**/{test,spec,features}/**/*", path, File::FNM_PATHNAME | File::FNM_EXTGLOB)
|
|
111
|
+
|
|
112
|
+
if File.fnmatch?("**/tapioca/**/compilers/**/*.rb", path, File::FNM_PATHNAME)
|
|
113
|
+
needs_compiler_reload = true
|
|
108
114
|
next
|
|
109
115
|
end
|
|
110
116
|
|
|
111
|
-
entries =
|
|
117
|
+
entries = index.entries_for(change[:uri])
|
|
112
118
|
next unless entries
|
|
113
119
|
|
|
114
120
|
entries.filter_map do |entry|
|
|
@@ -124,19 +130,22 @@ module RubyLsp
|
|
|
124
130
|
@rails_runner_client.delegate_notification(
|
|
125
131
|
server_addon_name: "Tapioca",
|
|
126
132
|
request_name: "reload_workspace_compilers",
|
|
127
|
-
workspace_path:
|
|
133
|
+
workspace_path: @global_state.workspace_path,
|
|
128
134
|
)
|
|
129
135
|
end
|
|
130
136
|
|
|
131
137
|
if has_route_change
|
|
138
|
+
send_usage_telemetry("route_dsl")
|
|
132
139
|
@rails_runner_client.delegate_notification(server_addon_name: "Tapioca", request_name: "route_dsl")
|
|
133
140
|
end
|
|
134
141
|
|
|
135
142
|
if has_fixtures_change
|
|
143
|
+
send_usage_telemetry("fixtures_dsl")
|
|
136
144
|
@rails_runner_client.delegate_notification(server_addon_name: "Tapioca", request_name: "fixtures_dsl")
|
|
137
145
|
end
|
|
138
146
|
|
|
139
147
|
if constants.any?
|
|
148
|
+
send_usage_telemetry("dsl")
|
|
140
149
|
@rails_runner_client.delegate_notification(
|
|
141
150
|
server_addon_name: "Tapioca",
|
|
142
151
|
request_name: "dsl",
|
|
@@ -147,8 +156,29 @@ module RubyLsp
|
|
|
147
156
|
|
|
148
157
|
private
|
|
149
158
|
|
|
150
|
-
|
|
159
|
+
#: (String feature_name) -> void
|
|
160
|
+
def send_usage_telemetry(feature_name)
|
|
161
|
+
return unless @outgoing_queue && @global_state
|
|
162
|
+
|
|
163
|
+
# Telemetry is not captured by default even if events are produced by the server
|
|
164
|
+
# See https://github.com/Shopify/ruby-lsp/tree/main/vscode#telemetry
|
|
165
|
+
@outgoing_queue << Notification.telemetry({
|
|
166
|
+
eventName: "tapioca_addon.feature_usage",
|
|
167
|
+
type: "data",
|
|
168
|
+
data: {
|
|
169
|
+
type: "counter",
|
|
170
|
+
attributes: {
|
|
171
|
+
label: feature_name,
|
|
172
|
+
machineId: @global_state.telemetry_machine_id,
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
})
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
#: (Hash[Symbol, untyped] change, String path) -> bool
|
|
151
179
|
def file_updated?(change, path)
|
|
180
|
+
queue = @outgoing_queue #: as !nil
|
|
181
|
+
|
|
152
182
|
case change[:type]
|
|
153
183
|
when Constant::FileChangeType::CREATED
|
|
154
184
|
@file_checksums[path] = Zlib.crc32(File.read(path)).to_s
|
|
@@ -156,7 +186,7 @@ module RubyLsp
|
|
|
156
186
|
when Constant::FileChangeType::CHANGED
|
|
157
187
|
current_checksum = Zlib.crc32(File.read(path)).to_s
|
|
158
188
|
if @file_checksums[path] == current_checksum
|
|
159
|
-
|
|
189
|
+
queue << Notification.window_log_message(
|
|
160
190
|
"File has not changed. Skipping #{path}",
|
|
161
191
|
type: Constant::MessageType::INFO,
|
|
162
192
|
)
|
|
@@ -167,7 +197,7 @@ module RubyLsp
|
|
|
167
197
|
when Constant::FileChangeType::DELETED
|
|
168
198
|
@file_checksums.delete(path)
|
|
169
199
|
else
|
|
170
|
-
|
|
200
|
+
queue << Notification.window_log_message(
|
|
171
201
|
"Unexpected file change type: #{change[:type]}",
|
|
172
202
|
type: Constant::MessageType::WARNING,
|
|
173
203
|
)
|
|
@@ -176,18 +206,18 @@ module RubyLsp
|
|
|
176
206
|
false
|
|
177
207
|
end
|
|
178
208
|
|
|
179
|
-
|
|
209
|
+
#: -> void
|
|
180
210
|
def run_gem_rbi_check
|
|
181
|
-
|
|
211
|
+
state = @global_state #: as !nil
|
|
212
|
+
gem_rbi_check = RunGemRbiCheck.new(state.workspace_path)
|
|
182
213
|
gem_rbi_check.run
|
|
183
214
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
gem_rbi_check.stderr,
|
|
189
|
-
|
|
190
|
-
) unless gem_rbi_check.stderr.empty?
|
|
215
|
+
queue = @outgoing_queue #: as !nil
|
|
216
|
+
queue << Notification.window_log_message(gem_rbi_check.stdout) unless gem_rbi_check.stdout.empty?
|
|
217
|
+
|
|
218
|
+
unless gem_rbi_check.stderr.empty?
|
|
219
|
+
queue << Notification.window_log_message(gem_rbi_check.stderr, type: Constant::MessageType::WARNING)
|
|
220
|
+
end
|
|
191
221
|
end
|
|
192
222
|
end
|
|
193
223
|
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# typed:
|
|
1
|
+
# typed: strict
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
require "open3"
|
|
@@ -7,21 +7,21 @@ require "ruby_lsp/tapioca/lockfile_diff_parser"
|
|
|
7
7
|
module RubyLsp
|
|
8
8
|
module Tapioca
|
|
9
9
|
class RunGemRbiCheck
|
|
10
|
-
|
|
10
|
+
#: String
|
|
11
|
+
attr_reader :stdout, :stderr
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
attr_reader :stderr
|
|
13
|
+
#: Process::Status?
|
|
14
14
|
attr_reader :status
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
#: (String project_path) -> void
|
|
17
17
|
def initialize(project_path)
|
|
18
18
|
@project_path = project_path
|
|
19
|
-
@stdout =
|
|
20
|
-
@stderr =
|
|
21
|
-
@status =
|
|
19
|
+
@stdout = "" #: String
|
|
20
|
+
@stderr = "" #: String
|
|
21
|
+
@status = nil #: Process::Status?
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
#: -> void
|
|
25
25
|
def run
|
|
26
26
|
return log_message("Not a git repository") unless git_repo?
|
|
27
27
|
|
|
@@ -34,37 +34,35 @@ module RubyLsp
|
|
|
34
34
|
|
|
35
35
|
private
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
sig { returns(T.nilable(T::Boolean)) }
|
|
37
|
+
#: -> bool?
|
|
40
38
|
def git_repo?
|
|
41
|
-
_, status = Open3.capture2e("git", "rev-parse", "--is-inside-work-tree", chdir: project_path)
|
|
39
|
+
_, status = Open3.capture2e("git", "rev-parse", "--is-inside-work-tree", chdir: @project_path)
|
|
42
40
|
status.success?
|
|
43
41
|
end
|
|
44
42
|
|
|
45
|
-
|
|
43
|
+
#: -> bool
|
|
46
44
|
def lockfile_changed?
|
|
47
45
|
!lockfile_diff.empty?
|
|
48
46
|
end
|
|
49
47
|
|
|
50
|
-
|
|
48
|
+
#: -> Pathname
|
|
51
49
|
def lockfile
|
|
52
|
-
@lockfile ||=
|
|
50
|
+
@lockfile ||= Pathname(@project_path).join("Gemfile.lock") #: Pathname?
|
|
53
51
|
end
|
|
54
52
|
|
|
55
|
-
|
|
53
|
+
#: -> String
|
|
56
54
|
def lockfile_diff
|
|
57
|
-
@lockfile_diff ||=
|
|
55
|
+
@lockfile_diff ||= read_lockfile_diff #: String?
|
|
58
56
|
end
|
|
59
57
|
|
|
60
|
-
|
|
58
|
+
#: -> String
|
|
61
59
|
def read_lockfile_diff
|
|
62
60
|
return "" unless lockfile.exist?
|
|
63
61
|
|
|
64
62
|
execute_in_project_path("git", "diff", lockfile.to_s).strip
|
|
65
63
|
end
|
|
66
64
|
|
|
67
|
-
|
|
65
|
+
#: -> void
|
|
68
66
|
def generate_gem_rbis
|
|
69
67
|
parser = Tapioca::LockfileDiffParser.new(@lockfile_diff)
|
|
70
68
|
removed_gems = parser.removed_gems
|
|
@@ -78,18 +76,19 @@ module RubyLsp
|
|
|
78
76
|
end
|
|
79
77
|
end
|
|
80
78
|
|
|
81
|
-
|
|
79
|
+
#: (Array[String] gems) -> void
|
|
82
80
|
def execute_tapioca_gem_command(gems)
|
|
83
81
|
Bundler.with_unbundled_env do
|
|
84
|
-
stdout, stderr, status =
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
82
|
+
stdout, stderr, status = Open3 #: as untyped
|
|
83
|
+
.capture3(
|
|
84
|
+
"bundle",
|
|
85
|
+
"exec",
|
|
86
|
+
"tapioca",
|
|
87
|
+
"gem",
|
|
88
|
+
"--lsp_addon",
|
|
89
|
+
*gems,
|
|
90
|
+
chdir: @project_path,
|
|
91
|
+
)
|
|
93
92
|
|
|
94
93
|
log_message(stdout) unless stdout.empty?
|
|
95
94
|
@stderr = stderr unless stderr.empty?
|
|
@@ -97,16 +96,16 @@ module RubyLsp
|
|
|
97
96
|
end
|
|
98
97
|
end
|
|
99
98
|
|
|
100
|
-
|
|
99
|
+
#: (Array[String] gems) -> void
|
|
101
100
|
def remove_rbis(gems)
|
|
102
101
|
files = Dir.glob(
|
|
103
102
|
"sorbet/rbi/gems/{#{gems.join(",")}}@*.rbi",
|
|
104
|
-
base: project_path,
|
|
103
|
+
base: @project_path,
|
|
105
104
|
)
|
|
106
105
|
delete_files(files, "Removed RBIs for")
|
|
107
106
|
end
|
|
108
107
|
|
|
109
|
-
|
|
108
|
+
#: -> void
|
|
110
109
|
def cleanup_orphaned_rbis
|
|
111
110
|
untracked_files = git_ls_gem_rbis("--others", "--exclude-standard")
|
|
112
111
|
deleted_files = git_ls_gem_rbis("--deleted")
|
|
@@ -115,37 +114,38 @@ module RubyLsp
|
|
|
115
114
|
restore_files(deleted_files, "Restored deleted RBIs")
|
|
116
115
|
end
|
|
117
116
|
|
|
118
|
-
|
|
117
|
+
#: (*untyped flags) -> Array[String]
|
|
119
118
|
def git_ls_gem_rbis(*flags)
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
execute_in_project_path(*flags)
|
|
119
|
+
self #: as untyped # rubocop:disable Style/RedundantSelf
|
|
120
|
+
.execute_in_project_path("git", "ls-files", *flags, "sorbet/rbi/gems/")
|
|
123
121
|
.lines
|
|
124
122
|
.map(&:strip)
|
|
125
123
|
end
|
|
126
124
|
|
|
127
|
-
|
|
125
|
+
#: (Array[String] files, String message) -> void
|
|
128
126
|
def delete_files(files, message)
|
|
129
|
-
files_to_remove = files.map { |file| File.join(project_path, file) }
|
|
127
|
+
files_to_remove = files.map { |file| File.join(@project_path, file) }
|
|
130
128
|
FileUtils.rm(files_to_remove)
|
|
131
129
|
log_message("#{message}: #{files.join(", ")}") unless files.empty?
|
|
132
130
|
end
|
|
133
131
|
|
|
134
|
-
|
|
132
|
+
#: (Array[String] files, String message) -> void
|
|
135
133
|
def restore_files(files, message)
|
|
136
134
|
execute_in_project_path("git", "checkout", "--pathspec-from-file=-", stdin: files.join("\n"))
|
|
137
135
|
log_message("#{message}: #{files.join(", ")}") unless files.empty?
|
|
138
136
|
end
|
|
139
137
|
|
|
140
|
-
|
|
138
|
+
#: (String message) -> void
|
|
141
139
|
def log_message(message)
|
|
142
140
|
@stdout += "#{message}\n"
|
|
143
141
|
end
|
|
144
142
|
|
|
143
|
+
#: (*String, ?stdin: String?) -> String
|
|
145
144
|
def execute_in_project_path(*parts, stdin: nil)
|
|
146
|
-
options = { chdir: project_path }
|
|
145
|
+
options = { chdir: @project_path }
|
|
147
146
|
options[:stdin_data] = stdin if stdin
|
|
148
|
-
stdout_and_stderr, _status =
|
|
147
|
+
stdout_and_stderr, _status = Open3 #: as untyped
|
|
148
|
+
.capture2e(*parts, options)
|
|
149
149
|
stdout_and_stderr
|
|
150
150
|
end
|
|
151
151
|
end
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
require "tapioca/internal"
|
|
5
|
-
require "tapioca/dsl/compilers/url_helpers"
|
|
6
|
-
require "tapioca/dsl/compilers/active_record_fixtures"
|
|
7
5
|
|
|
8
6
|
module RubyLsp
|
|
9
7
|
module Tapioca
|
|
@@ -21,13 +19,16 @@ module RubyLsp
|
|
|
21
19
|
when "load_compilers_and_extensions"
|
|
22
20
|
# Load DSL extensions and compilers ahead of time, so that we don't have to pay the price of invoking
|
|
23
21
|
# `Gem.find_files` on every execution, which is quite expensive
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
22
|
+
with_notification_wrapper("load_compilers_and_extensions", "Loading DSL compilers") do
|
|
23
|
+
::Tapioca::Dsl::Compiler.extend(T::Generic)
|
|
24
|
+
@loader = ::Tapioca::Loaders::Dsl.new(
|
|
25
|
+
tapioca_path: ::Tapioca::TAPIOCA_DIR,
|
|
26
|
+
eager_load: false,
|
|
27
|
+
app_root: params[:workspace_path],
|
|
28
|
+
halt_upon_load_error: false,
|
|
29
|
+
)
|
|
30
|
+
@loader.load_dsl_extensions_and_compilers
|
|
31
|
+
end
|
|
31
32
|
when "dsl"
|
|
32
33
|
fork do
|
|
33
34
|
with_notification_wrapper("dsl", "Generating DSL RBIs") do
|
|
@@ -62,11 +63,13 @@ module RubyLsp
|
|
|
62
63
|
def dsl(constants, *args)
|
|
63
64
|
load("tapioca/cli.rb") # Reload the CLI to reset thor defaults between requests
|
|
64
65
|
|
|
66
|
+
::Tapioca::Cli.addon_mode!
|
|
67
|
+
|
|
65
68
|
# Order here is important to avoid having Thor confuse arguments. Do not put an array argument at the end before
|
|
66
69
|
# the list of constants
|
|
67
70
|
arguments = ["dsl"]
|
|
68
71
|
arguments.concat(args)
|
|
69
|
-
arguments.push("--
|
|
72
|
+
arguments.push("--workers=1")
|
|
70
73
|
arguments.concat(constants)
|
|
71
74
|
|
|
72
75
|
::Tapioca::Cli.start(arguments)
|
|
@@ -6,19 +6,16 @@ module Tapioca
|
|
|
6
6
|
# This is a module that gets prepended to `Bundler::Dependency` and
|
|
7
7
|
# makes sure even gems marked as `require: false` are required during
|
|
8
8
|
# `Bundler.require`.
|
|
9
|
+
# @requires_ancestor: ::Bundler::Dependency
|
|
9
10
|
module AutoRequireHook
|
|
10
11
|
extend T::Sig
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
requires_ancestor { ::Bundler::Dependency }
|
|
14
|
-
|
|
15
|
-
@exclude = T.let([], T::Array[String])
|
|
16
|
-
@enabled = T.let(false, T::Boolean)
|
|
12
|
+
@exclude = [] #: Array[String]
|
|
13
|
+
@enabled = false #: bool
|
|
17
14
|
|
|
18
15
|
class << self
|
|
19
16
|
extend T::Sig
|
|
20
17
|
|
|
21
|
-
|
|
18
|
+
#: (untyped name) -> bool
|
|
22
19
|
def excluded?(name)
|
|
23
20
|
@exclude.include?(name)
|
|
24
21
|
end
|
|
@@ -27,12 +24,7 @@ module Tapioca
|
|
|
27
24
|
@enabled
|
|
28
25
|
end
|
|
29
26
|
|
|
30
|
-
|
|
31
|
-
type_parameters(:Result).params(
|
|
32
|
-
exclude: T::Array[String],
|
|
33
|
-
blk: T.proc.returns(T.type_parameter(:Result)),
|
|
34
|
-
).returns(T.type_parameter(:Result))
|
|
35
|
-
end
|
|
27
|
+
#: [Result] (exclude: Array[String]) { -> Result } -> Result
|
|
36
28
|
def override_require_false(exclude:, &blk)
|
|
37
29
|
@enabled = true
|
|
38
30
|
@exclude = exclude
|
|
@@ -42,7 +34,7 @@ module Tapioca
|
|
|
42
34
|
end
|
|
43
35
|
end
|
|
44
36
|
|
|
45
|
-
|
|
37
|
+
#: -> untyped
|
|
46
38
|
def autorequire
|
|
47
39
|
value = super
|
|
48
40
|
|
data/lib/tapioca/cli.rb
CHANGED
|
@@ -143,11 +143,6 @@ module Tapioca
|
|
|
143
143
|
type: :hash,
|
|
144
144
|
desc: "Options to pass to the DSL compilers",
|
|
145
145
|
default: {}
|
|
146
|
-
option :lsp_addon,
|
|
147
|
-
type: :boolean,
|
|
148
|
-
desc: "Generate DSL RBIs from the LSP add-on. Internal to Tapioca and not intended for end-users",
|
|
149
|
-
default: false,
|
|
150
|
-
hide: true
|
|
151
146
|
def dsl(*constant_or_paths)
|
|
152
147
|
set_environment(options)
|
|
153
148
|
|
|
@@ -170,7 +165,7 @@ module Tapioca
|
|
|
170
165
|
app_root: options[:app_root],
|
|
171
166
|
halt_upon_load_error: options[:halt_upon_load_error],
|
|
172
167
|
compiler_options: options[:compiler_options],
|
|
173
|
-
lsp_addon:
|
|
168
|
+
lsp_addon: self.class.addon_mode,
|
|
174
169
|
}
|
|
175
170
|
|
|
176
171
|
command = if options[:verify]
|
|
@@ -358,7 +353,7 @@ module Tapioca
|
|
|
358
353
|
default: {}
|
|
359
354
|
def annotations
|
|
360
355
|
if !options[:netrc] && options[:netrc_file]
|
|
361
|
-
raise
|
|
356
|
+
raise Tapioca::Error, set_color("Options `--no-netrc` and `--netrc-file` can't be used together", :bold, :red)
|
|
362
357
|
end
|
|
363
358
|
|
|
364
359
|
command = Commands::Annotations.new(
|
|
@@ -379,9 +374,22 @@ module Tapioca
|
|
|
379
374
|
end
|
|
380
375
|
|
|
381
376
|
no_commands do
|
|
377
|
+
@addon_mode = false
|
|
378
|
+
|
|
382
379
|
class << self
|
|
380
|
+
extend T::Sig
|
|
381
|
+
|
|
382
|
+
# Indicates that we are running from the LSP, set using the `addon_mode!` method
|
|
383
|
+
attr_reader :addon_mode
|
|
384
|
+
|
|
385
|
+
#: -> void
|
|
386
|
+
def addon_mode!
|
|
387
|
+
@addon_mode = true
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
#: -> bool
|
|
383
391
|
def exit_on_failure?
|
|
384
|
-
|
|
392
|
+
!@addon_mode
|
|
385
393
|
end
|
|
386
394
|
end
|
|
387
395
|
end
|