docscribe 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -28,7 +28,15 @@ module Docscribe
28
28
  # Emit the header line:
29
29
  #
30
30
  # +MyClass#my_method+ -> ReturnType
31
- header: true
31
+ header: false
32
+
33
+ # Whether to include the default placeholder line:
34
+ # # Method documentation.
35
+ include_default_message: true
36
+
37
+ # Whether to append placeholder text to generated @param tags:
38
+ # # @param [String] name Param documentation.
39
+ include_param_documentation: true
32
40
 
33
41
  # Emit @param tags.
34
42
  param_tags: true
@@ -129,6 +137,18 @@ module Docscribe
129
137
  include: []
130
138
  exclude: ["spec"]
131
139
 
140
+ plugins:
141
+ # Load custom plugins by path or gem name.
142
+ #
143
+ # Each entry is passed to `require`. Registration happens inside
144
+ # the required file via Docscribe::Plugin::Registry.register.
145
+ #
146
+ # Example:
147
+ # require:
148
+ # - ./docscribe_plugins
149
+ # - docscribe-rails-associations
150
+ require: []
151
+
132
152
  rbs:
133
153
  # Optional: use RBS signatures to improve @param / @return types.
134
154
  #
@@ -147,6 +167,11 @@ module Docscribe
147
167
  # - Hash<Symbol, String> => Hash
148
168
  # - Array<Integer> => Array
149
169
  collapse_generics: false
170
+ # Auto-discover RBS collection from rbs_collection.lock.yaml.
171
+ # Equivalent to --rbs-collection CLI flag.
172
+ # Requires `bundle exec rbs collection install` to have been run.
173
+ #
174
+ collection: false
150
175
 
151
176
  sorbet:
152
177
  # Optional: use Sorbet signatures from inline `sig` declarations and
@@ -33,3 +33,4 @@ require_relative 'config/filtering'
33
33
  require_relative 'config/rbs'
34
34
  require_relative 'config/sorting'
35
35
  require_relative 'config/sorbet'
36
+ require_relative 'config/plugin'
@@ -56,8 +56,11 @@ module Docscribe
56
56
  # @param [Parser::AST::Node] node `:def` or `:defs` node
57
57
  # @param [String] fallback_type type used when inference is uncertain
58
58
  # @param [Boolean] nil_as_optional whether `nil` unions should be rendered as optional types
59
+ # @param [nil] core_rbs_provider Param documentation.
60
+ # @param [nil] param_types Param documentation.
59
61
  # @return [Hash]
60
- def returns_spec_from_node(node, fallback_type: FALLBACK_TYPE, nil_as_optional: true)
62
+ def returns_spec_from_node(node, fallback_type: FALLBACK_TYPE, nil_as_optional: true, core_rbs_provider: nil,
63
+ param_types: nil)
61
64
  body =
62
65
  case node.type
63
66
  when :def then node.children[2]
@@ -70,7 +73,8 @@ module Docscribe
70
73
  if body.type == :rescue
71
74
  main_body = body.children[0]
72
75
  spec[:normal] =
73
- last_expr_type(main_body, fallback_type: fallback_type, nil_as_optional: nil_as_optional) || FALLBACK_TYPE
76
+ last_expr_type(main_body, fallback_type: fallback_type, nil_as_optional: nil_as_optional,
77
+ core_rbs_provider: core_rbs_provider, param_types: param_types) || FALLBACK_TYPE
74
78
 
75
79
  body.children.each do |ch|
76
80
  next unless ch.is_a?(Parser::AST::Node) && ch.type == :resbody
@@ -78,13 +82,15 @@ module Docscribe
78
82
  exc_list, _asgn, rescue_body = *ch
79
83
  exc_names = Raises.exception_names_from_rescue_list(exc_list)
80
84
  rtype =
81
- last_expr_type(rescue_body, fallback_type: fallback_type, nil_as_optional: nil_as_optional) ||
85
+ last_expr_type(rescue_body, fallback_type: fallback_type, nil_as_optional: nil_as_optional,
86
+ core_rbs_provider: core_rbs_provider, param_types: param_types) ||
82
87
  fallback_type
83
88
  spec[:rescues] << [exc_names, rtype]
84
89
  end
85
90
  else
86
91
  spec[:normal] =
87
- last_expr_type(body, fallback_type: fallback_type, nil_as_optional: nil_as_optional) || FALLBACK_TYPE
92
+ last_expr_type(body, fallback_type: fallback_type, nil_as_optional: nil_as_optional,
93
+ core_rbs_provider: core_rbs_provider, param_types: param_types) || FALLBACK_TYPE
88
94
  end
89
95
 
90
96
  spec
@@ -98,30 +104,38 @@ module Docscribe
98
104
  # - `case` expressions
99
105
  # - explicit `return`
100
106
  # - literal-like expressions via {Literals.type_from_literal}
107
+ # - method calls with RBS core type lookup
101
108
  #
102
109
  # @note module_function: when included, also defines #last_expr_type (instance visibility: private)
103
110
  # @param [Parser::AST::Node, nil] node expression node
104
111
  # @param [String] fallback_type type used when inference is uncertain
105
112
  # @param [Boolean] nil_as_optional whether `nil` unions should be rendered as optional types
113
+ # @param [Object, nil] core_rbs_provider optional RBS provider for core type lookup
114
+ # @param [Hash, nil] param_types parameter name -> type map for lvar resolution
106
115
  # @return [String, nil]
107
- def last_expr_type(node, fallback_type:, nil_as_optional:)
116
+ def last_expr_type(node, fallback_type:, nil_as_optional:, core_rbs_provider: nil, param_types: nil)
108
117
  return nil unless node
