rubydex 0.2.9 → 0.4.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.
Files changed (96) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +110 -6
  3. data/THIRD_PARTY_LICENSES.html +271 -2
  4. data/exe/rdx +2 -73
  5. data/ext/rubydex/config.c +140 -0
  6. data/ext/rubydex/config.h +16 -0
  7. data/ext/rubydex/declaration.c +1 -1
  8. data/ext/rubydex/definition.c +32 -4
  9. data/ext/rubydex/diagnostic.c +75 -1
  10. data/ext/rubydex/diagnostic.h +2 -0
  11. data/ext/rubydex/graph.c +27 -48
  12. data/ext/rubydex/graph.h +6 -0
  13. data/ext/rubydex/query.c +487 -0
  14. data/ext/rubydex/query.h +8 -0
  15. data/ext/rubydex/reference.c +60 -0
  16. data/ext/rubydex/rubydex.c +4 -0
  17. data/ext/rubydex/utils.c +23 -4
  18. data/ext/rubydex/utils.h +5 -0
  19. data/lib/ruby_lsp/rubydex/addon.rb +211 -0
  20. data/lib/rubydex/cli/command/console.rb +55 -0
  21. data/lib/rubydex/cli/command/lint/explain.rb +74 -0
  22. data/lib/rubydex/cli/command/lint.rb +202 -0
  23. data/lib/rubydex/cli/command/mcp.rb +30 -0
  24. data/lib/rubydex/cli/command/query.rb +70 -0
  25. data/lib/rubydex/cli/command/skill.rb +69 -0
  26. data/lib/rubydex/cli/command.rb +168 -0
  27. data/lib/rubydex/cli.rb +93 -0
  28. data/lib/rubydex/config.rb +59 -0
  29. data/lib/rubydex/diagnostic.rb +12 -3
  30. data/lib/rubydex/errors.rb +42 -1
  31. data/lib/rubydex/graph.rb +10 -3
  32. data/lib/rubydex/linter/custom_rule.rb +97 -0
  33. data/lib/rubydex/linter/helpers/path_helpers.rb +78 -0
  34. data/lib/rubydex/linter/helpers/source_access_helpers.rb +31 -0
  35. data/lib/rubydex/linter/rule_loader.rb +36 -0
  36. data/lib/rubydex/linter/rule_test_case.rb +343 -0
  37. data/lib/rubydex/linter/runner.rb +56 -0
  38. data/lib/rubydex/linter.rb +19 -0
  39. data/lib/rubydex/location.rb +3 -0
  40. data/lib/rubydex/mcp_server.rb +1 -2
  41. data/lib/rubydex/related_information.rb +17 -0
  42. data/lib/rubydex/rule.rb +33 -0
  43. data/lib/rubydex/severity.rb +70 -0
  44. data/lib/rubydex/skill.rb +88 -0
  45. data/lib/rubydex/skill_registry.rb +62 -0
  46. data/lib/rubydex/version.rb +1 -1
  47. data/lib/rubydex.rb +6 -0
  48. data/lib/rubydex_linter/rules/rule_structure.rb +125 -0
  49. data/rbi/rubydex.rbi +578 -15
  50. data/rust/Cargo.lock +7 -0
  51. data/rust/rubydex/Cargo.toml +1 -0
  52. data/rust/rubydex/benches/graph_memory.rs +20 -4
  53. data/rust/rubydex/src/compile_assertions.rs +15 -0
  54. data/rust/rubydex/src/config.rs +538 -157
  55. data/rust/rubydex/src/diagnostic.rs +66 -40
  56. data/rust/rubydex/src/errors.rs +0 -1
  57. data/rust/rubydex/src/indexing/local_graph.rs +6 -5
  58. data/rust/rubydex/src/indexing/rbs_indexer.rs +284 -8
  59. data/rust/rubydex/src/indexing/ruby_indexer.rs +59 -70
  60. data/rust/rubydex/src/indexing/ruby_indexer_tests.rs +195 -86
  61. data/rust/rubydex/src/lib.rs +1 -0
  62. data/rust/rubydex/src/listing.rs +26 -1
  63. data/rust/rubydex/src/main.rs +9 -128
  64. data/rust/rubydex/src/model/declaration.rs +301 -229
  65. data/rust/rubydex/src/model/definitions.rs +27 -26
  66. data/rust/rubydex/src/model/document.rs +43 -7
  67. data/rust/rubydex/src/model/graph.rs +67 -68
  68. data/rust/rubydex/src/model/id.rs +55 -0
  69. data/rust/rubydex/src/model/ids.rs +21 -9
  70. data/rust/rubydex/src/model/name.rs +88 -19
  71. data/rust/rubydex/src/model/references.rs +16 -13
  72. data/rust/rubydex/src/operation/ruby_builder.rs +78 -104
  73. data/rust/rubydex/src/path_helpers.rs +77 -0
  74. data/rust/rubydex/src/query/cypher/schema.rs +853 -0
  75. data/rust/rubydex/src/query/cypher/schema_info.rs +161 -0
  76. data/rust/rubydex/src/query/cypher/tests.rs +253 -0
  77. data/rust/rubydex/src/query/cypher.rs +54 -0
  78. data/rust/rubydex/src/query.rs +125 -43
  79. data/rust/rubydex/src/resolution.rs +368 -395
  80. data/rust/rubydex/src/resolution_tests.rs +504 -78
  81. data/rust/rubydex/src/test_utils/context.rs +2 -1
  82. data/rust/rubydex/src/test_utils/graph_test.rs +26 -12
  83. data/rust/rubydex/src/test_utils/local_graph_test.rs +19 -0
  84. data/rust/rubydex/tests/cli.rs +4 -4
  85. data/rust/rubydex-sys/src/config_api.rs +205 -0
  86. data/rust/rubydex-sys/src/cypher_api.rs +791 -0
  87. data/rust/rubydex-sys/src/declaration_api.rs +6 -3
  88. data/rust/rubydex-sys/src/definition_api.rs +27 -7
  89. data/rust/rubydex-sys/src/diagnostic_api.rs +77 -8
  90. data/rust/rubydex-sys/src/graph_api.rs +31 -68
  91. data/rust/rubydex-sys/src/lib.rs +2 -0
  92. data/rust/rubydex-sys/src/name_api.rs +2 -6
  93. data/rust/rubydex-sys/src/reference_api.rs +58 -12
  94. data/rust/rubydex-sys/src/utils.rs +37 -0
  95. data/skills/send-private-method/SKILL.md +133 -0
  96. metadata +37 -2
