@generouted/react-router
Version:
Generated file-based routes for React Router and Vite
71 lines (64 loc) • 2.93 kB
JavaScript
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
};