Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion packages/argent/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@
"scripts/postinstall.cjs"
],
"dependencies": {
"@modelcontextprotocol/sdk": "^1.20.0"
"@modelcontextprotocol/sdk": "^1.20.0",
"tree-sitter": "^0.21.1",
"tree-sitter-typescript": "^0.23.2"
},
"devDependencies": {
"@argent/cli": "file:../argent-cli",
Expand Down
4 changes: 4 additions & 0 deletions packages/argent/scripts/bundle-tools.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,10 @@ esbuild.buildSync({
outfile: OUT_FILE,
alias: ALIASES,
mainFields: MAIN_FIELDS,
// tree-sitter / tree-sitter-typescript are native addons (.node) that esbuild
// cannot inline; keep them external so the bundle `require()`s them at runtime
// from the published package's own dependencies (see package.json).
external: ["tree-sitter", "tree-sitter-typescript"],
});

console.log(`✓ Bundled tools server → ${path.relative(process.cwd(), OUT_FILE)}`);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,20 @@ Returns found: false if the component is not found in user-owned code (e.g. live
const entry = astIndex.index.get(params.component_name);

if (!entry) {
if (!astIndex.treeSitterAvailable) {
return {
found: false,
component: params.component_name,
message:
`Component source lookup is unavailable: the tree-sitter parser could not be loaded, ` +
`so no source files were indexed. Ensure @swmansion/argent's "tree-sitter" and ` +
`"tree-sitter-typescript" dependencies are installed.`,
};
}
return {
found: false,
component: params.component_name,
message: `Component "${params.component_name}" not found in ${params.project_root}`,
message: `Component "${params.component_name}" not found in ${params.project_root} (searched ${astIndex.indexedFiles} files).`,
};
}

Expand Down
38 changes: 38 additions & 0 deletions packages/tool-server/test/react-profiler/ast-index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { describe, it, expect } from "vitest";
import { mkdtempSync, mkdirSync, writeFileSync } from "fs";
import { tmpdir } from "os";
import { join } from "path";
import { buildAstIndexWithDiagnostics } from "../../src/utils/react-profiler/pipeline/06-resolve/ast-index";

/**
* react-profiler-component-source returned found:false for every component in a
* standard TS/TSX Expo project because @swmansion/argent never declared (or
* shipped) tree-sitter / tree-sitter-typescript, so the parser require() threw,
* was swallowed, and the index was always empty. The grammar/match logic itself
* is correct — this test guards it for the idiomatic declaration forms and, via
* treeSitterAvailable, fails loudly if the parser dependency goes missing again.
*/
describe("buildAstIndexWithDiagnostics", () => {
it("indexes export-default-function, plain-function, and arrow TSX components", async () => {
const dir = mkdtempSync(join(tmpdir(), "ast-index-"));
mkdirSync(join(dir, "components"), { recursive: true });
writeFileSync(
join(dir, "components", "foo.tsx"),
[
`import React from "react";`,
`type P = { x: number };`,
`export default function Foo({ x }: P) { return <View>{x}</View>; }`,
`function Bar({ y }: { y: number }) { return <View>{y}</View>; }`,
`const Baz = ({ z }: { z: number }) => <View>{z}</View>;`,
``,
].join("\n")
);

const res = await buildAstIndexWithDiagnostics(dir);

expect(res.treeSitterAvailable).toBe(true);
expect(res.index.get("Foo")?.line).toBe(3);
expect(res.index.get("Bar")?.line).toBe(4);
expect(res.index.get("Baz")?.line).toBe(5);
});
});