rigortype 0.1.9 → 0.1.11
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 +1 -1
- data/lib/rigor/analysis/baseline.rb +51 -15
- data/lib/rigor/analysis/runner.rb +67 -9
- data/lib/rigor/analysis/worker_session.rb +13 -4
- data/lib/rigor/cache/rbs_descriptor.rb +21 -2
- data/lib/rigor/cache/rbs_environment.rb +2 -1
- data/lib/rigor/cli/annotate_command.rb +57 -7
- data/lib/rigor/cli/baseline_command.rb +4 -3
- data/lib/rigor/cli/coverage_command.rb +126 -0
- data/lib/rigor/cli/coverage_renderer.rb +162 -0
- data/lib/rigor/cli/coverage_report.rb +75 -0
- data/lib/rigor/cli/mcp_command.rb +70 -0
- data/lib/rigor/cli.rb +88 -5
- data/lib/rigor/environment/rbs_loader.rb +46 -5
- data/lib/rigor/environment/reporters.rb +3 -2
- data/lib/rigor/environment.rb +159 -4
- data/lib/rigor/inference/def_return_typer.rb +98 -0
- data/lib/rigor/inference/expression_typer.rb +143 -12
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +5 -0
- data/lib/rigor/inference/method_dispatcher/literal_string_folding.rb +62 -15
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +115 -7
- data/lib/rigor/inference/precision_scanner.rb +131 -0
- data/lib/rigor/inference/statement_evaluator.rb +26 -2
- data/lib/rigor/mcp/loop.rb +43 -0
- data/lib/rigor/mcp/server.rb +263 -0
- data/lib/rigor/mcp.rb +16 -0
- data/lib/rigor/plugin/base.rb +28 -5
- data/lib/rigor/plugin/manifest.rb +33 -5
- data/lib/rigor/plugin/registry.rb +21 -0
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +51 -0
- data/lib/rigor/sig_gen/generator.rb +150 -75
- data/lib/rigor/type/combinator.rb +57 -0
- data/lib/rigor/version.rb +1 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/analyzer.rb +190 -0
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +189 -0
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +81 -0
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +142 -0
- data/plugins/rigor-actioncable/lib/rigor-actioncable.rb +3 -0
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/analyzer.rb +178 -0
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +310 -0
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +76 -0
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +177 -0
- data/plugins/rigor-actionmailer/lib/rigor-actionmailer.rb +3 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +589 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb +150 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +123 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +247 -0
- data/plugins/rigor-actionpack/lib/rigor-actionpack.rb +3 -0
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +114 -0
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +177 -0
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +65 -0
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +117 -0
- data/plugins/rigor-activejob/lib/rigor-activejob.rb +3 -0
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb +273 -0
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/inflector.rb +114 -0
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +561 -0
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +194 -0
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +240 -0
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_table.rb +94 -0
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +514 -0
- data/plugins/rigor-activerecord/lib/rigor-activerecord.rb +8 -0
- data/plugins/rigor-activerecord/sig/active_record/relation.rbs +182 -0
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/analyzer.rb +78 -0
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_discoverer.rb +162 -0
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_index.rb +43 -0
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +170 -0
- data/plugins/rigor-activestorage/lib/rigor-activestorage.rb +8 -0
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +34 -0
- data/plugins/rigor-activesupport-core-ext/lib/rigor-activesupport-core-ext.rb +20 -0
- data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +463 -0
- data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +108 -0
- data/plugins/rigor-devise/lib/rigor-devise.rb +8 -0
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +285 -0
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema.rb +124 -0
- data/plugins/rigor-dry-schema/lib/rigor-dry-schema.rb +8 -0
- data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +116 -0
- data/plugins/rigor-dry-struct/lib/rigor-dry-struct.rb +8 -0
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +341 -0
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +120 -0
- data/plugins/rigor-dry-types/lib/rigor-dry-types.rb +8 -0
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/contract_scanner.rb +120 -0
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +85 -0
- data/plugins/rigor-dry-validation/lib/rigor-dry-validation.rb +7 -0
- data/plugins/rigor-dry-validation/sig/dry_validation.rbs +25 -0
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/analyzer.rb +177 -0
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +242 -0
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_index.rb +56 -0
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +174 -0
- data/plugins/rigor-factorybot/lib/rigor-factorybot.rb +3 -0
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +409 -0
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +114 -0
- data/plugins/rigor-graphql/lib/rigor-graphql.rb +8 -0
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami/action_checker.rb +124 -0
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +111 -0
- data/plugins/rigor-hanami/lib/rigor-hanami.rb +3 -0
- data/plugins/rigor-hanami/sig/hanami_action.rbs +78 -0
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +302 -0
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +72 -0
- data/plugins/rigor-minitest/lib/rigor-minitest.rb +3 -0
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb +194 -0
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +140 -0
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_index.rb +65 -0
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +130 -0
- data/plugins/rigor-pundit/lib/rigor-pundit.rb +3 -0
- data/plugins/rigor-rails/lib/rigor-rails.rb +31 -0
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +277 -0
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +108 -0
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +138 -0
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +167 -0
- data/plugins/rigor-rails-i18n/lib/rigor-rails-i18n.rb +3 -0
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +161 -0
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_table.rb +103 -0
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +490 -0
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +158 -0
- data/plugins/rigor-rails-routes/lib/rigor-rails-routes.rb +3 -0
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +163 -0
- data/plugins/rigor-rbs-inline/lib/rigor-rbs-inline.rb +24 -0
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/analyzer.rb +110 -0
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb +200 -0
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_type_resolver.rb +170 -0
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +233 -0
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/scope_walker.rb +190 -0
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +188 -0
- data/plugins/rigor-rspec/lib/rigor-rspec.rb +3 -0
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/have_http_status_analyzer.rb +128 -0
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/http_status_codes.rb +60 -0
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +75 -0
- data/plugins/rigor-rspec-rails/lib/rigor-rspec-rails.rb +3 -0
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +266 -0
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb +113 -0
- data/plugins/rigor-shoulda-matchers/lib/rigor-shoulda-matchers.rb +3 -0
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/analyzer.rb +152 -0
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb +190 -0
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb +61 -0
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +124 -0
- data/plugins/rigor-sidekiq/lib/rigor-sidekiq.rb +3 -0
- data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +85 -0
- data/plugins/rigor-sinatra/lib/rigor-sinatra.rb +8 -0
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +108 -0
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +250 -0
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +95 -0
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +226 -0
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/method_signature.rb +28 -0
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +154 -0
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +100 -0
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +323 -0
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +660 -0
- data/plugins/rigor-sorbet/lib/rigor-sorbet.rb +3 -0
- data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +209 -0
- data/plugins/rigor-statesman/lib/rigor-statesman.rb +8 -0
- data/plugins/rigor-typescript-utility-types/lib/rigor/plugin/typescript_utility_types.rb +163 -0
- data/plugins/rigor-typescript-utility-types/lib/rigor-typescript-utility-types.rb +9 -0
- data/sig/rigor/analysis/baseline.rbs +39 -0
- data/sig/rigor/environment.rbs +3 -2
- data/sig/rigor/type.rbs +4 -0
- data/sig/rigor.rbs +2 -0
- metadata +180 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9c5853d88c57eb0ded87f9fbf801e3cfbbc7672be2a16bcc3171bd7e3f33122c
|
|
4
|
+
data.tar.gz: d3f3b9d936dd4aab4a10c93b7879b34bee26aa1313007619baadb1381b87310c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bebba3258c508b893a7ca22e98b17838bcc7267399882956a4ced9c214e87947754f5a15ecf80029cf601eed58c93fc53ffcb50636002df9f75c00d498a0585b
|
|
7
|
+
data.tar.gz: 4ac6679d930144ffc5a675a9189ed7ce20d500c5ae9d61820b44fcfbf3e02149b615b3b11a44fa48760c17a75b57ec6d6b5ee3e4a80a4b9139514c742c9c612a
|
data/README.md
CHANGED
|
@@ -63,7 +63,7 @@ the executable it installs is `rigor`.
|
|
|
63
63
|
|
|
64
64
|
Full options — `asdf`, dev containers, CI workflow template — are in the
|
|
65
65
|
[installation guide](https://rigor.typedduck.fail/reference/manual/01-installation/)
|
|
66
|
-
and [CI guide](https://rigor.typedduck.fail/reference/manual/
|
|
66
|
+
and [CI guide](https://rigor.typedduck.fail/reference/manual/11-ci/).
|
|
67
67
|
|
|
68
68
|
## Getting started with AI Skills
|
|
69
69
|
|
|
@@ -52,6 +52,15 @@ module Rigor
|
|
|
52
52
|
# CLI or `baseline: <path>` in `.rigor.yml`). The presence
|
|
53
53
|
# of `.rigor-baseline.yml` on disk alone never triggers a
|
|
54
54
|
# load — that's the CLI / Configuration's job to enforce.
|
|
55
|
+
#
|
|
56
|
+
# ## Path handling
|
|
57
|
+
#
|
|
58
|
+
# Baselines store file paths **relative to the project root**
|
|
59
|
+
# (the working directory when `rigor` is run). This makes the
|
|
60
|
+
# generated `.rigor-baseline.yml` portable across machines and
|
|
61
|
+
# checkout locations. When filtering a live diagnostic stream,
|
|
62
|
+
# the instance normalises each diagnostic's absolute path to a
|
|
63
|
+
# relative one before the bucket lookup.
|
|
55
64
|
class Baseline
|
|
56
65
|
# The bucket key is intentionally tuple-shaped so rule-ID
|
|
57
66
|
# rows and message-pattern rows can coexist in a single
|
|
@@ -69,12 +78,16 @@ module Rigor
|
|
|
69
78
|
# path is nil (the caller's "no baseline configured"
|
|
70
79
|
# state). Raises {LoadError} on malformed content;
|
|
71
80
|
# callers translate to a user-facing diagnostic.
|
|
72
|
-
|
|
81
|
+
#
|
|
82
|
+
# `project_root:` is the working directory against which
|
|
83
|
+
# stored relative paths are resolved during filtering.
|
|
84
|
+
# Defaults to `Dir.pwd`.
|
|
85
|
+
def load(path, project_root: Dir.pwd)
|
|
73
86
|
return nil if path.nil?
|
|
74
|
-
return new([]) unless File.exist?(path)
|
|
87
|
+
return new([], project_root: project_root) unless File.exist?(path)
|
|
75
88
|
|
|
76
89
|
raw = YAML.safe_load_file(path, permitted_classes: [Symbol])
|
|
77
|
-
parse_loaded(raw, path: path)
|
|
90
|
+
parse_loaded(raw, path: path, project_root: project_root)
|
|
78
91
|
end
|
|
79
92
|
|
|
80
93
|
# Build a baseline from a current run's diagnostic stream.
|
|
@@ -82,10 +95,14 @@ module Rigor
|
|
|
82
95
|
# message-mode generator passes literal messages through
|
|
83
96
|
# `Regexp.escape` so generated rows never accidentally
|
|
84
97
|
# over-match on punctuation.
|
|
85
|
-
|
|
98
|
+
#
|
|
99
|
+
# `project_root:` is used to convert absolute diagnostic
|
|
100
|
+
# paths to relative paths in the generated YAML. Defaults
|
|
101
|
+
# to `Dir.pwd`.
|
|
102
|
+
def from_diagnostics(diagnostics, match_mode: :rule, project_root: Dir.pwd)
|
|
86
103
|
raise ArgumentError, "match_mode must be :rule or :message" unless %i[rule message].include?(match_mode)
|
|
87
104
|
|
|
88
|
-
grouped = group_for_baseline(diagnostics, match_mode)
|
|
105
|
+
grouped = group_for_baseline(diagnostics, match_mode, project_root)
|
|
89
106
|
buckets = grouped.map do |key, entries|
|
|
90
107
|
Bucket.new(
|
|
91
108
|
file: key[0],
|
|
@@ -94,12 +111,12 @@ module Rigor
|
|
|
94
111
|
count: entries.size
|
|
95
112
|
)
|
|
96
113
|
end
|
|
97
|
-
new(buckets)
|
|
114
|
+
new(buckets, project_root: project_root)
|
|
98
115
|
end
|
|
99
116
|
|
|
100
117
|
private
|
|
101
118
|
|
|
102
|
-
def parse_loaded(raw, path:)
|
|
119
|
+
def parse_loaded(raw, path:, project_root:)
|
|
103
120
|
raise LoadError, "#{path}: expected a Hash at top level, got #{raw.class}" unless raw.is_a?(Hash)
|
|
104
121
|
|
|
105
122
|
version = raw["version"]
|
|
@@ -110,7 +127,8 @@ module Rigor
|
|
|
110
127
|
rows = raw["ignored"] || []
|
|
111
128
|
raise LoadError, "#{path}: `ignored:` must be an Array" unless rows.is_a?(Array)
|
|
112
129
|
|
|
113
|
-
new(rows.each_with_index.map { |row, idx| parse_row(row, path: path, index: idx) }
|
|
130
|
+
new(rows.each_with_index.map { |row, idx| parse_row(row, path: path, index: idx) },
|
|
131
|
+
project_root: project_root)
|
|
114
132
|
end
|
|
115
133
|
|
|
116
134
|
def parse_row(row, path:, index:)
|
|
@@ -141,16 +159,19 @@ module Rigor
|
|
|
141
159
|
# In message mode, each unique message gets its own bucket;
|
|
142
160
|
# in rule mode, every diagnostic for a (file, rule) pair
|
|
143
161
|
# contributes to a single bucket regardless of message.
|
|
144
|
-
|
|
162
|
+
# File paths are normalised to relative before keying.
|
|
163
|
+
def group_for_baseline(diagnostics, match_mode, project_root)
|
|
164
|
+
root = Pathname.new(project_root)
|
|
145
165
|
diagnostics.each_with_object({}) do |diag, into|
|
|
146
166
|
next if diag.qualified_rule.nil?
|
|
147
167
|
next if diag.path.nil?
|
|
148
168
|
|
|
169
|
+
rel = relative_path(diag.path, root)
|
|
149
170
|
key = case match_mode
|
|
150
171
|
when :rule
|
|
151
|
-
[
|
|
172
|
+
[rel, diag.qualified_rule, nil]
|
|
152
173
|
when :message
|
|
153
|
-
[
|
|
174
|
+
[rel, diag.qualified_rule, message_pattern_for(diag.message)]
|
|
154
175
|
end
|
|
155
176
|
(into[key] ||= []) << diag
|
|
156
177
|
end
|
|
@@ -164,13 +185,20 @@ module Rigor
|
|
|
164
185
|
def message_pattern_for(message)
|
|
165
186
|
Regexp.new(Regexp.escape(message.to_s))
|
|
166
187
|
end
|
|
188
|
+
|
|
189
|
+
def relative_path(path, root_pathname)
|
|
190
|
+
Pathname.new(path).relative_path_from(root_pathname).to_s
|
|
191
|
+
rescue ArgumentError
|
|
192
|
+
path # different drive letter on Windows or non-child path
|
|
193
|
+
end
|
|
167
194
|
end
|
|
168
195
|
|
|
169
196
|
class LoadError < StandardError; end
|
|
170
197
|
|
|
171
198
|
attr_reader :buckets
|
|
172
199
|
|
|
173
|
-
def initialize(buckets)
|
|
200
|
+
def initialize(buckets, project_root: Dir.pwd)
|
|
201
|
+
@project_root = Pathname.new(project_root)
|
|
174
202
|
@buckets = buckets.freeze
|
|
175
203
|
# For each (file, qualified_rule) pair, two arrays:
|
|
176
204
|
# - rule-ID rows (message_regex == nil)
|
|
@@ -264,7 +292,7 @@ module Rigor
|
|
|
264
292
|
# cleared buckets (`actual == 0`) from the on-disk file.
|
|
265
293
|
def without(buckets_to_drop)
|
|
266
294
|
dropset = buckets_to_drop.to_set
|
|
267
|
-
self.class.new(buckets.reject { |b| dropset.include?(b) })
|
|
295
|
+
self.class.new(buckets.reject { |b| dropset.include?(b) }, project_root: @project_root)
|
|
268
296
|
end
|
|
269
297
|
|
|
270
298
|
# Serialise to a YAML string. The generator path writes
|
|
@@ -307,6 +335,14 @@ module Rigor
|
|
|
307
335
|
[bucket.file, bucket.rule, bucket.message_regex&.source]
|
|
308
336
|
end
|
|
309
337
|
|
|
338
|
+
def normalize_path(path)
|
|
339
|
+
return path if path.nil?
|
|
340
|
+
|
|
341
|
+
Pathname.new(path).relative_path_from(@project_root).to_s
|
|
342
|
+
rescue ArgumentError
|
|
343
|
+
path # different drive letter on Windows or non-child path
|
|
344
|
+
end
|
|
345
|
+
|
|
310
346
|
def group_diagnostics_for_filtering(diagnostics)
|
|
311
347
|
# First pass: bin each diagnostic into the bucket that
|
|
312
348
|
# claims it. Message-pattern rows take precedence over
|
|
@@ -322,7 +358,7 @@ module Rigor
|
|
|
322
358
|
[bucket.file, bucket.rule,
|
|
323
359
|
bucket.message_regex&.source]
|
|
324
360
|
else
|
|
325
|
-
[diag.path, diag.qualified_rule, :__none__]
|
|
361
|
+
[normalize_path(diag.path), diag.qualified_rule, :__none__]
|
|
326
362
|
end
|
|
327
363
|
bin = (bins[key] ||= { bucket: bucket, diagnostics: [] })
|
|
328
364
|
bin[:diagnostics] << diag
|
|
@@ -331,7 +367,7 @@ module Rigor
|
|
|
331
367
|
end
|
|
332
368
|
|
|
333
369
|
def claim_bucket_for(diagnostic)
|
|
334
|
-
candidates = @by_pair[[diagnostic.path, diagnostic.qualified_rule]]
|
|
370
|
+
candidates = @by_pair[[normalize_path(diagnostic.path), diagnostic.qualified_rule]]
|
|
335
371
|
return nil if candidates.nil? || candidates.empty?
|
|
336
372
|
|
|
337
373
|
# Tighter (message-pattern) buckets first, then the
|
|
@@ -7,6 +7,7 @@ require_relative "../environment"
|
|
|
7
7
|
require_relative "../scope"
|
|
8
8
|
require_relative "../cache/store"
|
|
9
9
|
require_relative "../plugin"
|
|
10
|
+
require_relative "../plugin/source_rbs_synthesis_reporter"
|
|
10
11
|
require_relative "../rbs_extended/reporter"
|
|
11
12
|
require_relative "../reflection"
|
|
12
13
|
require_relative "../type/combinator"
|
|
@@ -97,6 +98,7 @@ module Rigor
|
|
|
97
98
|
@dependency_source_index = DependencySourceInference::Index::EMPTY
|
|
98
99
|
@rbs_extended_reporter = RbsExtended::Reporter.new
|
|
99
100
|
@boundary_cross_reporter = DependencySourceInference::BoundaryCrossReporter.new
|
|
101
|
+
@source_rbs_synthesis_reporter = Plugin::SourceRbsSynthesisReporter.new
|
|
100
102
|
# `#run` resets these for each invocation; pre-seed them to
|
|
101
103
|
# empty containers so `build_run_stats` / `pre_file_diagnostics`
|
|
102
104
|
# (private, called only from `#run`) can read them without
|
|
@@ -147,6 +149,7 @@ module Rigor
|
|
|
147
149
|
diagnostics += analyze_files(target_files(expansion))
|
|
148
150
|
diagnostics += rbs_extended_reporter_diagnostics
|
|
149
151
|
diagnostics += boundary_cross_diagnostics
|
|
152
|
+
diagnostics += source_rbs_synthesis_diagnostics
|
|
150
153
|
|
|
151
154
|
Result.new(
|
|
152
155
|
diagnostics: apply_severity_profile(diagnostics),
|
|
@@ -294,7 +297,7 @@ module Rigor
|
|
|
294
297
|
if pool_mode?
|
|
295
298
|
dispatch_pool(files)
|
|
296
299
|
else
|
|
297
|
-
environment = resolve_sequential_environment
|
|
300
|
+
environment = resolve_sequential_environment(source_files: files)
|
|
298
301
|
result = files.flat_map { |path| analyze_file(path, environment) }
|
|
299
302
|
if @collect_stats
|
|
300
303
|
loader = environment.rbs_loader
|
|
@@ -311,8 +314,8 @@ module Rigor
|
|
|
311
314
|
# runner's diagnostics) when present; otherwise builds a
|
|
312
315
|
# fresh Environment per-call via {#build_runner_environment}
|
|
313
316
|
# — preserving the pre-override behaviour bit-for-bit.
|
|
314
|
-
def resolve_sequential_environment
|
|
315
|
-
return build_runner_environment unless @environment_override
|
|
317
|
+
def resolve_sequential_environment(source_files: [])
|
|
318
|
+
return build_runner_environment(source_files: source_files) unless @environment_override
|
|
316
319
|
|
|
317
320
|
@environment_override.attach_reporters!(
|
|
318
321
|
rbs_extended_reporter: @rbs_extended_reporter,
|
|
@@ -505,7 +508,14 @@ module Rigor
|
|
|
505
508
|
# Coordinator-side Environment used by the sequential code
|
|
506
509
|
# path. Pool mode builds one Environment per worker inside
|
|
507
510
|
# the worker Ractor's body instead.
|
|
508
|
-
|
|
511
|
+
#
|
|
512
|
+
# ADR-32 WD4 — `source_files:` is threaded down so that
|
|
513
|
+
# `Environment.for_project` can invoke each loaded plugin's
|
|
514
|
+
# `source_rbs_synthesizer` callable per project source file
|
|
515
|
+
# at env-build time. Defaults to `[]` for callers that don't
|
|
516
|
+
# have a file list yet (e.g. pre-pass-only build paths); in
|
|
517
|
+
# that case no synthesised RBS is contributed.
|
|
518
|
+
def build_runner_environment(source_files: [])
|
|
509
519
|
Environment.for_project(
|
|
510
520
|
libraries: @configuration.libraries,
|
|
511
521
|
signature_paths: @configuration.signature_paths,
|
|
@@ -514,13 +524,15 @@ module Rigor
|
|
|
514
524
|
dependency_source_index: @dependency_source_index,
|
|
515
525
|
rbs_extended_reporter: @rbs_extended_reporter,
|
|
516
526
|
boundary_cross_reporter: @boundary_cross_reporter,
|
|
527
|
+
source_rbs_synthesis_reporter: @source_rbs_synthesis_reporter,
|
|
517
528
|
bundler_bundle_path: @configuration.bundler_bundle_path,
|
|
518
529
|
bundler_auto_detect: @configuration.bundler_auto_detect,
|
|
519
530
|
bundler_lockfile: @configuration.bundler_lockfile,
|
|
520
531
|
rbs_collection_lockfile: @configuration.rbs_collection_lockfile,
|
|
521
532
|
rbs_collection_auto_detect: @configuration.rbs_collection_auto_detect,
|
|
522
533
|
synthetic_method_index: @synthetic_method_index,
|
|
523
|
-
project_patched_methods: @project_patched_methods
|
|
534
|
+
project_patched_methods: @project_patched_methods,
|
|
535
|
+
source_files: source_files
|
|
524
536
|
)
|
|
525
537
|
end
|
|
526
538
|
|
|
@@ -559,7 +571,7 @@ module Rigor
|
|
|
559
571
|
# which dedupe on the same keys as a single-session run
|
|
560
572
|
# would. Net result: reporter state is identical to the
|
|
561
573
|
# sequential path.
|
|
562
|
-
def analyze_files_in_pool(files) # rubocop:disable Metrics/MethodLength,Metrics/AbcSize,Metrics/CyclomaticComplexity
|
|
574
|
+
def analyze_files_in_pool(files) # rubocop:disable Metrics/MethodLength,Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
|
|
563
575
|
# Pre-warm class-level lazy memos on the MAIN Ractor.
|
|
564
576
|
# `Environment::ClassRegistry.default` is the
|
|
565
577
|
# default kwarg threaded through `Environment.new`
|
|
@@ -591,15 +603,22 @@ module Rigor
|
|
|
591
603
|
cache_root = @cache_store&.root
|
|
592
604
|
blueprints = @plugin_registry.blueprints
|
|
593
605
|
explain = @explain
|
|
606
|
+
# ADR-32 WD4 — the full project file list travels into
|
|
607
|
+
# every Ractor worker so each worker's WorkerSession
|
|
608
|
+
# can invoke loaded plugins' source_rbs_synthesizers at
|
|
609
|
+
# env-build time. The list is a frozen Array<String>;
|
|
610
|
+
# cheaply shareable.
|
|
611
|
+
shareable_source_files = files.map { |path| path.to_s.dup.freeze }.freeze
|
|
594
612
|
|
|
595
613
|
pool = Array.new(@workers) do
|
|
596
|
-
Ractor.new(configuration, cache_root, blueprints, explain) do |configuration, cache_root, blueprints, explain|
|
|
614
|
+
Ractor.new(configuration, cache_root, blueprints, explain, shareable_source_files) do |configuration, cache_root, blueprints, explain, shareable_source_files| # rubocop:disable Layout/LineLength
|
|
597
615
|
cache_store = cache_root ? Rigor::Cache::Store.new(root: cache_root) : nil
|
|
598
616
|
session = Rigor::Analysis::WorkerSession.new(
|
|
599
617
|
configuration: configuration,
|
|
600
618
|
cache_store: cache_store,
|
|
601
619
|
plugin_blueprints: blueprints,
|
|
602
|
-
explain: explain
|
|
620
|
+
explain: explain,
|
|
621
|
+
source_files: shareable_source_files
|
|
603
622
|
)
|
|
604
623
|
main = Ractor.main
|
|
605
624
|
main.send([:prepare, session.prepare_diagnostics])
|
|
@@ -665,7 +684,8 @@ module Rigor
|
|
|
665
684
|
plugin_blueprints: @plugin_registry.blueprints,
|
|
666
685
|
explain: @explain,
|
|
667
686
|
synthetic_method_index: @synthetic_method_index,
|
|
668
|
-
project_patched_methods: @project_patched_methods
|
|
687
|
+
project_patched_methods: @project_patched_methods,
|
|
688
|
+
source_files: files
|
|
669
689
|
)
|
|
670
690
|
# Force the full RBS load on the parent so children
|
|
671
691
|
# copy-on-write inherit a warm Environment rather than each
|
|
@@ -851,6 +871,15 @@ module Rigor
|
|
|
851
871
|
rbs_display: entry.rbs_display
|
|
852
872
|
)
|
|
853
873
|
end
|
|
874
|
+
# ADR-32 WD6 — merge per-worker synthesizer failures
|
|
875
|
+
# back into the coordinator's reporter. Fetched with a
|
|
876
|
+
# default empty array so older drains (pre-slice-2)
|
|
877
|
+
# remain compatible.
|
|
878
|
+
Array(drained[:source_rbs_synthesis]).each do |entry|
|
|
879
|
+
@source_rbs_synthesis_reporter.record(
|
|
880
|
+
plugin_id: entry.plugin_id, path: entry.path, message: entry.message
|
|
881
|
+
)
|
|
882
|
+
end
|
|
854
883
|
end
|
|
855
884
|
|
|
856
885
|
# Loads project-configured plugins through {Rigor::Plugin::Loader}
|
|
@@ -1160,6 +1189,35 @@ module Rigor
|
|
|
1160
1189
|
# per-call-site — the diagnostic anchors at `.rigor.yml`
|
|
1161
1190
|
# like the other `dependency-source.*` diagnostics that
|
|
1162
1191
|
# report on opt-in configuration.
|
|
1192
|
+
# ADR-32 WD6 — drains the per-run
|
|
1193
|
+
# {Plugin::SourceRbsSynthesisReporter} into
|
|
1194
|
+
# `source-rbs-synthesis-failed` `:info` diagnostics. Each
|
|
1195
|
+
# entry names the plugin that owns the synthesizer, the
|
|
1196
|
+
# source file the rbs-inline parser couldn't process, and
|
|
1197
|
+
# the upstream error message. The synthesizer-emitting
|
|
1198
|
+
# plugin (currently only `rigor-rbs-inline`) treats a
|
|
1199
|
+
# parse failure as a no-contribution event so analysis
|
|
1200
|
+
# continues; this stream surfaces the failure so the user
|
|
1201
|
+
# can see which files contributed nothing and why.
|
|
1202
|
+
#
|
|
1203
|
+
# Severity profile re-stamps the rule per project taste.
|
|
1204
|
+
def source_rbs_synthesis_diagnostics
|
|
1205
|
+
return [] if @source_rbs_synthesis_reporter.empty?
|
|
1206
|
+
|
|
1207
|
+
@source_rbs_synthesis_reporter.entries.map do |entry|
|
|
1208
|
+
Diagnostic.new(
|
|
1209
|
+
path: entry.path, line: 1, column: 1,
|
|
1210
|
+
message: "plugin `#{entry.plugin_id}` failed to synthesise RBS from this file: " \
|
|
1211
|
+
"#{entry.message}. The file's analysis falls back to no inline-RBS " \
|
|
1212
|
+
"contribution. Fix the inline-RBS comment grammar or remove the " \
|
|
1213
|
+
"annotation to silence this diagnostic.",
|
|
1214
|
+
severity: :info,
|
|
1215
|
+
rule: "source-rbs-synthesis-failed",
|
|
1216
|
+
source_family: :builtin
|
|
1217
|
+
)
|
|
1218
|
+
end
|
|
1219
|
+
end
|
|
1220
|
+
|
|
1163
1221
|
def boundary_cross_diagnostics
|
|
1164
1222
|
return [] if @boundary_cross_reporter.empty?
|
|
1165
1223
|
|
|
@@ -93,15 +93,20 @@ module Rigor
|
|
|
93
93
|
# emits one `:info` `fallback` diagnostic per
|
|
94
94
|
# directly-unrecognised node, mirroring
|
|
95
95
|
# {Rigor::Analysis::Runner#explain_diagnostics}.
|
|
96
|
-
def initialize(configuration:, cache_store: nil, # rubocop:disable Metrics/MethodLength
|
|
96
|
+
def initialize(configuration:, cache_store: nil, # rubocop:disable Metrics/MethodLength,Metrics/ParameterLists
|
|
97
97
|
plugin_blueprints: [], explain: false, buffer: nil,
|
|
98
|
-
synthetic_method_index: nil, project_patched_methods: nil
|
|
98
|
+
synthetic_method_index: nil, project_patched_methods: nil,
|
|
99
|
+
source_files: [])
|
|
99
100
|
@configuration = configuration
|
|
100
101
|
@cache_store = cache_store
|
|
101
102
|
@explain = explain
|
|
102
103
|
@buffer = buffer
|
|
103
104
|
@synthetic_method_index = synthetic_method_index
|
|
104
105
|
@project_patched_methods = project_patched_methods
|
|
106
|
+
# ADR-32 WD4 — full project file list (frozen
|
|
107
|
+
# Array<String>) for env-build-time invocation of any
|
|
108
|
+
# loaded plugin's `source_rbs_synthesizer` callable.
|
|
109
|
+
@source_files = source_files
|
|
105
110
|
|
|
106
111
|
# NOTE: `Inference::MethodDispatcher::FileFolding.fold_platform_specific_paths`
|
|
107
112
|
# is process-global state. Writing it from a non-main
|
|
@@ -112,6 +117,7 @@ module Rigor
|
|
|
112
117
|
# pool. The substrate stays Ractor-safe by construction.
|
|
113
118
|
@rbs_extended_reporter = RbsExtended::Reporter.new
|
|
114
119
|
@boundary_cross_reporter = DependencySourceInference::BoundaryCrossReporter.new
|
|
120
|
+
@source_rbs_synthesis_reporter = Plugin::SourceRbsSynthesisReporter.new
|
|
115
121
|
@dependency_source_index = DependencySourceInference::Builder.build(configuration.dependencies)
|
|
116
122
|
|
|
117
123
|
@services = Plugin::Services.new(
|
|
@@ -132,13 +138,15 @@ module Rigor
|
|
|
132
138
|
dependency_source_index: @dependency_source_index,
|
|
133
139
|
rbs_extended_reporter: @rbs_extended_reporter,
|
|
134
140
|
boundary_cross_reporter: @boundary_cross_reporter,
|
|
141
|
+
source_rbs_synthesis_reporter: @source_rbs_synthesis_reporter,
|
|
135
142
|
bundler_bundle_path: configuration.bundler_bundle_path,
|
|
136
143
|
bundler_auto_detect: configuration.bundler_auto_detect,
|
|
137
144
|
bundler_lockfile: configuration.bundler_lockfile,
|
|
138
145
|
rbs_collection_lockfile: configuration.rbs_collection_lockfile,
|
|
139
146
|
rbs_collection_auto_detect: configuration.rbs_collection_auto_detect,
|
|
140
147
|
synthetic_method_index: @synthetic_method_index,
|
|
141
|
-
project_patched_methods: @project_patched_methods
|
|
148
|
+
project_patched_methods: @project_patched_methods,
|
|
149
|
+
source_files: @source_files
|
|
142
150
|
)
|
|
143
151
|
@prepare_diagnostics = run_plugin_prepare.freeze
|
|
144
152
|
end
|
|
@@ -180,7 +188,8 @@ module Rigor
|
|
|
180
188
|
unresolved_payloads: @rbs_extended_reporter.unresolved_payloads,
|
|
181
189
|
lossy_projections: @rbs_extended_reporter.lossy_projections
|
|
182
190
|
},
|
|
183
|
-
boundary_cross: @boundary_cross_reporter.entries
|
|
191
|
+
boundary_cross: @boundary_cross_reporter.entries,
|
|
192
|
+
source_rbs_synthesis: @source_rbs_synthesis_reporter.entries
|
|
184
193
|
}
|
|
185
194
|
end
|
|
186
195
|
|
|
@@ -19,7 +19,7 @@ module Rigor
|
|
|
19
19
|
Descriptor.new(
|
|
20
20
|
gems: [rbs_gem_entry],
|
|
21
21
|
files: file_entries(loader),
|
|
22
|
-
configs: [libraries_entry(loader)]
|
|
22
|
+
configs: [libraries_entry(loader), virtual_rbs_entry(loader)].compact
|
|
23
23
|
)
|
|
24
24
|
end
|
|
25
25
|
|
|
@@ -51,7 +51,26 @@ module Rigor
|
|
|
51
51
|
)
|
|
52
52
|
end
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
# ADR-32 WD5 — encode the loader's virtual_rbs set into a
|
|
55
|
+
# `ConfigEntry` so the env cache invalidates when a
|
|
56
|
+
# plugin-contributed synthesised RBS string changes (or
|
|
57
|
+
# appears for the first time). Returns nil when the
|
|
58
|
+
# loader has no virtual_rbs entries, so callers without
|
|
59
|
+
# any synthesizer-emitting plugin pay zero descriptor
|
|
60
|
+
# cost.
|
|
61
|
+
def self.virtual_rbs_entry(loader)
|
|
62
|
+
return nil unless loader.respond_to?(:virtual_rbs)
|
|
63
|
+
return nil if loader.virtual_rbs.nil? || loader.virtual_rbs.empty?
|
|
64
|
+
|
|
65
|
+
sorted_pairs = loader.virtual_rbs.sort_by { |name, _content| name }
|
|
66
|
+
joined = sorted_pairs.map { |name, content| "#{name}\0#{content}" }.join("\n\0\n")
|
|
67
|
+
Descriptor::ConfigEntry.new(
|
|
68
|
+
key: "rbs.virtual_rbs",
|
|
69
|
+
value_hash: Digest::SHA256.hexdigest(joined)
|
|
70
|
+
)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
private_class_method :rbs_gem_entry, :file_entries, :libraries_entry, :virtual_rbs_entry
|
|
55
74
|
end
|
|
56
75
|
end
|
|
57
76
|
end
|
|
@@ -42,7 +42,8 @@ module Rigor
|
|
|
42
42
|
def self.compute(loader)
|
|
43
43
|
Rigor::Environment::RbsLoader.build_env_for(
|
|
44
44
|
libraries: loader.libraries,
|
|
45
|
-
signature_paths: loader.signature_paths
|
|
45
|
+
signature_paths: loader.signature_paths,
|
|
46
|
+
virtual_rbs: loader.respond_to?(:virtual_rbs) ? loader.virtual_rbs : []
|
|
46
47
|
)
|
|
47
48
|
end
|
|
48
49
|
|
|
@@ -6,6 +6,7 @@ require "prism"
|
|
|
6
6
|
require_relative "../configuration"
|
|
7
7
|
require_relative "../environment"
|
|
8
8
|
require_relative "../scope"
|
|
9
|
+
require_relative "../inference/def_return_typer"
|
|
9
10
|
require_relative "../inference/scope_indexer"
|
|
10
11
|
require_relative "prism_colorizer"
|
|
11
12
|
|
|
@@ -83,7 +84,15 @@ module Rigor
|
|
|
83
84
|
|
|
84
85
|
def execute(file, options)
|
|
85
86
|
configuration = Configuration.load(options.fetch(:config))
|
|
86
|
-
|
|
87
|
+
# Force UTF-8 (with BOM tolerance) regardless of
|
|
88
|
+
# `Encoding.default_external`. Under a minimal locale
|
|
89
|
+
# the default is US-ASCII; reading multi-byte source
|
|
90
|
+
# under that tag makes the post-parse `String#sub` /
|
|
91
|
+
# `String#lines` calls in `#annotate` raise
|
|
92
|
+
# `invalid byte sequence in US-ASCII`. Ruby source is
|
|
93
|
+
# UTF-8 by convention (the parser's own assumption
|
|
94
|
+
# absent a magic comment).
|
|
95
|
+
source = File.read(file, mode: "r:bom|utf-8")
|
|
87
96
|
parse_result = Prism.parse(source, filepath: file, version: configuration.target_ruby)
|
|
88
97
|
return 1 if parse_errors?(parse_result, file)
|
|
89
98
|
|
|
@@ -164,20 +173,33 @@ module Rigor
|
|
|
164
173
|
by_line[statement.location.end_line] = type unless type.nil?
|
|
165
174
|
end
|
|
166
175
|
fill_uncovered_lines(program, by_line)
|
|
176
|
+
override_def_header_lines(program, by_line)
|
|
167
177
|
by_line
|
|
168
178
|
end
|
|
169
179
|
|
|
170
180
|
private
|
|
171
181
|
|
|
172
182
|
# Yields each statement node (a child of any `StatementsNode`
|
|
173
|
-
# anywhere in the tree) in
|
|
174
|
-
#
|
|
175
|
-
#
|
|
176
|
-
|
|
183
|
+
# anywhere in the tree) in post-order: nested statements are
|
|
184
|
+
# yielded before the enclosing statement that contains them.
|
|
185
|
+
# `by_line[end_line] = type` overwrites earlier entries, so
|
|
186
|
+
# post-order means the *outermost* statement closing a line
|
|
187
|
+
# wins — for `b = if cond then :then else :else end` the
|
|
188
|
+
# line resolves to the assignment's type (the if-expression's
|
|
189
|
+
# union), not the else-branch's inner `:else`. Direct siblings
|
|
190
|
+
# (`1; 2; 3`) are still yielded in source order so the last
|
|
191
|
+
# sibling wins.
|
|
192
|
+
def each_statement(node, &block)
|
|
177
193
|
return if node.nil?
|
|
178
194
|
|
|
179
|
-
|
|
180
|
-
|
|
195
|
+
if node.is_a?(Prism::StatementsNode)
|
|
196
|
+
node.body.each do |stmt|
|
|
197
|
+
each_statement(stmt, &block)
|
|
198
|
+
block.call(stmt)
|
|
199
|
+
end
|
|
200
|
+
else
|
|
201
|
+
node.compact_child_nodes.each { |child| each_statement(child, &block) }
|
|
202
|
+
end
|
|
181
203
|
end
|
|
182
204
|
|
|
183
205
|
# For a line no statement closes (the `if` / block header
|
|
@@ -219,6 +241,34 @@ module Rigor
|
|
|
219
241
|
rescue StandardError
|
|
220
242
|
nil
|
|
221
243
|
end
|
|
244
|
+
|
|
245
|
+
# For every `def`, replace the annotation on the header line
|
|
246
|
+
# (where the `def` keyword sits) with the method's inferred
|
|
247
|
+
# return type. The default annotation there comes from the
|
|
248
|
+
# parameter list (`name` typing as `Dynamic[top]`), which is
|
|
249
|
+
# noise; the return type is what readers actually want next
|
|
250
|
+
# to the method signature. When the return type cannot be
|
|
251
|
+
# inferred (empty body, scope-lookup miss, or any error
|
|
252
|
+
# under `DefReturnTyper.call`), the entry is deleted so no
|
|
253
|
+
# annotation is shown on that line.
|
|
254
|
+
def override_def_header_lines(program, by_line)
|
|
255
|
+
each_def_node(program) do |def_node|
|
|
256
|
+
line = def_node.location.start_line
|
|
257
|
+
return_type = Inference::DefReturnTyper.call(def_node, @scope_index)
|
|
258
|
+
if return_type.nil?
|
|
259
|
+
by_line.delete(line)
|
|
260
|
+
else
|
|
261
|
+
by_line[line] = return_type
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def each_def_node(node, &block)
|
|
267
|
+
return if node.nil?
|
|
268
|
+
|
|
269
|
+
block.call(node) if node.is_a?(Prism::DefNode)
|
|
270
|
+
node.compact_child_nodes.each { |child| each_def_node(child, &block) }
|
|
271
|
+
end
|
|
222
272
|
end
|
|
223
273
|
end
|
|
224
274
|
end
|
|
@@ -84,7 +84,8 @@ module Rigor
|
|
|
84
84
|
configuration = Configuration.load(options.fetch(:config))
|
|
85
85
|
diagnostics = collect_diagnostics(configuration, options)
|
|
86
86
|
|
|
87
|
-
baseline = Analysis::Baseline.from_diagnostics(diagnostics, match_mode: options.fetch(:match_mode)
|
|
87
|
+
baseline = Analysis::Baseline.from_diagnostics(diagnostics, match_mode: options.fetch(:match_mode),
|
|
88
|
+
project_root: Dir.pwd)
|
|
88
89
|
File.write(path, baseline.to_yaml)
|
|
89
90
|
|
|
90
91
|
@err.puts(
|
|
@@ -149,7 +150,7 @@ module Rigor
|
|
|
149
150
|
defaults = Configuration::DEFAULTS.merge(
|
|
150
151
|
"paths" => configuration.paths,
|
|
151
152
|
"exclude" => configuration.exclude_patterns,
|
|
152
|
-
"plugins" => configuration.plugins
|
|
153
|
+
"plugins" => configuration.plugins,
|
|
153
154
|
"disable" => configuration.disabled_rules,
|
|
154
155
|
"libraries" => configuration.libraries,
|
|
155
156
|
"signature_paths" => configuration.signature_paths,
|
|
@@ -372,7 +373,7 @@ module Rigor
|
|
|
372
373
|
@err.puts("rigor: baseline file not found: #{path}")
|
|
373
374
|
return :error
|
|
374
375
|
end
|
|
375
|
-
Analysis::Baseline.load(path)
|
|
376
|
+
Analysis::Baseline.load(path, project_root: Dir.pwd)
|
|
376
377
|
rescue Analysis::Baseline::LoadError => e
|
|
377
378
|
@err.puts("rigor: baseline load failed: #{e.message}")
|
|
378
379
|
:error
|