@hono-filebased-route/core
Version:
A core utility for file-based routing in Hono applications.
102 lines (85 loc) • 3.56 kB
text/typescript
import { writeFile } from 'fs/promises'
import {
getExportedHttpMethods,
getExportedMiddlewareHandler,
getFiles,
getRoutePath,
} from '../utils/load-routes-utils'
import path from 'path'
import { Config, METHODS } from '../types'
import { createLogger } from '../utils/logger'
const defaultConfig: Config = {
dir: './src/routes',
output: './src/generated-routes.ts',
write: true,
verbose: false,
externals: [],
typescript: true,
} as const
export async function generateRoutesFile(config?: Partial<Config>) {
const { dir, output, write, verbose, externals, typescript } = { ...defaultConfig, ...config }
const logger = createLogger(verbose)
logger.info(`Generating routes file..., ${dir}, ${output}`)
const absoluteRoutesDir = path.resolve(dir)
const files = await getFiles(absoluteRoutesDir, externals)
const importStatements: string[] = []
const routeDefinitions: string[] = []
importStatements.push(`import { Hono } from 'hono';`)
let counter = 0
for (const file of files) {
const routePath = getRoutePath(file, absoluteRoutesDir)
.replace(/\\/g, '/')
.replace(/\/index$/, '')
const relativePath = path
.relative(path.dirname(output), file)
.replace(/\.(ts)$/, '')
.replace(/\\/g, '/')
const moduleName = `routeModule${counter++}`
const exportedMethods = getExportedHttpMethods(file)
const middlewareHandler = getExportedMiddlewareHandler(file)
if (!exportedMethods.GET && !exportedMethods.POST) continue
importStatements.push(`import * as ${moduleName} from './${relativePath}';`)
const tempHonoVar = `honoApp${moduleName}`
routeDefinitions.push(` const ${tempHonoVar} = new Hono();`)
for (const method of METHODS) {
if (exportedMethods[method]) {
if (routePath.endsWith('/*')) {
const len = routePath.replace(/\/\*$/g, '').length + 1
if (!middlewareHandler[method])
routeDefinitions.push(
` ${tempHonoVar}.${method.toLowerCase()}('/', async (c) => ${moduleName}.${method}(c, c.req.path.substring(${len}).split('/')));`
)
else
routeDefinitions.push(
` ${tempHonoVar}.${method.toLowerCase()}('/', ${moduleName}.config${method}, async (c) => ${moduleName}.${method}(c, c.req.path.substring(${len}).split('/')));`
)
} else {
if (!middlewareHandler[method])
routeDefinitions.push(` ${tempHonoVar}.${method.toLowerCase()}('/', ${moduleName}.${method});`)
else
routeDefinitions.push(
` ${tempHonoVar}.${method.toLowerCase()}('/', ${moduleName}.config${method}, ${moduleName}.${method});`
)
}
logger.info(`Generated route: ${method} ${routePath}`)
}
}
routeDefinitions.push(` mainApp.route('${routePath}', ${tempHonoVar});`)
}
const fileContent = `
// THIS FILE IS AUTO-GENERATED BY scripts/generate-routes.ts. DO NOT EDIT.
${importStatements.join('\n')}
/**
* Registers all generated file-based routes to the main Hono application.
* @param mainApp The main Hono application instance.
*/
export function registerGeneratedRoutes(mainApp${typescript ? ': Hono' : ''}) {
${routeDefinitions.join('\n')}
}
`
if (write) {
await writeFile(output, fileContent.trimStart())
logger.info(`Generated routes file: ${output} with ${files.length} routes.`)
}
return fileContent.trimStart()
}