next-vite-router 1.2.3 → 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/dist/plugin.js CHANGED
@@ -1,60 +1,73 @@
1
- import h from "node:fs";
2
- import l from "node:path";
3
- import { a as b, n as j } from "./tree-HwBRWJNI.js";
4
- function $(n) {
5
- const e = n.split(l.sep).filter(Boolean).map(j).filter(Boolean);
6
- return e.length > 0 ? `/${e.join("/")}` : "/";
1
+ import P from "node:fs";
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
+ const a = n.map(k).filter(Boolean);
6
+ return a.length > 0 ? `/${a.join("/")}` : "/";
7
7
  }
8
- function T(n, e) {
9
- const r = /* @__PURE__ */ new Map();
10
- function i(a) {
11
- for (const o of h.readdirSync(a, { withFileTypes: !0 })) {
12
- const p = l.join(a, o.name);
13
- if (o.isDirectory())
14
- i(p);
15
- else if (o.isFile() && o.name === e) {
16
- const s = l.relative(n, a), u = s.split(l.sep).filter(Boolean), y = u.map((t) => {
17
- const c = t.match(/^\[\[\.\.\.(.+)\]\]$/);
18
- if (c)
19
- return { name: c[1], optional: !0 };
20
- const m = t.match(/^\[\.\.\.(.+)\]$/);
21
- return m ? { name: m[1], optional: !1 } : void 0;
22
- }).filter((t) => !!t), d = $(s);
23
- r.set(d, { path: d, params: y });
24
- const f = u[u.length - 1];
25
- if (f == null ? void 0 : f.match(/^\[\[\.\.\.(.+)\]\]$/)) {
26
- const t = u.slice(0, -1).join(l.sep), c = $(t);
27
- r.has(c) || r.set(c, { path: c, params: [] });
28
- }
29
- }
8
+ function G(n) {
9
+ const a = [
10
+ ["pagesDir", n.pagesDir],
11
+ ["pageFile", n.pageFile],
12
+ ["layoutFile", n.layoutFile],
13
+ ["notFoundFile", n.notFoundFile]
14
+ ];
15
+ for (const [e, t] of a)
16
+ if (!t.trim())
17
+ throw new Error(`nextViteRouter option "${e}" must not be empty.`);
18
+ const s = a.slice(1), i = s.find(
19
+ ([, e], t) => s.slice(t + 1).some(([, r]) => r === e)
20
+ );
21
+ if (i)
22
+ throw new Error(
23
+ `nextViteRouter file options must be distinct; "${i[0]}" is duplicated.`
24
+ );
25
+ }
26
+ function O(n) {
27
+ return n.replace(/\\/g, "/").replace(/^\.\//, "").replace(/^\/|\/$/g, "");
28
+ }
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: [] });
30
43
  }
31
44
  }
32
- return h.existsSync(n) && i(n), [...r.values()].sort((a, o) => a.path.localeCompare(o.path));
45
+ return [...e.values()].sort((t, r) => t.path.localeCompare(r.path));
33
46
  }
34
- function F(n, e) {
35
- const r = [];
36
- function i(a) {
37
- for (const o of h.readdirSync(a, { withFileTypes: !0 })) {
38
- const p = l.join(a, o.name);
39
- o.isDirectory() ? i(p) : o.isFile() && o.name === e && r.push(l.relative(n, p));
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
+ }
40
58
  }
41
59
  }
42
- return h.existsSync(n) && i(n), r;
60
+ return P.existsSync(n) && e(n), i;
43
61
  }
