fix: guard parentPort.on() in parse-worker for non-worker imports

The webhook integration test imports extractWebhooks directly from
parse-worker.ts. When imported outside a worker thread, parentPort is
null and the top-level parentPort!.on('message', ...) crashes with
"Cannot read properties of null (reading 'on')". Wrap the message
handler registration in an `if (parentPort)` guard.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Test 2026-03-26 07:20:56 +01:00
parent 2fac799c88
commit d8d8562264

View file

@ -2395,61 +2395,67 @@ const mergeResult = (target: ParseWorkerResult, src: ParseWorkerResult) => {
target.fileCount += src.fileCount;
};
parentPort!.on('message', (msg: WorkerIncomingMessage) => {
try {
// Legacy single-message mode (backward compat): array of files
if (Array.isArray(msg)) {
const result = processBatch(msg, (filesProcessed) => {
parentPort!.postMessage({ type: 'progress', filesProcessed });
});
parentPort!.postMessage({ type: 'result', data: result });
return;
}
// Sub-batch mode: { type: 'sub-batch', files: [...] }
if (msg.type === 'sub-batch') {
const result = processBatch(msg.files, (filesProcessed) => {
parentPort!.postMessage({
type: 'progress',
filesProcessed: cumulativeProcessed + filesProcessed,
// Only register message handler when running as a worker thread.
// When imported directly (e.g. tests importing extractWebhooks),
// parentPort is null and this block must be skipped.
if (parentPort) {
parentPort.on('message', (msg: WorkerIncomingMessage) => {
try {
// Legacy single-message mode (backward compat): array of files
if (Array.isArray(msg)) {
const result = processBatch(msg, (filesProcessed) => {
parentPort!.postMessage({ type: 'progress', filesProcessed });
});
});
cumulativeProcessed += result.fileCount;
mergeResult(accumulated, result);
// Signal ready for next sub-batch
parentPort!.postMessage({ type: 'sub-batch-done' });
return;
}
parentPort!.postMessage({ type: 'result', data: result });
return;
}
// Flush: send accumulated results
if (msg.type === 'flush') {
parentPort!.postMessage({ type: 'result', data: accumulated });
// Reset for potential reuse
accumulated = {
nodes: [],
relationships: [],
symbols: [],
imports: [],
calls: [],
assignments: [],
heritage: [],
routes: [],
fetchCalls: [],
decoratorRoutes: [],
toolDefs: [],
ormQueries: [],
webhooks: [],
queuePatterns: [],
constructorBindings: [],
fileScopeBindings: [],
skippedLanguages: {},
fileCount: 0,
};
cumulativeProcessed = 0;
return;
// Sub-batch mode: { type: 'sub-batch', files: [...] }
if (msg.type === 'sub-batch') {
const result = processBatch(msg.files, (filesProcessed) => {
parentPort!.postMessage({
type: 'progress',
filesProcessed: cumulativeProcessed + filesProcessed,
});
});
cumulativeProcessed += result.fileCount;
mergeResult(accumulated, result);
// Signal ready for next sub-batch
parentPort!.postMessage({ type: 'sub-batch-done' });
return;
}
// Flush: send accumulated results
if (msg.type === 'flush') {
parentPort!.postMessage({ type: 'result', data: accumulated });
// Reset for potential reuse
accumulated = {
nodes: [],
relationships: [],
symbols: [],
imports: [],
calls: [],
assignments: [],
heritage: [],
routes: [],
fetchCalls: [],
decoratorRoutes: [],
toolDefs: [],
ormQueries: [],
webhooks: [],
queuePatterns: [],
constructorBindings: [],
fileScopeBindings: [],
typeEnvBindings: [],
skippedLanguages: {},
fileCount: 0,
};
cumulativeProcessed = 0;
return;
}
} catch (err) {
const message = err instanceof Error ? err.message : String(err);
parentPort!.postMessage({ type: 'error', error: message });
}
} catch (err) {
const message = err instanceof Error ? err.message : String(err);
parentPort!.postMessage({ type: 'error', error: message });
}
});
});
}