mirror of
https://github.com/colbymchenry/codegraph.git
synced 2026-10-25 03:49:59 +08:00
fix(js,ts): an import of a package the repository declares itself links to that declaration (#2718)
A `declare module 'mammoth' { ... }` in a script .d.ts declares the module
outright, and TypeScript takes it before any file the specifier resolves to.
Nothing mapped a package name to a file in the repository, so an import of
such a package linked nothing, or, where the out-of-repo guard did not fire
(VS Code's extensions list no `vscode` dependency), a project namesake. A
bodiless function in an ambient context produced no node either, so
`convertToHtml` had nothing to link to.
- ambient-modules.ts: a token scanner for `declare module` blocks, a
per-context index of the project's declaration files, and the lookup the
import resolver makes: named, default (`export default`, `export =`),
export-clause and namespace-member imports, by position in the block.
- The import resolver consults a script declaration before a file a path
alias maps the specifier to (copilot's `paths` shim), and the import's
module reference and namespace or default binding link the declaring file.
- Extraction, both engines: a function_signature under `declare`, in
`declare global`, at a declaration file's top level or directly in its
`declare module` body is a function; never in a namespace, nor in an
ordinary module file's `declare module`, an augmentation.
- A module's function is reached from another file only through an import.
- A type merged across the files declaring one module is no single
declaration when a receiver is typed.
- Sync re-opens the importers of a package a changed declaration file
declares.
Augmentations, wildcard patterns, shorthands and test-fixture declarations
are left alone.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
642c7bb3a5
commit
a33040f786
@@ -681,6 +681,11 @@ impl<'t> Walker<'t> {
|
||||
// (the isInsideClassLike + methodTypes overlap is Python/Ruby-only)
|
||||
self.extract_function(node, None);
|
||||
skip_children = true;
|
||||
} else if kind == "function_signature" && self.variant.is_ts() && is_ambient_function_signature(node, self.file_path) {
|
||||
// A bodiless function that no implementation follows: a
|
||||
// `declare function`, a function in a `declare module` body or a `.d.ts`.
|
||||
self.extract_function(node, None);
|
||||
skip_children = true;
|
||||
} else if is_class_type(self.variant, kind) {
|
||||
self.extract_class(node);
|
||||
skip_children = true;
|
||||
@@ -1162,6 +1167,37 @@ fn is_ambient_export(node: Node) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// isAmbientFunctionSignature (languages/typescript.ts): a bodiless
|
||||
/// `function_signature` that is a function's declaration, not an overload of
|
||||
/// an implementation that follows it — a `declare function`, one in a
|
||||
/// `declare global` body, a declaration file's (`.d.ts`, `.d.mts`, `.d.cts`)
|
||||
/// own, and one a declaration file's `declare module 'x'` body declares.
|
||||
/// Never a namespace's (`declare namespace`, `module Foo {}`), nor one in an
|
||||
/// ordinary module file's `declare module` body, an augmentation.
|
||||
fn is_ambient_function_signature(node: Node, file_path: &str) -> bool {
|
||||
if node.kind() != "function_signature" {
|
||||
return false;
|
||||
}
|
||||
let lower = file_path.to_ascii_lowercase();
|
||||
let declaration_file = lower.ends_with(".d.ts") || lower.ends_with(".d.mts") || lower.ends_with(".d.cts");
|
||||
let mut ambient = false;
|
||||
let mut cur = node.parent();
|
||||
while let Some(p) = cur {
|
||||
match p.kind() {
|
||||
"internal_module" => return false,
|
||||
// `declare module 'x'`; `module Foo {}` is a namespace.
|
||||
"module" => {
|
||||
return declaration_file
|
||||
&& p.child_by_field_name("name").is_some_and(|n| n.kind() == "string");
|
||||
}
|
||||
"ambient_declaration" => ambient = true,
|
||||
_ => {}
|
||||
}
|
||||
cur = p.parent();
|
||||
}
|
||||
ambient || declaration_file
|
||||
}
|
||||
|
||||
/// hasExportDeclaration: a statement that exports by name or by assignment
|
||||
/// (`export {…}`, `export =`, `export default x`), not by declaring.
|
||||
fn has_export_declaration(block: Node) -> bool {
|
||||
|
||||
Reference in New Issue
Block a user