next-vite-router 1.2.4 → 1.3.0

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 CHANGED
@@ -4,7 +4,7 @@ File-based routing for React + Vite.
4
4
 
5
5
  Define routes with folders and let the package generate the
6
6
  [React Router](https://reactrouter.com/) `RouteObject[]`. It does not replace
7
- React Router, navigation, history, loaders, or application state.
7
+ React Router, navigation, history, or application state.
8
8
 
9
9
  ## Start here
10
10
 
@@ -31,6 +31,10 @@ export default defineConfig({
31
31
  });
32
32
  ```
33
33
 
34
+ The plugin ships both ESM and CJS, so this works when `package.json` has no
35
+ `"type": "module"` (Vite 5 loads `vite.config.ts` with `require()` in that
36
+ case). You can also rename the file to `vite.config.mts` to force ESM.
37
+
34
38
  Create your route tree:
35
39
 
36
40
  ```text
@@ -88,10 +92,12 @@ npm run dev
88
92
 
89
93
  ## Use React Router directly
90
94
 
91
- `Router` is only a convenience wrapper around `useRoutes(routes)`. Routes are
92
- generated lazily on the first render, so calls to `configureRouter` and
93
- `registerMiddleware` made during application setup are applied before route
94
- elements are created. You can keep using React Router APIs:
95
+ `Router` is only a convenience wrapper around `useRoutes(routes)`. The
96
+ lazy-loading behavior and `loadingFallback` configured through `configureRouter`
97
+ are read at render time, so they take effect even when `generateRoutes()` runs
98
+ at module scope before application setup finishes. Register middleware with
99
+ `registerMiddleware` *before* calling `generateRoutes()`, because route elements
100
+ are wrapped while the tree is built. You can keep using React Router APIs:
95
101
 
96
102
  ```tsx
97
103
  import {
@@ -115,10 +121,18 @@ export default function App() {
115
121
  }
116
122
  ```
117
123
 
118
- Use `useNavigate`, loaders, actions, and other React Router APIs from
119
- `react-router-dom`. The package `useParams` hook is also available from the
120
- virtual module and maps catch-all names such as `slug`. The package does not
121
- create competing navigation or data-loading APIs.
124
+ Keep using React Router's navigation and hooks from `react-router-dom`
125
+ (`useNavigate`, `useLocation`, `Link`, `Outlet`). For parameters, import
126
+ `useParams` from the virtual module instead of `react-router-dom`: dynamic
127
+ `[id]` segments work with either hook, but named catch-all segments
128
+ (`[...slug]`, `[[...slug]]`) are only surfaced as `slug` through the package
129
+ `useParams`. React Router's own `useParams` returns them under `params["*"]`.
130
+
131
+ The generated `RouteObject[]` carries page, layout, and not-found elements only.
132
+ There is no file convention that produces React Router route `loader` or
133
+ `action` functions, and those data APIs run only under a data router
134
+ (`createBrowserRouter` + `RouterProvider`), not under `BrowserRouter` with
135
+ `useRoutes`. Fetch data inside your page components instead.
122
136
 
123
137
  ## File conventions
124
138
 
@@ -210,6 +224,9 @@ configureRouter({
210
224
  });
211
225
  ```
212
226
 
227
+ The fallback is resolved when a route suspends during render, so the order of
228
+ `configureRouter` relative to `generateRoutes()` does not matter.
229
+
213
230
  `enableLazyLoading: false` is available for compatibility and testing. It does
214
231
  not turn Vite's asynchronous imports into synchronous imports.
215
232
 
package/dist/cli.cjs CHANGED
@@ -548,7 +548,7 @@ const init = new commander.Command().name("init").description(
548
548
  Project "${projectName}" is ready!
549
549
  `);
550
550
  });
551
- const version = "1.2.4";
551
+ const version = "1.3.0";
552
552
  const pkg = {
553
553
  version
554
554
  };