data/rbi/rubydex.rbi CHANGED
@@ -20,6 +20,9 @@ class Rubydex::ConstantReference < Rubydex::Reference
20
20
  sig { returns(Rubydex::Location) }
21
21
  def location; end
22
22
 
23
+ sig { returns(Rubydex::Document) }
24
+ def document; end
25
+
23
26
  class << self
24
27
  private
25
28
 
@@ -158,6 +161,9 @@ class Rubydex::Definition
158
161
  sig { returns(T::Array[Rubydex::Definition]) }
159
162
  def lexical_nesting; end
160
163
 
164
+ sig { returns(Rubydex::Document) }
165
+ def document; end
166
+
161
167
  class << self
162
168
  private
163
169
 
@@ -176,11 +182,91 @@ class Rubydex::GlobalVariableDefinition < Rubydex::Definition; end
176
182
  class Rubydex::InstanceVariableDefinition < Rubydex::Definition; end
177
183
 
178
184
  class Rubydex::MethodAliasDefinition < Rubydex::Definition
185
+ sig { returns(T::Array[Rubydex::Signature]) }
186
+ def signatures; end
187
+
179
188
  sig { returns(T.nilable(Rubydex::Method)) }
180
189
  def target; end
181
190
  end
182
191
 
183
- class Rubydex::MethodDefinition < Rubydex::Definition; end
192
+ class Rubydex::MethodDefinition < Rubydex::Definition
193
+ sig { returns(T::Array[Rubydex::Signature]) }
194
+ def signatures; end
195
+ end
196
+
197
+ class Rubydex::Signature
198
+ sig { params(parameters: T::Array[Rubydex::Signature::Parameter]).void }
199
+ def initialize(parameters); end
200
+
201
+ sig { returns(T::Array[Rubydex::Signature::Parameter]) }
202
+ def parameters; end
203
+
204
+ sig do
205
+ returns([
206
+ T::Array[Rubydex::Signature::PositionalParameter],
207
+ T::Array[Rubydex::Signature::OptionalPositionalParameter],
208
+ T.nilable(Rubydex::Signature::RestPositionalParameter),
209
+ T::Array[Rubydex::Signature::PostParameter],
210
+ T::Array[Rubydex::Signature::KeywordParameter],
211
+ T::Array[Rubydex::Signature::OptionalKeywordParameter],
212
+ T.nilable(Rubydex::Signature::RestKeywordParameter),
213
+ T.nilable(Rubydex::Signature::ForwardParameter),
214
+ T.nilable(Rubydex::Signature::BlockParameter),
215
+ ])
216
+ end
217
+ def deconstruct; end
218
+
219
+ sig { params(keys: T.nilable(T::Array[Symbol])).returns(T::Hash[Symbol, T.untyped]) }
220
+ def deconstruct_keys(keys); end
221
+
222
+ sig { returns(T::Array[Rubydex::Signature::PositionalParameter]) }
223
+ def positional_parameters; end
224
+
225
+ sig { returns(T::Array[Rubydex::Signature::OptionalPositionalParameter]) }
226
+ def optional_positional_parameters; end
227
+
228
+ sig { returns(T.nilable(Rubydex::Signature::RestPositionalParameter)) }
229
+ def rest_positional_parameter; end
230
+
231
+ sig { returns(T::Array[Rubydex::Signature::PostParameter]) }
232
+ def post_parameters; end
233
+
234
+ sig { returns(T::Array[Rubydex::Signature::KeywordParameter]) }
235
+ def keyword_parameters; end
236
+
237
+ sig { returns(T::Array[Rubydex::Signature::OptionalKeywordParameter]) }
238
+ def optional_keyword_parameters; end
239
+
240
+ sig { returns(T.nilable(Rubydex::Signature::RestKeywordParameter)) }
241
+ def rest_keyword_parameter; end
242
+
243
+ sig { returns(T.nilable(Rubydex::Signature::ForwardParameter)) }
244
+ def forward_parameter; end
245
+
246
+ sig { returns(T.nilable(Rubydex::Signature::BlockParameter)) }
247
+ def block_parameter; end
248
+ end
249
+
250
+ class Rubydex::Signature::Parameter
251
+ sig { returns(Symbol) }
252
+ def name; end
253
+
254
+ sig { returns(Rubydex::Location) }
255
+ def location; end
256
+
257
+ sig { params(name: Symbol, location: Rubydex::Location).void }
258
+ def initialize(name, location); end
259
+ end
260
+
261
+ class Rubydex::Signature::PositionalParameter < Rubydex::Signature::Parameter; end
262
+ class Rubydex::Signature::OptionalPositionalParameter < Rubydex::Signature::Parameter; end
263
+ class Rubydex::Signature::RestPositionalParameter < Rubydex::Signature::Parameter; end
264
+ class Rubydex::Signature::PostParameter < Rubydex::Signature::Parameter; end
265
+ class Rubydex::Signature::KeywordParameter < Rubydex::Signature::Parameter; end
266
+ class Rubydex::Signature::OptionalKeywordParameter < Rubydex::Signature::Parameter; end
267
+ class Rubydex::Signature::RestKeywordParameter < Rubydex::Signature::Parameter; end
268
+ class Rubydex::Signature::ForwardParameter < Rubydex::Signature::Parameter; end
269
+ class Rubydex::Signature::BlockParameter < Rubydex::Signature::Parameter; end
184
270
 
