164 lines
4.6 KiB
TypeScript
164 lines
4.6 KiB
TypeScript
import {
|
|
dirname,
|
|
fromFileUrl,
|
|
join,
|
|
} from "https://deno.land/std@0.224.0/path/mod.ts";
|
|
import { assertEquals } from "https://deno.land/std@0.224.0/testing/asserts.ts";
|
|
import { execTool, requireTool } from "./sys_exec.ts";
|
|
|
|
/**
|
|
* Proof of Concept: Local Code Intelligence (Gen 2)
|
|
*
|
|
* Replaces the naive regex extraction in Gen 1 with actual AST parsing using
|
|
* the tree-sitter CLI binary natively via system execution, proving that we can
|
|
* extract a true Semantic Code graph structure from code files.
|
|
*/
|
|
|
|
export interface ExportSymbol {
|
|
name: string;
|
|
type: "function" | "class" | "const";
|
|
signature: string;
|
|
}
|
|
|
|
export async function extractExports(
|
|
sourceCode: string,
|
|
): Promise<ExportSymbol[]> {
|
|
const currentDir = dirname(fromFileUrl(import.meta.url));
|
|
const TEMP_FILE = join(currentDir, "dummy_intelligence_target.js");
|
|
const exports: ExportSymbol[] = [];
|
|
|
|
try {
|
|
// Strip TypeScript annotations using a regex just to let the basic js tree-sitter parse it
|
|
const jsCode = sourceCode
|
|
.replace(/:\s*Promise<[^>]+>/g, "")
|
|
.replace(/:\s*[a-zA-Z0-9_]+/g, "")
|
|
.replace(/<[^>]+>/g, "");
|
|
|
|
await Deno.writeTextFile(TEMP_FILE, jsCode);
|
|
|
|
// Call native tree-sitter parser
|
|
const { code, stdout, stderr } = await execTool("tree-sitter", [
|
|
"parse",
|
|
TEMP_FILE,
|
|
"-x",
|
|
]);
|
|
|
|
if (code !== 0) {
|
|
throw new Error(`Tree-sitter CLI execution failed: ${stderr || stdout}`);
|
|
}
|
|
|
|
// In a full implementation, we'd use a real XML or s-expression parser
|
|
// For this PoC, we will do basic extraction from the XML output format
|
|
// of tree-sitter to demonstrate the tree traversal concept.
|
|
|
|
// Look for exported functions
|
|
const funcMatches = stdout.matchAll(
|
|
/<export_statement.*?<function_declaration.*?<identifier field="name".*?>(.*?)<\/identifier>.*?<formal_parameters field="parameters".*?>(.*?)<\/formal_parameters>.*?<\/function_declaration>.*?<\/export_statement>/gs,
|
|
);
|
|
for (const match of funcMatches) {
|
|
const name = match[1];
|
|
const paramsXml = match[2];
|
|
const params = [
|
|
...paramsXml.matchAll(/<identifier.*?>(.*?)<\/identifier>/gs),
|
|
].map((m) => m[1]).join(", ");
|
|
|
|
exports.push({
|
|
name,
|
|
type: "function",
|
|
signature: `(${params}) => any`,
|
|
});
|
|
}
|
|
|
|
// Look for exported consts
|
|
const constMatches = stdout.matchAll(
|
|
/<export_statement.*?<lexical_declaration.*?<variable_declarator.*?<identifier field="name".*?>(.*?)<\/identifier>.*?<\/variable_declarator>.*?<\/lexical_declaration>.*?<\/export_statement>/gs,
|
|
);
|
|
for (const match of constMatches) {
|
|
exports.push({
|
|
name: match[1],
|
|
type: "const",
|
|
signature: "const",
|
|
});
|
|
}
|
|
} finally {
|
|
try {
|
|
await Deno.remove(TEMP_FILE);
|
|
} catch {
|
|
// ignore
|
|
}
|
|
}
|
|
|
|
return exports;
|
|
}
|
|
|
|
const mockSourceCode = `
|
|
import { stuff } from "somewhere";
|
|
|
|
/**
|
|
* Calculates a complex value.
|
|
*/
|
|
export async function calculateValue(input: number, mode: string): Promise<number> {
|
|
return input * 2;
|
|
}
|
|
|
|
// An internal helper
|
|
function internalHelper() {
|
|
return true;
|
|
}
|
|
|
|
export const MAX_RETRIES = 5;
|
|
|
|
export function doSomethingElse(): void {
|
|
console.log(MAX_RETRIES);
|
|
}
|
|
`;
|
|
|
|
async function run() {
|
|
const hasTreeSitter = await requireTool(
|
|
"tree-sitter",
|
|
"npm install -g tree-sitter-cli",
|
|
);
|
|
if (!hasTreeSitter) {
|
|
console.warn(
|
|
"⚠️ Local Code Intelligence PoC skipped due to missing host dependency.",
|
|
);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const extracted = await extractExports(mockSourceCode);
|
|
|
|
assertEquals(extracted.length, 3);
|
|
|
|
const calcFunc = extracted.find((e) => e.name === "calculateValue");
|
|
assertEquals(calcFunc?.type, "function");
|
|
assertEquals(
|
|
calcFunc?.signature,
|
|
"(input, mode) => any",
|
|
);
|
|
|
|
const maxRetries = extracted.find((e) => e.name === "MAX_RETRIES");
|
|
assertEquals(maxRetries?.type, "const");
|
|
|
|
const doSomething = extracted.find((e) => e.name === "doSomethingElse");
|
|
assertEquals(doSomething?.type, "function");
|
|
assertEquals(doSomething?.signature, "() => any");
|
|
|
|
console.log(
|
|
"✅ Local Code Intelligence PoC (Gen 2) successful: Extracted structured context from raw source using native tree-sitter CLI.",
|
|
);
|
|
|
|
console.log("\n--- Agent Context Payload ---");
|
|
console.log(JSON.stringify(extracted, null, 2));
|
|
console.log("-----------------------------\n");
|
|
} catch (err) {
|
|
console.error("❌ Local Code Intelligence PoC (Gen 2) failed:", err);
|
|
Deno.exit(1);
|
|
}
|
|
}
|
|
|
|
if (import.meta.main) {
|
|
console.log("Running Local Code Intelligence PoC (Gen 2) tests...");
|
|
run();
|
|
}
|