Commit Graph

9 Commits

Author SHA1 Message Date
Giancarlo Erra 8c26ed8b49 fix(graph): allow Go resolution for projects with golang.org/* module paths
Address CodeRabbit review on PR #48. The early `isExternalModule` check
in resolveImport was filtering out any import starting with `golang.org/`
before the Go case had a chance to match it against the local module
path. This blocked legitimate local imports for any project whose own
module path starts with `golang.org/` (the Go team's own packages like
golang.org/x/sync, golang.org/x/net, etc., where each one's go.mod
declares `module golang.org/x/<name>`).

Skip the early external check for Go specifically. The Go case in
resolveImport already does its own module-path-aware classification
and returns null for everything outside the local module, including
stdlib and third-party deps. No regression in those cases.

New regression test asserts that
`module golang.org/x/custom` + `import "golang.org/x/custom/internal"`
resolves to the local internal/ package. Confirmed the test fails
without the fix and passes with it. Total: 752 unit tests pass.

Co-authored-by: mrsuit92 <mrsuit92@users.noreply.github.com>
2026-05-05 01:57:07 +01:00
Giancarlo Erra c156da1688 fix(graph): resolve Go imports via go.mod module path
Resolves #45. Reported by @mrsuit92.

Go projects produced 0 dependency edges in codebase_graph_query and
codebase_graph_stats even though import extraction worked correctly.
The Go case in resolveImport returned null unconditionally, with a
comment that resolution required go.mod analysis. This patch adds
that analysis and wires it into the resolver, mirroring the existing
buildJvmSuffixMap and buildCsNamespaceMap patterns.

Mechanism:

- buildGoModuleInfo reads <projectPath>/go.mod once at graph-build
  time, parses the `module <path>` directive, and walks the file set
  to build a directory-to-representative-file map for every Go
  package. _test.go files are excluded from representative selection
  because Go does not allow them to be imported from non-test code in
  other packages. Files are sorted lexicographically for
  deterministic representative selection across machines and runs.
  Returns null when go.mod is missing or has no parseable module
  directive; the resolver treats null as "no Go resolution available"
  and behaves exactly as before this patch in those cases.

- The Go case in resolveImport now strips the module path prefix
  from the import (handling the bare-module-path root case as well
  as subpackage paths) and looks up the resulting directory in the
  package map. Imports outside the module path return null and are
  treated as external dependencies (or stdlib already filtered
  upstream by isExternalModule).

- Map keys are forward-slash paths, not OS-native, so resolution
  works on Windows: Go imports are always forward-slash regardless
  of host OS, but path.dirname produces backslashes on Windows for
  nested directories. Normalising the key to forward slashes at
  build time keeps the lookup correct across platforms.

Limitations (deferred to follow-up issues if any user reports them):

- The parenthesised module ( path ) form in go.mod is not parsed.
  Not used by any mainstream Go project (verified against cobra,
  gin-gonic/gin, uber-go/zap real-world go.mod files).
- vendor/ directory shadowing of external imports is not honoured.
- replace directives in go.mod are not honoured.
- go.work multi-module workspaces are not handled (each workspace
  module would need its own go.mod read and prefix matching).

These are real Go features but each one widens the patch and
narrowly affects specific user populations. They can be added as
separate small PRs if a real user hits them.

Tests: 16 new cases in tests/unit/graph-resolution.test.ts covering
the new buildGoModuleInfo function (parses simple go.mod, handles
leading whitespace and trailing content, returns null on missing or
malformed go.mod, excludes _test.go from representative selection,
omits test-only directories, uses forward-slash keys for nested
packages) and the Go resolveImport case (back-compat null without
goModuleInfo, subpackage import resolves to lex-smallest non-test
.go file, root-package import resolves to a project-root .go file,
external imports return null, missing or malformed go.mod returns
null, _test.go excluded from representative selection, lexically
smallest file picked deterministically, similar-prefix imports do
not falsely resolve, nested-package imports work cross-platform).

Existing 735 unit tests continue to pass unchanged. Total: 751.

typecheck, biome, and CodeRabbit local review all clean. CodeRabbit
caught a real Windows path-separator bug in the first iteration; the
fix and a regression test for it are included.

Co-authored-by: mrsuit92 <mrsuit92@users.noreply.github.com>
2026-05-05 01:48:22 +01:00
Giancarlo Erra 8921690d72 fix(graph): resolve Python sibling-flat imports in service-style monorepos
Resolves #46. Reported by @mrsuit92.

Python projects where each top-level directory is a runnable application
root (a common service-style monorepo layout) had `import config` from
`service-a/main.py` produce 0 dependency edges, even when
`service-a/config.py` sits next to the importer. At runtime Python
resolves this correctly because the importer's directory is sys.path[0]
when the file is run as `python main.py` from inside its own directory.
The static resolver did not check that path.

The Python case in graph-resolution.ts only tried:

  <projectPath>/<module>.py
  <projectPath>/src/<module>.py
  <projectPath>/lib/<module>.py

It did not try `<sourceDir>/<module>.py`, so non-relative sibling
imports never resolved. Relative imports (`from .config import ...`)
already used sourceDir and worked.

Fix: add `<sourceDir>/<module>.py` as the LAST fallback, after the
existing project-root and src/lib checks. Tried last to preserve
project-root precedence, so any layout that resolved before this PR
continues to resolve to the same file. resolveRelativePath also handles
the `<sourceDir>/<module>/__init__.py` package case via its built-in
Python init fallback, so package-style sibling imports work too.

Tests: 5 new cases in tests/unit/graph-resolution.test.ts covering
sibling-flat resolution, dotted module paths, package via __init__.py,
project-root precedence preservation, and the negative case (no match
anywhere). Existing 730 tests continue to pass; total now 735.

typecheck, biome, and CodeRabbit local review all clean.

Co-authored-by: mrsuit92 <mrsuit92@users.noreply.github.com>
2026-05-05 00:54:22 +01:00
Giancarlo Erra ea69a72145 fix(graph): tighten C# namespace regex; capture nested declarations
The previous regex `^namespace\s+([\w.]+)` was anchored at column 0, so
nested namespace declarations (the `namespace Inner` block inside
`namespace Outer { ... }`) were silently missed. The capture group also
accepted invalid identifiers like `1Foo` and matched on stray
occurrences of the word `namespace` not followed by `;` or `{`.

The new regex `^\s*namespace\s+([A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)\s*(?=[;{])`:

- `^\s*` allows leading whitespace, so indented (nested) declarations
  are captured.
- The dotted-identifier capture requires each segment to start with a
  letter or underscore, matching C# identifier rules.
- `(?=[;{])` requires a real terminator, filtering out spurious matches.

Adds three regression tests: nested-namespace capture, rejection of
digit-leading identifiers, and the terminator-lookahead behaviour.

Found by CodeRabbit on PR #34 (nitpick).
2026-04-28 00:30:36 +01:00
Giancarlo Erra fc249fdfcf fix(graph): make C# namespace resolution deterministic
`buildCsNamespaceMap` previously iterated `fileSet` in fs.readdir()
traversal order, which POSIX does not guarantee. Combined with the
`candidates[0]` selection in `resolveImport`, this meant a `using`
directive could resolve to different files on different machines or
runs.

Sort the `.cs` paths lexically before scanning so candidate lists are
stable. Adds a regression test that builds the map twice from sets
populated in different orders and asserts both produce the same
candidate sequence and the same first candidate.

Found by CodeRabbit on PR #34.
2026-04-28 00:20:45 +01:00
Giancarlo Erra 0aaf3f1d75 fix(graph): resolve C# using directives via namespace scan (closes #33)
C# imports previously always returned null because there is no direct
filename mapping for `using X.Y.Z;`. As a result `codebase_graph_query`
reported zero edges for C# projects, and the symbol-level tools
(impact, flow, symbol) silently lost cross-file resolution because they
walk the file-import graph for Tier 2/3 candidates.

Build a namespace-to-files map once per graph build by regex-scanning
every `.cs` file for `^namespace X.Y.Z` (covers both block-scoped and
file-scoped C# 10+ syntax) and consult it from the csharp branch of
resolveImport. When a namespace spans multiple files the first
candidate is returned; multi-file fan-out is tracked as a follow-up.
External namespaces (System.*, Microsoft.*) are still filtered upstream
by isExternalModule, so the map is only consulted for project-internal
names.

Cost is O(n) reads at graph-build time, gated by a `hasCs` precheck so
non-C# projects pay nothing.

Adds 12 unit tests covering block-scoped, file-scoped, multi-file,
multi-namespace-per-file, commented-out lines, non-.cs files, empty
projects, unknown namespaces, and external (System.*) filtering.
2026-04-28 00:04:01 +01:00
jason.ma 5a734eb301 fix: resolve JVM imports in multi-module Maven/Gradle projects
Single-module resolution (src/main/java/…) already worked.
Multi-module layouts like:

  module-a/sub/src/main/java/com/example/Foo.java

were silently unresolved because the three fixed src-dir prefixes
never matched. The dependency graph therefore always produced 0
edges for any Java/Kotlin/Scala project that follows the standard
Maven/Gradle multi-module layout.

Fix: introduce `buildJvmSuffixMap()` which scans `fileSet` once
(O(n)) and registers every JVM source file by its class-path key
(i.e. everything after src/main/<lang>/). `resolveImport` accepts
the map as an optional last argument and falls back to it when the
existing prefix-based approach yields no result.

- `buildJvmSuffixMap` exported for reuse / testing.
- Map is built once per `buildCodeGraph` call, only when the
  project contains at least one JVM file — zero cost for other
  language projects.
- Lookup is O(1) per import, replacing a worst-case O(n) linear
  scan on every miss.
- Works on both Windows (backslash) and POSIX (forward-slash)
  because the map key is built with `path.sep`.
- 7 new unit tests covering: map construction, test-source
  exclusion, multi-module Java resolution, Kotlin resolution,
  unresolvable class, stdlib guard.

Fixes: enterprise Java/Spring Boot codebases (30+ Maven modules)
reporting 0 edges in codebase_graph_stats.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 20:23:03 +08:00
Csaba Tuncsik c7e160cb5c feat: add CSS @import tracking and path alias resolution to dependency graph
Add CSS @import extraction from Svelte/Vue <style> blocks and standalone
CSS/SCSS/SASS/LESS files. Add path alias resolution from tsconfig.json /
jsconfig.json compilerOptions.paths with extends chain support.
2026-03-18 20:18:44 +01:00
Giancarlo Erra 3f0ed5a286 feat: SocratiCode v1.0.0 — initial release 2026-02-28 17:06:21 +00:00