@contextjs/routing
Version:
Declarative, fast, and extensible route matching for ContextJS applications.
56 lines (55 loc) • 2.69 kB
JavaScript
import { Directory, File, Path } from "@contextjs/io";
import { StringExtensions } from "@contextjs/system";
import path from "path";
import "reflect-metadata";
import typescript from "typescript";
import { pathToFileURL } from "url";
import { clearRegisteredRoutes, getRegisteredRoutes } from "../decorators/route.decorator.js";
import { RouteDefinition } from "../models/route-definition.js";
import { RouteInfo } from "../models/route-info.js";
export class RouteDiscoveryService {
static async discoverRoutesAsync() {
const entryFile = Path.normalize(process.env['CTX_ENTRY_FILE'] || process.argv[1]);
const entryDir = path.dirname(entryFile);
const outDir = this.getProjectOutputDirectory(entryDir);
const files = Directory
.listFiles(outDir, true)
.filter(f => {
const ext = File.getExtension(f);
return ext === "js" || ext === "mjs";
})
.filter(f => Path.normalize(f) !== entryFile);
for (const file of files) {
const importPath = pathToFileURL(Path.normalize(file)).href;
try {
await import(importPath);
}
catch (error) {
console.error(`Failed to import ${importPath}:`, error);
}
}
const routeDefinitions = [];
for (const reg of getRegisteredRoutes()) {
const { target, propertyKey, template, name } = reg;
const className = target.constructor?.name || target.name || "unknown";
const routeInfo = new RouteInfo(template, name);
routeDefinitions.push(new RouteDefinition(className, propertyKey.toString(), routeInfo));
}
clearRegisteredRoutes();
return routeDefinitions;
}
static getProjectOutputDirectory(baseDir) {
const tsConfigFilePath = typescript.findConfigFile(baseDir, typescript.sys.fileExists, "tsconfig.json");
if (StringExtensions.isNullOrWhitespace(tsConfigFilePath))
throw new Error("Could not find tsconfig.json");
const configFile = typescript.readConfigFile(tsConfigFilePath, typescript.sys.readFile);
if (configFile.error)
throw new Error("Error reading tsconfig.json");
const configDir = path.dirname(tsConfigFilePath);
const parsedConfig = typescript.parseJsonConfigFileContent(configFile.config, typescript.sys, configDir);
const outDir = parsedConfig.options.outDir;
if (!StringExtensions.isNullOrWhitespace(outDir))
return path.isAbsolute(outDir) ? Path.normalize(outDir) : Path.normalize(path.join(configDir, outDir));
return configDir;
}
}