rigortype 0.1.10 → 0.1.12

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 (144) hide show
  1. checksums.yaml +4 -4
  2. data/lib/rigor/analysis/baseline.rb +51 -15
  3. data/lib/rigor/analysis/erb_template_detector.rb +38 -0
  4. data/lib/rigor/analysis/runner.rb +6 -1
  5. data/lib/rigor/analysis/worker_session.rb +6 -1
  6. data/lib/rigor/cli/baseline_command.rb +4 -3
  7. data/lib/rigor/cli/plugins_command.rb +308 -0
  8. data/lib/rigor/cli/plugins_renderer.rb +173 -0
  9. data/lib/rigor/cli.rb +44 -3
  10. data/lib/rigor/inference/block_parameter_binder.rb +35 -0
  11. data/lib/rigor/inference/expression_typer.rb +69 -30
  12. data/lib/rigor/inference/indexed_narrowing.rb +187 -0
  13. data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +24 -0
  14. data/lib/rigor/inference/method_dispatcher.rb +23 -0
  15. data/lib/rigor/inference/mutation_widening.rb +285 -0
  16. data/lib/rigor/inference/narrowing.rb +72 -4
  17. data/lib/rigor/inference/scope_indexer.rb +409 -12
  18. data/lib/rigor/inference/statement_evaluator.rb +256 -4
  19. data/lib/rigor/scope.rb +181 -4
  20. data/lib/rigor/version.rb +1 -1
  21. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/analyzer.rb +190 -0
  22. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +189 -0
  23. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +81 -0
  24. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +142 -0
  25. data/plugins/rigor-actioncable/lib/rigor-actioncable.rb +3 -0
  26. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/analyzer.rb +199 -0
  27. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +398 -0
  28. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +86 -0
  29. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +183 -0
  30. data/plugins/rigor-actionmailer/lib/rigor-actionmailer.rb +3 -0
  31. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +713 -0
  32. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb +201 -0
  33. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +226 -0
  34. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +261 -0
  35. data/plugins/rigor-actionpack/lib/rigor-actionpack.rb +3 -0
  36. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +114 -0
  37. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +177 -0
  38. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +65 -0
  39. data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +117 -0
  40. data/plugins/rigor-activejob/lib/rigor-activejob.rb +3 -0
  41. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb +283 -0
  42. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/inflector.rb +114 -0
  43. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +561 -0
  44. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +194 -0
  45. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +250 -0
  46. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_table.rb +98 -0
  47. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +590 -0
  48. data/plugins/rigor-activerecord/lib/rigor-activerecord.rb +8 -0
  49. data/plugins/rigor-activerecord/sig/active_record/relation.rbs +182 -0
  50. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/analyzer.rb +78 -0
  51. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_discoverer.rb +162 -0
  52. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_index.rb +43 -0
  53. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +170 -0
  54. data/plugins/rigor-activestorage/lib/rigor-activestorage.rb +8 -0
  55. data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +37 -0
  56. data/plugins/rigor-activesupport-core-ext/lib/rigor-activesupport-core-ext.rb +20 -0
  57. data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +478 -0
  58. data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +108 -0
  59. data/plugins/rigor-devise/lib/rigor-devise.rb +8 -0
  60. data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +285 -0
  61. data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema.rb +124 -0
  62. data/plugins/rigor-dry-schema/lib/rigor-dry-schema.rb +8 -0
  63. data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +116 -0
  64. data/plugins/rigor-dry-struct/lib/rigor-dry-struct.rb +8 -0
  65. data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +341 -0
  66. data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +120 -0
  67. data/plugins/rigor-dry-types/lib/rigor-dry-types.rb +8 -0
  68. data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/contract_scanner.rb +120 -0
  69. data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +85 -0
  70. data/plugins/rigor-dry-validation/lib/rigor-dry-validation.rb +7 -0
  71. data/plugins/rigor-dry-validation/sig/dry_validation.rbs +25 -0
  72. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/analyzer.rb +177 -0
  73. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +242 -0
  74. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_index.rb +56 -0
  75. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +174 -0
  76. data/plugins/rigor-factorybot/lib/rigor-factorybot.rb +3 -0
  77. data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +409 -0
  78. data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +114 -0
  79. data/plugins/rigor-graphql/lib/rigor-graphql.rb +8 -0
  80. data/plugins/rigor-hanami/lib/rigor/plugin/hanami/action_checker.rb +124 -0
  81. data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +111 -0
  82. data/plugins/rigor-hanami/lib/rigor-hanami.rb +3 -0
  83. data/plugins/rigor-hanami/sig/hanami_action.rbs +78 -0
  84. data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +302 -0
  85. data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +72 -0
  86. data/plugins/rigor-minitest/lib/rigor-minitest.rb +3 -0
  87. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb +194 -0
  88. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +140 -0
  89. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_index.rb +65 -0
  90. data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +130 -0
  91. data/plugins/rigor-pundit/lib/rigor-pundit.rb +3 -0
  92. data/plugins/rigor-rails/lib/rigor-rails.rb +31 -0
  93. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +353 -0
  94. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +108 -0
  95. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +138 -0
  96. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +175 -0
  97. data/plugins/rigor-rails-i18n/lib/rigor-rails-i18n.rb +3 -0
  98. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +350 -0
  99. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +264 -0
  100. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +100 -0
  101. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +175 -0
  102. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_table.rb +164 -0
  103. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +1538 -0
  104. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +235 -0
  105. data/plugins/rigor-rails-routes/lib/rigor-rails-routes.rb +3 -0
  106. data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +163 -0
  107. data/plugins/rigor-rbs-inline/lib/rigor-rbs-inline.rb +24 -0
  108. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/analyzer.rb +110 -0
  109. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb +200 -0
  110. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_type_resolver.rb +170 -0
  111. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +233 -0
  112. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/scope_walker.rb +190 -0
  113. data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +188 -0
  114. data/plugins/rigor-rspec/lib/rigor-rspec.rb +3 -0
  115. data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/have_http_status_analyzer.rb +128 -0
  116. data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/http_status_codes.rb +60 -0
  117. data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +75 -0
  118. data/plugins/rigor-rspec-rails/lib/rigor-rspec-rails.rb +3 -0
  119. data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +266 -0
  120. data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb +113 -0
  121. data/plugins/rigor-shoulda-matchers/lib/rigor-shoulda-matchers.rb +3 -0
  122. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/analyzer.rb +152 -0
  123. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb +190 -0
  124. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb +61 -0
  125. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +124 -0
  126. data/plugins/rigor-sidekiq/lib/rigor-sidekiq.rb +3 -0
  127. data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +85 -0
  128. data/plugins/rigor-sinatra/lib/rigor-sinatra.rb +8 -0
  129. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +108 -0
  130. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +250 -0
  131. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +95 -0
  132. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +226 -0
  133. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/method_signature.rb +28 -0
  134. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +154 -0
  135. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +100 -0
  136. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +323 -0
  137. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +660 -0
  138. data/plugins/rigor-sorbet/lib/rigor-sorbet.rb +3 -0
  139. data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +209 -0
  140. data/plugins/rigor-statesman/lib/rigor-statesman.rb +8 -0
  141. data/plugins/rigor-typescript-utility-types/lib/rigor/plugin/typescript_utility_types.rb +163 -0
  142. data/plugins/rigor-typescript-utility-types/lib/rigor-typescript-utility-types.rb +9 -0
  143. data/sig/rigor/scope.rbs +22 -0
  144. metadata +157 -1
