| 1405 | // with its file-order sequence so flushOrdered commits results in order. The |
| 1406 | // backpressure below bounds how far parsing runs ahead of the in-order commit. |
| 1407 | const feed = async (filePath: string, content: string, stats: fs.Stats): Promise<void> => { |
| 1408 | const seq = nextSeq++; |
| 1409 | const p = (async () => { |
| 1410 | try { |
| 1411 | const result = await parseFile(filePath, content); |
| 1412 | completed.set(seq, { ok: true, filePath, content, stats, result }); |
| 1413 | } catch (parseErr) { |
| 1414 | completed.set(seq, { ok: false, filePath, err: parseErr }); |
| 1415 | } |
| 1416 | flushOrdered(); |
| 1417 | })(); |
| 1418 | const tracked = p.finally(() => { inFlight.delete(tracked); }); |
| 1419 | inFlight.add(tracked); |
| 1420 | // Backpressure on the dispatched-but-not-yet-committed count (in-flight + |
| 1421 | // buffered), not just in-flight: a slow file sitting at the commit cursor |
| 1422 | // lets later parses finish and buffer, which would otherwise grow without |
| 1423 | // bound. Wait for parses to settle (each may advance the cursor) until the |
| 1424 | // window has room. `inFlight.size > 0` guards against an empty race — the |
| 1425 | // cursor file is always still in flight when the window is full. |
| 1426 | while (nextSeq - nextToStore >= windowSize && inFlight.size > 0) { |
| 1427 | await Promise.race(inFlight); |
| 1428 | } |
| 1429 | }; |
| 1430 | |
| 1431 | for (let i = 0; i < files.length; i += FILE_IO_BATCH_SIZE) { |
| 1432 | if (signal?.aborted) { aborted = true; break; } |