Add WASM fallbacks for tree-sitter and SQLite, fix installer

Replace native tree-sitter with web-tree-sitter + tree-sitter-wasms for
universal cross-platform support. Add node-sqlite3-wasm as a fallback
when better-sqlite3 native bindings aren't available. Move better-sqlite3
and sqlite-vss to optionalDependencies so installs never fail.

Fix installer to use npx fallback when global npm install fails, so MCP
config, hooks, and quick-start instructions all work without the bare
codegraph command in PATH.

Fix tests: update schema version expectation, fix db test paths and
method names, extract MAX_OUTPUT_LENGTH as module constant, normalize
Windows path separators in import resolver.
This commit is contained in:
Colby McHenry
2026-02-14 00:56:15 -06:00
parent 429359c25f
commit 8346440592
24 changed files with 707 additions and 781 deletions
+6 -2
View File
@@ -4,16 +4,20 @@
* Tests for the tree-sitter extraction system.
*/
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { describe, it, expect, beforeAll, beforeEach, afterEach } from 'vitest';
import * as fs from 'fs';
import * as path from 'path';
import * as os from 'os';
import { CodeGraph } from '../src';
import { extractFromSource, scanDirectory, shouldIncludeFile } from '../src/extraction';
import { detectLanguage, isLanguageSupported, getSupportedLanguages } from '../src/extraction/grammars';
import { detectLanguage, isLanguageSupported, getSupportedLanguages, initGrammars } from '../src/extraction/grammars';
import { normalizePath } from '../src/utils';
import { DEFAULT_CONFIG } from '../src/types';
beforeAll(async () => {
await initGrammars();
});
// Create a temporary directory for each test
function createTempDir(): string {
return fs.mkdtempSync(path.join(os.tmpdir(), 'codegraph-test-'));
+1 -1
View File
@@ -317,7 +317,7 @@ describe('Database Connection', () => {
const version = db.getSchemaVersion();
expect(version).not.toBeNull();
expect(version?.version).toBe(1);
expect(version?.version).toBe(2);
db.close();
});
+25 -23
View File
@@ -13,7 +13,7 @@
* - CLI uninit command
*/
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { describe, it, expect, beforeAll, beforeEach, afterEach } from 'vitest';
import * as fs from 'fs';
import * as path from 'path';
import * as os from 'os';
@@ -24,8 +24,13 @@ import {
getSupportedLanguages,
clearParserCache,
getUnavailableGrammarErrors,
initGrammars,
} from '../src/extraction/grammars';
beforeAll(async () => {
await initGrammars();
});
// Create a temporary directory for each test
function createTempDir(): string {
return fs.mkdtempSync(path.join(os.tmpdir(), 'codegraph-pr19-test-'));
@@ -320,8 +325,9 @@ describe('Database Layer Improvements', () => {
const { DatabaseConnection } = await import('../src/db');
const { QueryBuilder } = await import('../src/db/queries');
const db = DatabaseConnection.initialize(testDir);
const queries = new QueryBuilder(db.getDatabase());
const dbPath = path.join(testDir, 'codegraph.db');
const db = DatabaseConnection.initialize(dbPath);
const queries = new QueryBuilder(db.getDb());
// Insert a node first (needed as foreign key)
queries.insertNode({
@@ -375,8 +381,9 @@ describe('Database Layer Improvements', () => {
const { DatabaseConnection } = await import('../src/db');
const { QueryBuilder } = await import('../src/db/queries');
const db = DatabaseConnection.initialize(testDir);
const queries = new QueryBuilder(db.getDatabase());
const dbPath = path.join(testDir, 'codegraph.db');
const db = DatabaseConnection.initialize(dbPath);
const queries = new QueryBuilder(db.getDb());
// Insert some nodes
for (let i = 0; i < 3; i++) {
@@ -405,8 +412,9 @@ describe('Database Layer Improvements', () => {
it.skipIf(!HAS_SQLITE)('should set performance pragmas on initialization', async () => {
const { DatabaseConnection } = await import('../src/db');
const db = DatabaseConnection.initialize(testDir);
const rawDb = db.getDatabase();
const dbPath = path.join(testDir, 'codegraph.db');
const db = DatabaseConnection.initialize(dbPath);
const rawDb = db.getDb();
// Check pragmas were set
const synchronous = rawDb.pragma('synchronous', { simple: true });
@@ -428,8 +436,9 @@ describe('Database Layer Improvements', () => {
const { DatabaseConnection } = await import('../src/db');
const { QueryBuilder } = await import('../src/db/queries');
const db = DatabaseConnection.initialize(testDir);
const queries = new QueryBuilder(db.getDatabase());
const dbPath = path.join(testDir, 'codegraph.db');
const db = DatabaseConnection.initialize(dbPath);
const queries = new QueryBuilder(db.getDb());
// Should not throw on empty array
expect(() => queries.insertUnresolvedRefsBatch([])).not.toThrow();
@@ -665,28 +674,21 @@ describe('CLI uninit', () => {
// Tree-sitter Version Pinning
// =============================================================================
describe('Tree-sitter Version Pinning', () => {
it('should have exact versions (no caret) in package.json', () => {
describe('Tree-sitter WASM Setup', () => {
it('should use web-tree-sitter and tree-sitter-wasms in dependencies', () => {
const pkgPath = path.join(__dirname, '..', 'package.json');
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
const treeSitterDeps = Object.entries(pkg.dependencies as Record<string, string>)
.filter(([name]) => name.startsWith('tree-sitter') || name.includes('tree-sitter'));
for (const [name, version] of treeSitterDeps) {
// Skip github: references
if (version.startsWith('github:')) continue;
expect(version, `${name} should not use caret range`).not.toMatch(/^\^/);
}
expect(pkg.dependencies['web-tree-sitter']).toBeDefined();
expect(pkg.dependencies['tree-sitter-wasms']).toBeDefined();
});
it('should have tree-sitter override pinned', () => {
it('should not have native tree-sitter in dependencies', () => {
const pkgPath = path.join(__dirname, '..', 'package.json');
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
expect(pkg.overrides).toBeDefined();
expect(pkg.overrides['tree-sitter']).toBeDefined();
expect(pkg.overrides['tree-sitter']).not.toMatch(/^\^/);
expect(pkg.dependencies['tree-sitter']).toBeUndefined();
expect(pkg.overrides).toBeUndefined();
});
});