@@ -0,0 +1,209 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "prism"
4
+ require "rigor/plugin"
5
+
6
+ module Rigor
7
+ module Plugin
8
+ # Example plugin: validates state-machine references.
9
+ # Demonstrates the **two-pass DSL analysis** pattern many
10
+ # plugins reuse:
11
+ #
12
+ # 1. **Collect pass.** Walk the file once to gather every
13
+ # state name declared inside a `state_machine do ... end`
14
+ # block (`state :draft`, `state :submitted`, ...).
15
+ # 2. **Validate pass.** Walk the file again, validating each
16
+ # `transition_to(:sym)` and `event :sym` reference against
17
+ # the collected state set. Levenshtein distance ≤ 3 drives
18
+ # the did-you-mean suggestions.
19
+ #
20
+ # Useful for `aasm` / `statesman` / hand-rolled DSLs and any
21
+ # framework where declarations and uses live in the same
22
+ # file. The same skeleton lifts to GraphQL types,
23
+ # ActiveModel validations, route declarations — anywhere a
24
+ # declarative DSL produces a closed namespace and the rest
25
+ # of the file references that namespace by literal symbol.
26
+ #
27
+ # ## Configuration
28
+ #
29
+ # Defaults match the `Statesman::Machine` API; override via
30
+ # `.rigor.yml` if your DSL uses different names:
31
+ #
32
+ # plugins:
33
+ # - gem: rigor-statesman
34
+ # config:
35
+ # dsl_method: state_machine # the do-block opener
36
+ # state_method: state # state declaration inside the block
37
+ # transition_method: transition_to # call-site under check
38
+ #
39
+ # ## Diagnostics
40
+ #
41
+ # | Event | Severity | Rule |
42
+ # | --- | --- | --- |
43
+ # | `transition_to(:known_state)` | `:info` | `known-state` |
44
+ # | `transition_to(:typo)` (close match) | `:error` | `unknown-state` (with did-you-mean) |
45
+ # | `transition_to(:typo)` (no close match) | `:error` | `unknown-state` |
46
+ # | file declares no state machine | silent | — |
47
+ class Statesman < Rigor::Plugin::Base
48
+ manifest(
49
+ id: "statesman",
50
+ version: "0.1.0",
51
+ description: "Validates state-machine transition references against declared states.",
52
+ config_schema: {
53
+ "dsl_method" => :string,
54
+ "state_method" => :string,
55
+ "transition_method" => :string
56
+ }
57
+ )
58
+
59
+ DEFAULT_DSL_METHOD = "state_machine"
60
+ DEFAULT_STATE_METHOD = "state"
61
+ DEFAULT_TRANSITION_METHOD = "transition_to"
62
+ DID_YOU_MEAN_DISTANCE = 3
63
+
64
+ def init(_services)
65
+ @dsl_method = config.fetch("dsl_method", DEFAULT_DSL_METHOD).to_sym
66
+ @state_method = config.fetch("state_method", DEFAULT_STATE_METHOD).to_sym
67
+ @transition_method = config.fetch("transition_method", DEFAULT_TRANSITION_METHOD).to_sym
68
+ end
69
+
70
+ def diagnostics_for_file(path:, scope:, root:) # rubocop:disable Lint/UnusedMethodArgument
71
+ states = collect_states(root)
72
+ return [] if states.empty?
73
+
74
+ validate_transitions(path, root, states)
75
+ end
76
+
77
+ private
78
+
79
+ # Pass 1 — every `state :foo` declaration inside a
80
+ # `<dsl_method> do ... end` block on the file. Returns a
81
+ # frozen Set of state name Symbols.
82
+ def collect_states(root)
83
+ states = Set.new
84
+ walk(root) do |node|
85
+ next unless dsl_call?(node)
86
+
87
+ walk(node.block) do |inner|
88
+ next unless state_declaration?(inner)
89
+
90
+ sym = literal_symbol_arg(inner, 0)
91
+ states << sym if sym
92
+ end
93
+ end
94
+ states.freeze
95
+ end
96
+
97
+ # Pass 2 — every `<transition_method>(:sym)` call.
98
+ def validate_transitions(path, root, states)
99
+ diagnostics = []
100
+ walk(root) do |node|
101
+ next unless transition_call?(node)
102
+
103
+ sym = literal_symbol_arg(node, 0)
104
+ next if sym.nil? # not a literal — defer to runtime
105
+
106
+ diagnostics << build_diagnostic(path, node, sym, states)
107
+ end
108
+ diagnostics
109
+ end
110
+
111
+ def build_diagnostic(path, node, sym, states)
112
+ if states.include?(sym)
113
+ diagnostic(
114
+ path, node,
115
+ severity: :info,
116
+ rule: "known-state",
117
+ message: "#{@transition_method}(:#{sym}) — declared state"
118
+ )
119
+ else
120
+ hint = did_you_mean(sym, states)
121
+ message = "unknown state :#{sym}"
122
+ message += " (did you mean :#{hint}?)" if hint
123
+ diagnostic(path, node, severity: :error, rule: "unknown-state", message: message)
124
+ end
125
+ end
126
+
127
+ def dsl_call?(node)
128
+ node.is_a?(Prism::CallNode) &&
129
+ node.name == @dsl_method &&
130
+ node.block
131
+ end
132
+
133
+ def state_declaration?(node)
134
+ node.is_a?(Prism::CallNode) &&
135
+ node.name == @state_method &&
136
+ !node.arguments.nil?
137
+ end
138
+
139
+ def transition_call?(node)
140
+ node.is_a?(Prism::CallNode) &&
141
+ node.name == @transition_method &&
142
+ !node.arguments.nil?
143
+ end
144
+
145
+ def literal_symbol_arg(call, index)
146
+ node = call.arguments.arguments[index]
147
+ return nil unless node.is_a?(Prism::SymbolNode)
148
+
149
+ node.unescaped.to_sym
150
+ end
151
+
152
+ def walk(node, &)
153
+ return if node.nil?
154
+
155
+ yield node
156
+ node.compact_child_nodes.each { |child| walk(child, &) }
157
+ end
158
+
159
+ def did_you_mean(name, states)
160
+ target = name.to_s
161
+ best = nil
162
+ best_distance = DID_YOU_MEAN_DISTANCE + 1
163
+ states.each do |state|
164
+ distance = levenshtein(target, state.to_s)
165
+ if distance < best_distance
166
+ best = state
167
+ best_distance = distance
168
+ end
169
+ end
170
+ best
171
+ end
172
+
173
+ def levenshtein(a, b) # rubocop:disable Naming/MethodParameterName
174
+ return b.length if a.empty?
175
+ return a.length if b.empty?
176
+
177
+ rows = Array.new(a.length + 1) { |_i| Array.new(b.length + 1, 0) }
178
+ (0..a.length).each { |i| rows[i][0] = i }
179
+ (0..b.length).each { |j| rows[0][j] = j }
180
+
181
+ (1..a.length).each do |i|
182
+ (1..b.length).each do |j|
183
+ cost = a[i - 1] == b[j - 1] ? 0 : 1
184
+ rows[i][j] = [
185
+ rows[i - 1][j] + 1,
186
+ rows[i][j - 1] + 1,
187
+ rows[i - 1][j - 1] + cost
188
+ ].min
189
+ end
190
+ end
191
+ rows[a.length][b.length]
192
+ end
193
+
194
+ def diagnostic(path, node, severity:, rule:, message:)
195
+ location = node.location
196
+ Rigor::Analysis::Diagnostic.new(
197
+ path: path,
198
+ line: location.start_line,
199
+ column: location.start_column + 1,
200
+ message: message,
201
+ severity: severity,
202
+ rule: rule
203
+ )
204
+ end
205
+ end
206
+
207
+ Rigor::Plugin.register(Statesman)
208
+ end
209
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Gem entry point. Required by Rigor's plugin loader when
4
+ # `.rigor.yml` lists `rigor-statesman` under `plugins:`. The
5
+ # loader expects this `require` to side-effect a call to
6
+ # `Rigor::Plugin.register`, which the body of
7
+ # `lib/rigor/plugin/statesman.rb` performs at load time.
8
+ require_relative "rigor/plugin/statesman"
@@ -0,0 +1,163 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rigor/plugin"
4
+
5
+ module Rigor
6
+ module Plugin
7
+ # Example plugin: ships the TypeScript-canonical utility-type
8
+ # aliases (`Pick<T, K>`, `Omit<T, K>`, `Partial<T>`,
9
+ # `Required<T>`, `Readonly<T>`) as opt-in vocabulary that
10
+ # resolves to the Rigor-canonical shape-projection type
11
+ # functions introduced in ADR-13.
12
+ #
13
+ # Background. `docs/type-specification/imported-built-in-types.md`
14
+ # § "Deferred or rejected imports" deliberately rejects
15
+ # TypeScript-canonical names from the Rigor core surface: the
16
+ # core stays RBS-canonical per ADR-0 / ADR-1, and the shape
17
+ # semantics live in core under `pick_of[T, K]` /
18
+ # `omit_of[T, K]` / `partial_of[T]` / `required_of[T]` /
19
+ # `readonly_of[T]` (added in ADR-13 slice 4). This plugin
20
+ # ships the TS spellings as an opt-in translation layer for
21
+ # users migrating from TypeScript / Sorbet / Flow-style RBI.
22
+ #
23
+ # Off by default — users add the gem to their `.rigor.yml`
24
+ # plugins list to enable.
25
+ #
26
+ # @example .rigor.yml
27
+ # plugins:
28
+ # - gem: rigor-typescript-utility-types
29
+ #
30
+ # Once loaded, an RBS::Extended payload such as
31
+ # `%a{rigor:v1:return: Pick[Foo, :a | :b]}` resolves through
32
+ # the chain: the parser builds a `Generic("Pick", …)` AST,
33
+ # the registry / built-in parametric builders decline, the
34
+ # chain consults `Resolvers::Pick`, which recursively
35
+ # resolves the two arguments to Rigor types and calls
36
+ # `Type::Combinator.pick_of` on them.
37
+ #
38
+ # ## Translation table
39
+ #
40
+ # | TypeScript spelling | Rigor core call |
41
+ # | --- | --- |
42
+ # | `Pick<T, K>` | `Type::Combinator.pick_of(T, K)` |
43
+ # | `Omit<T, K>` | `Type::Combinator.omit_of(T, K)` |
44
+ # | `Partial<T>` | `Type::Combinator.partial_of(T)` |
45
+ # | `Required<T>` | `Type::Combinator.required_of(T)` |
46
+ # | `Readonly<T>` | `Type::Combinator.readonly_of(T)` |
47
+ #
48
+ # ## Deferred TypeScript utility names
49
+ #
50
+ # `Parameters<F>` / `ReturnType<F>` / `InstanceType<C>` /
51
+ # `Awaited<P>` / `Uppercase<S>` / `Lowercase<S>` /
52
+ # `Capitalize<S>` / `Uncapitalize<S>` / `ThisParameterType<F>`
53
+ # / `OmitThisParameter<F>` / `ConstructorParameters<C>` /
54
+ # `NoInfer<T>` are NOT mapped today. The plugin returns `nil`
55
+ # from `#resolve` for those heads, leaving the parser's
56
+ # default Nominal-fallback to produce `Nominal[ReturnType, …]`
57
+ # etc. Function-type projection operators (`params_of[F]` /
58
+ # `return_of[F]`) and class projections (`instance_type[C]`)
59
+ # would unlock these — they remain deferred in core.
60
+ class TypescriptUtilityTypes < Rigor::Plugin::Base
61
+ module Resolvers
62
+ # Common helper: extract a single-arg utility-type Generic
63
+ # whose head matches `name`. Returns the resolved
64
+ # argument's `Rigor::Type` or `nil` (so the chain falls
65
+ # through).
66
+ module SingleArg
67
+ def self.resolve(node, scope, name)
68
+ return nil unless node.is_a?(Rigor::TypeNode::Generic)
69
+ return nil unless node.head == name
70
+ return nil unless node.args.size == 1
71
+
72
+ scope.resolver.resolve(node.args[0], scope)
73
+ end
74
+ end
75
+
76
+ # Common helper for two-arg utility types.
77
+ module TwoArg
78
+ def self.resolve(node, scope, name)
79
+ return nil unless node.is_a?(Rigor::TypeNode::Generic)
80
+ return nil unless node.head == name
81
+ return nil unless node.args.size == 2
82
+
83
+ [scope.resolver.resolve(node.args[0], scope),
84
+ scope.resolver.resolve(node.args[1], scope)]
85
+ end
86
+ end
87
+
88
+ # `Pick<T, K>` → `pick_of[T, K]`.
89
+ class Pick < Rigor::Plugin::TypeNodeResolver
90
+ def resolve(node, scope)
91
+ resolved = TwoArg.resolve(node, scope, "Pick")
92
+ return nil if resolved.nil?
93
+
94
+ t_type, k_type = resolved
95
+ return nil if t_type.nil? || k_type.nil?
96
+
97
+ Rigor::Type::Combinator.pick_of(t_type, k_type)
98
+ end
99
+ end
100
+
101
+ # `Omit<T, K>` → `omit_of[T, K]`.
102
+ class Omit < Rigor::Plugin::TypeNodeResolver
103
+ def resolve(node, scope)
104
+ resolved = TwoArg.resolve(node, scope, "Omit")
105
+ return nil if resolved.nil?
106
+
107
+ t_type, k_type = resolved
108
+ return nil if t_type.nil? || k_type.nil?
109
+
110
+ Rigor::Type::Combinator.omit_of(t_type, k_type)
111
+ end
112
+ end
113
+
114
+ # `Partial<T>` → `partial_of[T]`.
115
+ class Partial < Rigor::Plugin::TypeNodeResolver
116
+ def resolve(node, scope)
117
+ t_type = SingleArg.resolve(node, scope, "Partial")
118
+ return nil if t_type.nil?
119
+
120
+ Rigor::Type::Combinator.partial_of(t_type)
121
+ end
122
+ end
123
+
124
+ # `Required<T>` → `required_of[T]`.
125
+ class Required < Rigor::Plugin::TypeNodeResolver
126
+ def resolve(node, scope)
127
+ t_type = SingleArg.resolve(node, scope, "Required")
128
+ return nil if t_type.nil?
129
+
130
+ Rigor::Type::Combinator.required_of(t_type)
131
+ end
132
+ end
133
+
134
+ # `Readonly<T>` → `readonly_of[T]`.
135
+ class Readonly < Rigor::Plugin::TypeNodeResolver
136
+ def resolve(node, scope)
137
+ t_type = SingleArg.resolve(node, scope, "Readonly")
138
+ return nil if t_type.nil?
139
+
140
+ Rigor::Type::Combinator.readonly_of(t_type)
141
+ end
142
+ end
143
+ end
144
+
145
+ manifest(
146
+ id: "typescript-utility-types",
147
+ version: "0.1.0",
148
+ description: "Maps TypeScript-canonical utility-type aliases " \
149
+ "(Pick, Omit, Partial, Required, Readonly) onto the " \
150
+ "Rigor-canonical shape-projection type functions.",
151
+ type_node_resolvers: [
152
+ Resolvers::Pick.new,
153
+ Resolvers::Omit.new,
154
+ Resolvers::Partial.new,
155
+ Resolvers::Required.new,
156
+ Resolvers::Readonly.new
157
+ ]
158
+ )
159
+ end
160
+
161
+ register(TypescriptUtilityTypes)
162
+ end
163
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Gem entry point. Required by Rigor's plugin loader when
4
+ # `.rigor.yml` lists `rigor-typescript-utility-types` under
5
+ # `plugins:`. The loader expects this `require` to side-effect
6
+ # a call to `Rigor::Plugin.register`, which the body of
7
+ # `lib/rigor/plugin/typescript_utility_types.rb` performs at
8
+ # load time.
9
+ require_relative "rigor/plugin/typescript_utility_types"
data/sig/rigor/scope.rbs CHANGED
@@ -18,8 +18,22 @@ module Rigor
18
18
  attr_reader discovered_method_visibilities: Hash[String, Hash[Symbol, Symbol]]
