mirror of
https://github.com/Egonex-AI/Understand-Anything.git
synced 2026-06-22 10:58:03 +08:00
fix(extract-import-map): preserve deterministic stderr order across concurrent loaders
Addresses the regression flagged by ZebangCheng on #346: under the parallelised `buildResolutionContext`, `loadTsConfigs` / `loadGoModules` / `loadPhpAutoloads` ran concurrently but each wrote warnings to stderr inline as it iterated read results, so a fixture with both a malformed `tsconfig.json` and a malformed `composer.json` could emit `composer, tsconfig` instead of the pre-PR `tsconfig, composer` depending on I/O timing. Each loader now buffers its warnings into a returned array and the caller drains them in canonical order (tsconfig → go → php) after `Promise.all`, restoring byte-identical stderr output. Added a regression test that fixtures both malformed configs and asserts the tsconfig warning precedes the composer warning in stderr. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1492,3 +1492,55 @@ describe('extract-import-map.mjs — tree-sitter init graceful failure', () => {
|
||||
expect(result.output.stats.totalEdges).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('extract-import-map.mjs — deterministic stderr ordering across loaders', () => {
|
||||
let projectRoot;
|
||||
|
||||
afterEach(() => {
|
||||
if (projectRoot) {
|
||||
rmSync(projectRoot, { recursive: true, force: true });
|
||||
projectRoot = null;
|
||||
}
|
||||
});
|
||||
|
||||
// Regression for the parallel-loader stderr-order bug surfaced in
|
||||
// PR #346 review: tsconfig / go.mod / composer.json loaders now run
|
||||
// concurrently, but warnings must still emit in the pre-PR canonical
|
||||
// order (tsconfig → go → php). If the loaders streamed warnings
|
||||
// mid-flight, I/O timing could reorder them — the assertions below
|
||||
// catch that regression.
|
||||
it('emits warnings in canonical order (tsconfig, go, php) regardless of I/O timing', () => {
|
||||
projectRoot = setupTree({
|
||||
'tsconfig.json': '{ "compilerOptions": { "baseUrl": ".", ', // unterminated
|
||||
'composer.json': '{ "autoload": { "psr-4": { "App\\\\": "src/" }, ', // unterminated
|
||||
'src/index.ts': `import { foo } from './foo';\n`,
|
||||
'src/foo.ts': `export const foo = 1;\n`,
|
||||
'src/Http/Controller.php':
|
||||
`<?php\nnamespace App\\Http;\n\nuse App\\Models\\User;\n\nclass Controller { }\n`,
|
||||
'src/Models/User.php':
|
||||
`<?php\nnamespace App\\Models;\nclass User { }\n`,
|
||||
});
|
||||
|
||||
const result = runScript(projectRoot, {
|
||||
projectRoot,
|
||||
files: [
|
||||
{ path: 'tsconfig.json', language: 'json', fileCategory: 'config' },
|
||||
{ path: 'composer.json', language: 'json', fileCategory: 'config' },
|
||||
{ path: 'src/index.ts', language: 'typescript', fileCategory: 'code' },
|
||||
{ path: 'src/foo.ts', language: 'typescript', fileCategory: 'code' },
|
||||
{ path: 'src/Http/Controller.php', language: 'php', fileCategory: 'code' },
|
||||
{ path: 'src/Models/User.php', language: 'php', fileCategory: 'code' },
|
||||
],
|
||||
});
|
||||
|
||||
expect(result.status).toBe(0);
|
||||
const tsLineIdx = result.stderr.indexOf('tsconfig.json at');
|
||||
const composerLineIdx = result.stderr.indexOf('composer.json at');
|
||||
expect(tsLineIdx).toBeGreaterThanOrEqual(0);
|
||||
expect(composerLineIdx).toBeGreaterThanOrEqual(0);
|
||||
// Canonical order: tsconfig warnings precede composer warnings.
|
||||
// Pre-PR-346 this fell out of sequential loader passes; post-fix it
|
||||
// falls out of buffering + ordered drain in buildResolutionContext.
|
||||
expect(tsLineIdx).toBeLessThan(composerLineIdx);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user