Skip to content

TypeScript parser drops local bare imports and overstates graph quality #41

Description

@tuannx

Summary

The TypeScript/JavaScript parser currently records bare import specifiers on entities but treats every non-relative specifier as an external package. In a monorepo, that silently drops imports between local workspace packages or tsconfig path aliases.

This is especially risky because downstream recovery and quality metrics consume DependencyGraph.edges. The graph can look complete enough to produce a high score even though local package dependencies are missing.

Evidence

In src/arcade_agent/parsers/typescript.py, resolve_module() returns None for every specifier that does not start with ., with the comment # external package. The second pass then skips the import when no target module is returned.

The README currently advertises TypeScript/JavaScript as full support:
https://github.com/lemduc/arcade-agent/blob/main/README.md#L134

Minimal reproduction

With the existing parser:

a.ts:
  export class A {}

b.ts:
  import { A } from "./a";
  export class B { make(): A { return new A(); } }

the parser emits import edges. Replacing the specifier with a local bare alias:

import { A } from "@workspace/a";

while keeping the same local a.ts entity produces:

relative_edges: [('b.B', 'a.A', 'import'), ('b.B.make', 'a.A', 'import')]
bare_edges: []
bare_imports_recorded_on_entity: ['@workspace/a']

This is not asking the analyzer to add external dependency entities. The problem is that it cannot distinguish an external package from a local workspace/path-alias import.

Metric impact

For a fixture with two intra-component relative edges and two inter-component local bare-import edges, using the same component assignment:

incomplete graph: RCI = 1.0  (2 intra / 2 observed edges)
with the missing local edges: RCI = 0.5  (2 intra / 4 total edges)

So the current result is numerically correct for the incomplete graph, but it creates false confidence about the analyzed architecture. The graph/report also has no unresolved-local import diagnostic or import coverage/confidence field that would warn consumers before interpreting the score.

Real-world monorepo example

DeepSeek Harness uses local @deepseek-ai/dsh-* workspace packages. Its tsconfig.base.json maps those package names to packages/*/src, and its generated module graph documents package manifests as the canonical dependency source:

Running the current parser against the production TypeScript sources found 1,271 source-level imports referring to local workspace packages (909 unique package pairs); those bare specifiers are not emitted as TypeScript import edges.

Suggested direction

  1. Read workspace package.json manifests and tsconfig baseUrl/paths when resolving TypeScript/JavaScript imports.
  2. Distinguish external imports from unresolved local imports; do not silently classify a local-looking unresolved specifier as external.
  3. Add graph/report metadata for resolved, external, and unresolved imports, plus coverage/confidence, before computing or presenting architecture scores.
  4. Add a monorepo/path-alias regression fixture and assert that an incomplete graph is visibly flagged or prevents the score from being presented as a complete assessment.

If the intended contract is only relative-import analysis, this should instead be documented as a limitation and the TypeScript/JavaScript “full support” claim should be narrowed.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions