Skip to content

Commit 0189305

Browse files
committed
Use Prism in Sorbet calls, if enabled
1 parent c4d0590 commit 0189305

3 files changed

Lines changed: 133 additions & 4 deletions

File tree

lib/tapioca/helpers/sorbet_helper.rb

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,24 +13,81 @@ module SorbetHelper
1313

1414
SPOOM_CONTEXT = Spoom::Context.new(".") #: Spoom::Context
1515

16+
# Represents the `sorbet/config` file, and provides access to its options. https://sorbet.org/docs/cli-ref
17+
# If the file doesn't exist, this object will still exist, but will return default values for all options.
18+
class SorbetConfig
19+
class << self
20+
#: (Spoom::Context spoom_context) -> SorbetConfig
21+
def parse_from(spoom_context)
22+
config_path = File.join(spoom_context.absolute_path, "sorbet", "config")
23+
content = File.exist?(config_path) ? File.read(config_path) : ""
24+
parse(content)
25+
end
26+
27+
#: (String content) -> SorbetConfig
28+
def parse(content)
29+
lines = content.lines.map(&:strip).reject(&:empty?)
30+
31+
options = lines.filter_map do |line|
32+
next if line.start_with?("#") # Skip comments
33+
next unless line.start_with?("--")
34+
35+
key, value = line.split("=", 2)
36+
key = key #: as !nil
37+
38+
[key, value]
39+
end.to_h #: Hash[String, String | bool | nil]
40+
41+
new(
42+
parser: options["--parser"] == "prism" ? :prism : :original,
43+
)
44+
end
45+
end
46+
47+
#: (parser: Symbol) -> void
48+
def initialize(parser:)
49+
@parser = parser #: Symbol
50+
end
51+
52+
#: Symbol
53+
attr_reader :parser
54+
55+
#: -> bool
56+
def parse_with_prism? = @parser == :prism
57+
end
58+
1659
FEATURE_REQUIREMENTS = {
1760
# feature_name: ::Gem::Requirement.new(">= ___"), # https://github.com/sorbet/sorbet/pull/___
61+
62+
prism_syntax_check_with_stop_after_parser: ::Gem::Requirement.new("> 0.6.13073"), # https://github.com/sorbet/sorbet/pull/10076
1863
}.freeze #: Hash[Symbol, ::Gem::Requirement]
1964

2065
#: (*String sorbet_args) -> Spoom::ExecResult
2166
def sorbet(*sorbet_args)
67+
if sorbet_config.parse_with_prism?
68+
sorbet_args << "--parser=prism"
69+
end
70+
2271
SPOOM_CONTEXT.srb(sorbet_args.join(" "), sorbet_bin: sorbet_path)
2372
end
2473

2574
#: (String, rbi_mode: bool) { (String stderr) -> void } -> void
2675
def sorbet_syntax_check!(source, rbi_mode:, &on_failure)
2776
quoted_source = "\"#{source}\""
2877

78+
stop_after = "--stop-after=parser"
79+
80+
# This version of Sorbet doesn't report parse errors until the desugarer, so we need to modify the
81+
# stop-after argument to get far enough to get those errors (and a non-zero exit code).
82+
if sorbet_config.parse_with_prism? && !sorbet_supports?(:prism_syntax_check_with_stop_after_parser)
83+
stop_after = "--stop-after=desugarer"
84+
end
85+
2986
result = if rbi_mode
3087
# --e-rbi cannot be used on its own, so we pass a dummy value like `-e ""`
31-
sorbet("--no-config", "--stop-after=parser", "-e", '""', "--e-rbi", quoted_source)
88+
sorbet("--no-config", stop_after, "-e", '""', "--e-rbi", quoted_source)
3289
else
33-
sorbet("--no-config", "--stop-after=parser", "-e", quoted_source)
90+
sorbet("--no-config", stop_after, "-e", quoted_source)
3491
end
3592

3693
unless result.status
@@ -41,6 +98,11 @@ def sorbet_syntax_check!(source, rbi_mode:, &on_failure)
4198
nil
4299
end
43100

101+
#: -> SorbetConfig
102+
def sorbet_config
103+
@sorbet_config ||= SorbetConfig.parse_from(SPOOM_CONTEXT) #: SorbetConfig?
104+
end
105+
44106
#: -> String
45107
def sorbet_path
46108
sorbet_path = ENV.fetch(SORBET_EXE_PATH_ENV_VAR, SORBET_BIN)

spec/tapioca/dsl/compiler_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ def foo(d:, e: 42, **f, &blk); end
222222

223223
e = assert_raises(SyntaxError) { rbi_for(:Post) }
224224

225-
assert_match('unexpected token ")"', e.message)
225+
assert_match("unexpected ')'", e.message)
226226
assert_match("sig { returns(void)) }", e.message)
227227
end
228228
end

spec/tapioca/helpers/sorbet_helper_spec.rb

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,74 @@ class Tapioca::SorbetHelperSpec < Minitest::Spec
3434
end
3535
end
3636

37-
private
37+
describe Tapioca::SorbetHelper::SorbetConfig do
38+
it "ignores comment lines" do
39+
config = parse(<<~CONFIG)
40+
# --parser=prism
41+
CONFIG
42+
assert_equal(:original, config.parser)
43+
end
44+
45+
it "ignores blank lines" do
46+
config = parse(<<~CONFIG)
47+
48+
--parser=prism
49+
50+
CONFIG
51+
assert_equal(:prism, config.parser)
52+
end
53+
54+
it "ignores lines without -- prefix" do
55+
config = parse(<<~CONFIG)
56+
.
57+
src/
58+
--parser=prism
59+
CONFIG
60+
assert_equal(:prism, config.parser)
61+
end
62+
63+
describe "--parser" do
64+
it "detects --parser=prism" do
65+
config = parse(<<~CONFIG)
66+
.
67+
--parser=prism
68+
CONFIG
69+
assert_equal(:prism, config.parser)
70+
assert_predicate(config, :parse_with_prism?)
71+
end
72+
73+
it "defaults to :original for empty config" do
74+
config = parse("")
75+
assert_equal(:original, config.parser)
76+
refute_predicate(config, :parse_with_prism?)
77+
end
78+
79+
it "defaults to :original when no --parser option" do
80+
config = parse(<<~CONFIG)
81+
.
82+
--dir=foo
83+
CONFIG
84+
assert_equal(:original, config.parser)
85+
end
86+
87+
it "treats non-prism values as :original" do
88+
config = parse(<<~CONFIG)
89+
.
90+
--parser=original
91+
CONFIG
92+
assert_equal(:original, config.parser)
93+
refute_predicate(config, :parse_with_prism?)
94+
end
95+
end
96+
97+
private
98+
99+
#: (String content) -> Tapioca::SorbetHelper::SorbetConfig
100+
def parse(content) = Tapioca::SorbetHelper::SorbetConfig.parse(content)
101+
end
102+
103+
# Rubocop thinks the `private` call above (in the `describe` block) still applies here. It doesn't.
104+
private # rubocop:disable Lint/UselessAccessModifier
38105

39106
#: (String? path) { (String? custom_path) -> void } -> void
40107
def with_custom_sorbet_exe_path(path, &block)

0 commit comments

Comments
 (0)