valyrian.js 7.0.4 → 7.1.1
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/router/index.d.ts +14 -12
- package/dist/router/index.d.ts.map +1 -1
- package/dist/router/index.js +59 -74
- package/dist/router/index.mjs +59 -74
- package/lib/router/index.ts +107 -95
- package/package.json +1 -1
package/dist/router/index.d.ts
CHANGED
|
@@ -1,11 +1,4 @@
|
|
|
1
1
|
import { Component, POJOComponent, VnodeComponentInterface } from "valyrian.js";
|
|
2
|
-
interface Path {
|
|
3
|
-
method: string;
|
|
4
|
-
path: string;
|
|
5
|
-
middlewares: Middlewares;
|
|
6
|
-
params: string[];
|
|
7
|
-
regexp: RegExp;
|
|
8
|
-
}
|
|
9
2
|
interface Request {
|
|
10
3
|
params: Record<string, any>;
|
|
11
4
|
query: Record<string, any>;
|
|
@@ -19,6 +12,13 @@ interface Middleware {
|
|
|
19
12
|
}
|
|
20
13
|
interface Middlewares extends Array<Middleware> {
|
|
21
14
|
}
|
|
15
|
+
interface Path {
|
|
16
|
+
method: string;
|
|
17
|
+
path: string;
|
|
18
|
+
middlewares: Middlewares;
|
|
19
|
+
params: string[];
|
|
20
|
+
regexp: RegExp;
|
|
21
|
+
}
|
|
22
22
|
interface RouterInterface {
|
|
23
23
|
paths: Path[];
|
|
24
24
|
container: Element | string | null;
|
|
@@ -42,13 +42,15 @@ export declare class Router implements RouterInterface {
|
|
|
42
42
|
path: string;
|
|
43
43
|
params: Record<string, string | number | any>;
|
|
44
44
|
matches: string[];
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
pathPrefix: string;
|
|
46
|
+
constructor(pathPrefix?: string);
|
|
47
|
+
add(path: string, ...middlewares: Middlewares): Router;
|
|
48
|
+
use(...middlewares: Middlewares | Router[] | string[]): Router;
|
|
47
49
|
routes(): string[];
|
|
48
|
-
go(path: string, parentComponent?: Component): Promise<string | void>;
|
|
50
|
+
go(path: string, parentComponent?: Component, preventPushState?: boolean): Promise<string | void>;
|
|
49
51
|
getOnClickHandler(url: string): (e: MouseEvent) => void;
|
|
50
52
|
}
|
|
51
|
-
export declare function redirect(url: string):
|
|
52
|
-
export declare function mountRouter(elementContainer: any, router:
|
|
53
|
+
export declare function redirect(url: string, parentComponent?: Component, preventPushState?: boolean): string | void;
|
|
54
|
+
export declare function mountRouter(elementContainer: string | any, router: Router): void;
|
|
53
55
|
export {};
|
|
54
56
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../lib/router/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,SAAS,EACT,aAAa,EACb,uBAAuB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../lib/router/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,SAAS,EACT,aAAa,EACb,uBAAuB,EASxB,MAAM,aAAa,CAAC;AAErB,UAAU,OAAO;IACf,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,EAAE,CAAC;IAElB,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,SAAS,GAAG,aAAa,GAAG,uBAAuB,KAAK,KAAK,CAAC;CAC1G;AAED,UAAU,UAAU;IAElB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,GAAG,GACpB,OAAO,CAAC,GAAG,GAAG,SAAS,GAAG,aAAa,GAAG,uBAAuB,CAAC,GAClE,GAAG,GACH,SAAS,GACT,aAAa,GACb,uBAAuB,CAAC;CAC7B;AAED,UAAU,WAAY,SAAQ,KAAK,CAAC,UAAU,CAAC;CAAG;AAElD,UAAU,IAAI;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,WAAW,CAAC;IACzB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,eAAe;IACvB,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,SAAS,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAAC;IACnC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;IACvC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,GAAG,CAAC,CAAC;IAC9C,OAAO,EAAE,MAAM,EAAE,CAAC;IAElB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,WAAW,GAAG,MAAM,CAAC;IAElD,GAAG,CAAC,GAAG,IAAI,EAAE,MAAM,EAAE,GAAG,WAAW,GAAG,MAAM,EAAE,GAAG,MAAM,CAAC;IAExD,MAAM,IAAI,MAAM,EAAE,CAAC;IAEnB,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,SAAS,GAAG,aAAa,GAAG,uBAAuB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CACjH;AAuID,qBAAa,MAAO,YAAW,eAAe;IAC5C,KAAK,EAAE,IAAI,EAAE,CAAM;IACnB,SAAS,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAAQ;IAC1C,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAM;IAC5C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAM;IAClC,GAAG,EAAE,MAAM,CAAM;IACjB,IAAI,EAAE,MAAM,CAAM;IAClB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,GAAG,CAAC,CAAM;IACnD,OAAO,EAAE,MAAM,EAAE,CAAM;IACvB,UAAU,EAAE,MAAM,CAAM;gBAEZ,UAAU,GAAE,MAAW;IAInC,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,WAAW,EAAE,WAAW,GAAG,MAAM;IAKtD,GAAG,CAAC,GAAG,WAAW,EAAE,WAAW,GAAG,MAAM,EAAE,GAAG,MAAM,EAAE,GAAG,MAAM;IAyB9D,MAAM,IAAI,MAAM,EAAE;IAIZ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,SAAS,EAAE,gBAAgB,UAAQ,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAwCrG,iBAAiB,CAAC,GAAG,EAAE,MAAM,OAChB,UAAU;CAOxB;AAID,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,SAAS,EAAE,gBAAgB,UAAQ,GAAG,MAAM,GAAG,IAAI,CAK1G;AAED,wBAAgB,WAAW,CAAC,gBAAgB,EAAE,MAAM,GAAG,GAAG,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAiBhF"}
|
package/dist/router/index.js
CHANGED
|
@@ -28,15 +28,17 @@ var import_valyrian = require("valyrian.js");
|
|
|
28
28
|
function flat(array) {
|
|
29
29
|
return Array.isArray(array) ? array.flat(Infinity) : [array];
|
|
30
30
|
}
|
|
31
|
-
var addPath = (
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
var addPath = ({
|
|
32
|
+
router,
|
|
33
|
+
method,
|
|
34
|
+
path,
|
|
35
|
+
middlewares
|
|
36
|
+
}) => {
|
|
37
|
+
if (!method || !path || !Array.isArray(middlewares) || middlewares.length === 0) {
|
|
38
|
+
throw new Error(`Invalid route input: ${method} ${path} ${middlewares}`);
|
|
34
39
|
}
|
|
35
40
|
let realpath = path.replace(/(\S)(\/+)$/, "$1");
|
|
36
|
-
let params = realpath.match(/:(\w+)?/gi) || [];
|
|
37
|
-
for (let param in params) {
|
|
38
|
-
params[param] = params[param].slice(1);
|
|
39
|
-
}
|
|
41
|
+
let params = (realpath.match(/:(\w+)?/gi) || []).map((param) => param.slice(1));
|
|
40
42
|
let regexpPath = "^" + realpath.replace(/:(\w+)/gi, "([^\\/\\s]+)") + "$";
|
|
41
43
|
router.paths.push({
|
|
42
44
|
method,
|
|
@@ -47,41 +49,27 @@ var addPath = (router, method, path, middlewares) => {
|
|
|
47
49
|
});
|
|
48
50
|
};
|
|
49
51
|
function parseQuery(queryParts) {
|
|
50
|
-
let parts = queryParts ? queryParts.split("&"
|
|
52
|
+
let parts = queryParts ? queryParts.split("&") : [];
|
|
51
53
|
let query = {};
|
|
52
|
-
let
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
nameValue = parts[i].split("=", 2);
|
|
56
|
-
query[nameValue[0]] = nameValue[1];
|
|
54
|
+
for (let nameValue of parts) {
|
|
55
|
+
let [name, value] = nameValue.split("=", 2);
|
|
56
|
+
query[name] = value || "";
|
|
57
57
|
}
|
|
58
58
|
return query;
|
|
59
59
|
}
|
|
60
60
|
function searchMiddlewares(router, path) {
|
|
61
|
-
let i;
|
|
62
|
-
let k;
|
|
63
|
-
let item;
|
|
64
|
-
let match;
|
|
65
|
-
let key;
|
|
66
61
|
let middlewares = [];
|
|
67
62
|
let params = {};
|
|
68
63
|
let matches = [];
|
|
69
|
-
router.
|
|
70
|
-
|
|
71
|
-
router.matches = [];
|
|
72
|
-
for (i = 0; i < router.paths.length; i++) {
|
|
73
|
-
item = router.paths[i];
|
|
74
|
-
match = item.regexp.exec(path);
|
|
64
|
+
for (let item of router.paths) {
|
|
65
|
+
let match = item.regexp.exec(path);
|
|
75
66
|
if (Array.isArray(match)) {
|
|
76
67
|
middlewares.push(...item.middlewares);
|
|
77
68
|
match.shift();
|
|
78
|
-
for (
|
|
79
|
-
key =
|
|
80
|
-
params[key] = match.shift();
|
|
81
|
-
}
|
|
82
|
-
while (match.length) {
|
|
83
|
-
matches.push(match.shift());
|
|
69
|
+
for (let [index, key] of item.params.entries()) {
|
|
70
|
+
params[key] = match[index];
|
|
84
71
|
}
|
|
72
|
+
matches.push(...match);
|
|
85
73
|
if (item.method === "add") {
|
|
86
74
|
router.path = item.path;
|
|
87
75
|
break;
|
|
@@ -93,8 +81,7 @@ function searchMiddlewares(router, path) {
|
|
|
93
81
|
return middlewares;
|
|
94
82
|
}
|
|
95
83
|
async function searchComponent(router, middlewares) {
|
|
96
|
-
|
|
97
|
-
let req = {
|
|
84
|
+
const request = {
|
|
98
85
|
params: router.params,
|
|
99
86
|
query: router.query,
|
|
100
87
|
url: router.url,
|
|
@@ -105,9 +92,9 @@ async function searchComponent(router, middlewares) {
|
|
|
105
92
|
return false;
|
|
106
93
|
}
|
|
107
94
|
};
|
|
108
|
-
let
|
|
109
|
-
for (
|
|
110
|
-
response = await
|
|
95
|
+
let response;
|
|
96
|
+
for (const middleware of middlewares) {
|
|
97
|
+
response = await middleware(request, response);
|
|
111
98
|
if (response !== void 0 && ((0, import_valyrian.isComponent)(response) || (0, import_valyrian.isVnodeComponent)(response))) {
|
|
112
99
|
return response;
|
|
113
100
|
}
|
|
@@ -125,59 +112,56 @@ var Router = class {
|
|
|
125
112
|
path = "";
|
|
126
113
|
params = {};
|
|
127
114
|
matches = [];
|
|
128
|
-
|
|
129
|
-
|
|
115
|
+
pathPrefix = "";
|
|
116
|
+
constructor(pathPrefix = "") {
|
|
117
|
+
this.pathPrefix = pathPrefix;
|
|
118
|
+
}
|
|
119
|
+
add(path, ...middlewares) {
|
|
120
|
+
addPath({ router: this, method: "add", path: `${this.pathPrefix}${path}`, middlewares });
|
|
130
121
|
return this;
|
|
131
122
|
}
|
|
132
|
-
use(...
|
|
133
|
-
let path = typeof
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
for (k = 0; k < subrouter.paths.length; k++) {
|
|
145
|
-
item = subrouter.paths[k];
|
|
146
|
-
subpath = `${path}${item.path}`.replace(/^\/\//, "/");
|
|
147
|
-
addPath(this, item.method, subpath, item.middlewares);
|
|
123
|
+
use(...middlewares) {
|
|
124
|
+
let path = `${this.pathPrefix}${typeof middlewares[0] === "string" ? middlewares.shift() : "/"}`;
|
|
125
|
+
for (const item of middlewares) {
|
|
126
|
+
if (item instanceof Router) {
|
|
127
|
+
const subrouter = item;
|
|
128
|
+
for (const subpath of subrouter.paths) {
|
|
129
|
+
addPath({
|
|
130
|
+
router: this,
|
|
131
|
+
method: subpath.method,
|
|
132
|
+
path: `${path}${subpath.path}`.replace(/^\/\//, "/"),
|
|
133
|
+
middlewares: subpath.middlewares
|
|
134
|
+
});
|
|
148
135
|
}
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
if (typeof item === "function") {
|
|
139
|
+
addPath({ router: this, method: "use", path: `${path}.*`, middlewares: [item] });
|
|
149
140
|
}
|
|
150
141
|
}
|
|
151
142
|
return this;
|
|
152
143
|
}
|
|
153
144
|
routes() {
|
|
154
|
-
|
|
155
|
-
this.paths.forEach((path) => {
|
|
156
|
-
if (path.method === "add") {
|
|
157
|
-
routes.push(path.path);
|
|
158
|
-
}
|
|
159
|
-
});
|
|
160
|
-
return routes;
|
|
145
|
+
return this.paths.filter((path) => path.method === "add").map((path) => path.path);
|
|
161
146
|
}
|
|
162
|
-
async go(path, parentComponent) {
|
|
147
|
+
async go(path, parentComponent, preventPushState = false) {
|
|
163
148
|
if (!path) {
|
|
164
149
|
throw new Error("router.url.required");
|
|
165
150
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
this.
|
|
170
|
-
|
|
171
|
-
let middlewares = searchMiddlewares(this, urlParts);
|
|
151
|
+
const constructedPath = `${this.pathPrefix}${path}`;
|
|
152
|
+
const parts = constructedPath.split("?", 2);
|
|
153
|
+
this.url = constructedPath;
|
|
154
|
+
this.query = parseQuery(parts[1]);
|
|
155
|
+
const middlewares = searchMiddlewares(this, parts[0].replace(/(.+)\/$/, "$1"));
|
|
172
156
|
let component = await searchComponent(this, middlewares);
|
|
173
157
|
if (component === false) {
|
|
174
158
|
return;
|
|
175
159
|
}
|
|
176
160
|
if (!component) {
|
|
177
|
-
throw new Error(`The url ${
|
|
161
|
+
throw new Error(`The url ${constructedPath} requested wasn't found`);
|
|
178
162
|
}
|
|
179
163
|
if ((0, import_valyrian.isComponent)(parentComponent) || (0, import_valyrian.isVnodeComponent)(parentComponent)) {
|
|
180
|
-
|
|
164
|
+
const childComponent = (0, import_valyrian.isVnodeComponent)(component) ? component : (0, import_valyrian.v)(component, {});
|
|
181
165
|
if ((0, import_valyrian.isVnodeComponent)(parentComponent)) {
|
|
182
166
|
parentComponent.children.push(childComponent);
|
|
183
167
|
component = parentComponent;
|
|
@@ -185,8 +169,8 @@ var Router = class {
|
|
|
185
169
|
component = (0, import_valyrian.v)(parentComponent, {}, childComponent);
|
|
186
170
|
}
|
|
187
171
|
}
|
|
188
|
-
if (!import_valyrian.isNodeJs) {
|
|
189
|
-
window.history.pushState(null, "",
|
|
172
|
+
if (!import_valyrian.isNodeJs && !preventPushState) {
|
|
173
|
+
window.history.pushState(null, "", constructedPath);
|
|
190
174
|
}
|
|
191
175
|
if (this.container) {
|
|
192
176
|
return (0, import_valyrian.mount)(this.container, component);
|
|
@@ -202,18 +186,19 @@ var Router = class {
|
|
|
202
186
|
}
|
|
203
187
|
};
|
|
204
188
|
var localRedirect;
|
|
205
|
-
function redirect(url) {
|
|
189
|
+
function redirect(url, parentComponent, preventPushState = false) {
|
|
206
190
|
if (!localRedirect) {
|
|
207
191
|
throw new Error("router.redirect.not.found");
|
|
208
192
|
}
|
|
209
|
-
return localRedirect(url);
|
|
193
|
+
return localRedirect(url, parentComponent, preventPushState);
|
|
210
194
|
}
|
|
211
195
|
function mountRouter(elementContainer, router) {
|
|
212
196
|
router.container = elementContainer;
|
|
213
197
|
localRedirect = router.go.bind(router);
|
|
214
198
|
if (!import_valyrian.isNodeJs) {
|
|
215
199
|
let onPopStateGoToRoute = function() {
|
|
216
|
-
|
|
200
|
+
let pathWithoutPrefix = document.location.pathname.replace(router.pathPrefix, "");
|
|
201
|
+
router.go(pathWithoutPrefix, void 0, true);
|
|
217
202
|
};
|
|
218
203
|
window.addEventListener("popstate", onPopStateGoToRoute, false);
|
|
219
204
|
onPopStateGoToRoute();
|
package/dist/router/index.mjs
CHANGED
|
@@ -11,15 +11,17 @@ import {
|
|
|
11
11
|
function flat(array) {
|
|
12
12
|
return Array.isArray(array) ? array.flat(Infinity) : [array];
|
|
13
13
|
}
|
|
14
|
-
var addPath = (
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
var addPath = ({
|
|
15
|
+
router,
|
|
16
|
+
method,
|
|
17
|
+
path,
|
|
18
|
+
middlewares
|
|
19
|
+
}) => {
|
|
20
|
+
if (!method || !path || !Array.isArray(middlewares) || middlewares.length === 0) {
|
|
21
|
+
throw new Error(`Invalid route input: ${method} ${path} ${middlewares}`);
|
|
17
22
|
}
|
|
18
23
|
let realpath = path.replace(/(\S)(\/+)$/, "$1");
|
|
19
|
-
let params = realpath.match(/:(\w+)?/gi) || [];
|
|
20
|
-
for (let param in params) {
|
|
21
|
-
params[param] = params[param].slice(1);
|
|
22
|
-
}
|
|
24
|
+
let params = (realpath.match(/:(\w+)?/gi) || []).map((param) => param.slice(1));
|
|
23
25
|
let regexpPath = "^" + realpath.replace(/:(\w+)/gi, "([^\\/\\s]+)") + "$";
|
|
24
26
|
router.paths.push({
|
|
25
27
|
method,
|
|
@@ -30,41 +32,27 @@ var addPath = (router, method, path, middlewares) => {
|
|
|
30
32
|
});
|
|
31
33
|
};
|
|
32
34
|
function parseQuery(queryParts) {
|
|
33
|
-
let parts = queryParts ? queryParts.split("&"
|
|
35
|
+
let parts = queryParts ? queryParts.split("&") : [];
|
|
34
36
|
let query = {};
|
|
35
|
-
let
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
nameValue = parts[i].split("=", 2);
|
|
39
|
-
query[nameValue[0]] = nameValue[1];
|
|
37
|
+
for (let nameValue of parts) {
|
|
38
|
+
let [name, value] = nameValue.split("=", 2);
|
|
39
|
+
query[name] = value || "";
|
|
40
40
|
}
|
|
41
41
|
return query;
|
|
42
42
|
}
|
|
43
43
|
function searchMiddlewares(router, path) {
|
|
44
|
-
let i;
|
|
45
|
-
let k;
|
|
46
|
-
let item;
|
|
47
|
-
let match;
|
|
48
|
-
let key;
|
|
49
44
|
let middlewares = [];
|
|
50
45
|
let params = {};
|
|
51
46
|
let matches = [];
|
|
52
|
-
router.
|
|
53
|
-
|
|
54
|
-
router.matches = [];
|
|
55
|
-
for (i = 0; i < router.paths.length; i++) {
|
|
56
|
-
item = router.paths[i];
|
|
57
|
-
match = item.regexp.exec(path);
|
|
47
|
+
for (let item of router.paths) {
|
|
48
|
+
let match = item.regexp.exec(path);
|
|
58
49
|
if (Array.isArray(match)) {
|
|
59
50
|
middlewares.push(...item.middlewares);
|
|
60
51
|
match.shift();
|
|
61
|
-
for (
|
|
62
|
-
key =
|
|
63
|
-
params[key] = match.shift();
|
|
64
|
-
}
|
|
65
|
-
while (match.length) {
|
|
66
|
-
matches.push(match.shift());
|
|
52
|
+
for (let [index, key] of item.params.entries()) {
|
|
53
|
+
params[key] = match[index];
|
|
67
54
|
}
|
|
55
|
+
matches.push(...match);
|
|
68
56
|
if (item.method === "add") {
|
|
69
57
|
router.path = item.path;
|
|
70
58
|
break;
|
|
@@ -76,8 +64,7 @@ function searchMiddlewares(router, path) {
|
|
|
76
64
|
return middlewares;
|
|
77
65
|
}
|
|
78
66
|
async function searchComponent(router, middlewares) {
|
|
79
|
-
|
|
80
|
-
let req = {
|
|
67
|
+
const request = {
|
|
81
68
|
params: router.params,
|
|
82
69
|
query: router.query,
|
|
83
70
|
url: router.url,
|
|
@@ -88,9 +75,9 @@ async function searchComponent(router, middlewares) {
|
|
|
88
75
|
return false;
|
|
89
76
|
}
|
|
90
77
|
};
|
|
91
|
-
let
|
|
92
|
-
for (
|
|
93
|
-
response = await
|
|
78
|
+
let response;
|
|
79
|
+
for (const middleware of middlewares) {
|
|
80
|
+
response = await middleware(request, response);
|
|
94
81
|
if (response !== void 0 && (isComponent(response) || isVnodeComponent(response))) {
|
|
95
82
|
return response;
|
|
96
83
|
}
|
|
@@ -108,59 +95,56 @@ var Router = class {
|
|
|
108
95
|
path = "";
|
|
109
96
|
params = {};
|
|
110
97
|
matches = [];
|
|
111
|
-
|
|
112
|
-
|
|
98
|
+
pathPrefix = "";
|
|
99
|
+
constructor(pathPrefix = "") {
|
|
100
|
+
this.pathPrefix = pathPrefix;
|
|
101
|
+
}
|
|
102
|
+
add(path, ...middlewares) {
|
|
103
|
+
addPath({ router: this, method: "add", path: `${this.pathPrefix}${path}`, middlewares });
|
|
113
104
|
return this;
|
|
114
105
|
}
|
|
115
|
-
use(...
|
|
116
|
-
let path = typeof
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
for (k = 0; k < subrouter.paths.length; k++) {
|
|
128
|
-
item = subrouter.paths[k];
|
|
129
|
-
subpath = `${path}${item.path}`.replace(/^\/\//, "/");
|
|
130
|
-
addPath(this, item.method, subpath, item.middlewares);
|
|
106
|
+
use(...middlewares) {
|
|
107
|
+
let path = `${this.pathPrefix}${typeof middlewares[0] === "string" ? middlewares.shift() : "/"}`;
|
|
108
|
+
for (const item of middlewares) {
|
|
109
|
+
if (item instanceof Router) {
|
|
110
|
+
const subrouter = item;
|
|
111
|
+
for (const subpath of subrouter.paths) {
|
|
112
|
+
addPath({
|
|
113
|
+
router: this,
|
|
114
|
+
method: subpath.method,
|
|
115
|
+
path: `${path}${subpath.path}`.replace(/^\/\//, "/"),
|
|
116
|
+
middlewares: subpath.middlewares
|
|
117
|
+
});
|
|
131
118
|
}
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
if (typeof item === "function") {
|
|
122
|
+
addPath({ router: this, method: "use", path: `${path}.*`, middlewares: [item] });
|
|
132
123
|
}
|
|
133
124
|
}
|
|
134
125
|
return this;
|
|
135
126
|
}
|
|
136
127
|
routes() {
|
|
137
|
-
|
|
138
|
-
this.paths.forEach((path) => {
|
|
139
|
-
if (path.method === "add") {
|
|
140
|
-
routes.push(path.path);
|
|
141
|
-
}
|
|
142
|
-
});
|
|
143
|
-
return routes;
|
|
128
|
+
return this.paths.filter((path) => path.method === "add").map((path) => path.path);
|
|
144
129
|
}
|
|
145
|
-
async go(path, parentComponent) {
|
|
130
|
+
async go(path, parentComponent, preventPushState = false) {
|
|
146
131
|
if (!path) {
|
|
147
132
|
throw new Error("router.url.required");
|
|
148
133
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
this.
|
|
153
|
-
|
|
154
|
-
let middlewares = searchMiddlewares(this, urlParts);
|
|
134
|
+
const constructedPath = `${this.pathPrefix}${path}`;
|
|
135
|
+
const parts = constructedPath.split("?", 2);
|
|
136
|
+
this.url = constructedPath;
|
|
137
|
+
this.query = parseQuery(parts[1]);
|
|
138
|
+
const middlewares = searchMiddlewares(this, parts[0].replace(/(.+)\/$/, "$1"));
|
|
155
139
|
let component = await searchComponent(this, middlewares);
|
|
156
140
|
if (component === false) {
|
|
157
141
|
return;
|
|
158
142
|
}
|
|
159
143
|
if (!component) {
|
|
160
|
-
throw new Error(`The url ${
|
|
144
|
+
throw new Error(`The url ${constructedPath} requested wasn't found`);
|
|
161
145
|
}
|
|
162
146
|
if (isComponent(parentComponent) || isVnodeComponent(parentComponent)) {
|
|
163
|
-
|
|
147
|
+
const childComponent = isVnodeComponent(component) ? component : v(component, {});
|
|
164
148
|
if (isVnodeComponent(parentComponent)) {
|
|
165
149
|
parentComponent.children.push(childComponent);
|
|
166
150
|
component = parentComponent;
|
|
@@ -168,8 +152,8 @@ var Router = class {
|
|
|
168
152
|
component = v(parentComponent, {}, childComponent);
|
|
169
153
|
}
|
|
170
154
|
}
|
|
171
|
-
if (!isNodeJs) {
|
|
172
|
-
window.history.pushState(null, "",
|
|
155
|
+
if (!isNodeJs && !preventPushState) {
|
|
156
|
+
window.history.pushState(null, "", constructedPath);
|
|
173
157
|
}
|
|
174
158
|
if (this.container) {
|
|
175
159
|
return mount(this.container, component);
|
|
@@ -185,18 +169,19 @@ var Router = class {
|
|
|
185
169
|
}
|
|
186
170
|
};
|
|
187
171
|
var localRedirect;
|
|
188
|
-
function redirect(url) {
|
|
172
|
+
function redirect(url, parentComponent, preventPushState = false) {
|
|
189
173
|
if (!localRedirect) {
|
|
190
174
|
throw new Error("router.redirect.not.found");
|
|
191
175
|
}
|
|
192
|
-
return localRedirect(url);
|
|
176
|
+
return localRedirect(url, parentComponent, preventPushState);
|
|
193
177
|
}
|
|
194
178
|
function mountRouter(elementContainer, router) {
|
|
195
179
|
router.container = elementContainer;
|
|
196
180
|
localRedirect = router.go.bind(router);
|
|
197
181
|
if (!isNodeJs) {
|
|
198
182
|
let onPopStateGoToRoute = function() {
|
|
199
|
-
|
|
183
|
+
let pathWithoutPrefix = document.location.pathname.replace(router.pathPrefix, "");
|
|
184
|
+
router.go(pathWithoutPrefix, void 0, true);
|
|
200
185
|
};
|
|
201
186
|
window.addEventListener("popstate", onPopStateGoToRoute, false);
|
|
202
187
|
onPopStateGoToRoute();
|
package/lib/router/index.ts
CHANGED
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
Component,
|
|
4
4
|
POJOComponent,
|
|
5
5
|
VnodeComponentInterface,
|
|
6
|
+
VnodeWithDom,
|
|
6
7
|
directive,
|
|
7
8
|
isComponent,
|
|
8
9
|
isNodeJs,
|
|
@@ -12,14 +13,6 @@ import {
|
|
|
12
13
|
v
|
|
13
14
|
} from "valyrian.js";
|
|
14
15
|
|
|
15
|
-
interface Path {
|
|
16
|
-
method: string;
|
|
17
|
-
path: string;
|
|
18
|
-
middlewares: Middlewares;
|
|
19
|
-
params: string[];
|
|
20
|
-
regexp: RegExp;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
16
|
interface Request {
|
|
24
17
|
params: Record<string, any>;
|
|
25
18
|
query: Record<string, any>;
|
|
@@ -42,6 +35,14 @@ interface Middleware {
|
|
|
42
35
|
|
|
43
36
|
interface Middlewares extends Array<Middleware> {}
|
|
44
37
|
|
|
38
|
+
interface Path {
|
|
39
|
+
method: string;
|
|
40
|
+
path: string;
|
|
41
|
+
middlewares: Middlewares;
|
|
42
|
+
params: string[];
|
|
43
|
+
regexp: RegExp;
|
|
44
|
+
}
|
|
45
|
+
|
|
45
46
|
interface RouterInterface {
|
|
46
47
|
paths: Path[];
|
|
47
48
|
container: Element | string | null;
|
|
@@ -61,25 +62,39 @@ interface RouterInterface {
|
|
|
61
62
|
go(path: string, parentComponent?: Component | POJOComponent | VnodeComponentInterface): Promise<string | void>;
|
|
62
63
|
}
|
|
63
64
|
|
|
65
|
+
interface RedirectFunction {
|
|
66
|
+
// eslint-disable-next-line no-unused-vars
|
|
67
|
+
(url: string, parentComponent?: Component, preventPushState?: boolean): string | void;
|
|
68
|
+
}
|
|
69
|
+
|
|
64
70
|
function flat(array: any) {
|
|
65
71
|
return Array.isArray(array) ? array.flat(Infinity) : [array];
|
|
66
72
|
}
|
|
67
73
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
74
|
+
const addPath = ({
|
|
75
|
+
router,
|
|
76
|
+
method,
|
|
77
|
+
path,
|
|
78
|
+
middlewares
|
|
79
|
+
}: {
|
|
80
|
+
router: Router;
|
|
81
|
+
method: string;
|
|
82
|
+
path: string;
|
|
83
|
+
middlewares: Middleware[];
|
|
84
|
+
}): void => {
|
|
85
|
+
if (!method || !path || !Array.isArray(middlewares) || middlewares.length === 0) {
|
|
86
|
+
throw new Error(`Invalid route input: ${method} ${path} ${middlewares}`);
|
|
71
87
|
}
|
|
72
88
|
|
|
89
|
+
// Trim trailing slashes from the path
|
|
73
90
|
let realpath = path.replace(/(\S)(\/+)$/, "$1");
|
|
74
91
|
|
|
75
|
-
// Find the express
|
|
76
|
-
let params = realpath.match(/:(\w+)?/gi) || []
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
for (let param in params) {
|
|
80
|
-
params[param] = params[param].slice(1);
|
|
81
|
-
}
|
|
92
|
+
// Find the express-like params in the path
|
|
93
|
+
let params = (realpath.match(/:(\w+)?/gi) || [])
|
|
94
|
+
// Set the names of the params found
|
|
95
|
+
.map((param) => param.slice(1));
|
|
82
96
|
|
|
97
|
+
// Generate a regular expression to match the path
|
|
83
98
|
let regexpPath = "^" + realpath.replace(/:(\w+)/gi, "([^\\/\\s]+)") + "$";
|
|
84
99
|
|
|
85
100
|
router.paths.push({
|
|
@@ -91,52 +106,43 @@ let addPath = (router: Router, method: string, path: string, middlewares: any[])
|
|
|
91
106
|
});
|
|
92
107
|
};
|
|
93
108
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
let
|
|
98
|
-
let
|
|
109
|
+
// Parse a query string into an object
|
|
110
|
+
function parseQuery(queryParts?: string): Record<string, string> {
|
|
111
|
+
// Split the query string into an array of name-value pairs
|
|
112
|
+
let parts = queryParts ? queryParts.split("&") : [];
|
|
113
|
+
let query: Record<string, string> = {};
|
|
99
114
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
115
|
+
// Iterate over the name-value pairs and add them to the query object
|
|
116
|
+
for (let nameValue of parts) {
|
|
117
|
+
let [name, value] = nameValue.split("=", 2);
|
|
118
|
+
query[name] = value || "";
|
|
103
119
|
}
|
|
104
120
|
|
|
105
121
|
return query;
|
|
106
122
|
}
|
|
107
123
|
|
|
124
|
+
// Search for middlewares that match a given path
|
|
108
125
|
function searchMiddlewares(router: RouterInterface, path: string): Middlewares {
|
|
109
|
-
let i;
|
|
110
|
-
let k;
|
|
111
|
-
let item;
|
|
112
|
-
let match;
|
|
113
|
-
let key;
|
|
114
126
|
let middlewares: Middlewares = [];
|
|
115
127
|
let params: Record<string, any> = {};
|
|
116
128
|
let matches = [];
|
|
117
|
-
router.params = {};
|
|
118
|
-
router.path = "";
|
|
119
|
-
router.matches = [];
|
|
120
129
|
|
|
121
130
|
// Search for middlewares
|
|
122
|
-
for (
|
|
123
|
-
|
|
131
|
+
for (let item of router.paths) {
|
|
132
|
+
let match = item.regexp.exec(path);
|
|
124
133
|
|
|
125
|
-
match = item.regexp.exec(path);
|
|
126
134
|
// If we found middlewares
|
|
127
135
|
if (Array.isArray(match)) {
|
|
128
136
|
middlewares.push(...item.middlewares);
|
|
129
137
|
match.shift();
|
|
130
138
|
|
|
131
139
|
// Parse params
|
|
132
|
-
for (
|
|
133
|
-
key =
|
|
134
|
-
params[key] = match.shift();
|
|
140
|
+
for (let [index, key] of item.params.entries()) {
|
|
141
|
+
params[key] = match[index];
|
|
135
142
|
}
|
|
136
143
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
}
|
|
144
|
+
// Add remaining matches to the array
|
|
145
|
+
matches.push(...match);
|
|
140
146
|
|
|
141
147
|
if (item.method === "add") {
|
|
142
148
|
router.path = item.path;
|
|
@@ -155,8 +161,8 @@ async function searchComponent(
|
|
|
155
161
|
router: RouterInterface,
|
|
156
162
|
middlewares: Middlewares
|
|
157
163
|
): Promise<Component | VnodeComponentInterface | false | void> {
|
|
158
|
-
|
|
159
|
-
|
|
164
|
+
// Define request object with default values
|
|
165
|
+
const request: Request = {
|
|
160
166
|
params: router.params,
|
|
161
167
|
query: router.query,
|
|
162
168
|
url: router.url,
|
|
@@ -164,18 +170,25 @@ async function searchComponent(
|
|
|
164
170
|
matches: router.matches,
|
|
165
171
|
redirect: (path: string, parentComponent?: Component) => {
|
|
166
172
|
router.go(path, parentComponent);
|
|
173
|
+
// Return false to stop the middleware chain
|
|
167
174
|
return false;
|
|
168
175
|
}
|
|
169
176
|
};
|
|
170
|
-
let i = 0;
|
|
171
177
|
|
|
172
|
-
|
|
173
|
-
|
|
178
|
+
// Initialize response variable
|
|
179
|
+
let response;
|
|
174
180
|
|
|
181
|
+
// Iterate through middlewares
|
|
182
|
+
for (const middleware of middlewares) {
|
|
183
|
+
// Invoke middleware and update response
|
|
184
|
+
response = await middleware(request, response);
|
|
185
|
+
|
|
186
|
+
// Return response if it's a valid component
|
|
175
187
|
if (response !== undefined && (isComponent(response) || isVnodeComponent(response))) {
|
|
176
188
|
return response;
|
|
177
189
|
}
|
|
178
190
|
|
|
191
|
+
// Return false if response is explicitly false to stop the middleware chain
|
|
179
192
|
if (response === false) {
|
|
180
193
|
return false;
|
|
181
194
|
}
|
|
@@ -191,59 +204,57 @@ export class Router implements RouterInterface {
|
|
|
191
204
|
path: string = "";
|
|
192
205
|
params: Record<string, string | number | any> = {};
|
|
193
206
|
matches: string[] = [];
|
|
207
|
+
pathPrefix: string = "";
|
|
208
|
+
|
|
209
|
+
constructor(pathPrefix: string = "") {
|
|
210
|
+
this.pathPrefix = pathPrefix;
|
|
211
|
+
}
|
|
194
212
|
|
|
195
|
-
add(path: string, ...
|
|
196
|
-
addPath(this, "add", path
|
|
213
|
+
add(path: string, ...middlewares: Middlewares): Router {
|
|
214
|
+
addPath({ router: this, method: "add", path: `${this.pathPrefix}${path}`, middlewares });
|
|
197
215
|
return this;
|
|
198
216
|
}
|
|
199
217
|
|
|
200
|
-
use(...
|
|
201
|
-
let path = typeof
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
for (k = 0; k < subrouter.paths.length; k++) {
|
|
214
|
-
item = subrouter.paths[k];
|
|
215
|
-
subpath = `${path}${item.path}`.replace(/^\/\//, "/");
|
|
216
|
-
addPath(this, item.method, subpath, item.middlewares);
|
|
218
|
+
use(...middlewares: Middlewares | Router[] | string[]): Router {
|
|
219
|
+
let path = `${this.pathPrefix}${typeof middlewares[0] === "string" ? middlewares.shift() : "/"}`;
|
|
220
|
+
|
|
221
|
+
for (const item of middlewares) {
|
|
222
|
+
if (item instanceof Router) {
|
|
223
|
+
const subrouter = item as Router;
|
|
224
|
+
for (const subpath of subrouter.paths) {
|
|
225
|
+
addPath({
|
|
226
|
+
router: this,
|
|
227
|
+
method: subpath.method,
|
|
228
|
+
path: `${path}${subpath.path}`.replace(/^\/\//, "/"),
|
|
229
|
+
middlewares: subpath.middlewares
|
|
230
|
+
});
|
|
217
231
|
}
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (typeof item === "function") {
|
|
236
|
+
addPath({ router: this, method: "use", path: `${path}.*`, middlewares: [item as Middleware] });
|
|
218
237
|
}
|
|
219
238
|
}
|
|
220
239
|
|
|
221
240
|
return this;
|
|
222
241
|
}
|
|
223
242
|
|
|
224
|
-
routes() {
|
|
225
|
-
|
|
226
|
-
this.paths.forEach((path) => {
|
|
227
|
-
if (path.method === "add") {
|
|
228
|
-
routes.push(path.path);
|
|
229
|
-
}
|
|
230
|
-
});
|
|
231
|
-
return routes;
|
|
243
|
+
routes(): string[] {
|
|
244
|
+
return this.paths.filter((path) => path.method === "add").map((path) => path.path);
|
|
232
245
|
}
|
|
233
246
|
|
|
234
|
-
async go(path: string, parentComponent?: Component): Promise<string | void> {
|
|
247
|
+
async go(path: string, parentComponent?: Component, preventPushState = false): Promise<string | void> {
|
|
235
248
|
if (!path) {
|
|
236
249
|
throw new Error("router.url.required");
|
|
237
250
|
}
|
|
238
251
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
this.
|
|
243
|
-
this.query = parseQuery(queryParts);
|
|
244
|
-
|
|
245
|
-
let middlewares = searchMiddlewares(this as RouterInterface, urlParts);
|
|
252
|
+
const constructedPath = `${this.pathPrefix}${path}`;
|
|
253
|
+
const parts = constructedPath.split("?", 2);
|
|
254
|
+
this.url = constructedPath;
|
|
255
|
+
this.query = parseQuery(parts[1]);
|
|
246
256
|
|
|
257
|
+
const middlewares = searchMiddlewares(this as RouterInterface, parts[0].replace(/(.+)\/$/, "$1"));
|
|
247
258
|
let component = await searchComponent(this as RouterInterface, middlewares);
|
|
248
259
|
|
|
249
260
|
if (component === false) {
|
|
@@ -251,11 +262,11 @@ export class Router implements RouterInterface {
|
|
|
251
262
|
}
|
|
252
263
|
|
|
253
264
|
if (!component) {
|
|
254
|
-
throw new Error(`The url ${
|
|
265
|
+
throw new Error(`The url ${constructedPath} requested wasn't found`);
|
|
255
266
|
}
|
|
256
267
|
|
|
257
268
|
if (isComponent(parentComponent) || isVnodeComponent(parentComponent)) {
|
|
258
|
-
|
|
269
|
+
const childComponent = isVnodeComponent(component) ? component : v(component as Component, {});
|
|
259
270
|
if (isVnodeComponent(parentComponent)) {
|
|
260
271
|
parentComponent.children.push(childComponent);
|
|
261
272
|
component = parentComponent;
|
|
@@ -264,8 +275,8 @@ export class Router implements RouterInterface {
|
|
|
264
275
|
}
|
|
265
276
|
}
|
|
266
277
|
|
|
267
|
-
if (!isNodeJs) {
|
|
268
|
-
window.history.pushState(null, "",
|
|
278
|
+
if (!isNodeJs && !preventPushState) {
|
|
279
|
+
window.history.pushState(null, "", constructedPath);
|
|
269
280
|
}
|
|
270
281
|
|
|
271
282
|
if (this.container) {
|
|
@@ -283,28 +294,29 @@ export class Router implements RouterInterface {
|
|
|
283
294
|
}
|
|
284
295
|
}
|
|
285
296
|
|
|
286
|
-
let localRedirect;
|
|
287
|
-
|
|
297
|
+
let localRedirect: RedirectFunction;
|
|
298
|
+
|
|
299
|
+
export function redirect(url: string, parentComponent?: Component, preventPushState = false): string | void {
|
|
288
300
|
if (!localRedirect) {
|
|
289
301
|
throw new Error("router.redirect.not.found");
|
|
290
302
|
}
|
|
291
|
-
return localRedirect(url);
|
|
303
|
+
return localRedirect(url, parentComponent, preventPushState);
|
|
292
304
|
}
|
|
293
305
|
|
|
294
|
-
export function mountRouter(elementContainer, router) {
|
|
306
|
+
export function mountRouter(elementContainer: string | any, router: Router): void {
|
|
295
307
|
router.container = elementContainer;
|
|
296
308
|
localRedirect = router.go.bind(router);
|
|
297
309
|
|
|
298
|
-
// Activate the use of the router
|
|
299
310
|
if (!isNodeJs) {
|
|
300
|
-
function onPopStateGoToRoute() {
|
|
301
|
-
|
|
311
|
+
function onPopStateGoToRoute(): void {
|
|
312
|
+
let pathWithoutPrefix = document.location.pathname.replace(router.pathPrefix, "");
|
|
313
|
+
(router as unknown as Router).go(pathWithoutPrefix, undefined, true);
|
|
302
314
|
}
|
|
303
315
|
window.addEventListener("popstate", onPopStateGoToRoute, false);
|
|
304
316
|
onPopStateGoToRoute();
|
|
305
317
|
}
|
|
306
318
|
|
|
307
|
-
directive("route", (url, vnode, oldnode) => {
|
|
319
|
+
directive("route", (url: string, vnode: VnodeWithDom, oldnode?: VnodeWithDom): void => {
|
|
308
320
|
setAttribute("href", url, vnode, oldnode);
|
|
309
321
|
setAttribute("onclick", router.getOnClickHandler(url), vnode, oldnode);
|
|
310
322
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "valyrian.js",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.1.1",
|
|
4
4
|
"description": "Lightweight steel to forge PWAs. (Minimal Frontend Framework with server side rendering and other capabilities)",
|
|
5
5
|
"repository": "git@github.com:Masquerade-Circus/valyrian.js.git",
|
|
6
6
|
"author": "Masquerade <christian@masquerade-circus.net>",
|