socraticode
Version:
SocratiCode — MCP server for local codebase indexing, semantic search, and code dependency graphs. All private, all local via Docker.
186 lines • 7.82 kB
TypeScript
import { Lang } from "@ast-grep/napi";
export interface ImportInfo {
moduleSpecifier: string;
isDynamic: boolean;
/** CommonJS require uses a different conditional-export branch from import. */
isRequire?: boolean;
isCssImport?: boolean;
/**
* Fallback specifier when the primary moduleSpecifier cannot be resolved.
* Used by Godot .tscn/.tres ext_resource: when both uid:// and path are
* present, uid is the primary specifier and path is the fallback, so the
* resolver can try the path if UID resolution misses.
*/
fallbackSpecifier?: string;
/**
* True when the specifier comes from a declaration that brings a file into
* the module tree — a Rust `mod foo;` — rather than from a path that merely
* names something. Rust needs the difference: a module has to be declared
* before an unanchored path can reach it, and the declaration is the only
* evidence of that in the file.
*/
isModuleDeclaration?: boolean;
/**
* The name a module declaration puts in the declaring file's own scope.
* Absent when the declaration is written inside an inline `mod` block,
* where the name belongs to the block rather than to the file.
*
* It is not the specifier: `#[path = "custom.rs"] mod foo;` travels as the
* path it declares, while the name it brings into scope is `foo`, and it is
* `foo` an unanchored `use foo::Item;` in that file may reach.
*/
declaredName?: string;
/**
* True when the path was written inside an inline `mod { … }` block and its
* head is not a module that block declares. Such a head cannot reach a module
* the *file* declares: rustc asks for an anchor first. Checked on cargo
* 1.98.0 — `pub mod corelib;` at file level with `use corelib::marker;`
* inside `pub mod block { … }` is E0432, "a similar path exists: use
* crate::corelib::marker" (`super::` where the block sits deeper).
*
* It is the mirror of the case already handled the other way round, where a
* declaration written inside a block does not count at file level.
*/
fromInlineBlock?: boolean;
/** Distinguishes Godot path semantics for extends, preload, and runtime load. */
godotImportKind?: "extends" | "preload" | "load";
}
/**
* Reset the per-language dedupe set. Intended for tests that want to assert
* deterministically on extraction warnings.
*/
export declare function resetImportExtractionWarnings(): void;
/**
* Decode a GDScript string literal from its raw source text.
*
* GDScript supports:
* - Single-quoted: 'hello', '''triple single'''
* - Double-quoted: "hello", \"\"\"triple double\"\\"\"
* - Raw strings: r"no escapes", r'no escapes', r\"\"\"triple\"\"
*
* In raw strings, escape sequences are not processed — the content is
* taken literally. In non-raw strings, \\n, \\t, \\\\, \\", \\', \\uXXXX
* are decoded.
*
* Returns the decoded string value, or null if the text is not a valid
* GDScript string literal.
*/
export declare function decodeGdscriptString(raw: string): string | null;
/**
* Parse a TSCN/.tres section header line into its resource type and
* key-value attributes.
*
* TSCN whitespace is insignificant outside strings. Headings are:
* [<resource_type> key1=value1 key2=value2 ...]
*
* This tokenizer handles:
* - Leading whitespace before [
* - Spaces around = in key=value pairs
* - Quoted values with escapes
* - Arbitrary attribute order
* - Comments (lines starting with ; outside a section)
*
* Returns { type, attrs } or null if the line is not a section header.
*/
export declare function parseTscnSectionHeader(line: string): {
type: string;
attrs: Map<string, string>;
} | null;
/**
* Syntax-aware GDScript import fallback for hosts where the optional native
* parser cannot load. The lightweight lexer excludes comments and string
* bodies before recognizing direct preload/load arguments and extends forms.
*/
export declare function extractGdscriptImportsRegex(source: string): ImportInfo[];
/**
* Tokenizer-based import extraction for Godot resource files (.tscn/.tres).
*
* These are text-based INI-like files with no tree-sitter grammar.
* Dependencies are declared via `[ext_resource path="..."]` lines.
*
* The path can be:
* - A `res://` path (absolute within the Godot project)
* - A relative path (relative to the .tscn/.tres file's directory)
* - A `uid://` path (resolved via .uid sidecar files)
*
* TSCN whitespace is insignificant outside strings, so the tokenizer handles
* leading whitespace, spaces around =, arbitrary attribute order, and quoted
* values with escapes. See the TSCN documentation:
* https://docs.godotengine.org/en/stable/engine_details/file_formats/tscn.html
*
* Scene-to-scene composition is represented by PackedScene entries in
* ext_resource, not a separate [instance] section. The `instance` keyword
* is an attribute of a [node] declaration, not a section heading.
*
* Both `uid` and `path` attributes are extracted. When both are present,
* Godot prefers the UID and falls back to the text path only when the UID
* cannot be resolved. The resolver handles this priority.
*/
export declare function extractGodotResourceImports(source: string): ImportInfo[];
/** The subset of the ast-grep node API this module reads. */
interface SgNodeLike {
kind(): string;
text(): string;
parent(): SgNodeLike | null;
prev(): SgNodeLike | null;
field(name: string): SgNodeLike | null;
findAll(matcher: {
rule: {
kind: string;
};
}): SgNodeLike[];
children(): SgNodeLike[];
range(): {
start: {
index: number;
};
end: {
index: number;
};
};
}
/**
* Flatten one `use` tree into the module paths it names, one per leaf:
*
* crate::config::Config → ["crate::config::Config"]
* crate::{a::Thing, b} → ["crate::a::Thing", "crate::b"]
* crate::a::{self, b as c} → ["crate::a", "crate::a::b"]
* crate::a::* → ["crate::a"]
*
* A braced group is not a module path and never resolved to one; recording the
* leaves instead is what lets `use crate::{parser, printer}` draw an edge to
* each of the two files rather than to their parent module — or, in a flat
* crate with no parent module file, to nothing at all.
*/
export declare function expandRustUseTree(tree: string): string[];
/** A half-open range of character indexes in a source. */
interface Span {
start: number;
end: number;
}
interface UnwrappedSource {
/** The rewritten Rust source. */
source: string;
/** Its tree, already built by the check that accepted it. */
root: SgNodeLike;
/**
* Every ERROR node that tree holds — each inside a macro unwrapped in this
* pass or an earlier one, or the check would not have accepted it. The next
* pass forgives exactly these, and nothing else.
*/
errors: Span[];
}
/**
* Extract import statements from source code using ast-grep.
* Returns raw module specifiers for each language's import syntax.
*
* `unwrapped` is internal, and only the Rust macro pass passes it: the tree it
* had to build to accept the source it rewrote, so the same text is not parsed
* twice, and the regions it blanked, which the next pass needs to tell its own
* damage from the last pass's leftovers. Nothing else should pass it — it
* describes one particular `source` and would be read as if it described this
* one.
*/
export declare function extractImports(source: string, lang: Lang | string, ext: string, unwrapPassesLeft?: number, unwrapped?: UnwrappedSource): ImportInfo[];
export {};
//# sourceMappingURL=graph-imports.d.ts.map