export interface PagePath { pathname: string; filepath: Filepath | undefined; chunkName?: string; params: { [index: string]: string }; } export function pathToImport(pages: string[], pathname: string): PagePath | undefined { const parsed = pages.map(parseFilepath); const psegs = pathSegments(pathname); const match = matchExact(parsed, psegs) || matchIndex(parsed, psegs) || matchParam(parsed, psegs) || matchFallback(parsed, psegs); return { pathname, filepath: match, chunkName: match && chunkName(match.raw), params: {}, }; } export interface Filepath { raw: string; segments: string[]; params: string[]; } function parseFilepath(filepath: string): Filepath { const stripped = filepath.slice(0, -4); const segments = stripped.split('/').map(camelToKebab); const params: string[] = []; segments.forEach((seg) => { const m = seg.match(/^\[(.+?)\]$/); if (m) { params.push(m[1]); } }); return { raw: filepath, segments, params, }; } function matchExact(files: Filepath[], path_segments: string[]): Filepath | undefined { return files.find((file) => { return ( file.segments.length === path_segments.length && file.segments.every((seg, index) => seg === path_segments[index]) ); }); } function matchIndex(files: Filepath[], path_segments: string[]): Filepath | undefined { const with_index = path_segments.concat('index'); return matchExact(files, with_index); } /** * Try to match when items are replaced with params * @param files * @param path_segments */ function matchParam(files: Filepath[], path_segments: string[]): Filepath | undefined { const subset = files .filter((file) => file.segments.length === path_segments.length && file.params.length > 0) .find((file) => { return file.segments.every((seg, index) => { const isParam = seg[0] === '['; if (seg === path_segments[index] || isParam) { return true; } }); }); if (subset) { return subset; } if (path_segments[path_segments.length - 1] !== 'index') { return matchParam(files, path_segments.concat('index')); } return undefined; } /** * Try to match to a root-level fallback * @param files * @param path_segments */ function matchFallback(files: Filepath[], path_segments: string[]): Filepath | undefined { const subset = files.find((file) => file.segments.length === 1 && file.params.length === 1); if (subset) { return subset; } return undefined; } function camelToKebab(string: string) { return string .replace(/([a-z0-9])([A-Z])/g, '$1-$2') .replace(/([A-Z])([A-Z])(?=[a-z])/g, '$1-$2') .toLowerCase(); } function pathSegments(pathname: string): string[] { return pathname .slice(1) .split('/') .map((x) => x.toLowerCase()) .filter(Boolean); } function chunkName(raw: string): string { const without_ext = raw.slice(0, -4); return without_ext.replace(/\//g, '-').replace(/\[/g, '').replace(/\]/g, '') + '_Page'; }