socraticode
Version:
SocratiCode — MCP server for local codebase indexing, semantic search, and code dependency graphs. All private, all local via Docker.
584 lines • 32.7 kB
TypeScript
import type { PathAliases } from "./graph-aliases.js";
import type { GraphInputRecorder } from "./graph-inputs.js";
/**
* Whether `seg` names a JVM source-set directory in a `src/<sourceSet>/<lang>`
* layout. `main` covers the classic Maven/Gradle convention; the `*Main` forms
* cover Kotlin Multiplatform and Gradle source sets (`commonMain`, `androidMain`,
* `iosMain`, `jvmMain`, `nativeMain`, `desktopMain`, `appleMain`, `iosArm64Main`, ...).
*/
export declare function isJvmSourceSetDir(seg: string): boolean;
/**
* Build a suffix lookup map for JVM (Java/Kotlin/Scala) files in multi-module projects.
*
* For a Maven/Gradle multi-module layout such as:
* module-a/sub-module/src/main/java/com/example/Foo.java
* the map entry is:
* key: "com/example/Foo.java" (forward-slash-normalized)
* value: "module-a/sub-module/src/main/java/com/example/Foo.java"
*
* This enables O(1) resolution of fully-qualified class names that cannot be
* found via the standard prefix-based scan (e.g. src/main/java/…).
*
* Call this once per graph build and pass the result to resolveImport.
*
* Classic src/main sources take precedence over KMP source sets. The map view
* retains the first file within each group; resolveImport can also select a
* retained KMP candidate matching the importing source set. Pass a
* lexicographically ordered set (as buildCodeGraph does) for stable picks.
* Keys are normalized, but values retain the input fileSet paths.
*/
export declare function buildJvmSuffixMap(fileSet: Set<string>): Map<string, string>;
/**
* Build a namespace lookup map for C# files.
*
* Scans every `.cs` file in the project for `namespace X.Y.Z` declarations
* (both block-scoped `namespace X { ... }` and file-scoped `namespace X;`
* introduced in C# 10) and builds:
*
* key: "App.Services"
* value: ["src/Services/OrderService.cs", "src/Services/UserService.cs"]
*
* Used to resolve `using App.Services;` to the candidate files that
* contribute to that namespace. Without this, every C# `using` resolved
* to `null` and C# projects produced an empty file-import graph.
*
* Files are processed in lexicographic order so the resulting candidate
* lists are deterministic across machines and runs. This matters because
* multi-file namespaces resolve to `candidates[0]` in `resolveImport`,
* and a stable "first" file is required for reproducible graphs.
*
* Cost: O(n) reads at graph-build time (negligible vs. AST parsing). Files
* with no `namespace` declaration are silently skipped. Read failures are
* swallowed since this is best-effort.
*/
export declare function buildCsNamespaceMap(fileSet: Set<string>, projectPath: string, recorder?: GraphInputRecorder): Map<string, string[]>;
/**
* Build a PSR-4 prefix map for PHP projects from every in-repo `composer.json`.
*
* PHP namespaces carry no path information — `App\Models\User` only maps to
* `app/Models/User.php` because `composer.json` says so. The convention-based
* fallback in `resolveImport` guesses that mapping from the directory layout,
* which works for a single-package project whose namespace root happens to
* match a real directory name, and silently drops every import that does not:
*
* - `Database\Seeders\Foo` → the directory is `database/seeders`, lowercase,
* so the case-sensitive guess misses it
* - `Acme\Auth\Models\Role` → lives in `packages/auth/src/Models/Role.php`,
* a path no namespace-shaped guess can reach
*
* The second case is the norm in Composer monorepos (path repositories), where
* every domain package declares its own PSR-4 root. Those imports resolved to
* nothing, so package-to-package edges were absent from the graph entirely and
* impact analysis reported "no callers" for code with many callers.
*
* Reads the root manifest plus each nested one (`autoload` and `autoload-dev`),
* mapping every prefix to directories relative to the manifest that declared
* it.
*
* Call this once per graph build and pass the result to resolveImport.
*/
export declare function buildPhpPsr4Map(projectPath: string, recorder?: GraphInputRecorder): Map<string, string[]>;
/**
* Build a fully-qualified-class-name lookup map for PHP files, derived from
* the declarations themselves rather than from any manifest.
*
* PSR-4 stays the authority wherever it exists, and this map is consulted only
* after it misses. It exists for the code PSR-4 cannot describe: a package that
* ships no autoload map at all and registers its namespaces at run time —
*
* $loader->addNamespace('Acme', PLUGIN_DIR . '/src/acme');
*
* — which is how WordPress plugins overwhelmingly do it, and which a
* composer.json reader cannot see. Such a package declares `"autoload": {}` or
* no manifest at all, so every `use` it makes and every `use` of it resolved to
* nothing, leaving whole trees orphaned in the graph while their symbols
* extracted perfectly (issue #120). Interpreting `spl_autoload_register` is not
* needed to fix that: the file that declares `Acme\Schema\Role` is a fact the
* source states outright.
*
* key: "Acme\\Schema\\Role"
* value: ["src/acme/schema/RoleSchema.php"]
*
* Scans every PHP file unconditionally rather than only those under roots no
* PSR-4 prefix covers, following `buildCsNamespaceMap`. One map means one
* resolution regime everywhere, and it keeps working where a composer.json
* exists but is incomplete — a partial map is the common case, not an edge one.
*
* The key is the exact FQCN, declared namespace and declared name together,
* with no tail matching, so a collision means two files literally declaring the
* same class — in practice a vendored duplicate. Files are read in
* lexicographic order and `resolveImport` takes `candidates[0]`, so the pick is
* deterministic across machines; an edge to either copy is a true "depends on
* this FQCN" edge, which is why this guesses rather than refusing, matching the
* C# resolver.
*
* Reads `fileSet`, which is already ignore-filtered, so a `vendor/` tree the
* project excluded contributes nothing and one it deliberately re-included is a
* legitimate target — no unconditional skip is needed here, unlike the
* manifest walk in `findComposerManifests`.
*
* Declarations are matched by regex at line start, as in `buildCsNamespaceMap`,
* which costs one read per file instead of a parse. Positional association
* carries the braced multi-namespace form (`namespace A { … } namespace B { … }`)
* as well as the file-scoped one. A `class` line inside a heredoc would be
* matched as a declaration; a false FQCN nobody imports resolves nothing.
*/
export declare function buildPhpFqcnMap(fileSet: Set<string>, projectPath: string, recorder?: GraphInputRecorder): Map<string, string[]>;
/**
* Information needed to resolve Go imports to local files for ONE module.
*
* A project may contain several Go modules (a monorepo with nested
* `go.mod` files), so {@link buildGoModuleInfo} returns one of these per
* `go.mod` it discovers. `modulePath` is the value of the `module`
* directive in `go.mod` (e.g. `github.com/user/repo`); imports starting
* with this prefix are local to that module. `moduleDir` is the
* project-relative directory that contains `go.mod` ("." when it sits at
* the indexed root). `packageMap` maps a Go package's directory *relative
* to the module directory* (with "." for the module's own root package)
* to the lex-smallest non-test `.go` file in that directory (stored
* project-relative), used as a representative target for file-level edges.
*
* {@link buildGoModuleInfo} returns an empty array when no `go.mod` is
* found or none parse. Callers must treat an empty result as "no Go
* resolution available" and return null for all Go imports.
*/
export interface GoModuleInfo {
modulePath: string;
moduleDir: string;
packageMap: Map<string, string>;
}
/** Map each in-project Elixir `defmodule` name to its files, deterministically. */
export declare function buildElixirModuleMap(fileSet: Set<string>, projectPath: string, recorder?: GraphInputRecorder): Map<string, string[]>;
/**
* Build Go module-resolution info for a project, one entry per `go.mod`.
*
* Discovers EVERY `go.mod` under the project root (so a monorepo with
* nested modules is supported, not just a single root-level `go.mod`),
* parses each module path with a regex, and constructs a per-module
* directory-to-representative-file map across the `.go` files owned by
* that module. `_test.go` files are excluded — Go does not allow them to
* be imported from non-test code in other packages. Files are sorted
* lexicographically before each map is built so the representative
* chosen for a multi-file package is deterministic across machines/runs.
*
* `go.mod` is discovered by walking the tree independently of `fileSet`:
* `go.mod` has no AST grammar and is not an extra extension, so it is
* NEVER admitted by `getGraphableFiles` and therefore never present in
* `fileSet`. An earlier attempt scanned `fileSet` for `go.mod` entries,
* which matched nothing in a real build and silently broke Go resolution
* for every project (issue #82, including the root-level #45 case). The
* walk reuses the same ignore filter `getGraphableFiles` uses, so a
* `go.mod` inside `node_modules/`, `.git/`, or a gitignored path is
* skipped.
*
* Each `.go` file is attributed to its DEEPEST owning module (the module
* whose `moduleDir` is the longest directory prefix of the file). The
* tie-break is directory DEPTH, not string length: the root module
* (`"."`, depth 0) must never win over a single-segment nested module
* whose directory name happens to be short (e.g. `z`, which is string
* length 1 just like `"."`).
*
* `packageMap` keys are MODULE-relative (the package directory with the
* module directory stripped), because a Go import strips the module path
* down to a module-relative directory. The map VALUES stay
* project-relative (they are the `fileSet` entries), so resolution needs
* no further translation even for a nested module.
*
* Cost: one tree walk (ignore-filtered) + one `readFileSync` per module
* plus an O(n) walk over `.go` files at graph-build time. Lookups during
* resolution are O(1).
*
* Limitations (deferred to follow-up issues if reported):
* - Parenthesized `module ( ... )` form (rare; not used by any
* mainstream Go project).
* - `vendor/` directory shadowing of external imports.
* - `replace` directives in `go.mod`.
* - `go.work` multi-module workspaces.
*/
export declare function buildGoModuleInfo(fileSet: Set<string>, projectPath: string, recorder?: GraphInputRecorder): GoModuleInfo[];
/**
* Map every in-repo Dart package name to its package root directory
* (project-relative, forward-slash; `"."` for a root-level `pubspec.yaml`).
*
* Dart/Flutter code imports intra-project files by package URI almost
* exclusively — `import 'package:my_app/src/service.dart';` is the layout
* convention pub itself generates — and a package URI carries no path
* information: `package:<name>/<rest>` maps to `<package_root>/lib/<rest>`
* only because `<name>`'s pubspec lives at `<package_root>`. Without this
* map every such import resolved to null (issue #106), so Flutter projects
* lost nearly all file-graph edges and impact analysis reported "no callers"
* for files with many consumers. Nested manifests are read too, which is what
* resolves cross-package `package:<sibling>/...` imports in pub-workspace and
* melos monorepos.
*
* The `name:` field is matched only at column 0: pubspec is YAML, so a
* nested `name:` key legitimately appears indented inside dependency blocks
* (`dependencies: { foo: { hosted: { name: ... } } }`), and an unanchored
* match could map a dependency's name to the wrong root. Pub package names
* are lowercase identifiers (`[a-z0-9_]`); the optional quote accepts the
* YAML-quoted spelling of the same name. A manifest without a matching
* `name:` contributes nothing; the first manifest (in sorted path order) to
* declare a name wins, mirroring `buildJvmSuffixMap`'s first-wins
* determinism.
*
* Call this once per graph build and pass the result to resolveImport.
*/
export declare function buildDartPackageMap(projectPath: string, recorder?: GraphInputRecorder): Map<string, string>;
/**
* One `pyproject.toml` found in the tree: where it sits, the import roots it
* implies, and the sibling packages it declares importable.
*/
export interface PythonManifest {
/** Project-relative directory holding the manifest; `"."` at the root. */
dir: string;
/** Import roots it implies: its own directory and its `src/`. */
roots: string[];
/**
* Project-relative directories of the workspace members it declares,
* resolved against the manifests actually discovered. Empty for a manifest
* with no `[tool.uv.workspace]` section.
*/
members: string[];
}
/**
* Discover every `pyproject.toml` in the tree and record, for each, the import
* roots it implies and the workspace members it declares.
*
* A packaged Python project puts its importable modules under the manifest's
* directory in one of two layouts: `src/` (what `uv init --lib`, hatchling
* and setuptools all generate) or flat, directly beside the manifest. Neither
* is derivable from the import itself. `from usa_wa_adapter_sos.house import
* build` names no directory that appears in
* `packages/usa-wa-adapter-sos/src/usa_wa_adapter_sos/house/build.py`: the
* distribution directory is dashed, the module is underscored, and `src/`
* sits between them. The resolver's existing project-root `src/`+`lib/` probe
* only reaches a single-package repo, so in a workspace every cross-package
* import — and every package's own absolute self-import — resolved to null
* (issue #107). A 362-file uv workspace built 3 edges.
*
* Both roots are recorded per manifest without probing the filesystem for
* which layout is in use: a root that does not exist holds no files, so it
* matches nothing, and the check would cost a `stat` per manifest to remove
* lookups that already miss.
*
* Roots are recorded rather than module names enumerated under them. Names
* would have to come from the directories actually present — a distribution
* name and its import name are not reliably related (Pillow imports as `PIL`),
* so `[project] name` cannot supply them — and enumerating directories alone
* would miss single-module distributions, where `src/mymodule.py` is the whole
* importable surface and no directory bears the module's name. Trying each
* root in turn covers both, and covers PEP 420 namespace packages (no
* `__init__.py`) for free, since it never asks what a directory contains.
*
* The only part of a manifest that is read is its `[tool.uv.workspace]`
* member list, which {@link pythonRootsForFile} needs to tell a sibling
* package apart from an unrelated project that merely carries a manifest.
*
* Sorted by directory so that when two manifests contribute a root holding the
* same top-level module name, the same one wins on every machine.
*
* Call this once per graph build and pass each file's scoped roots (see
* {@link pythonRootsForFile}) to resolveImport.
*/
export declare function buildPythonManifests(projectPath: string, recorder?: GraphInputRecorder): PythonManifest[];
/**
* The import roots that apply to one source file, nearest first.
*
* Two rules, each fixing a way a flat list of every root in the tree resolves
* an import to the wrong file:
*
* **Scope.** A manifest applies to a file only when it sits on the file's
* ancestor path, or when an ancestor manifest declares it as a workspace
* member. A repo's `examples/demo/pyproject.toml`, a checked-in `third_party/`
* sdist and an editable checkout inside an environment directory all carry
* manifests while sitting on no `sys.path` the file could import through;
* without this rule each one registers roots globally and turns an import that
* correctly resolved to nothing into a fabricated edge. Workspace members are
* the exception because that is exactly what a member declaration states: the
* sibling package IS importable from here, and resolving cross-package imports
* is what issue #107 is about.
*
* **Order.** Roots containing the file come first, deepest first, so a package
* resolves its own modules before a sibling's. Without this, a per-service
* monorepo of flat `uv init --app` services — each with its own `config.py` —
* resolved `import config` to whichever service sorted first alphabetically,
* drawing a confident edge into another service's file. Remaining in-scope
* roots follow lexicographically: they are the cross-package candidates, where
* nothing about the import says which package was meant, so the tie is broken
* the same way on every machine rather than left to walk order.
*
* `relSourceDir` is the file's directory, project-relative and
* forward-slashed, `"."` for a file at the root.
*/
export declare function pythonRootsForFile(manifests: PythonManifest[], relSourceDir: string): string[];
/** One crate found in the tree: what it is called, and where its modules start. */
export interface RustCrate {
/** Project-relative directory holding its `Cargo.toml`; `"."` at the root. */
dir: string;
/**
* The name other crates import it by — `[package] name` with dashes turned
* into underscores, which is the translation Cargo itself performs. Null for
* a manifest that declares no package (a `[workspace]`-only root) or no
* library target, neither of which anything can import by name.
*/
name: string | null;
/**
* `[package] name` with dashes turned into underscores, which is the name a
* dependency on this crate is declared under — while `name` above is what
* the code writes, and the two differ wherever `[lib] name` is set. Null for
* a manifest that declares no package.
*/
packageName: string | null;
/**
* Set when the manifest could not be parsed. The crate still contributes its
* convention targets, but nothing is known about what it declares, and a
* check that reads "declares nothing" off an unread manifest would cost the
* package every cross-crate edge — one unreadable `Cargo.toml` must not.
*/
manifestUnread?: true;
/** Project-relative path of the library root module, when the crate has one. */
libRoot: string | null;
/**
* Project-relative paths of every root module the manifest implies: the
* library, plus each binary, integration test, example and benchmark, plus
* the build script. Each is the top of its own module tree, which is what
* `crate::` is relative to.
*/
roots: string[];
/**
* The Rust edition the manifest declares, defaulting to `"2015"` when the
* key is absent, as Cargo does. It decides both target autodiscovery and
* where an unanchored path in a `use` starts counting from.
*/
edition: string;
/**
* Map from local dependency name / alias (with dashes turned to underscores)
* to the target crate's package name (with dashes turned to underscores).
*
* Covers:
* [dependencies]
* my_alias = { package = "actual-package-name", ... }
* as well as `[workspace.dependencies]` referenced via `workspace = true`.
*/
aliases?: Record<string, string>;
/**
* The dependency names this manifest fetches from outside the project — a
* registry or a git remote — rather than from a directory of its own.
*
* A dependency with no `path` is a different crate from a project crate that
* happens to carry the same name, and cargo compiles against the fetched one.
* `log = "0.4"` beside a workspace member also called `log` drew an edge into
* that member: verified on cargo 1.98.0 with a `compile_error!` in the local
* crate, which builds clean because rustc never reads it.
*/
externalDeps?: string[];
}
/**
* Build the crate map for a Rust project, one entry per `Cargo.toml`.
*
* Rust names its own code three ways, and only one of them says anything about
* the filesystem. `mod foo;` names a sibling file, which the resolver already
* followed. `crate::`, `super::` and `self::` name a position in the module
* tree, whose root is a target's root module — `src/lib.rs`, `src/main.rs`, or
* whatever `[[bin]] path` declares. `some_crate::` names a whole other crate,
* which is only in this project if a manifest here declares it, under a name
* whose dashes Cargo turns into underscores (`sailor-core` is imported as
* `sailor_core`). None of the three resolved before this map existed: every
* specifier containing `::` returned null, so a Rust project's file graph came
* out as its bare `mod` declarations and nothing else.
*
* Targets are read from the manifest where declared and taken by convention
* otherwise, matching Cargo's own autodiscovery rules per edition:
* - `autobins`, `autotests`, `autoexamples`, `autobenches`, `autolib` flags
* turn off autodiscovery for their respective directories when set to `false`.
* - In edition 2015, autodiscovery is turned off by default for a target type
* when at least one target of that type is manually declared. In edition
* 2018+, autodiscovery remains enabled unless explicitly set to `false`.
* - `[package] build = false` disables the build script target (`build.rs`).
* - `[workspace] exclude` patterns exclude matching directories from being
* registered as importable workspace members (`name = null`).
*
* The manifest is parsed with the same TOML reader the Python side uses rather
* than scanned, so a `path` key belonging to a dependency is a different key
* rather than nearby text. A manifest that cannot be parsed contributes its
* convention targets and no name: one unreadable `Cargo.toml` must not cost the
* whole project its Rust edges.
*
* Call this once per graph build and pass the result to resolveImport.
*/
export declare function buildRustCrateMap(fileSet: Set<string>, projectPath: string, recorder?: GraphInputRecorder): RustCrate[];
/**
* Resolve one Rust module path to the project file it names.
*
* `relSourceFile` is the importing file, project-relative and forward-slashed.
* `crates` comes from {@link buildRustCrateMap}; an empty list leaves
* `crate::` and cross-crate paths unresolved, which is what a tree carrying no
* `Cargo.toml` should produce.
*
* `super::` and `self::` are answered from the file's own position rather than
* from its crate root, so they resolve in a manifest-less tree too. Climbing
* stops at the crate root's directory when a root is known: a path cannot leave
* its crate through `super`, and without the guard `super::super::x` at the top
* of a workspace member would reach into a sibling's files.
*/
export declare function resolveRustImport(specifier: string, relSourceFile: string, fileSet: Set<string>, crates: RustCrate[], declaredMods?: Map<string, string>, isDeclaration?: boolean): string | null;
/**
* Pre-built index mapping GDScript class_name declarations to their file paths.
* Normal graph construction builds one scoped index per Godot project with
* buildGodotProjectIndexes() to avoid repeated file reads and cross-project
* name leakage.
*/
export type ClassNameIndex = Map<string, string>;
/**
* Scan all .gd files in a fileSet for `class_name X` declarations and build
* a global Map<className, relativePath>.
*
* @deprecated Legacy helper retained for compatibility. New graph-building
* code should use buildGodotProjectIndexes() so class names remain scoped to
* their nearest Godot project.
*/
export declare function buildClassNameIndex(projectPath: string, fileSet: Set<string>): ClassNameIndex;
/**
* A per-Godot-project class_name index. Maps each Godot project root
* (absolute path to the directory containing project.godot) to a
* ClassNameIndex scoped to the .gd files under that root.
*
* This supports repositories with multiple Godot projects (nested or
* sibling), where each project has its own class_name registry and
* res:// root. A class_name in one project must not resolve extends
* in another project.
*/
export type GodotProjectIndexes = Map<string, ClassNameIndex>;
/**
* A per-Godot-project UID index. Maps `uid://...` strings to relative
* file paths within the project. Built from `.uid` sidecar files and
* `uid="uid://..."` attributes in `.tscn`/`.tres` file headers.
*
* Godot prefers UIDs over text paths for resource loading. When both
* are present in an `[ext_resource]` declaration, the UID takes priority
* and the text path is used only as a fallback when the UID cannot be
* resolved.
*/
export type GodotUidIndex = Map<string, string>;
export type GodotProjectUidIndexes = Map<string, GodotUidIndex>;
/** Per-graph-build cache for nearest project.godot lookups. */
export type GodotRootCache = Map<string, string | null>;
/**
* Build per-Godot-project UID indexes from `.uid` sidecar files and
* `.tscn`/`.tres` file headers.
*
* For each `.uid` sidecar file (e.g. `Player.gd.uid`), reads the UID
* string and maps it to the corresponding resource file. For `.tscn`
* and `.tres` files, parses the `uid="uid://..."` attribute from the
* file header.
*
* @param projectPath - Absolute path to the SocratiCode indexing root
* @param fileSet - Set of relative file paths
* @returns Map of Godot project root (absolute) → UID index (uid:// → relative path)
*/
export declare function buildGodotUidIndexes(projectPath: string, fileSet: Set<string>, rootCache?: GodotRootCache, recorder?: GraphInputRecorder): GodotProjectUidIndexes;
/**
* Build per-Godot-project class_name indexes for a set of files.
*
* For each .gd file, finds the nearest project.godot ancestor and adds
* the file's class_name to that project's index. Files not under any
* project.godot are skipped (they have no Godot project context).
*
* @param projectPath - Absolute path to the SocratiCode indexing root
* @param fileSet - Set of relative file paths
* @returns Map of Godot project root (absolute) → ClassNameIndex (relative paths)
*/
export declare function buildGodotProjectIndexes(projectPath: string, fileSet: Set<string>, rootCache?: GodotRootCache, recorder?: GraphInputRecorder): GodotProjectIndexes;
/**
* Find the nearest Godot project root for a given source file.
*
* Walks up from the file's directory looking for project.godot.
* Returns the absolute path to the directory containing it, or null
* if no project.godot is found. This is per-file (not per-repo) to
* support repositories with multiple Godot projects.
*
* @param sourceFile - Absolute path to the source file
* @param godotProjectIndexes - Retained for compatibility with existing callers.
* @param rootCache - Optional cache scoped to one graph build.
*/
export declare function findGodotRootForFile(sourceFile: string, _godotProjectIndexes?: GodotProjectIndexes, rootCache?: GodotRootCache): string | null;
/**
* Resolve a module specifier to a relative file path within the project.
* Returns null if the module is external (e.g., npm package, stdlib).
*
* `language` is a display label as produced by `getLanguageFromExtension`
* (e.g. "shell", "typescript") — that is what `buildCodeGraph` passes. "bash"
* has its own case below as a synonym for "shell". The capitalised `Lang`
* grammar names ("JavaScript", "TypeScript", "Tsx", "Html", "Css") match no
* case. Not every display label has one either, so a switch miss is always
* possible, and it returns the same null an external module does.
*
* @param aliases - Optional path aliases (tsconfig/jsconfig paths) for JS/TS resolution
* @param classNameIndex - Pre-built GDScript class_name → file path index for O(1) extends resolution
* @param godotProjectRoot - Pre-resolved Godot project root (directory containing project.godot).
* When provided, res:// paths resolve relative to this instead of walking the filesystem per call.
* @param godotUidIndex - Pre-built UID → relative path index for uid:// resolution.
* When provided, uid:// paths are resolved via this index. When absent,
* uid:// paths cannot be resolved and return null.
* @param fallbackSpecifier - Optional path fallback for a primary uid:// specifier.
* @param godotImportKind - GDScript construct that supplied the path. Runtime
* load paths use the Godot project root; extends and preload use the source directory.
*/
export declare function resolveImport(moduleSpecifier: string, sourceFile: string, projectPath: string, fileSet: Set<string>, language: string, aliases?: PathAliases, jvmSuffixMap?: Map<string, string>, csNamespaceMap?: Map<string, string[]>, goModuleInfo?: GoModuleInfo[] | null, phpPsr4Map?: Map<string, string[]>, dartPackageMap?: Map<string, string>, pythonImportRoots?: string[], elixirModuleMap?: Map<string, string[]>, phpFqcnMap?: Map<string, string[]>, rustCrates?: RustCrate[], rustDeclaredMods?: Map<string, string>, rustIsDeclaration?: boolean, classNameIndex?: ClassNameIndex, godotProjectRoot?: string | null, godotUidIndex?: GodotUidIndex, fallbackSpecifier?: string, godotImportKind?: "extends" | "preload" | "load"): string | null;
/**
* Whether a shell `source` specifier has the shape of a literal path. This reads
* the text only — a well-shaped specifier naming a file that does not exist is
* still true here, and fails later at the file-set lookup.
*
* None of the shapes below can be told apart from a literal path here, and each
* has to be screened before resolution rather than after, because normalising
* them lands on a file the shell would not open — and a match there is the
* failure being prevented rather than a salvage:
*
* - extractImports captures the whole argument list, so any whitespace-class
* character means the text cannot be told apart from a word list or a path
* still carrying its quotes. Bash splits on fewer of them than `\s` matches —
* its default IFS is space, tab and newline — but skipping all of them errs
* toward dropping an edge rather than inventing one.
* - A backslash is a shell escape and never a separator, so the unescaped path
* is unknowable here; `path.resolve` treats it as a separator on win32, which
* would cancel `./x\..\lib.sh` down to a file the script never names.
* - A trailing `/` or `/.` names a directory, which cannot be sourced, and
* normalisation would drop that trailing segment, landing on the same-named
* file.
* - A `..` following a named segment cancels it lexically during normalisation,
* so `./x/../lib.sh` lands on lib.sh beside the script. The shell walks
* components instead and loads nothing when `x` is absent or is not a
* directory. Only a leading run of `.`/`..` anchors, and an empty segment from
* `//` does not end that run.
*
* These screen the raw captured text, so a change that honours quoting and
* strips arguments has to unquote and split upstream of here.
*/
export declare function hasLiteralShellPathShape(specifier: string): boolean;
/**
* Find the Godot project root for a set of files by checking if project.godot
* exists at the project path or any parent. Called once per graph build so
* that res:// resolution doesn't walk the filesystem for every import.
* Returns the absolute path to the directory containing project.godot,
* or null if not found.
*/
export declare function findGodotProjectRootForProject(projectPath: string): string | null;
/**
* Parse the `[autoload]` section from a Godot `project.godot` file and build
* a map of autoload name → relative script path.
*
* The `[autoload]` section has the form:
* [autoload]
* GameManager="*res://scripts/core/GameManager.gd"
* InputManager="res://scripts/core/InputManager.gd"
*
* The leading `*` means the autoload is enabled (singleton). Both `*` and
* non-`*` entries are included — the autoload name is still a global type
* regardless of singleton status.
*
* @param godotProjectRoot - Absolute path to the directory containing project.godot
* @returns Map of autoload name → relative path (forward-slash, relative to project root)
*/
export declare function parseGodotAutoloads(godotProjectRoot: string, recorder?: GraphInputRecorder): Map<string, string>;
//# sourceMappingURL=graph-resolution.d.ts.map