185
271
  class Rubydex::ModuleDefinition < Rubydex::Definition
186
272
  sig { returns(T::Array[Rubydex::Mixin]) }
@@ -214,9 +300,138 @@ class Rubydex::Include < Rubydex::Mixin; end
214
300
  class Rubydex::Prepend < Rubydex::Mixin; end
215
301
  class Rubydex::Extend < Rubydex::Mixin; end
216
302
 
303
+ module Rubydex::Severity
304
+ # Every severity, ordered from the most to the least severe.
305
+ ALL = T.let(T.unsafe(nil), T::Array[T.class_of(Rubydex::Severity::Base)])
306
+
307
+ sig { params(value: Symbol).returns(T.class_of(Rubydex::Severity::Base)) }
308
+ def self.from_value(value); end
309
+ end
310
+
311
+ class Rubydex::Severity::Base
312
+ abstract!
313
+
314
+ sig { returns(Symbol) }
315
+ def self.value; end
316
+ end
317
+
318
+ class Rubydex::Severity::Error < Rubydex::Severity::Base; end
319
+ class Rubydex::Severity::Warning < Rubydex::Severity::Base; end
320
+ class Rubydex::Severity::Information < Rubydex::Severity::Base; end
321
+ class Rubydex::Severity::Hint < Rubydex::Severity::Base; end
322
+
323
+ class Rubydex::Rule
324
+ abstract!
325
+
326
+ class << self
327
+ abstract!
328
+
329
+ sig { returns(String) }
330
+ def rule_name; end
331
+
332
+ sig { abstract.returns(T.class_of(Rubydex::Severity::Base)) }
333
+ def default_severity; end
334
+
335
+ sig { params(config: Rubydex::LinterConfig).returns(T.class_of(Rubydex::Severity::Base)) }
336
+ def severity(config); end
337
+ end
338
+ end
339
+
340
+ module Rubydex::Rules
341
+ ALL = T.let(T.unsafe(nil), T::Array[T.class_of(Rubydex::Rule)])
342
+ end
343
+
344
+ class Rubydex::Rules::ParseError < Rubydex::Rule
345
+ class << self
346
+ sig { override.returns(T.class_of(Rubydex::Severity::Base)) }
347
+ def default_severity; end
348
+ end
349
+ end
350
+
351
+ class Rubydex::Rules::ParseWarning < Rubydex::Rule
352
+ class << self
353
+ sig { override.returns(T.class_of(Rubydex::Severity::Base)) }
354
+ def default_severity; end
355
+ end
356
+ end
357
+
358
+ class Rubydex::Rules::DynamicConstantReference < Rubydex::Rule
359
+ class << self
360
+ sig { override.returns(T.class_of(Rubydex::Severity::Base)) }
361
+ def default_severity; end
362
+ end
363
+ end
364
+
365
+ class Rubydex::Rules::DynamicSingletonDefinition < Rubydex::Rule
366
+ class << self
367
+ sig { override.returns(T.class_of(Rubydex::Severity::Base)) }
368
+ def default_severity; end
369
+ end
370
+ end
371
+
372
+ class Rubydex::Rules::DynamicAncestor < Rubydex::Rule
373
+ class << self
374
+ sig { override.returns(T.class_of(Rubydex::Severity::Base)) }
375
+ def default_severity; end
376
+ end
377
+ end
378
+
379
+ class Rubydex::Rules::TopLevelMixinSelf < Rubydex::Rule
380
+ class << self
381
+ sig { override.returns(T.class_of(Rubydex::Severity::Base)) }
382
+ def default_severity; end
383
+ end
384
+ end
385
+
386
+ class Rubydex::Rules::InvalidConstantVisibility < Rubydex::Rule
387
+ class << self
388
+ sig { override.returns(T.class_of(Rubydex::Severity::Base)) }
389
+ def default_severity; end
390
+ end
391
+ end
392
+
393
+ class Rubydex::Rules::InvalidMethodVisibility < Rubydex::Rule
394
+ class << self
395
+ sig { override.returns(T.class_of(Rubydex::Severity::Base)) }
396
+ def default_severity; end
397
+ end
398
+ end
399
+
400
+ class Rubydex::Rules::UndefinedMethodVisibilityTarget < Rubydex::Rule
401
+ class << self
402
+ sig { override.returns(T.class_of(Rubydex::Severity::Base)) }
403
+ def default_severity; end
404
+ end
405
+ end
406
+
407
+ class Rubydex::Rules::UndefinedConstantVisibilityTarget < Rubydex::Rule
408
+ class << self
409
+ sig { override.returns(T.class_of(Rubydex::Severity::Base)) }
410
+ def default_severity; end
411
+ end
412
+ end
413
+
414
+ class Rubydex::RelatedInformation
415
+ sig { params(message: String, location: Rubydex::Location).void }
416
+ def initialize(message, location); end
417
+
418
+ sig { returns(Rubydex::Location) }
419
+ def location; end
420
+
421
+ sig { returns(String) }
422
+ def message; end
423
+ end
424
+
217
425
  class Rubydex::Diagnostic
