rubydex 0.1.0.beta11 → 0.1.0.beta13

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 (108) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +23 -23
  3. data/README.md +125 -125
  4. data/THIRD_PARTY_LICENSES.html +2018 -945
  5. data/exe/rdx +47 -47
  6. data/ext/rubydex/declaration.c +453 -388
  7. data/ext/rubydex/declaration.h +23 -23
  8. data/ext/rubydex/definition.c +284 -197
  9. data/ext/rubydex/definition.h +28 -28
  10. data/ext/rubydex/diagnostic.c +6 -6
  11. data/ext/rubydex/diagnostic.h +11 -11
  12. data/ext/rubydex/document.c +97 -98
  13. data/ext/rubydex/document.h +10 -10
  14. data/ext/rubydex/extconf.rb +146 -127
  15. data/ext/rubydex/graph.c +701 -512
  16. data/ext/rubydex/graph.h +10 -10
  17. data/ext/rubydex/handle.h +44 -44
  18. data/ext/rubydex/location.c +22 -22
  19. data/ext/rubydex/location.h +15 -15
  20. data/ext/rubydex/reference.c +123 -104
  21. data/ext/rubydex/reference.h +15 -16
  22. data/ext/rubydex/rubydex.c +22 -22
  23. data/ext/rubydex/utils.c +108 -86
  24. data/ext/rubydex/utils.h +34 -28
  25. data/lib/rubydex/comment.rb +17 -17
  26. data/lib/rubydex/declaration.rb +11 -0
  27. data/lib/rubydex/diagnostic.rb +21 -21
  28. data/lib/rubydex/failures.rb +15 -15
  29. data/lib/rubydex/graph.rb +98 -92
  30. data/lib/rubydex/keyword.rb +17 -0
  31. data/lib/rubydex/keyword_parameter.rb +13 -0
  32. data/lib/rubydex/location.rb +90 -90
  33. data/lib/rubydex/mixin.rb +22 -0
  34. data/lib/rubydex/version.rb +5 -5
  35. data/lib/rubydex.rb +24 -20
  36. data/rbi/rubydex.rbi +425 -310
  37. data/rust/Cargo.lock +1851 -1851
  38. data/rust/Cargo.toml +29 -29
  39. data/rust/about.toml +10 -10
  40. data/rust/{about.hbs → about_templates/about.hbs} +81 -78
  41. data/rust/about_templates/mingw_licenses.hbs +1071 -0
  42. data/rust/rubydex/Cargo.toml +42 -42
  43. data/rust/rubydex/src/compile_assertions.rs +13 -13
  44. data/rust/rubydex/src/diagnostic.rs +110 -109
  45. data/rust/rubydex/src/errors.rs +28 -28
  46. data/rust/rubydex/src/indexing/local_graph.rs +224 -224
  47. data/rust/rubydex/src/indexing/rbs_indexer.rs +1551 -1554
  48. data/rust/rubydex/src/indexing/ruby_indexer.rs +2329 -6753
  49. data/rust/rubydex/src/indexing/ruby_indexer_tests.rs +4962 -0
  50. data/rust/rubydex/src/indexing.rs +210 -210
  51. data/rust/rubydex/src/integrity.rs +279 -278
  52. data/rust/rubydex/src/job_queue.rs +199 -205
  53. data/rust/rubydex/src/lib.rs +17 -17
  54. data/rust/rubydex/src/listing.rs +371 -272
  55. data/rust/rubydex/src/main.rs +160 -160
  56. data/rust/rubydex/src/model/built_in.rs +83 -0
  57. data/rust/rubydex/src/model/comment.rs +24 -24
  58. data/rust/rubydex/src/model/declaration.rs +679 -588
  59. data/rust/rubydex/src/model/definitions.rs +1682 -1602
  60. data/rust/rubydex/src/model/document.rs +222 -252
  61. data/rust/rubydex/src/model/encoding.rs +22 -22
  62. data/rust/rubydex/src/model/graph.rs +3782 -3556
  63. data/rust/rubydex/src/model/id.rs +110 -110
  64. data/rust/rubydex/src/model/identity_maps.rs +58 -58
  65. data/rust/rubydex/src/model/ids.rs +60 -38
  66. data/rust/rubydex/src/model/keywords.rs +256 -256
  67. data/rust/rubydex/src/model/name.rs +298 -298
  68. data/rust/rubydex/src/model/references.rs +111 -111
  69. data/rust/rubydex/src/model/string_ref.rs +50 -50
  70. data/rust/rubydex/src/model/visibility.rs +41 -41
  71. data/rust/rubydex/src/model.rs +15 -14
  72. data/rust/rubydex/src/offset.rs +147 -147
  73. data/rust/rubydex/src/position.rs +6 -6
  74. data/rust/rubydex/src/query.rs +1841 -1700
  75. data/rust/rubydex/src/resolution.rs +1852 -5895
  76. data/rust/rubydex/src/resolution_tests.rs +4701 -0
  77. data/rust/rubydex/src/stats/memory.rs +71 -71
  78. data/rust/rubydex/src/stats/orphan_report.rs +264 -263
  79. data/rust/rubydex/src/stats/timer.rs +127 -127
  80. data/rust/rubydex/src/stats.rs +11 -11
  81. data/rust/rubydex/src/test_utils/context.rs +226 -226
  82. data/rust/rubydex/src/test_utils/graph_test.rs +730 -679
  83. data/rust/rubydex/src/test_utils/local_graph_test.rs +602 -602
  84. data/rust/rubydex/src/test_utils.rs +52 -52
  85. data/rust/rubydex/src/visualization/dot.rs +192 -176
  86. data/rust/rubydex/src/visualization.rs +6 -6
  87. data/rust/rubydex/tests/cli.rs +185 -167
  88. data/rust/rubydex-mcp/Cargo.toml +28 -28
  89. data/rust/rubydex-mcp/src/main.rs +48 -48
  90. data/rust/rubydex-mcp/src/server.rs +1145 -1145
  91. data/rust/rubydex-mcp/src/tools.rs +49 -49
  92. data/rust/rubydex-mcp/tests/mcp.rs +302 -302
  93. data/rust/rubydex-sys/Cargo.toml +20 -20
  94. data/rust/rubydex-sys/build.rs +14 -14
  95. data/rust/rubydex-sys/cbindgen.toml +12 -12
  96. data/rust/rubydex-sys/src/declaration_api.rs +485 -469
  97. data/rust/rubydex-sys/src/definition_api.rs +443 -352
  98. data/rust/rubydex-sys/src/diagnostic_api.rs +99 -99
  99. data/rust/rubydex-sys/src/document_api.rs +85 -54
  100. data/rust/rubydex-sys/src/graph_api.rs +1017 -700
  101. data/rust/rubydex-sys/src/lib.rs +79 -9
  102. data/rust/rubydex-sys/src/location_api.rs +79 -79
  103. data/rust/rubydex-sys/src/name_api.rs +187 -135
  104. data/rust/rubydex-sys/src/reference_api.rs +267 -195
  105. data/rust/rubydex-sys/src/utils.rs +70 -70
  106. data/rust/rustfmt.toml +2 -2
  107. metadata +16 -9
  108. data/lib/rubydex/librubydex_sys.so +0 -0