109
118
 
110
119
  case node.type
111
120
  when :begin
112
- last_expr_type(node.children.last, fallback_type: fallback_type, nil_as_optional: nil_as_optional)
121
+ last_expr_type(node.children.last, fallback_type: fallback_type, nil_as_optional: nil_as_optional,
122
+ core_rbs_provider: core_rbs_provider, param_types: param_types)
113
123
 
114
124
  when :if
115
- t = last_expr_type(node.children[1], fallback_type: fallback_type, nil_as_optional: nil_as_optional)
116
- e = last_expr_type(node.children[2], fallback_type: fallback_type, nil_as_optional: nil_as_optional)
125
+ t = last_expr_type(node.children[1], fallback_type: fallback_type, nil_as_optional: nil_as_optional,
126
+ core_rbs_provider: core_rbs_provider, param_types: param_types)
127
+ e = last_expr_type(node.children[2], fallback_type: fallback_type, nil_as_optional: nil_as_optional,
128
+ core_rbs_provider: core_rbs_provider, param_types: param_types)
117
129
  unify_types(t, e, fallback_type: fallback_type, nil_as_optional: nil_as_optional)
118
130
 
119
131
  when :case
120
132
  branches = node.children[1..].compact.flat_map do |child|
121
133
  if child.type == :when
122
- last_expr_type(child.children.last, fallback_type: fallback_type, nil_as_optional: nil_as_optional)
134
+ last_expr_type(child.children.last, fallback_type: fallback_type, nil_as_optional: nil_as_optional,
135
+ core_rbs_provider: core_rbs_provider, param_types: param_types)
123
136
  else
124
- last_expr_type(child, fallback_type: fallback_type, nil_as_optional: nil_as_optional)
137
+ last_expr_type(child, fallback_type: fallback_type, nil_as_optional: nil_as_optional,
138
+ core_rbs_provider: core_rbs_provider, param_types: param_types)
125
139
  end
126
140
  end.compact
127
141
 
@@ -136,11 +150,58 @@ module Docscribe
136
150
  when :return
137
151
  Literals.type_from_literal(node.children.first, fallback_type: fallback_type)
138
152
 
153
+ when :send
154
+ recv = node.children[0]
155
+ meth = node.children[1]
156
+
157
+ # Try to resolve return type from RBS core for method calls
158
+ if core_rbs_provider && recv&.type == :send
159
+ # Chained call: arg.to_i.positive?
160
+ inner_type = last_expr_type(recv, fallback_type: nil, nil_as_optional: false,
161
+ core_rbs_provider: core_rbs_provider, param_types: param_types)
162
+ if inner_type
163
+ rbs_type = resolve_rbs_return_type(inner_type, meth, core_rbs_provider)
164
+ return rbs_type unless rbs_type == FALLBACK_TYPE
165
+ end
166
+ elsif core_rbs_provider && recv&.type == :lvar
167
+ # Direct call: arg.positive?
168
+ lvar_name = recv.children.first
169
+ if lvar_name && param_types
170
+ recv_type = param_types[lvar_name.to_s]
171
+ if recv_type
172
+ rbs_type = resolve_rbs_return_type(recv_type, meth, core_rbs_provider)
173
+ return rbs_type unless rbs_type == FALLBACK_TYPE
174
+ end
175
+ end
176
+ end
177
+
178
+ Literals.type_from_literal(node, fallback_type: fallback_type)
179
+
139
180
  else
140
181
  Literals.type_from_literal(node, fallback_type: fallback_type)
141
182
  end
142
183
  end
143
184
 
185
+ # Resolve a return type from core RBS for a method call.
186
+ #
187
+ # @note module_function: when included, also defines #resolve_rbs_return_type (instance visibility: private)
188
+ # @private
189
+ # @param [String] container_type e.g. "Numeric", "String"
190
+ # @param [Symbol] method_name e.g. :positive?
191
+ # @param [Object, nil] core_rbs_provider RBS provider
192
+ # @return [String] FALLBACK_TYPE if lookup fails
193
+ def resolve_rbs_return_type(container_type, method_name, core_rbs_provider)
194
+ return FALLBACK_TYPE unless core_rbs_provider
195
+
196
+ sig = core_rbs_provider.signature_for(
197
+ container: container_type,
198
+ scope: :instance,
199
+ name: method_name
200
+ )
201
+
202
+ sig&.return_type || FALLBACK_TYPE
203
+ end
204
+
144
205
  # Unify two inferred types into a single type string.
145
206
  #
146
207
  # Rules:
@@ -93,12 +93,17 @@ module Docscribe
93
93
  # @param [Parser::AST::Node] node
94
94
  # @param [String] fallback_type
95
95
  # @param [Boolean] nil_as_optional
96
+ # @param [nil] core_rbs_provider Param documentation.
97
+ # @param [nil] param_types Param documentation.
96
98
  # @return [Hash]
97
- def returns_spec_from_node(node, fallback_type: FALLBACK_TYPE, nil_as_optional: true)
99
+ def returns_spec_from_node(node, fallback_type: FALLBACK_TYPE, nil_as_optional: true, core_rbs_provider: nil,
100
+ param_types: nil)
98
101
  Returns.returns_spec_from_node(
99
102
  node,
100
103
  fallback_type: fallback_type,
101
- nil_as_optional: nil_as_optional
104
+ nil_as_optional: nil_as_optional,
105
+ core_rbs_provider: core_rbs_provider,
106
+ param_types: param_types
102
107
  )
103
108
  end
104
109