218
- sig { params(rule: Symbol, message: String, location: Rubydex::Location).void }
219
- def initialize(rule:, message:, location:); end
426
+ sig do
427
+ params(
428
+ rule: T.class_of(Rubydex::Rule),
429
+ message: String,
430
+ location: Rubydex::Location,
431
+ related_information: T::Array[Rubydex::RelatedInformation],
432
+ ).void
433
+ end
434
+ def initialize(rule:, message:, location:, related_information: []); end
220
435
 
221
436
  sig { returns(Rubydex::Location) }
222
437
  def location; end
@@ -224,8 +439,231 @@ class Rubydex::Diagnostic
224
439
  sig { returns(String) }
225
440
  def message; end
226
441
 
227
- sig { returns(Symbol) }
442
+ sig { returns(T.class_of(Rubydex::Rule)) }
228
443
  def rule; end
444
+
445
+ sig { returns(T::Array[Rubydex::RelatedInformation]) }
446
+ def related_information; end
447
+ end
448
+
449
+ module Rubydex::Linter; end
450
+ module Rubydex::Linter::Helpers; end
451
+ module Rubydex::Linter::Rules; end
452
+
453
+ module Rubydex::Linter::Helpers::PathHelpers
454
+ extend T::Helpers
455
+
456
+ requires_ancestor { Rubydex::Linter::CustomRule }
457
+
458
+ EXCLUDE_FNMATCH_FLAGS = T.let(T.unsafe(nil), Integer)
459
+ TEST_PATHS = T.let(T.unsafe(nil), T::Array[String])
460
+
461
+ sig do
462
+ params(
463
+ path: String,
464
+ patterns: T::Array[String],
465
+ workspace: String,
466
+ flags: Integer,
467
+ ).returns(T::Boolean)
468
+ end
469
+ def self.path_matches_patterns?(path, patterns, workspace:, flags: 0); end
470
+
471
+ sig { params(location: Rubydex::Location, workspace: String).returns(String) }
472
+ def self.display_path(location, workspace:); end
473
+
474
+ sig do
475
+ params(
476
+ definitions: T::Enumerable[Rubydex::Definition],
477
+ excluded_patterns: T::Array[String],
478
+ ).returns(T::Array[Rubydex::Definition])
479
+ end
480
+ def reject_definitions_in_paths(definitions, excluded_patterns); end
481
+
482
+ sig do
483
+ params(
484
+ definitions: T::Enumerable[Rubydex::Definition],
485
+ patterns: T::Array[String],
486
+ ).returns(T::Array[Rubydex::Definition])
487
+ end
488
+ def select_definitions_in_paths(definitions, patterns); end
489
+
490
+ private
491
+
492
+ sig { params(path: String, patterns: T::Array[String]).returns(T::Boolean) }
493
+ def path_matches_patterns?(path, patterns); end
494
+
495
+ sig { params(path: String).returns(T::Boolean) }
496
+ def test_path?(path); end
497
+
498
+ sig { params(definition: Rubydex::Definition).returns(T.nilable(String)) }
499
+ def path_for_definition(definition); end
500
+ end
501
+
502
+ module Rubydex::Linter::Helpers::SourceAccessHelpers
503
+ sig { params(uri: String).returns(Rubydex::Location) }
504
+ def file_location(uri); end
505
+
506
+ sig { params(uri: String).returns(String) }
507
+ def path_for_uri(uri); end
508
+
509
+ private
510
+
511
+ sig { params(location: Rubydex::Location).returns(T.nilable(String)) }
512
+ def source_for_location(location); end
513
+ end
514
+
515
+ # Base class for semantic lint rules, which collect their diagnostics by walking a resolved graph.
516
+ class Rubydex::Linter::CustomRule < Rubydex::Rule
517
+ abstract!
518
+
519
+ sig { params(graph: Rubydex::Graph, config: Rubydex::LinterConfig).void }
520
+ def initialize(graph, config:); end
521
+
522
+ sig { returns(Rubydex::Graph) }
523
+ def graph; end
524
+
525
+ sig { returns(Rubydex::LinterConfig) }
526
+ def config; end
527
+
528
+ sig { returns(T::Array[Rubydex::Diagnostic]) }
529
+ def diagnostics; end
530
+
531
+ sig { params(definition: Rubydex::Definition).returns(Rubydex::Location) }
532
+ def diagnostic_location(definition); end
533
+
534
+ sig { params(base_name: String).returns(T::Enumerable[Rubydex::Class]) }
535
+ def child_classes(base_name); end
536
+
537
+ sig { params(name: String).returns(Rubydex::Namespace) }
538
+ def required_namespace(name); end
539
+
540
+ sig do
541
+ params(
542
+ namespace: Rubydex::Namespace,
543
+ method_name: String,
544
+ ).returns(Rubydex::Method)
545
+ end
546
+ def required_method(namespace, method_name); end
547
+
548
+ sig { returns(String) }
549
+ def rule_name; end
550
+
551
+ sig { abstract.void }
552
+ def lint; end
553
+
554
+ protected
555
+
556
+ sig do
557
+ params(
558
+ message: String,
559
+ location: Rubydex::Location,
560
+ related_information: T::Array[Rubydex::RelatedInformation],
561
+ ).void
562
+ end
563
+ def add_diagnostic(message, location, related_information: []); end
564
+ end
565
+
566
+ class Rubydex::Linter::MissingGraphDependencyError < StandardError
567
+ sig { params(rule_name: String, dependency: String).void }
568
+ def initialize(rule_name, dependency); end
569
+ end
570
+
571
+ class Rubydex::Linter::RuleLoadError < StandardError; end
572
+
573
+ class Rubydex::Linter::RuleLoader
574
+ RULE_GLOB = T.let(T.unsafe(nil), String)
575
+
576
+ sig { params(workspace_path: String).void }
577
+ def self.load(workspace_path); end
578
+ end
579
+
580
+ class Rubydex::Linter::Rules::RuleStructure < Rubydex::Linter::CustomRule
581
+ include Rubydex::Linter::Helpers::SourceAccessHelpers
582
+
583
+ BASE_RULE_NAME = T.let(T.unsafe(nil), String)
584
+ RULE_NAMESPACE = T.let(T.unsafe(nil), String)
585
+ RULE_FILE_PATTERNS = T.let(T.unsafe(nil), T::Array[String])
586
+ TEST_FILE_PATTERNS = T.let(T.unsafe(nil), T::Array[String])
587
+
588
+ class << self
589
+ sig { override.returns(T.class_of(Rubydex::Severity::Base)) }
590
+ def default_severity; end
591
+ end
592
+
593
+ sig { override.void }
594
+ def lint; end
595
+ end
596
+
597
+ class Rubydex::Linter::RuleTestCase < Minitest::Test
598
+ DEFAULT_FILE = T.let(T.unsafe(nil), String)
599
+ ANNOTATION_PATTERN = T.let(T.unsafe(nil), Regexp)
600
+
601
+ sig { returns(String) }
602
+ def workspace_path; end
603
+
604
+ sig { params(name: String).void }
605
+ def initialize(name); end
606
+
607
+ sig { void }
608
+ def teardown; end
609
+
610
+ sig { returns(T.class_of(Rubydex::Linter::CustomRule)) }
611
+ def rule_class; end
612
+
613
+ sig { params(sources: T::Hash[String, String]).void }
614
+ def add_shared_source(sources); end
615
+
616
+ sig { returns(T::Array[String]) }
617
+ def ignored_diagnostic_files; end
618
+
619
+ sig { returns(Rubydex::LinterConfig) }
620
+ def rule_config; end
621
+
622
+ sig do
623
+ params(
624
+ args: T.any(String, T::Hash[T.any(String, Symbol), String]),
625
+ rule_builder: T.nilable(T.proc.params(graph: Rubydex::Graph).returns(Rubydex::Linter::CustomRule)),
626
+ ).returns(T::Array[Rubydex::Diagnostic])
627
+ end
628
+ def assert_diagnostics(*args, &rule_builder); end
629
+
630
+ sig do
631
+ params(
632
+ args: T.any(String, T::Hash[T.any(String, Symbol), String]),
633
+ rule_builder: T.nilable(T.proc.params(graph: Rubydex::Graph).returns(Rubydex::Linter::CustomRule)),
634
+ ).returns(T::Array[Rubydex::Diagnostic])
635
+ end
636
+ def assert_no_diagnostics(*args, &rule_builder); end
637
+
638
+ sig do
639
+ params(
640
+ dependency: String,
641
+ args: T.any(String, T::Hash[T.any(String, Symbol), String]),
642
+ after_excluding: T::Array[String],
643
+ rule_builder: T.nilable(T.proc.params(graph: Rubydex::Graph).returns(Rubydex::Linter::CustomRule)),
644
+ ).void
645
+ end
646
+ def assert_handles_missing_required_dependency(dependency, *args, after_excluding: [], &rule_builder); end
647
+ end
648
+
649
+ class Rubydex::Linter::Runner
650
+ sig do
651
+ params(
652
+ graph: Rubydex::Graph,
653
+ custom_rules: T::Array[T.class_of(Rubydex::Linter::CustomRule)],
654
+ config: Rubydex::LinterConfig,
655
+ ).void
656
+ end
657
+ def initialize(graph, custom_rules:, config:); end
658
+
659
+ sig { returns(Rubydex::Graph) }
660
+ def graph; end
661
+
662
+ sig { returns(T::Array[T.class_of(Rubydex::Linter::CustomRule)]) }
663
+ def custom_rules; end
664
+
665
+ sig { returns(T::Array[Rubydex::Diagnostic]) }
666
+ def run; end
229
667
  end
