navilo 1.2.2 → 1.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -31,13 +31,17 @@ Navilo automatically generates a route tree from your `src/app` (or custom) dire
|
|
|
31
31
|
## Quick Start
|
|
32
32
|
|
|
33
33
|
### Vite Config
|
|
34
|
+
|
|
34
35
|
1. Install react router dom since its our peer dependency
|
|
36
|
+
|
|
35
37
|
```bash
|
|
36
38
|
npm install react-router-dom@6.16.0
|
|
37
39
|
|
|
38
|
-
```
|
|
40
|
+
```
|
|
41
|
+
|
|
39
42
|
2.Add the navilo to plugin in vite config
|
|
40
43
|
|
|
44
|
+
```ts
|
|
41
45
|
// vite.config.ts
|
|
42
46
|
import {defineConfig} from 'vite';
|
|
43
47
|
import react from '@vitejs/plugin-react';
|
package/dist/index.js
CHANGED
|
@@ -50,7 +50,7 @@ var DEFAULT_OPTIONS = {
|
|
|
50
50
|
pagesDir: "src/app",
|
|
51
51
|
typescript: true
|
|
52
52
|
};
|
|
53
|
-
var VIRTUAL_ROUTE_MODULE_ID = "virtual:
|
|
53
|
+
var VIRTUAL_ROUTE_MODULE_ID = "virtual:navilo-routes";
|
|
54
54
|
var RESOLVED_VIRTUAL_ROUTE_MODULE_ID = "\0" + VIRTUAL_ROUTE_MODULE_ID;
|
|
55
55
|
|
|
56
56
|
// src/generator/createRoutes.ts
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/plugin.ts","../src/constants.ts","../src/generator/createRoutes.ts","../src/generator/parser/segmentParser.ts","../src/generator/parser/routeTreeBuilder.ts","../src/generator/parser/routeDefinitionGenerator.ts"],"sourcesContent":["export { navilo } from './plugin';\n\nexport type {\n RouteFile,\n RouteType,\n RouteNode,\n ParserOptions\n} from './types';\n\nexport {\n normalizeFilePath,\n getRouteType,\n getComponentName,\n findRouteFiles\n} from './generator/createRoutes';\n\nexport { SegmentParser } from './generator/parser/segmentParser';\nexport { RouteTreeBuilder } from './generator/parser/routeTreeBuilder';\nexport { RouteDefinitionGenerator } from './generator/parser/routeDefinitionGenerator';","// src/plugin.ts\nimport { Plugin } from 'vite';\nimport path from 'path';\nimport fs from 'fs';\nimport { DEFAULT_OPTIONS, RESOLVED_VIRTUAL_ROUTE_MODULE_ID, VIRTUAL_ROUTE_MODULE_ID } from './constants';\nimport {naviloOptions, RouteFile} from './types';\nimport { findRouteFiles } from './generator/createRoutes';\nimport {RouteTreeBuilder} from \"./generator/parser/routeTreeBuilder\";\nimport {RouteDefinitionGenerator} from \"./generator/parser/routeDefinitionGenerator\";\n\nexport function navilo(options: naviloOptions = {}): Plugin {\n const resolvedOptions = { ...DEFAULT_OPTIONS, ...options };\n let root: string;\n const routeTreeBuilder = new RouteTreeBuilder();\n\n return {\n name: 'navilo',\n\n configResolved(config) {\n root = config.root;\n },\n\n configureServer(server) {\n const pagesDir = path.resolve(root, resolvedOptions.pagesDir);\n\n server.watcher.add(pagesDir);\n\n const handleFileChange = (file: string) => {\n if (file.startsWith(pagesDir)) {\n const module = server.moduleGraph.getModuleById(RESOLVED_VIRTUAL_ROUTE_MODULE_ID);\n if (module) {\n server.moduleGraph.invalidateModule(module);\n }\n server.ws.send({ type: 'full-reload' });\n }\n };\n\n server.watcher.on('add', handleFileChange);\n server.watcher.on('unlink', handleFileChange);\n server.watcher.on('change', handleFileChange);\n },\n\n resolveId(id) {\n if (id === VIRTUAL_ROUTE_MODULE_ID) {\n return RESOLVED_VIRTUAL_ROUTE_MODULE_ID;\n }\n },\n\n async load(id) {\n if (id === RESOLVED_VIRTUAL_ROUTE_MODULE_ID) {\n const pagesDir = path.resolve(root, resolvedOptions.pagesDir);\n\n if (!fs.existsSync(pagesDir)) {\n fs.mkdirSync(pagesDir, { recursive: true });\n return `export const router = null;`;\n }\n\n const routes = await findRouteFiles(pagesDir);\n\n if (routes.length === 0) {\n return `export const router = null;`;\n }\n\n const routeTree = routeTreeBuilder.build(routes, {\n strict: true,\n dynamicSegmentTransform: (segment) => `:${segment.toLowerCase()}`\n });\n\n const routeDefinitions = RouteDefinitionGenerator.generate(routeTree);\n\n return routerJSX(routes, routeDefinitions);\n }\n }\n };\n}\n\nexport function routerJSX(routes: RouteFile[], routeDefinitions: string): string {\n const importMap = new Map<string, string>();\n routes.forEach(route => importMap.set(route.filePath, route.componentName));\n\n const imports = Array.from(importMap.entries())\n .map(([filePath, componentName]) => `import ${componentName} from '${filePath}';`)\n .join('\\n');\n\n return `\nimport React, { Suspense } from 'react';\nimport { createBrowserRouter, useParams, Outlet, useRouteError, isRouteErrorResponse } from 'react-router-dom';\n${imports}\n\nfunction ErrorBoundary({ Component }) {\n const error = useRouteError();\n const params = useParams();\n\n if (!Component) {\n return React.createElement('div', { className: 'error-container' },\n React.createElement('div', { className: 'error-content' }, [\n React.createElement('h1', null, \n isRouteErrorResponse(error) ? \\`\\${error.status} - \\${error.statusText}\\` : 'Error'\n ),\n React.createElement('pre', { className: 'error-stack' },\n error instanceof Error ? error.stack : JSON.stringify(error, null, 2)\n ),\n React.createElement('button', {\n onClick: () => window.location.reload()\n }, 'Try again')\n ])\n );\n }\n\n return React.createElement(Component, { error, params });\n}\n\nfunction LoadingBoundary({ Component, children }) {\n if (!Component) {\n return children;\n }\n\n return React.createElement(Suspense, {\n fallback: React.createElement(Component)\n }, children);\n}\n\nfunction RouteWrapper({ Component, isLayout, loading, notFound }) {\n const params = useParams();\n \n if (isLayout) {\n const outlet = React.createElement(Outlet);\n const content = loading ? \n React.createElement(LoadingBoundary, { Component: loading }, outlet) :\n outlet;\n\n return React.createElement(Component, {\n children: content,\n params\n });\n }\n \n return React.createElement(Component, { params });\n}\n\n// Add global error listener\nwindow.addEventListener('error', (event) => {\n console.error('Global error:', event.error);\n});\n\n// Add global promise rejection handler\nwindow.addEventListener('unhandledrejection', (event) => {\n console.error('Unhandled promise rejection:', event.reason);\n});\n\nconst router = createBrowserRouter([\n${routeDefinitions}\n], {\n defaultErrorElement: React.createElement(ErrorBoundary, { Component: ${routes.find(r => r.type === 'not-found')?.componentName || 'null'} })\n});\n\nexport { router };\n`;\n}","export const DEFAULT_OPTIONS = {\n pagesDir: 'src/app',\n typescript: true,\n};\n\nexport const VIRTUAL_ROUTE_MODULE_ID = 'virtual:preluder-routes';\nexport const RESOLVED_VIRTUAL_ROUTE_MODULE_ID = '\\0' + VIRTUAL_ROUTE_MODULE_ID;","import path from 'path';\nimport glob from 'fast-glob';\nimport { RouteFile, RouteType } from '../types';\n\n/** Normalize Windows paths to forward slashes */\nexport function normalizeFilePath(filePath: string): string {\n return filePath.replace(/\\\\/g, '/');\n}\n\n/** Determine the type of a route file */\nexport function getRouteType(filePath: string): RouteType {\n const basename = path.basename(filePath);\n const fileTypes: Record<string, RouteType> = {\n 'layout.jsx': 'layout',\n 'layout.tsx': 'layout',\n 'page.jsx': 'page',\n 'page.tsx': 'page',\n 'error.jsx': 'error',\n 'error.tsx': 'error',\n 'loading.jsx': 'loading',\n 'loading.tsx': 'loading',\n 'not-found.jsx': 'not-found',\n 'not-found.tsx': 'not-found'\n };\n return fileTypes[basename] || 'page';\n}\n\n/** Generate a PascalCase component name based on folder structure */\nexport function getComponentName(filePath: string, pagesDir: string): string {\n const segments = normalizeFilePath(path.relative(pagesDir, filePath)).split('/');\n const fileNameWithExt = segments.pop()!;\n const fileName = path.basename(fileNameWithExt, path.extname(fileNameWithExt));\n\n const relevantSegments = segments.map(segment => {\n if (segment.startsWith('[') && segment.endsWith(']')) {\n return segment.slice(1, -1)\n .replace(/^\\.\\.\\./, 'CatchAll')\n .split(/[^a-zA-Z0-9]/)\n .map(p => p.charAt(0).toUpperCase() + p.slice(1))\n .join('');\n }\n return segment\n .split(/[^a-zA-Z0-9]/)\n .map(p => p.charAt(0).toUpperCase() + p.slice(1))\n .join('');\n });\n\n const typeSuffix = {\n page: 'Page',\n layout: 'Layout',\n error: 'Error',\n loading: 'Loading',\n 'not-found': 'NotFound'\n }[fileName] || 'Component';\n\n return relevantSegments.length === 0 ? `Root${typeSuffix}` : `${relevantSegments.join('')}${typeSuffix}`;\n}\n\n/** Extract segments from file path for building route tree */\nexport function getPathSegments(filePath: string, pagesDir: string): string[] {\n const relativePath = normalizeFilePath(path.relative(pagesDir, filePath));\n const segments = relativePath.split('/');\n const fileName = segments.pop()!;\n\n const filteredSegments = segments.filter(seg => !(seg.startsWith('(') && seg.endsWith(')')));\n\n if (/^page\\.(jsx|tsx)$/.test(fileName)) {\n filteredSegments.push('');\n }\n\n return filteredSegments;\n}\n\n/** Find all route files in the pages directory */\nexport async function findRouteFiles(pagesDir: string): Promise<RouteFile[]> {\n const files = await glob(['**/*.{jsx,tsx}'], {\n cwd: pagesDir,\n absolute: true,\n ignore: ['**/node_modules/**', '**/.*/**', '**/_*/**'],\n });\n\n const validFiles = files.filter(file => {\n const base = path.basename(file);\n return /^(layout|page|error|loading|not-found)\\.(jsx|tsx)$/.test(base);\n });\n\n return validFiles.map(file => {\n const type = getRouteType(file);\n return {\n type,\n path: '/' + normalizeFilePath(path.relative(pagesDir, path.dirname(file))),\n filePath: normalizeFilePath(file),\n componentName: getComponentName(file, pagesDir),\n segments: getPathSegments(file, pagesDir),\n };\n });\n}\n","import {ParserOptions} from \"../../types\";\n\nexport class SegmentParser {\n private static readonly SEGMENT_PATTERNS = {\n OPTIONAL_CATCH_ALL: /^\\[\\[\\.{3}(.+)\\]\\]$/,\n CATCH_ALL: /^\\[\\.{3}(.+)\\]$/,\n DYNAMIC: /^\\[(.+)\\]$/,\n GROUP: /^\\((.+)\\)$/\n };\n\n static normalize(segment: string, options?: ParserOptions): string | null {\n if (this.isGroupSegment(segment)) return null;\n\n if (segment.includes('/')) {\n return segment.split('/')\n .map(seg => this.normalizeSegment(seg, options))\n .filter(Boolean)\n .join('/');\n }\n\n return this.normalizeSegment(segment, options);\n }\n\n private static normalizeSegment(segment: string, options?: ParserOptions): string | null {\n const transform = options?.dynamicSegmentTransform || this.defaultTransform;\n\n if (this.isOptionalCatchAll(segment)) {\n const name = segment.match(this.SEGMENT_PATTERNS.OPTIONAL_CATCH_ALL)![1];\n return transform(`${name}*?`);\n }\n\n if (this.isCatchAll(segment)) {\n const name = segment.match(this.SEGMENT_PATTERNS.CATCH_ALL)![1];\n return transform(`${name}*`);\n }\n\n if (this.isDynamicSegment(segment)) {\n const name = segment.match(this.SEGMENT_PATTERNS.DYNAMIC)![1];\n return transform(name);\n }\n\n return segment;\n }\n\n private static defaultTransform(name: string): string {\n return `:${name}`;\n }\n\n private static isGroupSegment(segment: string): boolean {\n return this.SEGMENT_PATTERNS.GROUP.test(segment);\n }\n\n private static isOptionalCatchAll(segment: string): boolean {\n return this.SEGMENT_PATTERNS.OPTIONAL_CATCH_ALL.test(segment);\n }\n\n private static isCatchAll(segment: string): boolean {\n return this.SEGMENT_PATTERNS.CATCH_ALL.test(segment);\n }\n\n private static isDynamicSegment(segment: string): boolean {\n return this.SEGMENT_PATTERNS.DYNAMIC.test(segment);\n }\n}","import {SegmentParser} from './segmentParser';\nimport {ParserOptions, RouteFile, RouteNode} from \"../../types\";\n\nexport class RouteTreeBuilder {\n private readonly typeSetters: Record<string, (node: RouteNode, route: RouteFile) => void>;\n\n constructor() {\n this.typeSetters = {\n layout: (node, route) => {\n node.layout = route.componentName;\n },\n error: (node, route) => {\n node.error = route.componentName;\n },\n loading: (node, route) => {\n node.loading = route.componentName;\n },\n 'not-found': (node, route) => {\n node.notFound = route.componentName;\n },\n page: this.handlePageType.bind(this)\n };\n }\n\n build(routes: RouteFile[], options?: ParserOptions): RouteNode {\n const root: RouteNode = {\n segment: '',\n path: '/',\n fullPath: '/',\n children: new Map(),\n metadata: options?.metadata\n };\n\n const sortedRoutes = this.sortRoutes(routes);\n sortedRoutes.forEach(route => {\n this.processRoute(root, route, options);\n });\n\n return root;\n }\n\n private sortRoutes(routes: RouteFile[]): RouteFile[] {\n return [...routes].sort((a, b) =>\n a.type === 'layout' && b.type !== 'layout' ? -1 :\n a.type !== 'layout' && b.type === 'layout' ? 1 : 0\n );\n }\n\n private processRoute(root: RouteNode, route: RouteFile, options?: ParserOptions): void {\n const segments = route.segments.map(seg => String(seg));\n\n if (segments.length === 0) {\n this.applyTypeHandler(root, route);\n if (route.type === 'page') root.isIndex = true;\n return;\n }\n\n let current = root;\n let currentPath = '';\n\n segments.forEach((seg, idx) => {\n const isLast = idx === segments.length - 1;\n const key = SegmentParser.normalize(seg, options);\n\n if (key === null) return;\n\n currentPath = this.buildFullPath(currentPath, key);\n\n if (!current.children.has(key)) {\n current.children.set(key, {\n segment: key,\n path: key,\n fullPath: currentPath,\n children: new Map(),\n metadata: options?.metadata\n });\n }\n\n current = current.children.get(key)!;\n\n if (isLast) this.applyTypeHandler(current, route);\n });\n }\n\n private buildFullPath(currentPath: string, key: string): string {\n if (currentPath === '' || currentPath === '/') {\n return key === '' ? '/' : `/${key}`;\n }\n return `${currentPath}/${key}`;\n }\n\n private applyTypeHandler(node: RouteNode, route: RouteFile): void {\n const handler = this.typeSetters[route.type];\n if (handler) handler(node, route);\n }\n\n private handlePageType(node: RouteNode, route: RouteFile): void {\n const lastSegment = route.segments[route.segments.length - 1];\n const isDynamic = lastSegment?.startsWith('[');\n\n if (isDynamic || lastSegment === '') {\n node.component = route.componentName;\n node.isIndex = false;\n } else {\n node.indexPage = route.componentName;\n }\n }\n}","import { RouteNode } from \"../../types\";\n\nexport class RouteDefinitionGenerator {\n static generate(node: RouteNode, indent = ' '): string {\n const childNodes = Array.from(node.children.values());\n const children: string[] = [];\n\n if (node.indexPage) {\n children.push(this.generateIndexRoute(node, indent));\n }\n\n children.push(...childNodes.map(child =>\n this.generate(child, indent + ' ')\n ));\n\n return this.generateRouteObject(node, children, indent);\n }\n\n private static generateIndexRoute(node: RouteNode, indent: string): string {\n return `${indent} {\n${indent} index: true,\n${indent} element: React.createElement(RouteWrapper, {\n${indent} Component: ${node.indexPage}\n${indent} })\n${indent} }`;\n }\n\n private static generateRouteObject(node: RouteNode, children: string[], indent: string): string {\n const pathStr = node.fullPath;\n const elementStr = this.generateElementString(node, indent);\n const errorStr = this.generateErrorString(node, indent);\n\n return [\n `${indent}{`,\n `${indent} path: '${pathStr}'${elementStr}${errorStr}`,\n children.length > 0 ? `,\\n${indent} children: [\\n${children.join(',\\n')}\\n${indent} ]` : '',\n `${indent}}`\n ].filter(Boolean).join('');\n }\n\n private static generateElementString(node: RouteNode, indent: string): string {\n if (!node.layout && !node.component) return '';\n\n const props = node.layout\n ? this.generateLayoutProps(node, indent)\n : this.generateComponentProps(node, indent);\n\n return `,\\n${indent} element: React.createElement(RouteWrapper, ${props})`;\n }\n\n private static generateLayoutProps(node: RouteNode, indent: string): string {\n return `{\n${indent} Component: ${node.layout},\n${indent} isLayout: true,\n${indent} loading: ${node.loading || 'undefined'},\n${indent} notFound: ${node.notFound || 'undefined'}\n${indent} }`;\n }\n\n private static generateComponentProps(node: RouteNode, indent: string): string {\n return `{\n${indent} Component: ${node.component}\n${indent} }`;\n }\n\n private static generateErrorString(node: RouteNode, indent: string): string {\n if (!node.error) return '';\n\n return `,\\n${indent} errorElement: React.createElement(ErrorBoundary, {\n${indent} Component: ${node.error}\n${indent} })`;\n }\n}"],"mappings":"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","names":["import_path","path","glob","path","module","fs"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/plugin.ts","../src/constants.ts","../src/generator/createRoutes.ts","../src/generator/parser/segmentParser.ts","../src/generator/parser/routeTreeBuilder.ts","../src/generator/parser/routeDefinitionGenerator.ts"],"sourcesContent":["export { navilo } from './plugin';\n\nexport type {\n RouteFile,\n RouteType,\n RouteNode,\n ParserOptions\n} from './types';\n\nexport {\n normalizeFilePath,\n getRouteType,\n getComponentName,\n findRouteFiles\n} from './generator/createRoutes';\n\nexport { SegmentParser } from './generator/parser/segmentParser';\nexport { RouteTreeBuilder } from './generator/parser/routeTreeBuilder';\nexport { RouteDefinitionGenerator } from './generator/parser/routeDefinitionGenerator';","// src/plugin.ts\nimport { Plugin } from 'vite';\nimport path from 'path';\nimport fs from 'fs';\nimport { DEFAULT_OPTIONS, RESOLVED_VIRTUAL_ROUTE_MODULE_ID, VIRTUAL_ROUTE_MODULE_ID } from './constants';\nimport {naviloOptions, RouteFile} from './types';\nimport { findRouteFiles } from './generator/createRoutes';\nimport {RouteTreeBuilder} from \"./generator/parser/routeTreeBuilder\";\nimport {RouteDefinitionGenerator} from \"./generator/parser/routeDefinitionGenerator\";\n\nexport function navilo(options: naviloOptions = {}): Plugin {\n const resolvedOptions = { ...DEFAULT_OPTIONS, ...options };\n let root: string;\n const routeTreeBuilder = new RouteTreeBuilder();\n\n return {\n name: 'navilo',\n\n configResolved(config) {\n root = config.root;\n },\n\n configureServer(server) {\n const pagesDir = path.resolve(root, resolvedOptions.pagesDir);\n\n server.watcher.add(pagesDir);\n\n const handleFileChange = (file: string) => {\n if (file.startsWith(pagesDir)) {\n const module = server.moduleGraph.getModuleById(RESOLVED_VIRTUAL_ROUTE_MODULE_ID);\n if (module) {\n server.moduleGraph.invalidateModule(module);\n }\n server.ws.send({ type: 'full-reload' });\n }\n };\n\n server.watcher.on('add', handleFileChange);\n server.watcher.on('unlink', handleFileChange);\n server.watcher.on('change', handleFileChange);\n },\n\n resolveId(id) {\n if (id === VIRTUAL_ROUTE_MODULE_ID) {\n return RESOLVED_VIRTUAL_ROUTE_MODULE_ID;\n }\n },\n\n async load(id) {\n if (id === RESOLVED_VIRTUAL_ROUTE_MODULE_ID) {\n const pagesDir = path.resolve(root, resolvedOptions.pagesDir);\n\n if (!fs.existsSync(pagesDir)) {\n fs.mkdirSync(pagesDir, { recursive: true });\n return `export const router = null;`;\n }\n\n const routes = await findRouteFiles(pagesDir);\n\n if (routes.length === 0) {\n return `export const router = null;`;\n }\n\n const routeTree = routeTreeBuilder.build(routes, {\n strict: true,\n dynamicSegmentTransform: (segment) => `:${segment.toLowerCase()}`\n });\n\n const routeDefinitions = RouteDefinitionGenerator.generate(routeTree);\n\n return routerJSX(routes, routeDefinitions);\n }\n }\n };\n}\n\nexport function routerJSX(routes: RouteFile[], routeDefinitions: string): string {\n const importMap = new Map<string, string>();\n routes.forEach(route => importMap.set(route.filePath, route.componentName));\n\n const imports = Array.from(importMap.entries())\n .map(([filePath, componentName]) => `import ${componentName} from '${filePath}';`)\n .join('\\n');\n\n return `\nimport React, { Suspense } from 'react';\nimport { createBrowserRouter, useParams, Outlet, useRouteError, isRouteErrorResponse } from 'react-router-dom';\n${imports}\n\nfunction ErrorBoundary({ Component }) {\n const error = useRouteError();\n const params = useParams();\n\n if (!Component) {\n return React.createElement('div', { className: 'error-container' },\n React.createElement('div', { className: 'error-content' }, [\n React.createElement('h1', null, \n isRouteErrorResponse(error) ? \\`\\${error.status} - \\${error.statusText}\\` : 'Error'\n ),\n React.createElement('pre', { className: 'error-stack' },\n error instanceof Error ? error.stack : JSON.stringify(error, null, 2)\n ),\n React.createElement('button', {\n onClick: () => window.location.reload()\n }, 'Try again')\n ])\n );\n }\n\n return React.createElement(Component, { error, params });\n}\n\nfunction LoadingBoundary({ Component, children }) {\n if (!Component) {\n return children;\n }\n\n return React.createElement(Suspense, {\n fallback: React.createElement(Component)\n }, children);\n}\n\nfunction RouteWrapper({ Component, isLayout, loading, notFound }) {\n const params = useParams();\n \n if (isLayout) {\n const outlet = React.createElement(Outlet);\n const content = loading ? \n React.createElement(LoadingBoundary, { Component: loading }, outlet) :\n outlet;\n\n return React.createElement(Component, {\n children: content,\n params\n });\n }\n \n return React.createElement(Component, { params });\n}\n\n// Add global error listener\nwindow.addEventListener('error', (event) => {\n console.error('Global error:', event.error);\n});\n\n// Add global promise rejection handler\nwindow.addEventListener('unhandledrejection', (event) => {\n console.error('Unhandled promise rejection:', event.reason);\n});\n\nconst router = createBrowserRouter([\n${routeDefinitions}\n], {\n defaultErrorElement: React.createElement(ErrorBoundary, { Component: ${routes.find(r => r.type === 'not-found')?.componentName || 'null'} })\n});\n\nexport { router };\n`;\n}","export const DEFAULT_OPTIONS = {\n pagesDir: 'src/app',\n typescript: true,\n};\n\nexport const VIRTUAL_ROUTE_MODULE_ID = 'virtual:navilo-routes';\nexport const RESOLVED_VIRTUAL_ROUTE_MODULE_ID = '\\0' + VIRTUAL_ROUTE_MODULE_ID;","import path from 'path';\nimport glob from 'fast-glob';\nimport { RouteFile, RouteType } from '../types';\n\n/** Normalize Windows paths to forward slashes */\nexport function normalizeFilePath(filePath: string): string {\n return filePath.replace(/\\\\/g, '/');\n}\n\n/** Determine the type of a route file */\nexport function getRouteType(filePath: string): RouteType {\n const basename = path.basename(filePath);\n const fileTypes: Record<string, RouteType> = {\n 'layout.jsx': 'layout',\n 'layout.tsx': 'layout',\n 'page.jsx': 'page',\n 'page.tsx': 'page',\n 'error.jsx': 'error',\n 'error.tsx': 'error',\n 'loading.jsx': 'loading',\n 'loading.tsx': 'loading',\n 'not-found.jsx': 'not-found',\n 'not-found.tsx': 'not-found'\n };\n return fileTypes[basename] || 'page';\n}\n\n/** Generate a PascalCase component name based on folder structure */\nexport function getComponentName(filePath: string, pagesDir: string): string {\n const segments = normalizeFilePath(path.relative(pagesDir, filePath)).split('/');\n const fileNameWithExt = segments.pop()!;\n const fileName = path.basename(fileNameWithExt, path.extname(fileNameWithExt));\n\n const relevantSegments = segments.map(segment => {\n if (segment.startsWith('[') && segment.endsWith(']')) {\n return segment.slice(1, -1)\n .replace(/^\\.\\.\\./, 'CatchAll')\n .split(/[^a-zA-Z0-9]/)\n .map(p => p.charAt(0).toUpperCase() + p.slice(1))\n .join('');\n }\n return segment\n .split(/[^a-zA-Z0-9]/)\n .map(p => p.charAt(0).toUpperCase() + p.slice(1))\n .join('');\n });\n\n const typeSuffix = {\n page: 'Page',\n layout: 'Layout',\n error: 'Error',\n loading: 'Loading',\n 'not-found': 'NotFound'\n }[fileName] || 'Component';\n\n return relevantSegments.length === 0 ? `Root${typeSuffix}` : `${relevantSegments.join('')}${typeSuffix}`;\n}\n\n/** Extract segments from file path for building route tree */\nexport function getPathSegments(filePath: string, pagesDir: string): string[] {\n const relativePath = normalizeFilePath(path.relative(pagesDir, filePath));\n const segments = relativePath.split('/');\n const fileName = segments.pop()!;\n\n const filteredSegments = segments.filter(seg => !(seg.startsWith('(') && seg.endsWith(')')));\n\n if (/^page\\.(jsx|tsx)$/.test(fileName)) {\n filteredSegments.push('');\n }\n\n return filteredSegments;\n}\n\n/** Find all route files in the pages directory */\nexport async function findRouteFiles(pagesDir: string): Promise<RouteFile[]> {\n const files = await glob(['**/*.{jsx,tsx}'], {\n cwd: pagesDir,\n absolute: true,\n ignore: ['**/node_modules/**', '**/.*/**', '**/_*/**'],\n });\n\n const validFiles = files.filter(file => {\n const base = path.basename(file);\n return /^(layout|page|error|loading|not-found)\\.(jsx|tsx)$/.test(base);\n });\n\n return validFiles.map(file => {\n const type = getRouteType(file);\n return {\n type,\n path: '/' + normalizeFilePath(path.relative(pagesDir, path.dirname(file))),\n filePath: normalizeFilePath(file),\n componentName: getComponentName(file, pagesDir),\n segments: getPathSegments(file, pagesDir),\n };\n });\n}\n","import {ParserOptions} from \"../../types\";\n\nexport class SegmentParser {\n private static readonly SEGMENT_PATTERNS = {\n OPTIONAL_CATCH_ALL: /^\\[\\[\\.{3}(.+)\\]\\]$/,\n CATCH_ALL: /^\\[\\.{3}(.+)\\]$/,\n DYNAMIC: /^\\[(.+)\\]$/,\n GROUP: /^\\((.+)\\)$/\n };\n\n static normalize(segment: string, options?: ParserOptions): string | null {\n if (this.isGroupSegment(segment)) return null;\n\n if (segment.includes('/')) {\n return segment.split('/')\n .map(seg => this.normalizeSegment(seg, options))\n .filter(Boolean)\n .join('/');\n }\n\n return this.normalizeSegment(segment, options);\n }\n\n private static normalizeSegment(segment: string, options?: ParserOptions): string | null {\n const transform = options?.dynamicSegmentTransform || this.defaultTransform;\n\n if (this.isOptionalCatchAll(segment)) {\n const name = segment.match(this.SEGMENT_PATTERNS.OPTIONAL_CATCH_ALL)![1];\n return transform(`${name}*?`);\n }\n\n if (this.isCatchAll(segment)) {\n const name = segment.match(this.SEGMENT_PATTERNS.CATCH_ALL)![1];\n return transform(`${name}*`);\n }\n\n if (this.isDynamicSegment(segment)) {\n const name = segment.match(this.SEGMENT_PATTERNS.DYNAMIC)![1];\n return transform(name);\n }\n\n return segment;\n }\n\n private static defaultTransform(name: string): string {\n return `:${name}`;\n }\n\n private static isGroupSegment(segment: string): boolean {\n return this.SEGMENT_PATTERNS.GROUP.test(segment);\n }\n\n private static isOptionalCatchAll(segment: string): boolean {\n return this.SEGMENT_PATTERNS.OPTIONAL_CATCH_ALL.test(segment);\n }\n\n private static isCatchAll(segment: string): boolean {\n return this.SEGMENT_PATTERNS.CATCH_ALL.test(segment);\n }\n\n private static isDynamicSegment(segment: string): boolean {\n return this.SEGMENT_PATTERNS.DYNAMIC.test(segment);\n }\n}","import {SegmentParser} from './segmentParser';\nimport {ParserOptions, RouteFile, RouteNode} from \"../../types\";\n\nexport class RouteTreeBuilder {\n private readonly typeSetters: Record<string, (node: RouteNode, route: RouteFile) => void>;\n\n constructor() {\n this.typeSetters = {\n layout: (node, route) => {\n node.layout = route.componentName;\n },\n error: (node, route) => {\n node.error = route.componentName;\n },\n loading: (node, route) => {\n node.loading = route.componentName;\n },\n 'not-found': (node, route) => {\n node.notFound = route.componentName;\n },\n page: this.handlePageType.bind(this)\n };\n }\n\n build(routes: RouteFile[], options?: ParserOptions): RouteNode {\n const root: RouteNode = {\n segment: '',\n path: '/',\n fullPath: '/',\n children: new Map(),\n metadata: options?.metadata\n };\n\n const sortedRoutes = this.sortRoutes(routes);\n sortedRoutes.forEach(route => {\n this.processRoute(root, route, options);\n });\n\n return root;\n }\n\n private sortRoutes(routes: RouteFile[]): RouteFile[] {\n return [...routes].sort((a, b) =>\n a.type === 'layout' && b.type !== 'layout' ? -1 :\n a.type !== 'layout' && b.type === 'layout' ? 1 : 0\n );\n }\n\n private processRoute(root: RouteNode, route: RouteFile, options?: ParserOptions): void {\n const segments = route.segments.map(seg => String(seg));\n\n if (segments.length === 0) {\n this.applyTypeHandler(root, route);\n if (route.type === 'page') root.isIndex = true;\n return;\n }\n\n let current = root;\n let currentPath = '';\n\n segments.forEach((seg, idx) => {\n const isLast = idx === segments.length - 1;\n const key = SegmentParser.normalize(seg, options);\n\n if (key === null) return;\n\n currentPath = this.buildFullPath(currentPath, key);\n\n if (!current.children.has(key)) {\n current.children.set(key, {\n segment: key,\n path: key,\n fullPath: currentPath,\n children: new Map(),\n metadata: options?.metadata\n });\n }\n\n current = current.children.get(key)!;\n\n if (isLast) this.applyTypeHandler(current, route);\n });\n }\n\n private buildFullPath(currentPath: string, key: string): string {\n if (currentPath === '' || currentPath === '/') {\n return key === '' ? '/' : `/${key}`;\n }\n return `${currentPath}/${key}`;\n }\n\n private applyTypeHandler(node: RouteNode, route: RouteFile): void {\n const handler = this.typeSetters[route.type];\n if (handler) handler(node, route);\n }\n\n private handlePageType(node: RouteNode, route: RouteFile): void {\n const lastSegment = route.segments[route.segments.length - 1];\n const isDynamic = lastSegment?.startsWith('[');\n\n if (isDynamic || lastSegment === '') {\n node.component = route.componentName;\n node.isIndex = false;\n } else {\n node.indexPage = route.componentName;\n }\n }\n}","import { RouteNode } from \"../../types\";\n\nexport class RouteDefinitionGenerator {\n static generate(node: RouteNode, indent = ' '): string {\n const childNodes = Array.from(node.children.values());\n const children: string[] = [];\n\n if (node.indexPage) {\n children.push(this.generateIndexRoute(node, indent));\n }\n\n children.push(...childNodes.map(child =>\n this.generate(child, indent + ' ')\n ));\n\n return this.generateRouteObject(node, children, indent);\n }\n\n private static generateIndexRoute(node: RouteNode, indent: string): string {\n return `${indent} {\n${indent} index: true,\n${indent} element: React.createElement(RouteWrapper, {\n${indent} Component: ${node.indexPage}\n${indent} })\n${indent} }`;\n }\n\n private static generateRouteObject(node: RouteNode, children: string[], indent: string): string {\n const pathStr = node.fullPath;\n const elementStr = this.generateElementString(node, indent);\n const errorStr = this.generateErrorString(node, indent);\n\n return [\n `${indent}{`,\n `${indent} path: '${pathStr}'${elementStr}${errorStr}`,\n children.length > 0 ? `,\\n${indent} children: [\\n${children.join(',\\n')}\\n${indent} ]` : '',\n `${indent}}`\n ].filter(Boolean).join('');\n }\n\n private static generateElementString(node: RouteNode, indent: string): string {\n if (!node.layout && !node.component) return '';\n\n const props = node.layout\n ? this.generateLayoutProps(node, indent)\n : this.generateComponentProps(node, indent);\n\n return `,\\n${indent} element: React.createElement(RouteWrapper, ${props})`;\n }\n\n private static generateLayoutProps(node: RouteNode, indent: string): string {\n return `{\n${indent} Component: ${node.layout},\n${indent} isLayout: true,\n${indent} loading: ${node.loading || 'undefined'},\n${indent} notFound: ${node.notFound || 'undefined'}\n${indent} }`;\n }\n\n private static generateComponentProps(node: RouteNode, indent: string): string {\n return `{\n${indent} Component: ${node.component}\n${indent} }`;\n }\n\n private static generateErrorString(node: RouteNode, indent: string): string {\n if (!node.error) return '';\n\n return `,\\n${indent} errorElement: React.createElement(ErrorBoundary, {\n${indent} Component: ${node.error}\n${indent} })`;\n }\n}"],"mappings":"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","names":["import_path","path","glob","path","module","fs"]}
|
package/dist/index.mjs
CHANGED
|
@@ -7,7 +7,7 @@ var DEFAULT_OPTIONS = {
|
|
|
7
7
|
pagesDir: "src/app",
|
|
8
8
|
typescript: true
|
|
9
9
|
};
|
|
10
|
-
var VIRTUAL_ROUTE_MODULE_ID = "virtual:
|
|
10
|
+
var VIRTUAL_ROUTE_MODULE_ID = "virtual:navilo-routes";
|
|
11
11
|
var RESOLVED_VIRTUAL_ROUTE_MODULE_ID = "\0" + VIRTUAL_ROUTE_MODULE_ID;
|
|
12
12
|
|
|
13
13
|
// src/generator/createRoutes.ts
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/plugin.ts","../src/constants.ts","../src/generator/createRoutes.ts","../src/generator/parser/segmentParser.ts","../src/generator/parser/routeTreeBuilder.ts","../src/generator/parser/routeDefinitionGenerator.ts"],"sourcesContent":["// src/plugin.ts\nimport { Plugin } from 'vite';\nimport path from 'path';\nimport fs from 'fs';\nimport { DEFAULT_OPTIONS, RESOLVED_VIRTUAL_ROUTE_MODULE_ID, VIRTUAL_ROUTE_MODULE_ID } from './constants';\nimport {naviloOptions, RouteFile} from './types';\nimport { findRouteFiles } from './generator/createRoutes';\nimport {RouteTreeBuilder} from \"./generator/parser/routeTreeBuilder\";\nimport {RouteDefinitionGenerator} from \"./generator/parser/routeDefinitionGenerator\";\n\nexport function navilo(options: naviloOptions = {}): Plugin {\n const resolvedOptions = { ...DEFAULT_OPTIONS, ...options };\n let root: string;\n const routeTreeBuilder = new RouteTreeBuilder();\n\n return {\n name: 'navilo',\n\n configResolved(config) {\n root = config.root;\n },\n\n configureServer(server) {\n const pagesDir = path.resolve(root, resolvedOptions.pagesDir);\n\n server.watcher.add(pagesDir);\n\n const handleFileChange = (file: string) => {\n if (file.startsWith(pagesDir)) {\n const module = server.moduleGraph.getModuleById(RESOLVED_VIRTUAL_ROUTE_MODULE_ID);\n if (module) {\n server.moduleGraph.invalidateModule(module);\n }\n server.ws.send({ type: 'full-reload' });\n }\n };\n\n server.watcher.on('add', handleFileChange);\n server.watcher.on('unlink', handleFileChange);\n server.watcher.on('change', handleFileChange);\n },\n\n resolveId(id) {\n if (id === VIRTUAL_ROUTE_MODULE_ID) {\n return RESOLVED_VIRTUAL_ROUTE_MODULE_ID;\n }\n },\n\n async load(id) {\n if (id === RESOLVED_VIRTUAL_ROUTE_MODULE_ID) {\n const pagesDir = path.resolve(root, resolvedOptions.pagesDir);\n\n if (!fs.existsSync(pagesDir)) {\n fs.mkdirSync(pagesDir, { recursive: true });\n return `export const router = null;`;\n }\n\n const routes = await findRouteFiles(pagesDir);\n\n if (routes.length === 0) {\n return `export const router = null;`;\n }\n\n const routeTree = routeTreeBuilder.build(routes, {\n strict: true,\n dynamicSegmentTransform: (segment) => `:${segment.toLowerCase()}`\n });\n\n const routeDefinitions = RouteDefinitionGenerator.generate(routeTree);\n\n return routerJSX(routes, routeDefinitions);\n }\n }\n };\n}\n\nexport function routerJSX(routes: RouteFile[], routeDefinitions: string): string {\n const importMap = new Map<string, string>();\n routes.forEach(route => importMap.set(route.filePath, route.componentName));\n\n const imports = Array.from(importMap.entries())\n .map(([filePath, componentName]) => `import ${componentName} from '${filePath}';`)\n .join('\\n');\n\n return `\nimport React, { Suspense } from 'react';\nimport { createBrowserRouter, useParams, Outlet, useRouteError, isRouteErrorResponse } from 'react-router-dom';\n${imports}\n\nfunction ErrorBoundary({ Component }) {\n const error = useRouteError();\n const params = useParams();\n\n if (!Component) {\n return React.createElement('div', { className: 'error-container' },\n React.createElement('div', { className: 'error-content' }, [\n React.createElement('h1', null, \n isRouteErrorResponse(error) ? \\`\\${error.status} - \\${error.statusText}\\` : 'Error'\n ),\n React.createElement('pre', { className: 'error-stack' },\n error instanceof Error ? error.stack : JSON.stringify(error, null, 2)\n ),\n React.createElement('button', {\n onClick: () => window.location.reload()\n }, 'Try again')\n ])\n );\n }\n\n return React.createElement(Component, { error, params });\n}\n\nfunction LoadingBoundary({ Component, children }) {\n if (!Component) {\n return children;\n }\n\n return React.createElement(Suspense, {\n fallback: React.createElement(Component)\n }, children);\n}\n\nfunction RouteWrapper({ Component, isLayout, loading, notFound }) {\n const params = useParams();\n \n if (isLayout) {\n const outlet = React.createElement(Outlet);\n const content = loading ? \n React.createElement(LoadingBoundary, { Component: loading }, outlet) :\n outlet;\n\n return React.createElement(Component, {\n children: content,\n params\n });\n }\n \n return React.createElement(Component, { params });\n}\n\n// Add global error listener\nwindow.addEventListener('error', (event) => {\n console.error('Global error:', event.error);\n});\n\n// Add global promise rejection handler\nwindow.addEventListener('unhandledrejection', (event) => {\n console.error('Unhandled promise rejection:', event.reason);\n});\n\nconst router = createBrowserRouter([\n${routeDefinitions}\n], {\n defaultErrorElement: React.createElement(ErrorBoundary, { Component: ${routes.find(r => r.type === 'not-found')?.componentName || 'null'} })\n});\n\nexport { router };\n`;\n}","export const DEFAULT_OPTIONS = {\n pagesDir: 'src/app',\n typescript: true,\n};\n\nexport const VIRTUAL_ROUTE_MODULE_ID = 'virtual:preluder-routes';\nexport const RESOLVED_VIRTUAL_ROUTE_MODULE_ID = '\\0' + VIRTUAL_ROUTE_MODULE_ID;","import path from 'path';\nimport glob from 'fast-glob';\nimport { RouteFile, RouteType } from '../types';\n\n/** Normalize Windows paths to forward slashes */\nexport function normalizeFilePath(filePath: string): string {\n return filePath.replace(/\\\\/g, '/');\n}\n\n/** Determine the type of a route file */\nexport function getRouteType(filePath: string): RouteType {\n const basename = path.basename(filePath);\n const fileTypes: Record<string, RouteType> = {\n 'layout.jsx': 'layout',\n 'layout.tsx': 'layout',\n 'page.jsx': 'page',\n 'page.tsx': 'page',\n 'error.jsx': 'error',\n 'error.tsx': 'error',\n 'loading.jsx': 'loading',\n 'loading.tsx': 'loading',\n 'not-found.jsx': 'not-found',\n 'not-found.tsx': 'not-found'\n };\n return fileTypes[basename] || 'page';\n}\n\n/** Generate a PascalCase component name based on folder structure */\nexport function getComponentName(filePath: string, pagesDir: string): string {\n const segments = normalizeFilePath(path.relative(pagesDir, filePath)).split('/');\n const fileNameWithExt = segments.pop()!;\n const fileName = path.basename(fileNameWithExt, path.extname(fileNameWithExt));\n\n const relevantSegments = segments.map(segment => {\n if (segment.startsWith('[') && segment.endsWith(']')) {\n return segment.slice(1, -1)\n .replace(/^\\.\\.\\./, 'CatchAll')\n .split(/[^a-zA-Z0-9]/)\n .map(p => p.charAt(0).toUpperCase() + p.slice(1))\n .join('');\n }\n return segment\n .split(/[^a-zA-Z0-9]/)\n .map(p => p.charAt(0).toUpperCase() + p.slice(1))\n .join('');\n });\n\n const typeSuffix = {\n page: 'Page',\n layout: 'Layout',\n error: 'Error',\n loading: 'Loading',\n 'not-found': 'NotFound'\n }[fileName] || 'Component';\n\n return relevantSegments.length === 0 ? `Root${typeSuffix}` : `${relevantSegments.join('')}${typeSuffix}`;\n}\n\n/** Extract segments from file path for building route tree */\nexport function getPathSegments(filePath: string, pagesDir: string): string[] {\n const relativePath = normalizeFilePath(path.relative(pagesDir, filePath));\n const segments = relativePath.split('/');\n const fileName = segments.pop()!;\n\n const filteredSegments = segments.filter(seg => !(seg.startsWith('(') && seg.endsWith(')')));\n\n if (/^page\\.(jsx|tsx)$/.test(fileName)) {\n filteredSegments.push('');\n }\n\n return filteredSegments;\n}\n\n/** Find all route files in the pages directory */\nexport async function findRouteFiles(pagesDir: string): Promise<RouteFile[]> {\n const files = await glob(['**/*.{jsx,tsx}'], {\n cwd: pagesDir,\n absolute: true,\n ignore: ['**/node_modules/**', '**/.*/**', '**/_*/**'],\n });\n\n const validFiles = files.filter(file => {\n const base = path.basename(file);\n return /^(layout|page|error|loading|not-found)\\.(jsx|tsx)$/.test(base);\n });\n\n return validFiles.map(file => {\n const type = getRouteType(file);\n return {\n type,\n path: '/' + normalizeFilePath(path.relative(pagesDir, path.dirname(file))),\n filePath: normalizeFilePath(file),\n componentName: getComponentName(file, pagesDir),\n segments: getPathSegments(file, pagesDir),\n };\n });\n}\n","import {ParserOptions} from \"../../types\";\n\nexport class SegmentParser {\n private static readonly SEGMENT_PATTERNS = {\n OPTIONAL_CATCH_ALL: /^\\[\\[\\.{3}(.+)\\]\\]$/,\n CATCH_ALL: /^\\[\\.{3}(.+)\\]$/,\n DYNAMIC: /^\\[(.+)\\]$/,\n GROUP: /^\\((.+)\\)$/\n };\n\n static normalize(segment: string, options?: ParserOptions): string | null {\n if (this.isGroupSegment(segment)) return null;\n\n if (segment.includes('/')) {\n return segment.split('/')\n .map(seg => this.normalizeSegment(seg, options))\n .filter(Boolean)\n .join('/');\n }\n\n return this.normalizeSegment(segment, options);\n }\n\n private static normalizeSegment(segment: string, options?: ParserOptions): string | null {\n const transform = options?.dynamicSegmentTransform || this.defaultTransform;\n\n if (this.isOptionalCatchAll(segment)) {\n const name = segment.match(this.SEGMENT_PATTERNS.OPTIONAL_CATCH_ALL)![1];\n return transform(`${name}*?`);\n }\n\n if (this.isCatchAll(segment)) {\n const name = segment.match(this.SEGMENT_PATTERNS.CATCH_ALL)![1];\n return transform(`${name}*`);\n }\n\n if (this.isDynamicSegment(segment)) {\n const name = segment.match(this.SEGMENT_PATTERNS.DYNAMIC)![1];\n return transform(name);\n }\n\n return segment;\n }\n\n private static defaultTransform(name: string): string {\n return `:${name}`;\n }\n\n private static isGroupSegment(segment: string): boolean {\n return this.SEGMENT_PATTERNS.GROUP.test(segment);\n }\n\n private static isOptionalCatchAll(segment: string): boolean {\n return this.SEGMENT_PATTERNS.OPTIONAL_CATCH_ALL.test(segment);\n }\n\n private static isCatchAll(segment: string): boolean {\n return this.SEGMENT_PATTERNS.CATCH_ALL.test(segment);\n }\n\n private static isDynamicSegment(segment: string): boolean {\n return this.SEGMENT_PATTERNS.DYNAMIC.test(segment);\n }\n}","import {SegmentParser} from './segmentParser';\nimport {ParserOptions, RouteFile, RouteNode} from \"../../types\";\n\nexport class RouteTreeBuilder {\n private readonly typeSetters: Record<string, (node: RouteNode, route: RouteFile) => void>;\n\n constructor() {\n this.typeSetters = {\n layout: (node, route) => {\n node.layout = route.componentName;\n },\n error: (node, route) => {\n node.error = route.componentName;\n },\n loading: (node, route) => {\n node.loading = route.componentName;\n },\n 'not-found': (node, route) => {\n node.notFound = route.componentName;\n },\n page: this.handlePageType.bind(this)\n };\n }\n\n build(routes: RouteFile[], options?: ParserOptions): RouteNode {\n const root: RouteNode = {\n segment: '',\n path: '/',\n fullPath: '/',\n children: new Map(),\n metadata: options?.metadata\n };\n\n const sortedRoutes = this.sortRoutes(routes);\n sortedRoutes.forEach(route => {\n this.processRoute(root, route, options);\n });\n\n return root;\n }\n\n private sortRoutes(routes: RouteFile[]): RouteFile[] {\n return [...routes].sort((a, b) =>\n a.type === 'layout' && b.type !== 'layout' ? -1 :\n a.type !== 'layout' && b.type === 'layout' ? 1 : 0\n );\n }\n\n private processRoute(root: RouteNode, route: RouteFile, options?: ParserOptions): void {\n const segments = route.segments.map(seg => String(seg));\n\n if (segments.length === 0) {\n this.applyTypeHandler(root, route);\n if (route.type === 'page') root.isIndex = true;\n return;\n }\n\n let current = root;\n let currentPath = '';\n\n segments.forEach((seg, idx) => {\n const isLast = idx === segments.length - 1;\n const key = SegmentParser.normalize(seg, options);\n\n if (key === null) return;\n\n currentPath = this.buildFullPath(currentPath, key);\n\n if (!current.children.has(key)) {\n current.children.set(key, {\n segment: key,\n path: key,\n fullPath: currentPath,\n children: new Map(),\n metadata: options?.metadata\n });\n }\n\n current = current.children.get(key)!;\n\n if (isLast) this.applyTypeHandler(current, route);\n });\n }\n\n private buildFullPath(currentPath: string, key: string): string {\n if (currentPath === '' || currentPath === '/') {\n return key === '' ? '/' : `/${key}`;\n }\n return `${currentPath}/${key}`;\n }\n\n private applyTypeHandler(node: RouteNode, route: RouteFile): void {\n const handler = this.typeSetters[route.type];\n if (handler) handler(node, route);\n }\n\n private handlePageType(node: RouteNode, route: RouteFile): void {\n const lastSegment = route.segments[route.segments.length - 1];\n const isDynamic = lastSegment?.startsWith('[');\n\n if (isDynamic || lastSegment === '') {\n node.component = route.componentName;\n node.isIndex = false;\n } else {\n node.indexPage = route.componentName;\n }\n }\n}","import { RouteNode } from \"../../types\";\n\nexport class RouteDefinitionGenerator {\n static generate(node: RouteNode, indent = ' '): string {\n const childNodes = Array.from(node.children.values());\n const children: string[] = [];\n\n if (node.indexPage) {\n children.push(this.generateIndexRoute(node, indent));\n }\n\n children.push(...childNodes.map(child =>\n this.generate(child, indent + ' ')\n ));\n\n return this.generateRouteObject(node, children, indent);\n }\n\n private static generateIndexRoute(node: RouteNode, indent: string): string {\n return `${indent} {\n${indent} index: true,\n${indent} element: React.createElement(RouteWrapper, {\n${indent} Component: ${node.indexPage}\n${indent} })\n${indent} }`;\n }\n\n private static generateRouteObject(node: RouteNode, children: string[], indent: string): string {\n const pathStr = node.fullPath;\n const elementStr = this.generateElementString(node, indent);\n const errorStr = this.generateErrorString(node, indent);\n\n return [\n `${indent}{`,\n `${indent} path: '${pathStr}'${elementStr}${errorStr}`,\n children.length > 0 ? `,\\n${indent} children: [\\n${children.join(',\\n')}\\n${indent} ]` : '',\n `${indent}}`\n ].filter(Boolean).join('');\n }\n\n private static generateElementString(node: RouteNode, indent: string): string {\n if (!node.layout && !node.component) return '';\n\n const props = node.layout\n ? this.generateLayoutProps(node, indent)\n : this.generateComponentProps(node, indent);\n\n return `,\\n${indent} element: React.createElement(RouteWrapper, ${props})`;\n }\n\n private static generateLayoutProps(node: RouteNode, indent: string): string {\n return `{\n${indent} Component: ${node.layout},\n${indent} isLayout: true,\n${indent} loading: ${node.loading || 'undefined'},\n${indent} notFound: ${node.notFound || 'undefined'}\n${indent} }`;\n }\n\n private static generateComponentProps(node: RouteNode, indent: string): string {\n return `{\n${indent} Component: ${node.component}\n${indent} }`;\n }\n\n private static generateErrorString(node: RouteNode, indent: string): string {\n if (!node.error) return '';\n\n return `,\\n${indent} errorElement: React.createElement(ErrorBoundary, {\n${indent} Component: ${node.error}\n${indent} })`;\n }\n}"],"mappings":"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","names":["path","path"]}
|
|
1
|
+
{"version":3,"sources":["../src/plugin.ts","../src/constants.ts","../src/generator/createRoutes.ts","../src/generator/parser/segmentParser.ts","../src/generator/parser/routeTreeBuilder.ts","../src/generator/parser/routeDefinitionGenerator.ts"],"sourcesContent":["// src/plugin.ts\nimport { Plugin } from 'vite';\nimport path from 'path';\nimport fs from 'fs';\nimport { DEFAULT_OPTIONS, RESOLVED_VIRTUAL_ROUTE_MODULE_ID, VIRTUAL_ROUTE_MODULE_ID } from './constants';\nimport {naviloOptions, RouteFile} from './types';\nimport { findRouteFiles } from './generator/createRoutes';\nimport {RouteTreeBuilder} from \"./generator/parser/routeTreeBuilder\";\nimport {RouteDefinitionGenerator} from \"./generator/parser/routeDefinitionGenerator\";\n\nexport function navilo(options: naviloOptions = {}): Plugin {\n const resolvedOptions = { ...DEFAULT_OPTIONS, ...options };\n let root: string;\n const routeTreeBuilder = new RouteTreeBuilder();\n\n return {\n name: 'navilo',\n\n configResolved(config) {\n root = config.root;\n },\n\n configureServer(server) {\n const pagesDir = path.resolve(root, resolvedOptions.pagesDir);\n\n server.watcher.add(pagesDir);\n\n const handleFileChange = (file: string) => {\n if (file.startsWith(pagesDir)) {\n const module = server.moduleGraph.getModuleById(RESOLVED_VIRTUAL_ROUTE_MODULE_ID);\n if (module) {\n server.moduleGraph.invalidateModule(module);\n }\n server.ws.send({ type: 'full-reload' });\n }\n };\n\n server.watcher.on('add', handleFileChange);\n server.watcher.on('unlink', handleFileChange);\n server.watcher.on('change', handleFileChange);\n },\n\n resolveId(id) {\n if (id === VIRTUAL_ROUTE_MODULE_ID) {\n return RESOLVED_VIRTUAL_ROUTE_MODULE_ID;\n }\n },\n\n async load(id) {\n if (id === RESOLVED_VIRTUAL_ROUTE_MODULE_ID) {\n const pagesDir = path.resolve(root, resolvedOptions.pagesDir);\n\n if (!fs.existsSync(pagesDir)) {\n fs.mkdirSync(pagesDir, { recursive: true });\n return `export const router = null;`;\n }\n\n const routes = await findRouteFiles(pagesDir);\n\n if (routes.length === 0) {\n return `export const router = null;`;\n }\n\n const routeTree = routeTreeBuilder.build(routes, {\n strict: true,\n dynamicSegmentTransform: (segment) => `:${segment.toLowerCase()}`\n });\n\n const routeDefinitions = RouteDefinitionGenerator.generate(routeTree);\n\n return routerJSX(routes, routeDefinitions);\n }\n }\n };\n}\n\nexport function routerJSX(routes: RouteFile[], routeDefinitions: string): string {\n const importMap = new Map<string, string>();\n routes.forEach(route => importMap.set(route.filePath, route.componentName));\n\n const imports = Array.from(importMap.entries())\n .map(([filePath, componentName]) => `import ${componentName} from '${filePath}';`)\n .join('\\n');\n\n return `\nimport React, { Suspense } from 'react';\nimport { createBrowserRouter, useParams, Outlet, useRouteError, isRouteErrorResponse } from 'react-router-dom';\n${imports}\n\nfunction ErrorBoundary({ Component }) {\n const error = useRouteError();\n const params = useParams();\n\n if (!Component) {\n return React.createElement('div', { className: 'error-container' },\n React.createElement('div', { className: 'error-content' }, [\n React.createElement('h1', null, \n isRouteErrorResponse(error) ? \\`\\${error.status} - \\${error.statusText}\\` : 'Error'\n ),\n React.createElement('pre', { className: 'error-stack' },\n error instanceof Error ? error.stack : JSON.stringify(error, null, 2)\n ),\n React.createElement('button', {\n onClick: () => window.location.reload()\n }, 'Try again')\n ])\n );\n }\n\n return React.createElement(Component, { error, params });\n}\n\nfunction LoadingBoundary({ Component, children }) {\n if (!Component) {\n return children;\n }\n\n return React.createElement(Suspense, {\n fallback: React.createElement(Component)\n }, children);\n}\n\nfunction RouteWrapper({ Component, isLayout, loading, notFound }) {\n const params = useParams();\n \n if (isLayout) {\n const outlet = React.createElement(Outlet);\n const content = loading ? \n React.createElement(LoadingBoundary, { Component: loading }, outlet) :\n outlet;\n\n return React.createElement(Component, {\n children: content,\n params\n });\n }\n \n return React.createElement(Component, { params });\n}\n\n// Add global error listener\nwindow.addEventListener('error', (event) => {\n console.error('Global error:', event.error);\n});\n\n// Add global promise rejection handler\nwindow.addEventListener('unhandledrejection', (event) => {\n console.error('Unhandled promise rejection:', event.reason);\n});\n\nconst router = createBrowserRouter([\n${routeDefinitions}\n], {\n defaultErrorElement: React.createElement(ErrorBoundary, { Component: ${routes.find(r => r.type === 'not-found')?.componentName || 'null'} })\n});\n\nexport { router };\n`;\n}","export const DEFAULT_OPTIONS = {\n pagesDir: 'src/app',\n typescript: true,\n};\n\nexport const VIRTUAL_ROUTE_MODULE_ID = 'virtual:navilo-routes';\nexport const RESOLVED_VIRTUAL_ROUTE_MODULE_ID = '\\0' + VIRTUAL_ROUTE_MODULE_ID;","import path from 'path';\nimport glob from 'fast-glob';\nimport { RouteFile, RouteType } from '../types';\n\n/** Normalize Windows paths to forward slashes */\nexport function normalizeFilePath(filePath: string): string {\n return filePath.replace(/\\\\/g, '/');\n}\n\n/** Determine the type of a route file */\nexport function getRouteType(filePath: string): RouteType {\n const basename = path.basename(filePath);\n const fileTypes: Record<string, RouteType> = {\n 'layout.jsx': 'layout',\n 'layout.tsx': 'layout',\n 'page.jsx': 'page',\n 'page.tsx': 'page',\n 'error.jsx': 'error',\n 'error.tsx': 'error',\n 'loading.jsx': 'loading',\n 'loading.tsx': 'loading',\n 'not-found.jsx': 'not-found',\n 'not-found.tsx': 'not-found'\n };\n return fileTypes[basename] || 'page';\n}\n\n/** Generate a PascalCase component name based on folder structure */\nexport function getComponentName(filePath: string, pagesDir: string): string {\n const segments = normalizeFilePath(path.relative(pagesDir, filePath)).split('/');\n const fileNameWithExt = segments.pop()!;\n const fileName = path.basename(fileNameWithExt, path.extname(fileNameWithExt));\n\n const relevantSegments = segments.map(segment => {\n if (segment.startsWith('[') && segment.endsWith(']')) {\n return segment.slice(1, -1)\n .replace(/^\\.\\.\\./, 'CatchAll')\n .split(/[^a-zA-Z0-9]/)\n .map(p => p.charAt(0).toUpperCase() + p.slice(1))\n .join('');\n }\n return segment\n .split(/[^a-zA-Z0-9]/)\n .map(p => p.charAt(0).toUpperCase() + p.slice(1))\n .join('');\n });\n\n const typeSuffix = {\n page: 'Page',\n layout: 'Layout',\n error: 'Error',\n loading: 'Loading',\n 'not-found': 'NotFound'\n }[fileName] || 'Component';\n\n return relevantSegments.length === 0 ? `Root${typeSuffix}` : `${relevantSegments.join('')}${typeSuffix}`;\n}\n\n/** Extract segments from file path for building route tree */\nexport function getPathSegments(filePath: string, pagesDir: string): string[] {\n const relativePath = normalizeFilePath(path.relative(pagesDir, filePath));\n const segments = relativePath.split('/');\n const fileName = segments.pop()!;\n\n const filteredSegments = segments.filter(seg => !(seg.startsWith('(') && seg.endsWith(')')));\n\n if (/^page\\.(jsx|tsx)$/.test(fileName)) {\n filteredSegments.push('');\n }\n\n return filteredSegments;\n}\n\n/** Find all route files in the pages directory */\nexport async function findRouteFiles(pagesDir: string): Promise<RouteFile[]> {\n const files = await glob(['**/*.{jsx,tsx}'], {\n cwd: pagesDir,\n absolute: true,\n ignore: ['**/node_modules/**', '**/.*/**', '**/_*/**'],\n });\n\n const validFiles = files.filter(file => {\n const base = path.basename(file);\n return /^(layout|page|error|loading|not-found)\\.(jsx|tsx)$/.test(base);\n });\n\n return validFiles.map(file => {\n const type = getRouteType(file);\n return {\n type,\n path: '/' + normalizeFilePath(path.relative(pagesDir, path.dirname(file))),\n filePath: normalizeFilePath(file),\n componentName: getComponentName(file, pagesDir),\n segments: getPathSegments(file, pagesDir),\n };\n });\n}\n","import {ParserOptions} from \"../../types\";\n\nexport class SegmentParser {\n private static readonly SEGMENT_PATTERNS = {\n OPTIONAL_CATCH_ALL: /^\\[\\[\\.{3}(.+)\\]\\]$/,\n CATCH_ALL: /^\\[\\.{3}(.+)\\]$/,\n DYNAMIC: /^\\[(.+)\\]$/,\n GROUP: /^\\((.+)\\)$/\n };\n\n static normalize(segment: string, options?: ParserOptions): string | null {\n if (this.isGroupSegment(segment)) return null;\n\n if (segment.includes('/')) {\n return segment.split('/')\n .map(seg => this.normalizeSegment(seg, options))\n .filter(Boolean)\n .join('/');\n }\n\n return this.normalizeSegment(segment, options);\n }\n\n private static normalizeSegment(segment: string, options?: ParserOptions): string | null {\n const transform = options?.dynamicSegmentTransform || this.defaultTransform;\n\n if (this.isOptionalCatchAll(segment)) {\n const name = segment.match(this.SEGMENT_PATTERNS.OPTIONAL_CATCH_ALL)![1];\n return transform(`${name}*?`);\n }\n\n if (this.isCatchAll(segment)) {\n const name = segment.match(this.SEGMENT_PATTERNS.CATCH_ALL)![1];\n return transform(`${name}*`);\n }\n\n if (this.isDynamicSegment(segment)) {\n const name = segment.match(this.SEGMENT_PATTERNS.DYNAMIC)![1];\n return transform(name);\n }\n\n return segment;\n }\n\n private static defaultTransform(name: string): string {\n return `:${name}`;\n }\n\n private static isGroupSegment(segment: string): boolean {\n return this.SEGMENT_PATTERNS.GROUP.test(segment);\n }\n\n private static isOptionalCatchAll(segment: string): boolean {\n return this.SEGMENT_PATTERNS.OPTIONAL_CATCH_ALL.test(segment);\n }\n\n private static isCatchAll(segment: string): boolean {\n return this.SEGMENT_PATTERNS.CATCH_ALL.test(segment);\n }\n\n private static isDynamicSegment(segment: string): boolean {\n return this.SEGMENT_PATTERNS.DYNAMIC.test(segment);\n }\n}","import {SegmentParser} from './segmentParser';\nimport {ParserOptions, RouteFile, RouteNode} from \"../../types\";\n\nexport class RouteTreeBuilder {\n private readonly typeSetters: Record<string, (node: RouteNode, route: RouteFile) => void>;\n\n constructor() {\n this.typeSetters = {\n layout: (node, route) => {\n node.layout = route.componentName;\n },\n error: (node, route) => {\n node.error = route.componentName;\n },\n loading: (node, route) => {\n node.loading = route.componentName;\n },\n 'not-found': (node, route) => {\n node.notFound = route.componentName;\n },\n page: this.handlePageType.bind(this)\n };\n }\n\n build(routes: RouteFile[], options?: ParserOptions): RouteNode {\n const root: RouteNode = {\n segment: '',\n path: '/',\n fullPath: '/',\n children: new Map(),\n metadata: options?.metadata\n };\n\n const sortedRoutes = this.sortRoutes(routes);\n sortedRoutes.forEach(route => {\n this.processRoute(root, route, options);\n });\n\n return root;\n }\n\n private sortRoutes(routes: RouteFile[]): RouteFile[] {\n return [...routes].sort((a, b) =>\n a.type === 'layout' && b.type !== 'layout' ? -1 :\n a.type !== 'layout' && b.type === 'layout' ? 1 : 0\n );\n }\n\n private processRoute(root: RouteNode, route: RouteFile, options?: ParserOptions): void {\n const segments = route.segments.map(seg => String(seg));\n\n if (segments.length === 0) {\n this.applyTypeHandler(root, route);\n if (route.type === 'page') root.isIndex = true;\n return;\n }\n\n let current = root;\n let currentPath = '';\n\n segments.forEach((seg, idx) => {\n const isLast = idx === segments.length - 1;\n const key = SegmentParser.normalize(seg, options);\n\n if (key === null) return;\n\n currentPath = this.buildFullPath(currentPath, key);\n\n if (!current.children.has(key)) {\n current.children.set(key, {\n segment: key,\n path: key,\n fullPath: currentPath,\n children: new Map(),\n metadata: options?.metadata\n });\n }\n\n current = current.children.get(key)!;\n\n if (isLast) this.applyTypeHandler(current, route);\n });\n }\n\n private buildFullPath(currentPath: string, key: string): string {\n if (currentPath === '' || currentPath === '/') {\n return key === '' ? '/' : `/${key}`;\n }\n return `${currentPath}/${key}`;\n }\n\n private applyTypeHandler(node: RouteNode, route: RouteFile): void {\n const handler = this.typeSetters[route.type];\n if (handler) handler(node, route);\n }\n\n private handlePageType(node: RouteNode, route: RouteFile): void {\n const lastSegment = route.segments[route.segments.length - 1];\n const isDynamic = lastSegment?.startsWith('[');\n\n if (isDynamic || lastSegment === '') {\n node.component = route.componentName;\n node.isIndex = false;\n } else {\n node.indexPage = route.componentName;\n }\n }\n}","import { RouteNode } from \"../../types\";\n\nexport class RouteDefinitionGenerator {\n static generate(node: RouteNode, indent = ' '): string {\n const childNodes = Array.from(node.children.values());\n const children: string[] = [];\n\n if (node.indexPage) {\n children.push(this.generateIndexRoute(node, indent));\n }\n\n children.push(...childNodes.map(child =>\n this.generate(child, indent + ' ')\n ));\n\n return this.generateRouteObject(node, children, indent);\n }\n\n private static generateIndexRoute(node: RouteNode, indent: string): string {\n return `${indent} {\n${indent} index: true,\n${indent} element: React.createElement(RouteWrapper, {\n${indent} Component: ${node.indexPage}\n${indent} })\n${indent} }`;\n }\n\n private static generateRouteObject(node: RouteNode, children: string[], indent: string): string {\n const pathStr = node.fullPath;\n const elementStr = this.generateElementString(node, indent);\n const errorStr = this.generateErrorString(node, indent);\n\n return [\n `${indent}{`,\n `${indent} path: '${pathStr}'${elementStr}${errorStr}`,\n children.length > 0 ? `,\\n${indent} children: [\\n${children.join(',\\n')}\\n${indent} ]` : '',\n `${indent}}`\n ].filter(Boolean).join('');\n }\n\n private static generateElementString(node: RouteNode, indent: string): string {\n if (!node.layout && !node.component) return '';\n\n const props = node.layout\n ? this.generateLayoutProps(node, indent)\n : this.generateComponentProps(node, indent);\n\n return `,\\n${indent} element: React.createElement(RouteWrapper, ${props})`;\n }\n\n private static generateLayoutProps(node: RouteNode, indent: string): string {\n return `{\n${indent} Component: ${node.layout},\n${indent} isLayout: true,\n${indent} loading: ${node.loading || 'undefined'},\n${indent} notFound: ${node.notFound || 'undefined'}\n${indent} }`;\n }\n\n private static generateComponentProps(node: RouteNode, indent: string): string {\n return `{\n${indent} Component: ${node.component}\n${indent} }`;\n }\n\n private static generateErrorString(node: RouteNode, indent: string): string {\n if (!node.error) return '';\n\n return `,\\n${indent} errorElement: React.createElement(ErrorBoundary, {\n${indent} Component: ${node.error}\n${indent} })`;\n }\n}"],"mappings":"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","names":["path","path"]}
|