UNPKG

@generouted/react-router

Version:

Generated file-based routes for React Router and Vite

71 lines (64 loc) 2.93 kB
import { template } from "./chunk-LT7IQ3WI.js"; // src/plugin/generate.ts import { execSync } from "child_process"; import fs from "fs"; import path from "path"; import { createLogger } from "vite"; // ../../shared/core/src/index.ts var patterns = { route: [/^.*\/src\/pages\/|^\/pages\/|\.(jsx|tsx|mdx)$/g, ""], splat: [/\[\.{3}\w+\]/g, "*"], param: [/\[([^\]]+)\]/g, ":$1"], slash: [/^index$|\./g, "/"], optional: [/^-(:?[\w-]+|\*)/, "$1?"] }; // src/plugin/generate.ts import fg from "fast-glob"; var generateRouteTypes = async (options) => { const files = await fg(options.source.routes || "./src/pages/**/[\\w[-]*.{jsx,tsx,mdx}", { onlyFiles: true }); const modal = await fg(options.source.modals || "./src/pages/**/[+]*.{jsx,tsx,mdx}", { onlyFiles: true }); const filtered = files.filter((key) => !key.includes("/_") && !key.includes("/404")); const params = []; const paths = filtered.map((key) => { const path2 = key.replace(...patterns.route).replace(...patterns.splat).replace(...patterns.param).replace(/\([\w-]+\)\/|\/?_layout/g, "").replace(/\/?index|\./g, "/").replace(/(\w)\/$/g, "$1").split("/").map((segment) => segment.replace(...patterns.optional)).join("/"); if (path2) { const param = path2.split("/").filter((segment) => segment.startsWith(":")); if (param.length || path2.includes("*")) { const dynamic = param.length ? param.map((p) => p.replace(/:(.+)(\?)?/, "$1$2:") + " string") : []; const splat = path2.includes("*") ? ["'*': string"] : []; params.push(`'/${path2}': { ${[...dynamic, ...splat].join("; ")} }`); } return path2.length > 1 ? `/${path2}` : path2; } }); const modals = modal.map( (path2) => `/${path2.replace(...patterns.route).replace(/\+|\([\w-]+\)\//g, "").replace(/(\/)?index/g, "").replace(/\./g, "/")}` ); const types = `export type Path = | "${[...new Set(paths.filter(Boolean))].sort().join('"\n | "')}"`.replace(/"/g, "`") + ` export type Params = { ${params.sort().join("\n ")} } ` + `export type ModalPath = "${modals.sort().join('" | "') || "never"}"`.replace(/"/g, modals.length ? "`" : ""); const content = template.replace("// types", types); const count = paths.length + modals.length; return { content, count }; }; var logger = createLogger("info", { prefix: "[generouted]" }); var latestContent = ""; var generate = async (options) => { const start = Date.now(); const { content, count } = await generateRouteTypes(options); logger.info(`scanned ${count} routes in ${Date.now() - start} ms`, { timestamp: true }); if (latestContent === content) return; latestContent = content; await fs.promises.writeFile(options.output, content); if (!options.format) return; const prettier = path.resolve("./node_modules/.bin/prettier"); if (fs.existsSync(prettier)) execSync(`${prettier} --write --cache ${options.output}`); }; export { generate };