.
This commit is contained in:
+139
@@ -0,0 +1,139 @@
|
||||
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 as fsPromises } from 'fs';
|
||||
import { warn } from '../../build/output/log';
|
||||
import { cyan } from '../../lib/picocolors';
|
||||
import { isMetadataRouteFile } from '../../lib/metadata/is-metadata-route';
|
||||
import { escapeStringRegexp } from '../../shared/lib/escape-regexp';
|
||||
async function isTrueCasePagePath(pagePath, pagesDir) {
|
||||
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 fsPromises.readdir(segmentParentDir);
|
||||
return parentDirEntries.includes(segment);
|
||||
});
|
||||
return (await Promise.all(segmentExistsPromises)).every(Boolean);
|
||||
}
|
||||
/**
|
||||
* 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, normalizedPagePath, pageExtensions, isAppDir) {
|
||||
const pagePaths = getPagePaths(normalizedPagePath, pageExtensions, isAppDir);
|
||||
const [existingPath, ...others] = (await Promise.all(pagePaths.map(async (path)=>{
|
||||
const filePath = join(pagesDir, path);
|
||||
try {
|
||||
return await fileExists(filePath) ? path : null;
|
||||
} catch (err) {
|
||||
var _err_code;
|
||||
if (!(err == null ? void 0 : (_err_code = err.code) == null ? void 0 : _err_code.includes('ENOTDIR'))) throw err;
|
||||
}
|
||||
return null;
|
||||
}))).filter(nonNullable);
|
||||
if (!existingPath) {
|
||||
return null;
|
||||
}
|
||||
if (!await isTrueCasePagePath(existingPath, pagesDir)) {
|
||||
return null;
|
||||
}
|
||||
if (others.length > 0) {
|
||||
warn(`Duplicate page detected. ${cyan(join('pages', existingPath))} and ${cyan(join('pages', others[0]))} both resolve to ${cyan(normalizedPagePath)}.`);
|
||||
}
|
||||
return existingPath;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* createValidFileMatcher receives configured page extensions and return helpers to determine:
|
||||
* `isLayoutsLeafPage`: if a file is a valid page file or routes file under app directory
|
||||
* `isTrackedFiles`: if it's a tracked file for our file watcher
|
||||
*
|
||||
*/ export function createValidFileMatcher(pageExtensions, appDirPath) {
|
||||
// Helper to create extension regex pattern
|
||||
const extPattern = `(?:${pageExtensions.map((extension)=>escapeStringRegexp(extension)).join('|')})`;
|
||||
// Pattern factory for "leaf" files that can appear at start of path or after separator
|
||||
// e.g., 'page.tsx', '/path/page.tsx', '\\path\\route.js'
|
||||
const createLeafPattern = (fileNames)=>{
|
||||
const names = fileNames.length === 1 ? fileNames[0] : `(${fileNames.join('|')})`;
|
||||
return new RegExp(`(^${names}|[\\\\/]${names})\\.${extPattern}$`);
|
||||
};
|
||||
// Pattern factory for root-only files (no path separator allowed)
|
||||
const createRootOnlyPattern = (fileName)=>new RegExp(`^${fileName}\\.${extPattern}$`);
|
||||
// All file matching patterns
|
||||
const validExtensionFileRegex = new RegExp(`\\.${extPattern}$`);
|
||||
const leafOnlyPageFileRegex = createLeafPattern([
|
||||
'page',
|
||||
'route'
|
||||
]);
|
||||
const leafOnlyRouteFileRegex = createLeafPattern([
|
||||
'route'
|
||||
]);
|
||||
const leafOnlyLayoutFileRegex = createLeafPattern([
|
||||
'layout'
|
||||
]);
|
||||
const leafOnlyDefaultFileRegex = createLeafPattern([
|
||||
'default'
|
||||
]);
|
||||
const rootNotFoundFileRegex = createRootOnlyPattern('not-found');
|
||||
/** TODO-METADATA: support other metadata routes
|
||||
* regex for:
|
||||
*
|
||||
* /robots.txt|<ext>
|
||||
* /sitemap.xml|<ext>
|
||||
* /favicon.ico
|
||||
* /manifest.json|<ext>
|
||||
* <route>/icon.png|jpg|<ext>
|
||||
* <route>/apple-touch-icon.png|jpg|<ext>
|
||||
*
|
||||
*/ /**
|
||||
* Match the file if it's a metadata route file, static: if the file is a static metadata file.
|
||||
* It needs to be a file which doesn't match the custom metadata routes e.g. `app/robots.txt/route.js`
|
||||
*/ function isMetadataFile(filePath) {
|
||||
const appDirRelativePath = appDirPath ? filePath.replace(appDirPath, '') : filePath;
|
||||
return isMetadataRouteFile(appDirRelativePath, pageExtensions, true);
|
||||
}
|
||||
// Determine if the file is leaf node page file or route file under layouts,
|
||||
// 'page.<extension>' | 'route.<extension>'
|
||||
function isAppRouterPage(filePath) {
|
||||
return leafOnlyPageFileRegex.test(filePath) || isMetadataFile(filePath);
|
||||
}
|
||||
// Determine if the file is leaf node route file under app directory
|
||||
function isAppRouterRoute(filePath) {
|
||||
return leafOnlyRouteFileRegex.test(filePath);
|
||||
}
|
||||
function isAppLayoutPage(filePath) {
|
||||
return leafOnlyLayoutFileRegex.test(filePath);
|
||||
}
|
||||
function isAppDefaultPage(filePath) {
|
||||
return leafOnlyDefaultFileRegex.test(filePath);
|
||||
}
|
||||
function isPageFile(filePath) {
|
||||
return validExtensionFileRegex.test(filePath) || isMetadataFile(filePath);
|
||||
}
|
||||
function isRootNotFound(filePath) {
|
||||
if (!appDirPath) {
|
||||
return false;
|
||||
}
|
||||
if (!filePath.startsWith(appDirPath + sep)) {
|
||||
return false;
|
||||
}
|
||||
const rest = filePath.slice(appDirPath.length + 1);
|
||||
return rootNotFoundFileRegex.test(rest);
|
||||
}
|
||||
return {
|
||||
isPageFile,
|
||||
isAppRouterPage,
|
||||
isAppRouterRoute,
|
||||
isAppLayoutPage,
|
||||
isAppDefaultPage,
|
||||
isMetadataFile,
|
||||
isRootNotFound
|
||||
};
|
||||
}
|
||||
|
||||
//# sourceMappingURL=find-page-file.js.map
|
||||
Reference in New Issue
Block a user