next-translate-routes-multi-domain
Version:
Flexible and translated routes for Next.js without custom server
105 lines (95 loc) • 3.63 kB
text/typescript
import fs from 'fs'
import { findPagesDir } from 'next/dist/lib/find-pages-dir'
import pathUtils from 'path'
import YAML from 'yamljs'
import { anyDynamicFilepathPartRegex, spreadFilepathPartRegex } from '../shared/regex'
import type { TRouteBranch, TRouteSegment, TRouteSegmentPaths, TRouteSegmentsData } from '../types'
import { fileNameToPath } from './fileNameToPaths'
import { isRoutesFileName } from './routesFiles'
/** Get path and path translations from name and all translations #childrenOrder */
const getRouteSegment = <L extends string>(
name: string,
routeSegmentsData: TRouteSegmentsData<L>,
isDirectory?: boolean,
): TRouteSegment<L> => {
const routeSegmentData = routeSegmentsData?.[isDirectory ? '/' : name]
const { default: defaultPath = fileNameToPath(name), ...localized } =
typeof routeSegmentData === 'object' ? routeSegmentData : { default: routeSegmentData }
const paths = {
default: defaultPath,
...localized,
} as TRouteSegmentPaths<L>
return {
name,
paths,
}
}
/** Attribute a weight to a route branch so that they can be sorted: the heaviest must be the last */
const getOrderWeight = ({ name, children }: TRouteBranch) => {
let weight = 0
;[spreadFilepathPartRegex.test(name), anyDynamicFilepathPartRegex.test(name), children?.length].forEach(
(condition) => {
if (condition) {
weight++
}
},
)
return weight
}
export type TParsePageTreeProps = {
directoryPath: string
pageExtensions: string[]
isSubBranch?: boolean
routesDataFileName?: string
}
/**
* Recursively parse pages directory and build a page tree object
*/
export const parsePages = <L extends string>({
directoryPath: propDirectoryPath,
pageExtensions,
isSubBranch,
routesDataFileName,
}: TParsePageTreeProps): TRouteBranch<L> => {
const directoryPath = propDirectoryPath || findPagesDir(process.cwd()).pages
const directoryItems = fs.readdirSync(directoryPath)
const routesFileName = directoryItems.find((directoryItem) => isRoutesFileName(directoryItem, routesDataFileName))
const routeSegmentsFileContent = routesFileName
? fs.readFileSync(pathUtils.join(directoryPath, routesFileName), { encoding: 'utf8' })
: ''
const routeSegmentsData = (
routeSegmentsFileContent
? (/\.yaml$/.test(routesFileName as string) ? YAML : JSON).parse(routeSegmentsFileContent)
: {}
) as TRouteSegmentsData<L>
const directoryPathParts = directoryPath.replace(/[\\/]/, '').split(/[\\/]/)
const name = isSubBranch ? directoryPathParts[directoryPathParts.length - 1] : ''
const children = directoryItems
.reduce((acc, item) => {
const isDirectory = fs.statSync(pathUtils.join(directoryPath, item)).isDirectory()
const pageMatch = item.match(new RegExp(`(.+)\\.(${pageExtensions.join('|')})$`))
const pageName = (!isDirectory && pageMatch?.[1]) || ''
if (!isSubBranch && (['_app', '_document', '_error', '404', '500'].includes(pageName) || item === 'api')) {
return acc
}
if (isDirectory || pageName) {
return [
...acc,
isDirectory
? parsePages({
directoryPath: pathUtils.join(directoryPath, item),
isSubBranch: true,
pageExtensions,
routesDataFileName,
})
: getRouteSegment(pageName || item, routeSegmentsData),
]
}
return acc
}, [] as TRouteBranch<L>[])
.sort((childA, childB) => getOrderWeight(childA) - getOrderWeight(childB))
return {
...getRouteSegment(name, routeSegmentsData, true),
children,
}
}