Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@
},
"scripts": {
"clean": "node -e \"const fs=require('fs'); fs.rmSync('dist',{recursive:true,force:true});\"",
"build": "npm run clean && npx tsc",
"build:watch": "tsc --watch",
"build": "npm run clean && npx tsc -p tsconfig.build.json",
"build:watch": "tsc -p tsconfig.build.json --watch",
"dev": "tsx watch src/index.ts",
"start": "node dist/index.js",
"smoke": "npm run build && node dist/index.js --help",
Expand Down
50 changes: 50 additions & 0 deletions src/__tests__/build-excludes-test-code.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { execFileSync } from 'node:child_process';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { describe, expect, it } from 'vitest';

/**
* Guards against test-only source leaking into the published build (#217).
*
* The stale `tsconfig.json` exclude pointed at a path that no longer matched
* `test-helpers.ts`, so it (and the `.compile-test.ts` brand guards) shipped
* into `dist/`. `tsconfig.build.json` now excludes test code by pattern; this
* test asks tsc which files that config would compile and fails if any test
* module is still in the program.
*/

const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..');
const tscEntry = path.join(repoRoot, 'node_modules', 'typescript', 'bin', 'tsc');

function buildProgramSrcFiles(): string[] {
const out = execFileSync(
process.execPath,
[tscEntry, '-p', 'tsconfig.build.json', '--listFilesOnly'],
{ cwd: repoRoot, encoding: 'utf8', maxBuffer: 32 * 1024 * 1024 }
);
return out
.split('\n')
.map((line) => line.trim())
.filter(Boolean)
.map((abs) => path.relative(repoRoot, abs).split(path.sep).join('/'))
.filter((rel) => rel.startsWith('src/'));
}

// Mirrors tsconfig.build.json's exclude — add any new test-only suffix to both.
const TEST_CODE = [
/\.test\.ts$/,
/\.compile-test\.ts$/,
/(^|\/)test-helpers\.ts$/,
/(^|\/)__tests__\//,
];
Comment thread
timon0305 marked this conversation as resolved.

describe('build output excludes test code (#217)', () => {
it('the build tsconfig compiles no test-only modules from src', () => {
const files = buildProgramSrcFiles();
// Guard against a vacuous pass: if the build config ever compiled nothing,
// `leaked` would be empty while the real build is broken.
expect(files).toContain('src/index.ts');
const leaked = files.filter((f) => TEST_CODE.some((re) => re.test(f)));
expect(leaked).toEqual([]);
}, 60_000);
});
13 changes: 13 additions & 0 deletions tsconfig.build.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"extends": "./tsconfig.json",
// New test-only suffixes must also go in TEST_CODE in
// src/__tests__/build-excludes-test-code.test.ts, which guards this list.
"exclude": [
"node_modules",
"dist",
"**/*.test.ts",
"**/*.compile-test.ts",
"**/test-helpers.ts",
"**/__tests__/**"
]
}
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,5 @@
"typeRoots": ["./node_modules/@types"]
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "**/*.test.ts", "src/server/tools/test-helpers.ts"]
"exclude": ["node_modules", "dist", "**/*.test.ts"]
}
Loading