19
19
  attr_reader discovered_superclasses: Hash[String, String]
20
20
  attr_reader discovered_includes: Hash[String, Array[String]]
21
+ attr_reader indexed_narrowings: Hash[IndexedKey, Type::t]
22
+ attr_reader method_chain_narrowings: Hash[ChainKey, Type::t]
21
23
  attr_reader source_path: String?
22
24
 
25
+ class IndexedKey
26
+ attr_reader receiver_kind: Symbol
27
+ attr_reader receiver_name: Symbol
28
+ attr_reader key: untyped
29
+ end
30
+
31
+ class ChainKey
32
+ attr_reader receiver_kind: Symbol
33
+ attr_reader receiver_name: Symbol
34
+ attr_reader method_name: Symbol
35
+ end
36
+
23
37
  def self.empty: (?environment: Environment, ?source_path: String?) -> Scope
24
38
 
25
39
  def initialize: (environment: Environment, locals: Hash[Symbol, Type::t], ?fact_store: Analysis::FactStore, ?self_type: Type::t?, ?declared_types: Hash[untyped, Type::t], ?ivars: Hash[Symbol, Type::t], ?cvars: Hash[Symbol, Type::t], ?globals: Hash[Symbol, Type::t], ?source_path: String?) -> void
@@ -50,6 +64,14 @@ module Rigor
50
64
  def with_discovered_superclasses: (Hash[String, String] table) -> Scope
