{"version":3,"file":"createRouteManifest.js","sources":["../../../../src/config/manifest/createRouteManifest.ts"],"sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\nimport type { RouteInfo, RouteManifest } from './types';\n\nexport type CreateRouteManifestOptions = {\n // For starters we only support app router\n appDirPath?: string;\n /**\n * Whether to include route groups (e.g., (auth-layout)) in the final route paths.\n * By default, route groups are stripped from paths following Next.js convention.\n */\n includeRouteGroups?: boolean;\n /**\n * Base path for the application, if any. This will be prefixed to all routes.\n */\n basePath?: string;\n};\n\nlet manifestCache: RouteManifest | null = null;\nlet lastAppDirPath: string | null = null;\nlet lastIncludeRouteGroups: boolean | undefined = undefined;\n\nfunction isPageFile(filename: string): boolean {\n return filename === 'page.tsx' || filename === 'page.jsx' || filename === 'page.ts' || filename === 'page.js';\n}\n\nfunction isRouteGroup(name: string): boolean {\n return name.startsWith('(') && name.endsWith(')');\n}\n\nfunction normalizeRouteGroupPath(routePath: string): string {\n // Remove route group segments from the path\n // Using positive lookahead with (?=[^)\\/]*\\)) to avoid polynomial matching\n return routePath.replace(/\\/\\((?=[^)/]*\\))[^)/]+\\)/g, '');\n}\n\nfunction getDynamicRouteSegment(name: string): string {\n if (name.startsWith('[[...') && name.endsWith(']]')) {\n // Optional catchall: [[...param]]\n const paramName = name.slice(5, -2); // Remove [[... and ]]\n return `:${paramName}*?`; // Mark with ? as optional\n } else if (name.startsWith('[...') && name.endsWith(']')) {\n // Required catchall: [...param]\n const paramName = name.slice(4, -1); // Remove [... and ]\n return `:${paramName}*`;\n }\n // Regular dynamic: [param]\n return `:${name.slice(1, -1)}`;\n}\n\nfunction buildRegexForDynamicRoute(routePath: string): {\n regex: string;\n paramNames: string[];\n hasOptionalPrefix: boolean;\n} {\n const segments = routePath.split('/').filter(Boolean);\n const regexSegments: string[] = [];\n const paramNames: string[] = [];\n let hasOptionalCatchall = false;\n\n for (const segment of segments) {\n if (segment.startsWith(':')) {\n const paramName = segment.substring(1);\n\n if (paramName.endsWith('*?')) {\n // Optional catchall: matches zero or more segments\n const cleanParamName = paramName.slice(0, -2);\n paramNames.push(cleanParamName);\n // Handling this special case in pattern construction below\n hasOptionalCatchall = true;\n } else if (paramName.endsWith('*')) {\n // Required catchall: matches one or more segments\n const cleanParamName = paramName.slice(0, -1);\n paramNames.push(cleanParamName);\n regexSegments.push('(.+)');\n } else {\n // Regular dynamic segment\n paramNames.push(paramName);\n regexSegments.push('([^/]+)');\n }\n } else {\n // Static segment - escape regex special characters including route group parentheses\n regexSegments.push(segment.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'));\n }\n }\n\n let pattern: string;\n if (hasOptionalCatchall) {\n if (regexSegments.length === 0) {\n // If the optional catchall happens at the root, accept any path starting\n // with a slash. Need capturing group for parameter extraction.\n pattern = '^/(.*)$';\n } else {\n // For optional catchall, make the trailing slash and segments optional\n // This allows matching both /catchall and /catchall/anything\n const staticParts = regexSegments.join('/');\n pattern = `^/${staticParts}(?:/(.*))?$`;\n }\n } else {\n pattern = `^/${regexSegments.join('/')}$`;\n }\n\n return { regex: pattern, paramNames, hasOptionalPrefix: hasOptionalPrefix(paramNames) };\n}\n\n/**\n * Detect if the first parameter is a common i18n prefix segment\n * Common patterns: locale, lang, language\n */\nfunction hasOptionalPrefix(paramNames: string[]): boolean {\n const firstParam = paramNames[0];\n if (firstParam === undefined) {\n return false;\n }\n\n return firstParam === 'locale' || firstParam === 'lang' || firstParam === 'language';\n}\n\n/**\n * Check if a page file exports generateStaticParams (ISR/SSG indicator)\n */\nfunction checkForGenerateStaticParams(pageFilePath: string): boolean {\n try {\n const content = fs.readFileSync(pageFilePath, 'utf8');\n // check for generateStaticParams export\n // the regex covers `export function generateStaticParams`, `export async function generateStaticParams`, `export const generateStaticParams`\n return /export\\s+(async\\s+)?function\\s+generateStaticParams|export\\s+const\\s+generateStaticParams/.test(content);\n } catch {\n return false;\n }\n}\n\nfunction scanAppDirectory(dir: string, basePath: string = '', includeRouteGroups: boolean = false): RouteManifest {\n const dynamicRoutes: RouteInfo[] = [];\n const staticRoutes: RouteInfo[] = [];\n const isrRoutes: string[] = [];\n\n try {\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n const pageFile = entries.find(entry => isPageFile(entry.name));\n\n if (pageFile) {\n // Conditionally normalize the path based on includeRouteGroups option\n const routePath = includeRouteGroups ? basePath || '/' : normalizeRouteGroupPath(basePath || '/');\n const isDynamic = routePath.includes(':');\n\n // Check if this page has generateStaticParams (ISR/SSG indicator)\n const pageFilePath = path.join(dir, pageFile.name);\n const hasGenerateStaticParams = checkForGenerateStaticParams(pageFilePath);\n\n if (hasGenerateStaticParams) {\n isrRoutes.push(routePath);\n }\n\n if (isDynamic) {\n const { regex, paramNames, hasOptionalPrefix } = buildRegexForDynamicRoute(routePath);\n dynamicRoutes.push({\n path: routePath,\n regex,\n paramNames,\n hasOptionalPrefix,\n });\n } else {\n staticRoutes.push({\n path: routePath,\n });\n }\n }\n\n for (const entry of entries) {\n if (entry.isDirectory()) {\n const fullPath = path.join(dir, entry.name);\n let routeSegment: string;\n\n const isDynamic = entry.name.startsWith('[') && entry.name.endsWith(']');\n const isRouteGroupDir = isRouteGroup(entry.name);\n\n if (isRouteGroupDir) {\n if (includeRouteGroups) {\n routeSegment = entry.name;\n } else {\n routeSegment = '';\n }\n } else if (isDynamic) {\n routeSegment = getDynamicRouteSegment(entry.name);\n } else {\n routeSegment = entry.name;\n }\n\n const newBasePath = routeSegment ? `${basePath}/${routeSegment}` : basePath;\n const subRoutes = scanAppDirectory(fullPath, newBasePath, includeRouteGroups);\n\n dynamicRoutes.push(...subRoutes.dynamicRoutes);\n staticRoutes.push(...subRoutes.staticRoutes);\n isrRoutes.push(...subRoutes.isrRoutes);\n }\n }\n } catch (error) {\n // eslint-disable-next-line no-console\n console.warn('Error building route manifest:', error);\n }\n\n return { dynamicRoutes, staticRoutes, isrRoutes };\n}\n\n/**\n * Returns a route manifest for the given app directory\n */\nexport function createRouteManifest(options?: CreateRouteManifestOptions): RouteManifest {\n let targetDir: string | undefined;\n\n if (options?.appDirPath) {\n targetDir = options.appDirPath;\n } else {\n const projectDir = process.cwd();\n const maybeAppDirPath = path.join(projectDir, 'app');\n const maybeSrcAppDirPath = path.join(projectDir, 'src', 'app');\n\n if (fs.existsSync(maybeAppDirPath) && fs.lstatSync(maybeAppDirPath).isDirectory()) {\n targetDir = maybeAppDirPath;\n } else if (fs.existsSync(maybeSrcAppDirPath) && fs.lstatSync(maybeSrcAppDirPath).isDirectory()) {\n targetDir = maybeSrcAppDirPath;\n }\n }\n\n if (!targetDir) {\n return {\n isrRoutes: [],\n dynamicRoutes: [],\n staticRoutes: [],\n };\n }\n\n // Check if we can use cached version\n if (manifestCache && lastAppDirPath === targetDir && lastIncludeRouteGroups === options?.includeRouteGroups) {\n return manifestCache;\n }\n\n const { dynamicRoutes, staticRoutes, isrRoutes } = scanAppDirectory(\n targetDir,\n options?.basePath,\n options?.includeRouteGroups,\n );\n\n const manifest: RouteManifest = {\n dynamicRoutes,\n staticRoutes,\n isrRoutes,\n };\n\n // set cache\n manifestCache = manifest;\n lastAppDirPath = targetDir;\n lastIncludeRouteGroups = options?.includeRouteGroups;\n\n return manifest;\n}\n"],"names":[],"mappings":"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"}