rigortype 0.1.10 → 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.
Files changed (125) hide show
  1. checksums.yaml +4 -4
  2. data/lib/rigor/analysis/baseline.rb +51 -15
  3. data/lib/rigor/cli/baseline_command.rb +4 -3
  4. data/lib/rigor/cli.rb +16 -3
  5. data/lib/rigor/version.rb +1 -1
  6. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/analyzer.rb +190 -0
  7. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +189 -0
  8. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +81 -0
  9. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +142 -0
  10. data/plugins/rigor-actioncable/lib/rigor-actioncable.rb +3 -0
  11. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/analyzer.rb +178 -0
  12. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +310 -0
  13. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +76 -0
  14. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +177 -0
  15. data/plugins/rigor-actionmailer/lib/rigor-actionmailer.rb +3 -0
  16. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +589 -0
  17. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb +150 -0
  18. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +123 -0
  19. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +247 -0
  20. data/plugins/rigor-actionpack/lib/rigor-actionpack.rb +3 -0
  21. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +114 -0
  22. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +177 -0
  23. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +65 -0
  24. data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +117 -0
  25. data/plugins/rigor-activejob/lib/rigor-activejob.rb +3 -0
  26. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb +273 -0
  27. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/inflector.rb +114 -0
  28. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +561 -0
  29. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +194 -0
  30. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +240 -0
  31. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_table.rb +94 -0
  32. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +514 -0
  33. data/plugins/rigor-activerecord/lib/rigor-activerecord.rb +8 -0
  34. data/plugins/rigor-activerecord/sig/active_record/relation.rbs +182 -0
  35. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/analyzer.rb +78 -0
  36. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_discoverer.rb +162 -0
  37. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_index.rb +43 -0
  38. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +170 -0
  39. data/plugins/rigor-activestorage/lib/rigor-activestorage.rb +8 -0
  40. data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +34 -0
  41. data/plugins/rigor-activesupport-core-ext/lib/rigor-activesupport-core-ext.rb +20 -0
  42. data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +463 -0
  43. data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +108 -0
  44. data/plugins/rigor-devise/lib/rigor-devise.rb +8 -0
  45. data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +285 -0
  46. data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema.rb +124 -0
  47. data/plugins/rigor-dry-schema/lib/rigor-dry-schema.rb +8 -0
  48. data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +116 -0
  49. data/plugins/rigor-dry-struct/lib/rigor-dry-struct.rb +8 -0
  50. data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +341 -0
  51. data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +120 -0
  52. data/plugins/rigor-dry-types/lib/rigor-dry-types.rb +8 -0
  53. data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/contract_scanner.rb +120 -0
  54. data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +85 -0
  55. data/plugins/rigor-dry-validation/lib/rigor-dry-validation.rb +7 -0
  56. data/plugins/rigor-dry-validation/sig/dry_validation.rbs +25 -0
  57. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/analyzer.rb +177 -0
  58. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +242 -0
  59. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_index.rb +56 -0
  60. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +174 -0
  61. data/plugins/rigor-factorybot/lib/rigor-factorybot.rb +3 -0
  62. data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +409 -0
  63. data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +114 -0
  64. data/plugins/rigor-graphql/lib/rigor-graphql.rb +8 -0
  65. data/plugins/rigor-hanami/lib/rigor/plugin/hanami/action_checker.rb +124 -0
  66. data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +111 -0
  67. data/plugins/rigor-hanami/lib/rigor-hanami.rb +3 -0
  68. data/plugins/rigor-hanami/sig/hanami_action.rbs +78 -0
  69. data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +302 -0
  70. data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +72 -0
  71. data/plugins/rigor-minitest/lib/rigor-minitest.rb +3 -0
  72. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb +194 -0
  73. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +140 -0
  74. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_index.rb +65 -0
  75. data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +130 -0
  76. data/plugins/rigor-pundit/lib/rigor-pundit.rb +3 -0
  77. data/plugins/rigor-rails/lib/rigor-rails.rb +31 -0
  78. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +277 -0
  79. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +108 -0
  80. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +138 -0
  81. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +167 -0
  82. data/plugins/rigor-rails-i18n/lib/rigor-rails-i18n.rb +3 -0
  83. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +161 -0
  84. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_table.rb +103 -0
  85. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +490 -0
  86. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +158 -0
  87. data/plugins/rigor-rails-routes/lib/rigor-rails-routes.rb +3 -0
  88. data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +163 -0
  89. data/plugins/rigor-rbs-inline/lib/rigor-rbs-inline.rb +24 -0
  90. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/analyzer.rb +110 -0
  91. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb +200 -0
  92. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_type_resolver.rb +170 -0
  93. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +233 -0
  94. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/scope_walker.rb +190 -0
  95. data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +188 -0
  96. data/plugins/rigor-rspec/lib/rigor-rspec.rb +3 -0
  97. data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/have_http_status_analyzer.rb +128 -0
  98. data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/http_status_codes.rb +60 -0
  99. data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +75 -0
  100. data/plugins/rigor-rspec-rails/lib/rigor-rspec-rails.rb +3 -0
  101. data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +266 -0
  102. data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb +113 -0
  103. data/plugins/rigor-shoulda-matchers/lib/rigor-shoulda-matchers.rb +3 -0
  104. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/analyzer.rb +152 -0
  105. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb +190 -0
  106. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb +61 -0
  107. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +124 -0
  108. data/plugins/rigor-sidekiq/lib/rigor-sidekiq.rb +3 -0
  109. data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +85 -0
  110. data/plugins/rigor-sinatra/lib/rigor-sinatra.rb +8 -0
  111. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +108 -0
  112. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +250 -0
  113. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +95 -0
  114. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +226 -0
  115. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/method_signature.rb +28 -0
  116. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +154 -0
  117. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +100 -0
  118. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +323 -0
  119. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +660 -0
  120. data/plugins/rigor-sorbet/lib/rigor-sorbet.rb +3 -0
  121. data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +209 -0
  122. data/plugins/rigor-statesman/lib/rigor-statesman.rb +8 -0
  123. data/plugins/rigor-typescript-utility-types/lib/rigor/plugin/typescript_utility_types.rb +163 -0
  124. data/plugins/rigor-typescript-utility-types/lib/rigor-typescript-utility-types.rb +9 -0
  125. metadata +149 -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"
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.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rigor contributors
@@ -476,6 +476,125 @@ files:
476
476
  - lib/rigor/type_node/symbol_literal.rb