51
65
  def includes_of: (String | Symbol class_name) -> Array[String]
52
66
  def with_discovered_includes: (Hash[String, Array[String]] table) -> Scope
67
+ def indexed_narrowing: (Symbol receiver_kind, String | Symbol receiver_name, untyped key) -> Type::t?
68
+ def with_indexed_narrowing: (Symbol receiver_kind, String | Symbol receiver_name, untyped key, Type::t type) -> Scope
69
+ def without_indexed_narrowing: (Symbol receiver_kind, String | Symbol receiver_name, untyped key) -> Scope
70
+ def without_indexed_narrowings_for: (Symbol receiver_kind, String | Symbol receiver_name) -> Scope
71
+ def method_chain_narrowing: (Symbol receiver_kind, String | Symbol receiver_name, String | Symbol method_name) -> Type::t?
72
+ def with_method_chain_narrowing: (Symbol receiver_kind, String | Symbol receiver_name, String | Symbol method_name, Type::t type) -> Scope
73
+ def without_method_chain_narrowing: (Symbol receiver_kind, String | Symbol receiver_name, String | Symbol method_name) -> Scope
74
+ def without_method_chain_narrowings_for: (Symbol receiver_kind, String | Symbol receiver_name) -> Scope
53
75
  def with_fact: (Analysis::FactStore::Fact fact) -> Scope
