Commit Graph
19 Commits
Author SHA1 Message Date
rohit-jsfreaky 8be72ef7bf fix(js): stabilize unresolved local import target ids (#2457) 2026-08-12 14:20:21 +01:00
rajashidattapy ce942e144f fix(extract): canonicalize source_file to POSIX separators (#2627) 2026-08-11 20:03:55 +01:00
safishamsiandClaude Opus 4.8 e7ad693b5b fix(extract): don't guess an ambiguous barrel re-export (follow-up to #2034)
The barrel-chain resolver keyed (source, symbol) -> target as last-write-wins, so
a barrel re-exporting the same local name from two modules collapsed an importer's
edge onto whichever was learned last — a fabricated wrong edge. Learn into a set
per key and refuse to resolve when a name maps to more than one target; the edge
falls to the dangling-canonical fallback (dropped at build) instead. Adds a
regression test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-20 11:41:44 +01:00
HerenderKumar fab28ab7bc fix(extract): resolve alias re-exports and imports through barrels to the defining symbol (#1983) 2026-07-20 11:31:58 +01:00
oleksii-tumanov e5a4b51d87 fix(extract): rewrite alias re-export targets 2026-07-18 18:53:28 +01:00
oleksii-tumanov dea6ec0c24 fix(extract): remove dangling alias import edges 2026-07-17 10:54:07 +01:00
Synvoya 94392de640 fix(extract): don't report deferred import() as a file cycle (#1241)
`_dynamic_import_js` emitted a deferred `import('./x')` as a plain
`imports_from` edge, so `find_import_cycles` counted it as a static import.
A file that statically imports another which dynamically imports it back was
reported as a phantom circular dependency.

Keep the edge as `imports_from` (the dependency stays visible in the graph)
but mark it `deferred`, and skip deferred edges in `find_import_cycles`.

Closes #1241
2026-07-05 10:42:09 +01:00
oleksii-tumanovandClaude Opus 4.8 c8c604d08c feat(js): resolve namespace re-export bindings (export * as ns from) (#1552)
`export * as ns from './mod'` now creates a real symbol node for the
namespace binding `ns`, registers it as a named export (so a downstream
`import { ns }` resolves to it), and emits a file-level `re_exports` edge
to the target module. The binding is treated as a single opaque symbol —
`ns.member` accesses are deliberately NOT expanded into per-member
name-matching, avoiding the over-linking that would fan false edges.
Includes re-export cycle and deep-chain recursion guards.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 09:42:49 +01:00
oleksii-tumanovandClaude Opus 4.8 57469641cd feat(js): resolve TypeScript wildcard path aliases (#1544)
Extends the tsconfig path-alias resolver (#1531) with single-`*` wildcard
capture and substitution: a pattern like `@app/*` or `@*/interfaces`
captures the matched segment and substitutes it into each target in
declared order, honoring baseUrl and tsc's longest-prefix / exact-wins
specificity rules, and preserving #1531's first-existing-target-wins
fallback (no false edge when nothing resolves). Builds on the
_resolve_tsconfig_alias helper rather than reintroducing inline loops;
multi-star patterns remain out of scope.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 09:41:50 +01:00
guy oronandClaude Opus 4.8 e8dabadeb0 feat(imports): resolve workspace subpath exports via package.json exports map (#1308)
Workspace imports with subpath exports (e.g.
`import { x } from "@scope/pkg/browser"`) now resolve through the
package's `exports` map instead of falling back to a bare path. Supports
string values, condition objects, nested conditions, and single-`*`
wildcard patterns (`"./*": "./src/*.js"`), falling back to the existing
bare-path/index resolution when there is no exports map or no match.

Adapted from #1541, taking only the exports-map resolver and not that
PR's competing import-node-ID normalization (current v8 already resolves
the node-ID mismatch via the #1529 id-remap post-pass, and the PR's
_file_stem approach regressed the relative-input alias case). Two
hardening changes over the original:
- `default` is consulted LAST in the condition priority (it is Node's
  catch-all), so a matching `import`/`module`/`svelte` condition wins.
- Export targets that escape the package directory are rejected
  (`_contained_in_package`), so a malicious `exports` value like
  `"./x": "../../../etc/..."` cannot resolve to a file outside the package.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 13:57:16 +01:00
safishamsiandClaude Opus 4.8 2133539930 fix(js): resolve alias/workspace import edges + honor tsconfig paths fallbacks (#1529, #1531)
#1529 (regression from the 0.9.0 full-repo-relative node-ID migration):
relative JS/TS imports resolve to repo-relative paths and ride the
extract() id-remap to canonical node IDs, but tsconfig path-alias and
workspace-package imports resolve to ABSOLUTE paths (their bases are
.resolve()'d), so the import-target ID baked in the on-disk prefix and
never matched the repo-relative definition node — the edge was dropped at
build (common on Next.js/SvelteKit `@/`-alias codebases). The id-remap
post-pass now also registers the absolute-resolved form of each input
path (file-level edges) and both the input-form and absolute-form symbol
prefixes (named-import edges), so alias/workspace import targets remap to
the canonical ID. Verified the built graph has no orphan nodes or
dangling edges.

#1531: tsconfig `paths` values are ordered fallback lists (tsc tries each
target until one resolves), but only targets[0] was kept. The alias map
now stores all targets in order, and a single _resolve_tsconfig_alias
helper (replacing six duplicated inline loops) returns the first target
whose candidate exists on disk, falling back to the first candidate when
none exist (no false edge). Wildcards, baseUrl, and array `extends` are
preserved.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 13:14:36 +01:00
balloon72 9a7dbfbb84 fix js workspace import resolution (#1352)
Fixes #1334: detect npm/yarn package.json workspaces (array + yarn object form), pnpm precedence preserved. Reviewed: full suite 2087 passed, no regressions. Thanks @balloon72.
2026-06-17 10:29:47 +01:00
Jamie EvansandClaude Opus 4.8 6dc23db90f fix: emit symbol edges for default imports/exports
JS/TS symbol resolution only handled named imports. A default-exported
symbol (`export default class Foo`) imported as `import Foo from './foo'`
produced only a file→file `imports_from` edge; the class node received no
incoming symbol edge. On codebases that default-export most classes
(NestJS services/helpers/models, etc.) those symbols looked like isolated
leaf nodes, and `graphify affected "<Class>"` / `explain` reported no
callers.

Record default imports with imported_name="default", register a "default"
export for `export default <class|function|identifier>`, and let the
existing exported-origin resolver wire the `imports` edge — which also
resolves calls made through the local binding, even when it is renamed
(`import Bar from './foo'; new Bar()`). `export { X as default }` was
already handled via the export-clause path; anonymous defaults
(`export default class {}`) have no resolvable symbol and stay file-level.

Adds regression tests for default-export class/function/identifier import
resolution and renamed-binding call resolution.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 23:24:59 +01:00
Jamie EvansandClaude Opus 4.8 ec04152a90 fix: resolve tsconfig path aliases relative to baseUrl
_read_tsconfig_aliases joined alias targets onto the tsconfig's own
directory and ignored compilerOptions.baseUrl. In the common monorepo /
NestJS layout (baseUrl "./src" with "@services/*": ["services/*"]), the
alias resolved to <dir>/services instead of <dir>/src/services, so every
aliased import failed to resolve and the import edge was silently dropped
— leaving cross-file caller graphs nearly empty on alias-heavy TS repos.

Resolve `paths` relative to `baseUrl` (TypeScript's actual semantics),
defaulting to "." so configs without baseUrl keep their current behavior.
Add a regression test covering a subdirectory baseUrl; the existing alias
test only exercised baseUrl ".", which is why this slipped through.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 14:20:09 -04:00
SafiandClaude Sonnet 4.6 c898dc62cd match AST file-level node IDs to the skill.md spec (fixes #1033)
AST file nodes were ID'd from the full relative path plus extension
(match_script_pipeline_step_py) while semantic subagents follow the
{parent_dir}_{stem} spec (script_pipeline_step), so every file split
into two disconnected ghost nodes.

Fix at the single remap chokepoint in extract(): file node IDs and all
edge endpoints already funnel through the #502 relative-path remap, so
changing that remap to emit _file_node_id (one parent dir, no extension)
converts the node and every referencing edge together - Python, TS, Lua,
C and bash import edges all stay connected. symbol_resolution pre-computes
the canonical form directly (bypassing the remap) so it is synced too.

Per-site conversion (as attempted in #1038/#1065) orphans edges because
it moves the node without the edge targets; the chokepoint approach
avoids that entirely.

Backward compat for existing graphs: graphify extract --force, as the
skill.md spec already documents.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 12:23:56 +01:00
SafiandClaude Sonnet 4.6 d4e1d4b553 fix pnpm-workspace.yaml packages:'.' crash on Python 3.10 (closes #1083)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 13:13:23 +01:00
msotnikov 336652779b Fix: support array form of tsconfig extends (TypeScript 5.0) (#1017)
TS 5.0 allows `"extends": ["./a", "./b"]`. _read_tsconfig_aliases called
`extends.startswith("@")` directly, so an array raised
`AttributeError: 'list' object has no attribute 'startswith'`. _safe_extract
caught it and skipped the WHOLE file — and since alias resolution fires on any
path-aliased import, every TS file using `@/`-style imports in a repo with
array-extends tsconfig was dropped, yielding an empty graph.

Normalize `extends` to a list (str -> [str], list kept, else []), process
entries in order (later overrides earlier, current config's paths override all
parents per TS semantics), and skip scoped npm configs (`@...`) per entry as
before.

Adds regression test test_tsconfig_array_extends_alias_resolves_existing_ts_file.
2026-05-26 09:17:14 +01:00
TheFedaikin ab4e5424ca feat: add cross-language semantic contexts for Python, JS/TS, C#, and Java (#996) 2026-05-24 20:38:10 +01:00
Danil Tarasov e44e6e986c feat: add v8 affected and import-resolution support 2026-05-22 13:24:54 +01:00