230
668
 
231
669
  class Rubydex::Keyword
@@ -267,6 +705,74 @@ end
267
705
  class Rubydex::Error < StandardError; end
268
706
  class Rubydex::AliasCycleError < Rubydex::Error; end
269
707
  class Rubydex::ConfigError < Rubydex::Error; end
708
+ class Rubydex::QueryError < Rubydex::Error; end
709
+ class Rubydex::QuerySyntaxError < Rubydex::QueryError; end
710
+ class Rubydex::QueryExecutionError < Rubydex::QueryError; end
711
+ class Rubydex::StaleQueryResultError < Rubydex::QueryError; end
712
+
713
+ # The configuration of a workspace, parsed from its `rubydex.toml`. It carries both the settings that are global to
714
+ # every built-in tool, such as the workspace being analyzed, and the typed settings of each tool's own section (e.g.
715
+ # `[graph]`, `[linter]`).
716
+ class Rubydex::Config
717
+ class << self
718
+ # Loads the configuration file for `workspace_path/rubydex.toml` if it exists or uses the defaults.
719
+ sig { params(workspace_path: String).returns(Rubydex::Config) }
720
+ def load(workspace_path); end
721
+ end
722
+
723
+ # The linter's settings, read from the `[linter]` section.
724
+ sig { returns(Rubydex::LinterConfig) }
725
+ def linter; end
726
+
727
+ # The configured workspace path, which is usually PWD, except for editors that spawn language servers outside of pwd.
728
+ sig { returns(String) }
729
+ def workspace_path; end
730
+ end
731
+
732
+ # The linter's settings, read from the `[linter]` section of the configuration file.
733
+ class Rubydex::LinterConfig
734
+ # The configured rules, keyed by rule name. Only rules the configuration file mentions appear here, so a rule that
735
+ # was never configured is absent rather than present with its defaults.
736
+ sig { returns(T::Hash[String, Rubydex::RuleConfig]) }
737
+ attr_reader :rules
738
+
739
+ sig { params(rules: T::Hash[String, Rubydex::RuleConfig]).void }
740
+ def initialize(rules); end
741
+
742
+ sig { params(rule_class: T.class_of(Rubydex::Rule)).returns(T::Boolean) }
743
+ def rule_enabled?(rule_class); end
744
+
745
+ sig { params(rule_class: T.class_of(Rubydex::Rule)).returns(T::Array[String]) }
746
+ def excludes_for(rule_class); end
747
+
748
+ sig { params(rule_class: T.class_of(Rubydex::Rule)).returns(T.nilable(T.class_of(Rubydex::Severity::Base))) }
749
+ def severity_for(rule_class); end
750
+ end
751
+
752
+ # The settings of a single linter rule, read from a `[linter.rules.RuleName]` table.
753
+ class Rubydex::RuleConfig
754
+ sig { returns(String) }
755
+ attr_reader :name
756
+
757
+ sig { returns(T::Array[String]) }
758
+ attr_reader :exclude_patterns
759
+
760
+ sig { returns(T.nilable(T.class_of(Rubydex::Severity::Base))) }
761
+ attr_reader :severity
762
+
763
+ sig do
764
+ params(
765
+ name: String,
766
+ enabled: T::Boolean,
767
+ exclude_patterns: T::Array[String],
768
+ severity: T.nilable(T.class_of(Rubydex::Severity::Base)),
769
+ ).void
770
+ end
771
+ def initialize(name, enabled, exclude_patterns = [], severity = nil); end
772
+
773
+ sig { returns(T::Boolean) }
774
+ def enabled?; end
775
+ end
270
776
 
