(plan: MigrationFilePlan, options: ApplyMigrationPlanOptions)
| 136 | } |
| 137 | |
| 138 | async function preflightPlanOutputs(plan: MigrationFilePlan, options: ApplyMigrationPlanOptions): Promise<void> { |
| 139 | const outputRoot = resolve(plan.outputRoot); |
| 140 | const canonicalOutputRoot = await canonicalFutureDirectory(outputRoot, 'outputRoot'); |
| 141 | const canonicalOutputs = new Set<string>(); |
| 142 | for (const { sourcePath, outputPath, result } of plan.files) { |
| 143 | if (result.status === 'refused') throw new Error(`Migration result was refused for source: ${sourcePath}`); |
| 144 | const resolvedOutputPath = resolve(outputPath); |
| 145 | if (resolvedOutputPath === outputRoot) throw new Error(`Output path must identify a file below outputRoot: ${outputPath}`); |
| 146 | assertContained(outputRoot, resolvedOutputPath, `Output path is outside outputRoot: ${outputPath}`); |
| 147 | const canonicalOutputPath = await canonicalFuturePath(resolvedOutputPath); |
| 148 | assertContained(canonicalOutputRoot, canonicalOutputPath, `Output path resolves outside outputRoot: ${outputPath}`); |
| 149 | if (canonicalOutputs.has(canonicalOutputPath)) throw new Error(`Duplicate output path: ${outputPath}`); |
| 150 | canonicalOutputs.add(canonicalOutputPath); |
| 151 | await assertWritableOutput(resolvedOutputPath, options.overwrite ?? false); |
| 152 | } |
| 153 | } |
| 154 | |
| 155 | async function assertWritableOutput(outputPath: string, overwrite: boolean): Promise<void> { |
| 156 | try { |
no test coverage detected