477
477
  - lib/rigor/type_node/union.rb
478
478
  - lib/rigor/version.rb
479
+ - plugins/rigor-actioncable/lib/rigor-actioncable.rb
480
+ - plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb
481
+ - plugins/rigor-actioncable/lib/rigor/plugin/actioncable/analyzer.rb
482
+ - plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb
483
+ - plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb
484
+ - plugins/rigor-actionmailer/lib/rigor-actionmailer.rb
485
+ - plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb
486
+ - plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/analyzer.rb
487
+ - plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb
488
+ - plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb
489
+ - plugins/rigor-actionpack/lib/rigor-actionpack.rb
490
+ - plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb
491
+ - plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb
492
+ - plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb
493
+ - plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb
494
+ - plugins/rigor-activejob/lib/rigor-activejob.rb
495
+ - plugins/rigor-activejob/lib/rigor/plugin/activejob.rb
496
+ - plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb
497
+ - plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb
498
+ - plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb
499
+ - plugins/rigor-activerecord/lib/rigor-activerecord.rb
500
+ - plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb
501
+ - plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb
502
+ - plugins/rigor-activerecord/lib/rigor/plugin/activerecord/inflector.rb
503
+ - plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb
504
+ - plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb
505
+ - plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb
506
+ - plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_table.rb
507
+ - plugins/rigor-activerecord/sig/active_record/relation.rbs
508
+ - plugins/rigor-activestorage/lib/rigor-activestorage.rb
509
+ - plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb
510
+ - plugins/rigor-activestorage/lib/rigor/plugin/activestorage/analyzer.rb
511
+ - plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_discoverer.rb
512
+ - plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_index.rb
513
+ - plugins/rigor-activesupport-core-ext/lib/rigor-activesupport-core-ext.rb
514
+ - plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb
515
+ - plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs
516
+ - plugins/rigor-devise/lib/rigor-devise.rb
517
+ - plugins/rigor-devise/lib/rigor/plugin/devise.rb
518
+ - plugins/rigor-dry-schema/lib/rigor-dry-schema.rb
519
+ - plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema.rb
520
+ - plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb
521
+ - plugins/rigor-dry-struct/lib/rigor-dry-struct.rb
522
+ - plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb
523
+ - plugins/rigor-dry-types/lib/rigor-dry-types.rb
524
+ - plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb
525
+ - plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb
526
+ - plugins/rigor-dry-validation/lib/rigor-dry-validation.rb
527
+ - plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb
528
+ - plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/contract_scanner.rb
529
+ - plugins/rigor-dry-validation/sig/dry_validation.rbs
530
+ - plugins/rigor-factorybot/lib/rigor-factorybot.rb
531
+ - plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb
532
+ - plugins/rigor-factorybot/lib/rigor/plugin/factorybot/analyzer.rb
533
+ - plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb
534
+ - plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_index.rb
535
+ - plugins/rigor-graphql/lib/rigor-graphql.rb
536
+ - plugins/rigor-graphql/lib/rigor/plugin/graphql.rb
537
+ - plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb
538
+ - plugins/rigor-hanami/lib/rigor-hanami.rb
539
+ - plugins/rigor-hanami/lib/rigor/plugin/hanami.rb
540
+ - plugins/rigor-hanami/lib/rigor/plugin/hanami/action_checker.rb
541
+ - plugins/rigor-hanami/sig/hanami_action.rbs
542
+ - plugins/rigor-minitest/lib/rigor-minitest.rb
543
+ - plugins/rigor-minitest/lib/rigor/plugin/minitest.rb
544
+ - plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb
545
+ - plugins/rigor-pundit/lib/rigor-pundit.rb
546
+ - plugins/rigor-pundit/lib/rigor/plugin/pundit.rb
547
+ - plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb
548
+ - plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb
549
+ - plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_index.rb
550
+ - plugins/rigor-rails-i18n/lib/rigor-rails-i18n.rb
551
+ - plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb
552
+ - plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb
553
+ - plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb
554
+ - plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb
555
+ - plugins/rigor-rails-routes/lib/rigor-rails-routes.rb
556
+ - plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb
557
+ - plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb
558
+ - plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_table.rb
559
+ - plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb
560
+ - plugins/rigor-rails/lib/rigor-rails.rb
561
+ - plugins/rigor-rbs-inline/lib/rigor-rbs-inline.rb
562
+ - plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb
563
+ - plugins/rigor-rspec-rails/lib/rigor-rspec-rails.rb
564
+ - plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb
565
+ - plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/have_http_status_analyzer.rb
566
+ - plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/http_status_codes.rb
567
+ - plugins/rigor-rspec/lib/rigor-rspec.rb
568
+ - plugins/rigor-rspec/lib/rigor/plugin/rspec.rb
569
+ - plugins/rigor-rspec/lib/rigor/plugin/rspec/analyzer.rb
570
+ - plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb
571
+ - plugins/rigor-rspec/lib/rigor/plugin/rspec/let_type_resolver.rb
572
+ - plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb
573
+ - plugins/rigor-rspec/lib/rigor/plugin/rspec/scope_walker.rb
574
+ - plugins/rigor-shoulda-matchers/lib/rigor-shoulda-matchers.rb
575
+ - plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb
576
+ - plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb
577
+ - plugins/rigor-sidekiq/lib/rigor-sidekiq.rb
578
+ - plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb
579
+ - plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/analyzer.rb
580
+ - plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb
581
+ - plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb
582
+ - plugins/rigor-sinatra/lib/rigor-sinatra.rb
583
+ - plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb
584
+ - plugins/rigor-sorbet/lib/rigor-sorbet.rb
585
+ - plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb
586
+ - plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb
587
+ - plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb
588
+ - plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb
589
+ - plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb
590
+ - plugins/rigor-sorbet/lib/rigor/plugin/sorbet/method_signature.rb
591
+ - plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb
592
+ - plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb
593
+ - plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb
594
+ - plugins/rigor-statesman/lib/rigor-statesman.rb
595
+ - plugins/rigor-statesman/lib/rigor/plugin/statesman.rb
596
+ - plugins/rigor-typescript-utility-types/lib/rigor-typescript-utility-types.rb
597
+ - plugins/rigor-typescript-utility-types/lib/rigor/plugin/typescript_utility_types.rb
479
598
  - sig/rigor.rbs