271
777
  class Rubydex::Failure
272
778
  sig { params(message: String).void }
@@ -278,9 +784,64 @@ end
278
784
 
279
785
  class Rubydex::IntegrityFailure < Rubydex::Failure; end
280
786
 
787
+ class Rubydex::Query
788
+ class << self
789
+ sig { params(query: String).returns(Rubydex::Query) }
790
+ def parse(query); end
791
+
792
+ sig { params(format: T.any(String, Symbol)).returns(String) }
793
+ def schema(format = :table); end
794
+ end
795
+
796
+ sig { params(graph: Rubydex::Graph).returns(Rubydex::Query::Result) }
797
+ def run(graph); end
798
+ end
799
+
800
+ # The columns and rows produced by one run of a query. Enumerable over its rows.
801
+ class Rubydex::Query::Result
802
+ include Enumerable
803
+ extend T::Generic
804
+
805
+ Elem = type_member { { fixed: T::Hash[String, T.untyped] } }
806
+
807
+ class << self
808
+ private
809
+
810
+ # A result only comes from `Query#run`. The C extension undefines `new`, so a call raises.
811
+ sig { returns(T.noreturn) }
812
+ def new; end
813
+ end
814
+
815
+ sig { returns(T::Array[String]) }
816
+ def columns; end
817
+
818
+ sig { returns(T::Array[T::Hash[String, T.untyped]]) }
819
+ def rows; end
820
+
821
+ sig { override.params(block: T.proc.params(row: T::Hash[String, T.untyped]).void).returns(T.self_type) }
822
+ sig { override.returns(T::Enumerator[T::Hash[String, T.untyped]]) }
823
+ def each(&block); end
824
+
825
+ sig { returns(Integer) }
826
+ def size; end
827
+
828
+ sig { returns(Integer) }
829
+ def length; end
830
+
831
+ sig { returns(T::Boolean) }
832
+ def empty?; end
833
+
834
+ sig { params(format: T.any(String, Symbol)).returns(String) }
835
+ def render(format = :table); end
836
+ end
837
+
281
838
  class Rubydex::Graph
