Import Map Pre-Resolution in Understand-Anything: Eliminating Re-Parsing in File Analyzers

Import map pre-resolution builds a shared resolution context once at script startup, allowing every file analyzer to resolve imports via cheap in-memory lookups instead of re-parsing configuration files.

The Understand-Anything project by Lum1104 implements a high-performance import analysis pipeline that avoids expensive re-parsing operations. By leveraging import map pre-resolution, the system processes large monorepos with linear time complexity rather than quadratic degradation. This article examines how extract-import-map.mjs constructs a reusable resolution context that eliminates redundant file system operations during per-file import analysis.

The Bottleneck of Per-File Configuration Parsing

Traditional static analysis tools often re-read configuration files for every source file they analyze. When resolving TypeScript imports, this means repeatedly parsing tsconfig.json files; for Go projects, re-reading go.mod modules; and for PHP codebases, re-parsing composer.json autoload maps. This approach creates O(n×m) complexity where n is the file count and m is the configuration depth, causing severe performance degradation in large codebases.

Architecture of the Pre-Resolution Cache

The solution implemented in understand-anything-plugin/skills/understand/extract-import-map.mjs separates expensive I/O operations from per-file resolution logic. The system loads all configuration data once, indexes it into memory-efficient data structures, and provides read-only access to individual file analyzers.

One-Time Loading of TypeScript, Go, and PHP Configurations

The pipeline begins by eagerly loading all project configurations before processing individual files. Three specialized functions parse and cache these settings:

  • loadTsConfigs parses every tsconfig.json found in the project and stores results in a Map, eliminating per-file re-reads of compiler options.
  • loadGoModules performs the same caching operation for all go.mod files discovered during the project scan.
  • loadPhpAutoloads extracts PSR-4 autoload mappings from every composer.json into a reusable lookup table.

These functions execute during script initialization, ensuring that JSON and CSON parsing occurs exactly once regardless of how many files reference these configurations.

Constructing the Shared Resolution Context

After collecting the project files, the buildResolutionContext function assembles a single immutable context object used by all resolvers. This context contains:

  • fileSet: A Set of every project-relative file path for O(1) existence checks.
  • tsConfigs, goModules, phpAutoloads: The pre-parsed configuration maps from the previous step.
  • Language-specific indexes (javaIndex, kotlinIndex, csIndex) built via buildSuffixIndex for rapid package-to-path resolution.

This construction happens once per execution, immediately after the file list collection completes.

Stateless Resolution Functions

Each language resolver—resolveTsJsImport, resolveGoImport, resolvePhpImport, and others—receives the shared context as a parameter. These functions perform pure computation without file system access, looking up pre-loaded maps and probing the in-memory fileSet. For example, the TypeScript resolver locates the nearest configuration directory using the cached tsConfigs map:

const tsConfigDir = findNearestConfigDir(importerDir, ctx.tsConfigs);

This pattern ensures that resolving an import requires only map lookups and string manipulation, avoiding any disk I/O or parsing overhead during per-file analysis.

Performance Characteristics: Linear Time Complexity

By deferring all heavy I/O to the initialization phase, import map pre-resolution transforms the algorithmic complexity of the analysis pipeline. The expensive operations—reading configuration files, parsing JSON, and building suffix indexes—execute exactly once. Per-file resolution becomes a series of cheap hashtable lookups, reducing the total runtime from O(n×m) to O(n) with respect to the file count.

This architecture produces deterministic results even when processing enterprise-scale monorepos containing thousands of source files and hundreds of configuration files.

Practical Implementation Workflow

The following pattern demonstrates how client code leverages the pre-resolution architecture:

// Step 1: Load the project files (produced by scan-project.mjs)
const input = JSON.parse(readFileSync('project-files.json', 'utf-8'));

// Step 2: Build the one-time resolution context
const ctx = buildResolutionContext(input.projectRoot, input.files);

// Step 3: Resolve imports for individual TypeScript files
const file = input.files[0]; // e.g., { path: 'src/foo.ts', imports: [...] }
const imports = file.imports.map(i => ({
  source: i.source,
  resolved: resolveTsJsImport(i.source, file, ctx),
}));

// Step 4: Resolve Go imports using the same cached context
const goResolved = resolveGoImport('github.com/example/util', file, ctx);

Notice that ctx remains constant across all resolution calls, while the resolution functions remain pure and stateless.

Summary

  • Pre-resolution eliminates redundant parsing by loading tsconfig.json, go.mod, and composer.json exactly once during script initialization.
  • The buildResolutionContext function in extract-import-map.mjs creates an immutable lookup cache containing file sets, configuration maps, and language-specific indexes.
  • Language resolvers operate as pure functions that read from the shared context without performing file system operations.
  • This architecture guarantees linear time complexity relative to file count, making large-scale repository analysis feasible.
  • The Understand-Anything project implements this pattern to ensure deterministic, high-performance import resolution across TypeScript, Go, PHP, Java, Kotlin, and C# codebases.

Frequently Asked Questions

What specific configuration files does the pre-resolution system cache?

The system caches TypeScript compiler configurations (tsconfig.json), Go module definitions (go.mod), and PHP autoload mappings (composer.json). According to the source code in understand-anything-plugin/skills/understand/extract-import-map.mjs, these are loaded via loadTsConfigs, loadGoModules, and loadPhpAutoloads respectively, with results stored in JavaScript Map objects for constant-time access.

How does the resolution context handle different programming languages?

The buildResolutionContext function constructs language-specific indexes for Java, Kotlin, and C# using buildSuffixIndex, while storing TypeScript, Go, and PHP configurations in dedicated maps. Each resolver function—such as resolveTsJsImport or resolveGoImport—receives this unified context and accesses only the relevant portions for its target language.

Why is import map pre-resolution more efficient than on-demand parsing?

On-demand parsing requires reading and parsing configuration files every time an import statement is encountered, resulting in quadratic complexity. Pre-resolution performs all heavy I/O and parsing once at startup, reducing per-file resolution to simple hashtable lookups and string operations that execute in constant time.

Where can I find the test suite that validates this behavior?

The deterministic behavior and absence of per-file re-parsing are verified in tests/skill/understand/test_extract_import_map.test.mjs. This test suite ensures that the import-map generation pipeline produces consistent results without redundant file system access across multiple execution scenarios.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →