@fluixi/router 0.1.2-alpha.3 → 0.1.2-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.cjs +271 -0
- package/dist/index.mjs +249 -0
- package/dist/lib/history.cjs +96 -0
- package/dist/lib/history.mjs +75 -0
- package/dist/lib/match.cjs +122 -0
- package/dist/lib/match.mjs +101 -0
- package/dist/lib/router.cjs +211 -0
- package/dist/lib/router.d.ts.map +1 -1
- package/dist/lib/router.js +6 -4
- package/dist/lib/router.mjs +188 -0
- package/dist/lib/types.cjs +18 -0
- package/dist/lib/types.mjs +0 -0
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/package.json +11 -3
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/lib/match.ts
|
|
21
|
+
var match_exports = {};
|
|
22
|
+
__export(match_exports, {
|
|
23
|
+
matchPath: () => matchPath,
|
|
24
|
+
matchRoutes: () => matchRoutes,
|
|
25
|
+
rankRoutes: () => rankRoutes,
|
|
26
|
+
scoreRoute: () => scoreRoute
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(match_exports);
|
|
29
|
+
function normalizePath(p) {
|
|
30
|
+
return p.startsWith("//") ? p.replace(/^\/+/, "/") : p;
|
|
31
|
+
}
|
|
32
|
+
function matchPath(pattern, path, exact = false) {
|
|
33
|
+
const keys = [];
|
|
34
|
+
if (pattern === path) return { params: {}, path };
|
|
35
|
+
if (!exact && pattern === "/" && path.startsWith("/"))
|
|
36
|
+
return { params: {}, path: "/" };
|
|
37
|
+
let regexStr = pattern.replace(/:([a-zA-Z0-9_]+)/g, (_, key) => {
|
|
38
|
+
keys.push(key);
|
|
39
|
+
return "([^/]+)";
|
|
40
|
+
}).replace(/\*([a-zA-Z0-9_]*)/g, (_, name) => {
|
|
41
|
+
if (name) keys.push(name);
|
|
42
|
+
return "(.*)";
|
|
43
|
+
});
|
|
44
|
+
if (!regexStr.startsWith("/")) regexStr = "/" + regexStr;
|
|
45
|
+
if (regexStr === "") regexStr = "/";
|
|
46
|
+
const regex = new RegExp(`^${regexStr}${exact ? "$" : "(?=/|$)"}`);
|
|
47
|
+
const match = path.match(regex);
|
|
48
|
+
if (!match) return null;
|
|
49
|
+
const params = {};
|
|
50
|
+
keys.forEach((key, i) => {
|
|
51
|
+
params[key] = match[i + 1];
|
|
52
|
+
});
|
|
53
|
+
return { params, path: match[0] };
|
|
54
|
+
}
|
|
55
|
+
function scoreRoute(def) {
|
|
56
|
+
const segments = def.path.split("/").filter(Boolean);
|
|
57
|
+
if (segments.length === 0) return 5;
|
|
58
|
+
let score = 0;
|
|
59
|
+
for (const seg of segments) {
|
|
60
|
+
if (seg.startsWith("*")) score += 1;
|
|
61
|
+
else if (seg.startsWith(":")) score += 10;
|
|
62
|
+
else score += 100;
|
|
63
|
+
}
|
|
64
|
+
return score;
|
|
65
|
+
}
|
|
66
|
+
function rankRoutes(defs) {
|
|
67
|
+
return [...defs].sort((a, b) => scoreRoute(b) - scoreRoute(a));
|
|
68
|
+
}
|
|
69
|
+
function matchRoutes(routes, pathname) {
|
|
70
|
+
const path = pathname.length > 1 ? pathname.replace(/\/+$/, "") || "/" : pathname;
|
|
71
|
+
const result = matchInto(routes, path);
|
|
72
|
+
if (!result) return null;
|
|
73
|
+
const matched = [];
|
|
74
|
+
let cumulative = "";
|
|
75
|
+
const params = {};
|
|
76
|
+
for (const layer of result.layers) {
|
|
77
|
+
cumulative = normalizePath(joinMatched(cumulative, layer.consumed));
|
|
78
|
+
const layerParams = {};
|
|
79
|
+
for (const [k, v] of Object.entries(layer.params)) {
|
|
80
|
+
if (!(k in params)) layerParams[k] = v;
|
|
81
|
+
params[k] = v;
|
|
82
|
+
}
|
|
83
|
+
matched.push({
|
|
84
|
+
route: layer.route,
|
|
85
|
+
component: layer.route.component,
|
|
86
|
+
params: layerParams,
|
|
87
|
+
pathname: cumulative || "/"
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
return { matched, params, pathname };
|
|
91
|
+
}
|
|
92
|
+
function matchInto(defs, currentPath) {
|
|
93
|
+
if (!defs || defs.length === 0) return null;
|
|
94
|
+
const ranked = rankRoutes(defs);
|
|
95
|
+
for (const def of ranked) {
|
|
96
|
+
const hasChildren = !!def.children && def.children.length > 0;
|
|
97
|
+
const seg = matchPath(def.path, currentPath, !hasChildren);
|
|
98
|
+
if (!seg) continue;
|
|
99
|
+
if (hasChildren) {
|
|
100
|
+
const childMatch = matchInto(def.children, currentPath);
|
|
101
|
+
if (childMatch) {
|
|
102
|
+
return {
|
|
103
|
+
layers: [
|
|
104
|
+
{ route: def, params: seg.params, consumed: seg.path },
|
|
105
|
+
...childMatch.layers
|
|
106
|
+
]
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
return { layers: [{ route: def, params: seg.params, consumed: seg.path }] };
|
|
112
|
+
}
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
function joinMatched(cumulative, consumed) {
|
|
116
|
+
if (!cumulative) return consumed;
|
|
117
|
+
if (consumed === cumulative) return cumulative;
|
|
118
|
+
if (consumed.startsWith(cumulative)) return consumed;
|
|
119
|
+
const a = cumulative.replace(/\/$/, "");
|
|
120
|
+
const b = consumed.replace(/^\//, "");
|
|
121
|
+
return `${a}/${b}`;
|
|
122
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// src/lib/match.ts
|
|
2
|
+
function normalizePath(p) {
|
|
3
|
+
return p.startsWith("//") ? p.replace(/^\/+/, "/") : p;
|
|
4
|
+
}
|
|
5
|
+
function matchPath(pattern, path, exact = false) {
|
|
6
|
+
const keys = [];
|
|
7
|
+
if (pattern === path) return { params: {}, path };
|
|
8
|
+
if (!exact && pattern === "/" && path.startsWith("/"))
|
|
9
|
+
return { params: {}, path: "/" };
|
|
10
|
+
let regexStr = pattern.replace(/:([a-zA-Z0-9_]+)/g, (_, key) => {
|
|
11
|
+
keys.push(key);
|
|
12
|
+
return "([^/]+)";
|
|
13
|
+
}).replace(/\*([a-zA-Z0-9_]*)/g, (_, name) => {
|
|
14
|
+
if (name) keys.push(name);
|
|
15
|
+
return "(.*)";
|
|
16
|
+
});
|
|
17
|
+
if (!regexStr.startsWith("/")) regexStr = "/" + regexStr;
|
|
18
|
+
if (regexStr === "") regexStr = "/";
|
|
19
|
+
const regex = new RegExp(`^${regexStr}${exact ? "$" : "(?=/|$)"}`);
|
|
20
|
+
const match = path.match(regex);
|
|
21
|
+
if (!match) return null;
|
|
22
|
+
const params = {};
|
|
23
|
+
keys.forEach((key, i) => {
|
|
24
|
+
params[key] = match[i + 1];
|
|
25
|
+
});
|
|
26
|
+
return { params, path: match[0] };
|
|
27
|
+
}
|
|
28
|
+
function scoreRoute(def) {
|
|
29
|
+
const segments = def.path.split("/").filter(Boolean);
|
|
30
|
+
if (segments.length === 0) return 5;
|
|
31
|
+
let score = 0;
|
|
32
|
+
for (const seg of segments) {
|
|
33
|
+
if (seg.startsWith("*")) score += 1;
|
|
34
|
+
else if (seg.startsWith(":")) score += 10;
|
|
35
|
+
else score += 100;
|
|
36
|
+
}
|
|
37
|
+
return score;
|
|
38
|
+
}
|
|
39
|
+
function rankRoutes(defs) {
|
|
40
|
+
return [...defs].sort((a, b) => scoreRoute(b) - scoreRoute(a));
|
|
41
|
+
}
|
|
42
|
+
function matchRoutes(routes, pathname) {
|
|
43
|
+
const path = pathname.length > 1 ? pathname.replace(/\/+$/, "") || "/" : pathname;
|
|
44
|
+
const result = matchInto(routes, path);
|
|
45
|
+
if (!result) return null;
|
|
46
|
+
const matched = [];
|
|
47
|
+
let cumulative = "";
|
|
48
|
+
const params = {};
|
|
49
|
+
for (const layer of result.layers) {
|
|
50
|
+
cumulative = normalizePath(joinMatched(cumulative, layer.consumed));
|
|
51
|
+
const layerParams = {};
|
|
52
|
+
for (const [k, v] of Object.entries(layer.params)) {
|
|
53
|
+
if (!(k in params)) layerParams[k] = v;
|
|
54
|
+
params[k] = v;
|
|
55
|
+
}
|
|
56
|
+
matched.push({
|
|
57
|
+
route: layer.route,
|
|
58
|
+
component: layer.route.component,
|
|
59
|
+
params: layerParams,
|
|
60
|
+
pathname: cumulative || "/"
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
return { matched, params, pathname };
|
|
64
|
+
}
|
|
65
|
+
function matchInto(defs, currentPath) {
|
|
66
|
+
if (!defs || defs.length === 0) return null;
|
|
67
|
+
const ranked = rankRoutes(defs);
|
|
68
|
+
for (const def of ranked) {
|
|
69
|
+
const hasChildren = !!def.children && def.children.length > 0;
|
|
70
|
+
const seg = matchPath(def.path, currentPath, !hasChildren);
|
|
71
|
+
if (!seg) continue;
|
|
72
|
+
if (hasChildren) {
|
|
73
|
+
const childMatch = matchInto(def.children, currentPath);
|
|
74
|
+
if (childMatch) {
|
|
75
|
+
return {
|
|
76
|
+
layers: [
|
|
77
|
+
{ route: def, params: seg.params, consumed: seg.path },
|
|
78
|
+
...childMatch.layers
|
|
79
|
+
]
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
return { layers: [{ route: def, params: seg.params, consumed: seg.path }] };
|
|
85
|
+
}
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
function joinMatched(cumulative, consumed) {
|
|
89
|
+
if (!cumulative) return consumed;
|
|
90
|
+
if (consumed === cumulative) return cumulative;
|
|
91
|
+
if (consumed.startsWith(cumulative)) return consumed;
|
|
92
|
+
const a = cumulative.replace(/\/$/, "");
|
|
93
|
+
const b = consumed.replace(/^\//, "");
|
|
94
|
+
return `${a}/${b}`;
|
|
95
|
+
}
|
|
96
|
+
export {
|
|
97
|
+
matchPath,
|
|
98
|
+
matchRoutes,
|
|
99
|
+
rankRoutes,
|
|
100
|
+
scoreRoute
|
|
101
|
+
};
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/lib/router.ts
|
|
21
|
+
var router_exports = {};
|
|
22
|
+
__export(router_exports, {
|
|
23
|
+
createRouter: () => createRouter,
|
|
24
|
+
splitPath: () => splitPath
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(router_exports);
|
|
27
|
+
|
|
28
|
+
// src/lib/match.ts
|
|
29
|
+
function normalizePath(p) {
|
|
30
|
+
return p.startsWith("//") ? p.replace(/^\/+/, "/") : p;
|
|
31
|
+
}
|
|
32
|
+
function matchPath(pattern, path, exact = false) {
|
|
33
|
+
const keys = [];
|
|
34
|
+
if (pattern === path) return { params: {}, path };
|
|
35
|
+
if (!exact && pattern === "/" && path.startsWith("/"))
|
|
36
|
+
return { params: {}, path: "/" };
|
|
37
|
+
let regexStr = pattern.replace(/:([a-zA-Z0-9_]+)/g, (_, key) => {
|
|
38
|
+
keys.push(key);
|
|
39
|
+
return "([^/]+)";
|
|
40
|
+
}).replace(/\*([a-zA-Z0-9_]*)/g, (_, name) => {
|
|
41
|
+
if (name) keys.push(name);
|
|
42
|
+
return "(.*)";
|
|
43
|
+
});
|
|
44
|
+
if (!regexStr.startsWith("/")) regexStr = "/" + regexStr;
|
|
45
|
+
if (regexStr === "") regexStr = "/";
|
|
46
|
+
const regex = new RegExp(`^${regexStr}${exact ? "$" : "(?=/|$)"}`);
|
|
47
|
+
const match = path.match(regex);
|
|
48
|
+
if (!match) return null;
|
|
49
|
+
const params = {};
|
|
50
|
+
keys.forEach((key, i) => {
|
|
51
|
+
params[key] = match[i + 1];
|
|
52
|
+
});
|
|
53
|
+
return { params, path: match[0] };
|
|
54
|
+
}
|
|
55
|
+
function scoreRoute(def) {
|
|
56
|
+
const segments = def.path.split("/").filter(Boolean);
|
|
57
|
+
if (segments.length === 0) return 5;
|
|
58
|
+
let score = 0;
|
|
59
|
+
for (const seg of segments) {
|
|
60
|
+
if (seg.startsWith("*")) score += 1;
|
|
61
|
+
else if (seg.startsWith(":")) score += 10;
|
|
62
|
+
else score += 100;
|
|
63
|
+
}
|
|
64
|
+
return score;
|
|
65
|
+
}
|
|
66
|
+
function rankRoutes(defs) {
|
|
67
|
+
return [...defs].sort((a, b) => scoreRoute(b) - scoreRoute(a));
|
|
68
|
+
}
|
|
69
|
+
function matchRoutes(routes, pathname) {
|
|
70
|
+
const path = pathname.length > 1 ? pathname.replace(/\/+$/, "") || "/" : pathname;
|
|
71
|
+
const result = matchInto(routes, path);
|
|
72
|
+
if (!result) return null;
|
|
73
|
+
const matched = [];
|
|
74
|
+
let cumulative = "";
|
|
75
|
+
const params = {};
|
|
76
|
+
for (const layer of result.layers) {
|
|
77
|
+
cumulative = normalizePath(joinMatched(cumulative, layer.consumed));
|
|
78
|
+
const layerParams = {};
|
|
79
|
+
for (const [k, v] of Object.entries(layer.params)) {
|
|
80
|
+
if (!(k in params)) layerParams[k] = v;
|
|
81
|
+
params[k] = v;
|
|
82
|
+
}
|
|
83
|
+
matched.push({
|
|
84
|
+
route: layer.route,
|
|
85
|
+
component: layer.route.component,
|
|
86
|
+
params: layerParams,
|
|
87
|
+
pathname: cumulative || "/"
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
return { matched, params, pathname };
|
|
91
|
+
}
|
|
92
|
+
function matchInto(defs, currentPath) {
|
|
93
|
+
if (!defs || defs.length === 0) return null;
|
|
94
|
+
const ranked = rankRoutes(defs);
|
|
95
|
+
for (const def of ranked) {
|
|
96
|
+
const hasChildren = !!def.children && def.children.length > 0;
|
|
97
|
+
const seg = matchPath(def.path, currentPath, !hasChildren);
|
|
98
|
+
if (!seg) continue;
|
|
99
|
+
if (hasChildren) {
|
|
100
|
+
const childMatch = matchInto(def.children, currentPath);
|
|
101
|
+
if (childMatch) {
|
|
102
|
+
return {
|
|
103
|
+
layers: [
|
|
104
|
+
{ route: def, params: seg.params, consumed: seg.path },
|
|
105
|
+
...childMatch.layers
|
|
106
|
+
]
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
return { layers: [{ route: def, params: seg.params, consumed: seg.path }] };
|
|
112
|
+
}
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
function joinMatched(cumulative, consumed) {
|
|
116
|
+
if (!cumulative) return consumed;
|
|
117
|
+
if (consumed === cumulative) return cumulative;
|
|
118
|
+
if (consumed.startsWith(cumulative)) return consumed;
|
|
119
|
+
const a = cumulative.replace(/\/$/, "");
|
|
120
|
+
const b = consumed.replace(/^\//, "");
|
|
121
|
+
return `${a}/${b}`;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// src/lib/history.ts
|
|
125
|
+
function splitPath(to) {
|
|
126
|
+
let rest = to;
|
|
127
|
+
let hash = "";
|
|
128
|
+
const hashIdx = rest.indexOf("#");
|
|
129
|
+
if (hashIdx !== -1) {
|
|
130
|
+
hash = rest.slice(hashIdx);
|
|
131
|
+
rest = rest.slice(0, hashIdx);
|
|
132
|
+
}
|
|
133
|
+
let search = "";
|
|
134
|
+
const qIdx = rest.indexOf("?");
|
|
135
|
+
if (qIdx !== -1) {
|
|
136
|
+
search = rest.slice(qIdx);
|
|
137
|
+
rest = rest.slice(0, qIdx);
|
|
138
|
+
}
|
|
139
|
+
return { pathname: rest || "/", search, hash };
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// src/lib/router.ts
|
|
143
|
+
function parseQuery(search) {
|
|
144
|
+
const q = {};
|
|
145
|
+
if (search) {
|
|
146
|
+
const usp = new URLSearchParams(
|
|
147
|
+
search.startsWith("?") ? search.slice(1) : search
|
|
148
|
+
);
|
|
149
|
+
usp.forEach((v, k) => q[k] = v);
|
|
150
|
+
}
|
|
151
|
+
return q;
|
|
152
|
+
}
|
|
153
|
+
function stripBase(pathname, base) {
|
|
154
|
+
if (!base) return pathname || "/";
|
|
155
|
+
const b = base.replace(/\/$/, "");
|
|
156
|
+
if (pathname === b) return "/";
|
|
157
|
+
if (pathname.startsWith(b + "/")) return pathname.slice(b.length) || "/";
|
|
158
|
+
return pathname || "/";
|
|
159
|
+
}
|
|
160
|
+
function withBase(to, base) {
|
|
161
|
+
if (!base) return to;
|
|
162
|
+
if (/^https?:\/\//.test(to)) return to;
|
|
163
|
+
const b = base.replace(/\/$/, "");
|
|
164
|
+
return `${b}${to.startsWith("/") ? to : "/" + to}`;
|
|
165
|
+
}
|
|
166
|
+
function createRouter(config) {
|
|
167
|
+
const { routes, history, base } = config;
|
|
168
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
169
|
+
const readLocation = () => {
|
|
170
|
+
const raw = history.get();
|
|
171
|
+
return {
|
|
172
|
+
pathname: raw.pathname,
|
|
173
|
+
search: raw.search,
|
|
174
|
+
hash: raw.hash,
|
|
175
|
+
state: raw.state,
|
|
176
|
+
query: parseQuery(raw.search)
|
|
177
|
+
};
|
|
178
|
+
};
|
|
179
|
+
const computeMatch = (pathname) => matchRoutes(routes, stripBase(pathname, base));
|
|
180
|
+
let current = (() => {
|
|
181
|
+
const location = readLocation();
|
|
182
|
+
return { location, match: computeMatch(location.pathname) };
|
|
183
|
+
})();
|
|
184
|
+
const recompute = () => {
|
|
185
|
+
const location = readLocation();
|
|
186
|
+
current = { location, match: computeMatch(location.pathname) };
|
|
187
|
+
listeners.forEach((l) => l(current));
|
|
188
|
+
};
|
|
189
|
+
const unsubscribeHistory = history.subscribe(recompute);
|
|
190
|
+
return {
|
|
191
|
+
state() {
|
|
192
|
+
return current;
|
|
193
|
+
},
|
|
194
|
+
subscribe(listener) {
|
|
195
|
+
listeners.add(listener);
|
|
196
|
+
return () => listeners.delete(listener);
|
|
197
|
+
},
|
|
198
|
+
navigate(to, options = {}) {
|
|
199
|
+
const target = withBase(to, base);
|
|
200
|
+
if (options.replace) history.replace(target, options.state ?? null);
|
|
201
|
+
else history.push(target, options.state ?? null);
|
|
202
|
+
},
|
|
203
|
+
match(pathname) {
|
|
204
|
+
return computeMatch(pathname);
|
|
205
|
+
},
|
|
206
|
+
destroy() {
|
|
207
|
+
unsubscribeHistory();
|
|
208
|
+
listeners.clear();
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
}
|
package/dist/lib/router.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/lib/router.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,KAAK,EACV,MAAM,EACN,YAAY,EAKb,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/lib/router.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,KAAK,EACV,MAAM,EACN,YAAY,EAKb,MAAM,YAAY,CAAC;AAiCpB,wBAAgB,YAAY,CAAC,CAAC,GAAG,OAAO,EACtC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,GACtB,MAAM,CAAC,CAAC,CAAC,CAuDX;AAED,0DAA0D;AAC1D,OAAO,EAAE,SAAS,EAAE,CAAC"}
|
package/dist/lib/router.js
CHANGED
|
@@ -10,10 +10,12 @@ import { splitPath } from './history.js';
|
|
|
10
10
|
/** Parse a `?a=1&b=2` search string into an object. */
|
|
11
11
|
function parseQuery(search) {
|
|
12
12
|
const q = {};
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
// Guarded rather than an early return: `search` is typed as a string but reaches
|
|
14
|
+
// here from a location object, so a missing one must give `{}` and not throw.
|
|
15
|
+
if (search) {
|
|
16
|
+
const usp = new URLSearchParams(search.startsWith('?') ? search.slice(1) : search);
|
|
17
|
+
usp.forEach((v, k) => (q[k] = v));
|
|
18
|
+
}
|
|
17
19
|
return q;
|
|
18
20
|
}
|
|
19
21
|
/** Strip a base prefix from a pathname (so matching is base-relative). */
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
// src/lib/match.ts
|
|
2
|
+
function normalizePath(p) {
|
|
3
|
+
return p.startsWith("//") ? p.replace(/^\/+/, "/") : p;
|
|
4
|
+
}
|
|
5
|
+
function matchPath(pattern, path, exact = false) {
|
|
6
|
+
const keys = [];
|
|
7
|
+
if (pattern === path) return { params: {}, path };
|
|
8
|
+
if (!exact && pattern === "/" && path.startsWith("/"))
|
|
9
|
+
return { params: {}, path: "/" };
|
|
10
|
+
let regexStr = pattern.replace(/:([a-zA-Z0-9_]+)/g, (_, key) => {
|
|
11
|
+
keys.push(key);
|
|
12
|
+
return "([^/]+)";
|
|
13
|
+
}).replace(/\*([a-zA-Z0-9_]*)/g, (_, name) => {
|
|
14
|
+
if (name) keys.push(name);
|
|
15
|
+
return "(.*)";
|
|
16
|
+
});
|
|
17
|
+
if (!regexStr.startsWith("/")) regexStr = "/" + regexStr;
|
|
18
|
+
if (regexStr === "") regexStr = "/";
|
|
19
|
+
const regex = new RegExp(`^${regexStr}${exact ? "$" : "(?=/|$)"}`);
|
|
20
|
+
const match = path.match(regex);
|
|
21
|
+
if (!match) return null;
|
|
22
|
+
const params = {};
|
|
23
|
+
keys.forEach((key, i) => {
|
|
24
|
+
params[key] = match[i + 1];
|
|
25
|
+
});
|
|
26
|
+
return { params, path: match[0] };
|
|
27
|
+
}
|
|
28
|
+
function scoreRoute(def) {
|
|
29
|
+
const segments = def.path.split("/").filter(Boolean);
|
|
30
|
+
if (segments.length === 0) return 5;
|
|
31
|
+
let score = 0;
|
|
32
|
+
for (const seg of segments) {
|
|
33
|
+
if (seg.startsWith("*")) score += 1;
|
|
34
|
+
else if (seg.startsWith(":")) score += 10;
|
|
35
|
+
else score += 100;
|
|
36
|
+
}
|
|
37
|
+
return score;
|
|
38
|
+
}
|
|
39
|
+
function rankRoutes(defs) {
|
|
40
|
+
return [...defs].sort((a, b) => scoreRoute(b) - scoreRoute(a));
|
|
41
|
+
}
|
|
42
|
+
function matchRoutes(routes, pathname) {
|
|
43
|
+
const path = pathname.length > 1 ? pathname.replace(/\/+$/, "") || "/" : pathname;
|
|
44
|
+
const result = matchInto(routes, path);
|
|
45
|
+
if (!result) return null;
|
|
46
|
+
const matched = [];
|
|
47
|
+
let cumulative = "";
|
|
48
|
+
const params = {};
|
|
49
|
+
for (const layer of result.layers) {
|
|
50
|
+
cumulative = normalizePath(joinMatched(cumulative, layer.consumed));
|
|
51
|
+
const layerParams = {};
|
|
52
|
+
for (const [k, v] of Object.entries(layer.params)) {
|
|
53
|
+
if (!(k in params)) layerParams[k] = v;
|
|
54
|
+
params[k] = v;
|
|
55
|
+
}
|
|
56
|
+
matched.push({
|
|
57
|
+
route: layer.route,
|
|
58
|
+
component: layer.route.component,
|
|
59
|
+
params: layerParams,
|
|
60
|
+
pathname: cumulative || "/"
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
return { matched, params, pathname };
|
|
64
|
+
}
|
|
65
|
+
function matchInto(defs, currentPath) {
|
|
66
|
+
if (!defs || defs.length === 0) return null;
|
|
67
|
+
const ranked = rankRoutes(defs);
|
|
68
|
+
for (const def of ranked) {
|
|
69
|
+
const hasChildren = !!def.children && def.children.length > 0;
|
|
70
|
+
const seg = matchPath(def.path, currentPath, !hasChildren);
|
|
71
|
+
if (!seg) continue;
|
|
72
|
+
if (hasChildren) {
|
|
73
|
+
const childMatch = matchInto(def.children, currentPath);
|
|
74
|
+
if (childMatch) {
|
|
75
|
+
return {
|
|
76
|
+
layers: [
|
|
77
|
+
{ route: def, params: seg.params, consumed: seg.path },
|
|
78
|
+
...childMatch.layers
|
|
79
|
+
]
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
return { layers: [{ route: def, params: seg.params, consumed: seg.path }] };
|
|
85
|
+
}
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
function joinMatched(cumulative, consumed) {
|
|
89
|
+
if (!cumulative) return consumed;
|
|
90
|
+
if (consumed === cumulative) return cumulative;
|
|
91
|
+
if (consumed.startsWith(cumulative)) return consumed;
|
|
92
|
+
const a = cumulative.replace(/\/$/, "");
|
|
93
|
+
const b = consumed.replace(/^\//, "");
|
|
94
|
+
return `${a}/${b}`;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// src/lib/history.ts
|
|
98
|
+
function splitPath(to) {
|
|
99
|
+
let rest = to;
|
|
100
|
+
let hash = "";
|
|
101
|
+
const hashIdx = rest.indexOf("#");
|
|
102
|
+
if (hashIdx !== -1) {
|
|
103
|
+
hash = rest.slice(hashIdx);
|
|
104
|
+
rest = rest.slice(0, hashIdx);
|
|
105
|
+
}
|
|
106
|
+
let search = "";
|
|
107
|
+
const qIdx = rest.indexOf("?");
|
|
108
|
+
if (qIdx !== -1) {
|
|
109
|
+
search = rest.slice(qIdx);
|
|
110
|
+
rest = rest.slice(0, qIdx);
|
|
111
|
+
}
|
|
112
|
+
return { pathname: rest || "/", search, hash };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// src/lib/router.ts
|
|
116
|
+
function parseQuery(search) {
|
|
117
|
+
const q = {};
|
|
118
|
+
if (search) {
|
|
119
|
+
const usp = new URLSearchParams(
|
|
120
|
+
search.startsWith("?") ? search.slice(1) : search
|
|
121
|
+
);
|
|
122
|
+
usp.forEach((v, k) => q[k] = v);
|
|
123
|
+
}
|
|
124
|
+
return q;
|
|
125
|
+
}
|
|
126
|
+
function stripBase(pathname, base) {
|
|
127
|
+
if (!base) return pathname || "/";
|
|
128
|
+
const b = base.replace(/\/$/, "");
|
|
129
|
+
if (pathname === b) return "/";
|
|
130
|
+
if (pathname.startsWith(b + "/")) return pathname.slice(b.length) || "/";
|
|
131
|
+
return pathname || "/";
|
|
132
|
+
}
|
|
133
|
+
function withBase(to, base) {
|
|
134
|
+
if (!base) return to;
|
|
135
|
+
if (/^https?:\/\//.test(to)) return to;
|
|
136
|
+
const b = base.replace(/\/$/, "");
|
|
137
|
+
return `${b}${to.startsWith("/") ? to : "/" + to}`;
|
|
138
|
+
}
|
|
139
|
+
function createRouter(config) {
|
|
140
|
+
const { routes, history, base } = config;
|
|
141
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
142
|
+
const readLocation = () => {
|
|
143
|
+
const raw = history.get();
|
|
144
|
+
return {
|
|
145
|
+
pathname: raw.pathname,
|
|
146
|
+
search: raw.search,
|
|
147
|
+
hash: raw.hash,
|
|
148
|
+
state: raw.state,
|
|
149
|
+
query: parseQuery(raw.search)
|
|
150
|
+
};
|
|
151
|
+
};
|
|
152
|
+
const computeMatch = (pathname) => matchRoutes(routes, stripBase(pathname, base));
|
|
153
|
+
let current = (() => {
|
|
154
|
+
const location = readLocation();
|
|
155
|
+
return { location, match: computeMatch(location.pathname) };
|
|
156
|
+
})();
|
|
157
|
+
const recompute = () => {
|
|
158
|
+
const location = readLocation();
|
|
159
|
+
current = { location, match: computeMatch(location.pathname) };
|
|
160
|
+
listeners.forEach((l) => l(current));
|
|
161
|
+
};
|
|
162
|
+
const unsubscribeHistory = history.subscribe(recompute);
|
|
163
|
+
return {
|
|
164
|
+
state() {
|
|
165
|
+
return current;
|
|
166
|
+
},
|
|
167
|
+
subscribe(listener) {
|
|
168
|
+
listeners.add(listener);
|
|
169
|
+
return () => listeners.delete(listener);
|
|
170
|
+
},
|
|
171
|
+
navigate(to, options = {}) {
|
|
172
|
+
const target = withBase(to, base);
|
|
173
|
+
if (options.replace) history.replace(target, options.state ?? null);
|
|
174
|
+
else history.push(target, options.state ?? null);
|
|
175
|
+
},
|
|
176
|
+
match(pathname) {
|
|
177
|
+
return computeMatch(pathname);
|
|
178
|
+
},
|
|
179
|
+
destroy() {
|
|
180
|
+
unsubscribeHistory();
|
|
181
|
+
listeners.clear();
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
export {
|
|
186
|
+
createRouter,
|
|
187
|
+
splitPath
|
|
188
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __copyProps = (to, from, except, desc) => {
|
|
7
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
8
|
+
for (let key of __getOwnPropNames(from))
|
|
9
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
10
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
11
|
+
}
|
|
12
|
+
return to;
|
|
13
|
+
};
|
|
14
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
15
|
+
|
|
16
|
+
// src/lib/types.ts
|
|
17
|
+
var types_exports = {};
|
|
18
|
+
module.exports = __toCommonJS(types_exports);
|
|
File without changes
|