Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions lib/tapioca/dsl/pipeline.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ def run(&blk)

# It's OK if there are no constants to process if we received a valid file/path.
if constants_to_process.empty? && requested_paths.none? { |p| File.exist?(p) }
# When running within the add-on, return early so this expected case is not logged as an error
return [] if @lsp_addon

report_error(<<~ERROR)
No classes/modules can be matched for RBI generation.
Please check that the requested classes/modules include processable DSL methods.
Expand Down
5 changes: 5 additions & 0 deletions spec/dummy/app/models/foo.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# frozen_string_literal: true

# Plain class with no processable DSL methods, used by addon_spec.
class Foo
end
57 changes: 56 additions & 1 deletion spec/tapioca/addon_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,25 @@ class AddonSpec < Minitest::HooksSpec
FileUtils.rm_rf("spec/dummy/sorbet/rbi")
end

it "does not error when a constant has no processable DSL" do
create_client(supports_progress: true)

@client.delegate_notification(
server_addon_name: "Tapioca",
request_name: "dsl",
constants: ["Foo"],
)

messages = wait_for_dsl_completion

shutdown_client

assert_empty(messages.select { |message| error_message?(message) })
refute_path_exists("spec/dummy/sorbet/rbi/dsl/foo.rbi")
ensure
FileUtils.rm_rf("spec/dummy/sorbet/rbi")
end

it "triggers route DSL generation if routes.rb is modified" do
create_client

Expand Down Expand Up @@ -150,9 +169,12 @@ def decorate
private

# Starts a new client
def create_client
def create_client(supports_progress: false)
@outgoing_queue = Thread::Queue.new
global_state = GlobalState.new
if supports_progress
global_state.apply_options(capabilities: { window: { workDoneProgress: true } })
end
@client = FileUtils.chdir("spec/dummy") do
RubyLsp::Rails::RunnerClient.new(@outgoing_queue, global_state)
end
Expand Down Expand Up @@ -182,6 +204,39 @@ def wait_until_exists(path)
rescue Timeout::Error
flunk("#{path} was not created in time")
end

def wait_for_dsl_completion(token: "dsl")
messages = []
Timeout.timeout(10) do
loop do
notification = @outgoing_queue.pop
messages << notification
break if dsl_progress_end?(notification, token)
end
end
messages
rescue Timeout::Error
flunk("dsl request for #{token} did not complete in time")
end

def dsl_progress_end?(notification, token)
return false unless notification.is_a?(Hash)

params = notification[:params]
return false unless params

params[:token] == token && params.dig(:value, :kind) == "end"
end

def error_message?(notification)
message = if notification.is_a?(Hash)
notification.dig(:params, :message).to_s
else
notification.params&.message.to_s
end

message.include?("Tapioca::Error") || message.include?("failed with StandardError")
end
end
end
end
Loading