(rootPath: string, chunk: IndexedChunk)
| 68 | } |
| 69 | |
| 70 | function resolveAbsoluteChunkPath(rootPath: string, chunk: IndexedChunk): string | null { |
| 71 | const resolvedRoot = path.resolve(rootPath); |
| 72 | const isWithinRoot = (candidate: string): boolean => { |
| 73 | const resolvedCandidate = path.resolve(candidate); |
| 74 | const relative = path.relative(resolvedRoot, resolvedCandidate); |
| 75 | return Boolean(relative) && !relative.startsWith('..') && !path.isAbsolute(relative); |
| 76 | }; |
| 77 | |
| 78 | if (typeof chunk.filePath === 'string' && chunk.filePath.trim()) { |
| 79 | const raw = chunk.filePath.trim(); |
| 80 | if (path.isAbsolute(raw)) { |
| 81 | return isWithinRoot(raw) ? raw : null; |
| 82 | } |
| 83 | const resolved = path.resolve(resolvedRoot, raw); |
| 84 | return isWithinRoot(resolved) ? resolved : null; |
| 85 | } |
| 86 | |
| 87 | if (typeof chunk.relativePath === 'string' && chunk.relativePath.trim()) { |
| 88 | const resolved = path.resolve(resolvedRoot, chunk.relativePath.trim()); |
| 89 | return isWithinRoot(resolved) ? resolved : null; |
| 90 | } |
| 91 | |
| 92 | return null; |
| 93 | } |
| 94 | |
| 95 | async function fileExists(targetPath: string): Promise<boolean> { |
| 96 | try { |
no test coverage detected