44
- function k(n) {
45
- const e = n.match(/^\/(?:\[\.\.\.|:)([^/\]]+)\]?$/);
46
- return e == null ? void 0 : e[1];
47
- }
48
- function w(n) {
49
- const e = n.map(({ path: i }) => ` | "${i}"`).join(`
50
- `), r = n.map(({ path: i, params: a }) => {
51
- const o = i.split("/").map((s) => k(`/${s}`)).filter((s) => !!s), p = o.length > 0 || a.length > 0 ? [
52
- ...o.map((s) => ` ${s}: string;`),
53
- ...a.map(({ name: s, optional: u }) => ` ${s}${u ? "?" : ""}: string;`)
62
+ function D(n) {
63
+ const a = n.map(({ path: i }) => ` | ${JSON.stringify(i)}`).join(`
64
+ `), s = n.map(({ path: i, params: e }) => {
65
+ const t = e.length > 0 ? [
66
+ ...e.map(({ name: r, optional: l }) => ` ${r}${l ? "?" : ""}: string;`)
54
67
  ].join(`
55
68
  `) : " [key: string]: never;";
56
- return ` "${i}": {
57
- ${p}
69
+ return ` ${JSON.stringify(i)}: {
70
+ ${t}
58
71
  };`;
59
72
  }).join(`
60
73
  `);
@@ -63,14 +76,14 @@ ${p}
63
76
  import type { RouteObject } from 'react-router-dom';
64
77
 
65
78
  export type RoutePath =
66
- ${e || ' | "/"'};
79
+ ${a || ' | "/"'};
67
80
 
68
81
  export type RouteParams<P extends RoutePath> = P extends keyof RoutePathParams
69
82
  ? RoutePathParams[P]
70
83
  : never;
71
84
 
72
85
  export interface RoutePathParams {
73
- ${r}
86
+ ${s}
74
87
  }
75
88
 
76
89
  export const generateRoutes: () => RouteObject[];
@@ -80,78 +93,85 @@ ${r}
80
93
  }
81
94
  `;
82
95
  }
83
- function D(n = {}) {
96
+ function z(n = {}) {
84
97
  const {
85
- pagesDir: e = "src/app",
86
- pageFile: r = "page.tsx",
98
+ pagesDir: a = "src/app",
99
+ pageFile: s = "page.tsx",
87
100
  layoutFile: i = "layout.tsx",
88
- notFoundFile: a = "not-found.tsx"
89
- } = n, o = { pagesDir: e, pageFile: r, layoutFile: i, notFoundFile: a }, p = "virtual:next-vite-router", s = "\0" + p;
90
- let u = "", y = "", d, f;
91
- function g() {
92
- const t = w(T(u, r));
93
- h.writeFileSync(y, t, "utf-8");
101
+ notFoundFile: e = "not-found.tsx"
102
+ } = n;
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");
94
109
  }
95
110
  return {
96
111
  name: "next-vite-router",
97
- configResolved(t) {
98
- u = l.resolve(t.root, e), y = l.join(l.dirname(u), "virtual-next-vite-router.d.ts"), b(F(u, r), o), g();
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();
99
118
  },
100
- configureServer(t) {
101
- if (d === t)
119
+ configureServer(o) {
120
+ if (u === o)
102
121
  return;
103
- f == null || f(), d = t;
104
- const c = (P) => {
105
- if (l.relative(u, P).startsWith("..") || ![r, i, a].includes(l.basename(P)))
122
+ h == null || h(), u = o;
123
+ const g = (b) => {
124
+ if (f.relative(c, b).startsWith("..") || ![s, i, e].includes(f.basename(b)))
106
125
  return;
107
126
  try {
108
- b(F(u, r), o);
127
+ v(
128
+ R(c, s, t),
129
+ R(c, e, t),
130
+ r
131
+ );
109
132
  } catch (x) {
110
- t.config.logger.error(
133
+ o.config.logger.error(
111
134
  x instanceof Error ? x.message : String(x)
112
135
  );
113
136
  return;
114
137
  }
115
- g();
116
- const v = t.moduleGraph.getModuleById(s);
117
- v && (t.moduleGraph.invalidateModule(v), m && clearTimeout(m), m = setTimeout(() => {
118
- m = 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: "*" });
119
142
  }, 0));
120
143
  };
121
- let m;
122
- const R = () => {
123
- m && (clearTimeout(m), m = void 0), t.watcher.off("add", c), t.watcher.off("unlink", c), t.watcher.off("close", R), d === t && (d = void 0, f = void 0);
144
+ let p;
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);
124
147
  };
125
- t.watcher.on("add", c), t.watcher.on("unlink", c), t.watcher.once("close", R), f = R;
148
+ o.watcher.on("add", g), o.watcher.on("unlink", g), o.watcher.once("close", y), h = y;
126
149
  },
127
- resolveId(t) {
128
- if (t === p)
129
- return s;
150
+ resolveId(o) {
151
+ if (o === l)
152
+ return d;
130
153
  },
131
- load(t) {
132
- if (t === s)
154
+ load(o) {
155
+ if (o === d) {
156
+ const g = `/${t}/**/${s}`, p = `/${t}/**/${i}`, y = `/${t}/**/${e}`;
133
157
  return `
134
158
  import { buildRouteTree, treeToRoutes, normalizeSegment, createLazyElement, useParams } from 'next-vite-router';
135
159
  import { Link, useRoutes } from 'react-router-dom';
136
160
 
137
- const pagesGlob = import.meta.glob('/${e}/**/${r}');
138
- const layoutsGlob = import.meta.glob('/${e}/**/${i}', { eager: true });
139
- const notFoundsGlob = import.meta.glob('/${e}/**/${a}');
161
+ const pagesGlob = import.meta.glob(${JSON.stringify(g)});
162
+ const layoutsGlob = import.meta.glob(${JSON.stringify(p)}, { eager: true });
163
+ const notFoundsGlob = import.meta.glob(${JSON.stringify(y)});
140
164
 
141
- const transformPath = (path) => path.replace('/${e}/', '');
142
-
143
- const pages = Object.fromEntries(
144
- Object.entries(pagesGlob).map(([key, value]) => [transformPath(key), value])
145
- );
146
- const layouts = Object.fromEntries(
147
- Object.entries(layoutsGlob).map(([key, value]) => [transformPath(key), value])
148
- );
149
- const notFounds = Object.fromEntries(
150
- Object.entries(notFoundsGlob).map(([key, value]) => [transformPath(key), value])
151
- );
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;
152
172
 
153
173
  export function generateRoutes() {
154
- const tree = buildRouteTree(pages, layouts, notFounds, ${JSON.stringify(o)});
174
+ const tree = buildRouteTree(pages, layouts, notFounds, ${JSON.stringify(r)});
155
175
  const routes = treeToRoutes(tree, true);
156
176
  return routes;
157
177
  }
@@ -172,9 +192,10 @@ if (import.meta.hot) {
172
192
  export { Link, useRoutes };
173
193
  export { useParams };
174
194
  `;
195
+ }
175
196
  }
176
197
  };
177
198
  }
178
199
  export {
179
- D as nextViteRouter
200
+ z as nextViteRouter
180
201
  };
@@ -0,0 +1,143 @@
1
+ function R(t) {
2
+ return /^\([^)]+\)$/.test(t) ? "" : /^\[\[\.\.\.(.+)\]\]$/.test(t) || /^\[\.\.\.(.+)\]$/.test(t) ? "*" : /^\[([^\]]+)\]$/.test(t) ? t.replace(/^\[([^\]]+)\]$/, ":$1") : t;
3
+ }
4
+ const P = /^[A-Za-z_][A-Za-z0-9_]*$/;
5
+ function A(t) {
6
+ return t.kind === "group" ? "" : t.kind === "dynamic" ? `:${t.name}` : t.kind === "catchAll" ? "*" : t.name;
7
+ }
8
+ function m(t) {
9
+ const s = t ? t.split("/").filter(Boolean) : [], o = [], c = /* @__PURE__ */ new Set();
10
+ for (const a of s) {
11
+ 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;
12
+ if (n)
13
+ o.push({ kind: "group", name: n[1] });
14
+ else if (l) {
15
+ if (!P.test(l.name))
16
+ throw new Error(
17
+ `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.`
18
+ );
19
+ if (c.has(l.name))
20
+ throw new Error(
21
+ `Duplicate route parameter "${l.name}" in route "${t || "/"}".`
22
+ );
23
+ c.add(l.name), o.push(l);
24
+ } else
25
+ o.push({ kind: "static", name: a });
26
+ }
27
+ return o;
28
+ }
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(/^\.\//, "").replace(/^\/|\/$/g, ""), r = e == null ? void 0 : e.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), i = [o, c, a].map((l) => l.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
31
+ return n.replace(
32
+ e ? new RegExp(`^.*?(?:^|/)${r}/`) : /^.*?(?:^|\/)(?:app|pages)\//,
33
+ ""
34
+ ).replace(/\\/g, "/").replace(new RegExp(`/?(?:${i})$`), "");
35
+ }
36
+ function $(t) {
37
+ return t.kind === "group" ? "" : t.kind === "catchAll" ? "*" : t.kind === "dynamic" ? ":param" : A(t);
38
+ }
39
+ function g(t, s) {
40
+ const o = f(t, s), c = m(o), a = c.map($).filter(Boolean), n = [
41
+ a.length > 0 ? `/${a.join("/")}` : "/"
42
+ ], e = c[c.length - 1];
43
+ if ((e == null ? void 0 : e.kind) === "catchAll" && e.optional) {
44
+ const r = a.slice(0, -1);
45
+ n.push(r.length > 0 ? `/${r.join("/")}` : "/");
46
+ }
47
+ return n;
48
+ }
49
+ function w(t) {
50
+ return /(^|\/)(:param|\*)($|\/)/.test(t) ? "pattern" : "literal";
51
+ }
52
+ function j(t, s, o) {
53
+ const c = t.flatMap((n) => {
54
+ const e = f(n, o), r = m(e), i = r[r.length - 1];
55
+ if ((i == null ? void 0 : i.kind) !== "catchAll")
56
+ return [];
57
+ const l = r.map($).filter(Boolean), u = l.length > 0 ? `/${l.join("/")}` : "/", p = l.slice(0, -1), k = p.length > 0 ? `/${p.join("/")}` : "/";
58
+ return [{ filePath: n, paths: /* @__PURE__ */ new Set([u, k]) }];
59
+ }), a = /* @__PURE__ */ new Map();
60
+ for (const n of s)
61
+ for (const e of g(n, o))
62
+ for (const r of c)
63
+ if (r.paths.has(e)) {
64
+ const i = `${e}\0${r.filePath}\0${n}`;
65
+ a.set(i, {
66
+ routePath: e,
67
+ pageFile: r.filePath,
68
+ notFoundFile: n
69
+ });
70
+ }
71
+ if (a.size > 0)
72
+ throw new Error(
73
+ [...a.values()].sort((n, e) => n.routePath.localeCompare(e.routePath)).map(
74
+ ({ routePath: n, pageFile: e, notFoundFile: r }) => `Conflicting fallback routes "${n}" detected:
75
+ catch-all page: ${e}
76
+ not-found file: ${r}
77
+ A not-found route and a catch-all page cannot coexist at the same route level.`
78
+ ).join(`
79
+
80
+ `)
81
+ );
82
+ }
83
+ function d(t, s) {
84
+ const o = /* @__PURE__ */ new Map();
85
+ for (const a of t)
86
+ for (const n of g(a, s)) {
87
+ const e = o.get(n) ?? [];
88
+ e.push({ kind: w(n), filePath: a }), o.set(n, e);
89
+ }
90
+ const c = [...o.entries()].filter(([, a]) => a.length > 1).sort(([a], [n]) => a.localeCompare(n));
91
+ if (c.length > 0)
92
+ throw new Error(
93
+ c.map(
94
+ ([a, n]) => `${n[0].kind === "pattern" ? "Ambiguous route pattern" : "Duplicate route"} "${a}" detected:
95
+ ${n.sort((e, r) => e.filePath.localeCompare(r.filePath)).map((e) => ` ${e.filePath}`).join(`
96
+ `)}`
97
+ ).join(`
98
+
99
+ `)
100
+ );
101
+ }
102
+ function E(t, s, o) {
103
+ d(t, o), d(s, o), j(t, s, o);
104
+ }
105
+ function h(t, s, o, c, a) {
106
+ const n = f(s, a), e = n ? n.split("/") : [];
107
+ let r = t, i = "";
108
+ e.forEach((l, u) => {
109
+ i = i ? `${i}/${l}` : l, r.children.has(l) || r.children.set(l, {
110
+ segment: l,
111
+ fullPath: i,
112
+ children: /* @__PURE__ */ new Map()
113
+ }), r = r.children.get(l), u === e.length - 1 && (r[c] = o);
114
+ }), e.length === 0 && (t[c] = o);
115
+ }
116
+ function b(t, s, o, c) {
117
+ E(
118
+ Object.keys(t),
119
+ Object.keys(o),
120
+ c
121
+ );
122
+ const a = {
123
+ segment: "",
124
+ fullPath: "",
125
+ children: /* @__PURE__ */ new Map()
126
+ };
127
+ return Object.entries(s).forEach(([n, e]) => {
128
+ h(a, n, e.default, "layout", c);
129
+ }), Object.entries(t).forEach(([n, e]) => {
130
+ h(a, n, e, "page", c);
131
+ }), Object.entries(o).forEach(([n, e]) => {
132
+ h(a, n, e, "notFound", c);
133
+ }), a;
134
+ }
135
+ export {
136
+ d as a,
137
+ b,
138
+ E as c,
139
+ f as e,
140
+ R as n,
141
+ m as p,
142
+ A as r
143
+ };
@@ -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.3",
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",
@@ -1,64 +0,0 @@
1
- function p(t) {
2
- return /^\([^)]+\)$/.test(t) ? "" : /^\[\[\.\.\.(.+)\]\]$/.test(t) || /^\[\.\.\.(.+)\]$/.test(t) ? "*" : /^\[([^\]]+)\]$/.test(t) ? t.replace(/^\[([^\]]+)\]$/, ":$1") : t;
3
- }
4
- function h(t, { pagesDir: c, pageFile: a = "page.tsx", layoutFile: o = "layout.tsx", notFoundFile: r = "not-found.tsx" } = {}) {
5
- const n = t.replace(/\\/g, "/"), e = c == null ? void 0 : c.replace(/\\/g, "/").replace(/^\/|\/$/g, ""), l = [a, o, r].map((u) => u.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
6
- return n.replace(
7
- e ? new RegExp(`^.*(?:^|/)${e}/`) : /^.*(?:^|\/)(?:app|pages)\//,
8
- ""
9
- ).replace(/\\/g, "/").replace(new RegExp(`/?(?:${l})$`), "");
10
- }
11
- function $(t, c) {
12
- const a = h(t, c), o = a ? a.split("/").map(p).filter(Boolean) : [];
13
- return o.length > 0 ? `/${o.join("/")}` : "/";
14
- }
15
- function d(t, c) {
16
- const a = /* @__PURE__ */ new Map();
17
- for (const r of t) {
18
- const n = $(r, c), e = a.get(n) ?? [];
19
- e.push(r), a.set(n, e);
20
- }
21
- const o = [...a.entries()].filter(([, r]) => r.length > 1).sort(([r], [n]) => r.localeCompare(n));
22
- if (o.length > 0)
23
- throw new Error(
24
- o.map(
25
- ([r, n]) => `Duplicate route "${r}" detected:
26
- ${n.sort((e, l) => e.localeCompare(l)).map((e) => ` ${e}`).join(`
27
- `)}`
28
- ).join(`
29
-
30
- `)
31
- );
32
- }
33
- function i(t, c, a, o, r) {
34
- const n = h(c, r), e = n ? n.split("/") : [];
35
- let l = t, u = "";
36
- e.forEach((s, f) => {
37
- u = u ? `${u}/${s}` : s, l.children.has(s) || l.children.set(s, {
38
- segment: s,
39
- fullPath: u,
40
- children: /* @__PURE__ */ new Map()
41
- }), l = l.children.get(s), f === e.length - 1 && (l[o] = a);
42
- }), e.length === 0 && (t[o] = a);
43
- }
44
- function P(t, c, a, o) {
45
- d(Object.keys(t), o);
46
- const r = {
47
- segment: "",
48
- fullPath: "",
49
- children: /* @__PURE__ */ new Map()
50
- };
51
- return Object.entries(c).forEach(([n, e]) => {
52
- i(r, n, e.default, "layout", o);
53
- }), Object.entries(t).forEach(([n, e]) => {
54
- i(r, n, e, "page", o);
55
- }), Object.entries(a).forEach(([n, e]) => {
56
- i(r, n, e, "notFound", o);
57
- }), r;
58
- }
59
- export {
60
- d as a,
61
- P as b,
62
- h as e,
63
- p as n
64
- };