dep-resolver.ts

Import resolver primitives for the analysis session.

Exposes the ImportResolver token contract ({resolve, identity}) plus building blocks the session uses inside its three-phase setFiles pipeline:

- ensureLexerReady — one-time wasm init for es-module-lexer. Phase 1 is sync per-file; the session awaits this once before the loop starts. - lexImports — sync specifier extraction from already-prepared content (raw TS/JS, or svelte2tsx virtual content for .svelte files). - createDefaultResolver — the TS + tsconfig fallback used when neither AnalysisSessionOptions.resolveImport nor a per-call override is provided. Carries a fresh symbol identity per session (cache-key-safe). - normalizeResolveImport — coerces the public ResolveImport union (bare function or token-paired resolver) to an ImportResolver at each boundary. - wrapResolveImport — the fn→token primitive behind normalizeResolveImport: wraps a bare function in an ImportResolver, synthesizing a throwaway identity unless a stable one is passed.

@internal β€” subpath-importable for power users who want to drive resolution outside the session, but not part of the stable barrel surface.

@see session.ts for the three-phase ingestion pipeline that consumes these @see loadTsconfig in typescript-program.ts for the TS module-resolution compiler-options shortcut used by the default resolver

Declarations
#

9 declarations

view source

createDefaultResolver
#

dep-resolver.ts view source

(compilerOptions: CompilerOptions, projectRoot: string): ImportResolver

Create the default ImportResolver (TypeScript + tsconfig).

Uses ts.resolveModuleName against ts.sys directly β€” no ts.Program is built. Identity is a fresh symbol per call, so each session that constructs its own default gets a unique cache scope. Multiple sessions sharing one resolver instance share the cache scope (correct, since resolver state is shared too).

Falls back to appending .svelte when the bare specifier doesn't resolve β€” lets .svelte imports work without polluting the consumer's tsconfig.

compilerOptions

parsed tsconfig (from loadTsconfig)

type CompilerOptions

projectRoot

absolute project root for the module-resolution cache

type string

returns

ImportResolver

ensureLexerReady
#

dep-resolver.ts view source

(): Promise<void>

Ensure es-module-lexer's wasm runtime is initialized.

Idempotent and cheap after the first call. The session awaits this once at the top of setFiles so phase 1's per-file lex is purely synchronous.

returns

Promise<void>

ImportResolver
#

dep-resolver.ts view source

ImportResolver

Token-paired import resolver.

identity is a stable opaque token that keys the session's resolve cache alongside content. Cache hits require both (a) byte-for-byte identical source content and (b) identity equality. Naive function-reference keys would silently destroy cache reuse when callers wrap the resolver in fresh closures (a very common pattern in Vite/Rollup plugins) β€” opaque tokens lift the responsibility to the caller, where it can be done correctly.

resolve

Resolve an import specifier to an absolute file path, or null.

identity

Stable opaque token identifying this resolver's cache scope.

Two ImportResolvers with identity === to each other are treated as cache-equivalent. string for human-readable identities (e.g., 'vite-plugin-container'); symbol for generated sentinels.

type string | symbol

lexImports
#

dep-resolver.ts view source

(content: string, fileId: string): string[]

Lex import specifiers from prepared content.

Sync β€” caller must have awaited ensureLexerReady at least once before invoking. For .svelte files, pass the svelte2tsx-transformed virtual content, not the raw .svelte source (which isn't lex-able as JS/TS).

Dynamic imports (import(specifier) with non-literal arg) are omitted.

content

prepared file content (TS/JS, or svelte2tsx virtual)

type string

fileId

absolute file path (used for error messages)

type string

returns

string[]

specifiers in declaration order

throws

  • Error - if lexing fails (malformed source). Callers should catch and

noDepsResolver
#

dep-resolver.ts view source

ImportResolver

Shared no-op ImportResolver for the "dependency resolution disabled" case.

Stable string identity ('no-deps') instead of a per-call symbol so that repeated ingests within a long-lived session cache-hit on identity. Each session still owns its own cache (entries live on the per-session owned map; sessions don't share state), but within one session every reference to noDepsResolver is === to every other β€” so a Vite re-save of byte-identical content with resolveDependencies: false exercises the cache-hit branch. The resolver always returns null, so any two calls with identical content under this identity produce identical resolution results β€” string identity correctly captures that. Used by both the one-shot analyzeFromFiles path and the long-lived Vite plugin (resolveDependencies: false).

normalizeResolveImport
#

dep-resolver.ts view source

(value: ResolveImport | undefined): ImportResolver | undefined

Normalize the public ResolveImport union to an ImportResolver.

Wraps a bare function via wrapResolveImport (fresh synthesized identity); passes a token-paired resolver through unchanged. undefined in, undefined out β€” callers fall back to the session default. Call once per logical resolver scope: at session construction for the default, per call for an override.

value

type ResolveImport | undefined

returns

ImportResolver | undefined

ResolveImport
#

dep-resolver.ts view source

ResolveImport

Public resolver shape accepted across the API β€” a bare ResolveImportFn or the token-paired ImportResolver.

Every entry point that accepts resolveImport (analyze, analyzeFromFiles, createAnalysisSession, and the session's setFile/setFiles per-call override) takes this union, so the same value copy-pastes between them. Pass:

- a bare function for the common case β€” a fresh cache identity is synthesized at the boundary. Correct for one-shot use (analyze, analyzeFromFiles) and for a session default (wrapped once at construction, so identity is stable for the session's lifetime). - an ImportResolver with a stable identity when you need the session to reuse its resolve cache across calls where the same logical resolver is rebuilt as a fresh closure (Vite/Rollup plugins). A bare function handed to a *per-call* setFile/setFiles override is treated as a distinct resolver each call (fresh identity β†’ touched files re-resolve), which is the expected behavior for a deliberate one-off override.

ResolveImportFn
#

dep-resolver.ts view source

ResolveImportFn

Bare import-resolver function β€” the convenience form.

Resolve an import specifier to an absolute file path, or null if the specifier is unresolvable (external package, missing file, etc.). May return synchronously or asynchronously; sync returns are awaited harmlessly in the session's parallel resolve phase.

wrapResolveImport
#

dep-resolver.ts view source

(resolveImport: ResolveImportFn, identity?: string | symbol): ImportResolver

Wrap a bare resolveImport function into an ImportResolver token.

identity is optional; when omitted, a fresh Symbol('wrapped') is synthesized per call. The synthesized default suits single-use scopes β€” normalizeResolveImport relies on it to wrap a bare function for a one-shot analyze call or for a session default (wrapped once at construction, so the identity stays stable for the session's lifetime).

For a long-lived session that re-wraps the *same* logical resolver across calls (Vite plugin, LSP), a throwaway identity cache-misses every time β€” the fresh Symbol('wrapped') never compares equal. Pass a stable identity here, or β€” simpler β€” construct an ImportResolver ({resolve, identity}) directly and pass it through the ResolveImport union.

resolveImport

identity

type string | symbol
default Symbol('wrapped')

returns

ImportResolver

Imported by
#