steep 0.45.0 → 0.46.0

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 (60) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +1 -0
  3. data/CHANGELOG.md +17 -2
  4. data/Gemfile.lock +2 -2
  5. data/lib/steep/cli.rb +7 -1
  6. data/lib/steep/diagnostic/lsp_formatter.rb +59 -6
  7. data/lib/steep/diagnostic/ruby.rb +51 -0
  8. data/lib/steep/drivers/check.rb +3 -0
  9. data/lib/steep/drivers/init.rb +10 -3
  10. data/lib/steep/drivers/utils/driver_helper.rb +15 -0
  11. data/lib/steep/drivers/validate.rb +1 -1
  12. data/lib/steep/drivers/watch.rb +3 -0
  13. data/lib/steep/project/dsl.rb +105 -33
  14. data/lib/steep/project/options.rb +12 -53
  15. data/lib/steep/project/target.rb +21 -8
  16. data/lib/steep/server/type_check_worker.rb +6 -9
  17. data/lib/steep/services/hover_content.rb +2 -2
  18. data/lib/steep/version.rb +1 -1
  19. data/sample/Steepfile +10 -3
  20. data/smoke/alias/Steepfile +2 -1
  21. data/smoke/and/Steepfile +2 -1
  22. data/smoke/array/Steepfile +2 -1
  23. data/smoke/block/Steepfile +2 -2
  24. data/smoke/case/Steepfile +2 -1
  25. data/smoke/class/Steepfile +2 -1
  26. data/smoke/const/Steepfile +2 -1
  27. data/smoke/diagnostics/Steepfile +2 -1
  28. data/smoke/diagnostics-rbs/Steepfile +1 -1
  29. data/smoke/diagnostics-rbs-duplicated/Steepfile +2 -1
  30. data/smoke/diagnostics-ruby-unsat/Steepfile +2 -1
  31. data/smoke/dstr/Steepfile +2 -1
  32. data/smoke/ensure/Steepfile +2 -1
  33. data/smoke/enumerator/Steepfile +2 -1
  34. data/smoke/extension/Steepfile +2 -1
  35. data/smoke/hash/Steepfile +2 -1
  36. data/smoke/hello/Steepfile +2 -1
  37. data/smoke/if/Steepfile +2 -1
  38. data/smoke/implements/Steepfile +2 -1
  39. data/smoke/initialize/Steepfile +2 -1
  40. data/smoke/integer/Steepfile +2 -1
  41. data/smoke/interface/Steepfile +2 -1
  42. data/smoke/kwbegin/Steepfile +2 -1
  43. data/smoke/lambda/Steepfile +2 -1
  44. data/smoke/literal/Steepfile +2 -1
  45. data/smoke/map/Steepfile +2 -1
  46. data/smoke/method/Steepfile +2 -1
  47. data/smoke/module/Steepfile +2 -1
  48. data/smoke/regexp/Steepfile +2 -1
  49. data/smoke/regression/Steepfile +2 -1
  50. data/smoke/rescue/Steepfile +2 -1
  51. data/smoke/self/Steepfile +2 -1
  52. data/smoke/skip/Steepfile +2 -1
  53. data/smoke/stdout/Steepfile +2 -1
  54. data/smoke/super/Steepfile +2 -1
  55. data/smoke/toplevel/Steepfile +2 -1
  56. data/smoke/tsort/Steepfile +4 -5
  57. data/smoke/type_case/Steepfile +2 -1
  58. data/smoke/unexpected/Steepfile +2 -1
  59. data/smoke/yield/Steepfile +2 -1
  60. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '080cf1692f90640baacc712908524e2daf36039ea992eb3424de7094c49f6778'
4
- data.tar.gz: dd9f8837ec50e625ce9a0814fcbef03191bf484debd33034f9d00819115fef81
3
+ metadata.gz: e43c16938ef0238a9b3e44934a3e183ec663722b4c1161f9bd016dfcd2442b9b
4
+ data.tar.gz: 20168ebc69417b83c9eff010d44aac53ac43f47c572c8acc99d52d08ec11866d
5
5
  SHA512:
6
- metadata.gz: 67d26f6197f5b4fe53195c2202cdbbf556e2496fda4498151646c6d93a8455de0b75af66c35b16f32375fc239574600e33cc5f8caf92cc8f96a659ca0588b4da
7
- data.tar.gz: 718c99448377245e8e0871af93c445d037aef4dbc727185bfd658f49672c08a11e8acc3807c7cb2a55814ffd32fb87642c9b37fc9f17143d4474a2810e2e4f3e
6
+ metadata.gz: 33c2bd116ea87f549ffb29fbc2382e7c000405a74280fcc4a1a8553ae52e6b7af3d5611a150c828d494fe50f37e120e58e45f286bd374bbd35958ee0c760c872
7
+ data.tar.gz: 0466f3f59d18bf0ba34ce522bc6a1cceed85c1f6ca4df66b6647a557bec165c64dd9d594f673833dc24a0b5a9d0eb04795bff37dc391e22cf560b566c6f08319
@@ -15,6 +15,7 @@ jobs:
15
15
  - "2.6"
16
16
  - "2.7"
17
17
  - "3.0"
18
+ - "master-nightly-focal"
18
19
  task:
19
20
  - test
20
21
  - test:output