@@ -1,52 +1,52 @@
1
- mod context;
2
- mod graph_test;
3
- mod local_graph_test;
4
-
5
- pub use context::Context;
6
- pub use context::with_context;
7
- pub use graph_test::GraphTest;
8
- pub use local_graph_test::LocalGraphTest;
9
-
10
- #[must_use]
11
- pub fn normalize_indentation(input: &str) -> String {
12
- let input = if let Some(rest) = input.strip_prefix('\n') {
13
- match rest.chars().next() {
14
- Some(' ' | '\t') => rest,
15
- _ => input,
16
- }
17
- } else {
18
- input
19
- };
20
-
21
- let lines: Vec<&str> = input.lines().collect();
22
- if lines.is_empty() {
23
- return String::new();
24
- }
25
-
26
- let first_non_empty_line = match lines.iter().find(|line| !line.trim().is_empty()) {
27
- Some(line) => *line,
28
- None => return input.to_string(),
29
- };
30
-
31
- let base_indent = first_non_empty_line.len() - first_non_empty_line.trim_start().len();
32
-
33
- let mut normalized = lines
34
- .iter()
35
- .map(|line| {
36
- if line.trim().is_empty() {
37
- ""
38
- } else if line.len() >= base_indent && line.chars().take(base_indent).all(char::is_whitespace) {
39
- &line[base_indent..]
40
- } else {
41
- line
42
- }
43
- })
44
- .collect::<Vec<_>>()
45
- .join("\n");
46
-
47
- if input.ends_with('\n') {
48
- normalized.push('\n');
49
- }
50
-
51
- normalized
52
- }
1
+ mod context;
2
+ mod graph_test;
3
+ mod local_graph_test;
4
+
5
+ pub use context::Context;
6
+ pub use context::with_context;
7
+ pub use graph_test::GraphTest;
8
+ pub use local_graph_test::LocalGraphTest;
9
+
10
+ #[must_use]
11
+ pub fn normalize_indentation(input: &str) -> String {
12
+ let input = if let Some(rest) = input.strip_prefix('\n') {
13
+ match rest.chars().next() {
14
+ Some(' ' | '\t') => rest,
15
+ _ => input,
16
+ }
17
+ } else {
18
+ input
19
+ };
20
+
21
+ let lines: Vec<&str> = input.lines().collect();
22
+ if lines.is_empty() {
23
+ return String::new();
24
+ }
25
+
26
+ let first_non_empty_line = match lines.iter().find(|line| !line.trim().is_empty()) {
27
+ Some(line) => *line,
28
+ None => return input.to_string(),
29
+ };
30
+
31
+ let base_indent = first_non_empty_line.len() - first_non_empty_line.trim_start().len();
32
+
33
+ let mut normalized = lines
34
+ .iter()
35
+ .map(|line| {
36
+ if line.trim().is_empty() {
37
+ ""
38
+ } else if line.len() >= base_indent && line.chars().take(base_indent).all(char::is_whitespace) {
39
+ &line[base_indent..]
40
+ } else {
41
+ line
42
+ }
43
+ })
44
+ .collect::<Vec<_>>()
45
+ .join("\n");
46
+
47
+ if input.ends_with('\n') {
48
+ normalized.push('\n');
49
+ }
50
+
51
+ normalized
52
+ }
@@ -1,176 +1,192 @@
1
- //! DOT format generator for Graphviz visualization of the graph structure.
2
-
3
- use std::fmt::Write;
4
-
5
- use crate::model::graph::Graph;
6
-
7
- const NAME_NODE_SHAPE: &str = "hexagon";
8
- const DEFINITION_NODE_SHAPE: &str = "ellipse";
9
- const URI_NODE_SHAPE: &str = "box";
10
-
11
- /// Escapes a string for use in DOT format labels and identifiers.
12
- fn escape_dot_string(s: &str) -> String {
13
- if !s.contains('"') {
14
- return s.to_string();
15
- }
16
-
17
- let mut result = String::with_capacity(s.len());
18
- for c in s.chars() {
19
- match c {
20
- '"' => result.push_str("\\\""),
21
- _ => result.push(c),
22
- }
23
- }
24
- result
25
- }
26
-
27
- #[must_use]
28
- pub fn generate(graph: &Graph) -> String {
29
- let mut output = String::new();
30
- output.push_str("digraph {\n");
31
- output.push_str(" rankdir=TB;\n\n");
32
-
33
- write_declaration_nodes(&mut output, graph);
34
- write_definition_nodes(&mut output, graph);
35
- write_document_nodes(&mut output, graph);
36
-
37
- output.push_str("}\n");
38
- output
39
- }
40
-
41
- fn write_declaration_nodes(output: &mut String, graph: &Graph) {
42
- let mut declarations: Vec<_> = graph.declarations().values().collect();
43
- declarations.sort_by(|a, b| a.name().cmp(b.name()));
44
-
45
- for declaration in declarations {
46
- let name = declaration.name();
47
- let escaped_name = escape_dot_string(name);
48
- let node_id = format!("Name:{name}");
49
- let _ = writeln!(
50
- output,
51
- " \"{node_id}\" [label=\"{escaped_name}\",shape={NAME_NODE_SHAPE}];"
52
- );
53
-
54
- for def_id in declaration.definitions() {
55
- let _ = writeln!(output, " \"{node_id}\" -> \"def_{def_id}\" [dir=both];");
56
- }
57
- }
58
-
59
- output.push('\n');
60
- }
61
-
62
- fn write_definition_nodes(output: &mut String, graph: &Graph) {
63
- let mut definitions: Vec<_> = graph
64
- .definitions()
65
- .iter()
66
- .filter_map(|(def_id, definition)| {
67
- graph
68
- .declarations()
69
- .get(graph.definition_to_declaration_id(definition).unwrap())
70
- .map(|declaration| {
71
- let def_type = definition.kind();
72
- let escaped_name = escape_dot_string(declaration.name());
73
- let label = format!("{def_type}({escaped_name})");
74
- let line = format!(" \"def_{def_id}\" [label=\"{label}\",shape={DEFINITION_NODE_SHAPE}];\n");
75
- (label, line)
76
- })
77
- })
78
- .collect();
79
-
80
- definitions.sort_by(|a, b| a.0.cmp(&b.0));
81
-
82
- for (_, line) in definitions {
83
- output.push_str(&line);
84
- }
85
- output.push('\n');
86
- }
87
-
88
- fn write_document_nodes(output: &mut String, graph: &Graph) {
89
- let mut documents: Vec<_> = graph.documents().values().collect();
90
- documents.sort_by(|a, b| a.uri().cmp(b.uri()));
91
-
92
- for document in documents {
93
- let uri = document.uri();
94
- let label = uri.rsplit('/').next().unwrap_or(uri);
95
- let escaped_uri = escape_dot_string(uri);
96
- let escaped_label = escape_dot_string(label);
97
- let _ = writeln!(
98
- output,
99
- " \"{escaped_uri}\" [label=\"{escaped_label}\",shape={URI_NODE_SHAPE}];"
100
- );
101
-
102
- for def_id in document.definitions() {
103
- let _ = writeln!(output, " \"def_{def_id}\" -> \"{escaped_uri}\";");
104
- }
105
- }
106
- output.push('\n');
107
- }
108
-
109
- #[cfg(test)]
110
- mod tests {
111
- use super::*;
112
- use crate::test_utils::GraphTest;
113
-
114
- fn create_test_graph() -> GraphTest {
115
- let mut graph_test = GraphTest::new();
116
- graph_test.index_uri(
117
- "file:///test.rb",
118
- "
119
- class TestClass
120
- end
121
-
122
- module TestModule
123
- end
124
- ",
125
- );
126
- graph_test.resolve();
127
- graph_test
128
- }
129
-
130
- #[test]
131
- fn test_dot_generation() {
132
- let context = create_test_graph();
133
- let dot_output = generate(context.graph());
134
-
135
- let class_def_id = context
136
- .graph()
137
- .definitions()
138
- .iter()
139
- .find(|(_, def)| matches!(def, crate::model::definitions::Definition::Class(_)))
140
- .map(|(id, _)| id.to_string())
141
- .unwrap();
142
-
143
- let module_def_id = context
144
- .graph()
145
- .definitions()
146
- .iter()
147
- .find(|(_, def)| matches!(def, crate::model::definitions::Definition::Module(_)))
148
- .map(|(id, _)| id.to_string())
149
- .unwrap();
150
-
151
- let expected = format!(
152
- r#"digraph {{
153
- rankdir=TB;
154
-
155
- "Name:Class" [label="Class",shape=hexagon];
156
- "Name:Module" [label="Module",shape=hexagon];
157
- "Name:Object" [label="Object",shape=hexagon];
158
- "Name:TestClass" [label="TestClass",shape=hexagon];
159
- "Name:TestClass" -> "def_{class_def_id}" [dir=both];
160
- "Name:TestModule" [label="TestModule",shape=hexagon];
161
- "Name:TestModule" -> "def_{module_def_id}" [dir=both];
162
-
163
- "def_{class_def_id}" [label="Class(TestClass)",shape=ellipse];
164
- "def_{module_def_id}" [label="Module(TestModule)",shape=ellipse];
165
-
166
- "file:///test.rb" [label="test.rb",shape=box];
167
- "def_{class_def_id}" -> "file:///test.rb";
168
- "def_{module_def_id}" -> "file:///test.rb";
169
-
170
- }}
171
- "#
172
- );
173
-
174
- assert_eq!(dot_output, expected);
175
- }
176
- }
1
+ //! DOT format generator for Graphviz visualization of the graph structure.
2
+
3
+ use std::fmt::Write;
4
+
5
+ use crate::model::graph::Graph;
6
+
7
+ const NAME_NODE_SHAPE: &str = "hexagon";
8
+ const DEFINITION_NODE_SHAPE: &str = "ellipse";
9
+ const URI_NODE_SHAPE: &str = "box";
10
+
11
+ /// Escapes a string for use in DOT format labels and identifiers.
12
+ fn escape_dot_string(s: &str) -> String {
13
+ if !s.contains('"') {
14
+ return s.to_string();
15
+ }
16
+
17
+ let mut result = String::with_capacity(s.len());
18
+ for c in s.chars() {
19
+ match c {
20
+ '"' => result.push_str("\\\""),
21
+ _ => result.push(c),
22
+ }
23
+ }
24
+ result
25
+ }
26
+
27
+ #[must_use]
28
+ pub fn generate(graph: &Graph) -> String {
29
+ let mut output = String::new();
30
+ output.push_str("digraph {\n");
31
+ output.push_str(" rankdir=TB;\n\n");
32
+
33
+ write_declaration_nodes(&mut output, graph);
34
+ write_definition_nodes(&mut output, graph);
35
+ write_document_nodes(&mut output, graph);
36
+
37
+ output.push_str("}\n");
38
+ output
39
+ }
40
+
41
+ fn write_declaration_nodes(output: &mut String, graph: &Graph) {
42
+ let mut declarations: Vec<_> = graph.declarations().values().collect();
43
+ declarations.sort_by(|a, b| a.name().cmp(b.name()));
44
+
45
+ for declaration in declarations {
46
+ let name = declaration.name();
47
+ let escaped_name = escape_dot_string(name);
48
+ let node_id = format!("Name:{name}");
49
+ let _ = writeln!(
50
+ output,
51
+ " \"{node_id}\" [label=\"{escaped_name}\",shape={NAME_NODE_SHAPE}];"
52
+ );
53
+
54
+ for def_id in declaration.definitions() {
55
+ let _ = writeln!(output, " \"{node_id}\" -> \"def_{def_id}\" [dir=both];");
56
+ }
57
+ }
58
+
59
+ output.push('\n');
60
+ }
61
+
62
+ fn write_definition_nodes(output: &mut String, graph: &Graph) {
63
+ let mut definitions: Vec<_> = graph
64
+ .definitions()
65
+ .iter()
66
+ .filter_map(|(def_id, definition)| {
67
+ graph
68
+ .declarations()
69
+ .get(graph.definition_to_declaration_id(definition).unwrap())
70
+ .map(|declaration| {
71
+ let def_type = definition.kind();
72
+ let escaped_name = escape_dot_string(declaration.name());
73
+ let label = format!("{def_type}({escaped_name})");
74
+ let line = format!(" \"def_{def_id}\" [label=\"{label}\",shape={DEFINITION_NODE_SHAPE}];\n");
75
+ (label, line)
76
+ })
77
+ })
78
+ .collect();
79
+
80
+ definitions.sort_by(|a, b| a.0.cmp(&b.0));
81
+
82
+ for (_, line) in definitions {
83
+ output.push_str(&line);
84
+ }
85
+ output.push('\n');
86
+ }
87
+
88
+ fn write_document_nodes(output: &mut String, graph: &Graph) {
89
+ let mut documents: Vec<_> = graph.documents().values().collect();
90
+ documents.sort_by(|a, b| a.uri().cmp(b.uri()));
91
+
92
+ for document in documents {
93
+ let uri = document.uri();
94
+ let label = uri.rsplit('/').next().unwrap_or(uri);
95
+ let escaped_uri = escape_dot_string(uri);
96
+ let escaped_label = escape_dot_string(label);
97
+ let _ = writeln!(
98
+ output,
99
+ " \"{escaped_uri}\" [label=\"{escaped_label}\",shape={URI_NODE_SHAPE}];"
100
+ );
101
+
102
+ for def_id in document.definitions() {
103
+ let _ = writeln!(output, " \"def_{def_id}\" -> \"{escaped_uri}\";");
104
+ }
105
+ }
106
+ output.push('\n');
107
+ }
108
+
109
+ #[cfg(test)]
110
+ mod tests {
111
+ use super::*;
112
+ use crate::{model::ids::DeclarationId, test_utils::GraphTest};
113
+
114
+ fn create_test_graph() -> GraphTest {
115
+ let mut graph_test = GraphTest::new();
116
+ graph_test.index_uri(
117
+ "file:///test.rb",
118
+ "
119
+ class TestClass
120
+ end
121
+
122
+ module TestModule
123
+ end
124
+ ",
125
+ );
126
+ graph_test.resolve();
127
+ graph_test
128
+ }
129
+
130
+ /// Finds the first definition ID for the declaration with the given name.
131
+ fn def_id_for(graph: &Graph, name: &str) -> String {
132
+ let decl = graph.declarations().get(&DeclarationId::from(name)).unwrap();
133
+ decl.definitions().first().unwrap().to_string()
134
+ }
135
+
136
+ #[test]
137
+ fn test_dot_generation() {
138
+ let context = create_test_graph();
139
+ let dot_output = generate(context.graph());
140
+
141
+ let basic_object_def = def_id_for(context.graph(), "BasicObject");
142
+ let class_def = def_id_for(context.graph(), "Class");
143
+ let kernel_def = def_id_for(context.graph(), "Kernel");
144
+ let module_def = def_id_for(context.graph(), "Module");
145
+ let object_def = def_id_for(context.graph(), "Object");
146
+ let test_class_def = def_id_for(context.graph(), "TestClass");
147
+ let test_module_def = def_id_for(context.graph(), "TestModule");
148
+
149
+ let expected = format!(
150
+ r#"digraph {{
151
+ rankdir=TB;
152
+
153
+ "Name:BasicObject" [label="BasicObject",shape=hexagon];
154
+ "Name:BasicObject" -> "def_{basic_object_def}" [dir=both];
155
+ "Name:Class" [label="Class",shape=hexagon];
156
+ "Name:Class" -> "def_{class_def}" [dir=both];
157
+ "Name:Kernel" [label="Kernel",shape=hexagon];
158
+ "Name:Kernel" -> "def_{kernel_def}" [dir=both];
159
+ "Name:Module" [label="Module",shape=hexagon];
160
+ "Name:Module" -> "def_{module_def}" [dir=both];
161
+ "Name:Object" [label="Object",shape=hexagon];
162
+ "Name:Object" -> "def_{object_def}" [dir=both];
163
+ "Name:TestClass" [label="TestClass",shape=hexagon];
164
+ "Name:TestClass" -> "def_{test_class_def}" [dir=both];
165
+ "Name:TestModule" [label="TestModule",shape=hexagon];
166
+ "Name:TestModule" -> "def_{test_module_def}" [dir=both];
167
+
168
+ "def_{basic_object_def}" [label="Class(BasicObject)",shape=ellipse];
169
+ "def_{class_def}" [label="Class(Class)",shape=ellipse];
170
+ "def_{module_def}" [label="Class(Module)",shape=ellipse];
171
+ "def_{object_def}" [label="Class(Object)",shape=ellipse];
172
+ "def_{test_class_def}" [label="Class(TestClass)",shape=ellipse];
173
+ "def_{kernel_def}" [label="Module(Kernel)",shape=ellipse];
174
+ "def_{test_module_def}" [label="Module(TestModule)",shape=ellipse];
175
+
176
+ "file:///test.rb" [label="test.rb",shape=box];
177
+ "def_{test_class_def}" -> "file:///test.rb";
178
+ "def_{test_module_def}" -> "file:///test.rb";
179
+ "rubydex:built-in" [label="rubydex:built-in",shape=box];
180
+ "def_{basic_object_def}" -> "rubydex:built-in";
181
+ "def_{kernel_def}" -> "rubydex:built-in";
182
+ "def_{object_def}" -> "rubydex:built-in";
183
+ "def_{module_def}" -> "rubydex:built-in";
184
+ "def_{class_def}" -> "rubydex:built-in";
185
+
186
+ }}
187
+ "#
188
+ );
189
+
190
+ assert_eq!(dot_output, expected);
191
+ }
192
+ }
@@ -1,6 +1,6 @@
1
- //! Graph visualization module for the Index structure.
2
- //!
3
- //! This module provides functionality to generate visual representations of the Index's
4
- //! internal graph structure, showing the relationships between Names, Definitions, and URIs.
5
-
6
- pub mod dot;
1
+ //! Graph visualization module for the Index structure.
2
+ //!
3
+ //! This module provides functionality to generate visual representations of the Index's
4
+ //! internal graph structure, showing the relationships between Names, Definitions, and URIs.
5
+
6
+ pub mod dot;