54
76
  def with_self_type: (Type::t? type) -> Scope
55
77
  def with_declared_types: (Hash[untyped, Type::t] table) -> Scope
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rigortype
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.10
4
+ version: 0.1.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rigor contributors
@@ -257,6 +257,7 @@ files:
257
257
  - lib/rigor/analysis/dependency_source_inference/return_type_heuristic.rb
258
258
  - lib/rigor/analysis/dependency_source_inference/walker.rb
259
259
  - lib/rigor/analysis/diagnostic.rb
260
+ - lib/rigor/analysis/erb_template_detector.rb
260
261
  - lib/rigor/analysis/fact_store.rb
261
262
  - lib/rigor/analysis/project_scan.rb
262
263
  - lib/rigor/analysis/result.rb
@@ -290,6 +291,8 @@ files:
290
291
  - lib/rigor/cli/explain_command.rb
291
292
  - lib/rigor/cli/lsp_command.rb
292
293
  - lib/rigor/cli/mcp_command.rb
294
+ - lib/rigor/cli/plugins_command.rb
295
+ - lib/rigor/cli/plugins_renderer.rb
293
296
  - lib/rigor/cli/prism_colorizer.rb
294
297
  - lib/rigor/cli/sig_gen_command.rb
295
298
  - lib/rigor/cli/triage_command.rb
