import { basename } from 'node:path'; /** * Argument parsing for the e2e run script (runner.ts). Pure and side-effect * free, so the runner's argv contract is unit-testable without touching * Docker, the run-lock, or anything else main() reaches at import time. */ /** * Flags `e2e-run` understands. `--seed=` is value-carrying and recognized * by prefix, not listed here. */ export const KNOWN_RUN_FLAGS: readonly string[] = [ '--keep', '--reuse', '--live', '--published', '--source-cli', '--verbose', '--ci', '--no-ci', '--complete', // Passed through by `cele2e run` (harmless/no-op there, see cli/index.ts). '--ci-safe', '--notify', '--shuffle', '--no-interactive', ]; export interface ParsedRunArgs { /** Positional suite-name patterns (substring match against test file names). */ patterns: string[]; /** `--`-prefixed arguments the runner does not know. Must be empty before a run starts. */ unknownFlags: string[]; /** True when `--help` was requested. */ helpRequested: boolean; } /** * Split e2e-run argv into patterns and flags. Reports unrecognized `--` args * in `unknownFlags` instead of discarding them: the old filter stripped every * `--`-prefixed argument it did not know, so `cele2e run --help` (and any * typo'd flag) left zero patterns, which is the runner's encoding of "run * everything" — the one command an unsure operator types took the single most * expensive resource in the city. */ export function parseRunArgs(argv: readonly string[]): ParsedRunArgs { const patterns: string[] = []; const unknownFlags: string[] = []; let helpRequested = false; for (const arg of argv) { if (!arg.startsWith('--')) { patterns.push(arg); continue; } if (arg === '--help') { helpRequested = true; } else if (!isKnownFlag(arg)) { unknownFlags.push(arg); } } return { patterns, unknownFlags, helpRequested }; } /** * Filter collected test files by the run's positional patterns. A pattern * that exactly equals a test name selects only that file; otherwise the old * substring semantics apply. Without the exact rule, `cele2e run * aspect-fanout caddy-internal-private` also ran aspect-fanout-new-systems: * the substring OR matched the prefix whenever the top-level dir was in the * collected set. */ export function filterTestFilesByPatterns( files: readonly string[], patterns: readonly string[], ): string[] { if (patterns.length === 0) return [...files]; const exactPatterns = new Set( patterns.filter((p) => files.some((f) => basename(f, '.test.ts') === p)), ); return files.filter((f) => { const name = basename(f, '.test.ts'); return patterns.some((p) => (exactPatterns.has(p) ? name === p : name.includes(p))); }); } function isKnownFlag(arg: string): boolean { return KNOWN_RUN_FLAGS.includes(arg) || arg.startsWith('--seed='); }