282
- sig { params(workspace_path: T.nilable(String)).void }
283
- def initialize(workspace_path: nil); end
839
+ class << self
840
+ # Creates a new graph with the loaded configuration. For use cases where the graph must be shared between
841
+ # different tools, do not use this. Create and own a `Config` object instead.
842
+ sig { params(workspace_path: String).returns(T.attached_class) }
843
+ def configure_for_workspace(workspace_path); end
844
+ end
284
845
 
285
846
  sig { params(fully_qualified_name: String).returns(T.nilable(Rubydex::Declaration)) }
286
847
  def [](fully_qualified_name); end
@@ -313,12 +874,13 @@ class Rubydex::Graph
313
874
  sig { returns(T::Array[String]) }
314
875
  def index_workspace; end
315
876
 
316
- # Loads configuration, merging its exclusion patterns into the graph's configuration (the workspace path is never
317
- # overridden). With `config_path` (resolved relative to the workspace path), an explicitly named file that does not
318
- # exist raises `Rubydex::ConfigError`. With no argument, the default `.rubydex` is loaded if present and ignored if
319
- # missing. Raises `Rubydex::ConfigError` if a file cannot be read or is malformed.
320
- sig { params(config_path: T.nilable(String)).void }
321
- def load_config(config_path = nil); end
877
+ # Returns the keyword object for the name, or `nil` if it is not a Ruby keyword
878
+ sig { params(name: String).returns(T.nilable(Rubydex::Keyword)) }
879
+ def keyword(name); end
880
+
881
+ # Loads the configuration in the graph.
882
+ sig { params(config: Rubydex::Config).void }
883
+ def load_config(config); end
322
884
 