@@ -351,6 +354,7 @@ files:
351
354
  - lib/rigor/inference/hkt_body_parser.rb
352
355
  - lib/rigor/inference/hkt_reducer.rb
353
356
  - lib/rigor/inference/hkt_registry.rb
357
+ - lib/rigor/inference/indexed_narrowing.rb
354
358
  - lib/rigor/inference/macro_block_self_type.rb
355
359
  - lib/rigor/inference/method_dispatcher.rb
356
360
  - lib/rigor/inference/method_dispatcher/block_folding.rb
@@ -373,6 +377,7 @@ files:
373
377
  - lib/rigor/inference/method_dispatcher/uri_folding.rb
374
378
  - lib/rigor/inference/method_parameter_binder.rb
375
379
  - lib/rigor/inference/multi_target_binder.rb
380
+ - lib/rigor/inference/mutation_widening.rb
376
381
  - lib/rigor/inference/narrowing.rb
377
382
  - lib/rigor/inference/precision_scanner.rb
378
383
  - lib/rigor/inference/project_patched_methods.rb
@@ -476,6 +481,128 @@ files:
476
481
  - lib/rigor/type_node/symbol_literal.rb
477
482
  - lib/rigor/type_node/union.rb
478
483
  - lib/rigor/version.rb
484
+ - plugins/rigor-actioncable/lib/rigor-actioncable.rb
485
+ - plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb
486
+ - plugins/rigor-actioncable/lib/rigor/plugin/actioncable/analyzer.rb
487
+ - plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb
488
+ - plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb
489
+ - plugins/rigor-actionmailer/lib/rigor-actionmailer.rb
490
+ - plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb
491
+ - plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/analyzer.rb
492
+ - plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb
493
+ - plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb
494
+ - plugins/rigor-actionpack/lib/rigor-actionpack.rb
495
+ - plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb
496
+ - plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb
497
+ - plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb
498
+ - plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb
499
+ - plugins/rigor-activejob/lib/rigor-activejob.rb
500
+ - plugins/rigor-activejob/lib/rigor/plugin/activejob.rb
501
+ - plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb
502
+ - plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb
503
+ - plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb
504
+ - plugins/rigor-activerecord/lib/rigor-activerecord.rb
505
+ - plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb
506
+ - plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb
507
+ - plugins/rigor-activerecord/lib/rigor/plugin/activerecord/inflector.rb
508
+ - plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb
509
+ - plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb
510
+ - plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb
511
+ - plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_table.rb
512
+ - plugins/rigor-activerecord/sig/active_record/relation.rbs
513
+ - plugins/rigor-activestorage/lib/rigor-activestorage.rb
514
+ - plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb
515
+ - plugins/rigor-activestorage/lib/rigor/plugin/activestorage/analyzer.rb
516
+ - plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_discoverer.rb
517
+ - plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_index.rb
518
+ - plugins/rigor-activesupport-core-ext/lib/rigor-activesupport-core-ext.rb
519
+ - plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb
520
+ - plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs
521
+ - plugins/rigor-devise/lib/rigor-devise.rb
522
+ - plugins/rigor-devise/lib/rigor/plugin/devise.rb
523
+ - plugins/rigor-dry-schema/lib/rigor-dry-schema.rb
524
+ - plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema.rb
525
+ - plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb
526
+ - plugins/rigor-dry-struct/lib/rigor-dry-struct.rb
527
+ - plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb
528
+ - plugins/rigor-dry-types/lib/rigor-dry-types.rb
529
+ - plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb
530
+ - plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb
531
+ - plugins/rigor-dry-validation/lib/rigor-dry-validation.rb
532
+ - plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb
533
+ - plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/contract_scanner.rb
534
+ - plugins/rigor-dry-validation/sig/dry_validation.rbs
535
+ - plugins/rigor-factorybot/lib/rigor-factorybot.rb
536
+ - plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb
537
+ - plugins/rigor-factorybot/lib/rigor/plugin/factorybot/analyzer.rb
538
+ - plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb
539
+ - plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_index.rb
540
+ - plugins/rigor-graphql/lib/rigor-graphql.rb
541
+ - plugins/rigor-graphql/lib/rigor/plugin/graphql.rb
542
+ - plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb
543
+ - plugins/rigor-hanami/lib/rigor-hanami.rb
544
+ - plugins/rigor-hanami/lib/rigor/plugin/hanami.rb
545
+ - plugins/rigor-hanami/lib/rigor/plugin/hanami/action_checker.rb
546
+ - plugins/rigor-hanami/sig/hanami_action.rbs
547
+ - plugins/rigor-minitest/lib/rigor-minitest.rb
548
+ - plugins/rigor-minitest/lib/rigor/plugin/minitest.rb
549
+ - plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb
550
+ - plugins/rigor-pundit/lib/rigor-pundit.rb
551
+ - plugins/rigor-pundit/lib/rigor/plugin/pundit.rb
552
+ - plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb
553
+ - plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb
554
+ - plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_index.rb
555
+ - plugins/rigor-rails-i18n/lib/rigor-rails-i18n.rb
556
+ - plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb
557
+ - plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb
558
+ - plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb
559
+ - plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb
560
+ - plugins/rigor-rails-routes/lib/rigor-rails-routes.rb
561
+ - plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb
562
+ - plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb
563
+ - plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb
564
+ - plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb
565
+ - plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb
566
+ - plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_table.rb
567
+ - plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb
568
+ - plugins/rigor-rails/lib/rigor-rails.rb
569
+ - plugins/rigor-rbs-inline/lib/rigor-rbs-inline.rb
570
+ - plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb
571
+ - plugins/rigor-rspec-rails/lib/rigor-rspec-rails.rb
572
+ - plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb
573
+ - plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/have_http_status_analyzer.rb
574
+ - plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/http_status_codes.rb
575
+ - plugins/rigor-rspec/lib/rigor-rspec.rb
576
+ - plugins/rigor-rspec/lib/rigor/plugin/rspec.rb
577
+ - plugins/rigor-rspec/lib/rigor/plugin/rspec/analyzer.rb
578
+ - plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb
579
+ - plugins/rigor-rspec/lib/rigor/plugin/rspec/let_type_resolver.rb
580
+ - plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb
581
+ - plugins/rigor-rspec/lib/rigor/plugin/rspec/scope_walker.rb
582
+ - plugins/rigor-shoulda-matchers/lib/rigor-shoulda-matchers.rb
583
+ - plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb
584
+ - plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb
585
+ - plugins/rigor-sidekiq/lib/rigor-sidekiq.rb
586
+ - plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb
587
+ - plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/analyzer.rb
588
+ - plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb
589
+ - plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb
590
+ - plugins/rigor-sinatra/lib/rigor-sinatra.rb
591
+ - plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb
592
+ - plugins/rigor-sorbet/lib/rigor-sorbet.rb
593
+ - plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb
594
+ - plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb
595
+ - plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb
596
+ - plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb
597
+ - plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb
598
+ - plugins/rigor-sorbet/lib/rigor/plugin/sorbet/method_signature.rb
599
+ - plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb
600
+ - plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb
601
+ - plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb
602
+ - plugins/rigor-statesman/lib/rigor-statesman.rb
603
+ - plugins/rigor-statesman/lib/rigor/plugin/statesman.rb
604
+ - plugins/rigor-typescript-utility-types/lib/rigor-typescript-utility-types.rb
605
+ - plugins/rigor-typescript-utility-types/lib/rigor/plugin/typescript_utility_types.rb
479
606
  - sig/rigor.rbs
