UNPKG

graftthis

Version:

A collection of utility tools for working with the RWSDK (Redwood SDK)

157 lines (129 loc) 4.61 kB
#!/usr/bin/env node import * as fs from 'fs/promises'; import * as path from 'path'; interface RouteMatch { route: string; startIndex: number; endIndex: number; } interface ImportInfo { originalName?: string; path: string; } async function findMatchingBracket(content: string, startIndex: number): Promise<number> { let count = 1; let i = startIndex; while (count > 0 && i < content.length) { if (content[i] === '[') count++; if (content[i] === ']') count--; i++; } return i - 1; } async function findImportedRoutes(content: string): Promise<string[]> { const importRegex = /import\s*{\s*([^}]+)\s*}\s*from\s*["']([^"']+)["']/g; const spreadRegex = /\[\s*\.\.\.(\w+)\s*\]/g; const importedRoutes: string[] = []; let match; // Find all imports const imports = new Map<string, ImportInfo>(); while ((match = importRegex.exec(content)) !== null) { const [, importNames, importPath] = match; const names = importNames.split(',').map(n => n.trim()); for (const name of names) { if (name.includes(' as ')) { const [originalName, alias] = name.split(' as ').map(n => n.trim()); imports.set(alias, { originalName, path: importPath }); } else { imports.set(name, { path: importPath }); } } } // Find spread operators and process imported files while ((match = spreadRegex.exec(content)) !== null) { const variableName = match[1]; const importInfo = imports.get(variableName); if (importInfo) { // Convert relative path to absolute let absolutePath = importInfo.path; if (importInfo.path.startsWith('@/')) { absolutePath = path.join(process.cwd(), 'src', importInfo.path.slice(2)); } else if (importInfo.path.startsWith('./') || importInfo.path.startsWith('../')) { absolutePath = path.join(path.dirname(process.cwd()), importInfo.path); } try { const importedContent = await fs.readFile(absolutePath + '.ts', 'utf-8'); const newRoutes = await extractRoutesFromContent(importedContent); importedRoutes.push(...newRoutes); } catch (error) { console.warn(`Warning: Could not process imported routes from ${importInfo.path}`); } } } return importedRoutes; } async function extractRoutesFromContent(content: string, prefix = ''): Promise<string[]> { const routes: string[] = []; const routeRegex = /route\("([^"]+)"/g; const indexRegex = /index\(/g; const prefixRegex = /prefix\("([^"]+)",\s*\[/g; let match; // Process imported routes first const importedRoutes = await findImportedRoutes(content); routes.push(...importedRoutes); // Find all prefixed route blocks while ((match = prefixRegex.exec(content)) !== null) { const prefixPath = match[1]; const startIndex = match.index + match[0].length; const endIndex = await findMatchingBracket(content, startIndex); const nestedContent = content.substring(startIndex, endIndex); // Recursively process nested routes with combined prefix const nestedRoutes = await extractRoutesFromContent( nestedContent, prefix + prefixPath ); routes.push(...nestedRoutes); } // Find all regular routes while ((match = routeRegex.exec(content)) !== null) { // Skip if this route is part of a prefix block (we already processed those) const beforeMatch = content.substring(0, match.index); const lastPrefixIndex = beforeMatch.lastIndexOf('prefix('); const lastBracketIndex = beforeMatch.lastIndexOf(']'); if (lastPrefixIndex === -1 || lastBracketIndex > lastPrefixIndex) { const route = prefix + match[1]; routes.push(route); } } // Find index routes (which map to "/") if (indexRegex.test(content)) { routes.push(prefix + "/"); } // Remove duplicates return [...new Set(routes)]; } async function generateLinksFile(routes: string[]) { const content = `import { defineLinks } from "@redwoodjs/sdk/router"; export const link = defineLinks(${JSON.stringify(routes, null, 2)}); `; await fs.writeFile( path.resolve(process.cwd(), 'src/app/shared/links.ts'), content, 'utf-8' ); } async function main() { try { const workerContent = await fs.readFile( path.resolve(process.cwd(), 'src/worker.tsx'), 'utf-8' ); const routes = await extractRoutesFromContent(workerContent); await generateLinksFile(routes); console.log('✨ Successfully generated links.ts'); } catch (error) { console.error('Error generating routes:', error); process.exit(1); } } main();