Skip to content

Commit 2ea3446

Browse files
committed
feat(code): port posthog detection logic to new pkg
1 parent c9a5649 commit 2ea3446

23 files changed

+4843
-4
lines changed

mprocs.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ procs:
1313
git:
1414
shell: 'node scripts/pnpm-run.mjs --filter @posthog/git run dev'
1515

16+
detect:
17+
shell: 'node scripts/pnpm-run.mjs --filter @posthog/detect run dev'
18+
1619
storybook:
1720
shell: 'node scripts/pnpm-run.mjs --filter code run storybook'
1821
autostart: false
207 KB
Binary file not shown.
355 KB
Binary file not shown.
448 KB
Binary file not shown.
2.03 MB
Binary file not shown.
1.38 MB
Binary file not shown.
1.35 MB
Binary file not shown.
186 KB
Binary file not shown.

packages/detect/package.json

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"name": "@posthog/detect",
3+
"version": "1.0.0",
4+
"description": "Detect PostHog SDK usage in source code via tree-sitter AST analysis",
5+
"type": "module",
6+
"exports": {
7+
".": {
8+
"types": "./dist/index.d.ts",
9+
"import": "./dist/index.js"
10+
}
11+
},
12+
"scripts": {
13+
"build": "tsup",
14+
"dev": "tsup --watch",
15+
"typecheck": "tsc --noEmit",
16+
"clean": "node ../../scripts/rimraf.mjs dist .turbo",
17+
"fetch-grammars": "node scripts/fetch-grammars.cjs",
18+
"test": "vitest run"
19+
},
20+
"dependencies": {
21+
"web-tree-sitter": "^0.24.7"
22+
},
23+
"devDependencies": {
24+
"tree-sitter-cli": "^0.26.6",
25+
"tsup": "^8.5.1",
26+
"typescript": "^5.5.0",
27+
"vitest": "^2.1.9"
28+
},
29+
"files": [
30+
"dist/**/*",
31+
"src/**/*",
32+
"grammars/**/*"
33+
]
34+
}
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
#!/usr/bin/env node
2+
3+
/**
4+
* Builds tree-sitter WASM grammar files for all supported languages.
5+
* Requires: tree-sitter-cli and emscripten (or docker).
6+
*
7+
* Usage: node scripts/fetch-grammars.cjs
8+
*
9+
* If tree-sitter CLI cannot build WASM (no emscripten), you can manually
10+
* place pre-built .wasm files in the grammars/ directory.
11+
*
12+
* Copied from posthog-vscode/scripts/fetch-grammars.js
13+
*/
14+
15+
const { execSync } = require('child_process');
16+
const fs = require('fs');
17+
const path = require('path');
18+
19+
const GRAMMARS_DIR = path.join(__dirname, '..', 'grammars');
20+
21+
function hasCli() {
22+
try {
23+
execSync('npx tree-sitter --version', { stdio: 'pipe' });
24+
return true;
25+
} catch {
26+
return false;
27+
}
28+
}
29+
30+
function buildGrammar(grammarPkg, outputName, subDir) {
31+
const dest = path.join(GRAMMARS_DIR, outputName);
32+
if (fs.existsSync(dest) && fs.statSync(dest).size > 10000) {
33+
const size = (fs.statSync(dest).size / 1024).toFixed(0);
34+
console.log(` ✓ ${outputName} (${size}KB, cached)`);
35+
return true;
36+
}
37+
38+
const tempDir = path.join(__dirname, '..', '.grammar-build');
39+
if (!fs.existsSync(tempDir)) {
40+
fs.mkdirSync(tempDir, { recursive: true });
41+
}
42+
43+
// Strip version specifier from package name for the directory path
44+
const dirName = grammarPkg.replace(/@[\d.]+.*$/, '');
45+
const grammarDir = path.join(tempDir, 'node_modules', dirName);
46+
if (!fs.existsSync(grammarDir)) {
47+
process.stdout.write(` ↓ Installing ${grammarPkg}...`);
48+
try {
49+
execSync(`npm install ${grammarPkg} --prefix "${tempDir}" --ignore-scripts`, {
50+
stdio: 'pipe',
51+
cwd: tempDir,
52+
});
53+
console.log(' OK');
54+
} catch (err) {
55+
console.log(` FAILED`);
56+
return false;
57+
}
58+
}
59+
60+
const buildDir = subDir ? path.join(grammarDir, subDir) : grammarDir;
61+
process.stdout.write(` ⚙ Building ${outputName}...`);
62+
try {
63+
execSync(`npx tree-sitter build --wasm -o "${dest}"`, {
64+
stdio: 'pipe',
65+
cwd: buildDir,
66+
timeout: 120000,
67+
});
68+
const size = (fs.statSync(dest).size / 1024).toFixed(0);
69+
console.log(` ${size}KB`);
70+
return true;
71+
} catch (err) {
72+
const stderr = err.stderr ? err.stderr.toString().trim() : '';
73+
const stdout = err.stdout ? err.stdout.toString().trim() : '';
74+
const msg = stderr || stdout || err.message || '';
75+
console.log(` FAILED`);
76+
if (msg) { console.log(` → ${msg}`); }
77+
return false;
78+
}
79+
}
80+
81+
function main() {
82+
if (!fs.existsSync(GRAMMARS_DIR)) {
83+
fs.mkdirSync(GRAMMARS_DIR, { recursive: true });
84+
}
85+
86+
// Copy the core tree-sitter runtime WASM
87+
const runtimeSrc = path.join(__dirname, '..', 'node_modules', 'web-tree-sitter', 'tree-sitter.wasm');
88+
const altRuntimeSrc = path.join(__dirname, '..', '..', '..', 'node_modules', 'web-tree-sitter', 'tree-sitter.wasm');
89+
const runtimeDest = path.join(GRAMMARS_DIR, 'tree-sitter.wasm');
90+
const src = fs.existsSync(runtimeSrc) ? runtimeSrc : altRuntimeSrc;
91+
if (fs.existsSync(src)) {
92+
fs.copyFileSync(src, runtimeDest);
93+
const size = (fs.statSync(runtimeDest).size / 1024).toFixed(0);
94+
console.log(` ✓ tree-sitter.wasm runtime (${size}KB)`);
95+
}
96+
97+
console.log('\nBuilding tree-sitter grammar WASM files...\n');
98+
99+
if (!hasCli()) {
100+
console.log('⚠ tree-sitter CLI not found. Install it:');
101+
console.log(' npm install -g tree-sitter-cli\n');
102+
console.log('Then re-run: node scripts/fetch-grammars.cjs');
103+
process.exit(1);
104+
}
105+
106+
let built = 0;
107+
108+
// JavaScript — pinned to 0.23.1 for ABI v14 compatibility with web-tree-sitter@0.24.x
109+
if (buildGrammar('tree-sitter-javascript@0.23.1', 'tree-sitter-javascript.wasm')) built++;
110+
111+
// TypeScript (has typescript/ and tsx/ sub-directories)
112+
if (buildGrammar('tree-sitter-typescript', 'tree-sitter-typescript.wasm', 'typescript')) built++;
113+
if (buildGrammar('tree-sitter-typescript', 'tree-sitter-tsx.wasm', 'tsx')) built++;
114+
115+
// Python — pinned to 0.23.5 for ABI v14 compatibility with web-tree-sitter@0.24.x
116+
if (buildGrammar('tree-sitter-python@0.23.5', 'tree-sitter-python.wasm')) built++;
117+
118+
// Go — pinned to 0.23.4 for ABI v14 compatibility with web-tree-sitter@0.24.x
119+
if (buildGrammar('tree-sitter-go@0.23.4', 'tree-sitter-go.wasm')) built++;
120+
121+
// Ruby — pinned to 0.23.1 for ABI v14 compatibility with web-tree-sitter@0.24.x
122+
if (buildGrammar('tree-sitter-ruby@0.23.1', 'tree-sitter-ruby.wasm')) built++;
123+
124+
// Cleanup temp dir
125+
const tempDir = path.join(__dirname, '..', '.grammar-build');
126+
try { fs.rmSync(tempDir, { recursive: true, force: true }); } catch { /* */ }
127+
128+
console.log(`\n${built} grammar(s) ready in grammars/`);
129+
130+
if (built === 0) {
131+
console.log('\n⚠ No grammars were built. You may need emscripten installed.');
132+
console.log(' See: https://emscripten.org/docs/getting_started/downloads.html');
133+
console.log(' Or use Docker: tree-sitter build --wasm --docker');
134+
}
135+
}
136+
137+
main();

0 commit comments

Comments
 (0)