devlensio 1.0.1 → 1.0.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.
@@ -41,7 +41,7 @@ pub fn detect_calls(
41
41
  let mut edges = vec![];
42
42
 
43
43
  for pf in &repo.files {
44
- if pf.is_test_file {
44
+ if pf.is_pure_test_file {
45
45
  continue;
46
46
  }
47
47
  for item in &pf.items {
@@ -57,7 +57,7 @@ pub fn enrich_nodes(
57
57
  let mut model_table: std::collections::HashMap<String, String> =
58
58
  std::collections::HashMap::new();
59
59
  for pf in &repo.files {
60
- if pf.is_test_file {
60
+ if pf.is_pure_test_file {
61
61
  continue;
62
62
  }
63
63
  for item in &pf.items {
@@ -34,7 +34,7 @@ pub fn detect_imports(
34
34
  let mut seen: std::collections::HashSet<(String, String)> = std::collections::HashSet::new();
35
35
 
36
36
  for pf in &repo.files {
37
- if pf.is_test_file {
37
+ if pf.is_pure_test_file {
38
38
  // test files ARE leaf nodes, but they still import — emit edges
39
39
  // from the TEST node (same file id — parentFile covers it)
40
40
  }
@@ -37,7 +37,7 @@ pub fn detect_inheritance(
37
37
  let mut edges = vec![];
38
38
  let mut nodes = vec![];
39
39
  for pf in &repo.files {
40
- if pf.is_test_file {
40
+ if pf.is_pure_test_file {
41
41
  continue;
42
42
  }
43
43
  for item in &pf.items {
@@ -2,9 +2,11 @@
2
2
  //
3
3
  // Contract rules enforced here:
4
4
  // - FILE id `file::rel/path.rs`; file nodes parent themselves
5
- // - TEST files (any #[test] fn) = LEAF nodes: nodes=[] for them, test fns
6
- // ride in metadata.testCases only (the bug that shipped in Python's
7
- // parser — asserted in the bun suite)
5
+ // - PURE test files (tests/ integration files, or files whose every item is
6
+ // a #[test] fn) = LEAF TEST nodes; Rust's idiomatic inline #[cfg(test)]
7
+ // mod tests must NOT collapse a mixed production file — its non-test items
8
+ // emit normally and #[test] fns emit as FUNCTION nodes flagged
9
+ // metadata.isTestFunction (test bodies stay out of prod call edges there)
8
10
  // - rawCode + codeHash on every FUNCTION/METHOD/STRUCT/ENUM/TRAIT/IMPL_BLOCK
9
11
  // - deterministic ids (file-scoped; trait-impl method suffix for the
10
12
  // same-name-different-trait collision class)
@@ -17,7 +19,7 @@ use serde_json::{Map, Value};
17
19
  pub fn collect_file_nodes(files: &[ParsedFile]) -> Vec<CodeNode> {
18
20
  let mut out = vec![];
19
21
  for pf in files {
20
- if pf.is_test_file {
22
+ if pf.is_pure_test_file {
21
23
  let mut n = file_node(&pf.rel_path, pf.line_count, NODE_TEST);
22
24
  let meta = n
23
25
  .metadata
@@ -30,25 +32,43 @@ pub fn collect_file_nodes(files: &[ParsedFile]) -> Vec<CodeNode> {
30
32
  }
31
33
  out.push(n);
32
34
  } else {
33
- out.push(file_node(&pf.rel_path, pf.line_count, NODE_FILE));
35
+ let mut n = file_node(&pf.rel_path, pf.line_count, NODE_FILE);
36
+ // Mixed files keep a testCases index so consumers that never walk
37
+ // FUNCTION nodes still see the file's tests.
38
+ if !pf.test_fns.is_empty() {
39
+ let meta = n
40
+ .metadata
41
+ .entry("testCases".to_string())
42
+ .or_insert_with(|| Value::Array(vec![]));
43
+ if let Value::Array(arr) = meta {
44
+ for t in &pf.test_fns {
45
+ arr.push(Value::from(t.clone()));
46
+ }
47
+ }
48
+ }
49
+ out.push(n);
34
50
  }
35
51
  }
36
52
  out
37
53
  }
38
54
 
39
- /// Code nodes (FUNCTION/METHOD/STRUCT/ENUM/TRAIT/IMPL_BLOCK) — test fns are
40
- /// NOT emitted (leaf rule); they feed metadata.testCases only.
55
+ /// Code nodes. PURE test files stay leaves (their fns ride in testCases).
56
+ /// Mixed files emit ALL items; #[test] fns are flagged metadata.isTestFunction
57
+ /// instead of being dropped, so a test function is addressable without a new
58
+ /// node type.
41
59
  pub fn collect_code_nodes(files: &[ParsedFile]) -> Vec<CodeNode> {
42
60
  let mut out = vec![];
43
61
  for pf in files {
44
- if pf.is_test_file {
62
+ if pf.is_pure_test_file {
45
63
  continue;
46
64
  }
47
65
  for item in &pf.items {
66
+ let mut n = item_node(pf, item);
48
67
  if item.is_test {
49
- continue;
68
+ n.metadata
69
+ .insert("isTestFunction".to_string(), Value::from(true));
50
70
  }
51
- out.push(item_node(pf, item));
71
+ out.push(n);
52
72
  }
53
73
  }
54
74
  out
@@ -21,7 +21,7 @@ use std::collections::HashMap;
21
21
  pub fn table_to_model_map(repo: &ParsedRepo) -> HashMap<String, String> {
22
22
  let mut map = HashMap::new();
23
23
  for pf in &repo.files {
24
- if pf.is_test_file {
24
+ if pf.is_pure_test_file {
25
25
  continue;
26
26
  }
27
27
  for item in &pf.items {
@@ -89,7 +89,7 @@ pub fn detect_orm_edges(
89
89
  let table_to_schema_file = table_to_schema_file_map(repo);
90
90
 
91
91
  for pf in &repo.files {
92
- if pf.is_test_file {
92
+ if pf.is_pure_test_file {
93
93
  continue;
94
94
  }
95
95
  for item in &pf.items {
@@ -162,7 +162,12 @@ pub struct ParsedFile {
162
162
  pub items: Vec<ParsedItem>,
163
163
  pub tables: Vec<TableDecl>,
164
164
  pub test_fns: Vec<String>,
165
- pub is_test_file: bool,
165
+ /// True only when the file is EXCLUSIVELY tests (every top-level item is a
166
+ /// #[test] fn, or the file only holds inline #[cfg(test)] mods). Rust's
167
+ /// idiomatic inline `#[cfg(test)] mod tests` must NOT collapse a mixed
168
+ /// production file into a TEST leaf — only pure test files get leaf
169
+ /// treatment (mirrors the intent of go's _test.go rule).
170
+ pub is_pure_test_file: bool,
166
171
  pub line_count: i64,
167
172
  }
168
173
 
@@ -326,7 +331,7 @@ pub fn parse_file(rel_path: &str, source: &str) -> Result<ParsedFile, String> {
326
331
  items: vec![],
327
332
  tables: vec![],
328
333
  test_fns: vec![],
329
- is_test_file: false,
334
+ is_pure_test_file: false,
330
335
  line_count: line_index.line_count() as i64,
331
336
  };
332
337
 
@@ -342,7 +347,7 @@ pub fn parse_file(rel_path: &str, source: &str) -> Result<ParsedFile, String> {
342
347
  }
343
348
  pf.ast.items = ast_items;
344
349
 
345
- pf.is_test_file = !pf.test_fns.is_empty();
350
+ pf.is_pure_test_file = !pf.test_fns.is_empty() && pf.items.iter().all(|i| i.is_test);
346
351
  Ok(pf)
347
352
  }
348
353
 
@@ -96,7 +96,7 @@ pub fn detect_routes(
96
96
  let mut func_lit_vars: HashMap<(String, String), String> = HashMap::new();
97
97
 
98
98
  for pf in &repo.files {
99
- if pf.is_test_file {
99
+ if pf.is_pure_test_file {
100
100
  continue;
101
101
  }
102
102
  for item in &pf.items {
@@ -195,7 +195,7 @@ pub fn detect_routes(
195
195
  // ── actix-web / rocket: attribute macros ──
196
196
  if framework == "actix-web" || framework == "rocket" {
197
197
  for pf in &repo.files {
198
- if pf.is_test_file {
198
+ if pf.is_pure_test_file {
199
199
  continue;
200
200
  }
201
201
  for item in &pf.items {
@@ -22,7 +22,7 @@ pub fn detect_tests(
22
22
  ) -> Vec<CodeEdge> {
23
23
  let mut edges = vec![];
24
24
  for pf in &repo.files {
25
- if !pf.is_test_file {
25
+ if !pf.is_pure_test_file {
26
26
  continue;
27
27
  }
28
28
  let from = format!("file::{}", pf.rel_path);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "devlensio",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Codebase intelligence engine for TypeScript/JavaScript/React/Next.js, Python, Java, Go, and Rust repositories.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",