universal-ast-mapper 0.8.1 → 0.8.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.
package/README.md CHANGED
@@ -10,12 +10,12 @@ Built on [tree-sitter](https://tree-sitter.github.io/) WASM grammars. Zero regex
10
10
  |--------------------------|:-----:|:------:|:---:|:----:|:----:|:---:|:---:|:---:|:---:|:-----:|
11
11
  | Symbol extraction | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
12
12
  | Imports parsing | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
13
- | Graph `imports` edges | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | | | |
14
- | `resolve_imports` enrich | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | | | |
15
- | Call graph callee origin | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | — | — | | — |
16
- | Reverse `calledBy` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | — | — | | — |
13
+ | Graph `imports` edges | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | | | |
14
+ | `resolve_imports` enrich | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | | | |
15
+ | Call graph callee origin | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | — | — | | — |
16
+ | Reverse `calledBy` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | — | — | | — |
17
17
 
18
- > v0.8.0 introduces **symbol extraction + imports parsing** for C / C++ / Kotlin / Swift. Graph/resolver/callgraph dispatch for these four lands in a follow-up release. (Ruby grammar in `tree-sitter-wasms@0.1.13` is unstable and was skipped.)
18
+ > As of v0.8.2, all four v0.8.0 languages have **cross-file graph + resolver** wiring: Kotlin (FQCN/package index), C/C++ (`#include` with header↔impl pairing), and Swift (module = directory under `Sources/`). Call-graph callee origin is resolved for Kotlin; for C/C++/Swift it stays limited because their imports don't name individual symbols. (Ruby grammar in `tree-sitter-wasms@0.1.13` is unstable and was skipped.)
19
19
 
20
20
  Each language uses the resolution strategy that fits it:
21
21
  - **TS/JS/Python** — relative paths (`./foo`, `..mod`) resolved against the importing file's directory, with TS-ESM `.js` → `.ts` rewriting.
@@ -23,6 +23,8 @@ Each language uses the resolution strategy that fits it:
23
23
  - **Rust** — `Cargo.toml` ancestor → `crate::` / `self::` / `super::` walks; supports `mod.rs` + Rust-2018 sibling-dir style.
24
24
  - **Java** — project-wide FQCN index (`package + "." + className → file`) built lazily on first cross-lang call; supports wildcard imports.
25
25
  - **C#** — namespace-to-files index plus a `<ns>.<TypeName>` index so `using App.Models` + `new Inventory()` resolves to the right file.
26
+ - **Kotlin** — project-wide FQCN index (`package + "." + ClassName → file`), like Java; wildcard `import pkg.*` pulls every file in the package.
27
+ - **C / C++** — `#include "..."` resolved against the including file's directory; headers auto-paired with same-name `.c`/`.cpp`/`.cc`/`.cxx` impl files. `<system>` includes stay external.
26
28
 
27
29
  For C# and Go (where imports don't name the called symbol), reverse `calledBy` falls back to **call-site scanning** of candidate files.
28
30
 
@@ -290,7 +292,7 @@ Parse a function body → extract every call expression, resolve callees via the
290
292
  ```
291
293
 
292
294
  Supports all 8 languages with per-language call extraction (TS/JS `member_expression`, Rust `field_expression`/`scoped_identifier`, Java `method_invocation`, C# `invocation_expression`, etc.) and constructor calls (`new Foo`).
293
- Handles TS/JS destructured aliases (`const { sign } = jwt`), Java FQCN imports, C# `using` namespaces (via project-wide type index), Rust `use crate::path::Item`, Go `pkg.Func` (via go.mod module path). Reverse `calledBy` uses call-site scanning for C# and Go where import statements don't name the called symbol.
295
+ Handles TS/JS destructured aliases (`const { sign } = jwt`), Java FQCN imports, C# `using` namespaces (via project-wide type index), Rust `use crate::path::Item`, Go `pkg.Func` (via go.mod module path), Kotlin FQCN/package imports, C/C++ `#include`, and Swift module imports (`import <Module>` → files under `Sources/<Module>/`). Reverse `calledBy` uses call-site scanning for C# and Go where import statements don't name the called symbol.
294
296
 
295
297
  **Params:** `path`, `function`, `scanDir`
296
298
 
@@ -480,6 +482,7 @@ src/
480
482
 
481
483
  | Version | What changed |
482
484
  |---------|--------------|
485
+ | **0.8.2** | **Swift cross-file wiring** — `import <Module>` resolves to that module's files (module = the `Sources/<Module>/` directory, else parent dir), wired into `build_symbol_graph` + `resolve_imports`. System modules (Foundation, UIKit, …) stay external. Completes cross-file graph/resolver support for all four v0.8.0 languages. |
483
486
  | **0.8.1** | **Cross-file graph wiring for Kotlin & C/C++** — Kotlin FQCN/package index + C/C++ `#include` resolution (with header↔impl pairing) wired into `build_symbol_graph`, `resolve_imports`, and `get_call_graph`. Fixes a parse-cache rel-path leak (stale `.file` poisoned the cross-lang index → doubled paths) and Kotlin call-graph extraction (`function_declaration` name + field-less `call_expression`). |
484
487
  | **0.8.0** | **4 new languages: C · C++ · Kotlin · Swift** — symbol extraction + imports parsing. C++ tracks access_specifier through class bodies. Kotlin handles `package`/`object`/`data class`. Swift handles `class`/`struct`/`enum` (all under `class_declaration`) and `protocol_declaration`. Ruby grammar in tree-sitter-wasms@0.1.13 is unstable — skipped. |
485
488
  | **0.7.0** | Go full resolution (reads `go.mod`, resolves package-as-directory) · C# reverse `calledBy` via call-site scanning · `csharpTypes` index lets `using` directives resolve to specific types · 4-suite test harness (smoke + graph-smoke + resolver-smoke + callgraph-smoke) |
package/dist/callgraph.js CHANGED
@@ -6,7 +6,7 @@ import { resolveOptions, loadProjectConfig } from "./config.js";
6
6
  import { detectLanguage } from "./registry.js";
7
7
  import { resolveImportPath, getOrBuildCrossLangIndex } from "./resolver.js";
8
8
  import { resolveCrossLangTarget } from "./crosslang.js";
9
- const CROSS_LANG = new Set(["java", "csharp", "rust", "go", "kotlin", "c", "cpp"]);
9
+ const CROSS_LANG = new Set(["java", "csharp", "rust", "go", "kotlin", "c", "cpp", "swift"]);
10
10
  function pushCall(out, callee, anchor) {
11
11
  if (callee && anchor)
12
12
  out.push({ callee, line: anchor.startPosition.row + 1 });
package/dist/crosslang.js CHANGED
@@ -26,6 +26,7 @@ export function buildCrossLangIndex(skeletons) {
26
26
  csharpTypes: new Map(),
27
27
  kotlinFqcn: new Map(),
28
28
  kotlinPackages: new Map(),
29
+ swiftModules: new Map(),
29
30
  };
30
31
  for (const skel of skeletons) {
31
32
  if (skel.language === "java") {
@@ -68,9 +69,32 @@ export function buildCrossLangIndex(skeletons) {
68
69
  index.kotlinFqcn.set(`${pkg}.${sym.name}`, skel.file);
69
70
  }
70
71
  }
72
+ else if (skel.language === "swift") {
73
+ const mod = swiftModuleOf(skel.file);
74
+ if (!mod)
75
+ continue;
76
+ const arr = index.swiftModules.get(mod) ?? [];
77
+ arr.push(skel.file);
78
+ index.swiftModules.set(mod, arr);
79
+ }
71
80
  }
72
81
  return index;
73
82
  }
83
+ /**
84
+ * Derive a Swift module name from a project-relative file path.
85
+ * SwiftPM convention: sources live under `Sources/<ModuleName>/...`, so the
86
+ * module is the path segment right after `Sources`. For flat layouts we fall
87
+ * back to the immediate parent directory name. Returns null for bare files.
88
+ */
89
+ function swiftModuleOf(relFile) {
90
+ const parts = relFile.split("/");
91
+ const srcIdx = parts.lastIndexOf("Sources");
92
+ if (srcIdx >= 0 && srcIdx + 1 < parts.length - 1)
93
+ return parts[srcIdx + 1];
94
+ if (parts.length >= 2)
95
+ return parts[parts.length - 2];
96
+ return null;
97
+ }
74
98
  /* ─── Rust module resolution ──────────────────────────────────────────────── */
75
99
  function findCargoRoot(fromAbs, projectRoot) {
76
100
  let dir = path.dirname(fromAbs);
@@ -385,5 +409,17 @@ export function resolveCrossLangTarget(imp, skel, fromAbs, projectRoot, index) {
385
409
  return null;
386
410
  return { kind: "file", files: filtered };
387
411
  }
412
+ if (skel.language === "swift") {
413
+ // `import <Module>` brings in another in-project module's public symbols
414
+ // (no symbol named). Resolve to that module's files; unknown modules
415
+ // (Foundation, UIKit, …) are external.
416
+ const files = index.swiftModules.get(imp.from);
417
+ if (files && files.length > 0) {
418
+ const filtered = files.filter((f) => f !== skel.file);
419
+ if (filtered.length > 0)
420
+ return { kind: "file", files: filtered };
421
+ }
422
+ return null;
423
+ }
388
424
  return null;
389
425
  }
package/dist/graph.js CHANGED
@@ -142,7 +142,8 @@ export function buildSymbolGraph(skeletons, root) {
142
142
  skel.language === "go" ||
143
143
  skel.language === "kotlin" ||
144
144
  skel.language === "c" ||
145
- skel.language === "cpp") {
145
+ skel.language === "cpp" ||
146
+ skel.language === "swift") {
146
147
  wireCrossLangImport(skel, imp, fromFileAbs, root, crossIndex, exportedSymbolMap, edges);
147
148
  }
148
149
  }
