@zenithbuild/router 0.5.0-beta.2.3
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 +130 -0
- package/dist/ZenLink.zen +7 -0
- package/dist/events.js +53 -0
- package/dist/history.js +84 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/manifest.d.ts +32 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +180 -0
- package/dist/manifest.js.map +1 -0
- package/dist/match.js +191 -0
- package/dist/navigate.js +67 -0
- package/dist/navigation/client-router.d.ts +59 -0
- package/dist/navigation/client-router.d.ts.map +1 -0
- package/dist/navigation/client-router.js +373 -0
- package/dist/navigation/client-router.js.map +1 -0
- package/dist/navigation/index.d.ts +30 -0
- package/dist/navigation/index.d.ts.map +1 -0
- package/dist/navigation/index.js +44 -0
- package/dist/navigation/index.js.map +1 -0
- package/dist/navigation/zen-link.d.ts +234 -0
- package/dist/navigation/zen-link.d.ts.map +1 -0
- package/dist/navigation/zen-link.js +437 -0
- package/dist/navigation/zen-link.js.map +1 -0
- package/dist/router.js +111 -0
- package/dist/runtime.d.ts +33 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +157 -0
- package/dist/runtime.js.map +1 -0
- package/dist/types.d.ts +50 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/package.json +62 -0
- package/template.js +260 -0
package/README.md
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# @zenith/router
|
|
2
|
+
|
|
3
|
+
> **⚠️ Internal API:** This package is an internal implementation detail of the Zenith framework. It is not intended for public use and its API may break without warning. Please use `@zenithbuild/core` instead.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
File-based SPA router for Zenith framework with **deterministic, compile-time route resolution**.
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- 📁 **File-based routing** — Pages in `pages/` directory become routes automatically
|
|
11
|
+
- ⚡ **Compile-time resolution** — Route manifest generated at build time, not runtime
|
|
12
|
+
- 🔗 **ZenLink component** — Declarative navigation with prefetching
|
|
13
|
+
- 🧭 **Programmatic navigation** — `navigate()`, `prefetch()`, `isActive()` APIs
|
|
14
|
+
- 🎯 **Type-safe** — Full TypeScript support with route parameter inference
|
|
15
|
+
- 🚀 **Hydration-safe** — No runtime hacks, works seamlessly with SSR/SSG
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
bun add @zenith/router
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
### Programmatic Navigation
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
import { navigate, prefetch, isActive, getRoute } from '@zenith/router'
|
|
29
|
+
|
|
30
|
+
// Navigate to a route
|
|
31
|
+
navigate('/about')
|
|
32
|
+
|
|
33
|
+
// Navigate with replace (no history entry)
|
|
34
|
+
navigate('/dashboard', { replace: true })
|
|
35
|
+
|
|
36
|
+
// Prefetch a route for faster navigation
|
|
37
|
+
prefetch('/blog')
|
|
38
|
+
|
|
39
|
+
// Check if a route is active
|
|
40
|
+
if (isActive('/blog')) {
|
|
41
|
+
console.log('Currently on blog section')
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Get current route state
|
|
45
|
+
const { path, params, query } = getRoute()
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### ZenLink Component (in .zen files)
|
|
49
|
+
|
|
50
|
+
```html
|
|
51
|
+
<ZenLink href="/about">About Us</ZenLink>
|
|
52
|
+
|
|
53
|
+
<!-- With prefetching on hover -->
|
|
54
|
+
<ZenLink href="/blog" preload>Blog</ZenLink>
|
|
55
|
+
|
|
56
|
+
<!-- External links automatically open in new tab -->
|
|
57
|
+
<ZenLink href="https://github.com">GitHub</ZenLink>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Build-time Route Manifest
|
|
61
|
+
|
|
62
|
+
The router generates a route manifest at compile time:
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
import { generateRouteManifest, discoverPages } from '@zenith/router/manifest'
|
|
66
|
+
|
|
67
|
+
const pagesDir = './src/pages'
|
|
68
|
+
const manifest = generateRouteManifest(pagesDir)
|
|
69
|
+
|
|
70
|
+
// manifest contains:
|
|
71
|
+
// - path: Route pattern (e.g., /blog/:id)
|
|
72
|
+
// - regex: Compiled RegExp for matching
|
|
73
|
+
// - paramNames: Dynamic segment names
|
|
74
|
+
// - score: Priority for deterministic matching
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Route Patterns
|
|
78
|
+
|
|
79
|
+
| File Path | Route Pattern |
|
|
80
|
+
|-----------|---------------|
|
|
81
|
+
| `pages/index.zen` | `/` |
|
|
82
|
+
| `pages/about.zen` | `/about` |
|
|
83
|
+
| `pages/blog/index.zen` | `/blog` |
|
|
84
|
+
| `pages/blog/[id].zen` | `/blog/:id` |
|
|
85
|
+
| `pages/posts/[...slug].zen` | `/posts/*slug` |
|
|
86
|
+
| `pages/[[...all]].zen` | `/*all?` (optional) |
|
|
87
|
+
|
|
88
|
+
## Architecture
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
@zenith/router
|
|
92
|
+
├── src/
|
|
93
|
+
│ ├── index.ts # Main exports
|
|
94
|
+
│ ├── types.ts # Core types
|
|
95
|
+
│ ├── manifest.ts # Build-time manifest generation
|
|
96
|
+
│ ├── runtime.ts # Client-side SPA router
|
|
97
|
+
│ └── navigation/
|
|
98
|
+
│ ├── index.ts # Navigation exports
|
|
99
|
+
│ ├── zen-link.ts # Navigation API
|
|
100
|
+
│ └── ZenLink.zen # Declarative component
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## API Reference
|
|
104
|
+
|
|
105
|
+
### Navigation Functions
|
|
106
|
+
|
|
107
|
+
- `navigate(path, options?)` — Navigate to a path
|
|
108
|
+
- `prefetch(path)` — Prefetch a route for faster navigation
|
|
109
|
+
- `isActive(path, exact?)` — Check if path is currently active
|
|
110
|
+
- `getRoute()` — Get current route state
|
|
111
|
+
- `back()`, `forward()`, `go(delta)` — History navigation
|
|
112
|
+
|
|
113
|
+
### Manifest Generation
|
|
114
|
+
|
|
115
|
+
- `discoverPages(pagesDir)` — Find all .zen files in pages directory
|
|
116
|
+
- `generateRouteManifest(pagesDir)` — Generate complete route manifest
|
|
117
|
+
- `filePathToRoutePath(filePath, pagesDir)` — Convert file path to route
|
|
118
|
+
- `routePathToRegex(routePath)` — Compile route to RegExp
|
|
119
|
+
|
|
120
|
+
### Types
|
|
121
|
+
|
|
122
|
+
- `RouteState` — Current route state (path, params, query)
|
|
123
|
+
- `RouteRecord` — Compiled route definition
|
|
124
|
+
- `NavigateOptions` — Options for navigation
|
|
125
|
+
- `ZenLinkProps` — Props for ZenLink component
|
|
126
|
+
|
|
127
|
+
## License
|
|
128
|
+
|
|
129
|
+
MIT
|
|
130
|
+
# zenith-router
|
package/dist/ZenLink.zen
ADDED
package/dist/events.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// events.js — Zenith Router V0
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// Route change event system.
|
|
5
|
+
//
|
|
6
|
+
// Subscribers receive route change notifications.
|
|
7
|
+
// Returns unsubscribe function.
|
|
8
|
+
// No batching. No queue. Synchronous dispatch.
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
|
|
11
|
+
/** @type {Set<(detail: object) => void>} */
|
|
12
|
+
const _subscribers = new Set();
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Subscribe to route change events.
|
|
16
|
+
*
|
|
17
|
+
* @param {(detail: { path: string, params?: Record<string, string>, matched: boolean }) => void} callback
|
|
18
|
+
* @returns {() => void} unsubscribe
|
|
19
|
+
*/
|
|
20
|
+
export function onRouteChange(callback) {
|
|
21
|
+
_subscribers.add(callback);
|
|
22
|
+
|
|
23
|
+
return () => {
|
|
24
|
+
_subscribers.delete(callback);
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Dispatch a route change to all subscribers.
|
|
30
|
+
*
|
|
31
|
+
* @param {{ path: string, params?: Record<string, string>, matched: boolean }} detail
|
|
32
|
+
*/
|
|
33
|
+
export function _dispatchRouteChange(detail) {
|
|
34
|
+
for (const cb of _subscribers) {
|
|
35
|
+
cb(detail);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Clear all subscribers. Used for testing and teardown.
|
|
41
|
+
*/
|
|
42
|
+
export function _clearSubscribers() {
|
|
43
|
+
_subscribers.clear();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Get the current subscriber count. Used for leak detection.
|
|
48
|
+
*
|
|
49
|
+
* @returns {number}
|
|
50
|
+
*/
|
|
51
|
+
export function _getSubscriberCount() {
|
|
52
|
+
return _subscribers.size;
|
|
53
|
+
}
|
package/dist/history.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// history.js — Zenith Router V0
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// Minimal navigation helpers without History API mutation.
|
|
5
|
+
//
|
|
6
|
+
// - push(path) → hard navigation (assign)
|
|
7
|
+
// - replace(path) → hard navigation (replace)
|
|
8
|
+
// - listen(cb) → popstate listener, returns unlisten
|
|
9
|
+
// - current() → location.pathname
|
|
10
|
+
//
|
|
11
|
+
// No hash routing. No scroll restoration. No batching.
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
|
|
14
|
+
/** @type {Set<(path: string) => void>} */
|
|
15
|
+
const _listeners = new Set();
|
|
16
|
+
|
|
17
|
+
/** @type {boolean} */
|
|
18
|
+
let _listening = false;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Internal popstate handler — fires all registered listeners.
|
|
22
|
+
*/
|
|
23
|
+
function _onPopState() {
|
|
24
|
+
const path = current();
|
|
25
|
+
for (const cb of _listeners) {
|
|
26
|
+
cb(path);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Ensure the global popstate listener is attached (once).
|
|
32
|
+
*/
|
|
33
|
+
function _ensureListening() {
|
|
34
|
+
if (_listening) return;
|
|
35
|
+
window.addEventListener('popstate', _onPopState);
|
|
36
|
+
_listening = true;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Push a new path to the browser history.
|
|
41
|
+
*
|
|
42
|
+
* @param {string} path
|
|
43
|
+
*/
|
|
44
|
+
export function push(path) {
|
|
45
|
+
window.location.assign(path);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Replace the current path in browser history.
|
|
50
|
+
*
|
|
51
|
+
* @param {string} path
|
|
52
|
+
*/
|
|
53
|
+
export function replace(path) {
|
|
54
|
+
window.location.replace(path);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Subscribe to popstate (back/forward) events.
|
|
59
|
+
* Returns an unlisten function.
|
|
60
|
+
*
|
|
61
|
+
* @param {(path: string) => void} callback
|
|
62
|
+
* @returns {() => void} unlisten
|
|
63
|
+
*/
|
|
64
|
+
export function listen(callback) {
|
|
65
|
+
_ensureListening();
|
|
66
|
+
_listeners.add(callback);
|
|
67
|
+
|
|
68
|
+
return () => {
|
|
69
|
+
_listeners.delete(callback);
|
|
70
|
+
if (_listeners.size === 0) {
|
|
71
|
+
window.removeEventListener('popstate', _onPopState);
|
|
72
|
+
_listening = false;
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Get the current pathname.
|
|
79
|
+
*
|
|
80
|
+
* @returns {string}
|
|
81
|
+
*/
|
|
82
|
+
export function current() {
|
|
83
|
+
return window.location.pathname;
|
|
84
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @zenithbuild/router
|
|
3
|
+
*
|
|
4
|
+
* File-based SPA router for Zenith framework.
|
|
5
|
+
* Includes routing, navigation, and ZenLink components.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Deterministic, compile-time route resolution
|
|
9
|
+
* - File-based routing (pages/ directory → routes)
|
|
10
|
+
* - SPA navigation with prefetching
|
|
11
|
+
* - ZenLink component for declarative links
|
|
12
|
+
* - Type-safe route parameters
|
|
13
|
+
* - Hydration-safe, no runtime hacks
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* import { navigate, isActive, prefetch } from '@zenithbuild/router'
|
|
18
|
+
*
|
|
19
|
+
* // Navigate programmatically
|
|
20
|
+
* navigate('/about')
|
|
21
|
+
*
|
|
22
|
+
* // Check active state
|
|
23
|
+
* if (isActive('/blog')) {
|
|
24
|
+
* console.log('On blog section')
|
|
25
|
+
* }
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```ts
|
|
30
|
+
* // Build-time manifest generation
|
|
31
|
+
* import { generateRouteManifest, discoverPages } from '@zenithbuild/router/manifest'
|
|
32
|
+
*
|
|
33
|
+
* const manifest = generateRouteManifest('./src/pages')
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export * from "./types";
|
|
37
|
+
export { generateRouteManifest, generateRouteManifestCode } from "./manifest";
|
|
38
|
+
export { initRouter, resolveRoute, navigate, getRoute, onRouteChange, isActive, prefetch, isPrefetched, generateRuntimeRouterCode, zenRoute } from "./runtime";
|
|
39
|
+
export { zenNavigate, zenBack, zenForward, zenGo, zenIsActive, zenPrefetch, zenIsPrefetched, zenGetRoute, zenGetParam, zenGetQuery, createZenLink, zenLink, back, forward, go, getParam, getQuery, isExternalUrl, shouldUseSPANavigation, normalizePath, setGlobalTransition, getGlobalTransition, createTransitionContext } from "./navigation/index";
|
|
40
|
+
export type { ZenLinkProps, TransitionContext, TransitionHandler } from "./navigation/index";
|
|
41
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAMH,cAAc,SAAS,CAAA;AAMvB,OAAO,EACH,qBAAqB,EACrB,yBAAyB,EAC5B,MAAM,YAAY,CAAA;AAMnB,OAAO,EACH,UAAU,EACV,YAAY,EACZ,QAAQ,EACR,QAAQ,EACR,aAAa,EACb,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,yBAAyB,EACzB,QAAQ,EACX,MAAM,WAAW,CAAA;AAMlB,OAAO,EAEH,WAAW,EACX,OAAO,EACP,UAAU,EACV,KAAK,EACL,WAAW,EACX,WAAW,EACX,eAAe,EACf,WAAW,EACX,WAAW,EACX,WAAW,EACX,aAAa,EACb,OAAO,EAEP,IAAI,EACJ,OAAO,EACP,EAAE,EACF,QAAQ,EACR,QAAQ,EACR,aAAa,EACb,sBAAsB,EACtB,aAAa,EACb,mBAAmB,EACnB,mBAAmB,EACnB,uBAAuB,EAC1B,MAAM,oBAAoB,CAAA;AAM3B,YAAY,EACR,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,EACpB,MAAM,oBAAoB,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// index.js — Zenith Router V0 Public API
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// Seven exports. No more.
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
|
|
7
|
+
export { createRouter } from './router.js';
|
|
8
|
+
export { navigate, back, forward, getCurrentPath } from './navigate.js';
|
|
9
|
+
export { onRouteChange } from './events.js';
|
|
10
|
+
export { matchRoute } from './match.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,+CAA+C;AAC/C,aAAa;AACb,+CAA+C;AAE/C,cAAc,SAAS,CAAA;AAEvB,+CAA+C;AAC/C,iCAAiC;AACjC,+CAA+C;AAE/C,OAAO,EACH,qBAAqB,EACrB,yBAAyB,EAC5B,MAAM,YAAY,CAAA;AAEnB,+CAA+C;AAC/C,iBAAiB;AACjB,+CAA+C;AAE/C,OAAO,EACH,UAAU,EACV,YAAY,EACZ,QAAQ,EACR,QAAQ,EACR,aAAa,EACb,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,yBAAyB,EACzB,QAAQ,EACX,MAAM,WAAW,CAAA;AAElB,+CAA+C;AAC/C,uBAAuB;AACvB,+CAA+C;AAE/C,OAAO;AACH,uCAAuC;AACvC,WAAW,EACX,OAAO,EACP,UAAU,EACV,KAAK,EACL,WAAW,EACX,WAAW,EACX,eAAe,EACf,WAAW,EACX,WAAW,EACX,WAAW,EACX,aAAa,EACb,OAAO;AACP,kCAAkC;AAClC,IAAI,EACJ,OAAO,EACP,EAAE,EACF,QAAQ,EACR,QAAQ,EACR,aAAa,EACb,sBAAsB,EACtB,aAAa,EACb,mBAAmB,EACnB,mBAAmB,EACnB,uBAAuB,EAC1B,MAAM,oBAAoB,CAAA"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type RouteDefinition, type ParsedSegment } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Discover all .zen files in the pages directory
|
|
4
|
+
*/
|
|
5
|
+
export declare function discoverPages(pagesDir: string): string[];
|
|
6
|
+
/**
|
|
7
|
+
* Convert a file path to a route path
|
|
8
|
+
*/
|
|
9
|
+
export declare function filePathToRoutePath(filePath: string, pagesDir: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* Parse a route path into segments
|
|
12
|
+
*/
|
|
13
|
+
export declare function parseRouteSegments(routePath: string): ParsedSegment[];
|
|
14
|
+
/**
|
|
15
|
+
* Calculate route score
|
|
16
|
+
*/
|
|
17
|
+
export declare function calculateRouteScore(segments: ParsedSegment[]): number;
|
|
18
|
+
/**
|
|
19
|
+
* Extract parameter names
|
|
20
|
+
*/
|
|
21
|
+
export declare function extractParamNames(segments: ParsedSegment[]): string[];
|
|
22
|
+
/**
|
|
23
|
+
* Convert route path to regex pattern
|
|
24
|
+
*/
|
|
25
|
+
export declare function routePathToRegex(routePath: string): RegExp;
|
|
26
|
+
/**
|
|
27
|
+
* Generate a route definition from a file path
|
|
28
|
+
*/
|
|
29
|
+
export declare function generateRouteDefinition(filePath: string, pagesDir: string): RouteDefinition;
|
|
30
|
+
export declare function generateRouteManifest(pagesDir: string): RouteDefinition[];
|
|
31
|
+
export declare function generateRouteManifestCode(definitions: RouteDefinition[]): string;
|
|
32
|
+
//# sourceMappingURL=manifest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAGA,OAAO,EACH,KAAK,eAAe,EACpB,KAAK,aAAa,EAErB,MAAM,SAAS,CAAA;AAchB;;GAEG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAqBxD;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAgC9E;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,EAAE,CAuBrE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,MAAM,CASrE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,MAAM,EAAE,CAIrE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CA2B1D;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,eAAe,CAc3F;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,eAAe,EAAE,CAMzE;AAED,wBAAgB,yBAAyB,CAAC,WAAW,EAAE,eAAe,EAAE,GAAG,MAAM,CAahF"}
|
package/dist/manifest.js
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import native from "../index.js";
|
|
4
|
+
const { generateRouteManifestNative } = native;
|
|
5
|
+
/**
|
|
6
|
+
* Scoring constants for route ranking
|
|
7
|
+
*/
|
|
8
|
+
const SEGMENT_SCORES = {
|
|
9
|
+
[0 /* SegmentType.Static */]: 10,
|
|
10
|
+
[1 /* SegmentType.Dynamic */]: 5,
|
|
11
|
+
[2 /* SegmentType.CatchAll */]: 1,
|
|
12
|
+
[3 /* SegmentType.OptionalCatchAll */]: 0
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Discover all .zen files in the pages directory
|
|
16
|
+
*/
|
|
17
|
+
export function discoverPages(pagesDir) {
|
|
18
|
+
const pages = [];
|
|
19
|
+
function walk(dir) {
|
|
20
|
+
if (!fs.existsSync(dir))
|
|
21
|
+
return;
|
|
22
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
23
|
+
for (const entry of entries) {
|
|
24
|
+
const fullPath = path.join(dir, entry.name);
|
|
25
|
+
if (entry.isDirectory()) {
|
|
26
|
+
walk(fullPath);
|
|
27
|
+
}
|
|
28
|
+
else if (entry.isFile() && entry.name.endsWith(".zen")) {
|
|
29
|
+
pages.push(fullPath);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
walk(pagesDir);
|
|
34
|
+
return pages;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Convert a file path to a route path
|
|
38
|
+
*/
|
|
39
|
+
export function filePathToRoutePath(filePath, pagesDir) {
|
|
40
|
+
const relativePath = path.relative(pagesDir, filePath);
|
|
41
|
+
const withoutExt = relativePath.replace(/\.zen$/, "");
|
|
42
|
+
const segmentsList = withoutExt.split(path.sep);
|
|
43
|
+
const routeSegments = [];
|
|
44
|
+
for (const segment of segmentsList) {
|
|
45
|
+
if (segment === "index")
|
|
46
|
+
continue;
|
|
47
|
+
const optionalCatchAllMatch = segment.match(/^\[\[\.\.\.(\w+)\]\]$/);
|
|
48
|
+
if (optionalCatchAllMatch) {
|
|
49
|
+
routeSegments.push(`*${optionalCatchAllMatch[1]}?`);
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
const catchAllMatch = segment.match(/^\[\.\.\.(\w+)\]$/);
|
|
53
|
+
if (catchAllMatch) {
|
|
54
|
+
routeSegments.push(`*${catchAllMatch[1]}`);
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
const dynamicMatch = segment.match(/^\[(\w+)\]$/);
|
|
58
|
+
if (dynamicMatch) {
|
|
59
|
+
routeSegments.push(`:${dynamicMatch[1]}`);
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
routeSegments.push(segment);
|
|
63
|
+
}
|
|
64
|
+
const routePath = "/" + routeSegments.join("/");
|
|
65
|
+
return routePath === "/" ? "/" : routePath.replace(/\/$/, "");
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Parse a route path into segments
|
|
69
|
+
*/
|
|
70
|
+
export function parseRouteSegments(routePath) {
|
|
71
|
+
if (routePath === "/")
|
|
72
|
+
return [];
|
|
73
|
+
const segmentsList = routePath.slice(1).split("/");
|
|
74
|
+
const parsed = [];
|
|
75
|
+
for (const segment of segmentsList) {
|
|
76
|
+
if (segment.startsWith("*") && segment.endsWith("?")) {
|
|
77
|
+
parsed.push({ segmentType: 3 /* SegmentType.OptionalCatchAll */, paramName: segment.slice(1, -1), raw: segment });
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (segment.startsWith("*")) {
|
|
81
|
+
parsed.push({ segmentType: 2 /* SegmentType.CatchAll */, paramName: segment.slice(1), raw: segment });
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if (segment.startsWith(":")) {
|
|
85
|
+
parsed.push({ segmentType: 1 /* SegmentType.Dynamic */, paramName: segment.slice(1), raw: segment });
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
parsed.push({ segmentType: 0 /* SegmentType.Static */, raw: segment });
|
|
89
|
+
}
|
|
90
|
+
return parsed;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Calculate route score
|
|
94
|
+
*/
|
|
95
|
+
export function calculateRouteScore(segments) {
|
|
96
|
+
if (segments.length === 0)
|
|
97
|
+
return 100;
|
|
98
|
+
let score = 0;
|
|
99
|
+
for (const segment of segments) {
|
|
100
|
+
score += SEGMENT_SCORES[segment.segmentType];
|
|
101
|
+
}
|
|
102
|
+
const staticCount = segments.filter(s => s.segmentType === 0 /* SegmentType.Static */).length;
|
|
103
|
+
score += staticCount * 2;
|
|
104
|
+
return score;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Extract parameter names
|
|
108
|
+
*/
|
|
109
|
+
export function extractParamNames(segments) {
|
|
110
|
+
return segments
|
|
111
|
+
.filter(s => s.paramName !== undefined)
|
|
112
|
+
.map(s => s.paramName);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Convert route path to regex pattern
|
|
116
|
+
*/
|
|
117
|
+
export function routePathToRegex(routePath) {
|
|
118
|
+
if (routePath === "/")
|
|
119
|
+
return /^\/$/;
|
|
120
|
+
const segmentsList = routePath.slice(1).split("/");
|
|
121
|
+
const regexParts = [];
|
|
122
|
+
for (let i = 0; i < segmentsList.length; i++) {
|
|
123
|
+
const segment = segmentsList[i];
|
|
124
|
+
if (!segment)
|
|
125
|
+
continue;
|
|
126
|
+
if (segment.startsWith("*") && segment.endsWith("?")) {
|
|
127
|
+
regexParts.push("(?:\\/(.*))?");
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
if (segment.startsWith("*")) {
|
|
131
|
+
regexParts.push("\\/(.+)");
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
if (segment.startsWith(":")) {
|
|
135
|
+
regexParts.push("\\/([^/]+)");
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
const escaped = segment.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
139
|
+
regexParts.push(`\\/${escaped}`);
|
|
140
|
+
}
|
|
141
|
+
return new RegExp(`^${regexParts.join("")}\\/?$`);
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Generate a route definition from a file path
|
|
145
|
+
*/
|
|
146
|
+
export function generateRouteDefinition(filePath, pagesDir) {
|
|
147
|
+
const routePath = filePathToRoutePath(filePath, pagesDir);
|
|
148
|
+
const segments = parseRouteSegments(routePath);
|
|
149
|
+
const paramNames = extractParamNames(segments);
|
|
150
|
+
const score = calculateRouteScore(segments);
|
|
151
|
+
// Note: RouteDefinition extends RouteRecord, which no longer has segments
|
|
152
|
+
return {
|
|
153
|
+
path: routePath,
|
|
154
|
+
paramNames,
|
|
155
|
+
score,
|
|
156
|
+
filePath,
|
|
157
|
+
regex: routePathToRegex(routePath)
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
export function generateRouteManifest(pagesDir) {
|
|
161
|
+
// Optional: use native generator if available, but for now we keep the TS one for build-time safety
|
|
162
|
+
const pages = discoverPages(pagesDir);
|
|
163
|
+
const definitions = pages.map(filePath => generateRouteDefinition(filePath, pagesDir));
|
|
164
|
+
definitions.sort((a, b) => b.score - a.score);
|
|
165
|
+
return definitions;
|
|
166
|
+
}
|
|
167
|
+
export function generateRouteManifestCode(definitions) {
|
|
168
|
+
const routeEntries = definitions.map(def => {
|
|
169
|
+
const regex = routePathToRegex(def.path);
|
|
170
|
+
return ` {
|
|
171
|
+
path: ${JSON.stringify(def.path)},
|
|
172
|
+
regex: ${regex.toString()},
|
|
173
|
+
paramNames: ${JSON.stringify(def.paramNames)},
|
|
174
|
+
score: ${def.score},
|
|
175
|
+
filePath: ${JSON.stringify(def.filePath)}
|
|
176
|
+
}`;
|
|
177
|
+
});
|
|
178
|
+
return `// Auto-generated route manifest\n// Do not edit directly\n\nexport const routeManifest = [\n${routeEntries.join(",\n")}\n];\n`;
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"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"}
|