rubydex 0.1.0.beta4 → 0.1.0.beta6

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b478f1b6a25378ce0dfe556a64fcd7f1dac9aee981edec8a77e03a04dc2123ae
4
- data.tar.gz: d3d9164cca1d9071a8e53b7f5d769eec893f4b251ec95918427ea3ecd6ea30b0
3
+ metadata.gz: c2c48ae779052983ff0d4f7a345b2a6ac612271cc6c015ba99486220d5617949
4
+ data.tar.gz: 4c81285808882e4a545ecb34bc418821d996fd4e6fe34200f89963430f8014f6
5
5
  SHA512:
6
- metadata.gz: 6fc387f42024ccedb00e8c6feea3c3d6542ad512fa4b20711a4fdf30cf604833ad72ef890cc379024cbab763f3ae27c867e82885993756ac01f6709eb4dac4d8
7
- data.tar.gz: dc1616a4d88eb7de20099888ca7af449a58dba3cbd79ed63e6acb44066420b402007b6d41d98bb84ae9a83e233a914e345a38992dd34b8cd652c146724b57e6d
6
+ metadata.gz: 0e61f0fbf4d4cf6613042b40a4e72a41d36428b72c1f21c711b9c99ea3e6bc686b87edd9d182307e29af796df7256921da6e88ffb9cf54219630b34c324d151c
7
+ data.tar.gz: 1bb42b0c43a1483d1610ea743320852c1bcc4d3d5ebfab043949fb18671eb5a0c2d8f7275f3795c66faa884ac40bca62279739a23e38bbef624256c3cdf1a09e
data/README.md CHANGED
@@ -12,7 +12,7 @@ of using the Ruby API:
12
12
  # Create a new graph representing the current workspace
13
13
  graph = Rubydex::Graph.new
14
14
  # Configuring graph LSP encoding
15
- graph.set_encoding("utf16")
15
+ graph.encoding = "utf16"
16
16
  # Index the entire workspace with all dependencies
17
17
  graph.index_workspace
18
18
  # Or index specific file paths
data/ext/rubydex/graph.c CHANGED
@@ -61,6 +61,28 @@ static VALUE rdxr_graph_index_all(VALUE self, VALUE file_paths) {
61
61
  return array;
62
62
  }
63
63
 
64
+ // Indexes a single source string in memory, dispatching to the appropriate indexer based on language_id
65
+ //
66
+ // Graph#index_source: (String uri, String source, String language_id) -> void
67
+ static VALUE rdxr_graph_index_source(VALUE self, VALUE uri, VALUE source, VALUE language_id) {
68
+ Check_Type(uri, T_STRING);
69
+ Check_Type(source, T_STRING);
70
+ Check_Type(language_id, T_STRING);
71
+
72
+ void *graph;
73
+ TypedData_Get_Struct(self, void *, &graph_type, graph);
74
+
75
+ const char *uri_str = StringValueCStr(uri);
76
+ const char *source_str = StringValueCStr(source);
77
+ const char *language_id_str = StringValueCStr(language_id);
78
+
79
+ if (!rdx_index_source(graph, uri_str, source_str, language_id_str)) {
80
+ rb_raise(rb_eArgError, "unsupported language_id `%s`", language_id_str);
81
+ }
82
+
83
+ return Qnil;
84
+ }
85
+
64
86
  // Size function for the declarations enumerator
