()
| 185 | // ── Phase 3: Pack audit ──────────────────────────────────────────── |
| 186 | |
| 187 | function phase3() { |
| 188 | heading('Phase 3: Pack audit'); |
| 189 | |
| 190 | // 10. npm pack --dry-run |
| 191 | const pack = exec('npm pack --dry-run --json 2>/dev/null'); |
| 192 | let fileList: string[] = []; |
| 193 | |
| 194 | if (pack.ok) { |
| 195 | try { |
| 196 | const parsed = JSON.parse(pack.stdout); |
| 197 | const files = (parsed[0]?.files ?? parsed.files ?? []) as Array<{ path: string }>; |
| 198 | fileList = files.map((f) => f.path); |
| 199 | } catch { |
| 200 | // Fallback: parse the non-JSON dry-run output |
| 201 | const lines = pack.stdout.split('\n'); |
| 202 | fileList = lines |
| 203 | .map((l) => l.replace(/^npm notice\s+\d+[\w.]+\s+/, '').trim()) |
| 204 | .filter((l) => l.includes('/') || l.endsWith('.js') || l.endsWith('.json')); |
| 205 | } |
| 206 | } |
| 207 | |
| 208 | check('#10 `npm pack --dry-run` succeeds', pack.ok && fileList.length > 0, |
| 209 | 'npm pack failed or returned empty file list'); |
| 210 | |
| 211 | if (fileList.length === 0) { |
| 212 | fail('#11 No source .ts files in tarball', 'Skipped — no file list'); |
| 213 | fail('#12 No test files in tarball', 'Skipped — no file list'); |
| 214 | fail('#13 No config files in tarball', 'Skipped — no file list'); |
| 215 | fail('#14 No fixtures in tarball', 'Skipped — no file list'); |
| 216 | fail('#15 Entry point in tarball', 'Skipped — no file list'); |
| 217 | return; |
| 218 | } |
| 219 | |
| 220 | // 11. No source .ts files (allow .d.ts and .d.ts.map) |
| 221 | const rawTs = fileList.filter( |
| 222 | (f) => f.endsWith('.ts') && !f.endsWith('.d.ts') && !f.endsWith('.d.ts.map') |
| 223 | ); |
| 224 | check('#11 No source .ts files in tarball', rawTs.length === 0, |
| 225 | `Found: ${rawTs.join(', ')}`); |
| 226 | |
| 227 | // 12. No test files |
| 228 | const testInPack = fileList.filter((f) => f.includes('.test.')); |
| 229 | check('#12 No test files in tarball', testInPack.length === 0, |
| 230 | `Found: ${testInPack.join(', ')}`); |
| 231 | |
| 232 | // 13. No config files |
| 233 | const configInPack = fileList.filter((f) => f.includes('tsconfig')); |
| 234 | check('#13 No config files in tarball', configInPack.length === 0, |
| 235 | `Found: ${configInPack.join(', ')}`); |
| 236 | |
| 237 | // 14. No fixtures |
| 238 | const fixturesInPack = fileList.filter((f) => f.includes('fixtures')); |
| 239 | check('#14 No fixtures in tarball', fixturesInPack.length === 0, |
| 240 | `Found: ${fixturesInPack.join(', ')}`); |
| 241 | |
| 242 | // 15. Entry point present |
| 243 | const hasIndex = fileList.some((f) => f.includes('dist/index.js')); |
| 244 | const hasTypes = fileList.some((f) => f.includes('dist/index.d.ts')); |
no test coverage detected
searching dependent graphs…