docscribe 1.4.0 → 1.4.2

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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +194 -8
  3. data/lib/docscribe/cli/config_builder.rb +125 -35
  4. data/lib/docscribe/cli/generate.rb +288 -117
  5. data/lib/docscribe/cli/init.rb +49 -13
  6. data/lib/docscribe/cli/options.rb +303 -127
  7. data/lib/docscribe/cli/run.rb +391 -135
  8. data/lib/docscribe/cli.rb +23 -5
  9. data/lib/docscribe/config/defaults.rb +11 -11
  10. data/lib/docscribe/config/emit.rb +1 -0
  11. data/lib/docscribe/config/filtering.rb +24 -11
  12. data/lib/docscribe/config/loader.rb +7 -4
  13. data/lib/docscribe/config/plugin.rb +1 -0
  14. data/lib/docscribe/config/rbs.rb +31 -22
  15. data/lib/docscribe/config/sorbet.rb +41 -15
  16. data/lib/docscribe/config/sorting.rb +1 -0
  17. data/lib/docscribe/config/template.rb +1 -0
  18. data/lib/docscribe/config/utils.rb +3 -2
  19. data/lib/docscribe/config.rb +1 -0
  20. data/lib/docscribe/infer/constants.rb +15 -0
  21. data/lib/docscribe/infer/literals.rb +43 -25
  22. data/lib/docscribe/infer/names.rb +24 -15
  23. data/lib/docscribe/infer/params.rb +52 -6
  24. data/lib/docscribe/infer/raises.rb +24 -14
  25. data/lib/docscribe/infer/returns.rb +365 -182
  26. data/lib/docscribe/infer.rb +10 -9
  27. data/lib/docscribe/inline_rewriter/collector.rb +766 -375
  28. data/lib/docscribe/inline_rewriter/doc_block.rb +217 -74
  29. data/lib/docscribe/inline_rewriter/doc_builder.rb +1495 -583
  30. data/lib/docscribe/inline_rewriter/source_helpers.rb +100 -52
  31. data/lib/docscribe/inline_rewriter/tag_sorter.rb +109 -48
  32. data/lib/docscribe/inline_rewriter.rb +1052 -457
  33. data/lib/docscribe/plugin/base/collector_plugin.rb +2 -3
  34. data/lib/docscribe/plugin/base/tag_plugin.rb +1 -1
  35. data/lib/docscribe/plugin/registry.rb +34 -7
  36. data/lib/docscribe/plugin.rb +48 -17
  37. data/lib/docscribe/types/rbs/collection_loader.rb +0 -1
  38. data/lib/docscribe/types/rbs/provider.rb +75 -26
  39. data/lib/docscribe/types/rbs/type_formatter.rb +127 -59
  40. data/lib/docscribe/types/sorbet/base_provider.rb +31 -12
  41. data/lib/docscribe/version.rb +1 -1
  42. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 50c74b921731749cbf32726e24e557e526e1f65966e704171a652d10cc4ce945
4
- data.tar.gz: 2e254911cf9d81f5d5f7b5df29576c3c5c3c3f0433cfb387c0d22c1ce30eeb60
3
+ metadata.gz: 5b6ff6ead507182a9530fa2f2cc690d435448284f9212f4fbeea3950dddf40c3
4
+ data.tar.gz: 17e3285caddd09bda308e89f5cb1eb4579d8f96855177f81dbe459b7ad84e9d4
5
5
  SHA512:
