mirror of
https://github.com/giancarloerra/socraticode.git
synced 2026-07-03 14:05:21 +02:00
7bd9eb5308
Dart previously fell through to the regex symbol fallback, which cannot match type-first signatures (void foo(), Future<int> baz() async), so classes, methods, and calls were invisible to codebase_symbol, codebase_flow, and codebase_impact, and files were chunked by line count instead of declaration boundaries. - Register @ast-grep/lang-dart as a dynamic grammar (per-grammar failure isolation keeps missing prebuilds on the regex fallback). - Add extractFromDart: classes, mixins (trait), enums, extensions, typedefs, type-first top-level functions, getters/setters, and constructors including named and factory forms. Scope ranges are stitched from Dart's sibling function_signature/function_body pairs. Calls are recovered from argument_part nodes: method calls, bare calls, constructor invocations, prefixed calls, and cascades. - Add dart to TOP_LEVEL_KINDS so chunking follows declaration boundaries; signature and body kinds are both listed so the overlap-merge fuses each pair into one region. - Add dart main() to ENTRY_POINT_NAMES for entry-point detection. - Move Dart to Full Support in the README language matrix.
127 lines
3.6 KiB
TypeScript
127 lines
3.6 KiB
TypeScript
// SPDX-License-Identifier: AGPL-3.0-only
|
|
// Copyright (C) 2026 Giancarlo Erra - Altaire Limited
|
|
|
|
import { describe, expect, it } from "vitest";
|
|
import { detectEntryPoints } from "../../src/services/graph-entrypoints.js";
|
|
import type { CodeGraph, SymbolGraphFilePayload } from "../../src/types.js";
|
|
|
|
function mkPayload(file: string, syms: { name: string; line?: number }[]): SymbolGraphFilePayload {
|
|
return {
|
|
file,
|
|
language: "typescript",
|
|
contentHash: "abc",
|
|
symbols: [
|
|
{
|
|
id: `${file}::<module>#1`,
|
|
name: "<module>",
|
|
qualifiedName: "<module>",
|
|
kind: "module",
|
|
file,
|
|
line: 1,
|
|
endLine: 100,
|
|
language: "typescript",
|
|
},
|
|
...syms.map((s) => ({
|
|
id: `${file}::${s.name}#${s.line ?? 1}`,
|
|
name: s.name,
|
|
qualifiedName: s.name,
|
|
kind: "function" as const,
|
|
file,
|
|
line: s.line ?? 1,
|
|
endLine: (s.line ?? 1) + 5,
|
|
language: "typescript",
|
|
})),
|
|
],
|
|
outgoingCalls: [],
|
|
};
|
|
}
|
|
|
|
describe("graph-entrypoints", () => {
|
|
it("detects orphan files (no dependents) with outgoing calls", () => {
|
|
const graph: CodeGraph = {
|
|
nodes: [
|
|
{
|
|
relativePath: "src/main.ts",
|
|
imports: [],
|
|
exports: [],
|
|
dependencies: ["src/lib.ts"],
|
|
dependents: [], // orphan
|
|
},
|
|
{
|
|
relativePath: "src/lib.ts",
|
|
imports: [],
|
|
exports: [],
|
|
dependencies: [],
|
|
dependents: ["src/main.ts"],
|
|
},
|
|
],
|
|
edges: [],
|
|
};
|
|
const payloads: SymbolGraphFilePayload[] = [
|
|
{
|
|
...mkPayload("src/main.ts", [{ name: "run", line: 5 }]),
|
|
outgoingCalls: [
|
|
{
|
|
callerId: "src/main.ts::run#5",
|
|
calleeName: "lib",
|
|
calleeCandidates: ["src/lib.ts::lib#1"],
|
|
confidence: "unique",
|
|
callSite: { file: "src/main.ts", line: 6 },
|
|
},
|
|
],
|
|
},
|
|
mkPayload("src/lib.ts", [{ name: "lib", line: 1 }]),
|
|
];
|
|
const entries = detectEntryPoints(graph, payloads);
|
|
expect(entries.some((e) => e.reason === "orphan")).toBe(true);
|
|
});
|
|
|
|
it("detects conventional entry-point names like main()", () => {
|
|
const graph: CodeGraph = {
|
|
nodes: [
|
|
{
|
|
relativePath: "cmd/server.go",
|
|
imports: [],
|
|
exports: [],
|
|
dependencies: ["pkg/util.go"],
|
|
dependents: ["pkg/util.go"], // not an orphan
|
|
},
|
|
],
|
|
edges: [],
|
|
};
|
|
const payloads: SymbolGraphFilePayload[] = [
|
|
mkPayload("cmd/server.go", [{ name: "main", line: 10 }]),
|
|
];
|
|
const entries = detectEntryPoints(graph, payloads);
|
|
expect(entries.some((e) => e.name === "main")).toBe(true);
|
|
});
|
|
|
|
it("detects Dart main() as a conventional entry point", () => {
|
|
const graph: CodeGraph = {
|
|
nodes: [
|
|
{
|
|
relativePath: "lib/main.dart",
|
|
imports: [],
|
|
exports: [],
|
|
dependencies: [],
|
|
dependents: ["lib/app.dart"], // not an orphan — name heuristic must fire
|
|
},
|
|
],
|
|
edges: [],
|
|
};
|
|
const payloads: SymbolGraphFilePayload[] = [
|
|
{ ...mkPayload("lib/main.dart", [{ name: "main", line: 3 }]), language: "dart" },
|
|
];
|
|
const entries = detectEntryPoints(graph, payloads);
|
|
const main = entries.find((e) => e.name === "main");
|
|
expect(main).toBeDefined();
|
|
expect(main?.reason).toBe("well-known-name:main");
|
|
});
|
|
|
|
it("returns empty array when nothing matches", () => {
|
|
const graph: CodeGraph = { nodes: [], edges: [] };
|
|
const entries = detectEntryPoints(graph, []);
|
|
expect(entries).toEqual([]);
|
|
});
|
|
});
|