package/dist/index.cjs ADDED
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const c=require("./tree-hc1dSMdb.cjs"),l=require("react"),S=require("react-router-dom"),C={enableLazyLoading:!0};let f={...C};function v(e){f={...f,...e}}function F(){f={...C}}function T(){return f}let g=[];function x(e,t){g.push({pattern:e,middleware:t})}function A(){g=[]}function y(e,t){let r=t;for(const n of g)n.pattern.lastIndex=0,n.pattern.test(e)&&(r=n.middleware(r)),n.pattern.lastIndex=0;return r}const M=()=>l.createElement("div"),h=new Map;function N(){const e=T();if(e.enableLazyLoading===!1)return null;const t=e.loadingFallback||M;return l.createElement(t)}function $(){h.clear()}function p(e,t,r){let n=h.get(t);n||(n=l.lazy(e),h.set(t,n));const a=l.createElement(l.Suspense,{fallback:l.createElement(N)},l.createElement(n));return r?y(r,a):a}const P=l.createContext(void 0);function w({name:e,children:t}){return l.createElement(P.Provider,{value:e},t)}function k(){return l.useContext(P)}function E(e,t){return y(e,l.createElement(t))}function D(e){const t=c.parseRouteSegments(e)[0];return(t==null?void 0:t.kind)==="catchAll"&&t.optional}function d(e){const t=c.parseRouteSegments(e)[0];return t?c.routeSegmentToPath(t):""}function s(e,t){return m(e,t,!0)}function m(e,t,r=!1){const n=e.page;if(!n)throw new Error(`Route node "${e.fullPath}" has no page loader`);const a=p(async()=>({default:(await n()).default}),`page:${e.fullPath||t}`,t),o=c.parseRouteSegments(e.segment)[0],u=(o==null?void 0:o.kind)==="catchAll"?l.createElement(w,{name:o.name,children:a}):a;return r?{index:!0,element:u}:{path:d(e.segment),element:u}}function q(e){const t=e.notFound;if(!t)throw new Error(`Route node "${e.fullPath}" has no not-found loader`);const r=e.fullPath?`/${e.fullPath}`:"/";return{path:"*",element:p(async()=>({default:(await t()).default}),`notfound:${e.fullPath}`,r)}}function L(e){return e.notFound?[q(e)]:[]}function I(e,t,r,n){return{...t?{path:t}:{},element:E(e,r),children:n.length>0?n:void 0}}function b(e,t){const r=[];return[...e.children.entries()].sort(([n],[a])=>n.localeCompare(a)).forEach(([n,a])=>{const o=d(n),u=o?t?`${t}/${o}`:`/${o}`:t;r.push(...R(a,!1,u))}),r}function z(e,t){const r=[];return e.page&&r.push(s(e,t||"/")),r.push(...b(e,t)),r.push(...L(e)),r}function G(e,t,r,n,a,o){if(D(e.segment)){const u=[...a,...o];return[s(e,t),{path:n,element:m(e,r).element,children:u.length>0?u:void 0}]}return a.length>0||o.length>0?[{path:n,children:[s(e,r),...a,...o]}]:[{path:n,element:m(e,r).element}]}function O(e,t,r,n){const a=[...e.page?[s(e,t)]:[],...r,...n];return[{children:a.length>0?a:void 0}]}function j(e){const t=z(e,"");return e.layout?[{path:"/",element:E("/",e.layout),children:t}]:e.page?t.length>1?[{path:"/",children:t}]:[{path:"/",element:m(e,"/",!1).element}]:e.notFound?[{path:"/",children:t}]:t}function R(e,t=!1,r=""){if(t)return j(e);const n=d(e.segment),a=!n,o=a?r:r+"/"+n,u=b(e,o),i=L(e);return e.layout?[I(o,a?"":n,e.layout,z(e,o))]:e.page&&!a?G(e,r,o,n,u,i):e.page||e.notFound||!a?a?O(e,o,u,i):[{path:n,children:[...e.page?[s(e,o)]:[],...u,...i]}]:u}function B(e,t,r,n){return()=>{const a=c.buildRouteTree(e,t,r,n);return R(a,!0)}}function H(){const e=S.useParams(),t=k();return typeof t=="string"&&e["*"]!==void 0?{...e,[t]:e["*"]}:e}exports.assertNoDuplicateRoutes=c.assertNoDuplicateRoutes;exports.assertNoRouteConflicts=c.assertNoRouteConflicts;exports.buildRouteTree=c.buildRouteTree;exports.extractRoutePath=c.extractRoutePath;exports.normalizeSegment=c.normalizeSegment;exports.parseRouteSegments=c.parseRouteSegments;exports.routeSegmentToPath=c.routeSegmentToPath;exports.CatchAllParamProvider=w;exports.clearLazyCache=$;exports.clearMiddlewares=A;exports.configureRouter=v;exports.createLazyElement=p;exports.createRouteGenerator=B;exports.registerMiddleware=x;exports.resetRouterConfig=F;exports.treeToRoutes=R;exports.useParams=H;
@@ -0,0 +1,144 @@
1
+ import { ComponentType } from 'react';
2
+ import { default as default_2 } from 'react';
3
+ import { ReactElement } from 'react';
4
+ import { RouteObject } from 'react-router-dom';
5
+
6
+ export declare function assertNoDuplicateRoutes(filePaths: string[], fileOptions?: RouteFileOptions): void;
7
+
8
+ export declare function assertNoRouteConflicts(pageFiles: string[], notFoundFiles: string[], fileOptions?: RouteFileOptions): void;
9
+
10
+ export declare function buildRouteTree(pages: Record<string, () => Promise<any>>, layouts: Record<string, any>, notFounds: Record<string, () => Promise<any>>, fileOptions?: RouteFileOptions): RouteNode;
11
+
12
+ export declare function CatchAllParamProvider({ name, children, }: {
13
+ name: string;
14
+ children: default_2.ReactElement;
15
+ }): default_2.ReactElement;
16
+
17
+ /**
18
+ * Clear the module-level lazy component cache.
19
+ *
20
+ * `lazyComponentCache` is a package-wide singleton keyed by route path, so a
21
+ * `React.lazy` component created in one context (for example a previous test)
22
+ * is reused whenever another context requests the same key with a different
23
+ * loader. Exposing an explicit reset keeps that state from leaking, mirroring
24
+ * `clearMiddlewares` for the middleware registry.
25
+ */
26
+ export declare function clearLazyCache(): void;
27
+
28
+ export declare function clearMiddlewares(): void;
29
+
30
+ export declare function configureRouter(config: RouterConfig): void;
31
+
32
+ /**
33
+ * Create a lazy element wrapped with Suspense and apply middlewares
34
+ * @param loader - Function that loads the component
35
+ * @param cacheKey - Unique key for the cache
36
+ * @param routePath - Route path for middlewares
37
+ */
38
+ export declare function createLazyElement(loader: () => Promise<any>, cacheKey: string, routePath?: string): default_2.ReactElement;
39
+
40
+ /**
41
+ * Create a custom route generator function using your own files
42
+ *
43
+ * ⚠️ NOTE: This function is intended for advanced use only.
44
+ * For most cases, use the Vite plugin which automatically handles the paths.
45
+ *
46
+ * @example
47
+ * // In your configuration file
48
+ * const pages = import.meta.glob("../../pages/**\\/page.tsx");
49
+ * const layouts = import.meta.glob("../../pages/**\\/layout.tsx", { eager: true });
50
+ * const notFounds = import.meta.glob("../../pages/**\\/not-found.tsx");
51
+ *
52
+ * export const generateCustomRoutes = createRouteGenerator(pages, layouts, notFounds);
53
+ *
54
+ * // Then use it
55
+ * const routes = generateCustomRoutes();
56
+ */
57
+ export declare function createRouteGenerator(pages: Record<string, () => Promise<any>>, layouts: Record<string, any>, notFounds: Record<string, () => Promise<any>>, fileOptions?: RouteFileOptions): () => RouteObject[];
58
+
59
+ /**
60
+ * Extract the route path from a file path
61
+ * @example "../../app/blog/[id]/page.tsx" -> "blog/[id]"
62
+ * @example "../../app/page.tsx" -> ""
63
+ *
64
+ * `pagesDir` may be relative or absolute. The plugin resolves it relative to
65
+ * the Vite project root before passing it here.
66
+ * The prefix is stripped lazily so it matches the FIRST directory boundary
67
+ * that equals `pagesDir` (or the leading `app`/`pages` root marker when no
68
+ * `pagesDir` is supplied). A greedy match would instead consume up to the
69
+ * LAST such folder, which mangles routes that legitimately contain a nested
70
+ * folder named like the pages directory (e.g. `app/docs/app/page.tsx`).
71
+ */
72
+ export declare function extractRoutePath(filePath: string, { pagesDir, pageFile, layoutFile, notFoundFile }?: RouteFileOptions): string;
73
+
74
+ /**
75
+ * Normalize a Next.js segment to a React Router segment
76
+ * @example (admin) -> ""
77
+ * @example [id] -> :id
78
+ * @example [...slug] -> *
79
+ */
80
+ export declare function normalizeSegment(segment: string): string;
81
+
82
+ export declare function parseRouteSegments(routePath: string): RouteSegment[];
83
+
84
+ export declare function registerMiddleware(pattern: RegExp, middleware: RouteMiddleware): void;
85
+
86
+ /**
87
+ * Restore the module-level router configuration to its defaults.
88
+ *
89
+ * `configureRouter` merges, so it can never drop keys back to their initial
90
+ * state. A dedicated reset lets isolated contexts (for example tests) start
91
+ * from a known configuration instead of inheriting whatever was set globally
92
+ * before, matching the explicit reset offered by `clearMiddlewares`.
93
+ */
94
+ export declare function resetRouterConfig(): void;
95
+
96
+ export declare type RouteFileOptions = {
97
+ pagesDir?: string;
98
+ pageFile?: string;
99
+ layoutFile?: string;
100
+ notFoundFile?: string;
101
+ };
102
+
103
+ export declare type RouteMiddleware = (element: ReactElement) => ReactElement;
104
+
105
+ export declare type RouteModuleLoader = () => Promise<{
106
+ default: ComponentType;
107
+ }>;
108
+
109
+ export declare type RouteNode = {
110
+ segment: string;
111
+ fullPath: string;
112
+ page?: RouteModuleLoader;
113
+ layout?: ComponentType;
114
+ notFound?: RouteModuleLoader;
115
+ children: Map<string, RouteNode>;
116
+ };
117
+
118
+ export declare type RouterConfig = {
119
+ loadingFallback?: React.ComponentType;
120
+ enableLazyLoading?: boolean;
121
+ };
122
+
123
+ export declare type RouteSegment = {
124
+ kind: "group";
125
+ name: string;
126
+ } | {
127
+ kind: "static";
128
+ name: string;
129
+ } | {
130
+ kind: "dynamic";
131
+ name: string;
132
+ } | {
133
+ kind: "catchAll";
134
+ name: string;
135
+ optional: boolean;
136
+ };
137
+
138
+ export declare function routeSegmentToPath(segment: RouteSegment): string;
139
+
140
+ export declare function treeToRoutes(node: RouteNode, isRoot?: boolean, currentPath?: string): RouteObject[];
141
+
142
+ export declare function useParams<T extends Record<string, string | undefined> = Record<string, string | undefined>>(): T;
143
+
144
+ export { }
package/dist/index.d.ts CHANGED
@@ -14,6 +14,17 @@ export declare function CatchAllParamProvider({ name, children, }: {
14
14
  children: default_2.ReactElement;
15
15
  }): default_2.ReactElement;
