@rpcbase/test 0.402.0 → 0.404.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"report.js","names":["fs","path","fileURLToPath","libCoverage","libInstrument","fg","picomatch","v8ToIstanbul","createCollectCoverageMatcher","toPosix","generateConsoleTextCoverageReport","findCoverageFiles","CoverageConfig","CoverageThresholdTarget","CoverageThresholds","TEXT_REPORT_FILENAME","CoverageThresholdError","Error","constructor","message","name","generateCoverageReport","config","Promise","coverageFiles","length","console","warn","coverageLib","resolveCoverageLib","coverageMap","createCoverageMap","matchesCollectCoverageFrom","collectCoverageFrom","rootDir","file","payload","readCoverageFile","script","scripts","mergeScriptCoverage","includeAllFiles","includeUntestedFiles","files","rm","coverageReportDir","recursive","force","mkdir","createContext","reports","loadIstanbulModules","context","dir","defaultSummarizer","output","reportOutput","summarizer","process","stdout","write","create","execute","log","join","summary","getCoverageSummary","enforceThresholds","thresholds","targets","Array","isArray","thresholdTargets","fileSummaries","buildFileSummaries","target","matcher","createGlobMatcher","pattern","matchResult","collectTargetSummary","matched","collectCoveredFiles","sort","opts","maybeForceColor","libReportMod","reportsMod","all","default","isTTY","env","FORCE_COLOR","undefined","NO_COLOR","NODE_DISABLE_COLORS","CI","absolutePath","scriptPath","isNodeModulesPath","isViteVirtualModulePath","source","readFile","error","base","basename","code","includes","sourceMap","loadSourceMapForScript","converter","sourcemap","load","applyCoverage","functions","filtered","filterCoverageMap","toIstanbul","Object","keys","merge","raw","JSON","parse","label","failures","metric","minimum","actual","pct","push","details","map","toFixed","candidate","resolveInstrumentLib","createInstrumenter","existing","Set","filePath","resolve","String","candidates","findCollectCoverageFiles","instrumentLib","instrumenter","esModules","parserPlugins","normalized","has","catch","instrumentSync","fileCoverage","lastFileCoverage","addFileCoverage","add","relative","startsWith","DEFAULT_COLLECT_COVERAGE_IGNORES","patterns","rawFiles","cwd","absolute","dot","onlyFiles","unique","followSymbolicLinks","ignore","collected","endsWith","from","normalizedRoot","normalizedAbsolute","fileCoverageFor","toSummary","relativePath","relativePosix","createCoverageSummary","some","trim","isAbsoluteGlobPattern","test","stripQuery","url","queryIndex","indexOf","hashIndex","endIndex","Math","min","Number","POSITIVE_INFINITY","isFinite","slice","extractSourceMappingUrl","regex","last","match","exec","resolveSourceMapPath","mappingUrl","cleaned","isAbsolute","dirname","Record","entries","resolveCoveragePath","normalize","split","sep","baseName","parseSourceMapPayload","sources","normalizeSourceMap","root","sourceRoot","replace","fixedSources","withoutWebpack","normalizedCandidate","commaIndex","meta","Buffer","toString","decodeURIComponent","parsed","mapPath"],"sources":["../../src/coverage/report.ts"],"sourcesContent":["import fs from \"node:fs/promises\"\nimport path from \"node:path\"\nimport { fileURLToPath } from \"node:url\"\n\nimport * as libCoverage from \"istanbul-lib-coverage\"\nimport * as libInstrument from \"istanbul-lib-instrument\"\nimport fg from \"fast-glob\"\nimport picomatch from \"picomatch\"\nimport v8ToIstanbul from \"v8-to-istanbul\"\n\nimport { createCollectCoverageMatcher, toPosix } from \"./collect\"\nimport { generateConsoleTextCoverageReport } from \"./console-text-report\"\nimport { findCoverageFiles } from \"./files\"\nimport type { CoverageConfig, CoverageThresholdTarget, CoverageThresholds } from \"./types\"\n\n\nconst TEXT_REPORT_FILENAME = \"coverage.txt\"\n\nexport class CoverageThresholdError extends Error {\n constructor(message: string) {\n super(message)\n this.name = \"CoverageThresholdError\"\n }\n}\n\nexport async function generateCoverageReport(config: CoverageConfig): Promise<void> {\n const coverageFiles = await findCoverageFiles(config)\n\n if (coverageFiles.length === 0) {\n console.warn(\"[coverage] no V8 coverage artifacts were generated\")\n return\n }\n\n const coverageLib = resolveCoverageLib()\n const coverageMap = coverageLib.createCoverageMap({})\n const matchesCollectCoverageFrom = createCollectCoverageMatcher(config.collectCoverageFrom, config.rootDir)\n\n for (const file of coverageFiles) {\n const payload = await readCoverageFile(file)\n if (!payload) {\n continue\n }\n\n for (const script of payload.scripts as any[]) {\n await mergeScriptCoverage(coverageMap, script, config, matchesCollectCoverageFrom)\n }\n }\n\n if (config.includeAllFiles) {\n await includeUntestedFiles(coverageMap, config, matchesCollectCoverageFrom)\n }\n\n if (coverageMap.files().length === 0) {\n console.warn(\"[coverage] no library files matched the coverage filters\")\n return\n }\n\n await fs.rm(config.coverageReportDir, { recursive: true, force: true })\n await fs.mkdir(config.coverageReportDir, { recursive: true })\n\n const { createContext, reports } = await loadIstanbulModules()\n const context = createContext({\n dir: config.coverageReportDir,\n coverageMap,\n defaultSummarizer: \"pkg\",\n })\n\n const { output: reportOutput, summarizer } = generateConsoleTextCoverageReport(reports, context)\n process.stdout.write(reportOutput)\n reports.create(\"text\", { file: TEXT_REPORT_FILENAME, summarizer }).execute(context)\n\n console.log(`[coverage] Full text report saved to ${path.join(config.coverageReportDir, TEXT_REPORT_FILENAME)}`)\n\n const summary = coverageMap.getCoverageSummary()\n enforceThresholds(summary, config.thresholds, \"global\")\n\n const targets: CoverageThresholdTarget[] = Array.isArray(config.thresholdTargets) ? config.thresholdTargets : []\n if (targets.length > 0) {\n const fileSummaries = buildFileSummaries(coverageMap, config.rootDir)\n for (const target of targets) {\n const matcher = createGlobMatcher(target.pattern)\n const matchResult = collectTargetSummary(fileSummaries, matcher, coverageLib)\n\n if (matchResult.matched === 0) {\n console.warn(\n `[coverage] threshold pattern \"${target.pattern}\" did not match any files — skipping`,\n )\n continue\n }\n\n enforceThresholds(matchResult.summary, target.thresholds, target.pattern)\n }\n }\n}\n\nexport async function collectCoveredFiles(config: CoverageConfig): Promise<string[]> {\n const coverageFiles = await findCoverageFiles(config)\n if (coverageFiles.length === 0) {\n return []\n }\n\n const coverageLib = resolveCoverageLib()\n const coverageMap = coverageLib.createCoverageMap({})\n const matchesCollectCoverageFrom = createCollectCoverageMatcher(config.collectCoverageFrom, config.rootDir)\n\n for (const file of coverageFiles) {\n const payload = await readCoverageFile(file)\n if (!payload) {\n continue\n }\n\n for (const script of payload.scripts as any[]) {\n await mergeScriptCoverage(coverageMap, script, config, matchesCollectCoverageFrom)\n }\n }\n\n return coverageMap.files().sort()\n}\n\nasync function loadIstanbulModules(): Promise<{ createContext: (opts: any) => any; reports: any }> {\n maybeForceColor()\n const [libReportMod, reportsMod]: any[] = await Promise.all([\n import(\"istanbul-lib-report\"),\n import(\"istanbul-reports\"),\n ])\n\n const createContext = typeof libReportMod.createContext === \"function\"\n ? libReportMod.createContext\n : libReportMod.default?.createContext\n\n if (typeof createContext !== \"function\") {\n throw new Error(\"istanbul-lib-report exports are unavailable\")\n }\n\n return {\n createContext,\n reports: reportsMod.default ?? reportsMod,\n }\n}\n\nfunction maybeForceColor(): void {\n if (process.stdout.isTTY) {\n return\n }\n\n if (process.env.FORCE_COLOR !== undefined) {\n return\n }\n\n if (process.env.NO_COLOR !== undefined || process.env.NODE_DISABLE_COLORS !== undefined) {\n return\n }\n\n if (process.env.CI !== undefined) {\n return\n }\n\n process.env.FORCE_COLOR = \"1\"\n}\n\nasync function mergeScriptCoverage(\n coverageMap: any,\n script: any,\n config: CoverageConfig,\n matchesCollectCoverageFrom: (absolutePath: string) => boolean,\n): Promise<void> {\n const scriptPath = script.absolutePath\n if (!scriptPath) {\n return\n }\n\n if (isNodeModulesPath(scriptPath)) {\n return\n }\n\n if (isViteVirtualModulePath(scriptPath)) {\n return\n }\n\n let source = script.source && script.source.length > 0\n ? script.source\n : \"\"\n\n if (!source) {\n try {\n source = await fs.readFile(scriptPath, \"utf8\")\n } catch (error: any) {\n const base = path.basename(scriptPath)\n if (error?.code === \"ENOENT\" && base && !base.includes(\".\")) {\n return\n }\n if (error?.code === \"ENOENT\" && !matchesCollectCoverageFrom(scriptPath)) {\n return\n }\n throw error\n }\n }\n\n const sourceMap = await loadSourceMapForScript(scriptPath, source)\n const converter = v8ToIstanbul(\n scriptPath,\n 0,\n sourceMap ? { source, sourceMap: { sourcemap: sourceMap } } : { source },\n )\n await converter.load()\n converter.applyCoverage(script.functions)\n\n const filtered = filterCoverageMap(converter.toIstanbul(), config, matchesCollectCoverageFrom)\n if (Object.keys(filtered).length > 0) {\n coverageMap.merge(filtered)\n }\n}\n\nasync function readCoverageFile(file: string): Promise<any | null> {\n try {\n const raw = await fs.readFile(file, \"utf8\")\n return JSON.parse(raw)\n } catch (error) {\n console.warn(`[coverage] failed to parse ${file}:`, error)\n return null\n }\n}\n\nfunction enforceThresholds(summary: any, thresholds: CoverageThresholds, label = \"global\"): void {\n const failures = []\n\n for (const metric of Object.keys(thresholds) as Array<keyof CoverageThresholds>) {\n const minimum = thresholds[metric]\n const actual = summary[metric]?.pct ?? 0\n if (actual < minimum) {\n failures.push({ metric, actual, minimum })\n }\n }\n\n if (failures.length === 0) {\n return\n }\n\n const details = failures\n .map(({ metric, actual, minimum }) => `${metric}: ${actual.toFixed(2)}% < ${minimum}%`)\n .join(\"; \")\n\n throw new CoverageThresholdError(`[coverage] thresholds not met (target: ${label}) — ${details}`)\n}\n\nfunction resolveCoverageLib(): any {\n const candidate: any = libCoverage as any\n if (typeof candidate.createCoverageMap === \"function\") {\n return candidate\n }\n\n if (candidate.default && typeof candidate.default.createCoverageMap === \"function\") {\n return candidate.default\n }\n\n throw new Error(\"istanbul-lib-coverage exports are unavailable\")\n}\n\nfunction resolveInstrumentLib(): any {\n const candidate: any = libInstrument as any\n if (typeof candidate.createInstrumenter === \"function\") {\n return candidate\n }\n\n if (candidate.default && typeof candidate.default.createInstrumenter === \"function\") {\n return candidate.default\n }\n\n throw new Error(\"istanbul-lib-instrument exports are unavailable\")\n}\n\nasync function includeUntestedFiles(\n coverageMap: any,\n config: CoverageConfig,\n matchesCollectCoverageFrom: (absolutePath: string) => boolean,\n): Promise<void> {\n const existing = new Set(\n coverageMap.files().map((filePath: unknown) => path.resolve(String(filePath ?? \"\"))),\n )\n\n const candidates = await findCollectCoverageFiles(config, matchesCollectCoverageFrom)\n if (candidates.length === 0) {\n return\n }\n\n const instrumentLib = resolveInstrumentLib()\n const instrumenter = instrumentLib.createInstrumenter({\n esModules: true,\n parserPlugins: [\n \"typescript\",\n \"jsx\",\n \"classProperties\",\n \"classPrivateProperties\",\n \"classPrivateMethods\",\n \"decorators-legacy\",\n \"importMeta\",\n \"topLevelAwait\",\n ],\n })\n\n for (const filePath of candidates) {\n const normalized = path.resolve(filePath)\n if (existing.has(normalized)) {\n continue\n }\n\n const source = await fs.readFile(normalized, \"utf8\").catch(() => null)\n if (source === null) {\n continue\n }\n\n try {\n instrumenter.instrumentSync(source, normalized)\n const fileCoverage = instrumenter.lastFileCoverage()\n if (!fileCoverage) {\n continue\n }\n coverageMap.addFileCoverage(fileCoverage)\n existing.add(normalized)\n } catch (error) {\n const relative = path.relative(config.rootDir, normalized)\n console.warn(\n `[coverage] failed to instrument ${relative && !relative.startsWith(\"..\") ? relative : normalized}:`,\n error,\n )\n }\n }\n}\n\nconst DEFAULT_COLLECT_COVERAGE_IGNORES = [\n \"**/.git/**\",\n \"**/.next/**\",\n \"**/.turbo/**\",\n \"**/.vite/**\",\n \"**/.vitest/**\",\n \"**/build/**\",\n \"**/coverage/**\",\n \"**/dist/**\",\n \"**/node_modules/**\",\n \"**/playwright-report/**\",\n \"**/spec/**\",\n \"**/test/**\",\n \"**/test-results/**\",\n \"**/tests/**\",\n \"**/__tests__/**\",\n \"**/*.d.ts\",\n \"**/*.map\",\n]\n\nasync function findCollectCoverageFiles(\n config: CoverageConfig,\n matchesCollectCoverageFrom: (absolutePath: string) => boolean,\n): Promise<string[]> {\n const patterns = Array.isArray(config.collectCoverageFrom)\n ? config.collectCoverageFrom\n : []\n\n if (patterns.length === 0) {\n return []\n }\n\n const rawFiles = await fg(patterns, {\n cwd: config.rootDir,\n absolute: true,\n dot: true,\n onlyFiles: true,\n unique: true,\n followSymbolicLinks: false,\n ignore: DEFAULT_COLLECT_COVERAGE_IGNORES,\n }).catch(() => [])\n\n const collected = new Set<string>()\n\n for (const file of rawFiles) {\n const normalized = path.resolve(String(file ?? \"\"))\n if (!normalized) {\n continue\n }\n\n if (normalized.endsWith(\".d.ts\") || normalized.endsWith(\".map\")) {\n continue\n }\n\n if (isNodeModulesPath(normalized)) {\n continue\n }\n\n if (isViteVirtualModulePath(normalized)) {\n continue\n }\n\n if (!matchesCollectCoverageFrom(normalized)) {\n continue\n }\n\n collected.add(normalized)\n }\n\n return Array.from(collected).sort()\n}\n\nfunction buildFileSummaries(\n coverageMap: any,\n rootDir: string,\n): Array<{ summary: any; candidates: string[] }> {\n const normalizedRoot = path.resolve(rootDir)\n return coverageMap.files().map((filePath: string) => {\n const normalizedAbsolute = path.resolve(filePath)\n const summary = coverageMap.fileCoverageFor(filePath).toSummary()\n const relativePath = path.relative(normalizedRoot, normalizedAbsolute)\n const candidates = new Set<string>()\n\n if (relativePath) {\n const relativePosix = toPosix(relativePath)\n candidates.add(relativePosix)\n candidates.add(`./${relativePosix}`)\n } else {\n candidates.add(toPosix(path.basename(normalizedAbsolute)))\n }\n\n return {\n summary,\n candidates: Array.from(candidates),\n }\n })\n}\n\nfunction collectTargetSummary(\n fileSummaries: Array<{ summary: any; candidates: string[] }>,\n matcher: (candidate: string) => boolean,\n coverageLib: any,\n): { summary: any; matched: number } {\n const summary = coverageLib.createCoverageSummary()\n let matched = 0\n\n for (const file of fileSummaries) {\n if (file.candidates.some((candidate) => matcher(candidate))) {\n summary.merge(file.summary)\n matched += 1\n }\n }\n\n return { summary, matched }\n}\n\nfunction createGlobMatcher(pattern: string): (candidate: string) => boolean {\n const normalized = toPosix(String(pattern ?? \"\")).trim()\n if (!normalized) {\n return () => false\n }\n if (isAbsoluteGlobPattern(normalized)) {\n throw new Error(`[coverage] threshold patterns must be relative (absolute paths are not supported): \"${pattern}\"`)\n }\n return picomatch(normalized, { dot: true })\n}\n\nfunction isAbsoluteGlobPattern(pattern: string): boolean {\n const normalized = String(pattern ?? \"\").trim()\n if (!normalized) {\n return false\n }\n\n if (normalized.startsWith(\"/\")) {\n return true\n }\n\n if (normalized.startsWith(\"file://\")) {\n return true\n }\n\n return /^[A-Za-z]:\\//.test(normalized)\n}\n\nfunction stripQuery(url: string): string {\n const queryIndex = url.indexOf(\"?\")\n const hashIndex = url.indexOf(\"#\")\n\n const endIndex = Math.min(\n queryIndex === -1 ? Number.POSITIVE_INFINITY : queryIndex,\n hashIndex === -1 ? Number.POSITIVE_INFINITY : hashIndex,\n )\n\n if (!Number.isFinite(endIndex)) {\n return url\n }\n\n return url.slice(0, endIndex)\n}\n\nfunction extractSourceMappingUrl(source: string): string | null {\n const regex = /\\/\\/[#@]\\s*sourceMappingURL=([^\\s]+)/g\n\n let last = null\n let match = null\n\n while ((match = regex.exec(source)) !== null) {\n last = match[1]\n }\n\n return typeof last === \"string\" && last.length > 0 ? last : null\n}\n\nfunction resolveSourceMapPath(scriptPath: string, mappingUrl: string): string {\n const cleaned = stripQuery(mappingUrl)\n\n if (cleaned.startsWith(\"file://\")) {\n return fileURLToPath(cleaned)\n }\n\n if (path.isAbsolute(cleaned)) {\n return cleaned\n }\n\n return path.resolve(path.dirname(scriptPath), cleaned)\n}\n\nfunction filterCoverageMap(\n map: any,\n config: CoverageConfig,\n matchesCollectCoverageFrom: (absolutePath: string) => boolean,\n): Record<string, any> {\n if (!map || typeof map !== \"object\") {\n return {}\n }\n\n const filtered: Record<string, any> = {}\n\n for (const [filePath, fileCoverage] of Object.entries(map)) {\n const absolutePath = resolveCoveragePath(filePath, config.rootDir)\n if (!absolutePath) {\n continue\n }\n\n if (absolutePath.endsWith(\".d.ts\") || absolutePath.endsWith(\".map\")) {\n continue\n }\n\n if (isNodeModulesPath(absolutePath)) {\n continue\n }\n\n if (isViteVirtualModulePath(absolutePath)) {\n continue\n }\n\n if (!matchesCollectCoverageFrom(absolutePath)) {\n continue\n }\n\n if (fileCoverage && typeof fileCoverage === \"object\") {\n filtered[absolutePath] = { ...fileCoverage, path: absolutePath }\n } else {\n filtered[absolutePath] = fileCoverage\n }\n }\n\n return filtered\n}\n\nfunction resolveCoveragePath(filePath: string, rootDir: string): string | null {\n const raw = String(filePath ?? \"\").trim()\n if (!raw) {\n return null\n }\n\n const cleaned = stripQuery(raw)\n\n if (cleaned.startsWith(\"file://\")) {\n try {\n return path.normalize(fileURLToPath(cleaned))\n } catch {\n return null\n }\n }\n\n if (path.isAbsolute(cleaned)) {\n return path.normalize(cleaned)\n }\n\n if (cleaned.includes(\"://\")) {\n return null\n }\n\n return path.normalize(path.resolve(rootDir, cleaned))\n}\n\nfunction isNodeModulesPath(filePath: string): boolean {\n return path\n .normalize(String(filePath ?? \"\"))\n .split(path.sep)\n .includes(\"node_modules\")\n}\n\nfunction isViteVirtualModulePath(filePath: string): boolean {\n const normalized = path.normalize(String(filePath ?? \"\"))\n const baseName = path.basename(normalized)\n return baseName === \"__vite-browser-external\"\n || baseName.startsWith(\"__vite-browser-external:\")\n || baseName.startsWith(\"__vite-\")\n}\n\nfunction parseSourceMapPayload(raw: any): any | null {\n if (!raw || typeof raw !== \"object\") {\n return null\n }\n\n const sources = raw.sources\n if (!Array.isArray(sources) || sources.length === 0) {\n return null\n }\n\n return raw\n}\n\nfunction normalizeSourceMap(sourceMap: any, scriptPath: string): any {\n const root = typeof sourceMap.sourceRoot === \"string\"\n ? sourceMap.sourceRoot.replace(\"file://\", \"\")\n : \"\"\n\n const dir = path.dirname(scriptPath)\n const fixedSources = sourceMap.sources.map((source: unknown) => {\n const raw = String(source ?? \"\")\n const cleaned = stripQuery(raw)\n\n if (cleaned.startsWith(\"file://\")) {\n try {\n return path.normalize(fileURLToPath(cleaned))\n } catch {\n return cleaned\n }\n }\n\n const withoutWebpack = cleaned.replace(/^webpack:\\/\\//, \"\")\n const candidate = path.join(root, withoutWebpack)\n\n if (path.isAbsolute(candidate)) {\n return path.normalize(candidate)\n }\n\n const normalizedCandidate = candidate.split(\"/\").join(path.sep)\n\n if (dir.endsWith(`${path.sep}dist`) && !normalizedCandidate.startsWith(`..${path.sep}`)) {\n if (normalizedCandidate.startsWith(`src${path.sep}`) || normalizedCandidate.startsWith(`lib${path.sep}`)) {\n return path.normalize(path.resolve(dir, \"..\", normalizedCandidate))\n }\n }\n\n return path.normalize(path.resolve(dir, normalizedCandidate))\n })\n\n return {\n ...sourceMap,\n sources: fixedSources,\n }\n}\n\nasync function loadSourceMapForScript(scriptPath: string, source: string): Promise<any | null> {\n const mappingUrl = extractSourceMappingUrl(source)\n if (!mappingUrl) {\n return null\n }\n\n const cleaned = stripQuery(mappingUrl)\n\n if (cleaned.startsWith(\"data:\")) {\n const commaIndex = cleaned.indexOf(\",\")\n if (commaIndex === -1) {\n return null\n }\n\n const meta = cleaned.slice(0, commaIndex)\n const payload = cleaned.slice(commaIndex + 1)\n const raw = meta.includes(\";base64\")\n ? Buffer.from(payload, \"base64\").toString(\"utf8\")\n : decodeURIComponent(payload)\n\n try {\n const parsed = parseSourceMapPayload(JSON.parse(raw))\n return parsed ? normalizeSourceMap(parsed, scriptPath) : null\n } catch {\n return null\n }\n }\n\n try {\n const mapPath = resolveSourceMapPath(scriptPath, cleaned)\n const raw = await fs.readFile(mapPath, \"utf8\")\n const parsed = parseSourceMapPayload(JSON.parse(raw))\n return parsed ? normalizeSourceMap(parsed, scriptPath) : null\n } catch {\n return null\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"report.js","names":[],"sources":["../../src/coverage/report.ts"],"sourcesContent":["import fs from \"node:fs/promises\"\nimport path from \"node:path\"\nimport { fileURLToPath } from \"node:url\"\n\nimport * as libCoverage from \"istanbul-lib-coverage\"\nimport * as libInstrument from \"istanbul-lib-instrument\"\nimport fg from \"fast-glob\"\nimport picomatch from \"picomatch\"\nimport v8ToIstanbul from \"v8-to-istanbul\"\n\nimport { createCollectCoverageMatcher, toPosix } from \"./collect\"\nimport { generateConsoleTextCoverageReport } from \"./console-text-report\"\nimport { findCoverageFiles } from \"./files\"\nimport type { CoverageConfig, CoverageThresholdTarget, CoverageThresholds } from \"./types\"\n\n\nconst TEXT_REPORT_FILENAME = \"coverage.txt\"\n\nexport class CoverageThresholdError extends Error {\n constructor(message: string) {\n super(message)\n this.name = \"CoverageThresholdError\"\n }\n}\n\nexport async function generateCoverageReport(config: CoverageConfig): Promise<void> {\n const coverageFiles = await findCoverageFiles(config)\n\n if (coverageFiles.length === 0) {\n console.warn(\"[coverage] no V8 coverage artifacts were generated\")\n return\n }\n\n const coverageLib = resolveCoverageLib()\n const coverageMap = coverageLib.createCoverageMap({})\n const matchesCollectCoverageFrom = createCollectCoverageMatcher(config.collectCoverageFrom, config.rootDir)\n\n for (const file of coverageFiles) {\n const payload = await readCoverageFile(file)\n if (!payload) {\n continue\n }\n\n for (const script of payload.scripts as any[]) {\n await mergeScriptCoverage(coverageMap, script, config, matchesCollectCoverageFrom)\n }\n }\n\n if (config.includeAllFiles) {\n await includeUntestedFiles(coverageMap, config, matchesCollectCoverageFrom)\n }\n\n if (coverageMap.files().length === 0) {\n console.warn(\"[coverage] no library files matched the coverage filters\")\n return\n }\n\n await fs.rm(config.coverageReportDir, { recursive: true, force: true })\n await fs.mkdir(config.coverageReportDir, { recursive: true })\n\n const { createContext, reports } = await loadIstanbulModules()\n const context = createContext({\n dir: config.coverageReportDir,\n coverageMap,\n defaultSummarizer: \"pkg\",\n })\n\n const { output: reportOutput, summarizer } = generateConsoleTextCoverageReport(reports, context)\n process.stdout.write(reportOutput)\n reports.create(\"text\", { file: TEXT_REPORT_FILENAME, summarizer }).execute(context)\n\n console.log(`[coverage] Full text report saved to ${path.join(config.coverageReportDir, TEXT_REPORT_FILENAME)}`)\n\n const summary = coverageMap.getCoverageSummary()\n enforceThresholds(summary, config.thresholds, \"global\")\n\n const targets: CoverageThresholdTarget[] = Array.isArray(config.thresholdTargets) ? config.thresholdTargets : []\n if (targets.length > 0) {\n const fileSummaries = buildFileSummaries(coverageMap, config.rootDir)\n for (const target of targets) {\n const matcher = createGlobMatcher(target.pattern)\n const matchResult = collectTargetSummary(fileSummaries, matcher, coverageLib)\n\n if (matchResult.matched === 0) {\n console.warn(\n `[coverage] threshold pattern \"${target.pattern}\" did not match any files — skipping`,\n )\n continue\n }\n\n enforceThresholds(matchResult.summary, target.thresholds, target.pattern)\n }\n }\n}\n\nexport async function collectCoveredFiles(config: CoverageConfig): Promise<string[]> {\n const coverageFiles = await findCoverageFiles(config)\n if (coverageFiles.length === 0) {\n return []\n }\n\n const coverageLib = resolveCoverageLib()\n const coverageMap = coverageLib.createCoverageMap({})\n const matchesCollectCoverageFrom = createCollectCoverageMatcher(config.collectCoverageFrom, config.rootDir)\n\n for (const file of coverageFiles) {\n const payload = await readCoverageFile(file)\n if (!payload) {\n continue\n }\n\n for (const script of payload.scripts as any[]) {\n await mergeScriptCoverage(coverageMap, script, config, matchesCollectCoverageFrom)\n }\n }\n\n return coverageMap.files().sort()\n}\n\nasync function loadIstanbulModules(): Promise<{ createContext: (opts: any) => any; reports: any }> {\n maybeForceColor()\n const [libReportMod, reportsMod]: any[] = await Promise.all([\n import(\"istanbul-lib-report\"),\n import(\"istanbul-reports\"),\n ])\n\n const createContext = typeof libReportMod.createContext === \"function\"\n ? libReportMod.createContext\n : libReportMod.default?.createContext\n\n if (typeof createContext !== \"function\") {\n throw new Error(\"istanbul-lib-report exports are unavailable\")\n }\n\n return {\n createContext,\n reports: reportsMod.default ?? reportsMod,\n }\n}\n\nfunction maybeForceColor(): void {\n if (process.stdout.isTTY) {\n return\n }\n\n if (process.env.FORCE_COLOR !== undefined) {\n return\n }\n\n if (process.env.NO_COLOR !== undefined || process.env.NODE_DISABLE_COLORS !== undefined) {\n return\n }\n\n if (process.env.CI !== undefined) {\n return\n }\n\n process.env.FORCE_COLOR = \"1\"\n}\n\nasync function mergeScriptCoverage(\n coverageMap: any,\n script: any,\n config: CoverageConfig,\n matchesCollectCoverageFrom: (absolutePath: string) => boolean,\n): Promise<void> {\n const scriptPath = script.absolutePath\n if (!scriptPath) {\n return\n }\n\n if (isNodeModulesPath(scriptPath)) {\n return\n }\n\n if (isViteVirtualModulePath(scriptPath)) {\n return\n }\n\n let source = script.source && script.source.length > 0\n ? script.source\n : \"\"\n\n if (!source) {\n try {\n source = await fs.readFile(scriptPath, \"utf8\")\n } catch (error: any) {\n const base = path.basename(scriptPath)\n if (error?.code === \"ENOENT\" && base && !base.includes(\".\")) {\n return\n }\n if (error?.code === \"ENOENT\" && !matchesCollectCoverageFrom(scriptPath)) {\n return\n }\n throw error\n }\n }\n\n const sourceMap = await loadSourceMapForScript(scriptPath, source)\n const converter = v8ToIstanbul(\n scriptPath,\n 0,\n sourceMap ? { source, sourceMap: { sourcemap: sourceMap } } : { source },\n )\n await converter.load()\n converter.applyCoverage(script.functions)\n\n const filtered = filterCoverageMap(converter.toIstanbul(), config, matchesCollectCoverageFrom)\n if (Object.keys(filtered).length > 0) {\n coverageMap.merge(filtered)\n }\n}\n\nasync function readCoverageFile(file: string): Promise<any | null> {\n try {\n const raw = await fs.readFile(file, \"utf8\")\n return JSON.parse(raw)\n } catch (error) {\n console.warn(`[coverage] failed to parse ${file}:`, error)\n return null\n }\n}\n\nfunction enforceThresholds(summary: any, thresholds: CoverageThresholds, label = \"global\"): void {\n const failures = []\n\n for (const metric of Object.keys(thresholds) as Array<keyof CoverageThresholds>) {\n const minimum = thresholds[metric]\n const actual = summary[metric]?.pct ?? 0\n if (actual < minimum) {\n failures.push({ metric, actual, minimum })\n }\n }\n\n if (failures.length === 0) {\n return\n }\n\n const details = failures\n .map(({ metric, actual, minimum }) => `${metric}: ${actual.toFixed(2)}% < ${minimum}%`)\n .join(\"; \")\n\n throw new CoverageThresholdError(`[coverage] thresholds not met (target: ${label}) — ${details}`)\n}\n\nfunction resolveCoverageLib(): any {\n const candidate: any = libCoverage as any\n if (typeof candidate.createCoverageMap === \"function\") {\n return candidate\n }\n\n if (candidate.default && typeof candidate.default.createCoverageMap === \"function\") {\n return candidate.default\n }\n\n throw new Error(\"istanbul-lib-coverage exports are unavailable\")\n}\n\nfunction resolveInstrumentLib(): any {\n const candidate: any = libInstrument as any\n if (typeof candidate.createInstrumenter === \"function\") {\n return candidate\n }\n\n if (candidate.default && typeof candidate.default.createInstrumenter === \"function\") {\n return candidate.default\n }\n\n throw new Error(\"istanbul-lib-instrument exports are unavailable\")\n}\n\nasync function includeUntestedFiles(\n coverageMap: any,\n config: CoverageConfig,\n matchesCollectCoverageFrom: (absolutePath: string) => boolean,\n): Promise<void> {\n const existing = new Set(\n coverageMap.files().map((filePath: unknown) => path.resolve(String(filePath ?? \"\"))),\n )\n\n const candidates = await findCollectCoverageFiles(config, matchesCollectCoverageFrom)\n if (candidates.length === 0) {\n return\n }\n\n const instrumentLib = resolveInstrumentLib()\n const instrumenter = instrumentLib.createInstrumenter({\n esModules: true,\n parserPlugins: [\n \"typescript\",\n \"jsx\",\n \"classProperties\",\n \"classPrivateProperties\",\n \"classPrivateMethods\",\n \"decorators-legacy\",\n \"importMeta\",\n \"topLevelAwait\",\n ],\n })\n\n for (const filePath of candidates) {\n const normalized = path.resolve(filePath)\n if (existing.has(normalized)) {\n continue\n }\n\n const source = await fs.readFile(normalized, \"utf8\").catch(() => null)\n if (source === null) {\n continue\n }\n\n try {\n instrumenter.instrumentSync(source, normalized)\n const fileCoverage = instrumenter.lastFileCoverage()\n if (!fileCoverage) {\n continue\n }\n coverageMap.addFileCoverage(fileCoverage)\n existing.add(normalized)\n } catch (error) {\n const relative = path.relative(config.rootDir, normalized)\n console.warn(\n `[coverage] failed to instrument ${relative && !relative.startsWith(\"..\") ? relative : normalized}:`,\n error,\n )\n }\n }\n}\n\nconst DEFAULT_COLLECT_COVERAGE_IGNORES = [\n \"**/.git/**\",\n \"**/.next/**\",\n \"**/.turbo/**\",\n \"**/.vite/**\",\n \"**/.vitest/**\",\n \"**/build/**\",\n \"**/coverage/**\",\n \"**/dist/**\",\n \"**/node_modules/**\",\n \"**/playwright-report/**\",\n \"**/spec/**\",\n \"**/test/**\",\n \"**/test-results/**\",\n \"**/tests/**\",\n \"**/__tests__/**\",\n \"**/*.d.ts\",\n \"**/*.map\",\n]\n\nasync function findCollectCoverageFiles(\n config: CoverageConfig,\n matchesCollectCoverageFrom: (absolutePath: string) => boolean,\n): Promise<string[]> {\n const patterns = Array.isArray(config.collectCoverageFrom)\n ? config.collectCoverageFrom\n : []\n\n if (patterns.length === 0) {\n return []\n }\n\n const rawFiles = await fg(patterns, {\n cwd: config.rootDir,\n absolute: true,\n dot: true,\n onlyFiles: true,\n unique: true,\n followSymbolicLinks: false,\n ignore: DEFAULT_COLLECT_COVERAGE_IGNORES,\n }).catch(() => [])\n\n const collected = new Set<string>()\n\n for (const file of rawFiles) {\n const normalized = path.resolve(String(file ?? \"\"))\n if (!normalized) {\n continue\n }\n\n if (normalized.endsWith(\".d.ts\") || normalized.endsWith(\".map\")) {\n continue\n }\n\n if (isNodeModulesPath(normalized)) {\n continue\n }\n\n if (isViteVirtualModulePath(normalized)) {\n continue\n }\n\n if (!matchesCollectCoverageFrom(normalized)) {\n continue\n }\n\n collected.add(normalized)\n }\n\n return Array.from(collected).sort()\n}\n\nfunction buildFileSummaries(\n coverageMap: any,\n rootDir: string,\n): Array<{ summary: any; candidates: string[] }> {\n const normalizedRoot = path.resolve(rootDir)\n return coverageMap.files().map((filePath: string) => {\n const normalizedAbsolute = path.resolve(filePath)\n const summary = coverageMap.fileCoverageFor(filePath).toSummary()\n const relativePath = path.relative(normalizedRoot, normalizedAbsolute)\n const candidates = new Set<string>()\n\n if (relativePath) {\n const relativePosix = toPosix(relativePath)\n candidates.add(relativePosix)\n candidates.add(`./${relativePosix}`)\n } else {\n candidates.add(toPosix(path.basename(normalizedAbsolute)))\n }\n\n return {\n summary,\n candidates: Array.from(candidates),\n }\n })\n}\n\nfunction collectTargetSummary(\n fileSummaries: Array<{ summary: any; candidates: string[] }>,\n matcher: (candidate: string) => boolean,\n coverageLib: any,\n): { summary: any; matched: number } {\n const summary = coverageLib.createCoverageSummary()\n let matched = 0\n\n for (const file of fileSummaries) {\n if (file.candidates.some((candidate) => matcher(candidate))) {\n summary.merge(file.summary)\n matched += 1\n }\n }\n\n return { summary, matched }\n}\n\nfunction createGlobMatcher(pattern: string): (candidate: string) => boolean {\n const normalized = toPosix(String(pattern ?? \"\")).trim()\n if (!normalized) {\n return () => false\n }\n if (isAbsoluteGlobPattern(normalized)) {\n throw new Error(`[coverage] threshold patterns must be relative (absolute paths are not supported): \"${pattern}\"`)\n }\n return picomatch(normalized, { dot: true })\n}\n\nfunction isAbsoluteGlobPattern(pattern: string): boolean {\n const normalized = String(pattern ?? \"\").trim()\n if (!normalized) {\n return false\n }\n\n if (normalized.startsWith(\"/\")) {\n return true\n }\n\n if (normalized.startsWith(\"file://\")) {\n return true\n }\n\n return /^[A-Za-z]:\\//.test(normalized)\n}\n\nfunction stripQuery(url: string): string {\n const queryIndex = url.indexOf(\"?\")\n const hashIndex = url.indexOf(\"#\")\n\n const endIndex = Math.min(\n queryIndex === -1 ? Number.POSITIVE_INFINITY : queryIndex,\n hashIndex === -1 ? Number.POSITIVE_INFINITY : hashIndex,\n )\n\n if (!Number.isFinite(endIndex)) {\n return url\n }\n\n return url.slice(0, endIndex)\n}\n\nfunction extractSourceMappingUrl(source: string): string | null {\n const regex = /\\/\\/[#@]\\s*sourceMappingURL=([^\\s]+)/g\n\n let last = null\n let match = null\n\n while ((match = regex.exec(source)) !== null) {\n last = match[1]\n }\n\n return typeof last === \"string\" && last.length > 0 ? last : null\n}\n\nfunction resolveSourceMapPath(scriptPath: string, mappingUrl: string): string {\n const cleaned = stripQuery(mappingUrl)\n\n if (cleaned.startsWith(\"file://\")) {\n return fileURLToPath(cleaned)\n }\n\n if (path.isAbsolute(cleaned)) {\n return cleaned\n }\n\n return path.resolve(path.dirname(scriptPath), cleaned)\n}\n\nfunction filterCoverageMap(\n map: any,\n config: CoverageConfig,\n matchesCollectCoverageFrom: (absolutePath: string) => boolean,\n): Record<string, any> {\n if (!map || typeof map !== \"object\") {\n return {}\n }\n\n const filtered: Record<string, any> = {}\n\n for (const [filePath, fileCoverage] of Object.entries(map)) {\n const absolutePath = resolveCoveragePath(filePath, config.rootDir)\n if (!absolutePath) {\n continue\n }\n\n if (absolutePath.endsWith(\".d.ts\") || absolutePath.endsWith(\".map\")) {\n continue\n }\n\n if (isNodeModulesPath(absolutePath)) {\n continue\n }\n\n if (isViteVirtualModulePath(absolutePath)) {\n continue\n }\n\n if (!matchesCollectCoverageFrom(absolutePath)) {\n continue\n }\n\n if (fileCoverage && typeof fileCoverage === \"object\") {\n filtered[absolutePath] = { ...fileCoverage, path: absolutePath }\n } else {\n filtered[absolutePath] = fileCoverage\n }\n }\n\n return filtered\n}\n\nfunction resolveCoveragePath(filePath: string, rootDir: string): string | null {\n const raw = String(filePath ?? \"\").trim()\n if (!raw) {\n return null\n }\n\n const cleaned = stripQuery(raw)\n\n if (cleaned.startsWith(\"file://\")) {\n try {\n return path.normalize(fileURLToPath(cleaned))\n } catch {\n return null\n }\n }\n\n if (path.isAbsolute(cleaned)) {\n return path.normalize(cleaned)\n }\n\n if (cleaned.includes(\"://\")) {\n return null\n }\n\n return path.normalize(path.resolve(rootDir, cleaned))\n}\n\nfunction isNodeModulesPath(filePath: string): boolean {\n return path\n .normalize(String(filePath ?? \"\"))\n .split(path.sep)\n .includes(\"node_modules\")\n}\n\nfunction isViteVirtualModulePath(filePath: string): boolean {\n const normalized = path.normalize(String(filePath ?? \"\"))\n const baseName = path.basename(normalized)\n return baseName === \"__vite-browser-external\"\n || baseName.startsWith(\"__vite-browser-external:\")\n || baseName.startsWith(\"__vite-\")\n}\n\nfunction parseSourceMapPayload(raw: any): any | null {\n if (!raw || typeof raw !== \"object\") {\n return null\n }\n\n const sources = raw.sources\n if (!Array.isArray(sources) || sources.length === 0) {\n return null\n }\n\n return raw\n}\n\nfunction normalizeSourceMap(sourceMap: any, scriptPath: string): any {\n const root = typeof sourceMap.sourceRoot === \"string\"\n ? sourceMap.sourceRoot.replace(\"file://\", \"\")\n : \"\"\n\n const dir = path.dirname(scriptPath)\n const fixedSources = sourceMap.sources.map((source: unknown) => {\n const raw = String(source ?? \"\")\n const cleaned = stripQuery(raw)\n\n if (cleaned.startsWith(\"file://\")) {\n try {\n return path.normalize(fileURLToPath(cleaned))\n } catch {\n return cleaned\n }\n }\n\n const withoutWebpack = cleaned.replace(/^webpack:\\/\\//, \"\")\n const candidate = path.join(root, withoutWebpack)\n\n if (path.isAbsolute(candidate)) {\n return path.normalize(candidate)\n }\n\n const normalizedCandidate = candidate.split(\"/\").join(path.sep)\n\n if (dir.endsWith(`${path.sep}dist`) && !normalizedCandidate.startsWith(`..${path.sep}`)) {\n if (normalizedCandidate.startsWith(`src${path.sep}`) || normalizedCandidate.startsWith(`lib${path.sep}`)) {\n return path.normalize(path.resolve(dir, \"..\", normalizedCandidate))\n }\n }\n\n return path.normalize(path.resolve(dir, normalizedCandidate))\n })\n\n return {\n ...sourceMap,\n sources: fixedSources,\n }\n}\n\nasync function loadSourceMapForScript(scriptPath: string, source: string): Promise<any | null> {\n const mappingUrl = extractSourceMappingUrl(source)\n if (!mappingUrl) {\n return null\n }\n\n const cleaned = stripQuery(mappingUrl)\n\n if (cleaned.startsWith(\"data:\")) {\n const commaIndex = cleaned.indexOf(\",\")\n if (commaIndex === -1) {\n return null\n }\n\n const meta = cleaned.slice(0, commaIndex)\n const payload = cleaned.slice(commaIndex + 1)\n const raw = meta.includes(\";base64\")\n ? Buffer.from(payload, \"base64\").toString(\"utf8\")\n : decodeURIComponent(payload)\n\n try {\n const parsed = parseSourceMapPayload(JSON.parse(raw))\n return parsed ? normalizeSourceMap(parsed, scriptPath) : null\n } catch {\n return null\n }\n }\n\n try {\n const mapPath = resolveSourceMapPath(scriptPath, cleaned)\n const raw = await fs.readFile(mapPath, \"utf8\")\n const parsed = parseSourceMapPayload(JSON.parse(raw))\n return parsed ? normalizeSourceMap(parsed, scriptPath) : null\n } catch {\n return null\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"reporter.js","names":["fs","FullResult","CoverageThresholdError","generateCoverageReport","removeCoverageFiles","CoverageConfig","FullResultWithExitCode","exitCode","CoverageReporter","config","constructor","options","coverageConfig","Error","onBegin","process","env","RB_TEST_COMBINED_COVERAGE","coverageEnabled","rm","coverageReportDir","recursive","force","onEnd","result","status","console","warn","error","message","setFailureExitCode","mutable"],"sources":["../../src/coverage/reporter.ts"],"sourcesContent":["import fs from \"node:fs/promises\"\n\nimport type { FullResult } from \"@playwright/test/reporter\"\n\nimport { CoverageThresholdError, generateCoverageReport } from \"./report\"\nimport { removeCoverageFiles } from \"./files\"\nimport type { CoverageConfig } from \"./types\"\n\n\ntype FullResultWithExitCode = FullResult & { exitCode?: number }\n\nclass CoverageReporter {\n config: CoverageConfig\n\n constructor(options: { coverageConfig?: CoverageConfig } = {}) {\n this.config = options.coverageConfig as CoverageConfig\n if (!this.config) {\n throw new Error(\"CoverageReporter requires a coverageConfig option\")\n }\n }\n\n async onBegin() {\n if (process.env.RB_TEST_COMBINED_COVERAGE === \"1\") {\n return\n }\n\n if (!this.config.coverageEnabled) {\n return\n }\n\n await removeCoverageFiles(this.config)\n await fs.rm(this.config.coverageReportDir, { recursive: true, force: true })\n }\n\n async onEnd(result: FullResultWithExitCode) {\n if (process.env.RB_TEST_COMBINED_COVERAGE === \"1\") {\n return\n }\n\n if (!this.config.coverageEnabled) {\n return\n }\n\n if (result.status !== \"passed\") {\n console.warn(\"[coverage] skipping report generation because tests failed\")\n return\n }\n\n try {\n await generateCoverageReport(this.config)\n } catch (error) {\n if (error instanceof CoverageThresholdError) {\n console.error(error.message)\n setFailureExitCode(result)\n return\n }\n\n throw error\n }\n }\n}\n\nexport { CoverageReporter }\nexport default CoverageReporter\n\nfunction setFailureExitCode(result: FullResult): void {\n if (result && typeof result === \"object\") {\n const mutable = result as FullResultWithExitCode\n mutable.status = \"failed\"\n if (typeof mutable.exitCode !== \"number\" || mutable.exitCode === 0) {\n mutable.exitCode = 1\n }\n }\n\n if (!process.exitCode || process.exitCode === 0) {\n process.exitCode = 1\n }\n}\n"],"mappings":";;;;AAWA,IAAMQ,mBAAN,MAAuB;CACrBC;CAEAC,YAAYC,UAA+C,CAAC,GAAG;EAC7D,KAAKF,SAASE,QAAQC;EACtB,IAAI,CAAC,KAAKH,QACR,MAAM,IAAII,MAAM,mDAAmD;CAEvE;CAEA,MAAMC,UAAU;EACd,IAAIC,QAAQC,IAAIC,8BAA8B,KAC5C;EAGF,IAAI,CAAC,KAAKR,OAAOS,iBACf;EAGF,MAAMd,oBAAoB,KAAKK,MAAM;EACrC,MAAMT,GAAGmB,GAAG,KAAKV,OAAOW,mBAAmB;GAAEC,WAAW;GAAMC,OAAO;EAAK,CAAC;CAC7E;CAEA,MAAMC,MAAMC,QAAgC;EAC1C,IAAIT,QAAQC,IAAIC,8BAA8B,KAC5C;EAGF,IAAI,CAAC,KAAKR,OAAOS,iBACf;EAGF,IAAIM,OAAOC,WAAW,UAAU;GAC9BC,QAAQC,KAAK,4DAA4D;GACzE;EACF;EAEA,IAAI;GACF,MAAMxB,uBAAuB,KAAKM,MAAM;EAC1C,SAASmB,OAAO;GACd,IAAIA,iBAAiB1B,wBAAwB;IAC3CwB,QAAQE,MAAMA,MAAMC,OAAO;IAC3BC,mBAAmBN,MAAM;IACzB;GACF;GAEA,MAAMI;EACR;CACF;AACF;AAKA,SAASE,mBAAmBN,QAA0B;CACpD,IAAIA,UAAU,OAAOA,WAAW,UAAU;EACxC,MAAMO,UAAUP;EAChBO,QAAQN,SAAS;EACjB,IAAI,OAAOM,QAAQxB,aAAa,YAAYwB,QAAQxB,aAAa,GAC/DwB,QAAQxB,WAAW;CAEvB;CAEA,IAAI,CAACQ,QAAQR,YAAYQ,QAAQR,aAAa,GAC5CQ,QAAQR,WAAW;AAEvB"}
1
+ {"version":3,"file":"reporter.js","names":[],"sources":["../../src/coverage/reporter.ts"],"sourcesContent":["import fs from \"node:fs/promises\"\n\nimport type { FullResult } from \"@playwright/test/reporter\"\n\nimport { CoverageThresholdError, generateCoverageReport } from \"./report\"\nimport { removeCoverageFiles } from \"./files\"\nimport type { CoverageConfig } from \"./types\"\n\n\ntype FullResultWithExitCode = FullResult & { exitCode?: number }\n\nclass CoverageReporter {\n config: CoverageConfig\n\n constructor(options: { coverageConfig?: CoverageConfig } = {}) {\n this.config = options.coverageConfig as CoverageConfig\n if (!this.config) {\n throw new Error(\"CoverageReporter requires a coverageConfig option\")\n }\n }\n\n async onBegin() {\n if (process.env.RB_TEST_COMBINED_COVERAGE === \"1\") {\n return\n }\n\n if (!this.config.coverageEnabled) {\n return\n }\n\n await removeCoverageFiles(this.config)\n await fs.rm(this.config.coverageReportDir, { recursive: true, force: true })\n }\n\n async onEnd(result: FullResultWithExitCode) {\n if (process.env.RB_TEST_COMBINED_COVERAGE === \"1\") {\n return\n }\n\n if (!this.config.coverageEnabled) {\n return\n }\n\n if (result.status !== \"passed\") {\n console.warn(\"[coverage] skipping report generation because tests failed\")\n return\n }\n\n try {\n await generateCoverageReport(this.config)\n } catch (error) {\n if (error instanceof CoverageThresholdError) {\n console.error(error.message)\n setFailureExitCode(result)\n return\n }\n\n throw error\n }\n }\n}\n\nexport { CoverageReporter }\nexport default CoverageReporter\n\nfunction setFailureExitCode(result: FullResult): void {\n if (result && typeof result === \"object\") {\n const mutable = result as FullResultWithExitCode\n mutable.status = \"failed\"\n if (typeof mutable.exitCode !== \"number\" || mutable.exitCode === 0) {\n mutable.exitCode = 1\n }\n }\n\n if (!process.exitCode || process.exitCode === 0) {\n process.exitCode = 1\n }\n}\n"],"mappings":";;;;AAWA,IAAM,mBAAN,MAAuB;CACrB;CAEA,YAAY,UAA+C,CAAC,GAAG;EAC7D,KAAK,SAAS,QAAQ;EACtB,IAAI,CAAC,KAAK,QACR,MAAM,IAAI,MAAM,mDAAmD;CAEvE;CAEA,MAAM,UAAU;EACd,IAAI,QAAQ,IAAI,8BAA8B,KAC5C;EAGF,IAAI,CAAC,KAAK,OAAO,iBACf;EAGF,MAAM,oBAAoB,KAAK,MAAM;EACrC,MAAM,GAAG,GAAG,KAAK,OAAO,mBAAmB;GAAE,WAAW;GAAM,OAAO;EAAK,CAAC;CAC7E;CAEA,MAAM,MAAM,QAAgC;EAC1C,IAAI,QAAQ,IAAI,8BAA8B,KAC5C;EAGF,IAAI,CAAC,KAAK,OAAO,iBACf;EAGF,IAAI,OAAO,WAAW,UAAU;GAC9B,QAAQ,KAAK,4DAA4D;GACzE;EACF;EAEA,IAAI;GACF,MAAM,uBAAuB,KAAK,MAAM;EAC1C,SAAS,OAAO;GACd,IAAI,iBAAiB,wBAAwB;IAC3C,QAAQ,MAAM,MAAM,OAAO;IAC3B,mBAAmB,MAAM;IACzB;GACF;GAEA,MAAM;EACR;CACF;AACF;AAKA,SAAS,mBAAmB,QAA0B;CACpD,IAAI,UAAU,OAAO,WAAW,UAAU;EACxC,MAAM,UAAU;EAChB,QAAQ,SAAS;EACjB,IAAI,OAAO,QAAQ,aAAa,YAAY,QAAQ,aAAa,GAC/D,QAAQ,WAAW;CAEvB;CAEA,IAAI,CAAC,QAAQ,YAAY,QAAQ,aAAa,GAC5C,QAAQ,WAAW;AAEvB"}
@@ -1 +1 @@
1
- {"version":3,"file":"v8-tracker.js","names":["fs","path","Page","TestInfo","isInsideAnyRoot","resolveCollectCoverageRoots","CoverageConfig","VITE_FS_PREFIX","sanitizePathSegment","input","value","String","trim","replace","urlPathLooksLikeFile","pathname","base","posix","basename","length","includes","createCoverageTracker","page","config","Promise","stop","testInfo","session","context","newCDPSession","scriptMeta","Map","normalized","absolutePath","relativePath","url","sourceCache","scriptRoots","collectCoverageFrom","rootDir","send","on","event","normalizeScriptUrl","trackable","isNodeModulesPath","set","scriptId","callCount","detailed","payload","collectCoveragePayload","scripts","outputFile","resolveCoverageOutputFile","mkdir","dirname","recursive","writeFile","JSON","stringify","shutdownSession","projectName","project","name","testId","outputDir","join","coverageFileName","result","script","meta","get","source","resolveScriptSource","push","functions","titlePath","cache","cached","promise","fetchScriptSource","sourceResponse","scriptSource","error","message","allSettled","catch","undefined","detach","rawUrl","startsWith","cleaned","stripQuery","parsed","URL","decoded","decodeURIComponent","fsPath","slice","normalizedFsPath","test","normalize","resolve","process","cwd","createNormalizedPath","normalizedAbsolute","relative","queryIndex","indexOf","hashIndex","endIndex","Math","min","Number","POSITIVE_INFINITY","isFinite","filePath","split","sep"],"sources":["../../src/coverage/v8-tracker.ts"],"sourcesContent":["import fs from \"node:fs/promises\"\nimport path from \"node:path\"\n\nimport type { Page, TestInfo } from \"@playwright/test\"\n\nimport { isInsideAnyRoot, resolveCollectCoverageRoots } from \"./collect\"\nimport type { CoverageConfig } from \"./types\"\n\n\nconst VITE_FS_PREFIX = \"/@fs/\"\n\nfunction sanitizePathSegment(input: unknown): string {\n const value = String(input ?? \"\").trim()\n return value.replace(/[^a-zA-Z0-9._-]+/g, \"_\") || \"unknown\"\n}\n\nfunction urlPathLooksLikeFile(pathname: unknown): boolean {\n const base = path.posix.basename(String(pathname ?? \"\"))\n return base.length > 0 && base.includes(\".\")\n}\n\nexport async function createCoverageTracker(\n page: Page,\n config: CoverageConfig,\n): Promise<{ stop: (testInfo: TestInfo) => Promise<void> }> {\n const session = await page.context().newCDPSession(page)\n const scriptMeta = new Map<string, { normalized: { absolutePath: string; relativePath: string } | null; url: string }>()\n const sourceCache = new Map<string, Promise<string>>()\n const scriptRoots = resolveCollectCoverageRoots(config.collectCoverageFrom, config.rootDir)\n\n await session.send(\"Debugger.enable\")\n session.on(\"Debugger.scriptParsed\", (event: any) => {\n if (!event.url) {\n return\n }\n\n const normalized = normalizeScriptUrl(event.url, config)\n const trackable = normalized\n && !isNodeModulesPath(normalized.absolutePath)\n && isInsideAnyRoot(normalized.absolutePath, scriptRoots)\n\n scriptMeta.set(event.scriptId, {\n normalized: trackable ? normalized : null,\n url: event.url,\n })\n })\n\n await session.send(\"Profiler.enable\")\n await session.send(\"Profiler.startPreciseCoverage\", { callCount: false, detailed: true })\n\n return {\n async stop(testInfo: TestInfo) {\n try {\n const payload = await collectCoveragePayload(session, scriptMeta, sourceCache, testInfo, config)\n\n if (payload.scripts.length === 0) {\n return\n }\n\n const outputFile = resolveCoverageOutputFile(config, testInfo)\n await fs.mkdir(path.dirname(outputFile), { recursive: true })\n await fs.writeFile(outputFile, JSON.stringify(payload, null, 2), \"utf8\")\n } finally {\n await shutdownSession(session)\n }\n },\n }\n}\n\nfunction resolveCoverageOutputFile(config: CoverageConfig, testInfo: TestInfo): string {\n const projectName = sanitizePathSegment(testInfo.project?.name)\n const testId = sanitizePathSegment(testInfo.testId)\n const outputDir = path.join(config.rootDir, \"build\", \"playwright\", \"coverage\", projectName, testId)\n return path.join(outputDir, config.coverageFileName)\n}\n\nasync function collectCoveragePayload(\n session: any,\n scriptMeta: Map<string, { normalized: { absolutePath: string; relativePath: string } | null; url: string }>,\n sourceCache: Map<string, Promise<string>>,\n testInfo: TestInfo,\n config: CoverageConfig,\n): Promise<{ testId: string; scripts: any[] }> {\n const { result } = await session.send(\"Profiler.takePreciseCoverage\")\n await session.send(\"Profiler.stopPreciseCoverage\")\n\n const scripts = []\n\n for (const script of result) {\n const meta = scriptMeta.get(script.scriptId)\n if (!meta || !meta.normalized) {\n continue\n }\n\n const source = await resolveScriptSource(session, sourceCache, script.scriptId)\n scripts.push({\n absolutePath: meta.normalized.absolutePath,\n relativePath: meta.normalized.relativePath,\n source,\n functions: script.functions,\n url: meta.url,\n })\n }\n\n return {\n testId: testInfo.titlePath.join(\" › \"),\n scripts,\n }\n}\n\nasync function resolveScriptSource(session: any, cache: Map<string, Promise<string>>, scriptId: string): Promise<string> {\n const cached = cache.get(scriptId)\n if (cached) {\n return cached\n }\n\n const promise = fetchScriptSource(session, scriptId)\n cache.set(scriptId, promise)\n return promise\n}\n\nasync function fetchScriptSource(session: any, scriptId: string): Promise<string> {\n try {\n const sourceResponse = await session.send(\"Debugger.getScriptSource\", { scriptId })\n return sourceResponse?.scriptSource ?? \"\"\n } catch (error: any) {\n const message = String(error?.message ?? error)\n if (message.includes(\"Debugger agent is not enabled\")) {\n try {\n await session.send(\"Debugger.enable\")\n const sourceResponse = await session.send(\"Debugger.getScriptSource\", { scriptId })\n return sourceResponse?.scriptSource ?? \"\"\n } catch {\n return \"\"\n }\n }\n\n return \"\"\n }\n}\n\nasync function shutdownSession(session: any): Promise<void> {\n await Promise.allSettled([\n session.send(\"Profiler.stopPreciseCoverage\").catch(() => undefined),\n session.send(\"Profiler.disable\").catch(() => undefined),\n session.send(\"Debugger.disable\").catch(() => undefined),\n ])\n await session.detach().catch(() => undefined)\n}\n\nfunction normalizeScriptUrl(rawUrl: string, config: CoverageConfig): { absolutePath: string; relativePath: string } | null {\n if (!rawUrl || rawUrl.startsWith(\"node:\")) {\n return null\n }\n\n const cleaned = stripQuery(rawUrl)\n let pathname = cleaned\n\n try {\n const parsed = new URL(cleaned)\n pathname = parsed.pathname\n } catch {\n // keep as-is for relative paths\n }\n\n if (!pathname) {\n return null\n }\n\n let absolutePath\n\n const decoded = decodeURIComponent(pathname)\n if (decoded.startsWith(VITE_FS_PREFIX)) {\n const fsPath = decoded.slice(VITE_FS_PREFIX.length)\n const normalizedFsPath = fsPath.startsWith(\"/\") || /^[A-Za-z]:\\//.test(fsPath)\n ? fsPath\n : `/${fsPath}`\n absolutePath = path.normalize(normalizedFsPath)\n } else if (decoded.startsWith(\"/\")) {\n if (!urlPathLooksLikeFile(decoded)) {\n return null\n }\n absolutePath = path.resolve(process.cwd(), `.${decoded}`)\n } else {\n return null\n }\n\n return createNormalizedPath(absolutePath, config.rootDir)\n}\n\nfunction createNormalizedPath(absolutePath: string, rootDir: string): { absolutePath: string; relativePath: string } {\n const normalizedAbsolute = path.normalize(absolutePath)\n const relativePath = path.relative(rootDir, normalizedAbsolute)\n return {\n absolutePath: normalizedAbsolute,\n relativePath,\n }\n}\n\nfunction stripQuery(url: string): string {\n const queryIndex = url.indexOf(\"?\")\n const hashIndex = url.indexOf(\"#\")\n\n const endIndex = Math.min(\n queryIndex === -1 ? Number.POSITIVE_INFINITY : queryIndex,\n hashIndex === -1 ? Number.POSITIVE_INFINITY : hashIndex,\n )\n\n if (!Number.isFinite(endIndex)) {\n return url\n }\n\n return url.slice(0, endIndex)\n}\n\nfunction isNodeModulesPath(filePath: string): boolean {\n return path\n .normalize(String(filePath ?? \"\"))\n .split(path.sep)\n .includes(\"node_modules\")\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"v8-tracker.js","names":[],"sources":["../../src/coverage/v8-tracker.ts"],"sourcesContent":["import fs from \"node:fs/promises\"\nimport path from \"node:path\"\n\nimport type { Page, TestInfo } from \"@playwright/test\"\n\nimport { isInsideAnyRoot, resolveCollectCoverageRoots } from \"./collect\"\nimport type { CoverageConfig } from \"./types\"\n\n\nconst VITE_FS_PREFIX = \"/@fs/\"\n\nfunction sanitizePathSegment(input: unknown): string {\n const value = String(input ?? \"\").trim()\n return value.replace(/[^a-zA-Z0-9._-]+/g, \"_\") || \"unknown\"\n}\n\nfunction urlPathLooksLikeFile(pathname: unknown): boolean {\n const base = path.posix.basename(String(pathname ?? \"\"))\n return base.length > 0 && base.includes(\".\")\n}\n\nexport async function createCoverageTracker(\n page: Page,\n config: CoverageConfig,\n): Promise<{ stop: (testInfo: TestInfo) => Promise<void> }> {\n const session = await page.context().newCDPSession(page)\n const scriptMeta = new Map<string, { normalized: { absolutePath: string; relativePath: string } | null; url: string }>()\n const sourceCache = new Map<string, Promise<string>>()\n const scriptRoots = resolveCollectCoverageRoots(config.collectCoverageFrom, config.rootDir)\n\n await session.send(\"Debugger.enable\")\n session.on(\"Debugger.scriptParsed\", (event: any) => {\n if (!event.url) {\n return\n }\n\n const normalized = normalizeScriptUrl(event.url, config)\n const trackable = normalized\n && !isNodeModulesPath(normalized.absolutePath)\n && isInsideAnyRoot(normalized.absolutePath, scriptRoots)\n\n scriptMeta.set(event.scriptId, {\n normalized: trackable ? normalized : null,\n url: event.url,\n })\n })\n\n await session.send(\"Profiler.enable\")\n await session.send(\"Profiler.startPreciseCoverage\", { callCount: false, detailed: true })\n\n return {\n async stop(testInfo: TestInfo) {\n try {\n const payload = await collectCoveragePayload(session, scriptMeta, sourceCache, testInfo, config)\n\n if (payload.scripts.length === 0) {\n return\n }\n\n const outputFile = resolveCoverageOutputFile(config, testInfo)\n await fs.mkdir(path.dirname(outputFile), { recursive: true })\n await fs.writeFile(outputFile, JSON.stringify(payload, null, 2), \"utf8\")\n } finally {\n await shutdownSession(session)\n }\n },\n }\n}\n\nfunction resolveCoverageOutputFile(config: CoverageConfig, testInfo: TestInfo): string {\n const projectName = sanitizePathSegment(testInfo.project?.name)\n const testId = sanitizePathSegment(testInfo.testId)\n const outputDir = path.join(config.rootDir, \"build\", \"playwright\", \"coverage\", projectName, testId)\n return path.join(outputDir, config.coverageFileName)\n}\n\nasync function collectCoveragePayload(\n session: any,\n scriptMeta: Map<string, { normalized: { absolutePath: string; relativePath: string } | null; url: string }>,\n sourceCache: Map<string, Promise<string>>,\n testInfo: TestInfo,\n config: CoverageConfig,\n): Promise<{ testId: string; scripts: any[] }> {\n const { result } = await session.send(\"Profiler.takePreciseCoverage\")\n await session.send(\"Profiler.stopPreciseCoverage\")\n\n const scripts = []\n\n for (const script of result) {\n const meta = scriptMeta.get(script.scriptId)\n if (!meta || !meta.normalized) {\n continue\n }\n\n const source = await resolveScriptSource(session, sourceCache, script.scriptId)\n scripts.push({\n absolutePath: meta.normalized.absolutePath,\n relativePath: meta.normalized.relativePath,\n source,\n functions: script.functions,\n url: meta.url,\n })\n }\n\n return {\n testId: testInfo.titlePath.join(\" › \"),\n scripts,\n }\n}\n\nasync function resolveScriptSource(session: any, cache: Map<string, Promise<string>>, scriptId: string): Promise<string> {\n const cached = cache.get(scriptId)\n if (cached) {\n return cached\n }\n\n const promise = fetchScriptSource(session, scriptId)\n cache.set(scriptId, promise)\n return promise\n}\n\nasync function fetchScriptSource(session: any, scriptId: string): Promise<string> {\n try {\n const sourceResponse = await session.send(\"Debugger.getScriptSource\", { scriptId })\n return sourceResponse?.scriptSource ?? \"\"\n } catch (error: any) {\n const message = String(error?.message ?? error)\n if (message.includes(\"Debugger agent is not enabled\")) {\n try {\n await session.send(\"Debugger.enable\")\n const sourceResponse = await session.send(\"Debugger.getScriptSource\", { scriptId })\n return sourceResponse?.scriptSource ?? \"\"\n } catch {\n return \"\"\n }\n }\n\n return \"\"\n }\n}\n\nasync function shutdownSession(session: any): Promise<void> {\n await Promise.allSettled([\n session.send(\"Profiler.stopPreciseCoverage\").catch(() => undefined),\n session.send(\"Profiler.disable\").catch(() => undefined),\n session.send(\"Debugger.disable\").catch(() => undefined),\n ])\n await session.detach().catch(() => undefined)\n}\n\nfunction normalizeScriptUrl(rawUrl: string, config: CoverageConfig): { absolutePath: string; relativePath: string } | null {\n if (!rawUrl || rawUrl.startsWith(\"node:\")) {\n return null\n }\n\n const cleaned = stripQuery(rawUrl)\n let pathname = cleaned\n\n try {\n const parsed = new URL(cleaned)\n pathname = parsed.pathname\n } catch {\n // keep as-is for relative paths\n }\n\n if (!pathname) {\n return null\n }\n\n let absolutePath\n\n const decoded = decodeURIComponent(pathname)\n if (decoded.startsWith(VITE_FS_PREFIX)) {\n const fsPath = decoded.slice(VITE_FS_PREFIX.length)\n const normalizedFsPath = fsPath.startsWith(\"/\") || /^[A-Za-z]:\\//.test(fsPath)\n ? fsPath\n : `/${fsPath}`\n absolutePath = path.normalize(normalizedFsPath)\n } else if (decoded.startsWith(\"/\")) {\n if (!urlPathLooksLikeFile(decoded)) {\n return null\n }\n absolutePath = path.resolve(process.cwd(), `.${decoded}`)\n } else {\n return null\n }\n\n return createNormalizedPath(absolutePath, config.rootDir)\n}\n\nfunction createNormalizedPath(absolutePath: string, rootDir: string): { absolutePath: string; relativePath: string } {\n const normalizedAbsolute = path.normalize(absolutePath)\n const relativePath = path.relative(rootDir, normalizedAbsolute)\n return {\n absolutePath: normalizedAbsolute,\n relativePath,\n }\n}\n\nfunction stripQuery(url: string): string {\n const queryIndex = url.indexOf(\"?\")\n const hashIndex = url.indexOf(\"#\")\n\n const endIndex = Math.min(\n queryIndex === -1 ? Number.POSITIVE_INFINITY : queryIndex,\n hashIndex === -1 ? Number.POSITIVE_INFINITY : hashIndex,\n )\n\n if (!Number.isFinite(endIndex)) {\n return url\n }\n\n return url.slice(0, endIndex)\n}\n\nfunction isNodeModulesPath(filePath: string): boolean {\n return path\n .normalize(String(filePath ?? \"\"))\n .split(path.sep)\n .includes(\"node_modules\")\n}\n"],"mappings":"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"}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["test","baseTest","expect","baseExpect","defineConfig","playwrightDefineConfig","devices","loadCoverageOptionsSync","createCoverageHarness","clearDatabase","coverageOptions","optional","coverageHarness","extendTest","PlaywrightConfig","Parameters","ReporterEntry","Record","userConfig","normalized","reporters","ensureReporterArray","reporter","config","coverageEnabled","process","env","RB_TEST_COMBINED_COVERAGE","coverageReporter","reporterEntry","some","name","push","applySpecFileConventions","Array","isArray","normalizeReporterEntry","map","entry","DESKTOP_SPEC_MATCH","MOBILE_SPEC_MATCH","testMatch","projects","length","project","use","isMobile"],"sources":["../src/index.ts"],"sourcesContent":["import { test as baseTest, expect as baseExpect, defineConfig as playwrightDefineConfig, devices } from \"@playwright/test\"\n\nimport { loadCoverageOptionsSync } from \"./coverage/config-loader\"\nimport { createCoverageHarness } from \"./coverage\"\n\n\nexport * from \"@playwright/test\"\n\nexport { clearDatabase } from \"./clearDatabase\"\nexport * from \"./coverage\"\nexport * from \"./serverCoverage\"\n\nconst coverageOptions = loadCoverageOptionsSync({ optional: true })\nconst coverageHarness = coverageOptions ? createCoverageHarness(coverageOptions) : null\nexport const test: typeof baseTest = coverageHarness ? coverageHarness.extendTest(baseTest) : baseTest\nexport const expect = baseExpect\nexport { devices }\n\ntype PlaywrightConfig = Parameters<typeof playwrightDefineConfig>[0]\ntype ReporterEntry = [string, Record<string, unknown>?]\n\nexport function defineConfig(userConfig: PlaywrightConfig = {}) {\n const normalized: any = { ...userConfig }\n const reporters = ensureReporterArray(normalized.reporter)\n\n if (coverageHarness?.config.coverageEnabled && process.env.RB_TEST_COMBINED_COVERAGE !== \"1\") {\n const coverageReporter = coverageHarness.reporterEntry()\n if (!reporters.some(([name]) => name === coverageReporter[0])) {\n reporters.push(coverageReporter)\n }\n }\n\n normalized.reporter = reporters\n\n applySpecFileConventions(normalized)\n\n return playwrightDefineConfig(normalized)\n}\n\nfunction ensureReporterArray(reporter: any): ReporterEntry[] {\n if (!reporter) {\n return [[\"list\"]]\n }\n\n if (!Array.isArray(reporter)) {\n return [normalizeReporterEntry(reporter)]\n }\n\n return reporter.map((entry: any) => normalizeReporterEntry(entry))\n}\n\nfunction normalizeReporterEntry(entry: any): ReporterEntry {\n if (Array.isArray(entry)) {\n return entry as ReporterEntry\n }\n return [entry] as ReporterEntry\n}\n\nconst DESKTOP_SPEC_MATCH = [/\\.spec(?:\\.desktop)?\\.(?:[cm]?[jt]sx?)$/]\nconst MOBILE_SPEC_MATCH = [/\\.spec(?:\\.mobile)?\\.(?:[cm]?[jt]sx?)$/]\n\nfunction applySpecFileConventions(config: any): void {\n if (config.testMatch != null) {\n return\n }\n\n if (!Array.isArray(config.projects) || config.projects.length === 0) {\n config.testMatch = DESKTOP_SPEC_MATCH\n return\n }\n\n config.projects = config.projects.map((project: any) => {\n if (!project || project.testMatch != null) {\n return project\n }\n const testMatch = project.use?.isMobile ? MOBILE_SPEC_MATCH : DESKTOP_SPEC_MATCH\n return { ...project, testMatch }\n })\n}\n"],"mappings":";;;;;;;;;;;;;AAYA,IAAMU,kBAAkBH,wBAAwB,EAAEI,UAAU,KAAK,CAAC;AAClE,IAAMC,kBAAkBF,kBAAkBF,sBAAsBE,eAAe,IAAI;AACnF,IAAaV,OAAwBY,kBAAkBA,gBAAgBC,WAAWZ,MAAQ,IAAIA;AAC9F,IAAaC,SAASC;AAMtB,SAAgBC,aAAac,aAA+B,CAAC,GAAG;CAC9D,MAAMC,aAAkB,EAAE,GAAGD,WAAW;CACxC,MAAME,YAAYC,oBAAoBF,WAAWG,QAAQ;CAEzD,IAAIV,iBAAiBW,OAAOC,mBAAmBC,QAAQC,IAAIC,8BAA8B,KAAK;EAC5F,MAAMC,mBAAmBhB,gBAAgBiB,cAAc;EACvD,IAAI,CAACT,UAAUU,MAAM,CAACC,UAAUA,SAASH,iBAAiB,EAAE,GAC1DR,UAAUY,KAAKJ,gBAAgB;CAEnC;CAEAT,WAAWG,WAAWF;CAEtBa,yBAAyBd,UAAU;CAEnC,OAAOd,eAAuBc,UAAU;AAC1C;AAEA,SAASE,oBAAoBC,UAAgC;CAC3D,IAAI,CAACA,UACH,OAAO,CAAC,CAAC,MAAM,CAAC;CAGlB,IAAI,CAACY,MAAMC,QAAQb,QAAQ,GACzB,OAAO,CAACc,uBAAuBd,QAAQ,CAAC;CAG1C,OAAOA,SAASe,KAAKC,UAAeF,uBAAuBE,KAAK,CAAC;AACnE;AAEA,SAASF,uBAAuBE,OAA2B;CACzD,IAAIJ,MAAMC,QAAQG,KAAK,GACrB,OAAOA;CAET,OAAO,CAACA,KAAK;AACf;AAEA,IAAMC,qBAAqB,CAAC,yCAAyC;AACrE,IAAMC,oBAAoB,CAAC,wCAAwC;AAEnE,SAASP,yBAAyBV,QAAmB;CACnD,IAAIA,OAAOkB,aAAa,MACtB;CAGF,IAAI,CAACP,MAAMC,QAAQZ,OAAOmB,QAAQ,KAAKnB,OAAOmB,SAASC,WAAW,GAAG;EACnEpB,OAAOkB,YAAYF;EACnB;CACF;CAEAhB,OAAOmB,WAAWnB,OAAOmB,SAASL,KAAKO,YAAiB;EACtD,IAAI,CAACA,WAAWA,QAAQH,aAAa,MACnC,OAAOG;EAET,MAAMH,YAAYG,QAAQC,KAAKC,WAAWN,oBAAoBD;EAC9D,OAAO;GAAE,GAAGK;GAASH;EAAU;CACjC,CAAC;AACH"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import { test as baseTest, expect as baseExpect, defineConfig as playwrightDefineConfig, devices } from \"@playwright/test\"\n\nimport { loadCoverageOptionsSync } from \"./coverage/config-loader\"\nimport { createCoverageHarness } from \"./coverage\"\n\n\nexport * from \"@playwright/test\"\n\nexport { clearDatabase } from \"./clearDatabase\"\nexport * from \"./coverage\"\nexport * from \"./serverCoverage\"\n\nconst coverageOptions = loadCoverageOptionsSync({ optional: true })\nconst coverageHarness = coverageOptions ? createCoverageHarness(coverageOptions) : null\nexport const test: typeof baseTest = coverageHarness ? coverageHarness.extendTest(baseTest) : baseTest\nexport const expect = baseExpect\nexport { devices }\n\ntype PlaywrightConfig = Parameters<typeof playwrightDefineConfig>[0]\ntype ReporterEntry = [string, Record<string, unknown>?]\n\nexport function defineConfig(userConfig: PlaywrightConfig = {}) {\n const normalized: any = { ...userConfig }\n const reporters = ensureReporterArray(normalized.reporter)\n\n if (coverageHarness?.config.coverageEnabled && process.env.RB_TEST_COMBINED_COVERAGE !== \"1\") {\n const coverageReporter = coverageHarness.reporterEntry()\n if (!reporters.some(([name]) => name === coverageReporter[0])) {\n reporters.push(coverageReporter)\n }\n }\n\n normalized.reporter = reporters\n\n applySpecFileConventions(normalized)\n\n return playwrightDefineConfig(normalized)\n}\n\nfunction ensureReporterArray(reporter: any): ReporterEntry[] {\n if (!reporter) {\n return [[\"list\"]]\n }\n\n if (!Array.isArray(reporter)) {\n return [normalizeReporterEntry(reporter)]\n }\n\n return reporter.map((entry: any) => normalizeReporterEntry(entry))\n}\n\nfunction normalizeReporterEntry(entry: any): ReporterEntry {\n if (Array.isArray(entry)) {\n return entry as ReporterEntry\n }\n return [entry] as ReporterEntry\n}\n\nconst DESKTOP_SPEC_MATCH = [/\\.spec(?:\\.desktop)?\\.(?:[cm]?[jt]sx?)$/]\nconst MOBILE_SPEC_MATCH = [/\\.spec(?:\\.mobile)?\\.(?:[cm]?[jt]sx?)$/]\n\nfunction applySpecFileConventions(config: any): void {\n if (config.testMatch != null) {\n return\n }\n\n if (!Array.isArray(config.projects) || config.projects.length === 0) {\n config.testMatch = DESKTOP_SPEC_MATCH\n return\n }\n\n config.projects = config.projects.map((project: any) => {\n if (!project || project.testMatch != null) {\n return project\n }\n const testMatch = project.use?.isMobile ? MOBILE_SPEC_MATCH : DESKTOP_SPEC_MATCH\n return { ...project, testMatch }\n })\n}\n"],"mappings":";;;;;;;;;;;;;AAYA,IAAM,kBAAkB,wBAAwB,EAAE,UAAU,KAAK,CAAC;AAClE,IAAM,kBAAkB,kBAAkB,sBAAsB,eAAe,IAAI;AACnF,IAAa,OAAwB,kBAAkB,gBAAgB,WAAW,MAAQ,IAAI;AAC9F,IAAa,SAAS;AAMtB,SAAgB,aAAa,aAA+B,CAAC,GAAG;CAC9D,MAAM,aAAkB,EAAE,GAAG,WAAW;CACxC,MAAM,YAAY,oBAAoB,WAAW,QAAQ;CAEzD,IAAI,iBAAiB,OAAO,mBAAmB,QAAQ,IAAI,8BAA8B,KAAK;EAC5F,MAAM,mBAAmB,gBAAgB,cAAc;EACvD,IAAI,CAAC,UAAU,MAAM,CAAC,UAAU,SAAS,iBAAiB,EAAE,GAC1D,UAAU,KAAK,gBAAgB;CAEnC;CAEA,WAAW,WAAW;CAEtB,yBAAyB,UAAU;CAEnC,OAAO,eAAuB,UAAU;AAC1C;AAEA,SAAS,oBAAoB,UAAgC;CAC3D,IAAI,CAAC,UACH,OAAO,CAAC,CAAC,MAAM,CAAC;CAGlB,IAAI,CAAC,MAAM,QAAQ,QAAQ,GACzB,OAAO,CAAC,uBAAuB,QAAQ,CAAC;CAG1C,OAAO,SAAS,KAAK,UAAe,uBAAuB,KAAK,CAAC;AACnE;AAEA,SAAS,uBAAuB,OAA2B;CACzD,IAAI,MAAM,QAAQ,KAAK,GACrB,OAAO;CAET,OAAO,CAAC,KAAK;AACf;AAEA,IAAM,qBAAqB,CAAC,yCAAyC;AACrE,IAAM,oBAAoB,CAAC,wCAAwC;AAEnE,SAAS,yBAAyB,QAAmB;CACnD,IAAI,OAAO,aAAa,MACtB;CAGF,IAAI,CAAC,MAAM,QAAQ,OAAO,QAAQ,KAAK,OAAO,SAAS,WAAW,GAAG;EACnE,OAAO,YAAY;EACnB;CACF;CAEA,OAAO,WAAW,OAAO,SAAS,KAAK,YAAiB;EACtD,IAAI,CAAC,WAAW,QAAQ,aAAa,MACnC,OAAO;EAET,MAAM,YAAY,QAAQ,KAAK,WAAW,oBAAoB;EAC9D,OAAO;GAAE,GAAG;GAAS;EAAU;CACjC,CAAC;AACH"}
@@ -1 +1 @@
1
- {"version":3,"file":"playwright.js","names":["fs","fsPromises","path","createRequire","fileURLToPath","spawnAndCaptureStdout","spawnWithLogs","withRegisterShim","SpawnLauncher","require","import","meta","url","moduleDir","dirname","COMBINED_COVERAGE_ENV_VAR","PLAYWRIGHT_RESULTS_FILE","join","process","cwd","PlaywrightReportSummary","failedFiles","PlaywrightRuntimeSettings","retries","workers","PLAYWRIGHT_OPTIONS_WITH_REQUIRED_VALUE","Set","PLAYWRIGHT_OPTIONS_WITH_OPTIONAL_VALUE","PLAYWRIGHT_OPTIONS_TO_REMOVE_FOR_WORKER_RETRY","PLAYWRIGHT_OPTIONS_TO_REMOVE_FOR_INITIAL_FRESH_RUN","PLAYWRIGHT_RETRY_LOG_LABEL_MAX_LENGTH","runPlaywright","userArgs","disableCoverage","Promise","configPath","existsSync","hasCustomConfig","some","arg","startsWith","ensureJsxRuntimeShim","launcher","resolvePlaywrightLauncher","env","RB_DISABLE_COVERAGE","runtimeSettings","resolveFreshWorkerRetrySettings","configuredRetries","retryConcurrency","Math","max","resultsMtimeBeforeRun","getFileMtimeMs","initialRunArgs","buildPlaywrightInitialFreshWorkerArgs","initialPlaywrightArgs","push","runPlaywrightOnce","args","error","summary","readPlaywrightReportSummary","length","lastError","maxAttempts","attempt","activeRetryWorkers","min","console","warn","retryResults","runPlaywrightRetryAttempt","outputMode","bufferOutput","successMessage","failureMessage","stdoutLinePrefix","stderrLinePrefix","NodeJS","ProcessEnv","name","undefined","cliPath","resolveCliPath","command","execPath","localBin","resolve","searchRoots","base","pkgPath","paths","_error","buildPlaywrightWorkerRetryArgs","optionArgs","extractPlaywrightOptionArgs","sanitizedOptions","removePlaywrightOptions","buildPlaywrightRetryOutputDir","positionalArgs","extractPlaywrightPositionalArgs","configuredSettings","probeConfiguredPlaywrightSettings","probeArgs","extractPlaywrightProjectArgs","stdout","json","parseJsonObjectFromText","resolvePlaywrightRetriesFromReport","resolvePlaywrightWorkersFromReport","output","i","next","input","JSON","parse","start","indexOf","end","lastIndexOf","slice","includes","has","optionsToRemove","normalized","split","resultsFilePath","newerThanMtimeMs","stats","stat","catch","mtimeMs","data","readJson","resolveFailedPlaywrightFiles","filePath","statSync","projects","Array","isArray","config","retriesFromProjects","map","project","Number","filter","value","isFinite","floor","fallback","configWorkers","workersFromProjects","metadata","actualWorkers","suites","rootDir","suite","collectFailedPlaywrightFiles","from","sort","specs","spec","isPlaywrightSpecSuccessful","file","normalizePlaywrightReportFile","add","innerSuites","innerSuite","ok","tests","every","test","testStatus","String","status","results","result","raw","trim","absolutePath","isAbsolute","normalize","cwdCandidate","rootCandidate","relative","toPosixPath","replaceAll","sep","slug","replace","createPlaywrightRetryEnv","baseEnv","PLAYWRIGHT_FORCE_TTY","truncatePlaywrightRetryLogLabel","label","maxLength","repeat","visibleChars","startLength","ceil","endLength","getPlaywrightRetryLogName","failedFile","normalizedFile","relativeFile","strippedBaseName","formatPlaywrightRetryBracketLabel","suffix","formatPlaywrightRetryLogLabel","formatPlaywrightRetryLinePrefix","stream","failedAgain","nextIndex","retryEnv","runNext","fileIndex","retryLogLabel","retryArgs","retryPlaywrightArgs","retryError","all","readFile","projectRoot","shimDir","mkdirSync","recursive","shims","target","content","writeFileSync"],"sources":["../../src/runners/playwright.ts"],"sourcesContent":["import fs from \"node:fs\"\nimport fsPromises from \"node:fs/promises\"\nimport path from \"node:path\"\nimport { createRequire } from \"node:module\"\nimport { fileURLToPath } from \"node:url\"\n\nimport { spawnAndCaptureStdout, spawnWithLogs, withRegisterShim, type SpawnLauncher } from \"./process\"\n\n\nconst require = createRequire(import.meta.url)\nconst moduleDir = path.dirname(fileURLToPath(import.meta.url))\n\nconst COMBINED_COVERAGE_ENV_VAR = \"RB_TEST_COMBINED_COVERAGE\"\nconst PLAYWRIGHT_RESULTS_FILE = path.join(process.cwd(), \"build\", \"playwright\", \"results.json\")\n\ntype PlaywrightReportSummary = {\n failedFiles: string[]\n}\n\ntype PlaywrightRuntimeSettings = {\n retries: number | null\n workers: number | null\n}\n\nconst PLAYWRIGHT_OPTIONS_WITH_REQUIRED_VALUE = new Set([\n \"--browser\",\n \"--config\",\n \"-c\",\n \"--grep\",\n \"-g\",\n \"--grep-invert\",\n \"--global-timeout\",\n \"--max-failures\",\n \"--output\",\n \"--project\",\n \"--repeat-each\",\n \"--reporter\",\n \"--retries\",\n \"--shard\",\n \"--timeout\",\n \"--trace\",\n \"--tsconfig\",\n \"--workers\",\n \"-j\",\n])\n\nconst PLAYWRIGHT_OPTIONS_WITH_OPTIONAL_VALUE = new Set([\n \"--only-changed\",\n \"--update-snapshots\",\n \"-u\",\n])\n\nconst PLAYWRIGHT_OPTIONS_TO_REMOVE_FOR_WORKER_RETRY = new Set([\n \"--last-failed\",\n \"--only-changed\",\n \"--output\",\n \"--retries\",\n \"--pass-with-no-tests\",\n \"--reporter\",\n \"--workers\",\n \"-j\",\n])\n\nconst PLAYWRIGHT_OPTIONS_TO_REMOVE_FOR_INITIAL_FRESH_RUN = new Set([\n \"--retries\",\n])\n\nconst PLAYWRIGHT_RETRY_LOG_LABEL_MAX_LENGTH = 20\n\nexport async function runPlaywright(\n userArgs: string[],\n { disableCoverage = false }: { disableCoverage?: boolean } = {},\n): Promise<void> {\n const configPath = fs.existsSync(\n path.join(process.cwd(), \"playwright.config.ts\"),\n )\n ? path.join(process.cwd(), \"playwright.config.ts\")\n : path.join(moduleDir, \"..\", \"playwright.config.ts\")\n\n const hasCustomConfig = userArgs.some((arg) => {\n if (arg === \"--config\" || arg === \"-c\") {\n return true\n }\n\n return arg.startsWith(\"--config=\")\n })\n\n ensureJsxRuntimeShim(process.cwd())\n const launcher = resolvePlaywrightLauncher()\n const env = withRegisterShim(process.env)\n env[COMBINED_COVERAGE_ENV_VAR] = \"1\"\n if (disableCoverage) {\n env.RB_DISABLE_COVERAGE = \"1\"\n }\n\n const runtimeSettings = await resolveFreshWorkerRetrySettings({\n launcher,\n configPath,\n hasCustomConfig,\n userArgs,\n env,\n })\n const configuredRetries = runtimeSettings.retries\n const retryConcurrency = Math.max(1, runtimeSettings.workers ?? 1)\n\n const resultsMtimeBeforeRun = getFileMtimeMs(PLAYWRIGHT_RESULTS_FILE)\n const initialRunArgs = buildPlaywrightInitialFreshWorkerArgs(userArgs)\n const initialPlaywrightArgs = [\"test\"]\n if (!hasCustomConfig) {\n initialPlaywrightArgs.push(\"--config\", configPath)\n }\n initialPlaywrightArgs.push(...initialRunArgs)\n\n try {\n await runPlaywrightOnce({\n launcher,\n args: initialPlaywrightArgs,\n env,\n })\n return\n } catch (error) {\n const summary = await readPlaywrightReportSummary(PLAYWRIGHT_RESULTS_FILE, resultsMtimeBeforeRun)\n if (!summary || configuredRetries <= 0 || summary.failedFiles.length === 0) {\n throw error\n }\n\n let lastError = error\n let failedFiles = summary.failedFiles\n const maxAttempts = configuredRetries\n\n for (let attempt = 1; attempt <= maxAttempts && failedFiles.length > 0; attempt += 1) {\n const activeRetryWorkers = Math.max(1, Math.min(retryConcurrency, failedFiles.length))\n console.warn(\n `[rb-test] Retrying ${failedFiles.length} failed Playwright file(s) with fresh workers (${attempt}/${maxAttempts}, up to ${activeRetryWorkers} in parallel)`,\n )\n const retryResults = await runPlaywrightRetryAttempt({\n launcher,\n userArgs,\n failedFiles,\n retryConcurrency: activeRetryWorkers,\n configPath,\n hasCustomConfig,\n env,\n attempt,\n })\n\n if (retryResults.lastError) {\n lastError = retryResults.lastError\n }\n failedFiles = retryResults.failedFiles\n }\n\n if (failedFiles.length === 0) {\n return\n }\n\n throw lastError\n }\n}\n\nfunction runPlaywrightOnce({\n launcher,\n args,\n env,\n outputMode = \"chunk\",\n bufferOutput = false,\n successMessage,\n failureMessage,\n stdoutLinePrefix,\n stderrLinePrefix,\n}: {\n launcher: SpawnLauncher\n args: string[]\n env: NodeJS.ProcessEnv\n outputMode?: \"chunk\" | \"line\"\n bufferOutput?: boolean\n successMessage?: string | null\n failureMessage?: string | null\n stdoutLinePrefix?: string\n stderrLinePrefix?: string\n}): Promise<void> {\n return spawnWithLogs({\n name: \"Playwright\",\n launcher,\n args,\n env,\n outputMode,\n bufferOutput,\n successMessage: successMessage === undefined ? \"Playwright suite passed!\" : successMessage ?? undefined,\n failureMessage: failureMessage === undefined ? \"Playwright failed\" : failureMessage ?? undefined,\n stdoutLinePrefix,\n stderrLinePrefix,\n })\n}\n\nfunction resolvePlaywrightLauncher(): SpawnLauncher {\n const cliPath = resolveCliPath()\n if (cliPath) {\n return {\n command: process.execPath,\n args: [cliPath],\n }\n }\n\n const localBin = path.resolve(process.cwd(), \"node_modules/.bin/playwright\")\n if (fs.existsSync(localBin)) {\n return {\n command: localBin,\n args: [],\n }\n }\n\n return {\n command: \"playwright\",\n args: [],\n }\n}\n\nfunction resolveCliPath(): string | null {\n const searchRoots = [process.cwd(), moduleDir]\n\n for (const base of searchRoots) {\n try {\n const pkgPath = require.resolve(\"@playwright/test/package.json\", { paths: [base] })\n const cliPath = path.join(path.dirname(pkgPath), \"cli.js\")\n if (fs.existsSync(cliPath)) {\n return cliPath\n }\n } catch (_error) {\n // Continue searching for a usable playwright launcher.\n }\n }\n\n return null\n}\n\nfunction buildPlaywrightWorkerRetryArgs(userArgs: string[], failedFiles: string[], attempt: number): string[] {\n const optionArgs = extractPlaywrightOptionArgs(userArgs)\n const sanitizedOptions = removePlaywrightOptions(optionArgs, PLAYWRIGHT_OPTIONS_TO_REMOVE_FOR_WORKER_RETRY)\n return [\n ...sanitizedOptions,\n \"--retries=0\",\n \"--workers=1\",\n \"--reporter=list\",\n \"--output\",\n buildPlaywrightRetryOutputDir(attempt, failedFiles),\n ...failedFiles,\n ]\n}\n\nfunction buildPlaywrightInitialFreshWorkerArgs(userArgs: string[]): string[] {\n const optionArgs = extractPlaywrightOptionArgs(userArgs)\n const sanitizedOptions = removePlaywrightOptions(optionArgs, PLAYWRIGHT_OPTIONS_TO_REMOVE_FOR_INITIAL_FRESH_RUN)\n const positionalArgs = extractPlaywrightPositionalArgs(userArgs)\n return [...sanitizedOptions, \"--retries=0\", ...positionalArgs]\n}\n\nasync function resolveFreshWorkerRetrySettings({\n launcher,\n configPath,\n hasCustomConfig,\n userArgs,\n env,\n}: {\n launcher: SpawnLauncher\n configPath: string\n hasCustomConfig: boolean\n userArgs: string[]\n env: NodeJS.ProcessEnv\n}): Promise<{ retries: number; workers: number | null }> {\n const configuredSettings = await probeConfiguredPlaywrightSettings({\n launcher,\n configPath,\n hasCustomConfig,\n userArgs,\n env,\n })\n\n return {\n retries: configuredSettings.retries ?? 0,\n workers: configuredSettings.workers,\n }\n}\n\nasync function probeConfiguredPlaywrightSettings({\n launcher,\n configPath,\n hasCustomConfig,\n userArgs,\n env,\n}: {\n launcher: SpawnLauncher\n configPath: string\n hasCustomConfig: boolean\n userArgs: string[]\n env: NodeJS.ProcessEnv\n}): Promise<PlaywrightRuntimeSettings> {\n const probeArgs = [\"test\"]\n if (!hasCustomConfig) {\n probeArgs.push(\"--config\", configPath)\n }\n probeArgs.push(\"--list\", \"--reporter=json\", ...extractPlaywrightProjectArgs(userArgs))\n\n try {\n const stdout = await spawnAndCaptureStdout({\n name: \"Playwright retries probe\",\n launcher,\n args: probeArgs,\n env,\n })\n const json = parseJsonObjectFromText(stdout)\n if (!json) {\n return { retries: null, workers: null }\n }\n return {\n retries: resolvePlaywrightRetriesFromReport(json),\n workers: resolvePlaywrightWorkersFromReport(json),\n }\n } catch (_error) {\n return { retries: null, workers: null }\n }\n}\n\nfunction extractPlaywrightProjectArgs(userArgs: string[]): string[] {\n const output: string[] = []\n for (let i = 0; i < userArgs.length; i += 1) {\n const arg = userArgs[i]\n if (arg === \"--\") {\n break\n }\n if (arg === \"--project\") {\n const next = userArgs[i + 1]\n if (next != null) {\n output.push(arg, next)\n i += 1\n }\n continue\n }\n if (arg.startsWith(\"--project=\")) {\n output.push(arg)\n }\n }\n return output\n}\n\nfunction parseJsonObjectFromText(input: string): any | null {\n try {\n return JSON.parse(input)\n } catch {\n const start = input.indexOf(\"{\")\n const end = input.lastIndexOf(\"}\")\n if (start === -1 || end === -1 || end <= start) {\n return null\n }\n try {\n return JSON.parse(input.slice(start, end + 1))\n } catch {\n return null\n }\n }\n}\n\nfunction extractPlaywrightPositionalArgs(userArgs: string[]): string[] {\n const output: string[] = []\n\n for (let i = 0; i < userArgs.length; i += 1) {\n const arg = userArgs[i]\n\n if (arg === \"--\") {\n break\n }\n\n if (!arg.startsWith(\"-\")) {\n output.push(arg)\n continue\n }\n\n if (arg.includes(\"=\")) {\n continue\n }\n\n if (PLAYWRIGHT_OPTIONS_WITH_REQUIRED_VALUE.has(arg)) {\n const next = userArgs[i + 1]\n if (next !== undefined) {\n i += 1\n }\n continue\n }\n\n if (PLAYWRIGHT_OPTIONS_WITH_OPTIONAL_VALUE.has(arg)) {\n const next = userArgs[i + 1]\n if (next !== undefined && !next.startsWith(\"-\")) {\n i += 1\n }\n }\n }\n\n return output\n}\n\nfunction removePlaywrightOptions(optionArgs: string[], optionsToRemove: Set<string>): string[] {\n const output: string[] = []\n for (let i = 0; i < optionArgs.length; i += 1) {\n const arg = optionArgs[i]\n const normalized = arg.split(\"=\")[0]\n if (!arg.startsWith(\"-\") || !optionsToRemove.has(normalized)) {\n output.push(arg)\n continue\n }\n\n if (arg.includes(\"=\")) {\n continue\n }\n\n if (PLAYWRIGHT_OPTIONS_WITH_REQUIRED_VALUE.has(normalized)) {\n const next = optionArgs[i + 1]\n if (next !== undefined) {\n i += 1\n }\n continue\n }\n\n if (PLAYWRIGHT_OPTIONS_WITH_OPTIONAL_VALUE.has(normalized)) {\n const next = optionArgs[i + 1]\n if (next !== undefined && !next.startsWith(\"-\")) {\n i += 1\n }\n }\n }\n return output\n}\n\nfunction extractPlaywrightOptionArgs(userArgs: string[]): string[] {\n const output: string[] = []\n\n for (let i = 0; i < userArgs.length; i += 1) {\n const arg = userArgs[i]\n\n if (arg === \"--\") {\n break\n }\n\n if (!arg.startsWith(\"-\")) {\n continue\n }\n\n output.push(arg)\n\n if (arg.includes(\"=\")) {\n continue\n }\n\n if (PLAYWRIGHT_OPTIONS_WITH_REQUIRED_VALUE.has(arg)) {\n const next = userArgs[i + 1]\n if (next !== undefined) {\n output.push(next)\n i += 1\n }\n continue\n }\n\n if (PLAYWRIGHT_OPTIONS_WITH_OPTIONAL_VALUE.has(arg)) {\n const next = userArgs[i + 1]\n if (next !== undefined && !next.startsWith(\"-\")) {\n output.push(next)\n i += 1\n }\n }\n }\n\n return output\n}\n\nasync function readPlaywrightReportSummary(\n resultsFilePath: string,\n newerThanMtimeMs: number | null,\n): Promise<PlaywrightReportSummary | null> {\n const stats = await fsPromises.stat(resultsFilePath).catch(() => null)\n if (!stats) {\n return null\n }\n\n if (newerThanMtimeMs != null && stats.mtimeMs <= newerThanMtimeMs) {\n return null\n }\n\n const data = await readJson(resultsFilePath)\n if (!data || typeof data !== \"object\") {\n return null\n }\n\n return {\n failedFiles: resolveFailedPlaywrightFiles(data),\n }\n}\n\nfunction getFileMtimeMs(filePath: string): number | null {\n try {\n return fs.statSync(filePath).mtimeMs\n } catch {\n return null\n }\n}\n\nfunction resolvePlaywrightRetriesFromReport(data: any): number {\n const projects = Array.isArray(data?.config?.projects) ? data.config.projects : []\n const retriesFromProjects = projects\n .map((project: any) => Number(project?.retries))\n .filter((value: number) => Number.isFinite(value))\n .map((value: number) => Math.max(0, Math.floor(value)))\n\n if (retriesFromProjects.length > 0) {\n return Math.max(...retriesFromProjects)\n }\n\n const fallback = Number(data?.config?.retries)\n if (Number.isFinite(fallback)) {\n return Math.max(0, Math.floor(fallback))\n }\n\n return 0\n}\n\nfunction resolvePlaywrightWorkersFromReport(data: any): number | null {\n const configWorkers = Number(data?.config?.workers)\n if (Number.isFinite(configWorkers)) {\n return Math.max(1, Math.floor(configWorkers))\n }\n\n const projects = Array.isArray(data?.config?.projects) ? data.config.projects : []\n const workersFromProjects = projects\n .map((project: any) => Number(project?.metadata?.actualWorkers ?? project?.workers))\n .filter((value: number) => Number.isFinite(value))\n .map((value: number) => Math.max(1, Math.floor(value)))\n\n if (workersFromProjects.length > 0) {\n return Math.max(...workersFromProjects)\n }\n\n return null\n}\n\nfunction resolveFailedPlaywrightFiles(data: any): string[] {\n const suites = Array.isArray(data?.suites) ? data.suites : []\n const rootDir = typeof data?.config?.rootDir === \"string\" ? data.config.rootDir : null\n const failedFiles = new Set<string>()\n\n for (const suite of suites) {\n collectFailedPlaywrightFiles(suite, failedFiles, rootDir)\n }\n\n return Array.from(failedFiles).sort()\n}\n\nfunction collectFailedPlaywrightFiles(suite: any, output: Set<string>, rootDir: string | null): void {\n const specs = Array.isArray(suite?.specs) ? suite.specs : []\n\n for (const spec of specs) {\n if (isPlaywrightSpecSuccessful(spec)) {\n continue\n }\n const file = normalizePlaywrightReportFile(spec?.file ?? suite?.file, rootDir)\n if (file) {\n output.add(file)\n }\n }\n\n const innerSuites = Array.isArray(suite?.suites) ? suite.suites : []\n for (const innerSuite of innerSuites) {\n collectFailedPlaywrightFiles(innerSuite, output, rootDir)\n }\n}\n\nfunction isPlaywrightSpecSuccessful(spec: any): boolean {\n if (typeof spec?.ok === \"boolean\") {\n return spec.ok\n }\n\n const tests = Array.isArray(spec?.tests) ? spec.tests : []\n if (tests.length === 0) {\n return false\n }\n\n return tests.every((test: any) => {\n const testStatus = String(test?.status ?? \"\")\n if (testStatus === \"expected\" || testStatus === \"skipped\" || testStatus === \"flaky\") {\n return true\n }\n\n const results = Array.isArray(test?.results) ? test.results : []\n if (results.length === 0) {\n return false\n }\n return results.every((result: any) => result?.status === \"passed\" || result?.status === \"skipped\")\n })\n}\n\nfunction normalizePlaywrightReportFile(filePath: unknown, rootDir: string | null): string | null {\n const raw = String(filePath ?? \"\").trim()\n if (!raw) {\n return null\n }\n\n let absolutePath: string\n if (path.isAbsolute(raw)) {\n absolutePath = path.normalize(raw)\n } else {\n const cwdCandidate = path.resolve(process.cwd(), raw)\n const rootCandidate = rootDir ? path.resolve(rootDir, raw) : null\n if (rootCandidate && fs.existsSync(rootCandidate)) {\n absolutePath = rootCandidate\n } else if (fs.existsSync(cwdCandidate)) {\n absolutePath = cwdCandidate\n } else {\n absolutePath = rootCandidate ?? cwdCandidate\n }\n }\n\n const relative = path.relative(process.cwd(), absolutePath)\n if (relative === \"\" || (!relative.startsWith(\"..\") && !path.isAbsolute(relative))) {\n return toPosixPath(relative || raw)\n }\n\n return toPosixPath(raw)\n}\n\nfunction toPosixPath(input: unknown): string {\n return String(input ?? \"\").replaceAll(\"\\\\\", \"/\").split(path.sep).join(\"/\")\n}\n\nfunction buildPlaywrightRetryOutputDir(attempt: number, failedFiles: string[]): string {\n const slug = failedFiles\n .map((file) => toPosixPath(file).replace(/[^a-zA-Z0-9._/-]+/g, \"-\").replace(/\\//g, \"__\"))\n .join(\"--\")\n return toPosixPath(path.join(\"build\", \"playwright\", \"test-results\", \"rb-retries\", `attempt-${attempt}`, slug))\n}\n\nexport function createPlaywrightRetryEnv(baseEnv: NodeJS.ProcessEnv): NodeJS.ProcessEnv {\n return {\n ...baseEnv,\n PLAYWRIGHT_FORCE_TTY: \"false\",\n }\n}\n\nfunction truncatePlaywrightRetryLogLabel(label: string, maxLength = PLAYWRIGHT_RETRY_LOG_LABEL_MAX_LENGTH): string {\n if (label.length <= maxLength) {\n return label\n }\n\n if (maxLength <= 3) {\n return \".\".repeat(Math.max(0, maxLength))\n }\n\n const visibleChars = maxLength - 3\n const startLength = Math.ceil(visibleChars / 2)\n const endLength = Math.floor(visibleChars / 2)\n\n return `${label.slice(0, startLength)}...${label.slice(-endLength)}`\n}\n\nfunction getPlaywrightRetryLogName(failedFile: string): string {\n const normalizedFile = toPosixPath(failedFile)\n const relativeFile = normalizedFile.startsWith(\"build/spec/\")\n ? normalizedFile.slice(\"build/spec/\".length)\n : normalizedFile\n const strippedBaseName = relativeFile\n .replace(/\\.(spec|test)\\.[^.]+$/i, \"\")\n .replace(/\\.[^.]+$/i, \"\")\n .trim()\n\n return strippedBaseName || relativeFile || normalizedFile\n}\n\nfunction formatPlaywrightRetryBracketLabel({\n failedFile,\n suffix = \"\",\n}: {\n failedFile: string\n suffix?: string\n}): string {\n const label = truncatePlaywrightRetryLogLabel(\n getPlaywrightRetryLogName(failedFile),\n Math.max(1, PLAYWRIGHT_RETRY_LOG_LABEL_MAX_LENGTH - suffix.length),\n )\n return `[${label}${suffix}]`\n}\n\nexport function formatPlaywrightRetryLogLabel({\n failedFile,\n}: {\n failedFile: string\n}): string {\n return formatPlaywrightRetryBracketLabel({ failedFile })\n}\n\nexport function formatPlaywrightRetryLinePrefix({\n failedFile,\n stream,\n}: {\n failedFile: string\n stream: \"stdout\" | \"stderr\"\n}): string {\n return stream === \"stderr\"\n ? `${formatPlaywrightRetryBracketLabel({ failedFile, suffix: \" stderr\" })} `\n : `${formatPlaywrightRetryLogLabel({ failedFile })} `\n}\n\nasync function runPlaywrightRetryAttempt({\n launcher,\n userArgs,\n failedFiles,\n retryConcurrency,\n configPath,\n hasCustomConfig,\n env,\n attempt,\n}: {\n launcher: SpawnLauncher\n userArgs: string[]\n failedFiles: string[]\n retryConcurrency: number\n configPath: string\n hasCustomConfig: boolean\n env: NodeJS.ProcessEnv\n attempt: number\n}): Promise<{ failedFiles: string[]; lastError: unknown }> {\n const failedAgain = new Set<string>()\n let lastError: unknown = null\n let nextIndex = 0\n const retryEnv = createPlaywrightRetryEnv(env)\n\n async function runNext(): Promise<void> {\n while (nextIndex < failedFiles.length) {\n const fileIndex = nextIndex\n nextIndex += 1\n\n const failedFile = failedFiles[fileIndex]\n const retryLogLabel = formatPlaywrightRetryLogLabel({\n failedFile,\n })\n const retryArgs = buildPlaywrightWorkerRetryArgs(userArgs, [failedFile], attempt)\n const retryPlaywrightArgs = [\"test\"]\n if (!hasCustomConfig) {\n retryPlaywrightArgs.push(\"--config\", configPath)\n }\n retryPlaywrightArgs.push(...retryArgs)\n\n try {\n console.warn(`${retryLogLabel} Starting fresh-worker retry`)\n await runPlaywrightOnce({\n launcher,\n args: retryPlaywrightArgs,\n env: retryEnv,\n outputMode: \"line\",\n bufferOutput: true,\n successMessage: null,\n failureMessage: `${retryLogLabel} Playwright failed`,\n stdoutLinePrefix: formatPlaywrightRetryLinePrefix({\n failedFile,\n stream: \"stdout\",\n }),\n stderrLinePrefix: formatPlaywrightRetryLinePrefix({\n failedFile,\n stream: \"stderr\",\n }),\n })\n } catch (retryError) {\n lastError = retryError\n failedAgain.add(failedFile)\n }\n }\n }\n\n await Promise.all(\n Array.from(\n { length: Math.max(1, Math.min(retryConcurrency, failedFiles.length)) },\n () => runNext(),\n ),\n )\n\n return {\n failedFiles: failedFiles.filter((failedFile) => failedAgain.has(failedFile)),\n lastError,\n }\n}\n\nasync function readJson(filePath: string): Promise<any | null> {\n try {\n const raw = await fsPromises.readFile(filePath, \"utf8\")\n return JSON.parse(raw)\n } catch {\n return null\n }\n}\n\nfunction ensureJsxRuntimeShim(projectRoot: string): void {\n const shimDir = path.join(projectRoot, \"node_modules\", \"playwright\")\n fs.mkdirSync(shimDir, { recursive: true })\n const shims = [\n { file: \"jsx-runtime.js\", target: \"react/jsx-runtime\" },\n { file: \"jsx-dev-runtime.js\", target: \"react/jsx-dev-runtime\" },\n ]\n\n for (const { file, target } of shims) {\n const filePath = path.join(shimDir, file)\n if (!fs.existsSync(filePath)) {\n const content = `export * from \"${target}\";\\nexport { default } from \"${target}\";\\n`\n fs.writeFileSync(filePath, content, \"utf8\")\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"playwright.js","names":[],"sources":["../../src/runners/playwright.ts"],"sourcesContent":["import fs from \"node:fs\"\nimport fsPromises from \"node:fs/promises\"\nimport path from \"node:path\"\nimport { createRequire } from \"node:module\"\nimport { fileURLToPath } from \"node:url\"\n\nimport { spawnAndCaptureStdout, spawnWithLogs, withRegisterShim, type SpawnLauncher } from \"./process\"\n\n\nconst require = createRequire(import.meta.url)\nconst moduleDir = path.dirname(fileURLToPath(import.meta.url))\n\nconst COMBINED_COVERAGE_ENV_VAR = \"RB_TEST_COMBINED_COVERAGE\"\nconst PLAYWRIGHT_RESULTS_FILE = path.join(process.cwd(), \"build\", \"playwright\", \"results.json\")\n\ntype PlaywrightReportSummary = {\n failedFiles: string[]\n}\n\ntype PlaywrightRuntimeSettings = {\n retries: number | null\n workers: number | null\n}\n\nconst PLAYWRIGHT_OPTIONS_WITH_REQUIRED_VALUE = new Set([\n \"--browser\",\n \"--config\",\n \"-c\",\n \"--grep\",\n \"-g\",\n \"--grep-invert\",\n \"--global-timeout\",\n \"--max-failures\",\n \"--output\",\n \"--project\",\n \"--repeat-each\",\n \"--reporter\",\n \"--retries\",\n \"--shard\",\n \"--timeout\",\n \"--trace\",\n \"--tsconfig\",\n \"--workers\",\n \"-j\",\n])\n\nconst PLAYWRIGHT_OPTIONS_WITH_OPTIONAL_VALUE = new Set([\n \"--only-changed\",\n \"--update-snapshots\",\n \"-u\",\n])\n\nconst PLAYWRIGHT_OPTIONS_TO_REMOVE_FOR_WORKER_RETRY = new Set([\n \"--last-failed\",\n \"--only-changed\",\n \"--output\",\n \"--retries\",\n \"--pass-with-no-tests\",\n \"--reporter\",\n \"--workers\",\n \"-j\",\n])\n\nconst PLAYWRIGHT_OPTIONS_TO_REMOVE_FOR_INITIAL_FRESH_RUN = new Set([\n \"--retries\",\n])\n\nconst PLAYWRIGHT_RETRY_LOG_LABEL_MAX_LENGTH = 20\n\nexport async function runPlaywright(\n userArgs: string[],\n { disableCoverage = false }: { disableCoverage?: boolean } = {},\n): Promise<void> {\n const configPath = fs.existsSync(\n path.join(process.cwd(), \"playwright.config.ts\"),\n )\n ? path.join(process.cwd(), \"playwright.config.ts\")\n : path.join(moduleDir, \"..\", \"playwright.config.ts\")\n\n const hasCustomConfig = userArgs.some((arg) => {\n if (arg === \"--config\" || arg === \"-c\") {\n return true\n }\n\n return arg.startsWith(\"--config=\")\n })\n\n ensureJsxRuntimeShim(process.cwd())\n const launcher = resolvePlaywrightLauncher()\n const env = withRegisterShim(process.env)\n env[COMBINED_COVERAGE_ENV_VAR] = \"1\"\n if (disableCoverage) {\n env.RB_DISABLE_COVERAGE = \"1\"\n }\n\n const runtimeSettings = await resolveFreshWorkerRetrySettings({\n launcher,\n configPath,\n hasCustomConfig,\n userArgs,\n env,\n })\n const configuredRetries = runtimeSettings.retries\n const retryConcurrency = Math.max(1, runtimeSettings.workers ?? 1)\n\n const resultsMtimeBeforeRun = getFileMtimeMs(PLAYWRIGHT_RESULTS_FILE)\n const initialRunArgs = buildPlaywrightInitialFreshWorkerArgs(userArgs)\n const initialPlaywrightArgs = [\"test\"]\n if (!hasCustomConfig) {\n initialPlaywrightArgs.push(\"--config\", configPath)\n }\n initialPlaywrightArgs.push(...initialRunArgs)\n\n try {\n await runPlaywrightOnce({\n launcher,\n args: initialPlaywrightArgs,\n env,\n })\n return\n } catch (error) {\n const summary = await readPlaywrightReportSummary(PLAYWRIGHT_RESULTS_FILE, resultsMtimeBeforeRun)\n if (!summary || configuredRetries <= 0 || summary.failedFiles.length === 0) {\n throw error\n }\n\n let lastError = error\n let failedFiles = summary.failedFiles\n const maxAttempts = configuredRetries\n\n for (let attempt = 1; attempt <= maxAttempts && failedFiles.length > 0; attempt += 1) {\n const activeRetryWorkers = Math.max(1, Math.min(retryConcurrency, failedFiles.length))\n console.warn(\n `[rb-test] Retrying ${failedFiles.length} failed Playwright file(s) with fresh workers (${attempt}/${maxAttempts}, up to ${activeRetryWorkers} in parallel)`,\n )\n const retryResults = await runPlaywrightRetryAttempt({\n launcher,\n userArgs,\n failedFiles,\n retryConcurrency: activeRetryWorkers,\n configPath,\n hasCustomConfig,\n env,\n attempt,\n })\n\n if (retryResults.lastError) {\n lastError = retryResults.lastError\n }\n failedFiles = retryResults.failedFiles\n }\n\n if (failedFiles.length === 0) {\n return\n }\n\n throw lastError\n }\n}\n\nfunction runPlaywrightOnce({\n launcher,\n args,\n env,\n outputMode = \"chunk\",\n bufferOutput = false,\n successMessage,\n failureMessage,\n stdoutLinePrefix,\n stderrLinePrefix,\n}: {\n launcher: SpawnLauncher\n args: string[]\n env: NodeJS.ProcessEnv\n outputMode?: \"chunk\" | \"line\"\n bufferOutput?: boolean\n successMessage?: string | null\n failureMessage?: string | null\n stdoutLinePrefix?: string\n stderrLinePrefix?: string\n}): Promise<void> {\n return spawnWithLogs({\n name: \"Playwright\",\n launcher,\n args,\n env,\n outputMode,\n bufferOutput,\n successMessage: successMessage === undefined ? \"Playwright suite passed!\" : successMessage ?? undefined,\n failureMessage: failureMessage === undefined ? \"Playwright failed\" : failureMessage ?? undefined,\n stdoutLinePrefix,\n stderrLinePrefix,\n })\n}\n\nfunction resolvePlaywrightLauncher(): SpawnLauncher {\n const cliPath = resolveCliPath()\n if (cliPath) {\n return {\n command: process.execPath,\n args: [cliPath],\n }\n }\n\n const localBin = path.resolve(process.cwd(), \"node_modules/.bin/playwright\")\n if (fs.existsSync(localBin)) {\n return {\n command: localBin,\n args: [],\n }\n }\n\n return {\n command: \"playwright\",\n args: [],\n }\n}\n\nfunction resolveCliPath(): string | null {\n const searchRoots = [process.cwd(), moduleDir]\n\n for (const base of searchRoots) {\n try {\n const pkgPath = require.resolve(\"@playwright/test/package.json\", { paths: [base] })\n const cliPath = path.join(path.dirname(pkgPath), \"cli.js\")\n if (fs.existsSync(cliPath)) {\n return cliPath\n }\n } catch (_error) {\n // Continue searching for a usable playwright launcher.\n }\n }\n\n return null\n}\n\nfunction buildPlaywrightWorkerRetryArgs(userArgs: string[], failedFiles: string[], attempt: number): string[] {\n const optionArgs = extractPlaywrightOptionArgs(userArgs)\n const sanitizedOptions = removePlaywrightOptions(optionArgs, PLAYWRIGHT_OPTIONS_TO_REMOVE_FOR_WORKER_RETRY)\n return [\n ...sanitizedOptions,\n \"--retries=0\",\n \"--workers=1\",\n \"--reporter=list\",\n \"--output\",\n buildPlaywrightRetryOutputDir(attempt, failedFiles),\n ...failedFiles,\n ]\n}\n\nfunction buildPlaywrightInitialFreshWorkerArgs(userArgs: string[]): string[] {\n const optionArgs = extractPlaywrightOptionArgs(userArgs)\n const sanitizedOptions = removePlaywrightOptions(optionArgs, PLAYWRIGHT_OPTIONS_TO_REMOVE_FOR_INITIAL_FRESH_RUN)\n const positionalArgs = extractPlaywrightPositionalArgs(userArgs)\n return [...sanitizedOptions, \"--retries=0\", ...positionalArgs]\n}\n\nasync function resolveFreshWorkerRetrySettings({\n launcher,\n configPath,\n hasCustomConfig,\n userArgs,\n env,\n}: {\n launcher: SpawnLauncher\n configPath: string\n hasCustomConfig: boolean\n userArgs: string[]\n env: NodeJS.ProcessEnv\n}): Promise<{ retries: number; workers: number | null }> {\n const configuredSettings = await probeConfiguredPlaywrightSettings({\n launcher,\n configPath,\n hasCustomConfig,\n userArgs,\n env,\n })\n\n return {\n retries: configuredSettings.retries ?? 0,\n workers: configuredSettings.workers,\n }\n}\n\nasync function probeConfiguredPlaywrightSettings({\n launcher,\n configPath,\n hasCustomConfig,\n userArgs,\n env,\n}: {\n launcher: SpawnLauncher\n configPath: string\n hasCustomConfig: boolean\n userArgs: string[]\n env: NodeJS.ProcessEnv\n}): Promise<PlaywrightRuntimeSettings> {\n const probeArgs = [\"test\"]\n if (!hasCustomConfig) {\n probeArgs.push(\"--config\", configPath)\n }\n probeArgs.push(\"--list\", \"--reporter=json\", ...extractPlaywrightProjectArgs(userArgs))\n\n try {\n const stdout = await spawnAndCaptureStdout({\n name: \"Playwright retries probe\",\n launcher,\n args: probeArgs,\n env,\n })\n const json = parseJsonObjectFromText(stdout)\n if (!json) {\n return { retries: null, workers: null }\n }\n return {\n retries: resolvePlaywrightRetriesFromReport(json),\n workers: resolvePlaywrightWorkersFromReport(json),\n }\n } catch (_error) {\n return { retries: null, workers: null }\n }\n}\n\nfunction extractPlaywrightProjectArgs(userArgs: string[]): string[] {\n const output: string[] = []\n for (let i = 0; i < userArgs.length; i += 1) {\n const arg = userArgs[i]\n if (arg === \"--\") {\n break\n }\n if (arg === \"--project\") {\n const next = userArgs[i + 1]\n if (next != null) {\n output.push(arg, next)\n i += 1\n }\n continue\n }\n if (arg.startsWith(\"--project=\")) {\n output.push(arg)\n }\n }\n return output\n}\n\nfunction parseJsonObjectFromText(input: string): any | null {\n try {\n return JSON.parse(input)\n } catch {\n const start = input.indexOf(\"{\")\n const end = input.lastIndexOf(\"}\")\n if (start === -1 || end === -1 || end <= start) {\n return null\n }\n try {\n return JSON.parse(input.slice(start, end + 1))\n } catch {\n return null\n }\n }\n}\n\nfunction extractPlaywrightPositionalArgs(userArgs: string[]): string[] {\n const output: string[] = []\n\n for (let i = 0; i < userArgs.length; i += 1) {\n const arg = userArgs[i]\n\n if (arg === \"--\") {\n break\n }\n\n if (!arg.startsWith(\"-\")) {\n output.push(arg)\n continue\n }\n\n if (arg.includes(\"=\")) {\n continue\n }\n\n if (PLAYWRIGHT_OPTIONS_WITH_REQUIRED_VALUE.has(arg)) {\n const next = userArgs[i + 1]\n if (next !== undefined) {\n i += 1\n }\n continue\n }\n\n if (PLAYWRIGHT_OPTIONS_WITH_OPTIONAL_VALUE.has(arg)) {\n const next = userArgs[i + 1]\n if (next !== undefined && !next.startsWith(\"-\")) {\n i += 1\n }\n }\n }\n\n return output\n}\n\nfunction removePlaywrightOptions(optionArgs: string[], optionsToRemove: Set<string>): string[] {\n const output: string[] = []\n for (let i = 0; i < optionArgs.length; i += 1) {\n const arg = optionArgs[i]\n const normalized = arg.split(\"=\")[0]\n if (!arg.startsWith(\"-\") || !optionsToRemove.has(normalized)) {\n output.push(arg)\n continue\n }\n\n if (arg.includes(\"=\")) {\n continue\n }\n\n if (PLAYWRIGHT_OPTIONS_WITH_REQUIRED_VALUE.has(normalized)) {\n const next = optionArgs[i + 1]\n if (next !== undefined) {\n i += 1\n }\n continue\n }\n\n if (PLAYWRIGHT_OPTIONS_WITH_OPTIONAL_VALUE.has(normalized)) {\n const next = optionArgs[i + 1]\n if (next !== undefined && !next.startsWith(\"-\")) {\n i += 1\n }\n }\n }\n return output\n}\n\nfunction extractPlaywrightOptionArgs(userArgs: string[]): string[] {\n const output: string[] = []\n\n for (let i = 0; i < userArgs.length; i += 1) {\n const arg = userArgs[i]\n\n if (arg === \"--\") {\n break\n }\n\n if (!arg.startsWith(\"-\")) {\n continue\n }\n\n output.push(arg)\n\n if (arg.includes(\"=\")) {\n continue\n }\n\n if (PLAYWRIGHT_OPTIONS_WITH_REQUIRED_VALUE.has(arg)) {\n const next = userArgs[i + 1]\n if (next !== undefined) {\n output.push(next)\n i += 1\n }\n continue\n }\n\n if (PLAYWRIGHT_OPTIONS_WITH_OPTIONAL_VALUE.has(arg)) {\n const next = userArgs[i + 1]\n if (next !== undefined && !next.startsWith(\"-\")) {\n output.push(next)\n i += 1\n }\n }\n }\n\n return output\n}\n\nasync function readPlaywrightReportSummary(\n resultsFilePath: string,\n newerThanMtimeMs: number | null,\n): Promise<PlaywrightReportSummary | null> {\n const stats = await fsPromises.stat(resultsFilePath).catch(() => null)\n if (!stats) {\n return null\n }\n\n if (newerThanMtimeMs != null && stats.mtimeMs <= newerThanMtimeMs) {\n return null\n }\n\n const data = await readJson(resultsFilePath)\n if (!data || typeof data !== \"object\") {\n return null\n }\n\n return {\n failedFiles: resolveFailedPlaywrightFiles(data),\n }\n}\n\nfunction getFileMtimeMs(filePath: string): number | null {\n try {\n return fs.statSync(filePath).mtimeMs\n } catch {\n return null\n }\n}\n\nfunction resolvePlaywrightRetriesFromReport(data: any): number {\n const projects = Array.isArray(data?.config?.projects) ? data.config.projects : []\n const retriesFromProjects = projects\n .map((project: any) => Number(project?.retries))\n .filter((value: number) => Number.isFinite(value))\n .map((value: number) => Math.max(0, Math.floor(value)))\n\n if (retriesFromProjects.length > 0) {\n return Math.max(...retriesFromProjects)\n }\n\n const fallback = Number(data?.config?.retries)\n if (Number.isFinite(fallback)) {\n return Math.max(0, Math.floor(fallback))\n }\n\n return 0\n}\n\nfunction resolvePlaywrightWorkersFromReport(data: any): number | null {\n const configWorkers = Number(data?.config?.workers)\n if (Number.isFinite(configWorkers)) {\n return Math.max(1, Math.floor(configWorkers))\n }\n\n const projects = Array.isArray(data?.config?.projects) ? data.config.projects : []\n const workersFromProjects = projects\n .map((project: any) => Number(project?.metadata?.actualWorkers ?? project?.workers))\n .filter((value: number) => Number.isFinite(value))\n .map((value: number) => Math.max(1, Math.floor(value)))\n\n if (workersFromProjects.length > 0) {\n return Math.max(...workersFromProjects)\n }\n\n return null\n}\n\nfunction resolveFailedPlaywrightFiles(data: any): string[] {\n const suites = Array.isArray(data?.suites) ? data.suites : []\n const rootDir = typeof data?.config?.rootDir === \"string\" ? data.config.rootDir : null\n const failedFiles = new Set<string>()\n\n for (const suite of suites) {\n collectFailedPlaywrightFiles(suite, failedFiles, rootDir)\n }\n\n return Array.from(failedFiles).sort()\n}\n\nfunction collectFailedPlaywrightFiles(suite: any, output: Set<string>, rootDir: string | null): void {\n const specs = Array.isArray(suite?.specs) ? suite.specs : []\n\n for (const spec of specs) {\n if (isPlaywrightSpecSuccessful(spec)) {\n continue\n }\n const file = normalizePlaywrightReportFile(spec?.file ?? suite?.file, rootDir)\n if (file) {\n output.add(file)\n }\n }\n\n const innerSuites = Array.isArray(suite?.suites) ? suite.suites : []\n for (const innerSuite of innerSuites) {\n collectFailedPlaywrightFiles(innerSuite, output, rootDir)\n }\n}\n\nfunction isPlaywrightSpecSuccessful(spec: any): boolean {\n if (typeof spec?.ok === \"boolean\") {\n return spec.ok\n }\n\n const tests = Array.isArray(spec?.tests) ? spec.tests : []\n if (tests.length === 0) {\n return false\n }\n\n return tests.every((test: any) => {\n const testStatus = String(test?.status ?? \"\")\n if (testStatus === \"expected\" || testStatus === \"skipped\" || testStatus === \"flaky\") {\n return true\n }\n\n const results = Array.isArray(test?.results) ? test.results : []\n if (results.length === 0) {\n return false\n }\n return results.every((result: any) => result?.status === \"passed\" || result?.status === \"skipped\")\n })\n}\n\nfunction normalizePlaywrightReportFile(filePath: unknown, rootDir: string | null): string | null {\n const raw = String(filePath ?? \"\").trim()\n if (!raw) {\n return null\n }\n\n let absolutePath: string\n if (path.isAbsolute(raw)) {\n absolutePath = path.normalize(raw)\n } else {\n const cwdCandidate = path.resolve(process.cwd(), raw)\n const rootCandidate = rootDir ? path.resolve(rootDir, raw) : null\n if (rootCandidate && fs.existsSync(rootCandidate)) {\n absolutePath = rootCandidate\n } else if (fs.existsSync(cwdCandidate)) {\n absolutePath = cwdCandidate\n } else {\n absolutePath = rootCandidate ?? cwdCandidate\n }\n }\n\n const relative = path.relative(process.cwd(), absolutePath)\n if (relative === \"\" || (!relative.startsWith(\"..\") && !path.isAbsolute(relative))) {\n return toPosixPath(relative || raw)\n }\n\n return toPosixPath(raw)\n}\n\nfunction toPosixPath(input: unknown): string {\n return String(input ?? \"\").replaceAll(\"\\\\\", \"/\").split(path.sep).join(\"/\")\n}\n\nfunction buildPlaywrightRetryOutputDir(attempt: number, failedFiles: string[]): string {\n const slug = failedFiles\n .map((file) => toPosixPath(file).replace(/[^a-zA-Z0-9._/-]+/g, \"-\").replace(/\\//g, \"__\"))\n .join(\"--\")\n return toPosixPath(path.join(\"build\", \"playwright\", \"test-results\", \"rb-retries\", `attempt-${attempt}`, slug))\n}\n\nexport function createPlaywrightRetryEnv(baseEnv: NodeJS.ProcessEnv): NodeJS.ProcessEnv {\n return {\n ...baseEnv,\n PLAYWRIGHT_FORCE_TTY: \"false\",\n }\n}\n\nfunction truncatePlaywrightRetryLogLabel(label: string, maxLength = PLAYWRIGHT_RETRY_LOG_LABEL_MAX_LENGTH): string {\n if (label.length <= maxLength) {\n return label\n }\n\n if (maxLength <= 3) {\n return \".\".repeat(Math.max(0, maxLength))\n }\n\n const visibleChars = maxLength - 3\n const startLength = Math.ceil(visibleChars / 2)\n const endLength = Math.floor(visibleChars / 2)\n\n return `${label.slice(0, startLength)}...${label.slice(-endLength)}`\n}\n\nfunction getPlaywrightRetryLogName(failedFile: string): string {\n const normalizedFile = toPosixPath(failedFile)\n const relativeFile = normalizedFile.startsWith(\"build/spec/\")\n ? normalizedFile.slice(\"build/spec/\".length)\n : normalizedFile\n const strippedBaseName = relativeFile\n .replace(/\\.(spec|test)\\.[^.]+$/i, \"\")\n .replace(/\\.[^.]+$/i, \"\")\n .trim()\n\n return strippedBaseName || relativeFile || normalizedFile\n}\n\nfunction formatPlaywrightRetryBracketLabel({\n failedFile,\n suffix = \"\",\n}: {\n failedFile: string\n suffix?: string\n}): string {\n const label = truncatePlaywrightRetryLogLabel(\n getPlaywrightRetryLogName(failedFile),\n Math.max(1, PLAYWRIGHT_RETRY_LOG_LABEL_MAX_LENGTH - suffix.length),\n )\n return `[${label}${suffix}]`\n}\n\nexport function formatPlaywrightRetryLogLabel({\n failedFile,\n}: {\n failedFile: string\n}): string {\n return formatPlaywrightRetryBracketLabel({ failedFile })\n}\n\nexport function formatPlaywrightRetryLinePrefix({\n failedFile,\n stream,\n}: {\n failedFile: string\n stream: \"stdout\" | \"stderr\"\n}): string {\n return stream === \"stderr\"\n ? `${formatPlaywrightRetryBracketLabel({ failedFile, suffix: \" stderr\" })} `\n : `${formatPlaywrightRetryLogLabel({ failedFile })} `\n}\n\nasync function runPlaywrightRetryAttempt({\n launcher,\n userArgs,\n failedFiles,\n retryConcurrency,\n configPath,\n hasCustomConfig,\n env,\n attempt,\n}: {\n launcher: SpawnLauncher\n userArgs: string[]\n failedFiles: string[]\n retryConcurrency: number\n configPath: string\n hasCustomConfig: boolean\n env: NodeJS.ProcessEnv\n attempt: number\n}): Promise<{ failedFiles: string[]; lastError: unknown }> {\n const failedAgain = new Set<string>()\n let lastError: unknown = null\n let nextIndex = 0\n const retryEnv = createPlaywrightRetryEnv(env)\n\n async function runNext(): Promise<void> {\n while (nextIndex < failedFiles.length) {\n const fileIndex = nextIndex\n nextIndex += 1\n\n const failedFile = failedFiles[fileIndex]\n const retryLogLabel = formatPlaywrightRetryLogLabel({\n failedFile,\n })\n const retryArgs = buildPlaywrightWorkerRetryArgs(userArgs, [failedFile], attempt)\n const retryPlaywrightArgs = [\"test\"]\n if (!hasCustomConfig) {\n retryPlaywrightArgs.push(\"--config\", configPath)\n }\n retryPlaywrightArgs.push(...retryArgs)\n\n try {\n console.warn(`${retryLogLabel} Starting fresh-worker retry`)\n await runPlaywrightOnce({\n launcher,\n args: retryPlaywrightArgs,\n env: retryEnv,\n outputMode: \"line\",\n bufferOutput: true,\n successMessage: null,\n failureMessage: `${retryLogLabel} Playwright failed`,\n stdoutLinePrefix: formatPlaywrightRetryLinePrefix({\n failedFile,\n stream: \"stdout\",\n }),\n stderrLinePrefix: formatPlaywrightRetryLinePrefix({\n failedFile,\n stream: \"stderr\",\n }),\n })\n } catch (retryError) {\n lastError = retryError\n failedAgain.add(failedFile)\n }\n }\n }\n\n await Promise.all(\n Array.from(\n { length: Math.max(1, Math.min(retryConcurrency, failedFiles.length)) },\n () => runNext(),\n ),\n )\n\n return {\n failedFiles: failedFiles.filter((failedFile) => failedAgain.has(failedFile)),\n lastError,\n }\n}\n\nasync function readJson(filePath: string): Promise<any | null> {\n try {\n const raw = await fsPromises.readFile(filePath, \"utf8\")\n return JSON.parse(raw)\n } catch {\n return null\n }\n}\n\nfunction ensureJsxRuntimeShim(projectRoot: string): void {\n const shimDir = path.join(projectRoot, \"node_modules\", \"playwright\")\n fs.mkdirSync(shimDir, { recursive: true })\n const shims = [\n { file: \"jsx-runtime.js\", target: \"react/jsx-runtime\" },\n { file: \"jsx-dev-runtime.js\", target: \"react/jsx-dev-runtime\" },\n ]\n\n for (const { file, target } of shims) {\n const filePath = path.join(shimDir, file)\n if (!fs.existsSync(filePath)) {\n const content = `export * from \"${target}\";\\nexport { default } from \"${target}\";\\n`\n fs.writeFileSync(filePath, content, \"utf8\")\n }\n }\n}\n"],"mappings":"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"}
@@ -18,20 +18,24 @@ function spawnWithLogs({ name, launcher, args, env, successMessage, failureMessa
18
18
  const stderrForwarder = createOutputForwarder(stderrStream, outputMode, stderrLinePrefix);
19
19
  child.stdout?.on("data", (data) => {
20
20
  const text = data.toString();
21
- if (!isAider) if (bufferOutput) bufferedOutput.push({
22
- stream: "stdout",
23
- text
24
- });
25
- else stdoutForwarder.write(text);
21
+ if (!isAider) {
22
+ if (bufferOutput) bufferedOutput.push({
23
+ stream: "stdout",
24
+ text
25
+ });
26
+ else stdoutForwarder.write(text);
27
+ }
26
28
  stdoutBuffer.push(text);
27
29
  });
28
30
  child.stderr?.on("data", (data) => {
29
31
  const text = data.toString();
30
- if (!isAider) if (bufferOutput) bufferedOutput.push({
31
- stream: "stderr",
32
- text
33
- });
34
- else stderrForwarder.write(text);
32
+ if (!isAider) {
33
+ if (bufferOutput) bufferedOutput.push({
34
+ stream: "stderr",
35
+ text
36
+ });
37
+ else stderrForwarder.write(text);
38
+ }
35
39
  stderrBuffer.push(text);
36
40
  });
37
41
  child.on("close", (code) => {
@@ -1 +1 @@
1
- {"version":3,"file":"process.js","names":["spawn","path","fileURLToPath","moduleDir","dirname","import","meta","url","isAider","process","env","IS_AIDER","SpawnLauncher","command","args","SpawnOutputMode","BufferedOutputChunk","stream","text","OutputStream","Pick","NodeJS","WritableStream","queuedOutputWrite","Promise","resolve","spawnWithLogs","name","launcher","successMessage","failureMessage","outputMode","stdoutLinePrefix","stderrLinePrefix","bufferOutput","stdoutStream","stdout","stderrStream","stderr","ProcessEnv","reject","stdoutBuffer","stderrBuffer","bufferedOutput","child","shell","stdoutForwarder","createOutputForwarder","stderrForwarder","on","data","toString","push","write","code","flushBufferedOutput","flush","pendingWrites","then","console","log","error","length","join","Error","spawnAndCaptureStdout","withRegisterShim","baseEnv","nodeOptions","appendNodeRequire","NODE_OPTIONS","existing","modulePath","flag","prefixOutputLine","line","prefix","endsWith","slice","ReturnType","chunk","linePrefix","pendingLine","Buffer","queueStreamWrite","newlineIndex","indexOf","nextLine","catch","undefined"],"sources":["../../src/runners/process.ts"],"sourcesContent":["import { spawn } from \"node:child_process\"\nimport path from \"node:path\"\nimport { fileURLToPath } from \"node:url\"\n\n\nconst moduleDir = path.dirname(fileURLToPath(import.meta.url))\nconst isAider = process.env.IS_AIDER === \"yes\"\n\nexport type SpawnLauncher = {\n command: string\n args?: string[]\n}\n\ntype SpawnOutputMode = \"chunk\" | \"line\"\ntype BufferedOutputChunk = {\n stream: \"stdout\" | \"stderr\"\n text: string\n}\ntype OutputStream = Pick<NodeJS.WritableStream, \"write\">\n\nlet queuedOutputWrite: Promise<void> = Promise.resolve()\n\nexport function spawnWithLogs({\n name,\n launcher,\n args,\n env,\n successMessage,\n failureMessage,\n outputMode = \"chunk\",\n stdoutLinePrefix,\n stderrLinePrefix,\n bufferOutput = false,\n stdoutStream = process.stdout,\n stderrStream = process.stderr,\n}: {\n name: string\n launcher: SpawnLauncher\n args: string[]\n env: NodeJS.ProcessEnv\n successMessage?: string\n failureMessage?: string\n outputMode?: SpawnOutputMode\n stdoutLinePrefix?: string\n stderrLinePrefix?: string\n bufferOutput?: boolean\n stdoutStream?: OutputStream\n stderrStream?: OutputStream\n}): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const stdoutBuffer: string[] = []\n const stderrBuffer: string[] = []\n const bufferedOutput: BufferedOutputChunk[] = []\n\n const child = spawn(\n launcher.command,\n [...(launcher.args || []), ...args],\n {\n shell: false,\n env,\n },\n )\n\n const stdoutForwarder = createOutputForwarder(stdoutStream, outputMode, stdoutLinePrefix)\n const stderrForwarder = createOutputForwarder(stderrStream, outputMode, stderrLinePrefix)\n\n child.stdout?.on(\"data\", (data) => {\n const text = data.toString()\n if (!isAider) {\n if (bufferOutput) {\n bufferedOutput.push({ stream: \"stdout\", text })\n } else {\n stdoutForwarder.write(text)\n }\n }\n stdoutBuffer.push(text)\n })\n\n child.stderr?.on(\"data\", (data) => {\n const text = data.toString()\n if (!isAider) {\n if (bufferOutput) {\n bufferedOutput.push({ stream: \"stderr\", text })\n } else {\n stderrForwarder.write(text)\n }\n }\n stderrBuffer.push(text)\n })\n\n child.on(\"close\", (code) => {\n if (!isAider) {\n if (bufferOutput) {\n flushBufferedOutput(bufferedOutput, stdoutForwarder, stderrForwarder)\n }\n stdoutForwarder.flush()\n stderrForwarder.flush()\n }\n\n const pendingWrites = queuedOutputWrite\n pendingWrites.then(() => {\n if (code === 0) {\n if (successMessage) {\n console.log(successMessage)\n }\n resolve()\n } else {\n console.error(failureMessage || `${name} failed:`)\n\n if (isAider) {\n if (stdoutBuffer.length > 0) {\n console.error(stdoutBuffer.join(\"\"))\n }\n\n if (stderrBuffer.length > 0) {\n console.error(stderrBuffer.join(\"\"))\n }\n }\n\n reject(new Error(`${name} failed with exit code: ${code}`))\n }\n })\n })\n\n child.on(\"error\", (error) => {\n console.error(`Error spawning ${name}:`, error)\n reject(error)\n })\n })\n}\n\nexport function spawnAndCaptureStdout({\n name,\n launcher,\n args,\n env,\n}: {\n name: string\n launcher: SpawnLauncher\n args: string[]\n env: NodeJS.ProcessEnv\n}): Promise<string> {\n return new Promise<string>((resolve, reject) => {\n const stdoutBuffer: string[] = []\n const stderrBuffer: string[] = []\n\n const child = spawn(\n launcher.command,\n [...(launcher.args || []), ...args],\n {\n shell: false,\n env,\n },\n )\n\n child.stdout?.on(\"data\", (data) => {\n stdoutBuffer.push(data.toString())\n })\n\n child.stderr?.on(\"data\", (data) => {\n stderrBuffer.push(data.toString())\n })\n\n child.on(\"close\", (code) => {\n if (code === 0) {\n resolve(stdoutBuffer.join(\"\"))\n } else {\n reject(new Error(`${name} failed with exit code: ${code}\\n${stderrBuffer.join(\"\")}`))\n }\n })\n\n child.on(\"error\", (error) => {\n reject(error)\n })\n })\n}\n\nexport function withRegisterShim(baseEnv: NodeJS.ProcessEnv): NodeJS.ProcessEnv {\n const nodeOptions = appendNodeRequire(baseEnv.NODE_OPTIONS, path.join(moduleDir, \"..\", \"register-tty.cjs\"))\n return {\n ...baseEnv,\n NODE_OPTIONS: nodeOptions,\n }\n}\n\nfunction appendNodeRequire(existing: string | undefined, modulePath: string): string {\n const flag = `--require=${modulePath}`\n if (!existing || existing.length === 0) {\n return flag\n }\n return `${existing} ${flag}`\n}\n\nexport function prefixOutputLine(line: string, prefix?: string): string {\n if (!prefix || line.length === 0) {\n return line\n }\n\n if (line.endsWith(\"\\n\")) {\n return `${prefix}${line.slice(0, -1)}\\n`\n }\n\n return `${prefix}${line}`\n}\n\nfunction flushBufferedOutput(\n bufferedOutput: BufferedOutputChunk[],\n stdoutForwarder: ReturnType<typeof createOutputForwarder>,\n stderrForwarder: ReturnType<typeof createOutputForwarder>,\n): void {\n for (const chunk of bufferedOutput) {\n if (chunk.stream === \"stderr\") {\n stderrForwarder.write(chunk.text)\n } else {\n stdoutForwarder.write(chunk.text)\n }\n }\n}\n\nfunction createOutputForwarder(stream: OutputStream, outputMode: SpawnOutputMode, linePrefix?: string) {\n let pendingLine = \"\"\n\n return {\n write(data: Buffer | string) {\n const text = data.toString()\n if (outputMode === \"chunk\" && !linePrefix) {\n queueStreamWrite(stream, text)\n return\n }\n\n pendingLine += text\n while (true) {\n const newlineIndex = pendingLine.indexOf(\"\\n\")\n if (newlineIndex === -1) {\n break\n }\n const nextLine = pendingLine.slice(0, newlineIndex + 1)\n pendingLine = pendingLine.slice(newlineIndex + 1)\n queueStreamWrite(stream, prefixOutputLine(nextLine, linePrefix))\n }\n },\n flush() {\n if (pendingLine.length === 0) {\n return\n }\n queueStreamWrite(stream, prefixOutputLine(pendingLine, linePrefix))\n pendingLine = \"\"\n },\n }\n}\n\nfunction queueStreamWrite(stream: OutputStream, text: string): void {\n queuedOutputWrite = queuedOutputWrite\n .then(() => new Promise<void>((resolve) => {\n stream.write(text, () => resolve())\n }))\n .catch(() => undefined)\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"process.js","names":[],"sources":["../../src/runners/process.ts"],"sourcesContent":["import { spawn } from \"node:child_process\"\nimport path from \"node:path\"\nimport { fileURLToPath } from \"node:url\"\n\n\nconst moduleDir = path.dirname(fileURLToPath(import.meta.url))\nconst isAider = process.env.IS_AIDER === \"yes\"\n\nexport type SpawnLauncher = {\n command: string\n args?: string[]\n}\n\ntype SpawnOutputMode = \"chunk\" | \"line\"\ntype BufferedOutputChunk = {\n stream: \"stdout\" | \"stderr\"\n text: string\n}\ntype OutputStream = Pick<NodeJS.WritableStream, \"write\">\n\nlet queuedOutputWrite: Promise<void> = Promise.resolve()\n\nexport function spawnWithLogs({\n name,\n launcher,\n args,\n env,\n successMessage,\n failureMessage,\n outputMode = \"chunk\",\n stdoutLinePrefix,\n stderrLinePrefix,\n bufferOutput = false,\n stdoutStream = process.stdout,\n stderrStream = process.stderr,\n}: {\n name: string\n launcher: SpawnLauncher\n args: string[]\n env: NodeJS.ProcessEnv\n successMessage?: string\n failureMessage?: string\n outputMode?: SpawnOutputMode\n stdoutLinePrefix?: string\n stderrLinePrefix?: string\n bufferOutput?: boolean\n stdoutStream?: OutputStream\n stderrStream?: OutputStream\n}): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const stdoutBuffer: string[] = []\n const stderrBuffer: string[] = []\n const bufferedOutput: BufferedOutputChunk[] = []\n\n const child = spawn(\n launcher.command,\n [...(launcher.args || []), ...args],\n {\n shell: false,\n env,\n },\n )\n\n const stdoutForwarder = createOutputForwarder(stdoutStream, outputMode, stdoutLinePrefix)\n const stderrForwarder = createOutputForwarder(stderrStream, outputMode, stderrLinePrefix)\n\n child.stdout?.on(\"data\", (data) => {\n const text = data.toString()\n if (!isAider) {\n if (bufferOutput) {\n bufferedOutput.push({ stream: \"stdout\", text })\n } else {\n stdoutForwarder.write(text)\n }\n }\n stdoutBuffer.push(text)\n })\n\n child.stderr?.on(\"data\", (data) => {\n const text = data.toString()\n if (!isAider) {\n if (bufferOutput) {\n bufferedOutput.push({ stream: \"stderr\", text })\n } else {\n stderrForwarder.write(text)\n }\n }\n stderrBuffer.push(text)\n })\n\n child.on(\"close\", (code) => {\n if (!isAider) {\n if (bufferOutput) {\n flushBufferedOutput(bufferedOutput, stdoutForwarder, stderrForwarder)\n }\n stdoutForwarder.flush()\n stderrForwarder.flush()\n }\n\n const pendingWrites = queuedOutputWrite\n pendingWrites.then(() => {\n if (code === 0) {\n if (successMessage) {\n console.log(successMessage)\n }\n resolve()\n } else {\n console.error(failureMessage || `${name} failed:`)\n\n if (isAider) {\n if (stdoutBuffer.length > 0) {\n console.error(stdoutBuffer.join(\"\"))\n }\n\n if (stderrBuffer.length > 0) {\n console.error(stderrBuffer.join(\"\"))\n }\n }\n\n reject(new Error(`${name} failed with exit code: ${code}`))\n }\n })\n })\n\n child.on(\"error\", (error) => {\n console.error(`Error spawning ${name}:`, error)\n reject(error)\n })\n })\n}\n\nexport function spawnAndCaptureStdout({\n name,\n launcher,\n args,\n env,\n}: {\n name: string\n launcher: SpawnLauncher\n args: string[]\n env: NodeJS.ProcessEnv\n}): Promise<string> {\n return new Promise<string>((resolve, reject) => {\n const stdoutBuffer: string[] = []\n const stderrBuffer: string[] = []\n\n const child = spawn(\n launcher.command,\n [...(launcher.args || []), ...args],\n {\n shell: false,\n env,\n },\n )\n\n child.stdout?.on(\"data\", (data) => {\n stdoutBuffer.push(data.toString())\n })\n\n child.stderr?.on(\"data\", (data) => {\n stderrBuffer.push(data.toString())\n })\n\n child.on(\"close\", (code) => {\n if (code === 0) {\n resolve(stdoutBuffer.join(\"\"))\n } else {\n reject(new Error(`${name} failed with exit code: ${code}\\n${stderrBuffer.join(\"\")}`))\n }\n })\n\n child.on(\"error\", (error) => {\n reject(error)\n })\n })\n}\n\nexport function withRegisterShim(baseEnv: NodeJS.ProcessEnv): NodeJS.ProcessEnv {\n const nodeOptions = appendNodeRequire(baseEnv.NODE_OPTIONS, path.join(moduleDir, \"..\", \"register-tty.cjs\"))\n return {\n ...baseEnv,\n NODE_OPTIONS: nodeOptions,\n }\n}\n\nfunction appendNodeRequire(existing: string | undefined, modulePath: string): string {\n const flag = `--require=${modulePath}`\n if (!existing || existing.length === 0) {\n return flag\n }\n return `${existing} ${flag}`\n}\n\nexport function prefixOutputLine(line: string, prefix?: string): string {\n if (!prefix || line.length === 0) {\n return line\n }\n\n if (line.endsWith(\"\\n\")) {\n return `${prefix}${line.slice(0, -1)}\\n`\n }\n\n return `${prefix}${line}`\n}\n\nfunction flushBufferedOutput(\n bufferedOutput: BufferedOutputChunk[],\n stdoutForwarder: ReturnType<typeof createOutputForwarder>,\n stderrForwarder: ReturnType<typeof createOutputForwarder>,\n): void {\n for (const chunk of bufferedOutput) {\n if (chunk.stream === \"stderr\") {\n stderrForwarder.write(chunk.text)\n } else {\n stdoutForwarder.write(chunk.text)\n }\n }\n}\n\nfunction createOutputForwarder(stream: OutputStream, outputMode: SpawnOutputMode, linePrefix?: string) {\n let pendingLine = \"\"\n\n return {\n write(data: Buffer | string) {\n const text = data.toString()\n if (outputMode === \"chunk\" && !linePrefix) {\n queueStreamWrite(stream, text)\n return\n }\n\n pendingLine += text\n while (true) {\n const newlineIndex = pendingLine.indexOf(\"\\n\")\n if (newlineIndex === -1) {\n break\n }\n const nextLine = pendingLine.slice(0, newlineIndex + 1)\n pendingLine = pendingLine.slice(newlineIndex + 1)\n queueStreamWrite(stream, prefixOutputLine(nextLine, linePrefix))\n }\n },\n flush() {\n if (pendingLine.length === 0) {\n return\n }\n queueStreamWrite(stream, prefixOutputLine(pendingLine, linePrefix))\n pendingLine = \"\"\n },\n }\n}\n\nfunction queueStreamWrite(stream: OutputStream, text: string): void {\n queuedOutputWrite = queuedOutputWrite\n .then(() => new Promise<void>((resolve) => {\n stream.write(text, () => resolve())\n }))\n .catch(() => undefined)\n}\n"],"mappings":"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"}