323
885
  sig { returns(T::Enumerable[Rubydex::MethodReference]) }
324
886
  def method_references; end
@@ -344,12 +906,10 @@ class Rubydex::Graph
344
906
  sig { params(encoding: String).void }
345
907
  def encoding=(encoding); end
346
908
 
909
+ # The root directory of the workspace being analyzed, which comes from the loaded `Rubydex::Config`
347
910
  sig { returns(String) }
348
911
  def workspace_path; end
349
912
 
350
- sig { params(workspace_path: String).returns(String) }
351
- def workspace_path=(workspace_path); end
352
-
353
913
  sig { returns(T::Array[String]) }
354
914
  def workspace_paths; end
355
915
 
@@ -502,6 +1062,9 @@ class Rubydex::MethodReference < Rubydex::Reference
502
1062
 
503
1063
  sig { returns(T.nilable(Rubydex::Declaration)) }
504
1064
  def receiver; end
1065
+
1066
+ sig { returns(Rubydex::Document) }
1067
+ def document; end
505
1068
  end
506
1069
 
507
1070
  class Rubydex::Reference
data/rust/Cargo.lock CHANGED
@@ -260,6 +260,12 @@ version = "0.8.21"
260
260
  source = "registry+https://github.com/rust-lang/crates.io-index"
261
261
  checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
262
262
 
263
+ [[package]]
264
+ name = "cypher-parser"
265
+ version = "0.8.1"
266
+ source = "registry+https://github.com/rust-lang/crates.io-index"
267
+ checksum = "6ada60f869dbe5818d0ee40b06ad988627cc0d692d1ed42d692353bf0af8ddb6"
268
+
263
269
  [[package]]
264
270
  name = "difflib"
265
271
  version = "0.4.0"
@@ -763,6 +769,7 @@ dependencies = [
763
769
  "crossbeam-channel",
764
770
  "crossbeam-deque",
765
771
  "crossbeam-utils",
772
+ "cypher-parser",
766
773
  "glob",
767
774
  "libc",
768
775
  "line-index",
@@ -27,6 +27,7 @@ jemalloc_dylib = ["jemalloc", "tikv-jemallocator/disable_initial_exec_tls"]
27
27
  test_utils = ["dep:tempfile"]
28
28
 
29
29
  [dependencies]
30
+ cypher-parser = "0.8.1"
30
31
  ruby-prism = "1.9.0"
31
32
  ruby-rbs = "0.3"
32
33
  url = "2.5.4"