16
16
 
17
+ /**
18
+ * Clear the module-level lazy component cache.
19
+ *
20
+ * `lazyComponentCache` is a package-wide singleton keyed by route path, so a
21
+ * `React.lazy` component created in one context (for example a previous test)
22
+ * is reused whenever another context requests the same key with a different
23
+ * loader. Exposing an explicit reset keeps that state from leaking, mirroring
24
+ * `clearMiddlewares` for the middleware registry.
25
+ */
26
+ export declare function clearLazyCache(): void;
27
+
17
28
  export declare function clearMiddlewares(): void;
18
29
 
19
30
  export declare function configureRouter(config: RouterConfig): void;
@@ -52,6 +63,11 @@ export declare function createRouteGenerator(pages: Record<string, () => Promise
52
63
  *
53
64
  * `pagesDir` may be relative or absolute. The plugin resolves it relative to
54
65
  * the Vite project root before passing it here.
66
+ * The prefix is stripped lazily so it matches the FIRST directory boundary
67
+ * that equals `pagesDir` (or the leading `app`/`pages` root marker when no
68
+ * `pagesDir` is supplied). A greedy match would instead consume up to the
69
+ * LAST such folder, which mangles routes that legitimately contain a nested
70
+ * folder named like the pages directory (e.g. `app/docs/app/page.tsx`).
55
71
  */
56
72
  export declare function extractRoutePath(filePath: string, { pagesDir, pageFile, layoutFile, notFoundFile }?: RouteFileOptions): string;
57
73
 
@@ -67,6 +83,16 @@ export declare function parseRouteSegments(routePath: string): RouteSegment[];
67
83
 
68
84
  export declare function registerMiddleware(pattern: RegExp, middleware: RouteMiddleware): void;
69
85
 
86
+ /**
87
+ * Restore the module-level router configuration to its defaults.
88
+ *
89
+ * `configureRouter` merges, so it can never drop keys back to their initial
90
+ * state. A dedicated reset lets isolated contexts (for example tests) start
91
+ * from a known configuration instead of inheriting whatever was set globally
92
+ * before, matching the explicit reset offered by `clearMiddlewares`.
93
+ */
94
+ export declare function resetRouterConfig(): void;
95
+
70
96
  export declare type RouteFileOptions = {
71
97
  pagesDir?: string;
72
98
  pageFile?: string;
package/dist/index.js CHANGED
@@ -1,157 +1,160 @@
1
- import { p, r as v, b as z } from "./tree-DW5A1s6W.js";
2
- import { a as K, c as tt, e as et, n as nt } from "./tree-DW5A1s6W.js";
3
- import u, { Suspense as R, lazy as F, createContext as $, useContext as A } from "react";
1
+ import { p as h, r as F, b } from "./tree-DfnssFxU.js";
2
+ import { a as et, c as nt, e as rt, n as at } from "./tree-DfnssFxU.js";
3
+ import u, { lazy as v, Suspense as z, createContext as $, useContext as A } from "react";
4
4
  import { useParams as k } from "react-router-dom";
5
- const N = {
5
+ const d = {
6
6
  enableLazyLoading: !0
7
7
  };
8
- let f = { ...N };
8
+ let i = { ...d };
9
9
  function U(t) {
10
- f = { ...f, ...t };
11
- }
12
- function M() {
13
- return f;
14
- }
15
- let h = [];
16
- function V(t, e) {
17
- h.push({ pattern: t, middleware: e });
18
- }
19
- function W() {
20
- h = [];
21
- }
22
- function m(t, e) {
23
- let n = e;
24
- for (const r of h)
25
- r.pattern.lastIndex = 0, r.pattern.test(t) && (n = r.middleware(n)), r.pattern.lastIndex = 0;
26
- return n;
27
- }
28
- const T = () => u.createElement("div"), C = /* @__PURE__ */ new Map();
29
- function y(t, e, n) {
30
- const r = M();
31
- if (r.enableLazyLoading === !1) {
32
- const c = u.lazy(t), d = u.createElement(
33
- R,
34
- { fallback: null },
35
- // No loading fallback when disabled
36
- u.createElement(c)
37
- );
38
- return n ? m(n, d) : d;
39
- }
40
- let a = C.get(e);
41
- a || (a = F(t), C.set(e, a));
42
- const o = r.loadingFallback || T, l = u.createElement(
43
- R,
44
- { fallback: u.createElement(o) },
45
- u.createElement(a)
10
+ i = { ...i, ...t };
11
+ }
12
+ function V() {
13
+ i = { ...d };
14
+ }
15
+ function N() {
16
+ return i;
17
+ }
18
+ let p = [];
19
+ function W(t, e) {
20
+ p.push({ pattern: t, middleware: e });
21
+ }
22
+ function X() {
23
+ p = [];
24
+ }
25
+ function R(t, e) {
26
+ let r = e;
27
+ for (const n of p)
28
+ n.pattern.lastIndex = 0, n.pattern.test(t) && (r = n.middleware(r)), n.pattern.lastIndex = 0;
29
+ return r;
30
+ }
31
+ const M = () => u.createElement("div"), m = /* @__PURE__ */ new Map();
32
+ function T() {
33
+ const t = N();
34
+ if (t.enableLazyLoading === !1)
35
+ return null;
36
+ const e = t.loadingFallback || M;
37
+ return u.createElement(e);
38
+ }
39
+ function Y() {
40
+ m.clear();
41
+ }
42
+ function C(t, e, r) {
43
+ let n = m.get(e);
44
+ n || (n = v(t), m.set(e, n));
45
+ const a = u.createElement(
46
+ z,
47
+ { fallback: u.createElement(T) },
48
+ u.createElement(n)
46
49
  );
47
- return n ? m(n, l) : l;
50
+ return r ? R(r, a) : a;
48
51
  }
49
- const E = $(void 0);
50
- function D({
52
+ const y = $(void 0);
53
+ function I({
51
54
  name: t,
52
55
  children: e
53
56
  }) {
54
57
  return u.createElement(
55
- E.Provider,
58
+ y.Provider,
56
59
  { value: t },
57
60
  e
58
61
  );
59
62
  }
60
- function I() {
61
- return A(E);
63
+ function S() {
64
+ return A(y);
62
65
  }
63
- function w(t, e) {
64
- return m(t, u.createElement(e));
66
+ function P(t, e) {
67
+ return R(t, u.createElement(e));
65
68
  }
66
- function S(t) {
67
- const e = p(t)[0];
69
+ function D(t) {
70
+ const e = h(t)[0];
68
71
  return (e == null ? void 0 : e.kind) === "catchAll" && e.optional;
69
72
  }
70
73
  function g(t) {
71
- const e = p(t)[0];
72
- return e ? v(e) : "";
74
+ const e = h(t)[0];
75
+ return e ? F(e) : "";
73
76
  }
74
- function s(t, e) {
75
- return i(t, e, !0);
77
+ function c(t, e) {
78
+ return f(t, e, !0);
76
79
  }
77
- function i(t, e, n = !1) {
78
- const r = t.page;
79
- if (!r)
80
+ function f(t, e, r = !1) {
81
+ const n = t.page;
82
+ if (!n)
80
83
  throw new Error(`Route node "${t.fullPath}" has no page loader`);
81
- const a = y(
82
- async () => ({ default: (await r()).default }),
84
+ const a = C(
85
+ async () => ({ default: (await n()).default }),
83
86
  `page:${t.fullPath || e}`,
84
87
  e
85
- ), o = p(t.segment)[0], l = (o == null ? void 0 : o.kind) === "catchAll" ? u.createElement(D, {
88
+ ), o = h(t.segment)[0], l = (o == null ? void 0 : o.kind) === "catchAll" ? u.createElement(I, {
86
89
  name: o.name,
87
90
  children: a
88
91
  }) : a;
89
- return n ? { index: !0, element: l } : { path: g(t.segment), element: l };
92
+ return r ? { index: !0, element: l } : { path: g(t.segment), element: l };
90
93
  }
91
94
  function G(t) {
92
95
  const e = t.notFound;
93
96
  if (!e)
94
97
  throw new Error(`Route node "${t.fullPath}" has no not-found loader`);
95
- const n = t.fullPath ? `/${t.fullPath}` : "/";
98
+ const r = t.fullPath ? `/${t.fullPath}` : "/";
96
99
  return {
97
100
  path: "*",
98
- element: y(
101
+ element: C(
99
102
  async () => ({ default: (await e()).default }),
100
103
  `notfound:${t.fullPath}`,
101
- n
104
+ r
102
105
  )
103
106
  };
104
107
  }
105
- function P(t) {
108
+ function E(t) {
106
109
  return t.notFound ? [G(t)] : [];
107
110
  }
108
- function O(t, e, n, r) {
111
+ function O(t, e, r, n) {
109
112
  return {
110
113
  ...e ? { path: e } : {},
111
- element: w(t, n),
112
- children: r.length > 0 ? r : void 0
114
+ element: P(t, r),
115
+ children: n.length > 0 ? n : void 0
113
116
  };
114
117
  }
115
- function x(t, e) {
116
- const n = [];
117
- return [...t.children.entries()].sort(([r], [a]) => r.localeCompare(a)).forEach(([r, a]) => {
118
- const o = g(r), l = o ? e ? `${e}/${o}` : `/${o}` : e;
119
- n.push(...b(a, !1, l));
120
- }), n;
118
+ function w(t, e) {
119
+ const r = [];
120
+ return [...t.children.entries()].sort(([n], [a]) => n.localeCompare(a)).forEach(([n, a]) => {
121
+ const o = g(n), l = o ? e ? `${e}/${o}` : `/${o}` : e;
122
+ r.push(...x(a, !1, l));
123
+ }), r;
121
124
  }
122
125
  function L(t, e) {
123
- const n = [];
124
- return t.page && n.push(s(t, e || "/")), n.push(...x(t, e)), n.push(...P(t)), n;
126
+ const r = [];
127
+ return t.page && r.push(c(t, e || "/")), r.push(...w(t, e)), r.push(...E(t)), r;
125
128
  }
126
- function j(t, e, n, r, a, o) {
127
- if (S(t.segment)) {
129
+ function j(t, e, r, n, a, o) {
130
+ if (D(t.segment)) {
128
131
  const l = [...a, ...o];
129
132
  return [
130
- s(t, e),
133
+ c(t, e),
131
134
  {
132
- path: r,
133
- element: i(t, n).element,
135
+ path: n,
136
+ element: f(t, r).element,
134
137
  children: l.length > 0 ? l : void 0
135
138
  }
136
139
  ];
137
140
  }
138
141
  return a.length > 0 || o.length > 0 ? [{
139
- path: r,
142
+ path: n,
140
143
  children: [
141
- s(t, n),
144
+ c(t, r),
142
145
  ...a,
143
146
  ...o
144
147
  ]
145
148
  }] : [{
146
- path: r,
147
- element: i(t, n).element
149
+ path: n,
150
+ element: f(t, r).element
148
151
  }];
149
152
  }
150
- function q(t, e, n, r) {
153
+ function q(t, e, r, n) {
151
154
  const a = [
152
- ...t.page ? [s(t, e)] : [],
153
- ...n,
154
- ...r
155
+ ...t.page ? [c(t, e)] : [],
156
+ ...r,
157
+ ...n
155
158
  ];
156
159
  return [{
157
160
  children: a.length > 0 ? a : void 0
@@ -161,62 +164,64 @@ function B(t) {
161
164
  const e = L(t, "");
162
165
  return t.layout ? [{
163
166
  path: "/",
164
- element: w("/", t.layout),
167
+ element: P("/", t.layout),
165
168
  children: e
166
169
  }] : t.page ? e.length > 1 ? [{ path: "/", children: e }] : [{
167
170
  path: "/",
168
- element: i(t, "/", !1).element
171
+ element: f(t, "/", !1).element
169
172
  }] : t.notFound ? [{ path: "/", children: e }] : e;
170
173
  }
171
- function b(t, e = !1, n = "") {
174
+ function x(t, e = !1, r = "") {
172
175
  if (e)
173
176
  return B(t);
174
- const r = g(t.segment), a = !r, o = a ? n : n + "/" + r, l = x(t, o), c = P(t);
177
+ const n = g(t.segment), a = !n, o = a ? r : r + "/" + n, l = w(t, o), s = E(t);
175
178
  return t.layout ? [O(
176
179
  o,
177
- a ? "" : r,
180
+ a ? "" : n,
178
181
  t.layout,
179
182
  L(t, o)
180
183
  )] : t.page && !a ? j(
181
184
  t,
182
- n,
183
- o,
184
185
  r,
186
+ o,
187
+ n,
185
188
  l,
186
- c
187
- ) : t.page || t.notFound || !a ? a ? q(t, o, l, c) : [{
188
- path: r,
189
+ s
190
+ ) : t.page || t.notFound || !a ? a ? q(t, o, l, s) : [{
191
+ path: n,
189
192
  children: [
190
- ...t.page ? [s(t, o)] : [],
193
+ ...t.page ? [c(t, o)] : [],
191
194
  ...l,
192
- ...c
195
+ ...s
193
196
  ]
194
197
  }] : l;
195
198
  }
196
- function X(t, e, n, r) {
199
+ function Z(t, e, r, n) {
197
200
  return () => {
198
- const a = z(t, e, n, r);
199
- return b(a, !0);
201
+ const a = b(t, e, r, n);
202
+ return x(a, !0);
200
203
  };
201
204
  }
202
- function Y() {
203
- const t = k(), e = I();
205
+ function _() {
206
+ const t = k(), e = S();
204
207
  return typeof e == "string" && t["*"] !== void 0 ? { ...t, [e]: t["*"] } : t;
205
208
  }
206
209
  export {
207
- D as CatchAllParamProvider,
208
- K as assertNoDuplicateRoutes,
209
- tt as assertNoRouteConflicts,
210
- z as buildRouteTree,
211
- W as clearMiddlewares,
210
+ I as CatchAllParamProvider,
211
+ et as assertNoDuplicateRoutes,
212
+ nt as assertNoRouteConflicts,
213
+ b as buildRouteTree,
214
+ Y as clearLazyCache,
215
+ X as clearMiddlewares,
212
216
  U as configureRouter,
213
- y as createLazyElement,
214
- X as createRouteGenerator,
215
- et as extractRoutePath,
216
- nt as normalizeSegment,
217
- p as parseRouteSegments,
218
- V as registerMiddleware,
219
- v as routeSegmentToPath,
220
- b as treeToRoutes,
221
- Y as useParams
217
+ C as createLazyElement,
218
+ Z as createRouteGenerator,
219
+ rt as extractRoutePath,
220
+ at as normalizeSegment,
221
+ h as parseRouteSegments,
222
+ W as registerMiddleware,
223
+ V as resetRouterConfig,
224
+ F as routeSegmentToPath,
225
+ x as treeToRoutes,
226
+ _ as useParams
222
227
  };
@@ -0,0 +1,63 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const b=require("node:fs"),m=require("node:path"),x=require("./tree-hc1dSMdb.cjs");function w(n){const a=n.map(x.routeSegmentToPath).filter(Boolean);return a.length>0?`/${a.join("/")}`:"/"}function S(n){const a=[["pagesDir",n.pagesDir],["pageFile",n.pageFile],["layoutFile",n.layoutFile],["notFoundFile",n.notFoundFile]];for(const[t,e]of a)if(!e.trim())throw new Error(`nextViteRouter option "${t}" must not be empty.`);const s=a.slice(1),i=s.find(([,t],e)=>s.slice(e+1).some(([,r])=>r===t));if(i)throw new Error(`nextViteRouter file options must be distinct; "${i[0]}" is duplicated.`)}function T(n){return n.replace(/\\/g,"/").replace(/^\.\//,"").replace(/^\/|\/$/g,"")}function k(n,a,s){const i=a.pageFile??"page.tsx",t=new Map;for(const e of R(n,i,s)){const r=x.extractRoutePath(e,a),l=x.parseRouteSegments(r),d=l.filter(u=>u.kind==="dynamic"||u.kind==="catchAll").map(u=>({name:u.name,optional:u.kind==="catchAll"&&u.optional})),c=w(l);t.set(c,{path:c,params:d});const f=l[l.length-1];if((f==null?void 0:f.kind)==="catchAll"&&f.optional){const u=w(l.slice(0,-1));t.has(u)||t.set(u,{path:u,params:[]})}}return[...t.values()].sort((e,r)=>e.path.localeCompare(r.path))}function R(n,a,s){const i=[];function t(e){for(const r of b.readdirSync(e,{withFileTypes:!0})){const l=m.join(e,r.name);if(r.isDirectory())t(l);else if(r.isFile()&&r.name===a){const d=m.relative(n,l).replace(/\\/g,"/");i.push(`/${s}/${d}`)}}}return b.existsSync(n)&&t(n),i}function G(n){const a=n.map(({path:i})=>` | ${JSON.stringify(i)}`).join(`
2
+ `),s=n.map(({path:i,params:t})=>{const e=t.length>0?[...t.map(({name:r,optional:l})=>` ${r}${l?"?":""}: string;`)].join(`
3
+ `):" [key: string]: never;";return` ${JSON.stringify(i)}: {
4
+ ${e}
5
+ };`}).join(`
6
+ `);return`declare module 'virtual:next-vite-router' {
7
+ import type { ReactElement } from 'react';
8
+ import type { RouteObject } from 'react-router-dom';
9
+
10
+ export type RoutePath =
11
+ ${a||' | "/"'};
12
+
13
+ export type RouteParams<P extends RoutePath> = P extends keyof RoutePathParams
14
+ ? RoutePathParams[P]
15
+ : never;
16
+
17
+ export interface RoutePathParams {
18
+ ${s}
19
+ }
20
+
21
+ export const generateRoutes: () => RouteObject[];
22
+ export function Router(): ReactElement | null;
23
+ export function useParams<T extends Record<string, string | undefined> = Record<string, string | undefined>>(): T;
24
+ export { Link, useRoutes } from 'react-router-dom';
25
+ }
26
+ `}function O(n={}){const{pagesDir:a="src/app",pageFile:s="page.tsx",layoutFile:i="layout.tsx",notFoundFile:t="not-found.tsx"}=n;S({pagesDir:a,pageFile:s,layoutFile:i,notFoundFile:t});const e=T(a),r={pagesDir:e,pageFile:s,layoutFile:i,notFoundFile:t},l="virtual:next-vite-router",d="\0"+l;let c="",f="",u,h;function F(){const o=G(k(c,r,e));b.writeFileSync(f,o,"utf-8")}return{name:"next-vite-router",configResolved(o){c=m.resolve(o.root,a),f=m.join(m.dirname(c),"virtual-next-vite-router.d.ts"),x.assertNoRouteConflicts(R(c,s,e),R(c,t,e),r),F()},configureServer(o){if(u===o)return;h==null||h(),u=o;const g=$=>{if(m.relative(c,$).startsWith("..")||![s,i,t].includes(m.basename($)))return;try{x.assertNoRouteConflicts(R(c,s,e),R(c,t,e),r)}catch(P){o.config.logger.error(P instanceof Error?P.message:String(P));return}F();const v=o.moduleGraph.getModuleById(d);v&&(o.moduleGraph.invalidateModule(v),p&&clearTimeout(p),p=setTimeout(()=>{p=void 0,o.ws.send({type:"full-reload",path:"*"})},0))};let p;const y=()=>{p&&(clearTimeout(p),p=void 0),o.watcher.off("add",g),o.watcher.off("unlink",g),o.watcher.off("close",y),u===o&&(u=void 0,h=void 0)};o.watcher.on("add",g),o.watcher.on("unlink",g),o.watcher.once("close",y),h=y},resolveId(o){if(o===l)return d},load(o){if(o===d){const g=`/${e}/**/${s}`,p=`/${e}/**/${i}`,y=`/${e}/**/${t}`;return`
27
+ import { buildRouteTree, treeToRoutes, normalizeSegment, createLazyElement, useParams } from 'next-vite-router';
28
+ import { Link, useRoutes } from 'react-router-dom';
29
+
30
+ const pagesGlob = import.meta.glob(${JSON.stringify(g)});
31
+ const layoutsGlob = import.meta.glob(${JSON.stringify(p)}, { eager: true });
32
+ const notFoundsGlob = import.meta.glob(${JSON.stringify(y)});
33
+
34
+ // Keep the raw root-relative glob keys. extractRoutePath (via buildRouteTree)
35
+ // is the single place that strips the pagesDir prefix; stripping it here as
36
+ // well would double-remove it and let the prefix regex match a same-named
37
+ // nested folder (e.g. pagesDir "app" turning "app/docs/app" into "/").
38
+ const pages = pagesGlob;
39
+ const layouts = layoutsGlob;
40
+ const notFounds = notFoundsGlob;
41
+
42
+ export function generateRoutes() {
43
+ const tree = buildRouteTree(pages, layouts, notFounds, ${JSON.stringify(r)});
44
+ const routes = treeToRoutes(tree, true);
45
+ return routes;
46
+ }
47
+
48
+ export function Router() {
49
+ routes ??= generateRoutes();
50
+ return useRoutes(routes);
51
+ }
52
+
53
+ let routes;
54
+
55
+ if (import.meta.hot) {
56
+ import.meta.hot.accept(() => {
57
+ routes = undefined;
58
+ });
59
+ }
60
+
61
+ export { Link, useRoutes };
62
+ export { useParams };
63
+ `}}}}exports.nextViteRouter=O;
@@ -0,0 +1,12 @@
1
+ import { Plugin as Plugin_2 } from 'vite';
2
+
3
+ export declare function nextViteRouter(options?: NextViteRouterPluginOptions): Plugin_2;
4
+
5
+ export declare type NextViteRouterPluginOptions = {
6
+ pagesDir?: string;
7
+ pageFile?: string;
8
+ layoutFile?: string;
9
+ notFoundFile?: string;
10
+ };
11
+
12
+ export { }
package/dist/plugin.js CHANGED
@@ -1,22 +1,22 @@
1
1
  import P from "node:fs";
2
- import l from "node:path";
3
- import { c as $, p as S, r as k } from "./tree-DW5A1s6W.js";
4
- function j(n) {
2
+ import f from "node:path";
3
+ import { c as v, e as S, p as T, r as k } from "./tree-DfnssFxU.js";
4
+ function w(n) {
5
5
  const a = n.map(k).filter(Boolean);
6
6
  return a.length > 0 ? `/${a.join("/")}` : "/";
7
7
  }
8
- function w(n) {
8
+ function G(n) {
9
9
  const a = [
10
10
  ["pagesDir", n.pagesDir],
11
11
  ["pageFile", n.pageFile],
12
12
  ["layoutFile", n.layoutFile],
13
13
  ["notFoundFile", n.notFoundFile]
14
14
  ];
15
- for (const [e, o] of a)
16
- if (!o.trim())
15
+ for (const [e, t] of a)
16
+ if (!t.trim())
17
17
  throw new Error(`nextViteRouter option "${e}" must not be empty.`);
18
- const r = a.slice(1), i = r.find(
19
- ([, e], o) => r.slice(o + 1).some(([, u]) => u === e)
18
+ const s = a.slice(1), i = s.find(
19
+ ([, e], t) => s.slice(t + 1).some(([, r]) => r === e)
20
20
  );
21
21
  if (i)
22
22
  throw new Error(
@@ -24,54 +24,50 @@ function w(n) {
24
24
  );
25
25
  }
26
26
  function O(n) {
27
- return n.replace(/\\/g, "/").replace(/^\/|\/$/g, "");
27
+ return n.replace(/\\/g, "/").replace(/^\.\//, "").replace(/^\/|\/$/g, "");
28
28
  }
29
- function T(n, a) {
30
- const r = /* @__PURE__ */ new Map();
31
- function i(e) {
32
- for (const o of P.readdirSync(e, { withFileTypes: !0 })) {
33
- const u = l.join(e, o.name);
34
- if (o.isDirectory())
35
- i(u);
36
- else if (o.isFile() && o.name === a) {
37
- const d = l.relative(n, e).split(l.sep).filter(Boolean), s = S(d.join("/")), R = s.filter(
38
- (c) => c.kind === "dynamic" || c.kind === "catchAll"
39
- ).map((c) => ({
40
- name: c.name,
41
- optional: c.kind === "catchAll" && c.optional
42
- })), m = j(s);
43
- r.set(m, { path: m, params: R });
44
- const f = s[s.length - 1];
45
- if ((f == null ? void 0 : f.kind) === "catchAll" && f.optional) {
46
- const c = d.slice(0, -1).join(l.sep), t = j(
47
- S(c.split(l.sep).join("/"))
48
- );
49
- r.has(t) || r.set(t, { path: t, params: [] });
50
- }
51
- }
29
+ function j(n, a, s) {
30
+ const i = a.pageFile ?? "page.tsx", e = /* @__PURE__ */ new Map();
31
+ for (const t of R(n, i, s)) {
32
+ const r = S(t, a), l = T(r), d = l.filter(
33
+ (u) => u.kind === "dynamic" || u.kind === "catchAll"
34
+ ).map((u) => ({
35
+ name: u.name,
36
+ optional: u.kind === "catchAll" && u.optional
37
+ })), c = w(l);
38
+ e.set(c, { path: c, params: d });
39
+ const m = l[l.length - 1];
40
+ if ((m == null ? void 0 : m.kind) === "catchAll" && m.optional) {
41
+ const u = w(l.slice(0, -1));
42
+ e.has(u) || e.set(u, { path: u, params: [] });
52
43
  }
53
44
  }
54
- return P.existsSync(n) && i(n), [...r.values()].sort((e, o) => e.path.localeCompare(o.path));
45
+ return [...e.values()].sort((t, r) => t.path.localeCompare(r.path));
55
46
  }
56
- function b(n, a) {
57
- const r = [];
58
- function i(e) {
59
- for (const o of P.readdirSync(e, { withFileTypes: !0 })) {
60
- const u = l.join(e, o.name);
61
- o.isDirectory() ? i(u) : o.isFile() && o.name === a && r.push(l.relative(n, u));
47
+ function R(n, a, s) {
48
+ const i = [];
49
+ function e(t) {
50
+ for (const r of P.readdirSync(t, { withFileTypes: !0 })) {
51
+ const l = f.join(t, r.name);
52
+ if (r.isDirectory())
53
+ e(l);
54
+ else if (r.isFile() && r.name === a) {
55
+ const d = f.relative(n, l).replace(/\\/g, "/");
56
+ i.push(`/${s}/${d}`);
57
+ }
62
58
  }
63
59
  }
64
- return P.existsSync(n) && i(n), r;
60
+ return P.existsSync(n) && e(n), i;
65
61
  }
66
- function G(n) {
62
+ function D(n) {
67
63
  const a = n.map(({ path: i }) => ` | ${JSON.stringify(i)}`).join(`
68
- `), r = n.map(({ path: i, params: e }) => {
69
- const o = e.length > 0 ? [
70
- ...e.map(({ name: u, optional: y }) => ` ${u}${y ? "?" : ""}: string;`)
64
+ `), s = n.map(({ path: i, params: e }) => {
65
+ const t = e.length > 0 ? [
66
+ ...e.map(({ name: r, optional: l }) => ` ${r}${l ? "?" : ""}: string;`)
71
67
  ].join(`
72
68
  `) : " [key: string]: never;";
73
69
  return ` ${JSON.stringify(i)}: {
74
- ${o}
70
+ ${t}
75
71
  };`;
76
72
  }).join(`
77
73
  `);
@@ -87,7 +83,7 @@ ${a || ' | "/"'};
87
83
  : never;
88
84
 
89
85
  export interface RoutePathParams {
90
- ${r}
86
+ ${s}
91
87
  }
92
88
 
93
89
  export const generateRoutes: () => RouteObject[];
@@ -97,89 +93,85 @@ ${r}
97
93
  }
98
94
  `;
99
95
  }
100
- function M(n = {}) {
96
+ function z(n = {}) {
101
97
  const {
102
98
  pagesDir: a = "src/app",
103
- pageFile: r = "page.tsx",
99
+ pageFile: s = "page.tsx",
104
100
  layoutFile: i = "layout.tsx",
105
101
  notFoundFile: e = "not-found.tsx"
106
102
  } = n;
107
- w({ pagesDir: a, pageFile: r, layoutFile: i, notFoundFile: e });
108
- const o = O(a), u = { pagesDir: a, pageFile: r, layoutFile: i, notFoundFile: e }, y = "virtual:next-vite-router", d = "\0" + y;
109
- let s = "", R = "", m, f;
110
- function c() {
111
- const t = G(T(s, r));
112
- P.writeFileSync(R, t, "utf-8");
103
+ G({ pagesDir: a, pageFile: s, layoutFile: i, notFoundFile: e });
104
+ const t = O(a), r = { pagesDir: t, pageFile: s, layoutFile: i, notFoundFile: e }, l = "virtual:next-vite-router", d = "\0" + l;
105
+ let c = "", m = "", u, h;
106
+ function F() {
107
+ const o = D(j(c, r, t));
108
+ P.writeFileSync(m, o, "utf-8");
113
109
  }
114
110
  return {
115
111
  name: "next-vite-router",
116
- configResolved(t) {
117
- s = l.resolve(t.root, a), R = l.join(l.dirname(s), "virtual-next-vite-router.d.ts"), $(
118
- b(s, r),
119
- b(s, e),
120
- u
121
- ), c();
112
+ configResolved(o) {
113
+ c = f.resolve(o.root, a), m = f.join(f.dirname(c), "virtual-next-vite-router.d.ts"), v(
114
+ R(c, s, t),
115
+ R(c, e, t),
116
+ r
117
+ ), F();
122
118
  },
123
- configureServer(t) {
124
- if (m === t)
119
+ configureServer(o) {
120
+ if (u === o)
125
121
  return;
126
- f == null || f(), m = t;
127
- const h = (x) => {
128
- if (l.relative(s, x).startsWith("..") || ![r, i, e].includes(l.basename(x)))
122
+ h == null || h(), u = o;
123
+ const g = (b) => {
124
+ if (f.relative(c, b).startsWith("..") || ![s, i, e].includes(f.basename(b)))
129
125
  return;
130
126
  try {
131
- $(
132
- b(s, r),
133
- b(s, e),
134
- u
127
+ v(
128
+ R(c, s, t),
129
+ R(c, e, t),
130
+ r
135
131
  );
136
- } catch (v) {
137
- t.config.logger.error(
138
- v instanceof Error ? v.message : String(v)
132
+ } catch (x) {
133
+ o.config.logger.error(
134
+ x instanceof Error ? x.message : String(x)
139
135
  );
140
136
  return;
141
137
  }
142
- c();
143
- const F = t.moduleGraph.getModuleById(d);
144
- F && (t.moduleGraph.invalidateModule(F), p && clearTimeout(p), p = setTimeout(() => {
145
- p = void 0, t.ws.send({ type: "full-reload", path: "*" });
138
+ F();
139
+ const $ = o.moduleGraph.getModuleById(d);
140
+ $ && (o.moduleGraph.invalidateModule($), p && clearTimeout(p), p = setTimeout(() => {
141
+ p = void 0, o.ws.send({ type: "full-reload", path: "*" });
146
142
  }, 0));
147
143
  };
148
144
  let p;
149
- const g = () => {
150
- p && (clearTimeout(p), p = void 0), t.watcher.off("add", h), t.watcher.off("unlink", h), t.watcher.off("close", g), m === t && (m = void 0, f = void 0);
145
+ const y = () => {
146
+ p && (clearTimeout(p), p = void 0), o.watcher.off("add", g), o.watcher.off("unlink", g), o.watcher.off("close", y), u === o && (u = void 0, h = void 0);
151
147
  };
152
- t.watcher.on("add", h), t.watcher.on("unlink", h), t.watcher.once("close", g), f = g;
148
+ o.watcher.on("add", g), o.watcher.on("unlink", g), o.watcher.once("close", y), h = y;
153
149
  },
154
- resolveId(t) {
155
- if (t === y)
150
+ resolveId(o) {
151
+ if (o === l)
156
152
  return d;
157
153
  },
158
- load(t) {
159
- if (t === d) {
160
- const h = `/${o}/**/${r}`, p = `/${o}/**/${i}`, g = `/${o}/**/${e}`, x = `/${o}/`;
154
+ load(o) {
155
+ if (o === d) {
156
+ const g = `/${t}/**/${s}`, p = `/${t}/**/${i}`, y = `/${t}/**/${e}`;
161
157
  return `
162
158
  import { buildRouteTree, treeToRoutes, normalizeSegment, createLazyElement, useParams } from 'next-vite-router';
163
159
  import { Link, useRoutes } from 'react-router-dom';
164
160
 
165
- const pagesGlob = import.meta.glob(${JSON.stringify(h)});
161
+ const pagesGlob = import.meta.glob(${JSON.stringify(g)});
166
162
  const layoutsGlob = import.meta.glob(${JSON.stringify(p)}, { eager: true });
167
- const notFoundsGlob = import.meta.glob(${JSON.stringify(g)});
168
-
169
- const transformPath = (path) => path.replace(${JSON.stringify(x)}, '');
163
+ const notFoundsGlob = import.meta.glob(${JSON.stringify(y)});
170
164
 
171
- const pages = Object.fromEntries(
172
- Object.entries(pagesGlob).map(([key, value]) => [transformPath(key), value])
173
- );
174
- const layouts = Object.fromEntries(
175
- Object.entries(layoutsGlob).map(([key, value]) => [transformPath(key), value])
176
- );
177
- const notFounds = Object.fromEntries(
178
- Object.entries(notFoundsGlob).map(([key, value]) => [transformPath(key), value])
179
- );
165
+ // Keep the raw root-relative glob keys. extractRoutePath (via buildRouteTree)
166
+ // is the single place that strips the pagesDir prefix; stripping it here as
167
+ // well would double-remove it and let the prefix regex match a same-named
168
+ // nested folder (e.g. pagesDir "app" turning "app/docs/app" into "/").
169
+ const pages = pagesGlob;
170
+ const layouts = layoutsGlob;
171
+ const notFounds = notFoundsGlob;
180
172
 
181
173
  export function generateRoutes() {
182
- const tree = buildRouteTree(pages, layouts, notFounds, ${JSON.stringify(u)});
174
+ const tree = buildRouteTree(pages, layouts, notFounds, ${JSON.stringify(r)});
183
175
  const routes = treeToRoutes(tree, true);
184
176
  return routes;
185
177
  }
@@ -205,5 +197,5 @@ export { useParams };
205
197
  };
206
198
  }
207
199
  export {
208
- M as nextViteRouter
200
+ z as nextViteRouter
209
201
  };
@@ -27,9 +27,9 @@ function m(t) {
27
27
  return o;
28
28
  }
29
29
  function f(t, { pagesDir: s, pageFile: o = "page.tsx", layoutFile: c = "layout.tsx", notFoundFile: a = "not-found.tsx" } = {}) {
30
- const n = t.replace(/\\/g, "/"), e = s == null ? void 0 : s.replace(/\\/g, "/").replace(/^\/|\/$/g, ""), r = e == null ? void 0 : e.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), i = [o, c, a].map((l) => l.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
30
+ const n = t.replace(/\\/g, "/"), e = s == null ? void 0 : s.replace(/\\/g, "/").replace(/^\.\//, "").replace(/^\/|\/$/g, ""), r = e == null ? void 0 : e.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), i = [o, c, a].map((l) => l.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
31
31
  return n.replace(
32
- e ? new RegExp(`^.*(?:^|/)${r}/`) : /^.*(?:^|\/)(?:app|pages)\//,
32
+ e ? new RegExp(`^.*?(?:^|/)${r}/`) : /^.*?(?:^|\/)(?:app|pages)\//,
33
33
  ""
34
34
  ).replace(/\\/g, "/").replace(new RegExp(`/?(?:${i})$`), "");
35
35
  }
@@ -0,0 +1,10 @@
1
+ "use strict";function w(t){return/^\([^)]+\)$/.test(t)?"":/^\[\[\.\.\.(.+)\]\]$/.test(t)||/^\[\.\.\.(.+)\]$/.test(t)?"*":/^\[([^\]]+)\]$/.test(t)?t.replace(/^\[([^\]]+)\]$/,":$1"):t}const R=/^[A-Za-z_][A-Za-z0-9_]*$/;function $(t){return t.kind==="group"?"":t.kind==="dynamic"?`:${t.name}`:t.kind==="catchAll"?"*":t.name}function d(t){const s=t?t.split("/").filter(Boolean):[],o=[],c=new Set;for(const a of s){const n=a.match(/^\(([^)]+)\)$/),e=a.match(/^\[\[\.\.\.(.+)\]\]$/),r=a.match(/^\[\.\.\.(.+)\]$/),i=a.match(/^\[([^\]]+)\]$/),l=e?{name:e[1],optional:!0,kind:"catchAll"}:r?{name:r[1],optional:!1,kind:"catchAll"}:i?{name:i[1],optional:!1,kind:"dynamic"}:void 0;if(n)o.push({kind:"group",name:n[1]});else if(l){if(!R.test(l.name))throw new Error(`Invalid route parameter name "${l.name}" in segment "${a}". Parameter names must start with a letter or underscore and contain only letters, numbers, and underscores.`);if(c.has(l.name))throw new Error(`Duplicate route parameter "${l.name}" in route "${t||"/"}".`);c.add(l.name),o.push(l)}else o.push({kind:"static",name:a})}return o}function u(t,{pagesDir:s,pageFile:o="page.tsx",layoutFile:c="layout.tsx",notFoundFile:a="not-found.tsx"}={}){const n=t.replace(/\\/g,"/"),e=s==null?void 0:s.replace(/\\/g,"/").replace(/^\.\//,"").replace(/^\/|\/$/g,""),r=e==null?void 0:e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),i=[o,c,a].map(l=>l.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")).join("|");return n.replace(e?new RegExp(`^.*?(?:^|/)${r}/`):/^.*?(?:^|\/)(?:app|pages)\//,"").replace(/\\/g,"/").replace(new RegExp(`/?(?:${i})$`),"")}function g(t){return t.kind==="group"?"":t.kind==="catchAll"?"*":t.kind==="dynamic"?":param":$(t)}function P(t,s){const o=u(t,s),c=d(o),a=c.map(g).filter(Boolean),n=[a.length>0?`/${a.join("/")}`:"/"],e=c[c.length-1];if((e==null?void 0:e.kind)==="catchAll"&&e.optional){const r=a.slice(0,-1);n.push(r.length>0?`/${r.join("/")}`:"/")}return n}function j(t){return/(^|\/)(:param|\*)($|\/)/.test(t)?"pattern":"literal"}function E(t,s,o){const c=t.flatMap(n=>{const e=u(n,o),r=d(e),i=r[r.length-1];if((i==null?void 0:i.kind)!=="catchAll")return[];const l=r.map(g).filter(Boolean),h=l.length>0?`/${l.join("/")}`:"/",m=l.slice(0,-1),A=m.length>0?`/${m.join("/")}`:"/";return[{filePath:n,paths:new Set([h,A])}]}),a=new Map;for(const n of s)for(const e of P(n,o))for(const r of c)if(r.paths.has(e)){const i=`${e}\0${r.filePath}\0${n}`;a.set(i,{routePath:e,pageFile:r.filePath,notFoundFile:n})}if(a.size>0)throw new Error([...a.values()].sort((n,e)=>n.routePath.localeCompare(e.routePath)).map(({routePath:n,pageFile:e,notFoundFile:r})=>`Conflicting fallback routes "${n}" detected:
2
+ catch-all page: ${e}
3
+ not-found file: ${r}
4
+ A not-found route and a catch-all page cannot coexist at the same route level.`).join(`
5
+
6
+ `))}function p(t,s){const o=new Map;for(const a of t)for(const n of P(a,s)){const e=o.get(n)??[];e.push({kind:j(n),filePath:a}),o.set(n,e)}const c=[...o.entries()].filter(([,a])=>a.length>1).sort(([a],[n])=>a.localeCompare(n));if(c.length>0)throw new Error(c.map(([a,n])=>`${n[0].kind==="pattern"?"Ambiguous route pattern":"Duplicate route"} "${a}" detected:
7
+ ${n.sort((e,r)=>e.filePath.localeCompare(r.filePath)).map(e=>` ${e.filePath}`).join(`
8
+ `)}`).join(`
9
+
10
+ `))}function k(t,s,o){p(t,o),p(s,o),E(t,s,o)}function f(t,s,o,c,a){const n=u(s,a),e=n?n.split("/"):[];let r=t,i="";e.forEach((l,h)=>{i=i?`${i}/${l}`:l,r.children.has(l)||r.children.set(l,{segment:l,fullPath:i,children:new Map}),r=r.children.get(l),h===e.length-1&&(r[c]=o)}),e.length===0&&(t[c]=o)}function b(t,s,o,c){k(Object.keys(t),Object.keys(o),c);const a={segment:"",fullPath:"",children:new Map};return Object.entries(s).forEach(([n,e])=>{f(a,n,e.default,"layout",c)}),Object.entries(t).forEach(([n,e])=>{f(a,n,e,"page",c)}),Object.entries(o).forEach(([n,e])=>{f(a,n,e,"notFound",c)}),a}exports.assertNoDuplicateRoutes=p;exports.assertNoRouteConflicts=k;exports.buildRouteTree=b;exports.extractRoutePath=u;exports.normalizeSegment=w;exports.parseRouteSegments=d;exports.routeSegmentToPath=$;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "next-vite-router",
3
- "version": "1.2.4",
3
+ "version": "1.3.0",
4
4
  "description": "Next.js-like file-based routing for React + Vite",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -11,12 +11,24 @@
11
11
  },
12
12
  "exports": {
13
13
  ".": {
14
- "import": "./dist/index.js",
15
- "types": "./dist/index.d.ts"
14
+ "import": {
15
+ "types": "./dist/index.d.ts",
16
+ "default": "./dist/index.js"
17
+ },
18
+ "require": {
19
+ "types": "./dist/index.d.cts",
20
+ "default": "./dist/index.cjs"
21
+ }
16
22
  },
17
23
  "./plugin": {
18
- "import": "./dist/plugin.js",
19
- "types": "./dist/plugin.d.ts"
24
+ "import": {
25
+ "types": "./dist/plugin.d.ts",
26
+ "default": "./dist/plugin.js"
27
+ },
28
+ "require": {
29
+ "types": "./dist/plugin.d.cts",
30
+ "default": "./dist/plugin.cjs"
31
+ }
20
32
  }
21
33
  },
22
34
  "files": [
@@ -36,7 +48,7 @@
36
48
  "author": "Rlzee",
37
49
  "repository": {
38
50
  "type": "git",
39
- "url": "https://github.com/Rlzee/next-vite-router"
51
+ "url": "git+https://github.com/Rlzee/next-vite-router.git"
40
52
  },
41
53
  "homepage": "https://github.com/Rlzee/next-vite-router#readme",
42
54
  "license": "MIT",
@@ -62,7 +74,8 @@
62
74
  },
63
75
  "scripts": {
64
76
  "dev": "vite build --watch",
65
- "build": "vite build && vite build -c vite.config.cli.ts",
77
+ "build": "vite build && vite build -c vite.config.cli.ts && node -e \"import fs from 'node:fs'; for (const f of ['index','plugin']) fs.copyFileSync('dist/'+f+'.d.ts','dist/'+f+'.d.cts')\"",
78
+ "test": "pnpm run test:params && pnpm run test:generator && pnpm run test:routes && pnpm run test:local && pnpm run test:compatibility",
66
79
  "test:local": "node test/test-package.js",
67
80
  "test:routes": "node test/test-route-types.js",
68
81
  "test:generator": "node --test test/routes.test.js",