data/CHANGELOG.md CHANGED
@@ -2,17 +2,32 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## 0.46.0 (2021-08-30)
6
+
7
+ This release updates Steepfile DSL syntax, introducing `stdlib_path` and `configure_code_diagnostics` syntax (methods).
8
+
9
+ * `stdlib_path` allows configuring core/stdlib RBS file locations.
10
+ * `configure_code_diagnostics` allows configuring _severity_ of each type errors.
11
+
12
+ See the PRs for the explanation of these methods.
13
+ You can try `steep init` to generate updated `Steepfile` template.
14
+
15
+ * Flexible diagnostics configuration ([\#422](https://github.com/soutaro/steep/pull/422), [\#423](https://github.com/soutaro/steep/pull/423))
16
+ * Revise Steepfile _path_ DSL ([\#421](https://github.com/soutaro/steep/pull/421))
17
+ * Avoid to stop process by invalid jobs_count ([\#419](https://github.com/soutaro/steep/pull/419))
18
+ * Fix `Steep::Typing::UnknownNodeError` when hover method with numblock ([\#415](https://github.com/soutaro/steep/pull/415))
19
+
5
20
  ## 0.45.0 (2021-08-22)
6
21
 
7
22
  * Fix error reporting on `RBS::MixinClassError` ([\#411](https://github.com/soutaro/steep/pull/411))
8
23
  * Compact error reporting for method body type mismatch ([\#414](https://github.com/soutaro/steep/pull/414))
9
24
  * Fix NoMethodError with csend/numblock ([\#412](https://github.com/soutaro/steep/pull/412))
10
- * LSP completion for RBS files ([\#404](https://github.com/soutaro/steep/pull/404))
25
+ * LSP completion for RBS files ([\#404](https://github.com/soutaro/steep/pull/404))
11
26
  * Allow break without value from bot methods ([\#398](https://github.com/soutaro/steep/pull/398))
12
27
  * Type check on lvar assignments ([\#390](https://github.com/soutaro/steep/pull/390))
13
28
  * Assign different error code to break without value ([\#387](https://github.com/soutaro/steep/pull/387))
14
29
  * Support Ruby3 Keyword Arguments ([\#386](https://github.com/soutaro/steep/pull/386))
15
- * LSP hover for RBS files ([\#385](https://github.com/soutaro/steep/pull/385), [\#397](https://github.com/soutaro/steep/pull/397))
30
+ * LSP hover for RBS files ([\#385](https://github.com/soutaro/steep/pull/385), [\#397](https://github.com/soutaro/steep/pull/397))
16
31
  * Fix FileLoader to skip files not matching to the given pattern ([\#382](https://github.com/soutaro/steep/pull/382))
17
32
  * Ruby3 support for numbered block parameters and end-less def ([\#381](https://github.com/soutaro/steep/pull/381))
18
33
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- steep (0.45.0)
4
+ steep (0.46.0)
5
5
  activesupport (>= 5.1)
6
6
  language_server-protocol (>= 3.15, < 4.0)
7
7
  listen (~> 3.0)
@@ -35,7 +35,7 @@ GEM
35
35
  ffi (1.15.3)
36
36
  i18n (1.8.10)
37
37
  concurrent-ruby (~> 1.0)
38
- language_server-protocol (3.16.0.1)
38
+ language_server-protocol (3.16.0.2)
39
39
  listen (3.7.0)
40
40
  rb-fsevent (~> 0.10, >= 0.10.3)
41
41
  rb-inotify (~> 0.9, >= 0.9.10)
data/lib/steep/cli.rb CHANGED
@@ -70,7 +70,7 @@ module Steep
70
70
  default = physical_processor_count + modifier
71
71
  command.jobs_count = default
72
72
  opts.on("-j N", "--jobs=N", "Specify the number of type check workers (defaults: #{default})") do |count|
73
- command.jobs_count = Integer(count)
73
+ command.jobs_count = Integer(count) if Integer(count) > 0
74
74
  end
75
75
  end
76
76
 
@@ -99,6 +99,9 @@ module Steep
99
99
  opts.on("--save-expectations[=PATH]", "Save expectations with current type check result to PATH (or steep_expectations.yml)") do |path|
100
100
  check.save_expectations_path = Pathname(path || "steep_expectations.yml")
101
101
  end
102
+ opts.on("--severity-level=LEVEL", /^error|warning|information|hint$/, "Specify the minimum diagnostic severity to be recognized as an error (defaults: warning): error, warning, information, or hint") do |level|
103
+ check.severity_level = level.to_sym
104
+ end
102
105
  handle_jobs_option check, opts
103
106
  handle_logging_options opts
104
107
  end.parse!(argv)
@@ -155,6 +158,9 @@ module Steep
155
158
  Drivers::Watch.new(stdout: stdout, stderr: stderr).tap do |command|
156
159
  OptionParser.new do |opts|
157
160
  opts.banner = "Usage: steep watch [options] [dirs]"
161
+ opts.on("--severity-level=LEVEL", /^error|warning|information|hint$/, "Specify the minimum diagnostic severity to be recognized as an error (defaults: warning): error, warning, information, or hint") do |level|
162
+ command.severity_level = level.to_sym
163
+ end
158
164
  handle_jobs_option command, opts
159
165
  handle_logging_options opts
160
166
  end.parse!(argv)
@@ -3,13 +3,66 @@ module Steep
3
3
  class LSPFormatter
4
4
  LSP = LanguageServer::Protocol
5
5
 
6
+ attr_reader :config
7
+ attr_reader :default_severity
8
+
9
+ ERROR = :error
10
+ WARNING = :warning
11
+ INFORMATION = :information
12
+ HINT = :hint
13
+
14
+ def initialize(config = {}, default_severity: ERROR)
15
+ @config = config
16
+ @default_severity = default_severity
17
+
18
+ config.each do |klass, severity|
19
+ validate_severity(klass, severity)
20
+ validate_class(klass)
21
+ end
22
+ validate_severity(:default, default_severity)
23
+ end
24
+
25
+ def validate_class(klass)
26
+ unless klass < Diagnostic::Ruby::Base
27
+ raise "Unexpected diagnostics class `#{klass}` given"
28
+ end
29
+ end
30
+
31
+ def validate_severity(klass, severity)
32
+ case severity
33
+ when ERROR, WARNING, INFORMATION, HINT, nil
34
+ # ok
35
+ else
36
+ raise "Unexpected severity `#{severity}` is specified for #{klass}"
37
+ end
38
+ end
39
+
6
40
  def format(diagnostic)
7
- LSP::Interface::Diagnostic.new(
8
- message: diagnostic.full_message,
9
- code: diagnostic.diagnostic_code,
10
- severity: LSP::Constant::DiagnosticSeverity::ERROR,
11
- range: diagnostic.location.as_lsp_range
12
- ).to_hash
41
+ severity = severity_for(diagnostic)
42
+
43
+ if severity
44
+ LSP::Interface::Diagnostic.new(
45
+ message: diagnostic.full_message,
46
+ code: diagnostic.diagnostic_code,
47
+ severity: severity,
48
+ range: diagnostic.location.as_lsp_range
49
+ ).to_hash
50
+ end
51
+ end
52
+
53
+ def severity_for(diagnostic)
54
+ case config.fetch(diagnostic.class, default_severity)
55
+ when ERROR
56
+ LSP::Constant::DiagnosticSeverity::ERROR
57
+ when WARNING
58
+ LSP::Constant::DiagnosticSeverity::WARNING
59
+ when INFORMATION
60
+ LSP::Constant::DiagnosticSeverity::INFORMATION
61
+ when HINT
62
+ LSP::Constant::DiagnosticSeverity::HINT
63
+ when nil
64
+ nil
65
+ end
13
66
  end
14
67
  end
15
68
  end
@@ -700,6 +700,57 @@ module Steep
700
700
  "SyntaxError: #{message}"
701
701
  end
702
702
  end
703
+
704
+ ALL = ObjectSpace.each_object(Class).with_object([]) do |klass, array|
705
+ if klass < Base
706
+ array << klass
707
+ end
708
+ end
709
+
710
+ def self.all_error
711
+ @all_error ||= ALL.each.with_object({}) do |klass, hash|
712
+ hash[klass] = LSPFormatter::ERROR
713
+ end.freeze
714
+ end
715
+
716
+ def self.default
717
+ @default ||= all_error.merge(
718
+ {
719
+ ImplicitBreakValueMismatch => :warning,
720
+ FallbackAny => :information,
721
+ ElseOnExhaustiveCase => :warning,
722
+ UnknownConstantAssigned => :warning,
723
+ MethodDefinitionMissing => :information
724
+ }
725
+ ).freeze
726
+ end
727
+
728
+ def self.strict
729
+ @strict ||= all_error.merge(
730
+ {
731
+ NoMethod => nil,
732
+ ImplicitBreakValueMismatch => nil,
733
+ FallbackAny => nil,
734
+ ElseOnExhaustiveCase => nil,
735
+ UnknownConstantAssigned => nil,
736
+ MethodDefinitionMissing => nil
737
+ }
738
+ ).freeze
739
+ end
740
+
741
+ def self.lenient
742
+ @lenient ||= all_error.merge(
743
+ {
744
+ NoMethod => nil,
745
+ ImplicitBreakValueMismatch => nil,
746
+ FallbackAny => nil,
747
+ ElseOnExhaustiveCase => nil,
748
+ UnknownConstantAssigned => nil,
749
+ MethodDefinitionMissing => nil,
750
+ UnexpectedJump => nil
751
+ }
752
+ ).freeze
753
+ end
703
754
  end
704
755
  end
705
756
  end
@@ -8,6 +8,7 @@ module Steep
8
8
  attr_reader :command_line_patterns
9
9
  attr_accessor :with_expectations_path
10
10
  attr_accessor :save_expectations_path
11
+ attr_accessor :severity_level
11
12
 
12
13
  include Utils::DriverHelper
13
14
  include Utils::JobsCount
@@ -16,6 +17,7 @@ module Steep
16
17
  @stdout = stdout
17
18
  @stderr = stderr
18
19
  @command_line_patterns = []
20
+ @severity_level = :warning
19
21
  end
20
22
 
21
23
  def run
@@ -70,6 +72,7 @@ module Steep
70
72
  case
71
73
  when response[:method] == "textDocument/publishDiagnostics"
72
74
  ds = response[:params][:diagnostics]
75
+ ds.select! {|d| keep_diagnostic?(d) }
73
76
  if ds.empty?
74
77
  stdout.print "."
75
78
  else
@@ -8,6 +8,8 @@ module Steep
8
8
  include Utils::DriverHelper
9
9
 
10
10
  TEMPLATE = <<~EOF
11
+ # D = Steep::Diagnostic
12
+ #
11
13
  # target :lib do
12
14
  # signature "sig"
13
15
  #
@@ -18,15 +20,20 @@ module Steep
18
20
  #
19
21
  # # library "pathname", "set" # Standard libraries
20
22
  # # library "strong_json" # Gems
23
+ #
24
+ # # configure_code_diagnostics(D::Ruby.strict) # `strict` diagnostics setting
25
+ # # configure_code_diagnostics(D::Ruby.lenient) # `lenient` diagnostics setting
26
+ # # configure_code_diagnostics do |hash| # You can setup everything yourself
27
+ # # hash[D::Ruby::NoMethod] = :information
28
+ # # end
21
29
  # end
22
30
 
23
- # target :spec do
31
+ # target :test do
24
32
  # signature "sig", "sig-private"
25
33
  #
26
- # check "spec"
34
+ # check "test"
27
35
  #
28
36
  # # library "pathname", "set" # Standard libraries
29
- # # library "rspec"
30
37
  # end
31
38
  EOF
32
39
 
@@ -55,6 +55,21 @@ module Steep
55
55
  end
56
56
  end
57
57
  end
58
+
59
+ def keep_diagnostic?(diagnostic)
60
+ severity = diagnostic[:severity]
61
+
62
+ case self.severity_level
63
+ when nil, :hint
64
+ true
65
+ when :error
66
+ severity <= LanguageServer::Protocol::Constant::DiagnosticSeverity::ERROR
67
+ when :warning
68
+ severity <= LanguageServer::Protocol::Constant::DiagnosticSeverity::WARNING
69
+ when :information
70
+ severity <= LanguageServer::Protocol::Constant::DiagnosticSeverity::INFORMATION
71
+ end
72
+ end
58
73
  end
59
74
  end
60
75
  end
@@ -36,7 +36,7 @@ module Steep
36
36
 
37
37
  any_error ||= !errors.empty?
38
38
 
39
- formatter = Diagnostic::LSPFormatter.new
39
+ formatter = Diagnostic::LSPFormatter.new({})
40
40
  diagnostics = errors.group_by {|e| e.location.buffer }.transform_values do |errors|
41
41
  errors.map {|error| formatter.format(error) }
42
42
  end
@@ -5,6 +5,7 @@ module Steep
5
5
  attr_reader :stdout
6
6
  attr_reader :stderr
7
7
  attr_reader :queue
8
+ attr_accessor :severity_level
8
9
 
9
10
  include Utils::DriverHelper
10
11
  include Utils::JobsCount
@@ -16,6 +17,7 @@ module Steep
16
17
  @stdout = stdout
17
18
  @stderr = stderr
18
19
  @queue = Thread::Queue.new
20
+ @severity_level = :warning
19
21
  end
20
22
 
21
23
  def watching?(changed_path, files:, dirs:)
@@ -126,6 +128,7 @@ module Steep
126
128
  printer = DiagnosticPrinter.new(stdout: stdout, buffer: buffer)
127
129
 
128
130
  diagnostics = response[:params][:diagnostics]
131
+ diagnostics.filter! {|d| keep_diagnostic?(d) }
129
132
 
130
133
  unless diagnostics.empty?
131
134
  diagnostics.each do |diagnostic|
@@ -7,21 +7,21 @@ module Steep
7
7
  attr_reader :libraries
8
8
  attr_reader :signatures
9
9
  attr_reader :ignored_sources
10
- attr_reader :vendor_dir
11
- attr_reader :strictness_level
12
- attr_reader :typing_option_hash
10
+ attr_reader :stdlib_root
11
+ attr_reader :core_root
13
12
  attr_reader :repo_paths
13
+ attr_reader :code_diagnostics_config
14
14
 
15
- def initialize(name, sources: [], libraries: [], signatures: [], ignored_sources: [], repo_paths: [])
15
+ def initialize(name, sources: [], libraries: [], signatures: [], ignored_sources: [], repo_paths: [], code_diagnostics_config: {})
16
16
  @name = name
17
17
  @sources = sources
18
18
  @libraries = libraries
19
19
  @signatures = signatures
20
20
  @ignored_sources = ignored_sources
21
- @vendor_dir = nil
22
- @strictness_level = :default
23
- @typing_option_hash = {}
21
+ @core_root = nil
22
+ @stdlib_root = nil
24
23
  @repo_paths = []
24
+ @code_diagnostics_config = code_diagnostics_config
25
25
  end
26
26
 
27
27
  def initialize_copy(other)
@@ -30,10 +30,10 @@ module Steep
30
30
  @libraries = other.libraries.dup
31
31
  @signatures = other.signatures.dup
32
32
  @ignored_sources = other.ignored_sources.dup
33
- @vendor_dir = other.vendor_dir
34
- @strictness_level = other.strictness_level
35
- @typing_option_hash = other.typing_option_hash
36
33
  @repo_paths = other.repo_paths.dup
34
+ @core_root = other.core_root
35
+ @stdlib_root = other.stdlib_root
36
+ @code_diagnostics_config = other.code_diagnostics_config.dup
37
37
  end
38
38
 
39
39
  def check(*args)
@@ -48,9 +48,52 @@ module Steep
48
48
  libraries.push(*args)
49
49
  end
50
50
 
51
- def typing_options(level = @strictness_level, **hash)
52
- @strictness_level = level
53
- @typing_option_hash = hash
51
+ def typing_options(level = nil, **hash)
52
+ Steep.logger.error "#typing_options is deprecated and has no effect as of version 0.46.0. Update your Steepfile as follows for (almost) equivalent setting:"
53
+
54
+ messages = []
55
+
56
+ messages << "# D = Steep::Diagnostic # Define a constant to shorten namespace"
57
+
58
+ case level
59
+ when :strict
60
+ messages << "configure_code_diagnostics(D::Ruby.strict) # :strict"
61
+ when :default
62
+ messages << "configure_code_diagnostics(D::Ruby.default) # :default"
63
+ when :lenient
64
+ messages << "configure_code_diagnostics(D::Ruby.lenient) # :lenient"
65
+ end
66
+
67
+ messages.each do |msg|
68
+ Steep.logger.error " #{msg}"
69
+ end
70
+
71
+ config = []
72
+
73
+ if hash[:allow_missing_definitions]
74
+ config << "hash[D::Ruby::MethodDefinitionMissing] = nil # allow_missing_definitions"
75
+ end
76
+
77
+ if hash[:allow_fallback_any]
78
+ config << "hash[D::Ruby::FallbackAny] = nil # allow_fallback_any"
79
+ end
80
+
81
+ if hash[:allow_unknown_constant_assignment]
82
+ config << "hash[D::Ruby::UnknownConstantAssigned] = nil # allow_unknown_constant_assignment"
83
+ end
84
+
85
+ if hash[:allow_unknown_method_calls]
86
+ config << "hash[D::Ruby::NoMethod] = nil # allow_unknown_method_calls"
87
+ end
88
+
89
+ unless config.empty?
90
+ Steep.logger.error " configure_code_diagnostics do |hash|"
91
+ config.each do |c|
92
+ Steep.logger.error " #{c}"
93
+ end
94
+ Steep.logger.error " end"
95
+ end
96
+
54
97
  end
55
98
 
56
99
  def signature(*args)
@@ -68,20 +111,50 @@ module Steep
68
111
  end
69
112
 
70
113
  def no_builtin!(value = true)
71
- Steep.logger.error "`no_builtin!` in Steepfile is deprecated and ignored. Use `vendor` instead."
114
+ Steep.logger.error "`#no_builtin!` in Steepfile is deprecated and ignored. Use `#stdlib_path` instead."
72
115
  end
73
116
 
74
117
  def vendor(dir = "vendor/sigs", stdlib: nil, gems: nil)
75
- if stdlib || gems
76
- Steep.logger.warn { "#vendor with stdlib: or gems: keyword is deprecated." }
77
- end
118
+ Steep.logger.error "`#vendor` in Steepfile is deprecated and ignored. Use `#stdlib_path` instead."
119
+ end
78
120
 
79
- @vendor_dir = Pathname(dir)
121
+ def stdlib_path(core_root:, stdlib_root:)
122
+ @core_root = core_root ? Pathname(core_root) : core_root
123
+ @stdlib_root = stdlib_root ? Pathname(stdlib_root) : stdlib_root
80
124
  end
81
125
 
82
126
  def repo_path(*paths)
83
127
  @repo_paths.push(*paths.map {|s| Pathname(s) })
84
128
  end
129
+
130
+ # Configure the code diagnostics printing setup.
131
+ #
132
+ # Yields a hash, and the update the hash in the block.
133
+ #
134
+ # ```rb
135
+ # D = Steep::Diagnostic
136
+ #
137
+ # configure_code_diagnostics do |hash|
138
+ # # Assign one of :error, :warning, :information, :hint or :nil to error classes.
139
+ # hash[D::Ruby::UnexpectedPositionalArgument] = :error
140
+ # end
141
+ # ```
142
+ #
143
+ # Passing a hash is also allowed.
144
+ #
145
+ # ```rb
146
+ # D = Steep::Diagnostic
147
+ #
148
+ # configure_code_diagnostics(D::Ruby.lenient)
149
+ # ```
150
+ #
151
+ def configure_code_diagnostics(hash = nil)
152
+ if hash
153
+ code_diagnostics_config.merge!(hash)
154
+ end
155
+
156
+ yield code_diagnostics_config if block_given?
157
+ end
85
158
  end
86
159
 
87
160
  attr_reader :project
@@ -107,7 +180,9 @@ module Steep
107
180
  end
108
181
 
109
182
  def self.parse(project, code, filename: "Steepfile")
110
- self.new(project: project).instance_eval(code, filename)
183
+ Steep.logger.tagged filename do
184
+ self.new(project: project).instance_eval(code, filename)
185
+ end
111
186
  end
112
187
 
113
188
  def target(name, template: nil, &block)
@@ -115,10 +190,12 @@ module Steep
115
190
  self.class.templates[template]&.dup&.update(name: name) or
116
191
  raise "Unknown template: #{template}, available templates: #{@@templates.keys.join(", ")}"
117
192
  else
118
- TargetDSL.new(name)
193
+ TargetDSL.new(name, code_diagnostics_config: Diagnostic::Ruby.default.dup)
119
194
  end
120
195
 
121
- target.instance_eval(&block) if block_given?
196
+ Steep.logger.tagged "target=#{name}" do
197
+ target.instance_eval(&block) if block_given?
198
+ end
122
199
 
123
200
  source_pattern = Pattern.new(patterns: target.sources, ignores: target.ignored_sources, ext: ".rb")
124
201
  signature_pattern = Pattern.new(patterns: target.signatures, ext: ".rbs")
@@ -129,18 +206,13 @@ module Steep
129
206
  signature_pattern: signature_pattern,
130
207
  options: Options.new.tap do |options|
131
208
  options.libraries.push(*target.libraries)
132
- options.repository_paths.push(*target.repo_paths)
133
- options.vendor_path = target.vendor_dir
134
-
135
- case target.strictness_level
136
- when :strict
137
- options.apply_strict_typing_options!
138
- when :lenient
139
- options.apply_lenient_typing_options!
140
- end
141
-
142
- options.merge!(target.typing_option_hash)
143
- end
209
+ options.paths = Options::PathOptions.new(
210
+ core_root: target.core_root,
211
+ stdlib_root: target.stdlib_root,
212
+ repo_paths: target.repo_paths
213
+ )
214
+ end,
215
+ code_diagnostics_config: target.code_diagnostics_config
144
216
  ).tap do |target|
145
217
  project.targets << target
146
218
  end
@@ -1,63 +1,22 @@
1
1
  module Steep
2
2
  class Project
3
3
  class Options
4
- attr_accessor :allow_fallback_any
5
- attr_accessor :allow_missing_definitions
6
- attr_accessor :allow_unknown_constant_assignment
7
- attr_accessor :allow_unknown_method_calls
8
- attr_accessor :vendor_path
9
- attr_reader :libraries
10
- attr_reader :repository_paths
11
-
12
- def initialize
13
- apply_default_typing_options!
14
- self.vendor_path = nil
15
-
16
- @libraries = []
17
- @repository_paths = []
18
- end
19
-
20
- def apply_default_typing_options!
21
- self.allow_fallback_any = true
22
- self.allow_missing_definitions = true
23
- self.allow_unknown_constant_assignment = false
24
- self.allow_unknown_method_calls = false
25
- end
26
-
27
- def apply_strict_typing_options!
28
- self.allow_fallback_any = false
29
- self.allow_missing_definitions = false
30
- self.allow_unknown_constant_assignment = false
31
- self.allow_unknown_method_calls = false
32
- end
33
-
34
- def apply_lenient_typing_options!
35
- self.allow_fallback_any = true
36
- self.allow_missing_definitions = true
37
- self.allow_unknown_constant_assignment = true
38
- self.allow_unknown_method_calls = true
39
- end
4
+ PathOptions = Struct.new(:core_root, :stdlib_root, :repo_paths, keyword_init: true) do
5
+ def customized_stdlib?
6
+ stdlib_root != nil
7
+ end
40
8
 
41
- def error_to_report?(error)
42
- case
43
- when error.is_a?(Diagnostic::Ruby::FallbackAny)
44
- !allow_fallback_any
45
- when error.is_a?(Diagnostic::Ruby::MethodDefinitionMissing)
46
- !allow_missing_definitions
47
- when error.is_a?(Diagnostic::Ruby::NoMethod)
48
- !allow_unknown_method_calls
49
- when error.is_a?(Diagnostic::Ruby::UnknownConstantAssigned)
50
- !allow_unknown_constant_assignment
51
- else
52
- true
9
+ def customized_core?
10
+ core_root != nil
53
11
  end
54
12
  end
55
13
 
56
- def merge!(hash)
57
- self.allow_fallback_any = hash[:allow_fallback_any] if hash.key?(:allow_fallback_any)
58
- self.allow_missing_definitions = hash[:allow_missing_definitions] if hash.key?(:allow_missing_definitions)
59
- self.allow_unknown_constant_assignment = hash[:allow_unknown_constant_assignment] if hash.key?(:allow_unknown_constant_assignment)
60
- self.allow_unknown_method_calls = hash[:allow_unknown_method_calls] if hash.key?(:allow_unknown_method_calls)
14
+ attr_reader :libraries
15
+ attr_accessor :paths
16
+
17
+ def initialize
18
+ @paths = PathOptions.new(repo_paths: [])
19
+ @libraries = []
61
20
  end
62
21
  end
63
22
  end
@@ -6,12 +6,14 @@ module Steep
6
6
 
7
7
  attr_reader :source_pattern
8
8
  attr_reader :signature_pattern
9
+ attr_reader :code_diagnostics_config
9
10
 
10
- def initialize(name:, options:, source_pattern:, signature_pattern:)
11
+ def initialize(name:, options:, source_pattern:, signature_pattern:, code_diagnostics_config:)
11
12
  @name = name
12
13
  @options = options
13
14
  @source_pattern = source_pattern
14
15
  @signature_pattern = signature_pattern
16
+ @code_diagnostics_config = code_diagnostics_config
15
17
 
16
18
  @source_files = {}
17
19
  @signature_files = {}
@@ -30,16 +32,27 @@ module Steep
30
32
  end
31
33
 
32
34
  def self.construct_env_loader(options:, project:)
33
- repo = RBS::Repository.new(no_stdlib: options.vendor_path)
34
- options.repository_paths.each do |path|
35
+ repo = RBS::Repository.new(no_stdlib: options.paths.customized_stdlib?)
36
+
37
+ if options.paths.stdlib_root
38
+ repo.add(project.absolute_path(options.paths.stdlib_root))
39
+ end
40
+
41
+ options.paths.repo_paths.each do |path|
35
42
  repo.add(project.absolute_path(path))
36
43
  end
37
44
 
38
- loader = RBS::EnvironmentLoader.new(
39
- core_root: options.vendor_path ? nil : RBS::EnvironmentLoader::DEFAULT_CORE_ROOT,
40
- repository: repo
41
- )
42
- loader.add(path: options.vendor_path) if options.vendor_path
45
+ core_root_path =
46
+ if options.paths.customized_core?
47
+ if options.paths.core_root
48
+ project.absolute_path(options.paths.core_root)
49
+ end
50
+ else
51
+ RBS::EnvironmentLoader::DEFAULT_CORE_ROOT
52
+ end
53
+
54
+ loader = RBS::EnvironmentLoader.new(core_root: core_root_path, repository: repo)
55
+
43
56
  options.libraries.each do |lib|
44
57
  name, version = lib.split(/:/, 2)
45
58
  loader.add(library: name, version: version)
@@ -144,7 +144,7 @@ module Steep
144
144
  if job.guid == current_type_check_guid
145
145
  Steep.logger.info { "Processing ValidateAppSignature for guid=#{job.guid}, path=#{job.path}" }
146
146
  service.validate_signature(path: project.relative_path(job.path)) do |path, diagnostics|
147
- formatter = Diagnostic::LSPFormatter.new()
147
+ formatter = Diagnostic::LSPFormatter.new({})
148
148
 
149
149
  writer.write(
150
150
  method: :"textDocument/publishDiagnostics",
@@ -162,13 +162,13 @@ module Steep
162
162
  if job.guid == current_type_check_guid
163
163
  Steep.logger.info { "Processing ValidateLibrarySignature for guid=#{job.guid}, path=#{job.path}" }
164
164
  service.validate_signature(path: job.path) do |path, diagnostics|
165
- formatter = Diagnostic::LSPFormatter.new()
165
+ formatter = Diagnostic::LSPFormatter.new({})
166
166
 
167
167
  writer.write(
168
168
  method: :"textDocument/publishDiagnostics",
169
169
  params: LSP::Interface::PublishDiagnosticsParams.new(
170
170
  uri: URI.parse(job.path.to_s).tap {|uri| uri.scheme = "file"},
171
- diagnostics: diagnostics.map {|diagnostic| formatter.format(diagnostic) }.uniq
171
+ diagnostics: diagnostics.map {|diagnostic| formatter.format(diagnostic) }.uniq.compact
172
172
  )
173
173
  )
174
174
  end
@@ -180,17 +180,14 @@ module Steep
180
180
  if job.guid == current_type_check_guid
181
181
  Steep.logger.info { "Processing TypeCheckCodeJob for guid=#{job.guid}, path=#{job.path}" }
182
182
  service.typecheck_source(path: project.relative_path(job.path)) do |path, diagnostics|
183
- if target = project.target_for_source_path(path)
184
- diagnostics = diagnostics.select {|diagnostic| target.options.error_to_report?(diagnostic) }
185
- end
186
-
187
- formatter = Diagnostic::LSPFormatter.new()
183
+ target = project.target_for_source_path(path)
184
+ formatter = Diagnostic::LSPFormatter.new(target&.code_diagnostics_config || {})
188
185
 
189
186
  writer.write(
190
187
  method: :"textDocument/publishDiagnostics",
191
188
  params: LSP::Interface::PublishDiagnosticsParams.new(
192
189
  uri: URI.parse(job.path.to_s).tap {|uri| uri.scheme = "file"},
193
- diagnostics: diagnostics.map {|diagnostic| formatter.format(diagnostic) }.uniq
190
+ diagnostics: diagnostics.map {|diagnostic| formatter.format(diagnostic) }.uniq.compact
194
191
  )
195
192
  )
196
193
  end
@@ -128,8 +128,8 @@ module Steep
128
128
  when :send
129
129
  receiver, method_name, *_ = node.children
130
130
 
131
-
132
- result_node = if parents[0]&.type == :block
131
+ result_node = case parents[0]&.type
132
+ when :block, :numblock
133
133
  parents[0]
134
134
  else
135
135
  node
data/lib/steep/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Steep
2
- VERSION = "0.45.0"
2
+ VERSION = "0.46.0"
3
3
  end
data/sample/Steepfile CHANGED
@@ -1,6 +1,13 @@
1
- target :app do
2
- check "lib"
1
+ D = Steep::Diagnostic
2
+
3
+ target :lib do
3
4
  signature "sig"
4
5
 
5
- library "set", "pathname"
6
+ check "lib" # Directory name
7
+
8
+ # configure_code_diagnostics(D::Ruby.strict) # `strict` diagnostics setting
9
+ # configure_code_diagnostics(D::Ruby.lenient) # `lenient` diagnostics setting
10
+ # configure_code_diagnostics do |hash| # You can setup everything yourself
11
+ # hash[D::Ruby::NoMethod] = :information
12
+ # end
6
13
  end
@@ -1,5 +1,6 @@
1
1
  target :test do
2
- typing_options :strict
3
2
  check "*.rb"
4
3
  signature "*.rbs"
4
+
5
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
5
6
  end
data/smoke/and/Steepfile CHANGED
@@ -1,5 +1,6 @@
1
1
  target :test do
2
- typing_options :strict
3
2
  check "*.rb"
4
3
  signature "*.rbs"
4
+
5
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
5
6
  end
@@ -1,5 +1,6 @@
1
1
  target :test do
2
- typing_options :strict
3
2
  check "*.rb"
4
3
  signature "*.rbs"
4
+
5
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
5
6
  end
@@ -1,6 +1,6 @@
1
1
  target :test do
2
- typing_options :strict
3
2
  check "*.rb"
4
3
  signature "*.rbs"
5
- end
6
4
 
5
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
6
+ end
data/smoke/case/Steepfile CHANGED
@@ -1,5 +1,6 @@
1
1
  target :test do
2
- typing_options :strict
3
2
  check "*.rb"
4
3
  signature "*.rbs"
4
+
5
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
5
6
  end
@@ -1,5 +1,6 @@
1
1
  target :test do
2
- typing_options :strict
3
2
  check "*.rb"
4
3
  signature "*.rbs"
4
+
5
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
5
6
  end
@@ -1,5 +1,6 @@
1
1
  target :test do
2
- typing_options :strict
3
2
  check "*.rb"
4
3
  signature "*.rbs"
4
+
5
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
5
6
  end
@@ -1,5 +1,6 @@
1
1
  target :test do
2
- typing_options :strict
3
2
  check "*.rb"
4
3
  signature "*.rbs"
4
+
5
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
5
6
  end
@@ -2,7 +2,7 @@ all_sigs = Pathname.glob("*.rbs")
2
2
 
3
3
  all_sigs.each do |path|
4
4
  target path.basename(".rbs").to_s.to_sym do
5
- typing_options :strict
6
5
  signature path.to_s
6
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
7
7
  end
8
8
  end
@@ -1,5 +1,6 @@
1
1
  target :test do
2
- typing_options :strict
3
2
  check "*.rb"
4
3
  signature "*.rbs"
4
+
5
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
5
6
  end
@@ -1,5 +1,6 @@
1
1
  target :test do
2
- typing_options :strict
3
2
  check "*.rb"
4
3
  signature "*.rbs"
4
+
5
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
5
6
  end
data/smoke/dstr/Steepfile CHANGED
@@ -1,5 +1,6 @@
1
1
  target :test do
2
- typing_options :strict
3
2
  check "*.rb"
4
3
  signature "*.rbs"
4
+
5
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
5
6
  end
@@ -1,5 +1,6 @@
1
1
  target :test do
2
- typing_options :strict
3
2
  check "*.rb"
4
3
  signature "*.rbs"
4
+
5
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
5
6
  end
@@ -1,5 +1,6 @@
1
1
  target :test do
2
- typing_options :strict
3
2
  check "*.rb"
4
3
  signature "*.rbs"
4
+
5
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
5
6
  end
@@ -1,5 +1,6 @@
1
1
  target :test do
2
- typing_options :strict
3
2
  check "*.rb"
4
3
  signature "*.rbs"
4
+
5
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
5
6
  end
data/smoke/hash/Steepfile CHANGED
@@ -1,5 +1,6 @@
1
1
  target :test do
2
- typing_options :strict
3
2
  check "*.rb"
4
3
  signature "*.rbs"
4
+
5
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
5
6
  end
@@ -1,5 +1,6 @@
1
1
  target :test do
2
- typing_options :strict
3
2
  check "*.rb"
4
3
  signature "*.rbs"
4
+
5
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
5
6
  end
data/smoke/if/Steepfile CHANGED
@@ -1,5 +1,6 @@
1
1
  target :test do
2
- typing_options :strict
3
2
  check "*.rb"
4
3
  signature "*.rbs"
4
+
5
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
5
6
  end
@@ -1,5 +1,6 @@
1
1
  target :test do
2
- typing_options :strict
3
2
  check "*.rb"
4
3
  signature "*.rbs"
4
+
5
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
5
6
  end
@@ -1,5 +1,6 @@
1
1
  target :test do
2
- typing_options :strict
3
2
  check "*.rb"
4
3
  signature "*.rbs"
4
+
5
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
5
6
  end
@@ -1,5 +1,6 @@
1
1
  target :test do
2
- typing_options :strict
3
2
  check "*.rb"
4
3
  signature "*.rbs"
4
+
5
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
5
6
  end
@@ -1,5 +1,6 @@
1
1
  target :test do
2
- typing_options :strict
3
2
  check "*.rb"
4
3
  signature "*.rbs"
4
+
5
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
5
6
  end
@@ -1,5 +1,6 @@
1
1
  target :test do
2
- typing_options :strict
3
2
  check "*.rb"
4
3
  signature "*.rbs"
4
+
5
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
5
6
  end
@@ -1,5 +1,6 @@
1
1
  target :test do
2
- typing_options :strict
3
2
  check "*.rb"
4
3
  signature "*.rbs"
4
+
5
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
5
6
  end
@@ -1,5 +1,6 @@
1
1
  target :test do
2
- typing_options :strict
3
2
  check "*.rb"
4
3
  signature "*.rbs"
4
+
5
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
5
6
  end
data/smoke/map/Steepfile CHANGED
@@ -1,5 +1,6 @@
1
1
  target :test do
2
- typing_options :strict
3
2
  check "*.rb"
4
3
  signature "*.rbs"
4
+
5
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
5
6
  end
@@ -1,5 +1,6 @@
1
1
  target :test do
2
- typing_options :strict
3
2
  check "*.rb"
4
3
  signature "*.rbs"
4
+
5
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
5
6
  end
@@ -1,5 +1,6 @@
1
1
  target :test do
2
- typing_options :strict
3
2
  check "*.rb"
4
3
  signature "*.rbs"
4
+
5
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
5
6
  end
@@ -1,5 +1,6 @@
1
1
  target :test do
2
- typing_options :strict
3
2
  check "*.rb"
4
3
  signature "*.rbs"
4
+
5
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
5
6
  end
@@ -1,6 +1,7 @@
1
1
  target :test do
2
- typing_options :strict
3
2
  check "*.rb"
4
3
  signature "*.rbs"
5
4
  library "set"
5
+
6
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
6
7
  end
@@ -1,5 +1,6 @@
1
1
  target :test do
2
- typing_options :strict
3
2
  check "*.rb"
4
3
  signature "*.rbs"
4
+
5
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
5
6
  end
data/smoke/self/Steepfile CHANGED
@@ -1,5 +1,6 @@
1
1
  target :test do
2
- typing_options :strict
3
2
  check "*.rb"
4
3
  signature "*.rbs"
4
+
5
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
5
6
  end
data/smoke/skip/Steepfile CHANGED
@@ -1,5 +1,6 @@
1
1
  target :test do
2
- typing_options :strict
3
2
  check "*.rb"
4
3
  signature "*.rbs"
4
+
5
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
5
6
  end
@@ -1,5 +1,6 @@
1
1
  target :test do
2
- typing_options :strict
3
2
  check "*.rb"
4
3
  signature "*.rbs"
4
+
5
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
5
6
  end
@@ -1,5 +1,6 @@
1
1
  target :test do
2
- typing_options :strict
3
2
  check "*.rb"
4
3
  signature "*.rbs"
4
+
5
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
5
6
  end
@@ -1,5 +1,6 @@
1
1
  target :test do
2
- typing_options :strict
3
2
  check "*.rb"
4
3
  signature "*.rbs"
4
+
5
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
5
6
  end
@@ -1,8 +1,7 @@
1
1
  target :test do
2
- signature "."
3
- check "."
4
-
5
- typing_options :strict
6
-
2
+ check "*.rb"
3
+ signature "*.rbs"
7
4
  library "tsort"
5
+
6
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
8
7
  end
@@ -1,5 +1,6 @@
1
1
  target :test do
2
- typing_options :strict
3
2
  check "*.rb"
4
3
  signature "*.rbs"
4
+
5
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
5
6
  end
@@ -1,5 +1,6 @@
1
1
  target :test do
2
- typing_options :strict
3
2
  check "*.rb"
4
3
  signature "*.rbs"
4
+
5
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
5
6
  end
@@ -1,5 +1,6 @@
1
1
  target :test do
2
- typing_options :strict
3
2
  check "*.rb"
4
3
  signature "*.rbs"
4
+
5
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
5
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: steep
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.45.0
4
+ version: 0.46.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Soutaro Matsumoto
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-08-22 00:00:00.000000000 Z
11
+ date: 2021-08-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parser