480
607
  - sig/rigor/analysis/baseline.rbs
481
608
  - sig/rigor/analysis/check_rules/always_truthy_condition_collector.rbs
@@ -524,6 +651,35 @@ metadata:
524
651
  rdoc_options: []
525
652
  require_paths:
526
653
  - lib
654
+ - plugins/rigor-actioncable/lib
655
+ - plugins/rigor-actionmailer/lib
656
+ - plugins/rigor-actionpack/lib
657
+ - plugins/rigor-activejob/lib
658
+ - plugins/rigor-activerecord/lib
659
+ - plugins/rigor-activestorage/lib
660
+ - plugins/rigor-activesupport-core-ext/lib
661
+ - plugins/rigor-devise/lib
662
+ - plugins/rigor-dry-schema/lib
663
+ - plugins/rigor-dry-struct/lib
664
+ - plugins/rigor-dry-types/lib
665
+ - plugins/rigor-dry-validation/lib
666
+ - plugins/rigor-factorybot/lib
667
+ - plugins/rigor-graphql/lib
668
+ - plugins/rigor-hanami/lib
669
+ - plugins/rigor-minitest/lib
670
+ - plugins/rigor-pundit/lib
671
+ - plugins/rigor-rails/lib
672
+ - plugins/rigor-rails-i18n/lib
673
+ - plugins/rigor-rails-routes/lib
674
+ - plugins/rigor-rbs-inline/lib
675
+ - plugins/rigor-rspec/lib
676
+ - plugins/rigor-rspec-rails/lib
677
+ - plugins/rigor-shoulda-matchers/lib
678
+ - plugins/rigor-sidekiq/lib
679
+ - plugins/rigor-sinatra/lib
680
+ - plugins/rigor-sorbet/lib
681
+ - plugins/rigor-statesman/lib
682
+ - plugins/rigor-typescript-utility-types/lib
527
683
  required_ruby_version: !ruby/object:Gem::Requirement
528
684
  requirements:
529
685
  - - ">="