UNPKG

@itrocks/route

Version:

Domain-driven route manager with automatic generation, decorators, and static routes

111 lines 4.16 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const app_dir_1 = require("@itrocks/app-dir"); const node_fs_1 = require("node:fs"); const node_fs_2 = require("node:fs"); const typescript_1 = __importDefault(require("typescript")); // TODO support aliasing: import { Route as Alias } from './route' ; @Alias('/') const scanPath = app_dir_1.appDir; const staticRoutesFile = app_dir_1.appDir + '/static-routes.json'; let source; try { source = (0, node_fs_1.readFileSync)(staticRoutesFile) + ''; } catch { source = '{}'; } const routes = JSON.parse(source); const modules = {}; for (const [path, module] of Object.entries(routes)) { (modules[module] ?? (modules[module] = [])).push(path); } function saveStaticRoutes() { return (0, node_fs_2.writeFileSync)(staticRoutesFile, JSON.stringify(routes, null, '\t') + '\n'); } exports.default = () => (context) => (sourceFile) => { let hasRoute = false; const module = sourceFile.fileName.slice(scanPath.length, -3); const validRoutes = {}; function isRoute(node) { if (!typescript_1.default.isImportDeclaration(node)) return false; if (!node.importClause) return false; const moduleSpecifier = node.moduleSpecifier; if (moduleSpecifier.text !== '@itrocks/route') return false; if (node.importClause.name?.getText() === 'Route') { return true; } const namedBindings = node.importClause.namedBindings; if (!namedBindings || !typescript_1.default.isNamedImports(namedBindings)) return false; for (const importSpecifier of namedBindings.elements) { if (importSpecifier.name.getText() === 'Route') { return true; } } return false; } function routeDecoratorValues(node) { const routes = []; if (!typescript_1.default.canHaveDecorators(node)) return []; for (const decorator of typescript_1.default.getDecorators(node) ?? []) { if (!typescript_1.default.isCallExpression(decorator.expression)) continue; if (decorator.expression.expression.getText() !== 'Route') continue; const argument = decorator.expression.arguments[0]; if (!argument || !typescript_1.default.isStringLiteral(argument)) continue; routes.push(argument.text); } return routes; } const visit = (node) => { if (hasRoute ||= isRoute(node)) { for (const path of routeDecoratorValues(node)) { if (!path) continue; validRoutes[path] = module; if (module === routes[path]) continue; if (routes[path]) { const moduleRoutes = modules[routes[path]]; delete moduleRoutes[moduleRoutes.indexOf(path)]; } (modules[module] ?? (modules[module] = [])).push(path); routes[path] = module; } } return typescript_1.default.visitEachChild(node, visit, context); }; const resultNode = typescript_1.default.visitNode(sourceFile, visit); const moduleRoutes = modules[module]; if (moduleRoutes) { let deletions = 0; for (const path of moduleRoutes) { if (validRoutes[path]) continue; delete moduleRoutes[moduleRoutes.indexOf(path)]; delete routes[path]; deletions++; } if (deletions) { modules[module] = moduleRoutes.filter(path => path); if (!modules[module].length) { delete modules[module]; } saveStaticRoutes(); } else if (Object.keys(validRoutes).length) { saveStaticRoutes(); } } return resultNode; }; //# sourceMappingURL=static-routes-plugin.js.map