package/dist/resolver.js CHANGED
@@ -81,7 +81,7 @@ export async function getOrBuildCrossLangIndex(root) {
81
81
  const ext = path.extname(abs).toLowerCase();
82
82
  // Only Java/C# contribute to the index (Rust resolves via direct
83
83
  // module-path walk against the filesystem, no index needed).
84
- if (ext !== ".java" && ext !== ".cs" && ext !== ".kt" && ext !== ".kts")
84
+ if (ext !== ".java" && ext !== ".cs" && ext !== ".kt" && ext !== ".kts" && ext !== ".swift")
85
85
  continue;
86
86
  const rel = path.relative(key, abs).split(path.sep).join("/");
87
87
  try {
@@ -168,7 +168,7 @@ function assembleResolved(imp, resolvedAbs, resolvedRel, isExternal, enrichment)
168
168
  return out;
169
169
  }
170
170
  /* ─── Public entry point ──────────────────────────────────────────────────── */
171
- const CROSS_LANG = new Set(["java", "csharp", "rust", "go", "kotlin", "c", "cpp"]);
171
+ const CROSS_LANG = new Set(["java", "csharp", "rust", "go", "kotlin", "c", "cpp", "swift"]);
172
172
  export async function resolveFileImports(skel, absPath, root) {
173
173
  if (!skel.imports || skel.imports.length === 0)
174
174
  return [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "universal-ast-mapper",
3
- "version": "0.8.1",
3
+ "version": "0.8.2",
4
4
  "description": "MCP server that maps source files into a normalized code skeleton (JSON + HTML) using tree-sitter.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",