480
599
  - sig/rigor/analysis/baseline.rbs
481
600
  - sig/rigor/analysis/check_rules/always_truthy_condition_collector.rbs
@@ -524,6 +643,35 @@ metadata:
524
643
  rdoc_options: []
525
644
  require_paths:
526
645
  - lib
646
+ - plugins/rigor-actioncable/lib
647
+ - plugins/rigor-actionmailer/lib
648
+ - plugins/rigor-actionpack/lib
649
+ - plugins/rigor-activejob/lib
650
+ - plugins/rigor-activerecord/lib
651
+ - plugins/rigor-activestorage/lib
652
+ - plugins/rigor-activesupport-core-ext/lib
653
+ - plugins/rigor-devise/lib
654
+ - plugins/rigor-dry-schema/lib
655
+ - plugins/rigor-dry-struct/lib
656
+ - plugins/rigor-dry-types/lib
657
+ - plugins/rigor-dry-validation/lib
658
+ - plugins/rigor-factorybot/lib
659
+ - plugins/rigor-graphql/lib
660
+ - plugins/rigor-hanami/lib
661
+ - plugins/rigor-minitest/lib
662
+ - plugins/rigor-pundit/lib
663
+ - plugins/rigor-rails/lib
664
+ - plugins/rigor-rails-i18n/lib
665
+ - plugins/rigor-rails-routes/lib
666
+ - plugins/rigor-rbs-inline/lib
667
+ - plugins/rigor-rspec/lib
668
+ - plugins/rigor-rspec-rails/lib
669
+ - plugins/rigor-shoulda-matchers/lib
670
+ - plugins/rigor-sidekiq/lib
671
+ - plugins/rigor-sinatra/lib
672
+ - plugins/rigor-sorbet/lib
673
+ - plugins/rigor-statesman/lib
674
+ - plugins/rigor-typescript-utility-types/lib
527
675
  required_ruby_version: !ruby/object:Gem::Requirement
528
676
  requirements:
529
677
  - - ">="