pindex 1.2.3 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -5
- package/dist/db/migrations.d.ts +4 -1
- package/dist/db/migrations.d.ts.map +1 -1
- package/dist/db/migrations.js +9 -3
- package/dist/db/migrations.js.map +1 -1
- package/dist/db/queries.d.ts.map +1 -1
- package/dist/db/queries.js +21 -17
- package/dist/db/queries.js.map +1 -1
- package/dist/gui/server.d.ts.map +1 -1
- package/dist/gui/server.js +14 -5
- package/dist/gui/server.js.map +1 -1
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -1
- package/dist/indexer/index.d.ts +23 -3
- package/dist/indexer/index.d.ts.map +1 -1
- package/dist/indexer/index.js +146 -62
- package/dist/indexer/index.js.map +1 -1
- package/dist/indexer/lsp-mapper.d.ts +6 -0
- package/dist/indexer/lsp-mapper.d.ts.map +1 -0
- package/dist/indexer/lsp-mapper.js +40 -0
- package/dist/indexer/lsp-mapper.js.map +1 -0
- package/dist/indexer/lsp-python.d.ts +43 -0
- package/dist/indexer/lsp-python.d.ts.map +1 -0
- package/dist/indexer/lsp-python.js +234 -0
- package/dist/indexer/lsp-python.js.map +1 -0
- package/dist/indexer/parse-pool.d.ts +26 -0
- package/dist/indexer/parse-pool.d.ts.map +1 -0
- package/dist/indexer/parse-pool.js +201 -0
- package/dist/indexer/parse-pool.js.map +1 -0
- package/dist/indexer/parse-types.d.ts +33 -0
- package/dist/indexer/parse-types.d.ts.map +1 -0
- package/dist/indexer/parse-types.js +2 -0
- package/dist/indexer/parse-types.js.map +1 -0
- package/dist/indexer/parse-worker.d.ts +2 -0
- package/dist/indexer/parse-worker.d.ts.map +1 -0
- package/dist/indexer/parse-worker.js +39 -0
- package/dist/indexer/parse-worker.js.map +1 -0
- package/dist/indexer/parser.d.ts.map +1 -1
- package/dist/indexer/parser.js +10 -4
- package/dist/indexer/parser.js.map +1 -1
- package/dist/indexer/summarizer.d.ts +18 -7
- package/dist/indexer/summarizer.d.ts.map +1 -1
- package/dist/indexer/summarizer.js +110 -13
- package/dist/indexer/summarizer.js.map +1 -1
- package/dist/indexer/watcher.d.ts.map +1 -1
- package/dist/indexer/watcher.js +2 -0
- package/dist/indexer/watcher.js.map +1 -1
- package/dist/memory/observer.d.ts.map +1 -1
- package/dist/memory/observer.js +20 -4
- package/dist/memory/observer.js.map +1 -1
- package/dist/monitoring/server.d.ts.map +1 -1
- package/dist/monitoring/server.js +5 -1
- package/dist/monitoring/server.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +32 -16
- package/dist/server.js.map +1 -1
- package/dist/tools/get_context.d.ts.map +1 -1
- package/dist/tools/get_context.js +4 -2
- package/dist/tools/get_context.js.map +1 -1
- package/dist/tools/schemas.d.ts +75 -0
- package/dist/tools/schemas.d.ts.map +1 -0
- package/dist/tools/schemas.js +79 -0
- package/dist/tools/schemas.js.map +1 -0
- package/dist/tools/search_symbols.d.ts.map +1 -1
- package/dist/tools/search_symbols.js +8 -6
- package/dist/tools/search_symbols.js.map +1 -1
- package/dist/util/paths.d.ts +9 -0
- package/dist/util/paths.d.ts.map +1 -0
- package/dist/util/paths.js +18 -0
- package/dist/util/paths.js.map +1 -0
- package/package.json +15 -7
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { spawn as nodeSpawn } from 'node:child_process';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { resolve, join } from 'node:path';
|
|
4
|
+
import { pathToFileURL } from 'node:url';
|
|
5
|
+
import { StreamMessageReader, StreamMessageWriter, createMessageConnection, } from 'vscode-jsonrpc/node.js';
|
|
6
|
+
import { mapDocumentSymbols } from './lsp-mapper.js';
|
|
7
|
+
import { parseFile } from './parser.js';
|
|
8
|
+
export class LspPythonClient {
|
|
9
|
+
_state = 'idle';
|
|
10
|
+
enabled;
|
|
11
|
+
projectRoot;
|
|
12
|
+
timeoutMs;
|
|
13
|
+
spawnImpl;
|
|
14
|
+
resolveImpl;
|
|
15
|
+
proc = null;
|
|
16
|
+
connection = null;
|
|
17
|
+
static warnedMissing = false;
|
|
18
|
+
pendingQueue = Promise.resolve();
|
|
19
|
+
restartAttempted = false;
|
|
20
|
+
consecutiveTimeouts = 0;
|
|
21
|
+
constructor(options) {
|
|
22
|
+
this.enabled = options.enabled;
|
|
23
|
+
this.projectRoot = options.projectRoot;
|
|
24
|
+
this.timeoutMs = options.timeoutMs ?? 5000;
|
|
25
|
+
this.spawnImpl =
|
|
26
|
+
options._spawn ??
|
|
27
|
+
((path) => nodeSpawn(path, ['--stdio'], { stdio: ['pipe', 'pipe', 'pipe'] }));
|
|
28
|
+
this.resolveImpl = options._resolveServerPath ?? (() => resolvePyrightLangserver());
|
|
29
|
+
}
|
|
30
|
+
/** Test-only: resets module-level warning guard so tests can observe
|
|
31
|
+
* stderr output repeatedly. NOT for production use. */
|
|
32
|
+
static _resetWarnedMissingForTest() {
|
|
33
|
+
LspPythonClient.warnedMissing = false;
|
|
34
|
+
}
|
|
35
|
+
get state() {
|
|
36
|
+
return this._state;
|
|
37
|
+
}
|
|
38
|
+
get ready() {
|
|
39
|
+
return this._state === 'ready';
|
|
40
|
+
}
|
|
41
|
+
async start() {
|
|
42
|
+
if (this._state !== 'idle')
|
|
43
|
+
return;
|
|
44
|
+
if (!this.enabled) {
|
|
45
|
+
this._state = 'failed';
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const path = this.resolveImpl();
|
|
49
|
+
if (!path) {
|
|
50
|
+
if (!LspPythonClient.warnedMissing) {
|
|
51
|
+
process.stderr.write(`[pindex] LSP: pyright-langserver not found on PATH or in node_modules; ` +
|
|
52
|
+
`falling back to regex parsing. Install with "npm install pyright" or ` +
|
|
53
|
+
`set PINDEX_LSP=false to silence this.\n`);
|
|
54
|
+
LspPythonClient.warnedMissing = true;
|
|
55
|
+
}
|
|
56
|
+
this._state = 'failed';
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
this._state = 'starting';
|
|
60
|
+
try {
|
|
61
|
+
this.proc = this.spawnImpl(path);
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
process.stderr.write(`[pindex] LSP: spawn failed: ${String(err)}\n`);
|
|
65
|
+
this._state = 'failed';
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
// exitReject lets us abort the initialize handshake when the process exits early.
|
|
69
|
+
let exitReject;
|
|
70
|
+
const exitPromise = new Promise((_, reject) => { exitReject = reject; });
|
|
71
|
+
this.proc.on('exit', (code) => {
|
|
72
|
+
if (this._state === 'closed')
|
|
73
|
+
return;
|
|
74
|
+
process.stderr.write(`[pindex] LSP: pyright-langserver exited (code ${code})\n`);
|
|
75
|
+
if (!this.restartAttempted && this._state === 'ready') {
|
|
76
|
+
this.restartAttempted = true;
|
|
77
|
+
process.stderr.write(`[pindex] LSP: attempting one restart\n`);
|
|
78
|
+
this._state = 'idle';
|
|
79
|
+
this.proc = null;
|
|
80
|
+
this.connection?.dispose();
|
|
81
|
+
this.connection = null;
|
|
82
|
+
// Fire and forget — the restart is opportunistic.
|
|
83
|
+
this.start().catch(() => {
|
|
84
|
+
/* swallow — state already reflects any failure */
|
|
85
|
+
});
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
this._state = 'failed';
|
|
89
|
+
exitReject(new Error(`pyright-langserver exited with code ${String(code)}`));
|
|
90
|
+
});
|
|
91
|
+
this.connection = createMessageConnection(new StreamMessageReader(this.proc.stdout), new StreamMessageWriter(this.proc.stdin));
|
|
92
|
+
this.connection.listen();
|
|
93
|
+
try {
|
|
94
|
+
await Promise.race([
|
|
95
|
+
this.connection.sendRequest('initialize', {
|
|
96
|
+
processId: process.pid,
|
|
97
|
+
rootUri: pathToFileURL(resolve(this.projectRoot)).href,
|
|
98
|
+
capabilities: { textDocument: { documentSymbol: { hierarchicalDocumentSymbolSupport: true } } },
|
|
99
|
+
}),
|
|
100
|
+
exitPromise,
|
|
101
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error('initialize timeout')), this.timeoutMs)),
|
|
102
|
+
]);
|
|
103
|
+
this.connection.sendNotification('initialized', {});
|
|
104
|
+
this._state = 'ready';
|
|
105
|
+
}
|
|
106
|
+
catch (err) {
|
|
107
|
+
// The exit handler may have already set _state to 'failed' via the event loop.
|
|
108
|
+
const currentState = this._state;
|
|
109
|
+
if (currentState !== 'failed' && currentState !== 'closed') {
|
|
110
|
+
process.stderr.write(`[pindex] LSP: initialize failed: ${String(err)}\n`);
|
|
111
|
+
this._state = 'failed';
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
async getDocumentSymbols(relPath, content) {
|
|
116
|
+
if (this._state !== 'ready' || !this.connection)
|
|
117
|
+
return null;
|
|
118
|
+
// Serialise concurrent callers so the LSP sees one request at a time.
|
|
119
|
+
const task = this.pendingQueue.then(() => this.runRequest(relPath, content));
|
|
120
|
+
this.pendingQueue = task.catch(() => undefined);
|
|
121
|
+
return task;
|
|
122
|
+
}
|
|
123
|
+
async runRequest(relPath, content) {
|
|
124
|
+
if (!this.connection || this._state !== 'ready')
|
|
125
|
+
return null;
|
|
126
|
+
const uri = pathToFileURL(resolve(this.projectRoot, relPath)).href;
|
|
127
|
+
try {
|
|
128
|
+
this.connection.sendNotification('textDocument/didOpen', {
|
|
129
|
+
textDocument: { uri, languageId: 'python', version: 1, text: content },
|
|
130
|
+
});
|
|
131
|
+
let timedOut = false;
|
|
132
|
+
let response;
|
|
133
|
+
try {
|
|
134
|
+
response = (await Promise.race([
|
|
135
|
+
this.connection.sendRequest('textDocument/documentSymbol', {
|
|
136
|
+
textDocument: { uri },
|
|
137
|
+
}),
|
|
138
|
+
new Promise((_, reject) => setTimeout(() => {
|
|
139
|
+
timedOut = true;
|
|
140
|
+
reject(new Error('request timeout'));
|
|
141
|
+
}, this.timeoutMs)),
|
|
142
|
+
]));
|
|
143
|
+
}
|
|
144
|
+
catch (err) {
|
|
145
|
+
if (timedOut) {
|
|
146
|
+
this.consecutiveTimeouts++;
|
|
147
|
+
if (this.consecutiveTimeouts >= 3) {
|
|
148
|
+
process.stderr.write(`[pindex] LSP: 3 consecutive timeouts, treating as crash\n`);
|
|
149
|
+
this.simulateCrash();
|
|
150
|
+
}
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
throw err;
|
|
154
|
+
}
|
|
155
|
+
this.connection.sendNotification('textDocument/didClose', {
|
|
156
|
+
textDocument: { uri },
|
|
157
|
+
});
|
|
158
|
+
if (!response || !Array.isArray(response)) {
|
|
159
|
+
return { symbols: [], imports: extractImportsFromContent(content) };
|
|
160
|
+
}
|
|
161
|
+
this.consecutiveTimeouts = 0;
|
|
162
|
+
return {
|
|
163
|
+
symbols: mapDocumentSymbols(response),
|
|
164
|
+
imports: extractImportsFromContent(content),
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
catch (err) {
|
|
168
|
+
process.stderr.write(`[pindex] LSP: documentSymbol failed for ${relPath}: ${String(err)}\n`);
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
/** Manually triggers the same restart-or-fail path the exit handler uses.
|
|
173
|
+
* Used when the subprocess is unresponsive (repeated request timeouts). */
|
|
174
|
+
simulateCrash() {
|
|
175
|
+
if (this._state !== 'ready')
|
|
176
|
+
return;
|
|
177
|
+
this._state = 'idle';
|
|
178
|
+
try {
|
|
179
|
+
this.proc?.kill('SIGKILL');
|
|
180
|
+
}
|
|
181
|
+
catch { /* process already dead */ }
|
|
182
|
+
this.proc = null;
|
|
183
|
+
this.connection?.dispose();
|
|
184
|
+
this.connection = null;
|
|
185
|
+
if (!this.restartAttempted) {
|
|
186
|
+
this.restartAttempted = true;
|
|
187
|
+
this.start().catch(() => { });
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
this._state = 'failed';
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
async close() {
|
|
194
|
+
this._state = 'closed';
|
|
195
|
+
if (this.connection) {
|
|
196
|
+
const conn = this.connection;
|
|
197
|
+
this.connection = null;
|
|
198
|
+
try {
|
|
199
|
+
await Promise.race([
|
|
200
|
+
conn.sendRequest('shutdown', null),
|
|
201
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error('shutdown timeout')), 1000)),
|
|
202
|
+
]);
|
|
203
|
+
conn.sendNotification('exit', null);
|
|
204
|
+
}
|
|
205
|
+
catch { /* subprocess may already be dead */ }
|
|
206
|
+
conn.dispose();
|
|
207
|
+
}
|
|
208
|
+
if (this.proc) {
|
|
209
|
+
try {
|
|
210
|
+
this.proc.kill('SIGTERM');
|
|
211
|
+
}
|
|
212
|
+
catch { /* ignore */ }
|
|
213
|
+
this.proc = null;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
/** Resolves the pyright-langserver binary path by checking node_modules/.bin.
|
|
218
|
+
* Returns null if not found; PATH-based discovery is intentionally not
|
|
219
|
+
* implemented (would require spawn + stderr capture to detect failure, which
|
|
220
|
+
* is a larger change and not worth the complexity for the optionalDependency
|
|
221
|
+
* install path where node_modules is the canonical location). */
|
|
222
|
+
function resolvePyrightLangserver() {
|
|
223
|
+
const local = join(process.cwd(), 'node_modules', '.bin', 'pyright-langserver');
|
|
224
|
+
if (existsSync(local))
|
|
225
|
+
return local;
|
|
226
|
+
return null;
|
|
227
|
+
}
|
|
228
|
+
/** Reuses the existing Python regex import extractor from parseFile(). Pyright's
|
|
229
|
+
* documentSymbol does not expose import statements; the regex is reliable
|
|
230
|
+
* enough for `import X` / `from Y import Z`. */
|
|
231
|
+
function extractImportsFromContent(content) {
|
|
232
|
+
return parseFile('pseudo.py', content).imports;
|
|
233
|
+
}
|
|
234
|
+
//# sourceMappingURL=lsp-python.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lsp-python.js","sourceRoot":"","sources":["../../src/indexer/lsp-python.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ParseJobInput, ParseJobResult, ParsePoolOptions } from './parse-types.js';
|
|
2
|
+
export declare class ParsePool {
|
|
3
|
+
private readonly maxWorkers;
|
|
4
|
+
private readonly maxFileSize;
|
|
5
|
+
private workers;
|
|
6
|
+
private idleWorkers;
|
|
7
|
+
private workerJobs;
|
|
8
|
+
private pending;
|
|
9
|
+
private closed;
|
|
10
|
+
constructor(options: ParsePoolOptions);
|
|
11
|
+
parseMany(jobs: ParseJobInput[]): AsyncGenerator<ParseJobResult>;
|
|
12
|
+
close(): Promise<void>;
|
|
13
|
+
private spawnWorker;
|
|
14
|
+
private enqueue;
|
|
15
|
+
private drainQueue;
|
|
16
|
+
/** Picks a default worker count based on the host CPU count and an env
|
|
17
|
+
* override. Capped to leave at least one CPU for the main thread. Forces
|
|
18
|
+
* 0 (sync fallback) when VITEST is running, so the global tree-sitter
|
|
19
|
+
* mock in tests/setup.ts continues to apply. */
|
|
20
|
+
static pickDefaultWorkerCount(explicit: number | undefined): number;
|
|
21
|
+
/** Picks the effective worker count for a given job batch. Small batches
|
|
22
|
+
* downshift to avoid the worker startup overhead exceeding the gain. */
|
|
23
|
+
static pickEffectiveWorkerCount(jobCount: number, configured: number): number;
|
|
24
|
+
private runJobSync;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=parse-pool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-pool.d.ts","sourceRoot":"","sources":["../../src/indexer/parse-pool.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACV,aAAa,EACb,cAAc,EACd,gBAAgB,EACjB,MAAM,kBAAkB,CAAC;AAgB1B,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,WAAW,CAAgB;IACnC,OAAO,CAAC,UAAU,CAAiC;IACnD,OAAO,CAAC,OAAO,CAAoB;IACnC,OAAO,CAAC,MAAM,CAAS;gBAEX,OAAO,EAAE,gBAAgB;IAQ9B,SAAS,CAAC,IAAI,EAAE,aAAa,EAAE,GAAG,cAAc,CAAC,cAAc,CAAC;IAyCjE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA0B5B,OAAO,CAAC,WAAW;IAsCnB,OAAO,CAAC,OAAO;IAKf,OAAO,CAAC,UAAU;IAYlB;;;qDAGiD;IACjD,MAAM,CAAC,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM;IAYnE;6EACyE;IACzE,MAAM,CAAC,wBAAwB,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM;YAO/D,UAAU;CAwBzB"}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { readFile, stat } from 'node:fs/promises';
|
|
2
|
+
import { cpus } from 'node:os';
|
|
3
|
+
import { Worker } from 'node:worker_threads';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { dirname, resolve } from 'node:path';
|
|
6
|
+
import { parseFile, hashContent } from './parser.js';
|
|
7
|
+
const DEFAULT_MAX_FILE_SIZE = 1024 * 1024;
|
|
8
|
+
const MAX_RETRIES = 1;
|
|
9
|
+
// Resolve the compiled worker script relative to this module.
|
|
10
|
+
// After `npm run build`, both files live in dist/indexer/.
|
|
11
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
const WORKER_URL = resolve(__dirname, 'parse-worker.js');
|
|
13
|
+
export class ParsePool {
|
|
14
|
+
maxWorkers;
|
|
15
|
+
maxFileSize;
|
|
16
|
+
workers = [];
|
|
17
|
+
idleWorkers = [];
|
|
18
|
+
workerJobs = new Map();
|
|
19
|
+
pending = [];
|
|
20
|
+
closed = false;
|
|
21
|
+
constructor(options) {
|
|
22
|
+
this.maxWorkers = Math.max(0, options.maxWorkers);
|
|
23
|
+
this.maxFileSize = options.maxFileSize ?? DEFAULT_MAX_FILE_SIZE;
|
|
24
|
+
for (let i = 0; i < this.maxWorkers; i++) {
|
|
25
|
+
this.spawnWorker();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
async *parseMany(jobs) {
|
|
29
|
+
if (this.closed)
|
|
30
|
+
throw new Error('ParsePool is closed');
|
|
31
|
+
if (this.maxWorkers === 0) {
|
|
32
|
+
for (const job of jobs) {
|
|
33
|
+
yield await this.runJobSync(job);
|
|
34
|
+
}
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
// Submit all jobs; drain results in completion order via a shared buffer.
|
|
38
|
+
const buffer = [];
|
|
39
|
+
let notify = null;
|
|
40
|
+
let remaining = jobs.length;
|
|
41
|
+
for (const job of jobs) {
|
|
42
|
+
this.enqueue({
|
|
43
|
+
job,
|
|
44
|
+
attempts: 0,
|
|
45
|
+
resolve: (result) => {
|
|
46
|
+
buffer.push(result);
|
|
47
|
+
remaining--;
|
|
48
|
+
notify?.();
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
while (remaining > 0 || buffer.length > 0) {
|
|
53
|
+
if (buffer.length === 0) {
|
|
54
|
+
await new Promise((r) => {
|
|
55
|
+
notify = () => {
|
|
56
|
+
notify = null;
|
|
57
|
+
r();
|
|
58
|
+
};
|
|
59
|
+
});
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
yield buffer.shift();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async close() {
|
|
66
|
+
this.closed = true;
|
|
67
|
+
// Drain the pending queue: every waiting job gets a terminal result so the
|
|
68
|
+
// AsyncGenerator in parseMany can exit instead of hanging.
|
|
69
|
+
const cancelResult = (job) => ({
|
|
70
|
+
status: 'error',
|
|
71
|
+
relativePath: job.relativePath,
|
|
72
|
+
error: 'ParsePool closed',
|
|
73
|
+
});
|
|
74
|
+
for (const p of this.pending) {
|
|
75
|
+
p.resolve(cancelResult(p.job));
|
|
76
|
+
}
|
|
77
|
+
this.pending = [];
|
|
78
|
+
// Resolve any in-flight jobs BEFORE terminate, so the generator notifies
|
|
79
|
+
// and wakes before we tear down the workers.
|
|
80
|
+
for (const [, p] of this.workerJobs) {
|
|
81
|
+
p.resolve(cancelResult(p.job));
|
|
82
|
+
}
|
|
83
|
+
this.workerJobs.clear();
|
|
84
|
+
await Promise.all(this.workers.map((w) => w.terminate().then(() => undefined)));
|
|
85
|
+
this.workers = [];
|
|
86
|
+
this.idleWorkers = [];
|
|
87
|
+
}
|
|
88
|
+
// ─── Internal ────────────────────────────────────────────────────────────────
|
|
89
|
+
spawnWorker() {
|
|
90
|
+
const worker = new Worker(WORKER_URL);
|
|
91
|
+
worker.on('message', (msg) => {
|
|
92
|
+
const pending = this.workerJobs.get(worker);
|
|
93
|
+
this.workerJobs.delete(worker);
|
|
94
|
+
this.idleWorkers.push(worker);
|
|
95
|
+
pending?.resolve(msg.result);
|
|
96
|
+
this.drainQueue();
|
|
97
|
+
});
|
|
98
|
+
worker.on('error', (err) => {
|
|
99
|
+
process.stderr.write(`[pindex] ParsePool worker error: ${String(err)}\n`);
|
|
100
|
+
});
|
|
101
|
+
worker.on('exit', (code) => {
|
|
102
|
+
if (code === 0 || this.closed)
|
|
103
|
+
return;
|
|
104
|
+
// Unexpected crash. If a job was in flight, requeue once; then replace.
|
|
105
|
+
const pending = this.workerJobs.get(worker);
|
|
106
|
+
this.workerJobs.delete(worker);
|
|
107
|
+
this.workers = this.workers.filter((w) => w !== worker);
|
|
108
|
+
this.idleWorkers = this.idleWorkers.filter((w) => w !== worker);
|
|
109
|
+
if (pending) {
|
|
110
|
+
if (pending.attempts < MAX_RETRIES) {
|
|
111
|
+
pending.attempts++;
|
|
112
|
+
this.pending.unshift(pending);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
pending.resolve({
|
|
116
|
+
status: 'error',
|
|
117
|
+
relativePath: pending.job.relativePath,
|
|
118
|
+
error: `Worker exited (code ${code}) after ${pending.attempts + 1} attempts`,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (!this.closed)
|
|
123
|
+
this.spawnWorker();
|
|
124
|
+
this.drainQueue();
|
|
125
|
+
});
|
|
126
|
+
this.workers.push(worker);
|
|
127
|
+
this.idleWorkers.push(worker);
|
|
128
|
+
}
|
|
129
|
+
enqueue(pending) {
|
|
130
|
+
this.pending.push(pending);
|
|
131
|
+
this.drainQueue();
|
|
132
|
+
}
|
|
133
|
+
drainQueue() {
|
|
134
|
+
while (this.pending.length > 0 && this.idleWorkers.length > 0) {
|
|
135
|
+
const pending = this.pending.shift();
|
|
136
|
+
const worker = this.idleWorkers.shift();
|
|
137
|
+
this.workerJobs.set(worker, pending);
|
|
138
|
+
worker.postMessage({
|
|
139
|
+
job: pending.job,
|
|
140
|
+
maxFileSize: this.maxFileSize,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/** Picks a default worker count based on the host CPU count and an env
|
|
145
|
+
* override. Capped to leave at least one CPU for the main thread. Forces
|
|
146
|
+
* 0 (sync fallback) when VITEST is running, so the global tree-sitter
|
|
147
|
+
* mock in tests/setup.ts continues to apply. */
|
|
148
|
+
static pickDefaultWorkerCount(explicit) {
|
|
149
|
+
if (explicit !== undefined)
|
|
150
|
+
return Math.max(0, explicit);
|
|
151
|
+
const fromEnv = process.env.PINDEX_PARSE_WORKERS;
|
|
152
|
+
if (fromEnv !== undefined && fromEnv !== '') {
|
|
153
|
+
const n = parseInt(fromEnv, 10);
|
|
154
|
+
if (!Number.isNaN(n) && n >= 0)
|
|
155
|
+
return n;
|
|
156
|
+
}
|
|
157
|
+
if (process.env.VITEST === 'true')
|
|
158
|
+
return 0;
|
|
159
|
+
const cpuCount = cpus().length;
|
|
160
|
+
return Math.max(1, cpuCount - 1);
|
|
161
|
+
}
|
|
162
|
+
/** Picks the effective worker count for a given job batch. Small batches
|
|
163
|
+
* downshift to avoid the worker startup overhead exceeding the gain. */
|
|
164
|
+
static pickEffectiveWorkerCount(jobCount, configured) {
|
|
165
|
+
if (configured === 0)
|
|
166
|
+
return 0;
|
|
167
|
+
if (jobCount < 10)
|
|
168
|
+
return 0;
|
|
169
|
+
if (jobCount < configured * 2)
|
|
170
|
+
return 1;
|
|
171
|
+
return configured;
|
|
172
|
+
}
|
|
173
|
+
async runJobSync(job) {
|
|
174
|
+
try {
|
|
175
|
+
const st = await stat(job.absolutePath);
|
|
176
|
+
if (st.size > this.maxFileSize) {
|
|
177
|
+
return { status: 'skipped', relativePath: job.relativePath, reason: 'too_large' };
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
catch (err) {
|
|
181
|
+
process.stderr.write(`[pindex] ParsePool: stat failed for ${job.relativePath}: ${String(err)}\n`);
|
|
182
|
+
return { status: 'skipped', relativePath: job.relativePath, reason: 'not_found' };
|
|
183
|
+
}
|
|
184
|
+
let content;
|
|
185
|
+
try {
|
|
186
|
+
content = await readFile(job.absolutePath, 'utf-8');
|
|
187
|
+
}
|
|
188
|
+
catch (err) {
|
|
189
|
+
return { status: 'error', relativePath: job.relativePath, error: String(err) };
|
|
190
|
+
}
|
|
191
|
+
try {
|
|
192
|
+
const parsed = parseFile(job.absolutePath, content);
|
|
193
|
+
const hash = hashContent(content);
|
|
194
|
+
return { status: 'ok', relativePath: job.relativePath, parsed, hash, content };
|
|
195
|
+
}
|
|
196
|
+
catch (err) {
|
|
197
|
+
return { status: 'error', relativePath: job.relativePath, error: String(err) };
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=parse-pool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-pool.js","sourceRoot":"","sources":["../../src/indexer/parse-pool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { ParsedFile, ParsedImport } from '../types.js';
|
|
2
|
+
export type { ParsedFile, ParsedImport };
|
|
3
|
+
/** Job submitted to the pool. Paths are absolute for the worker's readFile,
|
|
4
|
+
* and project-relative for the main thread's DB lookups. */
|
|
5
|
+
export interface ParseJobInput {
|
|
6
|
+
absolutePath: string;
|
|
7
|
+
relativePath: string;
|
|
8
|
+
}
|
|
9
|
+
export type ParseJobResult = {
|
|
10
|
+
status: 'ok';
|
|
11
|
+
relativePath: string;
|
|
12
|
+
parsed: ParsedFile;
|
|
13
|
+
hash: string;
|
|
14
|
+
/** File content, sent back so the main thread can slice snippets /
|
|
15
|
+
* summarise without a second disk read. */
|
|
16
|
+
content: string;
|
|
17
|
+
} | {
|
|
18
|
+
status: 'skipped';
|
|
19
|
+
relativePath: string;
|
|
20
|
+
reason: 'too_large' | 'not_found';
|
|
21
|
+
} | {
|
|
22
|
+
status: 'error';
|
|
23
|
+
relativePath: string;
|
|
24
|
+
error: string;
|
|
25
|
+
};
|
|
26
|
+
export interface ParsePoolOptions {
|
|
27
|
+
/** 0 = run synchronously in the calling thread (test mode).
|
|
28
|
+
* N > 0 = spawn N worker_threads. */
|
|
29
|
+
maxWorkers: number;
|
|
30
|
+
/** Max file size in bytes; larger files are returned as 'skipped'. Defaults to 1 MB. */
|
|
31
|
+
maxFileSize?: number;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=parse-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-types.d.ts","sourceRoot":"","sources":["../../src/indexer/parse-types.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE5D,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC;AAEzC;6DAC6D;AAC7D,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,MAAM,cAAc,GACtB;IACE,MAAM,EAAE,IAAI,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,UAAU,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb;gDAC4C;IAC5C,OAAO,EAAE,MAAM,CAAC;CACjB,GACD;IACE,MAAM,EAAE,SAAS,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,WAAW,GAAG,WAAW,CAAC;CACnC,GACD;IACE,MAAM,EAAE,OAAO,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEN,MAAM,WAAW,gBAAgB;IAC/B;0CACsC;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,wFAAwF;IACxF,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-types.js","sourceRoot":"","sources":["../../src/indexer/parse-types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-worker.d.ts","sourceRoot":"","sources":["../../src/indexer/parse-worker.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// src/indexer/parse-worker.ts
|
|
2
|
+
import { readFileSync, statSync } from 'node:fs';
|
|
3
|
+
import { parentPort } from 'node:worker_threads';
|
|
4
|
+
import { parseFile, hashContent } from './parser.js';
|
|
5
|
+
if (!parentPort) {
|
|
6
|
+
throw new Error('parse-worker.ts must be loaded as a worker_threads script');
|
|
7
|
+
}
|
|
8
|
+
parentPort.on('message', (msg) => {
|
|
9
|
+
const result = runJob(msg.job, msg.maxFileSize);
|
|
10
|
+
parentPort.postMessage({ result });
|
|
11
|
+
});
|
|
12
|
+
function runJob(job, maxFileSize) {
|
|
13
|
+
try {
|
|
14
|
+
const st = statSync(job.absolutePath);
|
|
15
|
+
if (st.size > maxFileSize) {
|
|
16
|
+
return { status: 'skipped', relativePath: job.relativePath, reason: 'too_large' };
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
catch (err) {
|
|
20
|
+
process.stderr.write(`[pindex] parse-worker: stat failed for ${job.relativePath}: ${String(err)}\n`);
|
|
21
|
+
return { status: 'skipped', relativePath: job.relativePath, reason: 'not_found' };
|
|
22
|
+
}
|
|
23
|
+
let content;
|
|
24
|
+
try {
|
|
25
|
+
content = readFileSync(job.absolutePath, 'utf-8');
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
return { status: 'error', relativePath: job.relativePath, error: String(err) };
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
const parsed = parseFile(job.absolutePath, content);
|
|
32
|
+
const hash = hashContent(content);
|
|
33
|
+
return { status: 'ok', relativePath: job.relativePath, parsed, hash, content };
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
return { status: 'error', relativePath: job.relativePath, error: String(err) };
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=parse-worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-worker.js","sourceRoot":"","sources":["../../src/indexer/parse-worker.ts"],"names":[],"mappings":"AAAA,8BAA8B;AAC9B,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAGrD,IAAI,CAAC,UAAU,EAAE,CAAC;IAChB,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAC;AAC/E,CAAC;AAOD,UAAU,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,GAAkB,EAAE,EAAE;IAC9C,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC;IAChD,UAAW,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;AACtC,CAAC,CAAC,CAAC;AAEH,SAAS,MAAM,CAAC,GAAkB,EAAE,WAAmB;IACrD,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,QAAQ,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QACtC,IAAI,EAAE,CAAC,IAAI,GAAG,WAAW,EAAE,CAAC;YAC1B,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,GAAG,CAAC,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;QACpF,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,0CAA0C,GAAG,CAAC,YAAY,KAAK,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACrG,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,GAAG,CAAC,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;IACpF,CAAC;IAED,IAAI,OAAe,CAAC;IACpB,IAAI,CAAC;QACH,OAAO,GAAG,YAAY,CAAC,GAAG,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IACpD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,CAAC,YAAY,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;IACjF,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QACpD,MAAM,IAAI,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;QAClC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IACjF,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,CAAC,YAAY,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;IACjF,CAAC;AACH,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/indexer/parser.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY,EAAc,cAAc,EAAiB,MAAM,aAAa,CAAC;AAkC9H,uFAAuF;AACvF,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE5D;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGvD;AAID,gEAAgE;AAChE,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGtD;AAID,kEAAkE;AAClE,wBAAgB,cAAc,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAiClE;AAuJD,wDAAwD;AACxD,wBAAgB,cAAc,CAAC,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY,EAAE,CAmClF;AAID,kEAAkE;AAClE,wBAAgB,cAAc,CAAC,QAAQ,EAAE,OAAO,GAAG,YAAY,EAAE,CAsBhE;AA8KD;kDACkD;AAClD,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,UAAU,
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/indexer/parser.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY,EAAc,cAAc,EAAiB,MAAM,aAAa,CAAC;AAkC9H,uFAAuF;AACvF,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE5D;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGvD;AAID,gEAAgE;AAChE,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGtD;AAID,kEAAkE;AAClE,wBAAgB,cAAc,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAiClE;AAuJD,wDAAwD;AACxD,wBAAgB,cAAc,CAAC,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY,EAAE,CAmClF;AAID,kEAAkE;AAClE,wBAAgB,cAAc,CAAC,QAAQ,EAAE,OAAO,GAAG,YAAY,EAAE,CAsBhE;AA8KD;kDACkD;AAClD,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,UAAU,CAkFvE;AAyDD,4DAA4D;AAC5D,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,cAAc,CAkB/E;AAED,qEAAqE;AACrE,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEnD"}
|
package/dist/indexer/parser.js
CHANGED
|
@@ -482,9 +482,15 @@ export function parseFile(filePath, content) {
|
|
|
482
482
|
return { language, symbols, imports, rawTokenEstimate };
|
|
483
483
|
}
|
|
484
484
|
let lang;
|
|
485
|
-
if (language === 'typescript' ||
|
|
485
|
+
if (language === 'typescript' ||
|
|
486
|
+
language === 'tsx' ||
|
|
487
|
+
language === 'javascript' ||
|
|
488
|
+
language === 'jsx') {
|
|
489
|
+
// The tree-sitter-typescript grammar is a TS-superset parser that also
|
|
490
|
+
// handles plain JavaScript and JSX correctly. Using it for JS files
|
|
491
|
+
// gives real AST-based symbol extraction instead of a silent empty result.
|
|
486
492
|
const tsLangs = _require('tree-sitter-typescript');
|
|
487
|
-
lang = language === 'tsx' ? tsLangs.tsx : tsLangs.typescript;
|
|
493
|
+
lang = language === 'tsx' || language === 'jsx' ? tsLangs.tsx : tsLangs.typescript;
|
|
488
494
|
}
|
|
489
495
|
else {
|
|
490
496
|
return { language, symbols: [], imports: [], rawTokenEstimate };
|
|
@@ -495,8 +501,8 @@ export function parseFile(filePath, content) {
|
|
|
495
501
|
const imports = extractImports(tree.rootNode);
|
|
496
502
|
return { language, symbols, imports, rawTokenEstimate };
|
|
497
503
|
}
|
|
498
|
-
catch {
|
|
499
|
-
|
|
504
|
+
catch (err) {
|
|
505
|
+
process.stderr.write(`[pindex] Parse error for ${filePath}: ${err}\n`);
|
|
500
506
|
return { language, symbols: [], imports: [], rawTokenEstimate };
|
|
501
507
|
}
|
|
502
508
|
}
|