Skip to content

Commit acda474

Browse files
committed
test(cli): prove the shape pin's program with --listFiles before reading its silence
A clean tsc run and a tsc run that compiled nothing both print nothing and both exit 0, so "no diagnostics" is only evidence once the program is known to hold the fixture and the packed `.d.ts`. The run now asks for `--listFiles` and asserts the population before the silence over it is read: the fixture, the ratified entry and the internal module it re-exports are all present, and no file from this workspace is. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D47qPfEWVPmhguWgBZCi5N
1 parent 502b2f1 commit acda474

1 file changed

Lines changed: 43 additions & 5 deletions

File tree

packages/cli/test/published-subpath-hook-body.pin.test.ts

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,8 @@ let scratch: string;
441441
let packedFiles: string[];
442442
let installedRoot: string;
443443
let probe: ProbeResult;
444-
let conformance: { status: number; output: string };
444+
let typecheckDir: string;
445+
let conformance: { status: number; diagnostics: string; programFiles: string[] };
445446

446447
beforeAll(() => {
447448
const rootEntry = MANIFEST.exports['.'];
@@ -503,7 +504,7 @@ beforeAll(() => {
503504
// fixture as ESM (this package IS ESM-only, and a CJS-classified fixture
504505
// would red with TS1479 — a fact about the fixture's own manifest, not about
505506
// the ratified surface). Nothing of the probe's environment changes.
506-
const typecheckDir = join(consumer, 'typecheck');
507+
typecheckDir = join(consumer, 'typecheck');
507508
mkdirSync(typecheckDir);
508509
writeFileSync(
509510
join(typecheckDir, 'package.json'),
@@ -515,13 +516,27 @@ beforeAll(() => {
515516
// the version question is not what this file pins), but it is spawned with
516517
// the consumer directory as cwd, so what it RESOLVES it resolves from there.
517518
const tscEntry = createRequire(import.meta.url).resolve('typescript/lib/tsc.js');
518-
const tsc = spawnSync(process.execPath, [tscEntry, '--pretty', 'false', '-p', 'tsconfig.json'], {
519+
// `--listFiles` is not decoration: a clean tsc run and a tsc run that
520+
// compiled NOTHING both print nothing and both exit 0, so "no diagnostics"
521+
// is only evidence once the program is known to contain the fixture AND the
522+
// packed `.d.ts` it is supposed to be judging. The file list is what
523+
// separates those two, and it is asserted below rather than assumed here.
524+
const tsc = spawnSync(process.execPath, [tscEntry, '--pretty', 'false', '--listFiles', '-p', 'tsconfig.json'], {
519525
cwd: typecheckDir,
520526
encoding: 'utf8',
521527
env: childEnv(),
522528
});
523529
if (tsc.error) throw new Error(`tsc could not start: ${tsc.error.message}`);
524-
conformance = { status: tsc.status ?? -1, output: `${tsc.stdout ?? ''}${tsc.stderr ?? ''}`.trim() };
530+
// tsc interleaves the file list with the diagnostics on stdout. A listed
531+
// file is a path that EXISTS; a diagnostic is `path(l,c): error TSxxxx: …`,
532+
// which never does — so the split is by disk, not by a regex over prose.
533+
const lines = `${tsc.stdout ?? ''}${tsc.stderr ?? ''}`.split('\n').map((l) => l.trim()).filter((l) => l !== '');
534+
const listed = new Set(lines.filter((l) => existsSync(l)));
535+
conformance = {
536+
status: tsc.status ?? -1,
537+
diagnostics: lines.filter((l) => !listed.has(l)).join('\n'),
538+
programFiles: [...listed].map((p) => realpathSync(p)),
539+
};
525540
}, 120_000);
526541

527542
afterAll(() => {
@@ -594,9 +609,32 @@ describe('the ratified surface is exactly four names', () => {
594609
});
595610

596611
describe('the ratified surface still has the SHAPES a consumer compiles against (#15630)', () => {
612+
// ⛔ This assertion comes FIRST on purpose. Zero diagnostics is the verdict
613+
// the next test reads, and zero diagnostics is also what a program that
614+
// compiled nothing prints — so the population has to be established before
615+
// the silence over it means anything.
616+
it('put the fixture AND the packed .d.ts in the program — not the workspace source, not nothing', () => {
617+
const real = (p: string): string => realpathSync(p);
618+
expect(conformance.programFiles, 'the fixture itself was never compiled').toContain(
619+
real(join(typecheckDir, 'conformance.ts')),
620+
);
621+
expect(
622+
conformance.programFiles,
623+
'the ratified entry was not reached — a `types` condition that stops resolving lands here',
624+
).toContain(real(join(installedRoot, 'dist', 'hook-body.d.ts')));
625+
expect(
626+
conformance.programFiles,
627+
'the shapes were read from somewhere other than the PACKED tarball',
628+
).toContain(real(join(installedRoot, 'dist', 'utils', 'extract-hook-body.d.ts')));
629+
// Nothing of this workspace may be in that program: a source-tree file
630+
// would make every shape below a verdict about the checkout instead of
631+
// about what ships.
632+
expect(conformance.programFiles.filter((p) => p.startsWith(`${realpathSync(PACKAGE_ROOT)}/`))).toEqual([]);
633+
});
634+
597635
it('compiles a real consumer against the PACKED .d.ts, reached through the exports map', () => {
598636
expect(
599-
conformance.output,
637+
conformance.diagnostics,
600638
'tsc reported diagnostics compiling the conformance fixture against the packed .d.ts. Either the ratified ' +
601639
'shape moved — in which case this is a BREAKING change to a published surface and the fixture is updated ' +
602640
'deliberately, with a changeset — or a CONTROL stopped firing (TS2578), which says the same thing from the ' +

0 commit comments

Comments
 (0)