chore: remove leftover debug scripts and stale docs
Delete dead dev scratch (debug_python_ast*.js, test_python_inheritance.js), the obsolete tree-sitter-dart native patch (Dart loads via WASM now and the package is no longer a dependency), and orphaned docs superseded by the current code and the agent-eval skill (IMPLEMENTATION_PLAN.md, DELPHI-SUPPORT.md, run-interactive-test.md). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
c3f1e273d4
commit
2fc0df7108
@@ -1,157 +0,0 @@
|
|||||||
# Pascal / Delphi Support for CodeGraph
|
|
||||||
|
|
||||||
## Why Delphi?
|
|
||||||
|
|
||||||
Delphi (Object Pascal) remains one of the most widely used languages for Windows desktop and enterprise applications. With an estimated **1.5–3 million active developers** and a strong presence in industries like healthcare, finance, logistics, and government, Delphi projects often involve large, long-lived codebases that benefit significantly from semantic code intelligence.
|
|
||||||
|
|
||||||
Many Delphi codebases have grown over decades — making structural understanding, impact analysis, and cross-file navigation exactly the kind of tooling gap CodeGraph is designed to fill.
|
|
||||||
|
|
||||||
Adding Delphi support positions CodeGraph as a uniquely valuable tool for a community that has historically been underserved by modern static analysis and AI-assisted development tools.
|
|
||||||
|
|
||||||
## What Was Implemented
|
|
||||||
|
|
||||||
### Pascal / Object Pascal (tree-sitter)
|
|
||||||
|
|
||||||
Full extraction support for `.pas`, `.dpr`, `.dpk`, and `.lpr` files using the `tree-sitter-pascal` grammar:
|
|
||||||
|
|
||||||
| Feature | NodeKind | Details |
|
|
||||||
|---------|----------|---------|
|
|
||||||
| Units / Programs | `module` | `unit`, `program`, `package`, `library` |
|
|
||||||
| Classes | `class` | Including inheritance and interface implementation |
|
|
||||||
| Records | `class` | Treated as classes (consistent with AST structure) |
|
|
||||||
| Interfaces | `interface` | With GUID support |
|
|
||||||
| Methods | `method` | Constructor, destructor, procedures, functions |
|
|
||||||
| Functions / Procedures | `function` | Top-level (non-class) routines |
|
|
||||||
| Properties | `property` | With read/write accessors |
|
|
||||||
| Fields | `field` | Class and record fields |
|
|
||||||
| Constants | `constant` | `const` declarations |
|
|
||||||
| Enums | `enum` | With enum members |
|
|
||||||
| Type Aliases | `type_alias` | `type TFoo = ...` |
|
|
||||||
| Uses / Imports | `import` | `uses` clause extraction |
|
|
||||||
| Function Calls | — | `calls` edges for call graph |
|
|
||||||
| Visibility | — | `public`, `private`, `protected` on methods/fields |
|
|
||||||
| Static Methods | — | `class function` / `class procedure` |
|
|
||||||
| Containment | — | `contains` edges (class → method, unit → type, etc.) |
|
|
||||||
| Inheritance | — | `extends` / `implements` edges |
|
|
||||||
|
|
||||||
### DFM / FMX Form Files (custom extractor)
|
|
||||||
|
|
||||||
Support for Delphi form files (`.dfm` for VCL, `.fmx` for FireMonkey) using a regex-based custom extractor — no tree-sitter grammar exists for this format:
|
|
||||||
|
|
||||||
| Feature | NodeKind / EdgeKind | Details |
|
|
||||||
|---------|---------------------|---------|
|
|
||||||
| Components | `component` | `object Button1: TButton` |
|
|
||||||
| Nested hierarchy | `contains` | Panel1 → Button1 |
|
|
||||||
| Event handlers | `references` (unresolved) | `OnClick = Button1Click` → links UI to Pascal methods |
|
|
||||||
| `inherited` keyword | `component` | Inherited form components |
|
|
||||||
| Multi-line properties | — | Correctly skipped during parsing |
|
|
||||||
| Item collections | — | `<item>...</end>` blocks correctly handled |
|
|
||||||
|
|
||||||
The DFM ↔ PAS linkage via event handlers enables **cross-file impact analysis**: renaming a method in `.pas` immediately reveals which UI components reference it.
|
|
||||||
|
|
||||||
## Architecture
|
|
||||||
|
|
||||||
The implementation follows CodeGraph's established patterns:
|
|
||||||
|
|
||||||
- **Pascal extraction** uses the standard `TreeSitterExtractor` with a Pascal-specific `LanguageExtractor` configuration and a `visitPascalNode()` hook for AST nodes that require special handling (e.g., `declType` wrappers, `defProc` implementation bodies)
|
|
||||||
- **DFM/FMX extraction** uses a `DfmExtractor` class — analogous to `LiquidExtractor` and `SvelteExtractor` — that parses the line-based format with regex
|
|
||||||
- **Routing** in `extractFromSource()` dispatches `.dfm`/`.fmx` files to `DfmExtractor` before reaching the tree-sitter path
|
|
||||||
- **`tree-sitter-pascal`** is declared as an `optionalDependency` (consistent with all other grammars), pinned to a specific commit for reproducible builds
|
|
||||||
|
|
||||||
## Performance Improvements
|
|
||||||
|
|
||||||
Testing with a large Delphi codebase (~3,400 files, ~244k nodes) uncovered performance bottlenecks in the reference resolution pipeline. The following fixes **benefit all languages**, not just Pascal:
|
|
||||||
|
|
||||||
| Fix | Scope | Impact |
|
|
||||||
|-----|-------|--------|
|
|
||||||
| **Fuzzy match index** — replaced O(n) linear scan with lazily-built case-insensitive `Map` index | `name-matcher.ts` (all languages) | O(1) lookup per ref instead of iterating all nodes |
|
|
||||||
| **Import mapping cache** — cached per-file import mappings instead of re-reading/re-parsing for every ref | `import-resolver.ts` (all languages) | Eliminated redundant file I/O during resolution |
|
|
||||||
| **Kind cache** — pre-populated `getNodesByKind` results during warm-up | `resolution/index.ts` (all languages) | Avoided repeated DB queries for the same node kinds |
|
|
||||||
| **Pascal built-in filtering** — skip known RTL/VCL/FMX identifiers before resolution | `resolution/index.ts` (Pascal-specific) | ~60 built-in identifiers filtered out early |
|
|
||||||
| **Method index for `defProc`** — replaced O(n) `find()` with `Map` lookup when linking implementation bodies to declarations | `tree-sitter.ts` (Pascal-specific) | O(1) per implementation body |
|
|
||||||
| **Delphi-specific excludes** — `__history/**`, `__recovery/**`, `*.dcu` added to default excludes | `types.ts` (Pascal-specific) | Skips Delphi IDE temp files during indexing |
|
|
||||||
|
|
||||||
**Result:** Reference resolution on a large Delphi project dropped from **~30 minutes to ~15 seconds** (120x speedup). The general improvements (fuzzy index, import cache, kind cache) will benefit all CodeGraph users.
|
|
||||||
|
|
||||||
## Files Changed
|
|
||||||
|
|
||||||
| File | Change |
|
|
||||||
|------|--------|
|
|
||||||
| `src/types.ts` | Added `'pascal'` to `Language` type, file patterns to `DEFAULT_CONFIG.include` |
|
|
||||||
| `src/extraction/grammars.ts` | Grammar loader, extension mappings (`.pas`, `.dpr`, `.dpk`, `.lpr`, `.dfm`, `.fmx`), display name |
|
|
||||||
| `src/extraction/tree-sitter.ts` | Pascal `LanguageExtractor`, `visitPascalNode()` with 7 helper methods, `DfmExtractor` class, routing in `extractFromSource()`, method index |
|
|
||||||
| `src/resolution/index.ts` | Pascal built-in filtering, kind cache, cache clearing |
|
|
||||||
| `src/resolution/import-resolver.ts` | Import mapping cache |
|
|
||||||
| `src/resolution/name-matcher.ts` | Fuzzy match index (case-insensitive `Map`) |
|
|
||||||
| `package.json` | `tree-sitter-pascal` in `optionalDependencies` (pinned commit) |
|
|
||||||
| `__tests__/extraction.test.ts` | 37 new tests covering all Pascal and DFM extraction features |
|
|
||||||
|
|
||||||
## Test Results
|
|
||||||
|
|
||||||
- **36 new tests**, all passing
|
|
||||||
- **0 regressions** — the same 28 pre-existing failures (unrelated: missing Swift/Dart grammars, database path issues, MCP truncation test) are unchanged
|
|
||||||
- Tests cover: language detection, modules, imports, classes, records, interfaces, methods, visibility, static methods, enums, properties, constants, type aliases, calls, containment, full fixture files (UAuth.pas, UTypes.pas, MainForm.dfm)
|
|
||||||
|
|
||||||
## Dependency Note
|
|
||||||
|
|
||||||
The npm package `tree-sitter-pascal@0.0.1` is outdated (uses NAN bindings, incompatible with Node.js v24+). The implementation uses the actively maintained GitHub repository ([Isopod/tree-sitter-pascal](https://github.com/Isopod/tree-sitter-pascal), v0.10.2) with a pinned commit hash for deterministic builds. This is consistent with how `@sengac/tree-sitter-dart` handles a similar situation.
|
|
||||||
|
|
||||||
## Testing Instructions
|
|
||||||
|
|
||||||
### Prerequisites
|
|
||||||
|
|
||||||
- Node.js >= 18
|
|
||||||
- npm
|
|
||||||
- Git
|
|
||||||
|
|
||||||
### 1. Clone and build
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git clone -b delphi-support https://github.com/omonien/codegraph.git
|
|
||||||
cd codegraph
|
|
||||||
npm install
|
|
||||||
npm run build
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. Link globally
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm link
|
|
||||||
```
|
|
||||||
|
|
||||||
Verify with:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
codegraph --version
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. Index a Delphi project
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd /path/to/your/delphi-project
|
|
||||||
codegraph init -i
|
|
||||||
codegraph index
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. Query the code graph
|
|
||||||
|
|
||||||
```bash
|
|
||||||
codegraph status # Show index statistics
|
|
||||||
codegraph query "TFormMain" # Search for a symbol
|
|
||||||
codegraph context "What does TCustomer do?" # Build AI context
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5. Set up the MCP server (for Claude Code)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
codegraph install
|
|
||||||
```
|
|
||||||
|
|
||||||
This configures the MCP server, tool permissions, auto-sync hooks, and CLAUDE.md in one step. After that, start Claude Code in the project — CodeGraph tools will be available immediately.
|
|
||||||
|
|
||||||
### 6. Clean up
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm unlink -g @colbymchenry/codegraph # Remove global link
|
|
||||||
rm -rf /path/to/delphi-project/.codegraph # Remove project index
|
|
||||||
```
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,26 +0,0 @@
|
|||||||
const { getParser, initGrammars, loadAllGrammars } = require('./dist/extraction/grammars');
|
|
||||||
|
|
||||||
(async () => {
|
|
||||||
await initGrammars();
|
|
||||||
await loadAllGrammars();
|
|
||||||
|
|
||||||
const parser = getParser('python');
|
|
||||||
|
|
||||||
const code = `class Child(Parent):
|
|
||||||
pass`;
|
|
||||||
|
|
||||||
const tree = parser.parse(code);
|
|
||||||
|
|
||||||
function walk(node, depth = 0) {
|
|
||||||
const indent = ' '.repeat(depth);
|
|
||||||
const preview = node.text.substring(0, 30).replace(/\n/g, '\\n');
|
|
||||||
console.log(`${indent}${node.type} [${node.startPosition.row}:${node.startPosition.column}] "${preview}"`);
|
|
||||||
|
|
||||||
for (let i = 0; i < node.namedChildCount; i++) {
|
|
||||||
const child = node.namedChild(i);
|
|
||||||
if (child) walk(child, depth + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
walk(tree.rootNode);
|
|
||||||
})();
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
const { getParser, initGrammars, loadAllGrammars } = require('./dist/extraction/grammars');
|
|
||||||
|
|
||||||
(async () => {
|
|
||||||
await initGrammars();
|
|
||||||
await loadAllGrammars();
|
|
||||||
|
|
||||||
const parser = getParser('python');
|
|
||||||
|
|
||||||
const code = `class Child(Parent, Mixin, Base):
|
|
||||||
pass`;
|
|
||||||
|
|
||||||
const tree = parser.parse(code);
|
|
||||||
|
|
||||||
function walk(node, depth = 0) {
|
|
||||||
const indent = ' '.repeat(depth);
|
|
||||||
const preview = node.text.substring(0, 40).replace(/\n/g, '\\n');
|
|
||||||
console.log(`${indent}${node.type} "${preview}"`);
|
|
||||||
|
|
||||||
for (let i = 0; i < node.namedChildCount; i++) {
|
|
||||||
const child = node.namedChild(i);
|
|
||||||
if (child) walk(child, depth + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
walk(tree.rootNode);
|
|
||||||
})();
|
|
||||||
@@ -1,131 +0,0 @@
|
|||||||
# Running the agent-behavior test (how agents actually use codegraph)
|
|
||||||
|
|
||||||
This explains how to measure **how a Claude Code agent uses the codegraph MCP
|
|
||||||
tools** on a real repo — which tools it calls (does it lead with
|
|
||||||
`codegraph_explore`?), how many follow-up `Read`/`Grep`s it does, and the token
|
|
||||||
cost. Use it when changing tool guidance (`server-instructions.ts`,
|
|
||||||
`instructions-template.ts`, tool descriptions) or retrieval, to verify the
|
|
||||||
change actually shifts agent behavior.
|
|
||||||
|
|
||||||
Scripts live in `scripts/agent-eval/`.
|
|
||||||
|
|
||||||
## Why two harnesses (read this first)
|
|
||||||
|
|
||||||
| | Interactive (`itrun.sh`) | Headless (`run-agent.sh`) |
|
|
||||||
|---|---|---|
|
|
||||||
| Drives | the real TUI via tmux | `claude -p` print mode |
|
|
||||||
| Subagent it picks | **Explore** (matches real UX) | general-purpose (diverges) |
|
|
||||||
| Metrics | tool breakdown (from session logs) + `Done(…)` token summary | exact per-tool calls + tokens/cost (stream-json) |
|
|
||||||
| Cost | Claude Max subscription | API $ (`total_cost_usd`) |
|
|
||||||
|
|
||||||
**Headless `claude -p` does NOT reproduce what users see** — it silently picks
|
|
||||||
the general-purpose subagent, while interactive sessions delegate to the
|
|
||||||
read-first **Explore** subagent. So for "what does my session actually do," use
|
|
||||||
the interactive harness. For a clean per-tool/token breakdown in one shot, use
|
|
||||||
headless (and ask for the Explore subagent in the prompt if you want that path).
|
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
|
|
||||||
- **tmux 3.0+**
|
|
||||||
- A logged-in `claude` CLI (Claude Max or API).
|
|
||||||
- codegraph configured as an MCP server (`claude mcp list` shows `codegraph`).
|
|
||||||
The interactive harness uses your global config, so it runs whatever
|
|
||||||
`codegraph` resolves to — point that at your dev build (`npm link` / the
|
|
||||||
symlinked global) to test local changes.
|
|
||||||
- A target repo, cloned and indexed:
|
|
||||||
```bash
|
|
||||||
git clone --depth 1 https://github.com/square/okhttp /tmp/corpus/okhttp
|
|
||||||
cd /tmp/corpus/okhttp && codegraph init -i
|
|
||||||
```
|
|
||||||
Good scale spread for a sweep: Alamofire (~100 files), Excalidraw (~600),
|
|
||||||
OkHttp (~640), VS Code (~10k).
|
|
||||||
|
|
||||||
## Interactive test (the faithful one)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
scripts/agent-eval/itrun.sh <repo-path> <label> "<question>"
|
|
||||||
```
|
|
||||||
|
|
||||||
Example:
|
|
||||||
```bash
|
|
||||||
scripts/agent-eval/itrun.sh /tmp/corpus/vscode vscode \
|
|
||||||
"How does the extension host communicate with the main process?"
|
|
||||||
```
|
|
||||||
|
|
||||||
It opens `claude` in a tmux session, types the question, waits for the agent to
|
|
||||||
finish, then prints:
|
|
||||||
- the `Done (N tool uses · Xk tokens · Ym)` subagent summary (from the pane),
|
|
||||||
- the `Context Xk/1.0M` main-session size,
|
|
||||||
- a **tool breakdown** parsed from the session logs (main + subagents), ending
|
|
||||||
in a `VERDICT: codegraph_explore used Nx | Read N | Grep/Bash N` line.
|
|
||||||
|
|
||||||
### Startup robustness (so unattended runs don't silently no-op)
|
|
||||||
|
|
||||||
Two things bite an unattended driver before the prompt even runs:
|
|
||||||
- **The `❯` glyph is drawn ~6s before the input accepts keystrokes.** Waiting
|
|
||||||
for `❯` is necessary but not sufficient. The harness sends the prompt, then
|
|
||||||
**verifies a chunk of it actually landed in the input box**, retrying until it
|
|
||||||
does — so it can't type into a not-yet-live input and submit nothing.
|
|
||||||
- **First time claude opens a repo it shows "Is this a project you trust?"**
|
|
||||||
(which also contains `❯`). The harness detects that dialog and presses Enter
|
|
||||||
to accept it before typing.
|
|
||||||
|
|
||||||
If the prompt never lands or work never starts, the harness now **fails loudly**
|
|
||||||
(non-zero exit) instead of capturing an empty pane and reporting a bogus run.
|
|
||||||
|
|
||||||
### How completion is detected (the tricky part)
|
|
||||||
|
|
||||||
Claude's TUI redraws in place, so you can't just wait for output to stop. The
|
|
||||||
harness polls `tmux capture-pane` and treats the pane as **busy** when it shows
|
|
||||||
the spinner's elapsed-time-in-parens — `(8s · …)` / `(1m 3s · …)`, matched by
|
|
||||||
`\(([0-9]+m )?[0-9]+s ·`. That's the *universal* working signal: it shows during
|
|
||||||
the pre-stream **thinking** phase (`(8s · thinking with max effort)`, which has
|
|
||||||
no token arrow yet) *and* during streaming. The `↓ N`/`↑ N` token arrow,
|
|
||||||
`esc to interrupt`, and `Initializing…` are OR'd in as belt-and-braces (some TUI
|
|
||||||
versions show one but not the others). It declares **idle** when the `❯` prompt
|
|
||||||
is present and not busy for 10 consecutive polls (~5s, long enough to ride out
|
|
||||||
mid-conversation thinking gaps that briefly drop the spinner). (Technique
|
|
||||||
adapted from devpit's `WaitForIdle`.)
|
|
||||||
|
|
||||||
### Where the breakdown comes from
|
|
||||||
|
|
||||||
`parse-session.mjs` reads the newest session log under
|
|
||||||
`~/.claude/projects/<escaped-cwd>/<session>.jsonl` and its subagent transcripts
|
|
||||||
under `<session>/subagents/*.jsonl`. The **subagent** file is where the real
|
|
||||||
tool calls are — the main log only shows the `Agent` delegation. You can run it
|
|
||||||
standalone:
|
|
||||||
```bash
|
|
||||||
node scripts/agent-eval/parse-session.mjs /tmp/corpus/vscode
|
|
||||||
```
|
|
||||||
|
|
||||||
## Headless test (clean tokens, forceable Explore path)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
scripts/agent-eval/run-agent.sh <repo-path> <label> "<question>"
|
|
||||||
```
|
|
||||||
Writes stream-json and prints the tool sequence + exact tokens/cost. To
|
|
||||||
reproduce the Explore-subagent path headlessly, ask for it:
|
|
||||||
`"Use an Explore subagent to investigate, then answer: …"`.
|
|
||||||
|
|
||||||
## Running a sweep
|
|
||||||
|
|
||||||
Single runs vary a lot (the VS Code question has ranged 26–37 tool uses /
|
|
||||||
88–105k tokens across runs). For a real signal, run N≥3 and take the median:
|
|
||||||
```bash
|
|
||||||
for i in 1 2 3; do
|
|
||||||
scripts/agent-eval/itrun.sh /tmp/corpus/vscode "vscode-$i" "<question>"
|
|
||||||
done
|
|
||||||
```
|
|
||||||
|
|
||||||
## What "good" looks like
|
|
||||||
|
|
||||||
After the explore-first guidance (PR #191), an understanding question should
|
|
||||||
show the agent **leading with `codegraph_explore`** and using `search`/`node`
|
|
||||||
to fill gaps — not a wall of `Read`/`Grep`. Example faithful run:
|
|
||||||
`VERDICT: codegraph_explore used 3x | Read 8 | Grep/Bash 1`. If `explore` is 0
|
|
||||||
and `Read`/`Grep` dominate, the guidance regressed.
|
|
||||||
|
|
||||||
## Output artifacts
|
|
||||||
|
|
||||||
Transcripts and logs go to `$AGENT_EVAL_OUT` (default `/tmp/agent-eval/`):
|
|
||||||
`itrun-<label>.txt` (pane capture), `run-<label>.jsonl` (headless stream-json).
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
/**
|
|
||||||
* Patches tree-sitter-dart to use NAPI bindings compatible with tree-sitter 0.22+
|
|
||||||
*
|
|
||||||
* tree-sitter-dart v1.0.0 ships with NAN-style bindings that are incompatible
|
|
||||||
* with tree-sitter 0.22+ which expects NAPI-style bindings with type-tagged
|
|
||||||
* externals. This script rewrites the binding files and rebuilds.
|
|
||||||
*/
|
|
||||||
const { writeFileSync, existsSync } = require('fs');
|
|
||||||
const { join } = require('path');
|
|
||||||
const { execSync } = require('child_process');
|
|
||||||
|
|
||||||
const DART_DIR = join(__dirname, '..', 'node_modules', 'tree-sitter-dart');
|
|
||||||
|
|
||||||
if (!existsSync(DART_DIR)) {
|
|
||||||
// tree-sitter-dart not installed, skip
|
|
||||||
process.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if already patched (look for NAPI-style binding)
|
|
||||||
const bindingPath = join(DART_DIR, 'bindings', 'node', 'binding.cc');
|
|
||||||
const { readFileSync } = require('fs');
|
|
||||||
try {
|
|
||||||
const existing = readFileSync(bindingPath, 'utf8');
|
|
||||||
if (existing.includes('napi.h')) {
|
|
||||||
// Already patched, check if build exists
|
|
||||||
const buildPath = join(DART_DIR, 'build', 'Release', 'tree_sitter_dart_binding.node');
|
|
||||||
if (existsSync(buildPath)) {
|
|
||||||
console.log('tree-sitter-dart: already patched and built.');
|
|
||||||
process.exit(0);
|
|
||||||
}
|
|
||||||
// Patched but not built, fall through to rebuild
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
// Can't read, continue with patch
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('Patching tree-sitter-dart for NAPI compatibility...');
|
|
||||||
|
|
||||||
// Write NAPI-compatible binding.cc
|
|
||||||
const bindingCC = `#include <napi.h>
|
|
||||||
|
|
||||||
typedef struct TSLanguage TSLanguage;
|
|
||||||
|
|
||||||
extern "C" TSLanguage *tree_sitter_dart();
|
|
||||||
|
|
||||||
// "tree-sitter", "language" hashed with BLAKE2
|
|
||||||
const napi_type_tag LANGUAGE_TYPE_TAG = {
|
|
||||||
0x8AF2E5212AD58ABF, 0xD5006CAD83ABBA16
|
|
||||||
};
|
|
||||||
|
|
||||||
Napi::Object Init(Napi::Env env, Napi::Object exports) {
|
|
||||||
exports["name"] = Napi::String::New(env, "dart");
|
|
||||||
auto language = Napi::External<TSLanguage>::New(env, tree_sitter_dart());
|
|
||||||
language.TypeTag(&LANGUAGE_TYPE_TAG);
|
|
||||||
exports["language"] = language;
|
|
||||||
return exports;
|
|
||||||
}
|
|
||||||
|
|
||||||
NODE_API_MODULE(tree_sitter_dart_binding, Init)
|
|
||||||
`;
|
|
||||||
writeFileSync(bindingPath, bindingCC);
|
|
||||||
|
|
||||||
// Write NAPI-compatible binding.gyp
|
|
||||||
const bindingGyp = `{
|
|
||||||
"targets": [
|
|
||||||
{
|
|
||||||
"target_name": "tree_sitter_dart_binding",
|
|
||||||
"dependencies": [
|
|
||||||
"<!(node -p \\"require('node-addon-api').targets\\"):node_addon_api_except"
|
|
||||||
],
|
|
||||||
"include_dirs": [
|
|
||||||
"src"
|
|
||||||
],
|
|
||||||
"sources": [
|
|
||||||
"src/parser.c",
|
|
||||||
"bindings/node/binding.cc",
|
|
||||||
"src/scanner.c"
|
|
||||||
],
|
|
||||||
"conditions": [
|
|
||||||
["OS!='win'", {
|
|
||||||
"cflags_c": [
|
|
||||||
"-std=c99"
|
|
||||||
]
|
|
||||||
}, {
|
|
||||||
"cflags_c": [
|
|
||||||
"/std:c11",
|
|
||||||
"/utf-8"
|
|
||||||
]
|
|
||||||
}]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
writeFileSync(join(DART_DIR, 'binding.gyp'), bindingGyp);
|
|
||||||
|
|
||||||
// Rebuild native module
|
|
||||||
try {
|
|
||||||
execSync('npx node-gyp rebuild', {
|
|
||||||
cwd: DART_DIR,
|
|
||||||
stdio: 'pipe',
|
|
||||||
timeout: 120000,
|
|
||||||
});
|
|
||||||
console.log('tree-sitter-dart: patched and rebuilt successfully.');
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Warning: Failed to rebuild tree-sitter-dart native module.');
|
|
||||||
console.error('Dart language support may not work.');
|
|
||||||
if (process.env.DEBUG) {
|
|
||||||
console.error(error.stderr?.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
const { extractFromSource } = require('./dist/extraction');
|
|
||||||
const { initGrammars, loadAllGrammars } = require('./dist/extraction/grammars');
|
|
||||||
|
|
||||||
(async () => {
|
|
||||||
await initGrammars();
|
|
||||||
await loadAllGrammars();
|
|
||||||
|
|
||||||
const code = `
|
|
||||||
class Parent:
|
|
||||||
pass
|
|
||||||
|
|
||||||
class Child(Parent):
|
|
||||||
pass
|
|
||||||
|
|
||||||
class Multiple(Parent, Mixin):
|
|
||||||
pass
|
|
||||||
`;
|
|
||||||
|
|
||||||
const result = extractFromSource('test.py', code);
|
|
||||||
|
|
||||||
console.log('=== NODES ===');
|
|
||||||
result.nodes.forEach(n => {
|
|
||||||
console.log(`${n.kind}: ${n.name} (line ${n.startLine})`);
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('\n=== UNRESOLVED REFERENCES ===');
|
|
||||||
result.unresolvedReferences.forEach(r => {
|
|
||||||
console.log(`${r.referenceKind}: ${r.referenceName} (from ${r.fromNodeId})`);
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('\n=== EDGES ===');
|
|
||||||
result.edges.forEach(e => {
|
|
||||||
console.log(`${e.kind}: ${e.source} -> ${e.target}`);
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
Reference in New Issue
Block a user