UNPKG

universal-autorouter

Version:

An universal plugin that scans the file system and automatically loads to a server all routes in a target directory.

69 lines (65 loc) 2.85 kB
import fs from 'node:fs'; import path from 'node:path'; const countParams = (filepath) => { return (filepath.match(/\[(.*?)\]/gu) || []).length; }; const toPosix = (filepath) => { return filepath.replaceAll("\\", "/"); }; const sortRoutesByParams = (routes) => { return routes.sort((a, b) => countParams(a) - countParams(b)); }; const filepathToRoute = (filepath) => { return filepath.replace(/\.(ts|tsx|mjs|js|jsx|cjs)$/u, "").replaceAll(/\[\.\.\..*?\]/gu, "*").replaceAll(/\[(.+?)\]/gu, (_, match) => `:${match}`).replace(/\/?\((.*?)\)/, "").replaceAll("]-[", "-:").replaceAll("]/", "/").replaceAll(/\[|\]/gu, "").replace(/\/?index$/, ""); }; const DEFAULT_PATTERN = "**/*.{ts,tsx,mjs,js,jsx,cjs}"; const DEFAULT_ROUTES_DIR = "./api"; const DEFAULT_METHOD = "get"; var index = async (app, { pattern = DEFAULT_PATTERN, prefix = "", routesDir = DEFAULT_ROUTES_DIR, defaultMethod = DEFAULT_METHOD, viteDevServer, skipNoRoutes = false, skipImportErrors = false }) => { const entryDir = path.isAbsolute(routesDir) ? toPosix(routesDir) : path.posix.join(process.cwd(), routesDir); if (!fs.existsSync(entryDir)) { throw new Error(`Directory ${entryDir} doesn't exist`); } if (!fs.statSync(entryDir).isDirectory()) { throw new Error(`${entryDir} isn't a directory`); } const files = typeof Bun === "undefined" ? fs.globSync(pattern, { cwd: entryDir }) : [...new Bun.Glob(pattern).scanSync({ cwd: entryDir })]; if (files.length === 0 && !skipNoRoutes) { throw new Error(`No matches found in ${entryDir} (you can disable this error with 'skipFailGlob' option to true)`); } let _import; if (viteDevServer) { _import = (filepath) => viteDevServer.ssrLoadModule(filepath, { fixStacktrace: true }); } else if (process.platform === "win32") { const { pathToFileURL } = await import('node:url'); _import = (filepath) => import(pathToFileURL(filepath).href); } else { _import = (filepath) => import(filepath); } for (const file of sortRoutesByParams(files)) { const endFilepath = toPosix(file); const fullFilepath = `${entryDir}/${endFilepath}`; const { default: handler } = await _import(fullFilepath); if (!handler && !skipImportErrors) { throw new Error(`${fullFilepath} doesn't have default export (you can disable this error with 'skipImportErrors' option to true)`); } if (typeof handler === "function") { const matchedFile = endFilepath.match(/\/?\((.*?)\)/); const method = matchedFile ? matchedFile[1] : defaultMethod; const route = `${prefix}/${filepathToRoute(endFilepath)}`; app[method](route, handler); } else { console.warn(`Exported function of ${fullFilepath} is not a function`); } } return app; }; export { DEFAULT_METHOD, DEFAULT_ROUTES_DIR, index as default, filepathToRoute, toPosix };