@shanepadgett/tau-agent 0.33.1 → 0.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/context.md +29 -20
- package/docs/extending-tau-agent.md +63 -24
- package/extensions/appshot/index.ts +112 -111
- package/extensions/aside/README.md +7 -0
- package/extensions/aside/index.ts +168 -0
- package/extensions/aside/panel.ts +83 -0
- package/extensions/branch/index.ts +38 -21
- package/extensions/cache-diagnostics/index.ts +70 -58
- package/extensions/checkpoint/README.md +9 -0
- package/extensions/checkpoint/checkpoint-budget.ts +79 -0
- package/extensions/checkpoint/checkpoint.ts +277 -0
- package/extensions/checkpoint/index.ts +102 -0
- package/extensions/checkpoint/messages.ts +169 -0
- package/extensions/checkpoint/prompt.ts +24 -0
- package/extensions/checkpoint/settings.ts +27 -0
- package/extensions/commit/commit-effort.ts +3 -3
- package/extensions/context/README.md +12 -8
- package/extensions/context/definitions.ts +178 -55
- package/extensions/context/index.ts +192 -160
- package/extensions/context/panel.ts +57 -37
- package/extensions/context/sync.ts +139 -89
- package/extensions/context/validation.ts +37 -25
- package/extensions/effort/README.md +1 -1
- package/extensions/effort/index.ts +3 -3
- package/extensions/effort/state.ts +3 -18
- package/extensions/explore/guidance.ts +6 -47
- package/extensions/explore/index.ts +38 -53
- package/extensions/explore/{ast/read → read}/hook.ts +12 -7
- package/extensions/explore/{ast/tools → tools}/ast-search.ts +15 -19
- package/extensions/explore/{ast/tools → tools}/context.ts +16 -23
- package/extensions/explore/{ast/tools → tools}/deps.ts +11 -15
- package/extensions/explore/{ast/tools → tools}/discover.ts +15 -17
- package/extensions/explore/{ast/tools → tools}/impact.ts +20 -23
- package/extensions/explore/{ast/tools → tools}/outline.ts +21 -24
- package/extensions/explore/{ast/tools → tools}/relationships.ts +23 -32
- package/extensions/explore/{ast/tools → tools}/render.ts +1 -1
- package/extensions/explore/{ast/tools → tools}/reverse-deps.ts +11 -15
- package/extensions/explore/{ast/tools → tools}/show.ts +16 -19
- package/extensions/explore/tools/target-params.ts +9 -0
- package/extensions/footer/index.ts +75 -56
- package/extensions/handoff/index.ts +8 -30
- package/extensions/image-gen/index.ts +46 -40
- package/extensions/patch/executor.ts +190 -135
- package/extensions/patch/matcher.ts +82 -48
- package/extensions/patch/parser.ts +149 -105
- package/extensions/patch/render.ts +32 -39
- package/extensions/patch/summary.ts +30 -26
- package/extensions/ready/README.md +7 -0
- package/extensions/ready/index.ts +58 -0
- package/extensions/ready/model.ts +128 -0
- package/extensions/ready/packs.ts +272 -0
- package/extensions/ready/render.ts +445 -0
- package/extensions/ready/scan.ts +760 -0
- package/extensions/reference/panel.ts +28 -16
- package/extensions/review/index.ts +63 -51
- package/extensions/review/panel.ts +5 -34
- package/extensions/runtime-context/context.ts +30 -26
- package/extensions/script-runner/README.md +2 -2
- package/extensions/script-runner/index.ts +122 -82
- package/extensions/silent-command-runner/index.ts +38 -23
- package/extensions/subagent/agents/context-sync.md +185 -33
- package/extensions/subagent/agents/scout.md +2 -2
- package/extensions/subagent/agents.ts +137 -84
- package/extensions/subagent/cmux-dashboard.ts +39 -30
- package/extensions/subagent/index.ts +79 -59
- package/extensions/subagent/resume.ts +1 -1
- package/extensions/subagent/run.ts +304 -193
- package/extensions/subagent/runtime.ts +781 -343
- package/extensions/tau/index.ts +47 -38
- package/extensions/tau-help/help.md +14 -6
- package/extensions/tool-loader/README.md +4 -2
- package/extensions/tool-loader/index.ts +77 -52
- package/extensions/web/index.ts +6 -3
- package/extensions/web/webfetch.ts +114 -86
- package/package.json +3 -3
- package/schemas/tau.schema.json +20 -33
- package/shared/bounded-text-result.ts +1 -0
- package/shared/checkpoint-visibility.ts +9 -0
- package/shared/events.ts +28 -10
- package/shared/isolated-session.ts +71 -29
- package/shared/model-effort.ts +9 -19
- package/shared/model-fallback/index.ts +66 -41
- package/shared/settings/load.ts +45 -38
- package/shared/temporary-output-store.ts +16 -10
- package/{extensions/explore → src}/ast/adapter.ts +11 -2
- package/{extensions/explore → src}/ast/engine.ts +54 -38
- package/{extensions/explore → src}/ast/format/ast-search.ts +15 -6
- package/{extensions/explore → src}/ast/format/context.ts +3 -6
- package/src/ast/format/deps.ts +94 -0
- package/{extensions/explore → src}/ast/format/discover.ts +2 -2
- package/{extensions/explore → src}/ast/format/impact.ts +9 -11
- package/{extensions/explore → src}/ast/format/outline.ts +2 -2
- package/{extensions/explore → src}/ast/format/relationships.ts +11 -7
- package/{extensions/explore → src}/ast/format/show.ts +1 -1
- package/src/ast/format/targeted-result.ts +20 -0
- package/src/ast/grammars/c_sharp.wasm +0 -0
- package/{extensions/explore → src}/ast/grammars/manifest.json +9 -12
- package/{extensions/explore → src}/ast/grammars/manifest.ts +0 -4
- package/{extensions/explore → src}/ast/graph/file-graph.ts +210 -98
- package/{extensions/explore → src}/ast/graph/relationships.ts +285 -72
- package/{extensions/explore → src}/ast/ir.ts +6 -0
- package/src/ast/languages/csharp-file-deps.ts +90 -0
- package/{extensions/explore → src}/ast/languages/csharp.ts +9 -40
- package/src/ast/languages/dotted-index.ts +131 -0
- package/{extensions/explore → src}/ast/languages/file-dep-util.ts +22 -13
- package/src/ast/languages/fixtures/sample.cs +53 -0
- package/src/ast/languages/fixtures/sample.cs.expected.json +156 -0
- package/src/ast/languages/fixtures/sample.go +37 -0
- package/src/ast/languages/fixtures/sample.go.expected.json +96 -0
- package/src/ast/languages/fixtures/sample.java +40 -0
- package/src/ast/languages/fixtures/sample.java.expected.json +126 -0
- package/src/ast/languages/fixtures/sample.kt +31 -0
- package/src/ast/languages/fixtures/sample.kt.expected.json +134 -0
- package/src/ast/languages/fixtures/sample.md +23 -0
- package/src/ast/languages/fixtures/sample.md.expected.json +44 -0
- package/src/ast/languages/fixtures/sample.rs +54 -0
- package/src/ast/languages/fixtures/sample.rs.expected.json +178 -0
- package/src/ast/languages/fixtures/sample.swift +45 -0
- package/src/ast/languages/fixtures/sample.swift.expected.json +147 -0
- package/src/ast/languages/fixtures/sample.ts +45 -0
- package/src/ast/languages/fixtures/sample.ts.expected.json +141 -0
- package/src/ast/languages/fixtures/sample.tsx +36 -0
- package/src/ast/languages/fixtures/sample.tsx.expected.json +59 -0
- package/{extensions/explore → src}/ast/languages/go-file-deps.ts +6 -0
- package/{extensions/explore → src}/ast/languages/go.ts +21 -3
- package/{extensions/explore → src}/ast/languages/java.ts +5 -38
- package/src/ast/languages/jvm-file-deps.ts +135 -0
- package/{extensions/explore → src}/ast/languages/kotlin.ts +5 -39
- package/{extensions/explore → src}/ast/languages/rust-file-deps.ts +3 -3
- package/{extensions/explore → src}/ast/languages/rust.ts +21 -13
- package/{extensions/explore → src}/ast/languages/swift-file-deps.ts +22 -15
- package/{extensions/explore → src}/ast/languages/swift.ts +9 -39
- package/{extensions/explore → src}/ast/languages/tree.ts +47 -0
- package/{extensions/explore → src}/ast/languages/typescript-file-deps.ts +108 -0
- package/{extensions/explore → src}/ast/languages/typescript-package-surface.ts +4 -3
- package/{extensions/explore → src}/ast/languages/typescript.ts +3 -5
- package/{extensions/explore → src}/ast/markdown.ts +72 -47
- package/{extensions/explore → src}/ast/queries/ast-search.ts +164 -146
- package/{extensions/explore → src}/ast/queries/composite-target.ts +1 -1
- package/{extensions/explore → src}/ast/queries/context.ts +116 -80
- package/{extensions/explore → src}/ast/queries/discover.ts +154 -105
- package/src/ast/queries/impact.ts +291 -0
- package/{extensions/explore → src}/ast/queries/outline.ts +4 -2
- package/{extensions/explore → src}/ast/queries/show.ts +46 -42
- package/{extensions/explore → src}/ast/query.ts +1 -1
- package/{extensions/explore → src}/ast/registry.ts +1 -2
- package/{extensions/explore → src}/ast/scan.ts +1 -1
- package/src/ast/session.ts +50 -0
- package/{extensions/explore → src}/ast/slice.ts +8 -0
- package/{extensions/explore → src/ast}/traverse.ts +32 -20
- package/src/file-injection/index.ts +547 -0
- package/src/image-generation/client.ts +50 -31
- package/src/image-generation/index.ts +177 -134
- package/src/index.ts +2 -0
- package/src/tool-loading/index.ts +58 -0
- package/extensions/context/evidence.ts +0 -517
- package/extensions/context/projection.ts +0 -141
- package/extensions/context/state.ts +0 -30
- package/extensions/context/write-scope.ts +0 -109
- package/extensions/explore/ast/format/deps.ts +0 -86
- package/extensions/explore/ast/grammars/odin.wasm +0 -0
- package/extensions/explore/ast/languages/csharp-file-deps.ts +0 -189
- package/extensions/explore/ast/languages/fixtures/sample.cs +0 -17
- package/extensions/explore/ast/languages/fixtures/sample.java +0 -21
- package/extensions/explore/ast/languages/fixtures/sample.kt +0 -15
- package/extensions/explore/ast/languages/fixtures/sample.odin +0 -28
- package/extensions/explore/ast/languages/fixtures/sample.rs +0 -31
- package/extensions/explore/ast/languages/fixtures/sample.swift +0 -25
- package/extensions/explore/ast/languages/jvm-file-deps.ts +0 -217
- package/extensions/explore/ast/languages/odin-file-deps.ts +0 -175
- package/extensions/explore/ast/languages/odin.ts +0 -407
- package/extensions/explore/ast/queries/impact.ts +0 -250
- package/extensions/explore/outline-injection.ts +0 -151
- package/extensions/explore/read/autoread.ts +0 -118
- package/extensions/working-memory/README.md +0 -17
- package/extensions/working-memory/checkpoint.ts +0 -242
- package/extensions/working-memory/index.ts +0 -341
- package/extensions/working-memory/memory.ts +0 -235
- package/extensions/working-memory/render.ts +0 -185
- package/extensions/working-memory/settings.ts +0 -38
- package/extensions/working-memory/state.ts +0 -158
- package/shared/autoread.ts +0 -234
- package/shared/context-messages.ts +0 -19
- package/shared/outline-injection.ts +0 -56
- /package/{extensions/explore → src}/ast/format/composite.ts +0 -0
- /package/{extensions/explore → src}/ast/grammars/kotlin.wasm +0 -0
- /package/{extensions/explore → src}/ast/grammars/swift.wasm +0 -0
- /package/{extensions/explore → src}/ast/identity.ts +0 -0
- /package/{extensions/explore → src}/ast/package-surface.ts +0 -0
- /package/{extensions/explore/ast/read/policy.ts → src/ast/read-policy.ts} +0 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
import type { FileDepResolver } from "../adapter.ts";
|
|
3
|
+
import { buildDottedIndex, resolveDottedFile, resolveDottedPackage, type HeadScan } from "./dotted-index.ts";
|
|
4
|
+
import { externalId, internalPaths, isWithin, packageDirectory } from "./file-dep-util.ts";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Java / Kotlin file deps. Real multi-module builds put module B's sources
|
|
8
|
+
* anywhere, so resolution goes through a package-path index rather than a fixed
|
|
9
|
+
* list of source-root suffixes: a type import resolves to the declaring file, a
|
|
10
|
+
* wildcard or top-level member import to the package directory.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
type JvmFileDepOptions = {
|
|
14
|
+
/** File extensions to match, e.g. .java / .kt */
|
|
15
|
+
extensions: readonly string[];
|
|
16
|
+
/** Leading packages always treated as external. */
|
|
17
|
+
externalPrefixes: readonly string[];
|
|
18
|
+
/** Top-level declaration keywords, in this language's syntax. */
|
|
19
|
+
declarationPattern: RegExp;
|
|
20
|
+
memoPrefix: string;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const PACKAGE_LINE = /^[ \t]*package\s+([\w.]+)\s*;?[ \t]*$/mu;
|
|
24
|
+
|
|
25
|
+
function scanJvmHead(head: string, declarationPattern: RegExp): HeadScan {
|
|
26
|
+
const pkg = PACKAGE_LINE.exec(head)?.[1] ?? "";
|
|
27
|
+
if (pkg.length === 0) return { packages: [], names: [] };
|
|
28
|
+
const names: HeadScan["names"] = [];
|
|
29
|
+
// Fresh lastIndex per scan: the pattern is shared across files.
|
|
30
|
+
const pattern = new RegExp(declarationPattern.source, declarationPattern.flags);
|
|
31
|
+
for (const match of head.matchAll(pattern)) {
|
|
32
|
+
const name = match[2];
|
|
33
|
+
if (name !== undefined) names.push({ pkg, name });
|
|
34
|
+
}
|
|
35
|
+
return { packages: [pkg], names };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function startsLower(text: string): boolean {
|
|
39
|
+
const first = text.charAt(0);
|
|
40
|
+
return first.length > 0 && first === first.toLowerCase() && first !== first.toUpperCase();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Split an import into the dotted path plus how it should resolve.
|
|
45
|
+
* Package segments are lowercase and type segments capitalized, so the first
|
|
46
|
+
* capitalized segment ends a type import; an import with none names a package
|
|
47
|
+
* member (Kotlin top-level fun/val) and resolves to the package.
|
|
48
|
+
*/
|
|
49
|
+
function classifyImport(specifier: string): { path: string; packageLike: boolean } {
|
|
50
|
+
let s = specifier.trim().replace(/;$/u, "");
|
|
51
|
+
s = s.replace(/^static\s+/u, "");
|
|
52
|
+
if (s.endsWith(".*")) {
|
|
53
|
+
// Keep the full package path — do not peel segments (all-lowercase packages).
|
|
54
|
+
return { path: s.slice(0, -2).trim(), packageLike: true };
|
|
55
|
+
}
|
|
56
|
+
const parts = s.split(".").filter((part) => part.length > 0);
|
|
57
|
+
const typeAt = parts.findIndex((part) => !startsLower(part));
|
|
58
|
+
// pkg.Type.member / pkg.Type.Companion.member all resolve through pkg.Type.
|
|
59
|
+
if (typeAt >= 0) return { path: parts.slice(0, typeAt + 1).join("."), packageLike: false };
|
|
60
|
+
if (parts.length <= 1) return { path: parts.join("."), packageLike: false };
|
|
61
|
+
return { path: parts.slice(0, -1).join("."), packageLike: true };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function isExternalPackage(path: string, prefixes: readonly string[]): boolean {
|
|
65
|
+
for (const prefix of prefixes) {
|
|
66
|
+
if (path === prefix || path.startsWith(`${prefix}.`)) return true;
|
|
67
|
+
}
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function createJvmFileDepResolver(options: JvmFileDepOptions): FileDepResolver {
|
|
72
|
+
return async (fromPath, specifier, host, signal) => {
|
|
73
|
+
signal.throwIfAborted();
|
|
74
|
+
const { path, packageLike } = classifyImport(specifier);
|
|
75
|
+
if (path.length === 0) return { kind: "unresolved" };
|
|
76
|
+
if (isExternalPackage(path, options.externalPrefixes)) return externalId(path);
|
|
77
|
+
|
|
78
|
+
const index = await buildDottedIndex(
|
|
79
|
+
host,
|
|
80
|
+
options.memoPrefix,
|
|
81
|
+
options.extensions,
|
|
82
|
+
(head) => scanJvmHead(head, options.declarationPattern),
|
|
83
|
+
signal,
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
if (packageLike) {
|
|
87
|
+
const pkg = resolveDottedPackage(index, fromPath, path);
|
|
88
|
+
if (pkg === undefined || !isWithin(host.scopeRoot, pkg.dir)) return externalId(path);
|
|
89
|
+
return packageDirectory(path, pkg.dir, pkg.fileCount);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const file = resolveDottedFile(index, fromPath, path);
|
|
93
|
+
if (file !== undefined && isWithin(host.scopeRoot, file) && host.ownsPath(file)) {
|
|
94
|
+
if (resolve(file) === resolve(fromPath)) return { kind: "unresolved" };
|
|
95
|
+
return internalPaths([file]);
|
|
96
|
+
}
|
|
97
|
+
// No declaring file, but the package may still be in the repo: generated
|
|
98
|
+
// sources (Android `R`, Apollo fragments) and declarations below the head
|
|
99
|
+
// window land here, and the package they live in is the real dependency.
|
|
100
|
+
const owningPackage = path.split(".").slice(0, -1).join(".");
|
|
101
|
+
const pkg = owningPackage.length === 0 ? undefined : resolveDottedPackage(index, fromPath, owningPackage);
|
|
102
|
+
if (pkg === undefined || !isWithin(host.scopeRoot, pkg.dir)) return externalId(path);
|
|
103
|
+
return packageDirectory(owningPackage, pkg.dir, pkg.fileCount);
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const MODIFIERS =
|
|
108
|
+
"public|protected|private|static|final|abstract|sealed|non-sealed|strictfp|default|internal|open|data|value|annotation|enum|expect|actual|external|inline|suspend|const|lateinit|companion|operator|infix|tailrec";
|
|
109
|
+
|
|
110
|
+
/** `@Anno`s and modifiers, then the keyword and the declared name. */
|
|
111
|
+
const JAVA_DECLARATION = new RegExp(
|
|
112
|
+
`^[ \\t]*(?:@[\\w.]+(?:\\([^)]*\\))?[ \\t]*)*(?:(?:${MODIFIERS})[ \\t]+)*(class|interface|enum|record|@interface)\\s+([A-Za-z_]\\w*)`,
|
|
113
|
+
"gmu",
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
/** Kotlin also indexes top-level fun/val/typealias; the optional dotted part is an extension receiver. */
|
|
117
|
+
const KOTLIN_DECLARATION = new RegExp(
|
|
118
|
+
`^[ \\t]*(?:@[\\w.]+(?:\\([^)]*\\))?[ \\t]*)*(?:(?:${MODIFIERS})[ \\t]+)*(class|interface|object|fun|val|var|typealias)\\s+(?:<[^>]*>\\s+)?(?:[A-Za-z_][\\w.]*\\.)?([A-Za-z_]\\w*)`,
|
|
119
|
+
"gmu",
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
export const resolveJavaFileDep = createJvmFileDepResolver({
|
|
123
|
+
extensions: [".java"],
|
|
124
|
+
externalPrefixes: ["java", "javax", "jakarta", "jdk", "sun"],
|
|
125
|
+
declarationPattern: JAVA_DECLARATION,
|
|
126
|
+
memoPrefix: "java-dotted",
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
export const resolveKotlinFileDep = createJvmFileDepResolver({
|
|
130
|
+
// .kts is often Gradle — not a package type file.
|
|
131
|
+
extensions: [".kt", ".java"],
|
|
132
|
+
externalPrefixes: ["java", "javax", "jakarta", "kotlin", "kotlinx"],
|
|
133
|
+
declarationPattern: KOTLIN_DECLARATION,
|
|
134
|
+
memoPrefix: "kotlin-dotted",
|
|
135
|
+
});
|
|
@@ -3,17 +3,15 @@ import type { ExtractResult, GrammarAdapter, LanguageCapabilities } from "../ada
|
|
|
3
3
|
import { resolveKotlinFileDep } from "./jvm-file-deps.ts";
|
|
4
4
|
import type { CallSite, Decl, ImportRef, Visibility } from "../ir.ts";
|
|
5
5
|
import {
|
|
6
|
-
applyDoc,
|
|
7
6
|
callSite,
|
|
7
|
+
type DocSpan,
|
|
8
8
|
docSpanBefore,
|
|
9
9
|
docSpanTrailingChild,
|
|
10
|
-
|
|
11
|
-
finishDecl,
|
|
10
|
+
createLeafBuilder,
|
|
12
11
|
nameText,
|
|
13
12
|
qualify,
|
|
14
13
|
startLine,
|
|
15
14
|
walkBodyNodes,
|
|
16
|
-
type DocSpan,
|
|
17
15
|
} from "./tree.ts";
|
|
18
16
|
|
|
19
17
|
const CAPABILITIES: LanguageCapabilities = {
|
|
@@ -22,6 +20,7 @@ const CAPABILITIES: LanguageCapabilities = {
|
|
|
22
20
|
fileDeps: true,
|
|
23
21
|
callEdges: true,
|
|
24
22
|
packageSurface: false,
|
|
23
|
+
structuralImplements: false,
|
|
25
24
|
};
|
|
26
25
|
|
|
27
26
|
const IMPORT_NOISE = new Set([
|
|
@@ -282,40 +281,7 @@ function functionBody(node: Node): Node | null {
|
|
|
282
281
|
return body ?? null;
|
|
283
282
|
}
|
|
284
283
|
|
|
285
|
-
|
|
286
|
-
node: Node,
|
|
287
|
-
owner: string,
|
|
288
|
-
kind: Decl["kind"],
|
|
289
|
-
name: string,
|
|
290
|
-
visibility: Visibility,
|
|
291
|
-
body: Node | null,
|
|
292
|
-
children: Decl[],
|
|
293
|
-
doc: DocSpan | undefined,
|
|
294
|
-
): Decl | undefined {
|
|
295
|
-
if (name.length === 0) return undefined;
|
|
296
|
-
const callable = kind === "function" || kind === "method" || kind === "constructor";
|
|
297
|
-
const typeLike =
|
|
298
|
-
kind === "class" || kind === "interface" || kind === "enum" || kind === "struct" || kind === "object";
|
|
299
|
-
const decl = finishDecl(
|
|
300
|
-
{
|
|
301
|
-
kind,
|
|
302
|
-
name,
|
|
303
|
-
qualifiedName: qualify(owner, name),
|
|
304
|
-
startLine: startLine(node),
|
|
305
|
-
endLine: endLine(node),
|
|
306
|
-
startOffset: node.startIndex,
|
|
307
|
-
endOffset: node.endIndex,
|
|
308
|
-
visibility,
|
|
309
|
-
exported: visibility === "public" || visibility === "internal",
|
|
310
|
-
children,
|
|
311
|
-
calls: callable ? extractCalls(body) : [],
|
|
312
|
-
bases: typeLike ? heritageBases(node) : [],
|
|
313
|
-
},
|
|
314
|
-
body,
|
|
315
|
-
);
|
|
316
|
-
if (body === null) decl.signatureEndOffset = node.endIndex;
|
|
317
|
-
return applyDoc(decl, doc);
|
|
318
|
-
}
|
|
284
|
+
const leaf = createLeafBuilder(extractCalls, heritageBases);
|
|
319
285
|
|
|
320
286
|
function primaryConstructorProperties(ctor: Node, owner: string): Decl[] {
|
|
321
287
|
const out: Decl[] = [];
|
|
@@ -595,7 +561,7 @@ function extractKotlin(tree: Tree, source: string): ExtractResult {
|
|
|
595
561
|
for (const node of root.children) {
|
|
596
562
|
if (node.isNamed || node.isError) decls.push(...declsFromNode(node, "", source));
|
|
597
563
|
}
|
|
598
|
-
return { decls: rehomeOrphanMembers(decls), imports: collectImports(root) };
|
|
564
|
+
return { decls: rehomeOrphanMembers(decls), imports: collectImports(root), fileCalls: extractCalls(root) };
|
|
599
565
|
}
|
|
600
566
|
|
|
601
567
|
export function kotlinAdapter(): GrammarAdapter {
|
|
@@ -27,9 +27,9 @@ async function resolveModuleChain(
|
|
|
27
27
|
const candidates = await moduleFileCandidates(dir, name);
|
|
28
28
|
const file = await firstExistingFile(host, candidates);
|
|
29
29
|
if (file === undefined) {
|
|
30
|
-
//
|
|
31
|
-
|
|
32
|
-
return
|
|
30
|
+
// Remaining segments are items inside the deepest module that exists
|
|
31
|
+
// (inline `mod`, re-export, cfg-gated shim). Never drop the edge silently.
|
|
32
|
+
return lastFile;
|
|
33
33
|
}
|
|
34
34
|
lastFile = file;
|
|
35
35
|
// Next modules live beside foo.rs → foo/ or inside foo/ for mod.rs
|
|
@@ -23,6 +23,7 @@ const CAPABILITIES: LanguageCapabilities = {
|
|
|
23
23
|
fileDeps: true,
|
|
24
24
|
callEdges: true,
|
|
25
25
|
packageSurface: false,
|
|
26
|
+
structuralImplements: false,
|
|
26
27
|
};
|
|
27
28
|
|
|
28
29
|
const IMPORT_NOISE = new Set([
|
|
@@ -393,32 +394,39 @@ function declsFromItem(
|
|
|
393
394
|
return decl === undefined ? [] : [decl];
|
|
394
395
|
}
|
|
395
396
|
case IMPL_ITEM: {
|
|
396
|
-
// Methods become siblings under the target type name (inherent + trait impls).
|
|
397
397
|
const target = rustTypeName(field(node, "type"));
|
|
398
398
|
const body = field(node, "body");
|
|
399
399
|
if (body === null || body.type !== DECLARATION_LIST || target.length === 0) return [];
|
|
400
400
|
const methodOwner = owner.length === 0 ? target : qualify(owner, target);
|
|
401
401
|
const methods = walkDeclList(body, owner, source, methodOwner, true);
|
|
402
|
-
// Marker decl so `implementations Trait` finds this impl via bases (trait name).
|
|
403
402
|
const trait = rustTypeName(field(node, "trait"));
|
|
404
|
-
|
|
405
|
-
|
|
403
|
+
// The impl block is the container its methods belong to: named for what it
|
|
404
|
+
// is, so it never shadows the target type, and holding its own methods.
|
|
405
|
+
const name = trait.length === 0 ? `impl ${target}` : `impl ${trait} for ${target}`;
|
|
406
|
+
// An impl block carries no visibility modifier; its surface is its methods'.
|
|
407
|
+
const visibility: Visibility = methods.some((method) => method.visibility === "public")
|
|
408
|
+
? "public"
|
|
409
|
+
: methods.some((method) => method.visibility === "internal")
|
|
410
|
+
? "internal"
|
|
411
|
+
: "private";
|
|
412
|
+
const container = finishDecl(
|
|
406
413
|
{
|
|
407
414
|
kind: "class",
|
|
408
|
-
name
|
|
409
|
-
qualifiedName:
|
|
415
|
+
name,
|
|
416
|
+
qualifiedName: name,
|
|
410
417
|
startLine: node.startPosition.row + 1,
|
|
411
418
|
endLine: endLine(node),
|
|
412
419
|
startOffset: node.startIndex,
|
|
413
420
|
endOffset: node.endIndex,
|
|
414
|
-
visibility
|
|
415
|
-
exported:
|
|
416
|
-
children:
|
|
417
|
-
|
|
421
|
+
visibility,
|
|
422
|
+
exported: rustExported(visibility),
|
|
423
|
+
children: methods,
|
|
424
|
+
// `implementations Trait` finds this impl through the trait base.
|
|
425
|
+
bases: trait.length === 0 ? [] : [trait],
|
|
418
426
|
},
|
|
419
|
-
|
|
427
|
+
body,
|
|
420
428
|
);
|
|
421
|
-
return [
|
|
429
|
+
return [applyDoc(container, doc)];
|
|
422
430
|
}
|
|
423
431
|
case MOD_ITEM: {
|
|
424
432
|
const name = nameText(field(node, "name"));
|
|
@@ -490,7 +498,7 @@ function extractRust(tree: Tree, source: string): ExtractResult {
|
|
|
490
498
|
}
|
|
491
499
|
const imports: ImportRef[] = [];
|
|
492
500
|
collectImports(root, imports);
|
|
493
|
-
return { decls, imports };
|
|
501
|
+
return { decls, imports, fileCalls: extractCalls(root) };
|
|
494
502
|
}
|
|
495
503
|
|
|
496
504
|
export function rustAdapter(): GrammarAdapter {
|
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { join, resolve, sep } from "node:path";
|
|
2
2
|
import type { FileDepResolver } from "../adapter.ts";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
collectFilesWithExtensions,
|
|
5
|
+
externalId,
|
|
6
|
+
isWithin,
|
|
7
|
+
packageDirectory,
|
|
8
|
+
pickClosestPath,
|
|
9
|
+
} from "./file-dep-util.ts";
|
|
4
10
|
|
|
5
11
|
async function findModuleDirs(
|
|
6
12
|
host: Parameters<FileDepResolver>[2],
|
|
@@ -37,23 +43,24 @@ async function findModuleDirs(
|
|
|
37
43
|
return hits;
|
|
38
44
|
}
|
|
39
45
|
|
|
40
|
-
|
|
46
|
+
/**
|
|
47
|
+
* `import SomeModule` names a module, not a file list: expanding it to every
|
|
48
|
+
* file in the module directory made `deps` and `impact` unusable on real corpora.
|
|
49
|
+
* One package edge for the module directory instead.
|
|
50
|
+
*/
|
|
51
|
+
export const resolveSwiftFileDep: FileDepResolver = async (fromPath, specifier, host, signal) => {
|
|
41
52
|
signal.throwIfAborted();
|
|
42
53
|
const moduleName = specifier.trim().split(/\s+/u)[0] ?? "";
|
|
43
54
|
if (moduleName.length === 0) return { kind: "unresolved" };
|
|
44
55
|
|
|
45
56
|
// Skip obvious system modules when no local dir exists — still try local first.
|
|
46
57
|
const dirs = await findModuleDirs(host, moduleName, signal);
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
if (files.length === 0) return externalId(moduleName);
|
|
58
|
-
return internalPaths(files);
|
|
58
|
+
const inScope = dirs.filter((dir) => isWithin(host.scopeRoot, dir));
|
|
59
|
+
const dir = pickClosestPath(inScope, fromPath);
|
|
60
|
+
if (dir === undefined) return externalId(moduleName);
|
|
61
|
+
const files = await collectFilesWithExtensions(host, dir, [".swift"], signal, 500);
|
|
62
|
+
// Package.swift is the manifest, not module source.
|
|
63
|
+
const sources = files.filter((file) => !file.endsWith(`${sep}Package.swift`));
|
|
64
|
+
if (sources.length === 0) return externalId(moduleName);
|
|
65
|
+
return packageDirectory(moduleName, dir, sources.length);
|
|
59
66
|
};
|
|
@@ -3,17 +3,15 @@ import type { ExtractResult, GrammarAdapter, LanguageCapabilities } from "../ada
|
|
|
3
3
|
import { resolveSwiftFileDep } from "./swift-file-deps.ts";
|
|
4
4
|
import type { CallSite, Decl, ImportRef, Visibility } from "../ir.ts";
|
|
5
5
|
import {
|
|
6
|
-
applyDoc,
|
|
7
6
|
callSite,
|
|
7
|
+
type DocSpan,
|
|
8
8
|
docSpanBefore,
|
|
9
|
-
endLine,
|
|
10
9
|
field,
|
|
11
|
-
|
|
10
|
+
createLeafBuilder,
|
|
12
11
|
nameText,
|
|
13
12
|
qualify,
|
|
14
13
|
startLine,
|
|
15
14
|
walkBodyNodes,
|
|
16
|
-
type DocSpan,
|
|
17
15
|
} from "./tree.ts";
|
|
18
16
|
|
|
19
17
|
const CAPABILITIES: LanguageCapabilities = {
|
|
@@ -22,6 +20,7 @@ const CAPABILITIES: LanguageCapabilities = {
|
|
|
22
20
|
fileDeps: true,
|
|
23
21
|
callEdges: true,
|
|
24
22
|
packageSurface: false,
|
|
23
|
+
structuralImplements: false,
|
|
25
24
|
};
|
|
26
25
|
|
|
27
26
|
const IMPORT_NOISE = new Set([
|
|
@@ -242,40 +241,7 @@ function bodyOf(node: Node): Node | null {
|
|
|
242
241
|
);
|
|
243
242
|
}
|
|
244
243
|
|
|
245
|
-
|
|
246
|
-
node: Node,
|
|
247
|
-
owner: string,
|
|
248
|
-
kind: Decl["kind"],
|
|
249
|
-
name: string,
|
|
250
|
-
visibility: Visibility,
|
|
251
|
-
body: Node | null,
|
|
252
|
-
children: Decl[],
|
|
253
|
-
doc: DocSpan | undefined,
|
|
254
|
-
): Decl | undefined {
|
|
255
|
-
if (name.length === 0) return undefined;
|
|
256
|
-
const callable = kind === "function" || kind === "method" || kind === "constructor";
|
|
257
|
-
const typeLike =
|
|
258
|
-
kind === "class" || kind === "interface" || kind === "enum" || kind === "struct" || kind === "object";
|
|
259
|
-
const decl = finishDecl(
|
|
260
|
-
{
|
|
261
|
-
kind,
|
|
262
|
-
name,
|
|
263
|
-
qualifiedName: qualify(owner, name),
|
|
264
|
-
startLine: startLine(node),
|
|
265
|
-
endLine: endLine(node),
|
|
266
|
-
startOffset: node.startIndex,
|
|
267
|
-
endOffset: node.endIndex,
|
|
268
|
-
visibility,
|
|
269
|
-
exported: visibility === "public",
|
|
270
|
-
children,
|
|
271
|
-
calls: callable ? extractCalls(body) : [],
|
|
272
|
-
bases: typeLike ? heritageBases(node) : [],
|
|
273
|
-
},
|
|
274
|
-
body,
|
|
275
|
-
);
|
|
276
|
-
if (body === null) decl.signatureEndOffset = node.endIndex;
|
|
277
|
-
return applyDoc(decl, doc);
|
|
278
|
-
}
|
|
244
|
+
const leaf = createLeafBuilder(extractCalls, heritageBases);
|
|
279
245
|
|
|
280
246
|
function classKind(kindText: string): Decl["kind"] {
|
|
281
247
|
if (kindText === "struct") return "struct";
|
|
@@ -450,7 +416,11 @@ function extractSwift(tree: Tree, source: string): ExtractResult {
|
|
|
450
416
|
}
|
|
451
417
|
decls.push(...declsFromNode(node, "", source));
|
|
452
418
|
}
|
|
453
|
-
return {
|
|
419
|
+
return {
|
|
420
|
+
decls: mergeExtensionMembers(decls, extensions),
|
|
421
|
+
imports: collectImports(root),
|
|
422
|
+
fileCalls: extractCalls(root),
|
|
423
|
+
};
|
|
454
424
|
}
|
|
455
425
|
|
|
456
426
|
export function swiftAdapter(): GrammarAdapter {
|
|
@@ -186,6 +186,53 @@ export function callSite(
|
|
|
186
186
|
return { name, receiver, line, startOffset, endOffset, kind };
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
+
const CALLABLE_KINDS = new Set<Decl["kind"]>(["function", "method", "constructor"]);
|
|
190
|
+
const TYPE_LIKE_KINDS = new Set<Decl["kind"]>(["class", "interface", "enum", "struct", "object"]);
|
|
191
|
+
|
|
192
|
+
export type LeafBuilder = (
|
|
193
|
+
node: Node,
|
|
194
|
+
owner: string,
|
|
195
|
+
kind: Decl["kind"],
|
|
196
|
+
name: string,
|
|
197
|
+
visibility: Decl["visibility"],
|
|
198
|
+
body: Node | null,
|
|
199
|
+
children: Decl[],
|
|
200
|
+
doc: DocSpan | undefined,
|
|
201
|
+
) => Decl | undefined;
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Builds one leaf decl per grammar adapter: calls come from callable bodies,
|
|
205
|
+
* bases from type-like heritage, and the span closes on the signature when the
|
|
206
|
+
* node has no body.
|
|
207
|
+
*/
|
|
208
|
+
export function createLeafBuilder(
|
|
209
|
+
extractCalls: (body: Node | null) => CallSite[],
|
|
210
|
+
heritageBases: (node: Node) => string[],
|
|
211
|
+
): LeafBuilder {
|
|
212
|
+
return (node, owner, kind, name, visibility, body, children, doc) => {
|
|
213
|
+
if (name.length === 0) return undefined;
|
|
214
|
+
const decl = finishDecl(
|
|
215
|
+
{
|
|
216
|
+
kind,
|
|
217
|
+
name,
|
|
218
|
+
qualifiedName: qualify(owner, name),
|
|
219
|
+
startLine: startLine(node),
|
|
220
|
+
endLine: endLine(node),
|
|
221
|
+
startOffset: node.startIndex,
|
|
222
|
+
endOffset: node.endIndex,
|
|
223
|
+
visibility,
|
|
224
|
+
exported: visibility === "public",
|
|
225
|
+
children,
|
|
226
|
+
calls: CALLABLE_KINDS.has(kind) ? extractCalls(body) : [],
|
|
227
|
+
bases: TYPE_LIKE_KINDS.has(kind) ? heritageBases(node) : [],
|
|
228
|
+
},
|
|
229
|
+
body,
|
|
230
|
+
);
|
|
231
|
+
if (body === null) decl.signatureEndOffset = node.endIndex;
|
|
232
|
+
return applyDoc(decl, doc);
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
|
|
189
236
|
/** Build a top-level-ish decl from a grammar node span + optional body. */
|
|
190
237
|
export function declFromNode(
|
|
191
238
|
node: Node,
|
|
@@ -239,6 +239,111 @@ async function resolveViaPaths(
|
|
|
239
239
|
return undefined;
|
|
240
240
|
}
|
|
241
241
|
|
|
242
|
+
/** package name → package root, from the scope root's npm workspaces globs. */
|
|
243
|
+
type WorkspaceMap = Map<string, string>;
|
|
244
|
+
|
|
245
|
+
async function readManifest(path: string): Promise<Record<string, unknown> | undefined> {
|
|
246
|
+
const json = await loadTsconfigFile(path);
|
|
247
|
+
return json;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function workspaceGlobs(manifest: Record<string, unknown>): string[] {
|
|
251
|
+
const value = manifest.workspaces;
|
|
252
|
+
if (Array.isArray(value)) return value.filter((entry): entry is string => typeof entry === "string");
|
|
253
|
+
const packages = asRecord(value)?.packages;
|
|
254
|
+
if (Array.isArray(packages)) return packages.filter((entry): entry is string => typeof entry === "string");
|
|
255
|
+
return [];
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Workspace packages resolve through an npm symlink the resolver must not follow:
|
|
260
|
+
* a `/node_modules/` path fails `host.ownsPath` and would duplicate the real file.
|
|
261
|
+
* Expand the globs against the scope root instead.
|
|
262
|
+
*/
|
|
263
|
+
async function loadWorkspacePackages(host: FileDepHost, signal: AbortSignal): Promise<WorkspaceMap> {
|
|
264
|
+
const key = `ts-workspaces:${host.scopeRoot}`;
|
|
265
|
+
const cached = host.memo.get(key);
|
|
266
|
+
if (cached !== undefined) return cached as WorkspaceMap;
|
|
267
|
+
|
|
268
|
+
const map: WorkspaceMap = new Map();
|
|
269
|
+
const root = await readManifest(join(host.scopeRoot, "package.json"));
|
|
270
|
+
for (const glob of root === undefined ? [] : workspaceGlobs(root)) {
|
|
271
|
+
signal.throwIfAborted();
|
|
272
|
+
const star = glob.indexOf("*");
|
|
273
|
+
const dirs: string[] = [];
|
|
274
|
+
if (star === -1) {
|
|
275
|
+
dirs.push(resolve(host.scopeRoot, glob));
|
|
276
|
+
} else {
|
|
277
|
+
const parent = resolve(host.scopeRoot, glob.slice(0, star).replace(/\/$/u, ""));
|
|
278
|
+
for (const name of await host.readDir(parent)) {
|
|
279
|
+
if (name.startsWith(".")) continue;
|
|
280
|
+
dirs.push(join(parent, name));
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
for (const dir of dirs) {
|
|
284
|
+
const manifest = await readManifest(join(dir, "package.json"));
|
|
285
|
+
const name = manifest?.name;
|
|
286
|
+
if (typeof name === "string" && name.length > 0) map.set(name, dir);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
host.memo.set(key, map);
|
|
291
|
+
return map;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function entryTargets(manifest: Record<string, unknown>): string[] {
|
|
295
|
+
const out: string[] = [];
|
|
296
|
+
const exports = manifest.exports;
|
|
297
|
+
if (typeof exports === "string") out.push(exports);
|
|
298
|
+
const dot = asRecord(exports)?.["."];
|
|
299
|
+
if (typeof dot === "string") out.push(dot);
|
|
300
|
+
const conditions = asRecord(dot);
|
|
301
|
+
if (conditions !== undefined) {
|
|
302
|
+
for (const field of ["types", "import", "module", "default"] as const) {
|
|
303
|
+
const value = conditions[field];
|
|
304
|
+
if (typeof value === "string") out.push(value);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
for (const field of ["types", "module", "main"] as const) {
|
|
308
|
+
const value = manifest[field];
|
|
309
|
+
if (typeof value === "string") out.push(value);
|
|
310
|
+
}
|
|
311
|
+
out.push("src/index.ts", "index.ts");
|
|
312
|
+
return out;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
async function resolveWorkspacePackage(
|
|
316
|
+
host: FileDepHost,
|
|
317
|
+
specifier: string,
|
|
318
|
+
signal: AbortSignal,
|
|
319
|
+
): Promise<string | undefined> {
|
|
320
|
+
const workspaces = await loadWorkspacePackages(host, signal);
|
|
321
|
+
if (workspaces.size === 0) return undefined;
|
|
322
|
+
|
|
323
|
+
let matched: { name: string; dir: string } | undefined;
|
|
324
|
+
for (const [name, dir] of workspaces) {
|
|
325
|
+
if (specifier !== name && !specifier.startsWith(`${name}/`)) continue;
|
|
326
|
+
if (matched === undefined || name.length > matched.name.length) matched = { name, dir };
|
|
327
|
+
}
|
|
328
|
+
if (matched === undefined) return undefined;
|
|
329
|
+
|
|
330
|
+
if (specifier.length > matched.name.length) {
|
|
331
|
+
const subpath = specifier.slice(matched.name.length + 1);
|
|
332
|
+
return (
|
|
333
|
+
(await resolveExistingSource(host, resolve(matched.dir, subpath))) ??
|
|
334
|
+
(await resolveExistingSource(host, resolve(matched.dir, "src", subpath)))
|
|
335
|
+
);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
const manifest = await readManifest(join(matched.dir, "package.json"));
|
|
339
|
+
if (manifest === undefined) return undefined;
|
|
340
|
+
for (const target of entryTargets(manifest)) {
|
|
341
|
+
const file = await resolveExistingSource(host, resolve(matched.dir, target));
|
|
342
|
+
if (file !== undefined) return file;
|
|
343
|
+
}
|
|
344
|
+
return undefined;
|
|
345
|
+
}
|
|
346
|
+
|
|
242
347
|
export const resolveTypescriptFileDep: FileDepResolver = async (fromPath, specifier, host, signal) => {
|
|
243
348
|
signal.throwIfAborted();
|
|
244
349
|
const trimmed = specifier.trim();
|
|
@@ -255,5 +360,8 @@ export const resolveTypescriptFileDep: FileDepResolver = async (fromPath, specif
|
|
|
255
360
|
const aliased = await resolveViaPaths(host, fromPath, trimmed, signal);
|
|
256
361
|
if (aliased !== undefined) return internalPaths([aliased]);
|
|
257
362
|
|
|
363
|
+
const workspace = await resolveWorkspacePackage(host, trimmed, signal);
|
|
364
|
+
if (workspace !== undefined && isWithin(host.scopeRoot, workspace)) return internalPaths([workspace]);
|
|
365
|
+
|
|
258
366
|
return externalId(packageNameFromBareSpecifier(trimmed));
|
|
259
367
|
};
|
|
@@ -3,7 +3,7 @@ import { dirname, extname, isAbsolute, join, relative, resolve, sep } from "node
|
|
|
3
3
|
import type { Decl } from "../ir.ts";
|
|
4
4
|
import type { FileSource } from "../engine.ts";
|
|
5
5
|
import { packageDeclKey, type PackageSurfaceHost, type PackageSurfaceResolver } from "../package-surface.ts";
|
|
6
|
-
import { formatPathForDisplay } from "
|
|
6
|
+
import { formatPathForDisplay } from "../traverse.ts";
|
|
7
7
|
|
|
8
8
|
const RE_EXPORT_DEPTH = 4;
|
|
9
9
|
const TS_SOURCE_EXTENSIONS = [".ts", ".tsx", ".mts", ".cts", ".mtsx"] as const;
|
|
@@ -40,6 +40,7 @@ async function fileExists(path: string): Promise<boolean> {
|
|
|
40
40
|
async function findPackageJson(startDir: string, stopDir: string): Promise<string | undefined> {
|
|
41
41
|
let dir = resolve(startDir);
|
|
42
42
|
const stop = resolve(stopDir);
|
|
43
|
+
const bounded = isWithin(stop, dir);
|
|
43
44
|
for (;;) {
|
|
44
45
|
const candidate = join(dir, "package.json");
|
|
45
46
|
try {
|
|
@@ -47,10 +48,10 @@ async function findPackageJson(startDir: string, stopDir: string): Promise<strin
|
|
|
47
48
|
} catch {
|
|
48
49
|
// walk up
|
|
49
50
|
}
|
|
50
|
-
if (dir === stop) return undefined;
|
|
51
|
+
if (bounded && dir === stop) return undefined;
|
|
51
52
|
const parent = dirname(dir);
|
|
52
53
|
if (parent === dir) return undefined;
|
|
53
|
-
if (!isWithin(stop, parent) && parent !== stop) return undefined;
|
|
54
|
+
if (bounded && !isWithin(stop, parent) && parent !== stop) return undefined;
|
|
54
55
|
dir = parent;
|
|
55
56
|
}
|
|
56
57
|
}
|
|
@@ -25,6 +25,7 @@ const CAPABILITIES: LanguageCapabilities = {
|
|
|
25
25
|
fileDeps: true,
|
|
26
26
|
callEdges: true,
|
|
27
27
|
packageSurface: true,
|
|
28
|
+
structuralImplements: false,
|
|
28
29
|
};
|
|
29
30
|
|
|
30
31
|
/** Keywords/types skipped when matching imports to a decl slice. */
|
|
@@ -153,10 +154,7 @@ const EXPORT_SPECIFIER = "export_specifier";
|
|
|
153
154
|
|
|
154
155
|
const NESTED_CALLABLE = new Set([
|
|
155
156
|
FUNCTION_DECLARATION,
|
|
156
|
-
FUNCTION_EXPRESSION,
|
|
157
157
|
GENERATOR_FUNCTION_DECLARATION,
|
|
158
|
-
ARROW_FUNCTION,
|
|
159
|
-
METHOD_DEFINITION,
|
|
160
158
|
CLASS_DECLARATION,
|
|
161
159
|
ABSTRACT_CLASS_DECLARATION,
|
|
162
160
|
CLASS,
|
|
@@ -548,7 +546,7 @@ function variableDecls(node: Node, owner: string, exported: boolean, doc: DocSpa
|
|
|
548
546
|
endOffset: spanNode.endIndex,
|
|
549
547
|
visibility: "public",
|
|
550
548
|
exported,
|
|
551
|
-
calls: isFn ? extractCalls(body) : [],
|
|
549
|
+
calls: isFn ? extractCalls(body) : value === null ? [] : extractCalls(value),
|
|
552
550
|
},
|
|
553
551
|
body,
|
|
554
552
|
);
|
|
@@ -725,7 +723,7 @@ function extractTypeScript(tree: Tree, source: string): ExtractResult {
|
|
|
725
723
|
const decls = walkStatementList(top, "", source, false);
|
|
726
724
|
const imports: ImportRef[] = [];
|
|
727
725
|
collectImportsFrom(root, imports);
|
|
728
|
-
return { decls, imports };
|
|
726
|
+
return { decls, imports, fileCalls: extractCalls(root) };
|
|
729
727
|
}
|
|
730
728
|
|
|
731
729
|
function makeAdapter(id: "typescript" | "tsx", extensions: readonly string[]): GrammarAdapter {
|