rsnext/packages/next/server/lib/find-page-file.ts
JJ Kasper e8a8220d49
Tweak routing tests (#36667)
Co-authored-by: Tim Neutkens <tim@timneutkens.nl>
2022-05-05 13:15:32 +02:00

62 lines
2 KiB
TypeScript

import { fileExists } from '../../lib/file-exists'
import { getPagePaths } from '../../shared/lib/page-path/get-page-paths'
import { nonNullable } from '../../lib/non-nullable'
import { join, sep, normalize } from 'path'
import { promises } from 'fs'
import { warn } from '../../build/output/log'
import chalk from '../../lib/chalk'
/**
* Finds a page file with the given parameters. If the page is duplicated with
* multiple extensions it will throw, otherwise it will return the *relative*
* path to the page file or null if it is not found.
*
* @param pagesDir Absolute path to the pages folder with trailing `/pages`.
* @param normalizedPagePath The page normalized (it will be denormalized).
* @param pageExtensions Array of page extensions.
*/
export async function findPageFile(
pagesDir: string,
normalizedPagePath: string,
pageExtensions: string[]
): Promise<string | null> {
const pagePaths = getPagePaths(normalizedPagePath, pageExtensions)
const [existingPath, ...others] = (
await Promise.all(
pagePaths.map(async (path) =>
(await fileExists(join(pagesDir, path))) ? path : null
)
)
).filter(nonNullable)
if (!existingPath) {
return null
}
if (!(await isTrueCasePagePath(existingPath, pagesDir))) {
return null
}
if (others.length > 0) {
warn(
`Duplicate page detected. ${chalk.cyan(
join('pages', existingPath)
)} and ${chalk.cyan(
join('pages', others[0])
)} both resolve to ${chalk.cyan(normalizedPagePath)}.`
)
}
return existingPath
}
async function isTrueCasePagePath(pagePath: string, pagesDir: string) {
const pageSegments = normalize(pagePath).split(sep).filter(Boolean)
const segmentExistsPromises = pageSegments.map(async (segment, i) => {
const segmentParentDir = join(pagesDir, ...pageSegments.slice(0, i))
const parentDirEntries = await promises.readdir(segmentParentDir)
return parentDirEntries.includes(segment)
})
return (await Promise.all(segmentExistsPromises)).every(Boolean)
}