first commit
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Filesystem scanning for the file-based router.
|
||||
*
|
||||
* Scanning happens once at startup. We build a table of routes from the files
|
||||
* that exist on disk; request paths are later matched against that table.
|
||||
* Crucially, request input is NEVER turned into a file path — this is what
|
||||
* makes the router immune to path-traversal.
|
||||
*/
|
||||
|
||||
import { existsSync, readdirSync, statSync } from "node:fs";
|
||||
import { join, relative, sep } from "node:path";
|
||||
|
||||
/** Extensions we are willing to load as route modules. */
|
||||
const ALLOWED_EXTENSIONS = [".ts", ".tsx", ".wrn"] as const;
|
||||
|
||||
export interface ScannedFile {
|
||||
/** Absolute path to the file on disk. */
|
||||
file: string;
|
||||
/** Path relative to the scanned base directory, using forward slashes. */
|
||||
rel: string;
|
||||
}
|
||||
|
||||
function hasAllowedExtension(name: string): boolean {
|
||||
return ALLOWED_EXTENSIONS.some((ext) => name.endsWith(ext));
|
||||
}
|
||||
|
||||
/** Hidden files/dirs (dotfiles) and underscore-prefixed files are ignored. */
|
||||
function isIgnored(name: string): boolean {
|
||||
return name.startsWith(".") || name.startsWith("_");
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively collect allowed route files under `baseDir`.
|
||||
* Returns [] if the directory does not exist (a route kind may be unused).
|
||||
*/
|
||||
export function scanDir(baseDir: string): ScannedFile[] {
|
||||
if (!existsSync(baseDir)) return [];
|
||||
|
||||
const out: ScannedFile[] = [];
|
||||
|
||||
const walk = (dir: string): void => {
|
||||
for (const entry of readdirSync(dir)) {
|
||||
if (isIgnored(entry)) continue;
|
||||
const abs = join(dir, entry);
|
||||
const stats = statSync(abs);
|
||||
if (stats.isDirectory()) {
|
||||
walk(abs);
|
||||
} else if (stats.isFile() && hasAllowedExtension(entry)) {
|
||||
out.push({
|
||||
file: abs,
|
||||
rel: relative(baseDir, abs).split(sep).join("/"),
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
walk(baseDir);
|
||||
return out;
|
||||
}
|
||||
Reference in New Issue
Block a user