6
- metadata.gz: 824133cf33505568edc84fe99bd51ced4451616552b2ba33e5584fcbd68bdd2ede0e4df365510a4e6be73ef9bf191a66e37746a5331e2ccb8abae2a80a3f69b4
7
- data.tar.gz: 6662f828e5d324c226432df0e00359a36a97cd47dfeedefd4ead014752fbebe51b93e6cb693d6a342ca3d7e24683b74c189576792e558bf12e28bcc6365e2ed2
6
+ metadata.gz: d7a764fb2d297c1449995727c7d79704db934df7a52f2f2475d21fc6b29c60ea8908fc7ebb560592a3ad6de4d1384937ce75836cbce3e7899eef5918f05e6ab9
7
+ data.tar.gz: 8ab0b426a364eb5dfe823370148b2e2e9e93ad1f2e788bda9143533aa139821c2d159351255a86d8dd739b647572168e4c539e5764e6d562cc6cf7ea9b79acd2
data/README.md CHANGED
@@ -44,6 +44,8 @@ Common workflows:
44
44
  * [Contents](#contents)
45
45
  * [Installation](#installation)
46
46
  * [Quick start](#quick-start)
47
+ * [Architecture](#architecture)
48
+ * [Data flow](#data-flow)
47
49
  * [CLI](#cli)
48
50
  * [Options](#options)
49
51
  * [Examples](#examples)
@@ -68,7 +70,10 @@ Common workflows:
68
70
  * [Plugin system](#plugin-system)
69
71
  * [TagPlugin](#tagplugin)
70
72
  * [CollectorPlugin](#collectorplugin)
73
+ * [Plugin doc normalization (CollectorPlugin)](#plugin-doc-normalization-collectorplugin)
74
+ * [`method_override` (structured patch)](#method_override-structured-patch)
71
75
  * [Registering plugins](#registering-plugins)
76
+ * [Plugin priority](#plugin-priority)
72
77
  * [Idempotency](#idempotency)
73
78
  * [Plugin examples](#plugin-examples)
74
79
  * [Configuration](#configuration)
@@ -83,6 +88,8 @@ Common workflows:
83
88
  * [Generate a plugin skeleton](#generate-a-plugin-skeleton)
84
89
  * [CI integration](#ci-integration)
85
90
  * [Comparison to YARD's parser](#comparison-to-yards-parser)
91
+ * [Mermaid Architecture Reference](#mermaid-architecture-reference)
92
+ * [Data flow](#data-flow)
86
93
  * [Limitations](#limitations)
87
94
  * [Roadmap](#roadmap)
88
95
  * [Contributing](#contributing)
@@ -201,6 +208,151 @@ end
201
208
  > - Class methods show with a dot (`+Demo.bump+`, `+Demo.internal+`).
202
209
  > - Methods inside `class << self` under `private` are marked `@private`.
203
210
 
211
+ ## Architecture
212
+
213
+ Docscribe is organized into seven subsystems. The CLI layer receives user input and orchestrates configuration loading,
214
+ then delegates to the core engine which parses source code, collects methods (using an AST walker), builds YARD doc
215
+ lines — combining heuristic type inference, external RBS/Sorbet signatures, and plugin output — and finally rewrites the
216
+ source via a strategy (safe merge or aggressive replace).
217
+
218
+ ```mermaid
219
+ flowchart TB
220
+ subgraph CLI["CLI Layer"]
221
+ Exe["exe/docscribe\nEntry point"]
222
+ Run["CLI::Run\nMain execution\n· expand paths\n· iterate files\n· report results"]
223
+ Options["CLI::Options\nARGV parsing\n(mode, strategy,\nfilters, flags)"]
224
+ InitCmd["CLI::Init\ndocscribe init\nGenerate config"]
225
+ GenCmd["CLI::Generate\ndocscribe generate\nScaffold plugins"]
226
+ ConfigBuilder["CLI::ConfigBuilder\nApply CLI overrides\nto config"]
227
+ end
228
+
229
+ subgraph Config["Configuration"]
230
+ ConfigClass["Config\nCentral config object\n· raw hash\n· query methods"]
231
+ Defaults["config/defaults.rb\nDEFAULT hash"]
232
+ Loader["config/loader.rb\nYAML loading\n+ deep merge"]
233
+ Emit["config/emit.rb\nEmission toggles\n(header, tags, etc.)"]
234
+ Filtering["config/filtering.rb\nFile/method\ninclude/exclude"]
235
+ RBSConfig["config/rbs.rb\nRBS provider\nfactory"]
236
+ SorbetConfig["config/sorbet.rb\nSorbet provider\nchain factory"]
237
+ PluginConfig["config/plugin.rb\nPlugin loading\nfrom YAML"]
238
+ end
239
+
240
+ subgraph Parsing["Parsing"]
241
+ ParsingModule["Parsing\nBackend selection\n(:parser / :prism)"]
242
+ ParserGem["Parser gem\n(whitequark/parser)"]
243
+ Prism["Prism translator\n(Ruby 3.4+)"]
244
+ end
245
+
246
+ subgraph Core["Core Engine"]
247
+ InlineRewriter["InlineRewriter\n· parse → collect\n· deduplicate → dispatch\n· rewrite"]
248
+ Collector["Collector\n< Parser::AST::Processor\nAST walker\n· find methods/attrs\n· track visibility\n· track containers"]
249
+ DocBuilder["DocBuilder\nGenerate YARD doc lines\n· combine inference\n· external signatures\n· plugin tags"]
250
+ DocBlock["DocBlock\nSafe strategy:\nparse → merge → sort\nexisting doc blocks"]
251
+ SourceHelpers["SourceHelpers\nPosition/range\nutilities"]
252
+ end
253
+
254
+ subgraph Infer["Inference Engine"]
255
+ InferModule["Infer\nEntry point"]
256
+ Params["Infer::Params\nParameter type\nfrom name + default"]
257
+ Returns["Infer::Returns\nReturn type\nfrom method body"]
258
+ Raises["Infer::Raises\n@raise tags\nfrom raise/rescue"]
259
+ Literals["Infer::Literals\nAST literal →\ntype string"]
260
+ Names["Infer::Names\n:const node →\nFQN string"]
261
+ ASTWalk["Infer::ASTWalk\nRecursive DFS\nAST traversal"]
262
+ end
263
+
264
+ subgraph Plugins["Plugin System"]
265
+ PluginModule["Plugin\nTag/Collector\ndispatch"]
266
+ Registry["Plugin::Registry\nGlobal registry\n· register → route\n· tag_entries\n· collector_entries"]
267
+ TagPlugin["Base::TagPlugin\nOverride #call(context)\n→ Array<Tag>"]
268
+ CollectorPlugin["Base::CollectorPlugin\nOverride #collect(ast, buffer)\n→ Array<Hash>"]
269
+ TagValue["Plugin::Tag\nStruct (name, text, types)"]
270
+ Context["Plugin::Context\nMethod snapshot struct"]
271
+ end
272
+
273
+ subgraph Types["External Type System"]
274
+ ProviderChain["ProviderChain\nComposite:\nquery in order\nfirst match wins"]
275
+ RBSProvider["RBS::Provider\n.rbs files\n→ RBS lib"]
276
+ RBSFormatter["RBS::TypeFormatter\nRBS type →\nYARD type string"]
277
+ RBSCollection["RBS::CollectionLoader\nrbs_collection\n.lock.yaml"]
278
+ SorbetBase["Sorbet::BaseProvider\nRBS::Prototype::RBI\nbridge"]
279
+ SorbetSource["Sorbet::SourceProvider\nInline sig{}\ndeclarations"]
280
+ SorbetRBI["Sorbet::RBIProvider\n.rbi files\ndirectories"]
281
+ end
282
+
283
+ Exe --> Run
284
+ Run --> Options
285
+ Run --> InitCmd
286
+ Run --> GenCmd
287
+ Run --> ConfigBuilder
288
+ ConfigBuilder --> ConfigClass
289
+ ConfigClass --> Defaults
290
+ ConfigClass --> Loader
291
+ ConfigClass --> Emit
292
+ ConfigClass --> Filtering
293
+ ConfigClass --> RBSConfig
294
+ ConfigClass --> SorbetConfig
295
+ ConfigClass --> PluginConfig
296
+ Run --> InlineRewriter
297
+ InlineRewriter --> ParsingModule
298
+ ParsingModule --> ParserGem
299
+ ParsingModule --> Prism
300
+ InlineRewriter --> Collector
301
+ Collector --> PluginModule
302
+ PluginModule --> Registry
303
+ Registry --> CollectorPlugin
304
+ InlineRewriter --> DocBuilder
305
+ DocBuilder --> InferModule
306
+ InferModule --> Params
307
+ InferModule --> Returns
308
+ InferModule --> Raises
309
+ Params --> Literals
310
+ Returns --> Literals
311
+ Raises --> ASTWalk
312
+ Raises --> Names
313
+ DocBuilder --> ProviderChain
314
+ ProviderChain --> SorbetSource
315
+ ProviderChain --> SorbetRBI
316
+ ProviderChain --> RBSProvider
317
+ SorbetSource --> SorbetBase
318
+ SorbetRBI --> SorbetBase
319
+ RBSProvider --> RBSFormatter
320
+ RBSProvider --> RBSCollection
321
+ DocBuilder --> PluginModule
322
+ PluginModule --> Registry
323
+ Registry --> TagPlugin
324
+ TagPlugin --> TagValue
325
+ TagPlugin --> Context
326
+ InlineRewriter --> DocBlock
327
+ InlineRewriter --> SourceHelpers
328
+ ```
329
+
330
+ ### Data flow
331
+
332
+ ```mermaid
333
+ flowchart LR
334
+ Input["Source files\n(.rb)"] --> Parse["Parsing.parse_buffer\nParser gem / Prism"]
335
+ Parse --> AST["AST + Comments"]
336
+ AST --> Collect["Collector.process\n· Find methods\n· Track visibility\n· Find attr_*"]
337
+ AST --> CollectPlugins["CollectorPlugin#collect\n· Custom AST walks\n· Non-standard constructs"]
338
+ Collect --> Insertions["Insertion list\n(sorted by position)"]
339
+ CollectPlugins --> Insertions
340
+ Insertions --> Dedup["Deduplicate\n(override by position)"]
341
+ Dedup --> Build["DocBuilder.build_doc_lines\nper insertion"]
342
+ Build --> Infer["Infer params / returns / raises\n(heuristic fallback)"]
343
+ Build --> SigQuery["ProviderChain\nquery external types"]
344
+ Build --> TagPlugins["TagPlugin#call\n(add extra @tags)"]
345
+ Infer --> ResultDoc["Generated YARD doc block"]
346
+ SigQuery --> ResultDoc
347
+ TagPlugins --> ResultDoc
348
+ ResultDoc --> Strategy{"Strategy?"}
349
+ Strategy -->|Safe| Merge["DocBlock.merge\npreserve + append + sort"]
350
+ Strategy -->|Aggressive| Replace["Replace entirely"]
351
+ Merge --> Rewritten["Rewriter#process\n→ rewritten source"]
352
+ Replace --> Rewritten
353
+ Rewritten --> Output["Modified .rb file\n/ STDOUT"]
354
+ ```
355
+
204
356
  ## CLI
205
357
 
206
358
  ```shell
@@ -865,17 +1017,49 @@ class DefineMethodPlugin < Docscribe::Plugin::Base::CollectorPlugin
865
1017
  end
866
1018
  ```
867
1019
 
868
- Each result hash must have:
1020
+ Each result hash must have `:anchor_node` plus either `:doc` or `:method_override`:
869
1021
 
870
- | Key | Type | Description |
871
- |----------------|---------------------|--------------------------------------------|
872
- | `:anchor_node` | `Parser::AST::Node` | Node above which to insert the doc block |
873
- | `:doc` | `String` | Complete doc block text including newlines |
1022
+ | Key | Type | Description |
1023
+ |--------------------|---------------------|-------------------------------------------------------------------------------------------------------------------------|
1024
+ | `:anchor_node` | `Parser::AST::Node` | Node above which to insert the doc block |
1025
+ | `:doc` | `String` | Complete doc block text including newlines (Docscribe may normalize indentation and default message for method anchors) |
1026
+ | `:method_override` | `Hash` | Structured overrides that patch the standard DocBuilder output instead of replacing it (see below) |
874
1027
 
875
1028
  > [!NOTE]
876
1029
  > You do not need to handle indentation manually. Docscribe reads the indentation from `anchor_node` and applies it to
877
1030
  > every line of `:doc` automatically.
878
1031
 
1032
+ #### Plugin doc normalization (CollectorPlugin)
1033
+
1034
+ When returning `doc:`, CollectorPlugins provide raw strings that Docscribe inserts without running the standard
1035
+ method DocBuilder pipeline. Docscribe does normalize indentation and may prepend the default method message for
1036
+ `def/defs` anchors, but headers (`emit.header`) and param/return tags must be included explicitly.
1037
+
1038
+ #### `method_override` (structured patch)
1039
+
1040
+ When a CollectorPlugin targets a `def` method, it can return `method_override:` instead of `doc:` to patch the
1041
+ standard DocBuilder output rather than replace it entirely:
1042
+
1043
+ ```ruby
1044
+ {
1045
+ anchor_node: node,
1046
+ method_override: {
1047
+ return_type: 'ActiveRecord::Relation', # overrides @return
1048
+ param_types: { 'period' => 'Integer' }, # merges into @param types
1049
+ tags: [Docscribe::Plugin::Tag.new(name: 'since', text: '2.0')] # additional tags
1050
+ }
1051
+ }
1052
+ ```
1053
+
1054
+ | Key | Type | Description |
1055
+ |----------------|------------------------|-------------------------------------------------------------|
1056
+ | `:return_type` | `String` | Overrides the `@return` type name |
1057
+ | `:param_types` | `Hash{String=>String}` | Merges into inferred param types (external sig wins) |
1058
+ | `:tags` | `Array<Tag/Hash>` | Tags appended to the doc block (Hash auto-converted to Tag) |
1059
+
1060
+ `method_override` merges at the data level before rendering, so the standard pipeline still generates headers,
1061
+ `@param` tags, default messages, and tag sorting. Only the specified fields are overridden.
1062
+
879
1063
  ### Registering plugins
880
1064
 
881
1065
  Plugins are registered at load time. The recommended pattern is to put registrations in a dedicated file and reference
@@ -932,9 +1116,11 @@ Higher number means higher priority.
932
1116
 
933
1117
  **CollectorPlugin priority (conflicts at the same source position):**
934
1118
 
935
- - If a plugin insertion and a standard *method* insertion share the same source position (
936
- `anchor_node.loc.expression.begin_pos`), the standard insertion is dropped and the plugin insertion is kept.
937
- - If multiple CollectorPlugins insert at the same source position, only insertions from the highest-priority plugin(s)
1119
+ - For `doc:` insertions: if a plugin insertion and a standard *method* insertion share the same source position
1120
+ (`anchor_node.loc.expression.begin_pos`), the standard insertion is dropped and the plugin insertion is kept.
1121
+ - For `method_override:` insertions: the method insertion is kept and patched with the override data. The standard
1122
+ DocBuilder pipeline still runs (generating `@param`, headers, etc.), and only the specified fields are overridden.
1123
+ - If multiple CollectorPlugins target the same source position, only insertions from the highest-priority plugin(s)
938
1124
  are kept (ties are kept).
939
1125
  - Multiple insertions from the winning plugin(s) at the same position are preserved (e.g. one `@!attribute` per column).
940
1126
 
@@ -4,6 +4,7 @@ require 'docscribe/config'
4
4
 
5
5
  module Docscribe
6
6
  module CLI
7
+ # Build and override effective config from CLI flags.
7
8
  module ConfigBuilder
8
9
  module_function
9
10
 
@@ -21,53 +22,142 @@ module Docscribe
21
22
  # @param [Hash] options parsed CLI options
22
23
  # @return [Docscribe::Config] merged effective config
23
24
  def build(base, options)
24
- needs_override =
25
- options[:include].any? ||
25
+ return base unless needs_override?(options)
26
+
27
+ raw = Marshal.load(Marshal.dump(base.raw))
28
+ apply_filter_overrides(raw, options)
29
+ apply_rbs_overrides(raw, options) if options[:rbs] || options[:rbs_collection] || options[:sig_dirs].any?
30
+ apply_sorbet_overrides(raw, options) if options[:sorbet] || options[:rbi_dirs].any?
31
+ Docscribe::Config.new(raw)
32
+ end
33
+
34
+ # Whether any CLI override is present.
35
+ #
36
+ # @note module_function: when included, also defines # (instance visibility: private)
37
+ # @private
38
+ # @param [Hash] options parsed CLI options
39
+ # @return [Boolean]
40
+ def needs_override?(options)
41
+ filter_overrides?(options) ||
42
+ rbs_overrides?(options) ||
43
+ sorbet_overrides?(options)
44
+ end
45
+
46
+ # Whether any method or file filter CLI options were provided.
47
+ #
48
+ # @note module_function: when included, also defines #filter_overrides? (instance visibility: private)
49
+ # @param [Hash] options parsed CLI options
50
+ # @return [Boolean]
51
+ def filter_overrides?(options)
52
+ options[:include].any? ||
26
53
  options[:exclude].any? ||
27
54
  options[:include_file].any? ||
28
- options[:exclude_file].any? ||
29
- options[:rbs] ||
30
- options[:rbs_collection] ||
31
- options[:sig_dirs].any? ||
32
- options[:sorbet] ||
33
- options[:rbi_dirs].any?
55
+ options[:exclude_file].any?
56
+ end
34
57
 
35
- return base unless needs_override
58
+ # Whether any RBS-related CLI options were provided.
59
+ #
60
+ # @note module_function: when included, also defines #rbs_overrides? (instance visibility: private)
61
+ # @param [Hash] options parsed CLI options
62
+ # @return [Boolean]
63
+ def rbs_overrides?(options)
64
+ options[:rbs] ||
65
+ options[:rbs_collection] ||
66
+ options[:sig_dirs].any?
67
+ end
36
68
 
37
- raw = Marshal.load(Marshal.dump(base.raw))
69
+ # Whether any Sorbet-related CLI options were provided.
70
+ #
71
+ # @note module_function: when included, also defines #sorbet_overrides? (instance visibility: private)
72
+ # @param [Hash] options parsed CLI options
73
+ # @return [Boolean]
74
+ def sorbet_overrides?(options)
75
+ options[:sorbet] ||
76
+ options[:rbi_dirs].any?
77
+ end
78
+
79
+ # Apply method and file filter overrides to the raw config.
80
+ #
81
+ # @note module_function: when included, also defines # (instance visibility: private)
82
+ # @private
83
+ # @param [Hash] raw raw config hash
84
+ # @param [Hash] options parsed CLI options
85
+ # @return [void]
86
+ def apply_filter_overrides(raw, options)
87
+ apply_method_filters(raw, options)
88
+ apply_file_filters(raw, options)
89
+ end
38
90
 
91
+ # Merge CLI method include/exclude patterns into the raw config hash.
92
+ #
93
+ # @note module_function: when included, also defines #apply_method_filters (instance visibility: private)
94
+ # @param [Hash] raw raw config hash
95
+ # @param [Hash] options parsed CLI options
96
+ # @return [void]
97
+ def apply_method_filters(raw, options)
39
98
  raw['filter'] ||= {}
40
99
  raw['filter']['include'] = Array(raw['filter']['include']) + options[:include]
41
100
  raw['filter']['exclude'] = Array(raw['filter']['exclude']) + options[:exclude]
101
+ end
42
102
 
43
- raw['filter']['files'] ||= {}
44
- raw['filter']['files']['include'] = Array(raw['filter']['files']['include']) + options[:include_file]
45
- raw['filter']['files']['exclude'] = Array(raw['filter']['files']['exclude']) + options[:exclude_file]
46
-
47
- if options[:rbs] || options[:rbs_collection] || options[:sig_dirs].any?
48
- raw['rbs'] ||= {}
49
- raw['rbs']['enabled'] = true
50
- raw['rbs']['sig_dirs'] = Array(raw['rbs']['sig_dirs']) + options[:sig_dirs] if options[:sig_dirs].any?
51
-
52
- if options[:rbs_collection]
53
- require 'docscribe/types/rbs/collection_loader'
54
- collection_path = Docscribe::Types::RBS::CollectionLoader.resolve
55
- if collection_path
56
- raw['rbs']['collection_dirs'] = Array(raw['rbs']['collection_dirs']) + [collection_path]
57
- else
58
- warn 'Docscribe: rbs_collection.lock.yaml not found or collection not installed. ' \
59
- 'Run `bundle exec rbs collection install` first.'
60
- end
61
- end
62
- end
103
+ # Merge CLI file include/exclude patterns into the raw config hash.
104
+ #
105
+ # @note module_function: when included, also defines #apply_file_filters (instance visibility: private)
106
+ # @param [Hash] raw raw config hash
107
+ # @param [Hash] options parsed CLI options
108
+ # @return [void]
109
+ def apply_file_filters(raw, options)
110
+ files = raw['filter']['files'] ||= {} #: Hash[String, untyped]
111
+ files['include'] = Array(files['include']) + options[:include_file]
112
+ files['exclude'] = Array(files['exclude']) + options[:exclude_file]
113
+ end
114
+
115
+ # Apply RBS-related CLI overrides to the raw config.
116
+ #
117
+ # @note module_function: when included, also defines # (instance visibility: private)
118
+ # @private
119
+ # @param [Hash] raw raw config hash
120
+ # @param [Hash] options parsed CLI options
121
+ # @return [void]
122
+ def apply_rbs_overrides(raw, options)
123
+ raw['rbs'] ||= {}
124
+ raw['rbs']['enabled'] = true
125
+ raw['rbs']['sig_dirs'] = Array(raw['rbs']['sig_dirs']) + options[:sig_dirs] if options[:sig_dirs].any?
126
+
127
+ return unless options[:rbs_collection]
63
128
 
64
- if options[:sorbet] || options[:rbi_dirs].any?
65
- raw['sorbet'] ||= {}
66
- raw['sorbet']['enabled'] = true
67
- raw['sorbet']['rbi_dirs'] = Array(raw['sorbet']['rbi_dirs']) + options[:rbi_dirs] if options[:rbi_dirs].any?
129
+ apply_rbs_collection(raw)
130
+ end
131
+
132
+ # Resolve and apply the RBS collection path into the raw config hash.
133
+ #
134
+ # @note module_function: when included, also defines #apply_rbs_collection (instance visibility: private)
135
+ # @param [Hash] raw raw config hash
136
+ # @return [void]
137
+ def apply_rbs_collection(raw)
138
+ require 'docscribe/types/rbs/collection_loader'
139
+ collection_path = Docscribe::Types::RBS::CollectionLoader.resolve
140
+ if collection_path
141
+ raw['rbs']['collection_dirs'] = Array(raw['rbs']['collection_dirs']) + [collection_path]
142
+ else
143
+ warn 'Docscribe: rbs_collection.lock.yaml not found or collection not installed. ' \
144
+ 'Run `bundle exec rbs collection install` first.'
68
145
  end
146
+ end
69
147
 
70
- Docscribe::Config.new(raw)
148
+ # Apply Sorbet-related CLI overrides to the raw config.
149
+ #
150
+ # @note module_function: when included, also defines # (instance visibility: private)
151
+ # @private
152
+ # @param [Hash] raw raw config hash
153
+ # @param [Hash] options parsed CLI options
154
+ # @return [void]
155
+ def apply_sorbet_overrides(raw, options)
156
+ raw['sorbet'] ||= {}
157
+ raw['sorbet']['enabled'] = true
158
+ return unless options[:rbi_dirs].any?
159
+
160
+ raw['sorbet']['rbi_dirs'] = Array(raw['sorbet']['rbi_dirs']) + options[:rbi_dirs]
71
161
  end
72
162
  end
73
163
  end