65
87
  static VALUE graph_declarations_size(VALUE self, VALUE _args, VALUE _eobj) {
66
88
  void *graph;
@@ -303,7 +325,7 @@ static VALUE rdxr_graph_resolve(VALUE self) {
303
325
  return self;
304
326
  }
305
327
 
306
- // Graph#set_encoding: (String) -> void
328
+ // Graph#encoding=: (String) -> void
307
329
  // Sets the encoding used for transforming byte offsets into LSP code unit line/column positions
308
330
  static VALUE rdxr_graph_set_encoding(VALUE self, VALUE encoding) {
309
331
  Check_Type(encoding, T_STRING);
@@ -449,6 +471,7 @@ void rdxi_initialize_graph(VALUE mRubydex) {
449
471
  cGraph = rb_define_class_under(mRubydex, "Graph", rb_cObject);
450
472
  rb_define_alloc_func(cGraph, rdxr_graph_alloc);
451
473
  rb_define_method(cGraph, "index_all", rdxr_graph_index_all, 1);
474
+ rb_define_method(cGraph, "index_source", rdxr_graph_index_source, 3);
452
475
  rb_define_method(cGraph, "delete_document", rdxr_graph_delete_document, 1);
453
476
  rb_define_method(cGraph, "resolve", rdxr_graph_resolve, 0);
454
477
  rb_define_method(cGraph, "resolve_constant", rdxr_graph_resolve_constant, 2);
@@ -459,7 +482,7 @@ void rdxi_initialize_graph(VALUE mRubydex) {
459
482
  rb_define_method(cGraph, "diagnostics", rdxr_graph_diagnostics, 0);
460
483
  rb_define_method(cGraph, "[]", rdxr_graph_aref, 1);
461
484
  rb_define_method(cGraph, "search", rdxr_graph_search, 1);
462
- rb_define_method(cGraph, "set_encoding", rdxr_graph_set_encoding, 1);
485
+ rb_define_method(cGraph, "encoding=", rdxr_graph_set_encoding, 1);
463
486
  rb_define_method(cGraph, "resolve_require_path", rdxr_graph_resolve_require_path, 2);
464
487
  rb_define_method(cGraph, "require_paths", rdxr_graph_require_paths, 1);
465
488
  }
Binary file
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rubydex
4
- VERSION = "0.1.0.beta4"
4
+ VERSION = "0.1.0.beta6"
5
5
  end
@@ -1,23 +1,35 @@
1
1
  //! Visit the RBS AST and create type definitions.
2
2
 
3
- use crate::{
4
- indexing::local_graph::LocalGraph,
5
- model::{document::Document, ids::UriId},
6
- };
3
+ use ruby_rbs::node::{self, ModuleNode, Node, TypeNameNode, Visit};
7
4
 
8
- pub struct RBSIndexer {
9
- #[allow(dead_code)]
5
+ use crate::diagnostic::Rule;
6
+ use crate::indexing::local_graph::LocalGraph;
7
+ use crate::model::comment::Comment;
8
+ use crate::model::definitions::{Definition, DefinitionFlags, ModuleDefinition};
9
+ use crate::model::document::Document;
10
+ use crate::model::ids::{DefinitionId, NameId, UriId};
11
+ use crate::model::name::{Name, ParentScope};
12
+ use crate::offset::Offset;
13
+
14
+ pub struct RBSIndexer<'a> {
10
15
  uri_id: UriId,
11
16
  local_graph: LocalGraph,
17
+ source: &'a str,
18
+ nesting_stack: Vec<DefinitionId>,
12
19
  }
13
20
 
14
- impl RBSIndexer {
21
+ impl<'a> RBSIndexer<'a> {
15
22
  #[must_use]
16
- pub fn new(uri: String, source: &str) -> Self {
23
+ pub fn new(uri: String, source: &'a str) -> Self {
17
24
  let uri_id = UriId::from(&uri);
18
25
  let local_graph = LocalGraph::new(uri_id, Document::new(uri, source));
19
26
 
20
- Self { uri_id, local_graph }
27
+ Self {
28
+ uri_id,
29
+ local_graph,
30
+ source,
31
+ nesting_stack: Vec::new(),
32
+ }
21
33
  }
22
34
 
23
35
  #[must_use]
@@ -25,5 +37,203 @@ impl RBSIndexer {
25
37
  self.local_graph
26
38
  }
27
39
 
28
- pub fn index(&mut self) {}
40
+ pub fn index(&mut self) {
41
+ let Ok(signature) = node::parse(self.source.as_bytes()) else {
42
+ self.local_graph.add_diagnostic(
43
+ Rule::ParseError,
44
+ Offset::new(0, 0),
45
+ "Failed to parse RBS document".to_string(),
46
+ );
47
+ return;
48
+ };
49
+
50
+ self.visit(&signature.as_node());
51
+ }
52
+
53
+ fn bytes_to_string(name: &[u8]) -> String {
54
+ String::from_utf8_lossy(name).into_owned()
55
+ }
56
+
57
+ /// Converts an RBS `TypeNameNode` into a rubydex `NameId`.
58
+ ///
59
+ /// Walks the namespace path (e.g. `Foo::Bar` in `Foo::Bar::Baz`) to build
60
+ /// a `ParentScope` chain, then creates the final `Name` for the leaf segment.
61
+ fn index_type_name(&mut self, type_name: &TypeNameNode, nesting_name_id: Option<NameId>) -> NameId {
62
+ let namespace = type_name.namespace();
63
+
64
+ let mut parent_scope = if namespace.absolute() {
65
+ ParentScope::TopLevel
66
+ } else {
67
+ ParentScope::None
68
+ };
69
+
70
+ for path_node in namespace.path().iter() {
71
+ let Node::Symbol(symbol) = path_node else {
72
+ continue;
73
+ };
74
+ parent_scope = ParentScope::Some(self.intern_name(symbol.name(), parent_scope, nesting_name_id));
75
+ }
76
+
77
+ self.intern_name(type_name.name().name(), parent_scope, nesting_name_id)
78
+ }
79
+
80
+ fn intern_name(&mut self, name_bytes: &[u8], parent_scope: ParentScope, nesting_name_id: Option<NameId>) -> NameId {
81
+ let string_id = self.local_graph.intern_string(Self::bytes_to_string(name_bytes));
82
+ self.local_graph
83
+ .add_name(Name::new(string_id, parent_scope, nesting_name_id))
84
+ }
85
+
86
+ fn parent_lexical_scope_id(&self) -> Option<DefinitionId> {
87
+ self.nesting_stack.last().copied()
88
+ }
89
+
90
+ fn add_member_to_current_lexical_scope(&mut self, owner_id: DefinitionId, member_id: DefinitionId) {
91
+ let owner = self
92
+ .local_graph
93
+ .get_definition_mut(owner_id)
94
+ .expect("owner definition should exist");
95
+
96
+ match owner {
97
+ Definition::Module(module) => module.add_member(member_id),
98
+ Definition::Class(class) => class.add_member(member_id),
99
+ _ => unreachable!("RBS nesting stack only contains modules/classes"),
100
+ }
101
+ }
102
+ }
103
+
104
+ impl Visit for RBSIndexer<'_> {
105
+ fn visit_module_node(&mut self, module_node: &ModuleNode) {
106
+ let lexical_nesting_id = self.parent_lexical_scope_id();
107
+ let nesting_name_id = lexical_nesting_id.map(|id| {
108
+ let owner = self
109
+ .local_graph
110
+ .definitions()
111
+ .get(&id)
112
+ .expect("owner definition should exist");
113
+ *owner.name_id().expect("nesting definition should have a name")
114
+ });
115
+
116
+ let type_name = module_node.name();
117
+ let name_id = self.index_type_name(&type_name, nesting_name_id);
118
+ let offset = Offset::from_rbs_location(&module_node.location());
119
+ let name_offset = Offset::from_rbs_location(&type_name.name().location());
120
+
121
+ let comments: Vec<_> = module_node
122
+ .comment()
123
+ .into_iter()
124
+ .map(|comment| {
125
+ let text = Self::bytes_to_string(comment.string().as_bytes());
126
+ Comment::new(Offset::from_rbs_location(&comment.location()), text)
127
+ })
128
+ .collect();
129
+
130
+ let definition = Definition::Module(Box::new(ModuleDefinition::new(
131
+ name_id,
132
+ self.uri_id,
133
+ offset,
134
+ name_offset,
135
+ comments,
136
+ DefinitionFlags::empty(),
137
+ lexical_nesting_id,
138
+ )));
139
+
140
+ let definition_id = self.local_graph.add_definition(definition);
141
+ if let Some(id) = lexical_nesting_id {
142
+ self.add_member_to_current_lexical_scope(id, definition_id);
143
+ }
144
+
145
+ self.nesting_stack.push(definition_id);
146
+
147
+ for member in module_node.members().iter() {
148
+ self.visit(&member);
149
+ }
150
+
151
+ self.nesting_stack.pop();
152
+ }
153
+ }
154
+
155
+ #[cfg(test)]
156
+ mod tests {
157
+ use crate::test_utils::LocalGraphTest;
158
+ use crate::{
159
+ assert_def_name_eq, assert_def_name_offset_eq, assert_definition_at, assert_local_diagnostics_eq,
160
+ assert_no_local_diagnostics,
161
+ };
162
+
163
+ fn index_source(source: &str) -> LocalGraphTest {
164
+ LocalGraphTest::new_rbs("file:///foo.rbs", source)
165
+ }
166
+
167
+ #[test]
168
+ fn index_source_with_errors() {
169
+ let context = index_source("module");
170
+
171
+ assert_local_diagnostics_eq!(&context, ["parse-error: Failed to parse RBS document (1:1-1:1)"]);
172
+
173
+ assert!(context.graph().definitions().is_empty());
174
+ }
175
+
176
+ #[test]
177
+ fn index_module_node() {
178
+ let context = index_source({
179
+ "
180
+ module Foo
181
+ module Bar
182
+ end
183
+ end
184
+ "
185
+ });
186
+
187
+ assert_no_local_diagnostics!(&context);
188
+ assert_eq!(context.graph().definitions().len(), 2);
189
+
190
+ assert_definition_at!(&context, "1:1-4:4", Module, |def| {
191
+ assert_def_name_eq!(&context, def, "Foo");
192
+ assert_def_name_offset_eq!(&context, def, "1:8-1:11");
193
+ assert_eq!(1, def.members().len());
194
+ assert!(def.lexical_nesting_id().is_none());
195
+ });
196
+
197
+ assert_definition_at!(&context, "2:3-3:6", Module, |def| {
198
+ assert_def_name_eq!(&context, def, "Bar");
199
+ assert_def_name_offset_eq!(&context, def, "2:10-2:13");
200
+
201
+ assert_definition_at!(&context, "1:1-4:4", Module, |parent_nesting| {
202
+ assert_eq!(parent_nesting.id(), def.lexical_nesting_id().unwrap());
203
+ assert_eq!(parent_nesting.members()[0], def.id());
204
+ });
205
+ });
206
+ }
207
+
208
+ #[test]
209
+ fn index_module_node_with_qualified_name() {
210
+ let context = index_source({
211
+ "
212
+ module Foo
213
+ module Bar::Baz
214
+ end
215
+ end
216
+ "
217
+ });
218
+
219
+ assert_no_local_diagnostics!(&context);
220
+ assert_eq!(context.graph().definitions().len(), 2);
221
+
222
+ assert_definition_at!(&context, "1:1-4:4", Module, |def| {
223
+ assert_def_name_eq!(&context, def, "Foo");
224
+ assert_def_name_offset_eq!(&context, def, "1:8-1:11");
225
+ assert_eq!(1, def.members().len());
226
+ assert!(def.lexical_nesting_id().is_none());
227
+ });
228
+
229
+ assert_definition_at!(&context, "2:3-3:6", Module, |def| {
230
+ assert_def_name_eq!(&context, def, "Bar::Baz");
231
+ assert_def_name_offset_eq!(&context, def, "2:15-2:18");
232
+
233
+ assert_definition_at!(&context, "1:1-4:4", Module, |parent_nesting| {
234
+ assert_eq!(parent_nesting.id(), def.lexical_nesting_id().unwrap());
235
+ assert_eq!(parent_nesting.members()[0], def.id());
236
+ });
237
+ });
238
+ }
29
239
  }