@kcrwfrd/trouter 0.1.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/trouter.js +528 -0
- package/dist/trouter.js.map +1 -0
- package/dist/trouter.umd.js +2 -0
- package/dist/trouter.umd.js.map +1 -0
- package/package.json +33 -0
package/dist/trouter.js
ADDED
|
@@ -0,0 +1,528 @@
|
|
|
1
|
+
const P = (n) => n !== null && typeof n == "object", d = (n) => typeof n == "string";
|
|
2
|
+
class w {
|
|
3
|
+
/**
|
|
4
|
+
* @param {Router} router
|
|
5
|
+
* @param {Route} current
|
|
6
|
+
*/
|
|
7
|
+
constructor(t, e) {
|
|
8
|
+
this.router = t, this.params = {}, this.route = null, this.put(e);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* @method put
|
|
12
|
+
* @description
|
|
13
|
+
* Updates current route.
|
|
14
|
+
*
|
|
15
|
+
* @param {Route} route
|
|
16
|
+
* @param {Object} [params]
|
|
17
|
+
*/
|
|
18
|
+
put(t, e = {}) {
|
|
19
|
+
this.params = e, this.route = t;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* @method path
|
|
23
|
+
* @description
|
|
24
|
+
* Returns path to current route.
|
|
25
|
+
*
|
|
26
|
+
* @returns {Array.<Route>}
|
|
27
|
+
*/
|
|
28
|
+
path() {
|
|
29
|
+
return this.route.path;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* @method url
|
|
33
|
+
* @description
|
|
34
|
+
* Returns current URL
|
|
35
|
+
*
|
|
36
|
+
* @returns {String}
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* this.url()
|
|
40
|
+
* -> /#!/foo/1/bar
|
|
41
|
+
*/
|
|
42
|
+
url() {
|
|
43
|
+
return this.router.href(this.route, this.params);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
class g {
|
|
47
|
+
/**
|
|
48
|
+
* @constructor
|
|
49
|
+
* @description
|
|
50
|
+
* Takes a URL pattern with optional params denoted by ':'
|
|
51
|
+
*
|
|
52
|
+
* @param {String} urlPattern - e.g. /foo/:fooId/bar?bazId
|
|
53
|
+
*/
|
|
54
|
+
constructor(t) {
|
|
55
|
+
this.params = [], this.pathParams = [], this.queryParams = [], this.queryPatterns = [];
|
|
56
|
+
let e = "", [r, i] = t.split("?");
|
|
57
|
+
r === "/" && (e += "/");
|
|
58
|
+
for (let s of r.split("/")) {
|
|
59
|
+
if (s === "") continue;
|
|
60
|
+
if (s.startsWith(":")) {
|
|
61
|
+
let u = s.slice(1);
|
|
62
|
+
this.pathParams.push(u), e += "/([\\w-]+)";
|
|
63
|
+
} else
|
|
64
|
+
e += "/" + s;
|
|
65
|
+
}
|
|
66
|
+
if (i)
|
|
67
|
+
for (let s of i.split("&")) {
|
|
68
|
+
this.queryParams.push(s);
|
|
69
|
+
let o = `${s}=([\\w-.~:/?#[\\]@!$'"()*+,:%]+)`;
|
|
70
|
+
this.queryPatterns.push(new RegExp(o));
|
|
71
|
+
}
|
|
72
|
+
this.params = this.pathParams.concat(this.queryParams), this.pattern = new RegExp(`^${e}(?:\\?.*)?$`);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* @method exec
|
|
76
|
+
* @description
|
|
77
|
+
* Tests a path, providing route params if match found.
|
|
78
|
+
* Returns null if not a match.
|
|
79
|
+
*
|
|
80
|
+
* @param {String} path
|
|
81
|
+
*
|
|
82
|
+
* @returns {Object|null}
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* new UrlMatcher('/foo/:id').exec('/foo/1') -> { id: '1'}
|
|
86
|
+
*/
|
|
87
|
+
exec(t) {
|
|
88
|
+
let e = this.pattern.exec(t);
|
|
89
|
+
if (!e)
|
|
90
|
+
return null;
|
|
91
|
+
let r = {};
|
|
92
|
+
e = e.slice(1);
|
|
93
|
+
for (let [i, s] of this.pathParams.entries())
|
|
94
|
+
r[s] && console.warn(`Warning: duplicate param '${s}'`), r[s] = e[i];
|
|
95
|
+
for (let [i, s] of this.queryParams.entries()) {
|
|
96
|
+
r[s] && console.warn(`Warning: duplicate param '${s}'`);
|
|
97
|
+
let o = this.queryPatterns[i].exec(t);
|
|
98
|
+
r[s] = o && o[1] || null;
|
|
99
|
+
}
|
|
100
|
+
return r;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* @method getParams
|
|
104
|
+
* @static
|
|
105
|
+
* @description
|
|
106
|
+
* Extract param names from a URL pattern.
|
|
107
|
+
*
|
|
108
|
+
* @param {String} urlPattern
|
|
109
|
+
* @param {Function} [callback] - Optional
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* UrlMatcher.getParams('/foo/:fooId/bar/:barId')
|
|
113
|
+
* -> ['fooId', 'barId']
|
|
114
|
+
*/
|
|
115
|
+
static getParams(t) {
|
|
116
|
+
let e = [];
|
|
117
|
+
for (let r of t.split("/"))
|
|
118
|
+
r !== "" && r.startsWith(":") && e.push(r.slice(1));
|
|
119
|
+
return e;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
const y = /\:([A-Za-z0-9_-]+)/g;
|
|
123
|
+
class x {
|
|
124
|
+
constructor(t) {
|
|
125
|
+
let {
|
|
126
|
+
abstract: e,
|
|
127
|
+
controller: r,
|
|
128
|
+
name: i,
|
|
129
|
+
parent: s,
|
|
130
|
+
path: o,
|
|
131
|
+
resolve: u,
|
|
132
|
+
title: a,
|
|
133
|
+
url: l
|
|
134
|
+
} = t;
|
|
135
|
+
if (l = l || "", l)
|
|
136
|
+
var f = new g(l);
|
|
137
|
+
if (this.params = f && f.params || [], l = s && s.url ? s.url + l : l, r && r.resolve && u)
|
|
138
|
+
throw new Error("Resolve cannot be defined on both controller and route.");
|
|
139
|
+
this.Controller = r, this.controller = null, this.name = i, this.navigable = !!l && !e, this.parent = s || null, this.path = o.concat(this), this.resolve = u || r && r.resolve || {}, this.title = a || i, this.url = l;
|
|
140
|
+
}
|
|
141
|
+
getFqn() {
|
|
142
|
+
if (!this.parent)
|
|
143
|
+
return this.name;
|
|
144
|
+
let t = this.parent.getFqn();
|
|
145
|
+
return t ? t + "." + this.name : this.name;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* @method getRoot
|
|
149
|
+
* @description
|
|
150
|
+
* Returns the root node of this route's tree
|
|
151
|
+
*/
|
|
152
|
+
getRoot() {
|
|
153
|
+
return this.parent && this.parent.getRoot() || this;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* @method href
|
|
157
|
+
* @description
|
|
158
|
+
* Returns route's URL with specified params.
|
|
159
|
+
*
|
|
160
|
+
* @param {Object} [params] - Required if route has params
|
|
161
|
+
*
|
|
162
|
+
* @example
|
|
163
|
+
* this.url
|
|
164
|
+
* -> /foo/:fooId
|
|
165
|
+
*
|
|
166
|
+
* this.href({fooId: 1})
|
|
167
|
+
* -> /foo/1
|
|
168
|
+
*/
|
|
169
|
+
href(t = {}) {
|
|
170
|
+
if (!this.url)
|
|
171
|
+
return "";
|
|
172
|
+
let [e, r] = this.url.split("?"), i = e.replace(y, (s, o) => {
|
|
173
|
+
if (o in t)
|
|
174
|
+
return t[o];
|
|
175
|
+
throw new Error(`Missing required param '${o}'`);
|
|
176
|
+
});
|
|
177
|
+
if (r) {
|
|
178
|
+
let s = !0;
|
|
179
|
+
for (let o of r.split("&")) {
|
|
180
|
+
let u = t[o];
|
|
181
|
+
u != null && (s ? i += "?" : i += "&", i += `${o}=${u}`, s = !1);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return i;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* @method enter
|
|
188
|
+
* @description
|
|
189
|
+
* Route becomes active, instantiating its controller
|
|
190
|
+
* if one is defined.
|
|
191
|
+
*
|
|
192
|
+
* @returns {Promise}
|
|
193
|
+
*/
|
|
194
|
+
enter(t = {}) {
|
|
195
|
+
return S(this.resolve, t).then((r) => (this.Controller && (this.controller = new this.Controller(t, r)), r));
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* @method exit
|
|
199
|
+
* @description
|
|
200
|
+
* Route exits, calling controller.onExit and deleting its reference.
|
|
201
|
+
*
|
|
202
|
+
* @returns {Promise}
|
|
203
|
+
*/
|
|
204
|
+
exit() {
|
|
205
|
+
return (this.controller && this.controller.onExit ? Promise.resolve(this.controller.onExit()) : Promise.resolve()).then((e) => (this.controller && (this.controller = null), e));
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
function S(n, t) {
|
|
209
|
+
return n instanceof Promise ? n : typeof n == "function" ? Promise.resolve(n(t)) : R(n) ? b(n, t) : Array.isArray(n) ? Promise.all(n.map((e) => typeof e == "function" ? e(t) : e)) : Promise.resolve(n);
|
|
210
|
+
}
|
|
211
|
+
function b(n, t) {
|
|
212
|
+
let e = Object.keys(n);
|
|
213
|
+
return Promise.all(e.map((i) => {
|
|
214
|
+
let s = n[i];
|
|
215
|
+
return typeof s == "function" ? s(t) : s;
|
|
216
|
+
})).then((i) => i.reduce((s, o, u) => {
|
|
217
|
+
let a = e[u];
|
|
218
|
+
return s[a] = o, s;
|
|
219
|
+
}, {}));
|
|
220
|
+
}
|
|
221
|
+
function R(n) {
|
|
222
|
+
if (typeof n != "object" || n === null) return !1;
|
|
223
|
+
const t = Object.getPrototypeOf(n);
|
|
224
|
+
return t === Object.prototype || t === null;
|
|
225
|
+
}
|
|
226
|
+
class O {
|
|
227
|
+
constructor(t, e) {
|
|
228
|
+
this.router = t, this.urlRouter = e, this.routes = {}, this.root = this.register({
|
|
229
|
+
name: "",
|
|
230
|
+
url: "",
|
|
231
|
+
abstract: !0
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
buildRoute(t) {
|
|
235
|
+
let e = this.getParentName(t), r = q(t) ? null : this.get(e);
|
|
236
|
+
if (e && !r)
|
|
237
|
+
return null;
|
|
238
|
+
let i = r ? r.path : [];
|
|
239
|
+
return new x(Object.assign({}, t, { parent: r, path: i }));
|
|
240
|
+
}
|
|
241
|
+
register(t) {
|
|
242
|
+
if (this.routes.hasOwnProperty(t.name))
|
|
243
|
+
throw new Error(`Route '${t.name}' is already defined`);
|
|
244
|
+
let e = this.buildRoute(t);
|
|
245
|
+
return e && (this.routes[e.name] = e), e && e.navigable && this.urlRouter.when(e.url, (r) => this.router.transitionTo(e, r)), e;
|
|
246
|
+
}
|
|
247
|
+
getParentName(t) {
|
|
248
|
+
let e = t.name || "";
|
|
249
|
+
return e.indexOf(".") > -1 ? e.substring(0, e.lastIndexOf(".")) : t.parent ? d(t.parent) ? t.parent : t.parent.name : "";
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* @method getName
|
|
253
|
+
* @description
|
|
254
|
+
* Returns a route's fully qualified name.
|
|
255
|
+
*
|
|
256
|
+
* @example
|
|
257
|
+
* let route = { name: 'child', parent: 'parent' }
|
|
258
|
+
* getName(route) -> 'parent.child'
|
|
259
|
+
*/
|
|
260
|
+
getName(t) {
|
|
261
|
+
let e = t.name;
|
|
262
|
+
if (e.indexOf(".") !== -1 || !t.parent)
|
|
263
|
+
return e;
|
|
264
|
+
let r = d(t.parent) ? t.parent : t.parent.name;
|
|
265
|
+
return r ? r + "." + e : e;
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* @method get
|
|
269
|
+
* @description
|
|
270
|
+
* Returns a registered route.
|
|
271
|
+
*/
|
|
272
|
+
get(t) {
|
|
273
|
+
return this.routes[t] || null;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
function q(n) {
|
|
277
|
+
return n.name === "";
|
|
278
|
+
}
|
|
279
|
+
class m {
|
|
280
|
+
constructor(t = []) {
|
|
281
|
+
this.queue = t;
|
|
282
|
+
}
|
|
283
|
+
flush() {
|
|
284
|
+
if (this.queue.length === 0)
|
|
285
|
+
return Promise.resolve();
|
|
286
|
+
let t = this.queue.shift();
|
|
287
|
+
return this.queue.reduce((e, r) => e.then(() => r()), t());
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
class $ {
|
|
291
|
+
/**
|
|
292
|
+
* @param {Transitions} transitions
|
|
293
|
+
* @param {Route} current
|
|
294
|
+
* @param {Route} target
|
|
295
|
+
* @param {Object} [currentParams]
|
|
296
|
+
* @param {Object} [toParams]
|
|
297
|
+
*/
|
|
298
|
+
constructor(t, e, r, i = {}, s = {}) {
|
|
299
|
+
let o = Object.entries(i).reduce((h, [c, p]) => (c in s && s[c] !== p && (h[c] = s[c]), h), {}), u = e.path.findLast((h) => r.path.indexOf(h) > -1), a = r.path.findIndex((h, c) => h.params.some((p) => p in o)), l = (() => {
|
|
300
|
+
let h = r.path.indexOf(u) + 1;
|
|
301
|
+
return e === r && a < 0 ? r.path.length - 1 : a < 0 || h < a ? h : a;
|
|
302
|
+
})();
|
|
303
|
+
this.enterPath = r.path.slice(l);
|
|
304
|
+
let f = (() => {
|
|
305
|
+
let h = r.path[l], c = e.path.indexOf(h);
|
|
306
|
+
return c >= 0 ? c : e.path.indexOf(u) + 1;
|
|
307
|
+
})();
|
|
308
|
+
this.exitPath = e.path.slice(f).reverse(), this.onStartQueue = new m(t.onStartHandlers.map((h) => h.bind(h, r))), this.exitQueue = new m(this.exitPath.map((h) => h.exit.bind(h))), this.enterQueue = new m(this.enterPath.map((h) => h.enter.bind(h, s)));
|
|
309
|
+
}
|
|
310
|
+
run() {
|
|
311
|
+
return this.onStartQueue.flush().then(() => this.exitQueue.flush()).then(() => this.enterQueue.flush());
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
class E {
|
|
315
|
+
constructor() {
|
|
316
|
+
this.onErrorHandlers = [], this.onStartHandlers = [], this.onSuccessHandlers = [];
|
|
317
|
+
}
|
|
318
|
+
onError(t) {
|
|
319
|
+
if (typeof t != "function")
|
|
320
|
+
throw new Error(`Handler must be a function, was '${typeof t}' instead`);
|
|
321
|
+
this.onErrorHandlers.push(t);
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* @method onStart
|
|
325
|
+
* @description
|
|
326
|
+
* Registers a callback handler called on transition start.
|
|
327
|
+
* Handler may return a promise to cancel route transition.
|
|
328
|
+
*
|
|
329
|
+
* @TODO support returning Boolean to cancel or continue transition.
|
|
330
|
+
*
|
|
331
|
+
* @param {Function} handler
|
|
332
|
+
*
|
|
333
|
+
* @callback handler
|
|
334
|
+
* @param {Route} destination
|
|
335
|
+
*/
|
|
336
|
+
onStart(t) {
|
|
337
|
+
if (typeof t != "function")
|
|
338
|
+
throw new Error(`Handler must be a function, was '${typeof t}' instead`);
|
|
339
|
+
this.onStartHandlers.push(t);
|
|
340
|
+
}
|
|
341
|
+
onSuccess(t) {
|
|
342
|
+
if (typeof t != "function")
|
|
343
|
+
throw new Error(`Handler must be a function, was '${typeof t}' instead`);
|
|
344
|
+
this.onSuccessHandlers.push(t);
|
|
345
|
+
}
|
|
346
|
+
create(...t) {
|
|
347
|
+
return new $(this, ...t);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
class v {
|
|
351
|
+
constructor(t) {
|
|
352
|
+
this.prefix = t || "#!", this.rules = [], this.default = null, this.usePushState = !!(window.history && window.history.pushState);
|
|
353
|
+
}
|
|
354
|
+
onChange(t) {
|
|
355
|
+
let e = t.replace(this.prefix, "");
|
|
356
|
+
for (let r of this.rules)
|
|
357
|
+
if (r(e))
|
|
358
|
+
return !0;
|
|
359
|
+
if (console.warn(`No route handler found for '${e}'`), this.default && e !== this.default) {
|
|
360
|
+
let r = this.prefix + this.default;
|
|
361
|
+
this.replaceState({}, "", r), this.onChange(r);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
listen() {
|
|
365
|
+
window.addEventListener(
|
|
366
|
+
this.usePushState ? "popstate" : "hashchange",
|
|
367
|
+
() => this.onChange(window.location.hash)
|
|
368
|
+
), this.onChange(window.location.hash);
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* @method pushState
|
|
372
|
+
* @description
|
|
373
|
+
* Wraps window.history.pushState.
|
|
374
|
+
*
|
|
375
|
+
* @param {Object} state
|
|
376
|
+
* @param {String} title
|
|
377
|
+
* @param {String} url
|
|
378
|
+
*/
|
|
379
|
+
pushState(t = {}, e, r) {
|
|
380
|
+
this.usePushState ? window.history.pushState(t, e, r) : window.location.hash = r;
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* @method replaceState
|
|
384
|
+
* @description
|
|
385
|
+
* Wraps window.history.replaceState.
|
|
386
|
+
*
|
|
387
|
+
* @param {Object} state
|
|
388
|
+
* @param {String} title
|
|
389
|
+
* @param {String} url
|
|
390
|
+
*/
|
|
391
|
+
replaceState(t = {}, e, r) {
|
|
392
|
+
if (this.usePushState)
|
|
393
|
+
window.history.replaceState(t, e, r);
|
|
394
|
+
else {
|
|
395
|
+
let i = window.location.href.replace(/(javascript:|#).*$/, "");
|
|
396
|
+
window.location.replace(i + r);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
when(t, e) {
|
|
400
|
+
let r = new g(t);
|
|
401
|
+
this.rules.push((i) => {
|
|
402
|
+
let s = r.exec(i);
|
|
403
|
+
return s ? (e(s), !0) : !1;
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
otherwise(t) {
|
|
407
|
+
this.default = t;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
class j {
|
|
411
|
+
constructor({ prefix: t } = {}) {
|
|
412
|
+
this.prefix = t || "#!", this.urlRouter = new v(t), this.registry = new O(this, this.urlRouter), this.transitions = new E(), this.current = new w(this, this.registry.root), this.previous = new w(this, null);
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* @method route
|
|
416
|
+
* @description
|
|
417
|
+
* Registers a route.
|
|
418
|
+
*
|
|
419
|
+
* @param {[String]} name
|
|
420
|
+
* @param {Object} definition
|
|
421
|
+
* @param {Boolean} definition.abstract
|
|
422
|
+
* @param {String} definition.url
|
|
423
|
+
* @param {String} definition.name
|
|
424
|
+
* @param {String} definition.label - For page title, breadcrumbs, etc.
|
|
425
|
+
* @param {String} definition.parent
|
|
426
|
+
* @param {Function} definition.controller
|
|
427
|
+
* @param {Object|Array|*} definition.resolve
|
|
428
|
+
*/
|
|
429
|
+
route(t, e = {}) {
|
|
430
|
+
return P(t) ? e = t : e.name = t, this.registry.register(e), this;
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* @method listen
|
|
434
|
+
* @description
|
|
435
|
+
* Starts listening for hash changes to route to.
|
|
436
|
+
*/
|
|
437
|
+
listen() {
|
|
438
|
+
this.urlRouter.listen();
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* @method href
|
|
442
|
+
* @description
|
|
443
|
+
* Returns the URL for a given route with given params.
|
|
444
|
+
* Params inherit defaults from current params.
|
|
445
|
+
*
|
|
446
|
+
* @param {String|Route} route - Route name or instance
|
|
447
|
+
* @param {Object} [params]
|
|
448
|
+
*
|
|
449
|
+
* @returns {String}
|
|
450
|
+
*/
|
|
451
|
+
href(t, e = {}) {
|
|
452
|
+
let r = d(t) ? this.registry.get(t) : t;
|
|
453
|
+
return r ? (e = Object.assign({}, this.current.params, e), this.prefix + r.href(e)) : (console.error(`No match found for route '${t}'`), this.prefix);
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* @method go
|
|
457
|
+
* @description
|
|
458
|
+
* Programmatically navigate to a route by name, updating URL.
|
|
459
|
+
*/
|
|
460
|
+
go(t, e = {}) {
|
|
461
|
+
let r = this.registry.get(t);
|
|
462
|
+
if (!r)
|
|
463
|
+
throw new Error(`Route '${t}' not found.`);
|
|
464
|
+
return this.transitionTo(r, e, { location: !0 });
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* @method pushState
|
|
468
|
+
* @description
|
|
469
|
+
* Wraps window.history.pushState.
|
|
470
|
+
*
|
|
471
|
+
* @param {Object} state
|
|
472
|
+
* @param {String} title
|
|
473
|
+
* @param {String} url
|
|
474
|
+
*/
|
|
475
|
+
pushState(t = {}, e, r) {
|
|
476
|
+
return this.urlRouter.pushState(t, e, r);
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* @name reload
|
|
480
|
+
* @description
|
|
481
|
+
* Reloads current route with new params, optionally with
|
|
482
|
+
* a hard browser refresh.
|
|
483
|
+
*
|
|
484
|
+
* @param {Object} params
|
|
485
|
+
* @param {Boolean} hardRefresh
|
|
486
|
+
*/
|
|
487
|
+
reload(t = {}, e) {
|
|
488
|
+
let r = this.current.route;
|
|
489
|
+
if (e) {
|
|
490
|
+
this.pushState({}, r.title, this.href(r, t)), window.location.reload();
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
return this.transitionTo(r, t, { location: !0 });
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* @method transitionTo
|
|
497
|
+
* @description
|
|
498
|
+
* Lower-level method for transitioning to a route.
|
|
499
|
+
*
|
|
500
|
+
* @param {Route} route
|
|
501
|
+
* @param {Object} params
|
|
502
|
+
*/
|
|
503
|
+
transitionTo(t, e = {}, r = {}) {
|
|
504
|
+
e = Object.assign({}, this.current.params, e);
|
|
505
|
+
let i = this.transitions.create(
|
|
506
|
+
this.current.route,
|
|
507
|
+
t,
|
|
508
|
+
this.current.params,
|
|
509
|
+
e
|
|
510
|
+
);
|
|
511
|
+
r.location && this.pushState({}, t.title, this.href(t, e));
|
|
512
|
+
let s = this.current.route, o = this.current.params;
|
|
513
|
+
return this.current.put(t, e), i.run().then((u) => {
|
|
514
|
+
for (let a of this.transitions.onSuccessHandlers)
|
|
515
|
+
a(this.current);
|
|
516
|
+
return this.previous.put(s, o), this.current;
|
|
517
|
+
}).catch((u) => {
|
|
518
|
+
this.current.put(s, o), this.pushState({}, this.current.route.title, this.current.url());
|
|
519
|
+
for (let a of this.transitions.onErrorHandlers)
|
|
520
|
+
a(u);
|
|
521
|
+
throw u;
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
export {
|
|
526
|
+
j as default
|
|
527
|
+
};
|
|
528
|
+
//# sourceMappingURL=trouter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trouter.js","sources":["../src/common.js","../src/Current.js","../src/UrlMatcher.js","../src/Route.js","../src/Registry.js","../src/Queue.js","../src/transition/Transition.js","../src/transition/Transitions.js","../src/UrlRouter.js","../src/Router.js"],"sourcesContent":["export const isObject = (x) => x !== null && typeof x === 'object'\nexport const isString = (x) => typeof(x) === 'string'\n\nexport function defer() {\n let resolve, reject;\n\n let promise = new Promise((resolveFn, rejectFn) => {\n resolve = resolveFn\n reject = rejectFn\n })\n\n return { resolve, reject, promise}\n}\n\nexport function last(arr) {\n return arr[arr.length - 1]\n}\n","/**\n * @name Current\n * @description\n * Maintains current router state (i.e. current route, URL, and params).\n */\n\nclass Current {\n\n /**\n * @param {Router} router\n * @param {Route} current\n */\n\n constructor(router, current) {\n this.router = router\n\n this.params = {}\n this.route = null\n\n this.put(current)\n }\n\n /**\n * @method put\n * @description\n * Updates current route.\n *\n * @param {Route} route\n * @param {Object} [params]\n */\n\n put(route, params = {}) {\n this.params = params\n this.route = route\n }\n\n /**\n * @method path\n * @description\n * Returns path to current route.\n *\n * @returns {Array.<Route>}\n */\n\n path() {\n return this.route.path\n }\n\n /**\n * @method url\n * @description\n * Returns current URL\n *\n * @returns {String}\n *\n * @example\n * this.url()\n * -> /#!/foo/1/bar\n */\n\n url() {\n return this.router.href(this.route, this.params)\n }\n}\n\nexport default Current\n","class UrlMatcher {\n /**\n * @constructor\n * @description\n * Takes a URL pattern with optional params denoted by ':'\n *\n * @param {String} urlPattern - e.g. /foo/:fooId/bar?bazId\n */\n\n constructor(urlPattern) {\n this.params = []\n this.pathParams = []\n this.queryParams = []\n\n // Query args are optional and can occur in any order, so we\n // match for them separately from the path RegEx pattern.\n this.queryPatterns = []\n\n // We'll build up the regex string\n // as we iterate through the path.\n let pattern = ''\n\n let [pathPattern, queryPattern] = urlPattern.split('?')\n\n // @TODO: find a more elegant way\n if (pathPattern === '/') {\n pattern += '/'\n }\n\n for (let item of pathPattern.split('/')) {\n if (item === '') continue\n\n let isParam = item.startsWith(':')\n\n if (isParam) {\n let paramName = item.slice(1)\n\n this.pathParams.push(paramName)\n\n // Note: special characters in RegEx patterns written\n // as strings need to be double-escaped.\n pattern += '/([\\\\w-]+)'\n } else {\n pattern += '/' + item\n }\n }\n\n if (queryPattern) {\n for (let item of queryPattern.split('&')) {\n this.queryParams.push(item)\n\n let queryPattern = `${item}=([\\\\w-.~:/?#[\\\\]@!$'\"()*+,:%]+)`\n\n this.queryPatterns.push(new RegExp(queryPattern))\n }\n }\n\n this.params = this.pathParams.concat(this.queryParams)\n\n // Pattern may optionally end with query args\n this.pattern = new RegExp(`^${pattern}(?:\\\\?.*)?$`)\n }\n\n /**\n * @method exec\n * @description\n * Tests a path, providing route params if match found.\n * Returns null if not a match.\n *\n * @param {String} path\n *\n * @returns {Object|null}\n *\n * @example\n * new UrlMatcher('/foo/:id').exec('/foo/1') -> { id: '1'}\n */\n\n exec(path) {\n let match = this.pattern.exec(path)\n\n if (!match) {\n return null\n }\n\n let result = {}\n\n // Captured path params\n match = match.slice(1)\n\n for (let [index, param] of this.pathParams.entries()) {\n // @TODO: throw error at route definition time for duplicate params\n if (result[param]) {\n console.warn(`Warning: duplicate param '${param}'`)\n }\n\n result[param] = match[index]\n }\n\n for (let [index, param] of this.queryParams.entries()) {\n // @TODO: throw error at route definition time for duplicate params\n if (result[param]) {\n console.warn(`Warning: duplicate param '${param}'`)\n }\n\n let match = this.queryPatterns[index].exec(path)\n\n result[param] = match && match[1] || null\n }\n\n return result\n }\n\n /**\n * @method getParams\n * @static\n * @description\n * Extract param names from a URL pattern.\n *\n * @param {String} urlPattern\n * @param {Function} [callback] - Optional\n *\n * @example\n * UrlMatcher.getParams('/foo/:fooId/bar/:barId')\n * -> ['fooId', 'barId']\n */\n\n static getParams(urlPattern) {\n let params = []\n\n for (let item of urlPattern.split('/')) {\n if (item === '') continue\n\n if(item.startsWith(':')) {\n params.push(item.slice(1))\n }\n }\n\n return params\n }\n}\n\nexport default UrlMatcher\n","import UrlMatcher from './UrlMatcher'\n\n/**\n * @class Route\n * @description\n * A fully-built route.\n */\n\n// RegEx for matching URL params\nconst PARAMS = /\\:([A-Za-z0-9_-]+)/g\n\nclass Route {\n constructor(definition) {\n let {\n abstract, controller, name,\n parent, path, resolve, title, url\n } = definition\n\n url = url || ''\n\n if (url) {\n // @TODO abstract param parsing out from UrlMatcher.\n // We parse this routes URL before prepending parents so\n // we only have this route's params.\n var urlMatcher = new UrlMatcher(url)\n }\n\n this.params = urlMatcher && urlMatcher.params || []\n\n // Prepend URL with parent's URL\n // @TODO: should each route only be concerned with its section of the url?\n // e.g. fullUrl = this.path.reduce(((url, route) => url + route.url), this.router.base)\n url = (parent && parent.url) ? parent.url + url : url;\n\n // Only 1 resolve definition allowed\n if (controller && controller.resolve && resolve) {\n throw new Error('Resolve cannot be defined on both controller and route.')\n }\n\n this.Controller = controller // Controller definition\n this.controller = null // Controller instance\n this.name = name\n this.navigable = !!url && !abstract\n this.parent = parent || null\n this.path = path.concat(this)\n this.resolve = resolve || (controller && controller.resolve) || {}\n this.title = title || name\n this.url = url\n }\n\n getFqn() {\n if (!this.parent) {\n return this.name\n }\n\n let name = this.parent.getFqn()\n\n return name ? name + '.' + this.name : this.name\n }\n\n /**\n * @method getRoot\n * @description\n * Returns the root node of this route's tree\n */\n\n getRoot() {\n return this.parent && this.parent.getRoot() || this\n }\n\n /**\n * @method href\n * @description\n * Returns route's URL with specified params.\n *\n * @param {Object} [params] - Required if route has params\n *\n * @example\n * this.url\n * -> /foo/:fooId\n *\n * this.href({fooId: 1})\n * -> /foo/1\n */\n\n href(params = {}) {\n if (!this.url) {\n return ''\n }\n\n let [path, query] = this.url.split('?')\n\n let url = path.replace(PARAMS, (match, param) => {\n if (param in params) {\n return params[param]\n }\n\n throw new Error(`Missing required param '${param}'`)\n })\n\n if (query) {\n let isFirst = true\n\n for (let paramName of query.split('&')) {\n let paramValue = params[paramName]\n\n if (paramValue != null) {\n (isFirst) ? url += '?' : url += '&';\n\n url += `${paramName}=${paramValue}`\n\n isFirst = false\n }\n }\n }\n\n return url\n }\n\n /**\n * @method enter\n * @description\n * Route becomes active, instantiating its controller\n * if one is defined.\n *\n * @returns {Promise}\n */\n\n enter(params = {}) {\n let promise = getResolve(this.resolve, params)\n\n return promise.then((resolve) => {\n if (this.Controller) {\n this.controller = new this.Controller(params, resolve)\n }\n\n return resolve\n })\n }\n\n /**\n * @method exit\n * @description\n * Route exits, calling controller.onExit and deleting its reference.\n *\n * @returns {Promise}\n */\n\n exit() {\n let promise = (this.controller && this.controller.onExit) ?\n Promise.resolve(this.controller.onExit()) : Promise.resolve()\n\n return promise.then((result) => {\n if (this.controller) {\n this.controller = null\n }\n\n return result\n })\n }\n}\n\n/**\n * @method getResolve\n * @private\n * @description\n * Invokes/normalizes resolve functions and values into promises.\n *\n * @param {*} value\n *\n * @returns {Promise}\n */\n\nfunction getResolve(value, params) {\n if (value instanceof Promise) {\n return value\n }\n\n if (typeof value === 'function') {\n return Promise.resolve(value(params))\n }\n\n if (isPlainObject(value)) {\n return resolveObject(value, params)\n }\n\n if (Array.isArray(value)) {\n return Promise.all(value.map((item) => {\n return (typeof item === 'function') ? item(params) : item\n }))\n }\n\n return Promise.resolve(value)\n}\n\nfunction resolveObject(obj, params) {\n let keys = Object.keys(obj)\n\n // First invoke resolves and combine into single promise\n let combinedPromise = Promise.all(keys.map((key) => {\n let value = obj[key]\n\n return (typeof value === 'function') ? value(params) : value\n }))\n\n // Then assign resolved values to their keys\n return combinedPromise.then((values) => {\n return values.reduce((memo, value, index) => {\n let key = keys[index]\n\n memo[key] = value\n\n return memo\n }, {})\n })\n}\n\nfunction isPlainObject(value) {\n if (typeof value !== 'object' || value === null) return false\n const proto = Object.getPrototypeOf(value)\n return proto === Object.prototype || proto === null\n}\n\nexport default Route\n","import Route from './Route'\nimport {isString} from './common'\n\nclass Registry {\n constructor(router, urlRouter) {\n this.router = router\n this.urlRouter = urlRouter\n\n this.routes = {}\n\n this.root = this.register({\n name: '',\n url: '',\n abstract: true\n })\n }\n\n buildRoute(definition) {\n let parentName = this.getParentName(definition)\n let parent = (isRoot(definition)) ? null : this.get(parentName)\n\n // There's a parent, but it hasn't been built yet\n if (parentName && !parent) {\n return null\n }\n\n // The route's ancestors\n let path = (parent) ? parent.path : []\n\n let route = new Route(Object.assign({}, definition, { parent, path }))\n\n return route\n }\n\n register(definition) {\n if (this.routes.hasOwnProperty(definition.name)) {\n throw new Error(`Route '${definition.name}' is already defined`);\n }\n\n let route = this.buildRoute(definition)\n\n if (route) {\n this.routes[route.name] = route\n }\n\n if (route && route.navigable) {\n this.urlRouter.when(route.url, (params) => {\n return this.router.transitionTo(route, params)\n })\n }\n\n return route\n }\n\n getParentName(route) {\n let name = route.name || \"\"\n\n if (name.indexOf('.') > -1) {\n return name.substring(0, name.lastIndexOf('.'))\n }\n\n if (!route.parent) return \"\"\n\n return isString(route.parent) ? route.parent : route.parent.name\n }\n\n /**\n * @method getName\n * @description\n * Returns a route's fully qualified name.\n *\n * @example\n * let route = { name: 'child', parent: 'parent' }\n * getName(route) -> 'parent.child'\n */\n\n getName(route) {\n let name = route.name\n\n if (name.indexOf('.') !== -1 || !route.parent) {\n return name\n }\n\n let parentName = isString(route.parent) ?\n route.parent : route.parent.name\n\n return (parentName) ? parentName + '.' + name : name\n }\n\n /**\n * @method get\n * @description\n * Returns a registered route.\n */\n\n get(name) {\n return this.routes[name] || null\n }\n}\n\nfunction isRoot(route) { return route.name === \"\" }\n\nexport default Registry\n","/**\n * @name Queue\n * @description\n * A promise queue. Sequentially invokes a queue of functions that\n * each return a promise. The next function is called on successful\n * resolution of the current function's promise.\n */\n\nclass Queue {\n constructor(queue = []) {\n this.queue = queue\n }\n\n flush() {\n if (this.queue.length === 0) {\n return Promise.resolve()\n }\n\n let first = this.queue.shift()\n\n return this.queue.reduce((current, next) => {\n return current.then(() => next())\n }, first())\n }\n}\n\nexport default Queue\n","import Queue from '../Queue'\n\n/**\n * @name Transition\n * @description\n * Manages route transitions\n */\n\nclass Transition {\n\n /**\n * @param {Transitions} transitions\n * @param {Route} current\n * @param {Route} target\n * @param {Object} [currentParams]\n * @param {Object} [toParams]\n */\n\n constructor(transitions, current, target, currentParams = {}, toParams = {}) {\n // If a parent param has changed, we'll need to reload from there\n let changedParams = Object.entries(currentParams).reduce((memo, [key, value]) => {\n if (key in toParams && toParams[key] !== value) {\n memo[key] = toParams[key]\n }\n\n return memo\n }, {})\n\n // @TODO refactor path traversal into PathFactory\n\n let nearestCommonAncestor =\n current.path.findLast((ancestor) => {\n return target.path.indexOf(ancestor) > -1\n })\n\n // We'll need to reload starting from here if a param changed\n let minStartIndex = target.path.findIndex((route, index) => {\n return route.params.some((param) => param in changedParams)\n })\n\n // Determine which node in the entering target's path to start from\n let enterIndex = (() => {\n let fromAncestor = target.path.indexOf(nearestCommonAncestor) + 1\n\n if (current === target && minStartIndex < 0) {\n return target.path.length - 1\n }\n\n if (minStartIndex < 0 || fromAncestor < minStartIndex) {\n return fromAncestor\n }\n\n return minStartIndex\n })()\n\n this.enterPath = target.path.slice(enterIndex)\n\n // Determine last node in the exiting route's path to exit\n let exitIndex = (() => {\n let enterStart = target.path[enterIndex]\n\n let changedAncestorIndex = current.path.indexOf(enterStart)\n\n if (changedAncestorIndex >= 0) {\n return changedAncestorIndex\n }\n\n return current.path.indexOf(nearestCommonAncestor) + 1\n })()\n\n this.exitPath = current.path.slice(exitIndex).reverse()\n\n this.onStartQueue = new Queue(transitions.onStartHandlers.map((handler) => {\n return handler.bind(handler, target)\n }))\n\n this.exitQueue = new Queue(this.exitPath.map((route) => {\n return route.exit.bind(route)\n }))\n\n this.enterQueue = new Queue(this.enterPath.map((route) => {\n return route.enter.bind(route, toParams)\n }))\n }\n\n run() {\n return this.onStartQueue.flush()\n .then(() => this.exitQueue.flush())\n .then(() => this.enterQueue.flush())\n }\n}\n\nexport default Transition\n","import Transition from './Transition'\n\n/**\n * @name Transitions\n * @description\n * Registers global transition hooks.\n *\n * @TODO\n * - Implement additional transition lifecycle hooks\n * - Support handlers returning Boolean\n * - Write tests\n */\n\nclass Transitions {\n constructor(){\n this.onErrorHandlers = []\n this.onStartHandlers = []\n this.onSuccessHandlers = []\n }\n\n onError(handler) {\n if (typeof handler !== 'function') {\n throw new Error(`Handler must be a function, was '${typeof handler}' instead`)\n }\n\n this.onErrorHandlers.push(handler)\n }\n\n /**\n * @method onStart\n * @description\n * Registers a callback handler called on transition start.\n * Handler may return a promise to cancel route transition.\n *\n * @TODO support returning Boolean to cancel or continue transition.\n *\n * @param {Function} handler\n *\n * @callback handler\n * @param {Route} destination\n */\n\n onStart(handler) {\n if (typeof handler !== 'function') {\n throw new Error(`Handler must be a function, was '${typeof handler}' instead`)\n }\n\n this.onStartHandlers.push(handler)\n }\n\n onSuccess(handler) {\n if (typeof handler !== 'function') {\n throw new Error(`Handler must be a function, was '${typeof handler}' instead`)\n }\n\n this.onSuccessHandlers.push(handler)\n }\n\n create(...args) {\n return new Transition(this, ...args)\n }\n}\n\nexport default Transitions\n","import UrlMatcher from './UrlMatcher'\n\nclass UrlRouter {\n constructor(prefix) {\n this.prefix = prefix || '#!'\n this.rules = []\n this.default = null\n\n this.usePushState = !!(window.history && window.history.pushState)\n }\n\n onChange(hash) {\n let path = hash.replace(this.prefix, '')\n\n for (let rule of this.rules) {\n if (rule(path)) {\n return true\n }\n }\n\n console.warn(`No route handler found for '${path}'`)\n\n if (this.default && path !== this.default) {\n let url = this.prefix + this.default\n\n this.replaceState({}, '', url)\n this.onChange(url)\n }\n }\n\n listen() {\n window.addEventListener(\n this.usePushState ? 'popstate' : 'hashchange',\n () => this.onChange(window.location.hash)\n )\n\n // Handle the current hash\n this.onChange(window.location.hash)\n }\n\n /**\n * @method pushState\n * @description\n * Wraps window.history.pushState.\n *\n * @param {Object} state\n * @param {String} title\n * @param {String} url\n */\n\n pushState(state = {}, title, url) {\n if (this.usePushState) {\n window.history.pushState(state, title, url)\n } else {\n window.location.hash = url\n }\n }\n\n /**\n * @method replaceState\n * @description\n * Wraps window.history.replaceState.\n *\n * @param {Object} state\n * @param {String} title\n * @param {String} url\n */\n\n replaceState(state = {}, title, url) {\n if (this.usePushState) {\n window.history.replaceState(state, title, url)\n } else {\n let href = window.location.href.replace(/(javascript:|#).*$/, '')\n window.location.replace(href + url)\n }\n }\n\n when(url, handler) {\n let matcher = new UrlMatcher(url)\n\n this.rules.push((path) => {\n let result = matcher.exec(path)\n\n if (!result) {\n return false\n }\n\n handler(result)\n\n return true\n })\n }\n\n otherwise(url) {\n this.default = url\n }\n}\n\nexport default UrlRouter\n","import {isObject, isString} from './common'\nimport Current from './Current'\nimport Registry from './Registry'\nimport Transition from './transition/Transition'\nimport Transitions from './transition/Transitions'\nimport UrlRouter from './UrlRouter'\n\nclass Router {\n constructor({prefix} = {}) {\n this.prefix = prefix || '#!'\n\n this.urlRouter = new UrlRouter(prefix)\n this.registry = new Registry(this, this.urlRouter)\n this.transitions = new Transitions()\n\n // @TODO refactor current/previous into a full history stack\n this.current = new Current(this, this.registry.root)\n this.previous = new Current(this, null)\n }\n\n /**\n * @method route\n * @description\n * Registers a route.\n *\n * @param {[String]} name\n * @param {Object} definition\n * @param {Boolean} definition.abstract\n * @param {String} definition.url\n * @param {String} definition.name\n * @param {String} definition.label - For page title, breadcrumbs, etc.\n * @param {String} definition.parent\n * @param {Function} definition.controller\n * @param {Object|Array|*} definition.resolve\n */\n\n route(name, definition = {}) {\n if (isObject(name)) {\n definition = name\n } else {\n definition.name = name\n }\n\n this.registry.register(definition)\n\n return this\n }\n\n /**\n * @method listen\n * @description\n * Starts listening for hash changes to route to.\n */\n\n listen() {\n this.urlRouter.listen()\n }\n\n /**\n * @method href\n * @description\n * Returns the URL for a given route with given params.\n * Params inherit defaults from current params.\n *\n * @param {String|Route} route - Route name or instance\n * @param {Object} [params]\n *\n * @returns {String}\n */\n\n href(route, params = {}) {\n let destination = (isString(route)) ? this.registry.get(route) : route\n\n if (!destination) {\n console.error(`No match found for route '${route}'`)\n\n return this.prefix\n }\n\n params = Object.assign({}, this.current.params, params)\n\n return this.prefix + destination.href(params)\n }\n\n /**\n * @method go\n * @description\n * Programmatically navigate to a route by name, updating URL.\n */\n\n go(name, params = {}) {\n let destination = this.registry.get(name)\n\n if (!destination) {\n throw new Error(`Route '${name}' not found.`)\n }\n\n return this.transitionTo(destination, params, { location: true })\n }\n\n /**\n * @method pushState\n * @description\n * Wraps window.history.pushState.\n *\n * @param {Object} state\n * @param {String} title\n * @param {String} url\n */\n\n pushState(state = {}, title, url) {\n return this.urlRouter.pushState(state, title, url)\n }\n\n /**\n * @name reload\n * @description\n * Reloads current route with new params, optionally with\n * a hard browser refresh.\n *\n * @param {Object} params\n * @param {Boolean} hardRefresh\n */\n\n reload(params = {}, hardRefresh) {\n let route = this.current.route\n\n if (hardRefresh) {\n this.pushState({}, route.title, this.href(route, params))\n\n window.location.reload()\n\n return\n }\n\n return this.transitionTo(route, params, { location: true })\n }\n\n /**\n * @method transitionTo\n * @description\n * Lower-level method for transitioning to a route.\n *\n * @param {Route} route\n * @param {Object} params\n */\n\n transitionTo(route, params = {}, options = {}) {\n // Params inherit current by default\n params = Object.assign({}, this.current.params, params)\n\n let transition = this.transitions.create(\n this.current.route, route, this.current.params, params\n )\n\n if (options.location) {\n this.pushState({}, route.title, this.href(route, params))\n }\n\n let previous = this.current.route\n let previousParams = this.current.params\n\n // @TODO: should current only be set after successful route change?\n this.current.put(route, params)\n\n // @TODO: do transitions need to be queued as well? See test\n // 'Router: go(name): Should not invoke parent controller a\n // second time when go is called synchronously.'\n\n return transition.run()\n .then((result) => {\n for (let handler of this.transitions.onSuccessHandlers) {\n handler(this.current)\n }\n\n this.previous.put(previous, previousParams)\n\n return this.current\n }).catch((error) => {\n this.current.put(previous, previousParams)\n\n this.pushState({}, this.current.route.title, this.current.url())\n\n for (let handler of this.transitions.onErrorHandlers) {\n handler(error)\n }\n\n // Continue propagating the error down the promise chain\n throw error\n })\n }\n\n}\n\nexport default Router\n"],"names":["isObject","x","isString","Current","router","current","route","params","UrlMatcher","urlPattern","pattern","pathPattern","queryPattern","item","paramName","path","match","result","index","param","PARAMS","Route","definition","abstract","controller","name","parent","resolve","title","url","urlMatcher","query","isFirst","paramValue","getResolve","value","isPlainObject","resolveObject","obj","keys","key","values","memo","proto","Registry","urlRouter","parentName","isRoot","Queue","queue","first","next","Transition","transitions","target","currentParams","toParams","changedParams","nearestCommonAncestor","ancestor","minStartIndex","enterIndex","fromAncestor","exitIndex","enterStart","changedAncestorIndex","handler","Transitions","args","UrlRouter","prefix","hash","rule","state","href","matcher","Router","destination","hardRefresh","options","transition","previous","previousParams","error"],"mappings":"AAAO,MAAMA,IAAW,CAACC,MAAMA,MAAM,QAAQ,OAAOA,KAAM,UAC7CC,IAAW,CAACD,MAAM,OAAOA,KAAO;ACK7C,MAAME,EAAQ;AAAA;AAAA;AAAA;AAAA;AAAA,EAOZ,YAAYC,GAAQC,GAAS;AAC3B,SAAK,SAASD,GAEd,KAAK,SAAS,CAAA,GACd,KAAK,QAAQ,MAEb,KAAK,IAAIC,CAAO;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,IAAIC,GAAOC,IAAS,IAAI;AACtB,SAAK,SAASA,GACd,KAAK,QAAQD;AAAA,EACf;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,OAAO;AACL,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,MAAM;AACJ,WAAO,KAAK,OAAO,KAAK,KAAK,OAAO,KAAK,MAAM;AAAA,EACjD;AACF;AC/DA,MAAME,EAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASf,YAAYC,GAAY;AACtB,SAAK,SAAS,CAAA,GACd,KAAK,aAAa,CAAA,GAClB,KAAK,cAAc,CAAA,GAInB,KAAK,gBAAgB,CAAA;AAIrB,QAAIC,IAAU,IAEV,CAACC,GAAaC,CAAY,IAAIH,EAAW,MAAM,GAAG;AAGtD,IAAIE,MAAgB,QAClBD,KAAW;AAGb,aAASG,KAAQF,EAAY,MAAM,GAAG,GAAG;AACvC,UAAIE,MAAS,GAAI;AAIjB,UAFcA,EAAK,WAAW,GAAG,GAEpB;AACX,YAAIC,IAAYD,EAAK,MAAM,CAAC;AAE5B,aAAK,WAAW,KAAKC,CAAS,GAI9BJ,KAAW;AAAA,MACb;AACE,QAAAA,KAAW,MAAMG;AAAA,IAErB;AAEA,QAAID;AACF,eAASC,KAAQD,EAAa,MAAM,GAAG,GAAG;AACxC,aAAK,YAAY,KAAKC,CAAI;AAE1B,YAAID,IAAe,GAAGC,CAAI;AAE1B,aAAK,cAAc,KAAK,IAAI,OAAOD,CAAY,CAAC;AAAA,MAClD;AAGF,SAAK,SAAS,KAAK,WAAW,OAAO,KAAK,WAAW,GAGrD,KAAK,UAAU,IAAI,OAAO,IAAIF,CAAO,aAAa;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,KAAKK,GAAM;AACT,QAAIC,IAAQ,KAAK,QAAQ,KAAKD,CAAI;AAElC,QAAI,CAACC;AACH,aAAO;AAGT,QAAIC,IAAS,CAAA;AAGb,IAAAD,IAAQA,EAAM,MAAM,CAAC;AAErB,aAAS,CAACE,GAAOC,CAAK,KAAK,KAAK,WAAW;AAEzC,MAAIF,EAAOE,CAAK,KACd,QAAQ,KAAK,6BAA6BA,CAAK,GAAG,GAGpDF,EAAOE,CAAK,IAAIH,EAAME,CAAK;AAG7B,aAAS,CAACA,GAAOC,CAAK,KAAK,KAAK,YAAY,WAAW;AAErD,MAAIF,EAAOE,CAAK,KACd,QAAQ,KAAK,6BAA6BA,CAAK,GAAG;AAGpD,UAAIH,IAAQ,KAAK,cAAcE,CAAK,EAAE,KAAKH,CAAI;AAE/C,MAAAE,EAAOE,CAAK,IAAIH,KAASA,EAAM,CAAC,KAAK;AAAA,IACvC;AAEA,WAAOC;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,OAAO,UAAUR,GAAY;AAC3B,QAAIF,IAAS,CAAA;AAEb,aAASM,KAAQJ,EAAW,MAAM,GAAG;AACnC,MAAII,MAAS,MAEVA,EAAK,WAAW,GAAG,KACpBN,EAAO,KAAKM,EAAK,MAAM,CAAC,CAAC;AAI7B,WAAON;AAAA,EACT;AACF;AClIA,MAAMa,IAAS;AAEf,MAAMC,EAAM;AAAA,EACV,YAAYC,GAAY;AACtB,QAAI;AAAA,MACF,UAAAC;AAAA,MAAU,YAAAC;AAAA,MAAY,MAAAC;AAAA,MACtB,QAAAC;AAAA,MAAQ,MAAAX;AAAA,MAAM,SAAAY;AAAA,MAAS,OAAAC;AAAA,MAAO,KAAAC;AAAA,IACpC,IAAQP;AAIJ,QAFAO,IAAMA,KAAO,IAETA;AAIF,UAAIC,IAAa,IAAItB,EAAWqB,CAAG;AAWrC,QARA,KAAK,SAASC,KAAcA,EAAW,UAAU,CAAA,GAKjDD,IAAOH,KAAUA,EAAO,MAAOA,EAAO,MAAMG,IAAMA,GAG9CL,KAAcA,EAAW,WAAWG;AACtC,YAAM,IAAI,MAAM,yDAAyD;AAG3E,SAAK,aAAaH,GAClB,KAAK,aAAa,MAClB,KAAK,OAAOC,GACZ,KAAK,YAAY,CAAC,CAACI,KAAO,CAACN,GAC3B,KAAK,SAASG,KAAU,MACxB,KAAK,OAAOX,EAAK,OAAO,IAAI,GAC5B,KAAK,UAAUY,KAAYH,KAAcA,EAAW,WAAY,CAAA,GAChE,KAAK,QAAQI,KAASH,GACtB,KAAK,MAAMI;AAAA,EACb;AAAA,EAEA,SAAS;AACP,QAAI,CAAC,KAAK;AACR,aAAO,KAAK;AAGd,QAAIJ,IAAO,KAAK,OAAO,OAAM;AAE7B,WAAOA,IAAOA,IAAO,MAAM,KAAK,OAAO,KAAK;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,UAAU;AACR,WAAO,KAAK,UAAU,KAAK,OAAO,QAAO,KAAM;AAAA,EACjD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,KAAKlB,IAAS,IAAI;AAChB,QAAI,CAAC,KAAK;AACR,aAAO;AAGT,QAAI,CAACQ,GAAMgB,CAAK,IAAI,KAAK,IAAI,MAAM,GAAG,GAElCF,IAAMd,EAAK,QAAQK,GAAQ,CAACJ,GAAOG,MAAU;AAC/C,UAAIA,KAASZ;AACX,eAAOA,EAAOY,CAAK;AAGrB,YAAM,IAAI,MAAM,2BAA2BA,CAAK,GAAG;AAAA,IACrD,CAAC;AAED,QAAIY,GAAO;AACT,UAAIC,IAAU;AAEd,eAASlB,KAAaiB,EAAM,MAAM,GAAG,GAAG;AACtC,YAAIE,IAAa1B,EAAOO,CAAS;AAEjC,QAAImB,KAAc,SACfD,IAAWH,KAAO,MAAMA,KAAO,KAEhCA,KAAO,GAAGf,CAAS,IAAImB,CAAU,IAEjCD,IAAU;AAAA,MAEd;AAAA,IACF;AAEA,WAAOH;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAMtB,IAAS,IAAI;AAGjB,WAFc2B,EAAW,KAAK,SAAS3B,CAAM,EAE9B,KAAK,CAACoB,OACf,KAAK,eACP,KAAK,aAAa,IAAI,KAAK,WAAWpB,GAAQoB,CAAO,IAGhDA,EACR;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,OAAO;AAIL,YAHe,KAAK,cAAc,KAAK,WAAW,SAChD,QAAQ,QAAQ,KAAK,WAAW,OAAM,CAAE,IAAI,QAAQ,QAAO,GAE9C,KAAK,CAACV,OACf,KAAK,eACP,KAAK,aAAa,OAGbA,EACR;AAAA,EACH;AACF;AAaA,SAASiB,EAAWC,GAAO5B,GAAQ;AACjC,SAAI4B,aAAiB,UACZA,IAGL,OAAOA,KAAU,aACZ,QAAQ,QAAQA,EAAM5B,CAAM,CAAC,IAGlC6B,EAAcD,CAAK,IACdE,EAAcF,GAAO5B,CAAM,IAGhC,MAAM,QAAQ4B,CAAK,IACd,QAAQ,IAAIA,EAAM,IAAI,CAACtB,MACpB,OAAOA,KAAS,aAAcA,EAAKN,CAAM,IAAIM,CACtD,CAAC,IAGG,QAAQ,QAAQsB,CAAK;AAC9B;AAEA,SAASE,EAAcC,GAAK/B,GAAQ;AAClC,MAAIgC,IAAO,OAAO,KAAKD,CAAG;AAU1B,SAPsB,QAAQ,IAAIC,EAAK,IAAI,CAACC,MAAQ;AAClD,QAAIL,IAAQG,EAAIE,CAAG;AAEnB,WAAQ,OAAOL,KAAU,aAAcA,EAAM5B,CAAM,IAAI4B;AAAA,EACzD,CAAC,CAAC,EAGqB,KAAK,CAACM,MACpBA,EAAO,OAAO,CAACC,GAAMP,GAAOjB,MAAU;AAC3C,QAAIsB,IAAMD,EAAKrB,CAAK;AAEpB,WAAAwB,EAAKF,CAAG,IAAIL,GAELO;AAAA,EACT,GAAG,CAAA,CAAE,CACN;AACH;AAEA,SAASN,EAAcD,GAAO;AAC5B,MAAI,OAAOA,KAAU,YAAYA,MAAU,KAAM,QAAO;AACxD,QAAMQ,IAAQ,OAAO,eAAeR,CAAK;AACzC,SAAOQ,MAAU,OAAO,aAAaA,MAAU;AACjD;AC1NA,MAAMC,EAAS;AAAA,EACb,YAAYxC,GAAQyC,GAAW;AAC7B,SAAK,SAASzC,GACd,KAAK,YAAYyC,GAEjB,KAAK,SAAS,CAAA,GAEd,KAAK,OAAO,KAAK,SAAS;AAAA,MACxB,MAAM;AAAA,MACN,KAAK;AAAA,MACL,UAAU;AAAA,IAChB,CAAK;AAAA,EACH;AAAA,EAEA,WAAWvB,GAAY;AACrB,QAAIwB,IAAa,KAAK,cAAcxB,CAAU,GAC1CI,IAAUqB,EAAOzB,CAAU,IAAK,OAAO,KAAK,IAAIwB,CAAU;AAG9D,QAAIA,KAAc,CAACpB;AACjB,aAAO;AAIT,QAAIX,IAAQW,IAAUA,EAAO,OAAO,CAAA;AAIpC,WAFY,IAAIL,EAAM,OAAO,OAAO,CAAA,GAAIC,GAAY,EAAE,QAAAI,GAAQ,MAAAX,GAAM,CAAC;AAAA,EAGvE;AAAA,EAEA,SAASO,GAAY;AACnB,QAAI,KAAK,OAAO,eAAeA,EAAW,IAAI;AAC5C,YAAM,IAAI,MAAM,UAAUA,EAAW,IAAI,sBAAsB;AAGjE,QAAIhB,IAAQ,KAAK,WAAWgB,CAAU;AAEtC,WAAIhB,MACF,KAAK,OAAOA,EAAM,IAAI,IAAIA,IAGxBA,KAASA,EAAM,aACjB,KAAK,UAAU,KAAKA,EAAM,KAAK,CAACC,MACvB,KAAK,OAAO,aAAaD,GAAOC,CAAM,CAC9C,GAGID;AAAA,EACT;AAAA,EAEA,cAAcA,GAAO;AACnB,QAAImB,IAAOnB,EAAM,QAAQ;AAEzB,WAAImB,EAAK,QAAQ,GAAG,IAAI,KACfA,EAAK,UAAU,GAAGA,EAAK,YAAY,GAAG,CAAC,IAG3CnB,EAAM,SAEJJ,EAASI,EAAM,MAAM,IAAIA,EAAM,SAASA,EAAM,OAAO,OAFlC;AAAA,EAG5B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,QAAQA,GAAO;AACb,QAAImB,IAAOnB,EAAM;AAEjB,QAAImB,EAAK,QAAQ,GAAG,MAAM,MAAM,CAACnB,EAAM;AACrC,aAAOmB;AAGT,QAAIqB,IAAa5C,EAASI,EAAM,MAAM,IACpCA,EAAM,SAASA,EAAM,OAAO;AAE9B,WAAQwC,IAAcA,IAAa,MAAMrB,IAAOA;AAAA,EAClD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,IAAIA,GAAM;AACR,WAAO,KAAK,OAAOA,CAAI,KAAK;AAAA,EAC9B;AACF;AAEA,SAASsB,EAAOzC,GAAO;AAAE,SAAOA,EAAM,SAAS;AAAG;AC5FlD,MAAM0C,EAAM;AAAA,EACV,YAAYC,IAAQ,IAAI;AACtB,SAAK,QAAQA;AAAA,EACf;AAAA,EAEA,QAAQ;AACN,QAAI,KAAK,MAAM,WAAW;AACxB,aAAO,QAAQ,QAAO;AAGxB,QAAIC,IAAQ,KAAK,MAAM,MAAK;AAE5B,WAAO,KAAK,MAAM,OAAO,CAAC7C,GAAS8C,MAC1B9C,EAAQ,KAAK,MAAM8C,EAAI,CAAE,GAC/BD,EAAK,CAAE;AAAA,EACZ;AACF;AChBA,MAAME,EAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUf,YAAYC,GAAahD,GAASiD,GAAQC,IAAgB,CAAA,GAAIC,IAAW,IAAI;AAE3E,QAAIC,IAAgB,OAAO,QAAQF,CAAa,EAAE,OAAO,CAACb,GAAM,CAACF,GAAKL,CAAK,OACrEK,KAAOgB,KAAYA,EAAShB,CAAG,MAAML,MACvCO,EAAKF,CAAG,IAAIgB,EAAShB,CAAG,IAGnBE,IACN,CAAA,CAAE,GAIDgB,IACFrD,EAAQ,KAAK,SAAS,CAACsD,MACdL,EAAO,KAAK,QAAQK,CAAQ,IAAI,EACxC,GAGCC,IAAgBN,EAAO,KAAK,UAAU,CAAChD,GAAOY,MACzCZ,EAAM,OAAO,KAAK,CAACa,MAAUA,KAASsC,CAAa,CAC3D,GAGGI,KAAc,MAAM;AACtB,UAAIC,IAAeR,EAAO,KAAK,QAAQI,CAAqB,IAAI;AAEhE,aAAIrD,MAAYiD,KAAUM,IAAgB,IACjCN,EAAO,KAAK,SAAS,IAG1BM,IAAgB,KAAKE,IAAeF,IAC/BE,IAGFF;AAAA,IACT,GAAC;AAED,SAAK,YAAYN,EAAO,KAAK,MAAMO,CAAU;AAG7C,QAAIE,KAAa,MAAM;AACrB,UAAIC,IAAaV,EAAO,KAAKO,CAAU,GAEnCI,IAAuB5D,EAAQ,KAAK,QAAQ2D,CAAU;AAE1D,aAAIC,KAAwB,IACnBA,IAGF5D,EAAQ,KAAK,QAAQqD,CAAqB,IAAI;AAAA,IACvD,GAAC;AAED,SAAK,WAAWrD,EAAQ,KAAK,MAAM0D,CAAS,EAAE,QAAO,GAErD,KAAK,eAAe,IAAIf,EAAMK,EAAY,gBAAgB,IAAI,CAACa,MACtDA,EAAQ,KAAKA,GAASZ,CAAM,CACpC,CAAC,GAEF,KAAK,YAAY,IAAIN,EAAM,KAAK,SAAS,IAAI,CAAC1C,MACrCA,EAAM,KAAK,KAAKA,CAAK,CAC7B,CAAC,GAEF,KAAK,aAAa,IAAI0C,EAAM,KAAK,UAAU,IAAI,CAAC1C,MACvCA,EAAM,MAAM,KAAKA,GAAOkD,CAAQ,CACxC,CAAC;AAAA,EACJ;AAAA,EAEA,MAAM;AACJ,WAAO,KAAK,aAAa,MAAK,EAC3B,KAAK,MAAM,KAAK,UAAU,MAAK,CAAE,EACjC,KAAK,MAAM,KAAK,WAAW,MAAK,CAAE;AAAA,EACvC;AACF;AC7EA,MAAMW,EAAY;AAAA,EAChB,cAAa;AACX,SAAK,kBAAkB,CAAA,GACvB,KAAK,kBAAkB,CAAA,GACvB,KAAK,oBAAoB,CAAA;AAAA,EAC3B;AAAA,EAEA,QAAQD,GAAS;AACf,QAAI,OAAOA,KAAY;AACrB,YAAM,IAAI,MAAM,oCAAoC,OAAOA,CAAO,WAAW;AAG/E,SAAK,gBAAgB,KAAKA,CAAO;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,QAAQA,GAAS;AACf,QAAI,OAAOA,KAAY;AACrB,YAAM,IAAI,MAAM,oCAAoC,OAAOA,CAAO,WAAW;AAG/E,SAAK,gBAAgB,KAAKA,CAAO;AAAA,EACnC;AAAA,EAEA,UAAUA,GAAS;AACjB,QAAI,OAAOA,KAAY;AACrB,YAAM,IAAI,MAAM,oCAAoC,OAAOA,CAAO,WAAW;AAG/E,SAAK,kBAAkB,KAAKA,CAAO;AAAA,EACrC;AAAA,EAEA,UAAUE,GAAM;AACd,WAAO,IAAIhB,EAAW,MAAM,GAAGgB,CAAI;AAAA,EACrC;AACF;AC3DA,MAAMC,EAAU;AAAA,EACd,YAAYC,GAAQ;AAClB,SAAK,SAASA,KAAU,MACxB,KAAK,QAAQ,CAAA,GACb,KAAK,UAAU,MAEf,KAAK,eAAe,CAAC,EAAE,OAAO,WAAW,OAAO,QAAQ;AAAA,EAC1D;AAAA,EAEA,SAASC,GAAM;AACb,QAAIxD,IAAOwD,EAAK,QAAQ,KAAK,QAAQ,EAAE;AAEvC,aAASC,KAAQ,KAAK;AACpB,UAAIA,EAAKzD,CAAI;AACX,eAAO;AAMX,QAFA,QAAQ,KAAK,+BAA+BA,CAAI,GAAG,GAE/C,KAAK,WAAWA,MAAS,KAAK,SAAS;AACzC,UAAIc,IAAM,KAAK,SAAS,KAAK;AAE7B,WAAK,aAAa,IAAI,IAAIA,CAAG,GAC7B,KAAK,SAASA,CAAG;AAAA,IACnB;AAAA,EACF;AAAA,EAEA,SAAS;AACP,WAAO;AAAA,MACL,KAAK,eAAe,aAAa;AAAA,MACjC,MAAM,KAAK,SAAS,OAAO,SAAS,IAAI;AAAA,IAC9C,GAGI,KAAK,SAAS,OAAO,SAAS,IAAI;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,UAAU4C,IAAQ,IAAI7C,GAAOC,GAAK;AAChC,IAAI,KAAK,eACP,OAAO,QAAQ,UAAU4C,GAAO7C,GAAOC,CAAG,IAE1C,OAAO,SAAS,OAAOA;AAAA,EAE3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,aAAa4C,IAAQ,IAAI7C,GAAOC,GAAK;AACnC,QAAI,KAAK;AACP,aAAO,QAAQ,aAAa4C,GAAO7C,GAAOC,CAAG;AAAA,SACxC;AACL,UAAI6C,IAAO,OAAO,SAAS,KAAK,QAAQ,sBAAsB,EAAE;AAChE,aAAO,SAAS,QAAQA,IAAO7C,CAAG;AAAA,IACpC;AAAA,EACF;AAAA,EAEA,KAAKA,GAAKqC,GAAS;AACjB,QAAIS,IAAU,IAAInE,EAAWqB,CAAG;AAEhC,SAAK,MAAM,KAAK,CAACd,MAAS;AACxB,UAAIE,IAAS0D,EAAQ,KAAK5D,CAAI;AAE9B,aAAKE,KAILiD,EAAQjD,CAAM,GAEP,MALE;AAAA,IAMX,CAAC;AAAA,EACH;AAAA,EAEA,UAAUY,GAAK;AACb,SAAK,UAAUA;AAAA,EACjB;AACF;ACzFA,MAAM+C,EAAO;AAAA,EACX,YAAY,EAAC,QAAAN,EAAM,IAAI,IAAI;AACzB,SAAK,SAASA,KAAU,MAExB,KAAK,YAAY,IAAID,EAAUC,CAAM,GACrC,KAAK,WAAW,IAAI1B,EAAS,MAAM,KAAK,SAAS,GACjD,KAAK,cAAc,IAAIuB,EAAW,GAGlC,KAAK,UAAU,IAAIhE,EAAQ,MAAM,KAAK,SAAS,IAAI,GACnD,KAAK,WAAW,IAAIA,EAAQ,MAAM,IAAI;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBA,MAAMsB,GAAMH,IAAa,IAAI;AAC3B,WAAItB,EAASyB,CAAI,IACfH,IAAaG,IAEbH,EAAW,OAAOG,GAGpB,KAAK,SAAS,SAASH,CAAU,GAE1B;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,SAAS;AACP,SAAK,UAAU,OAAM;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,KAAKhB,GAAOC,IAAS,IAAI;AACvB,QAAIsE,IAAe3E,EAASI,CAAK,IAAK,KAAK,SAAS,IAAIA,CAAK,IAAIA;AAEjE,WAAKuE,KAMLtE,IAAS,OAAO,OAAO,CAAA,GAAI,KAAK,QAAQ,QAAQA,CAAM,GAE/C,KAAK,SAASsE,EAAY,KAAKtE,CAAM,MAP1C,QAAQ,MAAM,6BAA6BD,CAAK,GAAG,GAE5C,KAAK;AAAA,EAMhB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,GAAGmB,GAAMlB,IAAS,IAAI;AACpB,QAAIsE,IAAc,KAAK,SAAS,IAAIpD,CAAI;AAExC,QAAI,CAACoD;AACH,YAAM,IAAI,MAAM,UAAUpD,CAAI,cAAc;AAG9C,WAAO,KAAK,aAAaoD,GAAatE,GAAQ,EAAE,UAAU,GAAI,CAAE;AAAA,EAClE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,UAAUkE,IAAQ,IAAI7C,GAAOC,GAAK;AAChC,WAAO,KAAK,UAAU,UAAU4C,GAAO7C,GAAOC,CAAG;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,OAAOtB,IAAS,CAAA,GAAIuE,GAAa;AAC/B,QAAIxE,IAAQ,KAAK,QAAQ;AAEzB,QAAIwE,GAAa;AACf,WAAK,UAAU,CAAA,GAAIxE,EAAM,OAAO,KAAK,KAAKA,GAAOC,CAAM,CAAC,GAExD,OAAO,SAAS,OAAM;AAEtB;AAAA,IACF;AAEA,WAAO,KAAK,aAAaD,GAAOC,GAAQ,EAAE,UAAU,GAAI,CAAE;AAAA,EAC5D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,aAAaD,GAAOC,IAAS,CAAA,GAAIwE,IAAU,CAAA,GAAI;AAE7C,IAAAxE,IAAS,OAAO,OAAO,CAAA,GAAI,KAAK,QAAQ,QAAQA,CAAM;AAEtD,QAAIyE,IAAa,KAAK,YAAY;AAAA,MAChC,KAAK,QAAQ;AAAA,MAAO1E;AAAA,MAAO,KAAK,QAAQ;AAAA,MAAQC;AAAA,IACtD;AAEI,IAAIwE,EAAQ,YACV,KAAK,UAAU,CAAA,GAAIzE,EAAM,OAAO,KAAK,KAAKA,GAAOC,CAAM,CAAC;AAG1D,QAAI0E,IAAW,KAAK,QAAQ,OACxBC,IAAiB,KAAK,QAAQ;AAGlC,gBAAK,QAAQ,IAAI5E,GAAOC,CAAM,GAMvByE,EAAW,IAAG,EAClB,KAAK,CAAC/D,MAAW;AAChB,eAASiD,KAAW,KAAK,YAAY;AACnC,QAAAA,EAAQ,KAAK,OAAO;AAGtB,kBAAK,SAAS,IAAIe,GAAUC,CAAc,GAEnC,KAAK;AAAA,IACd,CAAC,EAAE,MAAM,CAACC,MAAU;AAClB,WAAK,QAAQ,IAAIF,GAAUC,CAAc,GAEzC,KAAK,UAAU,CAAA,GAAI,KAAK,QAAQ,MAAM,OAAO,KAAK,QAAQ,IAAG,CAAE;AAE/D,eAAShB,KAAW,KAAK,YAAY;AACnC,QAAAA,EAAQiB,CAAK;AAIf,YAAMA;AAAA,IACR,CAAC;AAAA,EACL;AAEF;"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
(function(p,f){typeof exports=="object"&&typeof module<"u"?module.exports=f():typeof define=="function"&&define.amd?define(f):(p=typeof globalThis<"u"?globalThis:p||self,p.trouter=f())})(this,(function(){"use strict";const p=n=>n!==null&&typeof n=="object",f=n=>typeof n=="string";class g{constructor(t,e){this.router=t,this.params={},this.route=null,this.put(e)}put(t,e={}){this.params=e,this.route=t}path(){return this.route.path}url(){return this.router.href(this.route,this.params)}}class y{constructor(t){this.params=[],this.pathParams=[],this.queryParams=[],this.queryPatterns=[];let e="",[r,i]=t.split("?");r==="/"&&(e+="/");for(let s of r.split("/")){if(s==="")continue;if(s.startsWith(":")){let h=s.slice(1);this.pathParams.push(h),e+="/([\\w-]+)"}else e+="/"+s}if(i)for(let s of i.split("&")){this.queryParams.push(s);let o=`${s}=([\\w-.~:/?#[\\]@!$'"()*+,:%]+)`;this.queryPatterns.push(new RegExp(o))}this.params=this.pathParams.concat(this.queryParams),this.pattern=new RegExp(`^${e}(?:\\?.*)?$`)}exec(t){let e=this.pattern.exec(t);if(!e)return null;let r={};e=e.slice(1);for(let[i,s]of this.pathParams.entries())r[s]&&console.warn(`Warning: duplicate param '${s}'`),r[s]=e[i];for(let[i,s]of this.queryParams.entries()){r[s]&&console.warn(`Warning: duplicate param '${s}'`);let o=this.queryPatterns[i].exec(t);r[s]=o&&o[1]||null}return r}static getParams(t){let e=[];for(let r of t.split("/"))r!==""&&r.startsWith(":")&&e.push(r.slice(1));return e}}const P=/\:([A-Za-z0-9_-]+)/g;class x{constructor(t){let{abstract:e,controller:r,name:i,parent:s,path:o,resolve:h,title:a,url:l}=t;if(l=l||"",l)var d=new y(l);if(this.params=d&&d.params||[],l=s&&s.url?s.url+l:l,r&&r.resolve&&h)throw new Error("Resolve cannot be defined on both controller and route.");this.Controller=r,this.controller=null,this.name=i,this.navigable=!!l&&!e,this.parent=s||null,this.path=o.concat(this),this.resolve=h||r&&r.resolve||{},this.title=a||i,this.url=l}getFqn(){if(!this.parent)return this.name;let t=this.parent.getFqn();return t?t+"."+this.name:this.name}getRoot(){return this.parent&&this.parent.getRoot()||this}href(t={}){if(!this.url)return"";let[e,r]=this.url.split("?"),i=e.replace(P,(s,o)=>{if(o in t)return t[o];throw new Error(`Missing required param '${o}'`)});if(r){let s=!0;for(let o of r.split("&")){let h=t[o];h!=null&&(s?i+="?":i+="&",i+=`${o}=${h}`,s=!1)}}return i}enter(t={}){return b(this.resolve,t).then(r=>(this.Controller&&(this.controller=new this.Controller(t,r)),r))}exit(){return(this.controller&&this.controller.onExit?Promise.resolve(this.controller.onExit()):Promise.resolve()).then(e=>(this.controller&&(this.controller=null),e))}}function b(n,t){return n instanceof Promise?n:typeof n=="function"?Promise.resolve(n(t)):R(n)?S(n,t):Array.isArray(n)?Promise.all(n.map(e=>typeof e=="function"?e(t):e)):Promise.resolve(n)}function S(n,t){let e=Object.keys(n);return Promise.all(e.map(i=>{let s=n[i];return typeof s=="function"?s(t):s})).then(i=>i.reduce((s,o,h)=>{let a=e[h];return s[a]=o,s},{}))}function R(n){if(typeof n!="object"||n===null)return!1;const t=Object.getPrototypeOf(n);return t===Object.prototype||t===null}class O{constructor(t,e){this.router=t,this.urlRouter=e,this.routes={},this.root=this.register({name:"",url:"",abstract:!0})}buildRoute(t){let e=this.getParentName(t),r=q(t)?null:this.get(e);if(e&&!r)return null;let i=r?r.path:[];return new x(Object.assign({},t,{parent:r,path:i}))}register(t){if(this.routes.hasOwnProperty(t.name))throw new Error(`Route '${t.name}' is already defined`);let e=this.buildRoute(t);return e&&(this.routes[e.name]=e),e&&e.navigable&&this.urlRouter.when(e.url,r=>this.router.transitionTo(e,r)),e}getParentName(t){let e=t.name||"";return e.indexOf(".")>-1?e.substring(0,e.lastIndexOf(".")):t.parent?f(t.parent)?t.parent:t.parent.name:""}getName(t){let e=t.name;if(e.indexOf(".")!==-1||!t.parent)return e;let r=f(t.parent)?t.parent:t.parent.name;return r?r+"."+e:e}get(t){return this.routes[t]||null}}function q(n){return n.name===""}class m{constructor(t=[]){this.queue=t}flush(){if(this.queue.length===0)return Promise.resolve();let t=this.queue.shift();return this.queue.reduce((e,r)=>e.then(()=>r()),t())}}class ${constructor(t,e,r,i={},s={}){let o=Object.entries(i).reduce((u,[c,w])=>(c in s&&s[c]!==w&&(u[c]=s[c]),u),{}),h=e.path.findLast(u=>r.path.indexOf(u)>-1),a=r.path.findIndex((u,c)=>u.params.some(w=>w in o)),l=(()=>{let u=r.path.indexOf(h)+1;return e===r&&a<0?r.path.length-1:a<0||u<a?u:a})();this.enterPath=r.path.slice(l);let d=(()=>{let u=r.path[l],c=e.path.indexOf(u);return c>=0?c:e.path.indexOf(h)+1})();this.exitPath=e.path.slice(d).reverse(),this.onStartQueue=new m(t.onStartHandlers.map(u=>u.bind(u,r))),this.exitQueue=new m(this.exitPath.map(u=>u.exit.bind(u))),this.enterQueue=new m(this.enterPath.map(u=>u.enter.bind(u,s)))}run(){return this.onStartQueue.flush().then(()=>this.exitQueue.flush()).then(()=>this.enterQueue.flush())}}class E{constructor(){this.onErrorHandlers=[],this.onStartHandlers=[],this.onSuccessHandlers=[]}onError(t){if(typeof t!="function")throw new Error(`Handler must be a function, was '${typeof t}' instead`);this.onErrorHandlers.push(t)}onStart(t){if(typeof t!="function")throw new Error(`Handler must be a function, was '${typeof t}' instead`);this.onStartHandlers.push(t)}onSuccess(t){if(typeof t!="function")throw new Error(`Handler must be a function, was '${typeof t}' instead`);this.onSuccessHandlers.push(t)}create(...t){return new $(this,...t)}}class j{constructor(t){this.prefix=t||"#!",this.rules=[],this.default=null,this.usePushState=!!(window.history&&window.history.pushState)}onChange(t){let e=t.replace(this.prefix,"");for(let r of this.rules)if(r(e))return!0;if(console.warn(`No route handler found for '${e}'`),this.default&&e!==this.default){let r=this.prefix+this.default;this.replaceState({},"",r),this.onChange(r)}}listen(){window.addEventListener(this.usePushState?"popstate":"hashchange",()=>this.onChange(window.location.hash)),this.onChange(window.location.hash)}pushState(t={},e,r){this.usePushState?window.history.pushState(t,e,r):window.location.hash=r}replaceState(t={},e,r){if(this.usePushState)window.history.replaceState(t,e,r);else{let i=window.location.href.replace(/(javascript:|#).*$/,"");window.location.replace(i+r)}}when(t,e){let r=new y(t);this.rules.push(i=>{let s=r.exec(i);return s?(e(s),!0):!1})}otherwise(t){this.default=t}}class v{constructor({prefix:t}={}){this.prefix=t||"#!",this.urlRouter=new j(t),this.registry=new O(this,this.urlRouter),this.transitions=new E,this.current=new g(this,this.registry.root),this.previous=new g(this,null)}route(t,e={}){return p(t)?e=t:e.name=t,this.registry.register(e),this}listen(){this.urlRouter.listen()}href(t,e={}){let r=f(t)?this.registry.get(t):t;return r?(e=Object.assign({},this.current.params,e),this.prefix+r.href(e)):(console.error(`No match found for route '${t}'`),this.prefix)}go(t,e={}){let r=this.registry.get(t);if(!r)throw new Error(`Route '${t}' not found.`);return this.transitionTo(r,e,{location:!0})}pushState(t={},e,r){return this.urlRouter.pushState(t,e,r)}reload(t={},e){let r=this.current.route;if(e){this.pushState({},r.title,this.href(r,t)),window.location.reload();return}return this.transitionTo(r,t,{location:!0})}transitionTo(t,e={},r={}){e=Object.assign({},this.current.params,e);let i=this.transitions.create(this.current.route,t,this.current.params,e);r.location&&this.pushState({},t.title,this.href(t,e));let s=this.current.route,o=this.current.params;return this.current.put(t,e),i.run().then(h=>{for(let a of this.transitions.onSuccessHandlers)a(this.current);return this.previous.put(s,o),this.current}).catch(h=>{this.current.put(s,o),this.pushState({},this.current.route.title,this.current.url());for(let a of this.transitions.onErrorHandlers)a(h);throw h})}}return v}));
|
|
2
|
+
//# sourceMappingURL=trouter.umd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trouter.umd.js","sources":["../src/common.js","../src/Current.js","../src/UrlMatcher.js","../src/Route.js","../src/Registry.js","../src/Queue.js","../src/transition/Transition.js","../src/transition/Transitions.js","../src/UrlRouter.js","../src/Router.js"],"sourcesContent":["export const isObject = (x) => x !== null && typeof x === 'object'\nexport const isString = (x) => typeof(x) === 'string'\n\nexport function defer() {\n let resolve, reject;\n\n let promise = new Promise((resolveFn, rejectFn) => {\n resolve = resolveFn\n reject = rejectFn\n })\n\n return { resolve, reject, promise}\n}\n\nexport function last(arr) {\n return arr[arr.length - 1]\n}\n","/**\n * @name Current\n * @description\n * Maintains current router state (i.e. current route, URL, and params).\n */\n\nclass Current {\n\n /**\n * @param {Router} router\n * @param {Route} current\n */\n\n constructor(router, current) {\n this.router = router\n\n this.params = {}\n this.route = null\n\n this.put(current)\n }\n\n /**\n * @method put\n * @description\n * Updates current route.\n *\n * @param {Route} route\n * @param {Object} [params]\n */\n\n put(route, params = {}) {\n this.params = params\n this.route = route\n }\n\n /**\n * @method path\n * @description\n * Returns path to current route.\n *\n * @returns {Array.<Route>}\n */\n\n path() {\n return this.route.path\n }\n\n /**\n * @method url\n * @description\n * Returns current URL\n *\n * @returns {String}\n *\n * @example\n * this.url()\n * -> /#!/foo/1/bar\n */\n\n url() {\n return this.router.href(this.route, this.params)\n }\n}\n\nexport default Current\n","class UrlMatcher {\n /**\n * @constructor\n * @description\n * Takes a URL pattern with optional params denoted by ':'\n *\n * @param {String} urlPattern - e.g. /foo/:fooId/bar?bazId\n */\n\n constructor(urlPattern) {\n this.params = []\n this.pathParams = []\n this.queryParams = []\n\n // Query args are optional and can occur in any order, so we\n // match for them separately from the path RegEx pattern.\n this.queryPatterns = []\n\n // We'll build up the regex string\n // as we iterate through the path.\n let pattern = ''\n\n let [pathPattern, queryPattern] = urlPattern.split('?')\n\n // @TODO: find a more elegant way\n if (pathPattern === '/') {\n pattern += '/'\n }\n\n for (let item of pathPattern.split('/')) {\n if (item === '') continue\n\n let isParam = item.startsWith(':')\n\n if (isParam) {\n let paramName = item.slice(1)\n\n this.pathParams.push(paramName)\n\n // Note: special characters in RegEx patterns written\n // as strings need to be double-escaped.\n pattern += '/([\\\\w-]+)'\n } else {\n pattern += '/' + item\n }\n }\n\n if (queryPattern) {\n for (let item of queryPattern.split('&')) {\n this.queryParams.push(item)\n\n let queryPattern = `${item}=([\\\\w-.~:/?#[\\\\]@!$'\"()*+,:%]+)`\n\n this.queryPatterns.push(new RegExp(queryPattern))\n }\n }\n\n this.params = this.pathParams.concat(this.queryParams)\n\n // Pattern may optionally end with query args\n this.pattern = new RegExp(`^${pattern}(?:\\\\?.*)?$`)\n }\n\n /**\n * @method exec\n * @description\n * Tests a path, providing route params if match found.\n * Returns null if not a match.\n *\n * @param {String} path\n *\n * @returns {Object|null}\n *\n * @example\n * new UrlMatcher('/foo/:id').exec('/foo/1') -> { id: '1'}\n */\n\n exec(path) {\n let match = this.pattern.exec(path)\n\n if (!match) {\n return null\n }\n\n let result = {}\n\n // Captured path params\n match = match.slice(1)\n\n for (let [index, param] of this.pathParams.entries()) {\n // @TODO: throw error at route definition time for duplicate params\n if (result[param]) {\n console.warn(`Warning: duplicate param '${param}'`)\n }\n\n result[param] = match[index]\n }\n\n for (let [index, param] of this.queryParams.entries()) {\n // @TODO: throw error at route definition time for duplicate params\n if (result[param]) {\n console.warn(`Warning: duplicate param '${param}'`)\n }\n\n let match = this.queryPatterns[index].exec(path)\n\n result[param] = match && match[1] || null\n }\n\n return result\n }\n\n /**\n * @method getParams\n * @static\n * @description\n * Extract param names from a URL pattern.\n *\n * @param {String} urlPattern\n * @param {Function} [callback] - Optional\n *\n * @example\n * UrlMatcher.getParams('/foo/:fooId/bar/:barId')\n * -> ['fooId', 'barId']\n */\n\n static getParams(urlPattern) {\n let params = []\n\n for (let item of urlPattern.split('/')) {\n if (item === '') continue\n\n if(item.startsWith(':')) {\n params.push(item.slice(1))\n }\n }\n\n return params\n }\n}\n\nexport default UrlMatcher\n","import UrlMatcher from './UrlMatcher'\n\n/**\n * @class Route\n * @description\n * A fully-built route.\n */\n\n// RegEx for matching URL params\nconst PARAMS = /\\:([A-Za-z0-9_-]+)/g\n\nclass Route {\n constructor(definition) {\n let {\n abstract, controller, name,\n parent, path, resolve, title, url\n } = definition\n\n url = url || ''\n\n if (url) {\n // @TODO abstract param parsing out from UrlMatcher.\n // We parse this routes URL before prepending parents so\n // we only have this route's params.\n var urlMatcher = new UrlMatcher(url)\n }\n\n this.params = urlMatcher && urlMatcher.params || []\n\n // Prepend URL with parent's URL\n // @TODO: should each route only be concerned with its section of the url?\n // e.g. fullUrl = this.path.reduce(((url, route) => url + route.url), this.router.base)\n url = (parent && parent.url) ? parent.url + url : url;\n\n // Only 1 resolve definition allowed\n if (controller && controller.resolve && resolve) {\n throw new Error('Resolve cannot be defined on both controller and route.')\n }\n\n this.Controller = controller // Controller definition\n this.controller = null // Controller instance\n this.name = name\n this.navigable = !!url && !abstract\n this.parent = parent || null\n this.path = path.concat(this)\n this.resolve = resolve || (controller && controller.resolve) || {}\n this.title = title || name\n this.url = url\n }\n\n getFqn() {\n if (!this.parent) {\n return this.name\n }\n\n let name = this.parent.getFqn()\n\n return name ? name + '.' + this.name : this.name\n }\n\n /**\n * @method getRoot\n * @description\n * Returns the root node of this route's tree\n */\n\n getRoot() {\n return this.parent && this.parent.getRoot() || this\n }\n\n /**\n * @method href\n * @description\n * Returns route's URL with specified params.\n *\n * @param {Object} [params] - Required if route has params\n *\n * @example\n * this.url\n * -> /foo/:fooId\n *\n * this.href({fooId: 1})\n * -> /foo/1\n */\n\n href(params = {}) {\n if (!this.url) {\n return ''\n }\n\n let [path, query] = this.url.split('?')\n\n let url = path.replace(PARAMS, (match, param) => {\n if (param in params) {\n return params[param]\n }\n\n throw new Error(`Missing required param '${param}'`)\n })\n\n if (query) {\n let isFirst = true\n\n for (let paramName of query.split('&')) {\n let paramValue = params[paramName]\n\n if (paramValue != null) {\n (isFirst) ? url += '?' : url += '&';\n\n url += `${paramName}=${paramValue}`\n\n isFirst = false\n }\n }\n }\n\n return url\n }\n\n /**\n * @method enter\n * @description\n * Route becomes active, instantiating its controller\n * if one is defined.\n *\n * @returns {Promise}\n */\n\n enter(params = {}) {\n let promise = getResolve(this.resolve, params)\n\n return promise.then((resolve) => {\n if (this.Controller) {\n this.controller = new this.Controller(params, resolve)\n }\n\n return resolve\n })\n }\n\n /**\n * @method exit\n * @description\n * Route exits, calling controller.onExit and deleting its reference.\n *\n * @returns {Promise}\n */\n\n exit() {\n let promise = (this.controller && this.controller.onExit) ?\n Promise.resolve(this.controller.onExit()) : Promise.resolve()\n\n return promise.then((result) => {\n if (this.controller) {\n this.controller = null\n }\n\n return result\n })\n }\n}\n\n/**\n * @method getResolve\n * @private\n * @description\n * Invokes/normalizes resolve functions and values into promises.\n *\n * @param {*} value\n *\n * @returns {Promise}\n */\n\nfunction getResolve(value, params) {\n if (value instanceof Promise) {\n return value\n }\n\n if (typeof value === 'function') {\n return Promise.resolve(value(params))\n }\n\n if (isPlainObject(value)) {\n return resolveObject(value, params)\n }\n\n if (Array.isArray(value)) {\n return Promise.all(value.map((item) => {\n return (typeof item === 'function') ? item(params) : item\n }))\n }\n\n return Promise.resolve(value)\n}\n\nfunction resolveObject(obj, params) {\n let keys = Object.keys(obj)\n\n // First invoke resolves and combine into single promise\n let combinedPromise = Promise.all(keys.map((key) => {\n let value = obj[key]\n\n return (typeof value === 'function') ? value(params) : value\n }))\n\n // Then assign resolved values to their keys\n return combinedPromise.then((values) => {\n return values.reduce((memo, value, index) => {\n let key = keys[index]\n\n memo[key] = value\n\n return memo\n }, {})\n })\n}\n\nfunction isPlainObject(value) {\n if (typeof value !== 'object' || value === null) return false\n const proto = Object.getPrototypeOf(value)\n return proto === Object.prototype || proto === null\n}\n\nexport default Route\n","import Route from './Route'\nimport {isString} from './common'\n\nclass Registry {\n constructor(router, urlRouter) {\n this.router = router\n this.urlRouter = urlRouter\n\n this.routes = {}\n\n this.root = this.register({\n name: '',\n url: '',\n abstract: true\n })\n }\n\n buildRoute(definition) {\n let parentName = this.getParentName(definition)\n let parent = (isRoot(definition)) ? null : this.get(parentName)\n\n // There's a parent, but it hasn't been built yet\n if (parentName && !parent) {\n return null\n }\n\n // The route's ancestors\n let path = (parent) ? parent.path : []\n\n let route = new Route(Object.assign({}, definition, { parent, path }))\n\n return route\n }\n\n register(definition) {\n if (this.routes.hasOwnProperty(definition.name)) {\n throw new Error(`Route '${definition.name}' is already defined`);\n }\n\n let route = this.buildRoute(definition)\n\n if (route) {\n this.routes[route.name] = route\n }\n\n if (route && route.navigable) {\n this.urlRouter.when(route.url, (params) => {\n return this.router.transitionTo(route, params)\n })\n }\n\n return route\n }\n\n getParentName(route) {\n let name = route.name || \"\"\n\n if (name.indexOf('.') > -1) {\n return name.substring(0, name.lastIndexOf('.'))\n }\n\n if (!route.parent) return \"\"\n\n return isString(route.parent) ? route.parent : route.parent.name\n }\n\n /**\n * @method getName\n * @description\n * Returns a route's fully qualified name.\n *\n * @example\n * let route = { name: 'child', parent: 'parent' }\n * getName(route) -> 'parent.child'\n */\n\n getName(route) {\n let name = route.name\n\n if (name.indexOf('.') !== -1 || !route.parent) {\n return name\n }\n\n let parentName = isString(route.parent) ?\n route.parent : route.parent.name\n\n return (parentName) ? parentName + '.' + name : name\n }\n\n /**\n * @method get\n * @description\n * Returns a registered route.\n */\n\n get(name) {\n return this.routes[name] || null\n }\n}\n\nfunction isRoot(route) { return route.name === \"\" }\n\nexport default Registry\n","/**\n * @name Queue\n * @description\n * A promise queue. Sequentially invokes a queue of functions that\n * each return a promise. The next function is called on successful\n * resolution of the current function's promise.\n */\n\nclass Queue {\n constructor(queue = []) {\n this.queue = queue\n }\n\n flush() {\n if (this.queue.length === 0) {\n return Promise.resolve()\n }\n\n let first = this.queue.shift()\n\n return this.queue.reduce((current, next) => {\n return current.then(() => next())\n }, first())\n }\n}\n\nexport default Queue\n","import Queue from '../Queue'\n\n/**\n * @name Transition\n * @description\n * Manages route transitions\n */\n\nclass Transition {\n\n /**\n * @param {Transitions} transitions\n * @param {Route} current\n * @param {Route} target\n * @param {Object} [currentParams]\n * @param {Object} [toParams]\n */\n\n constructor(transitions, current, target, currentParams = {}, toParams = {}) {\n // If a parent param has changed, we'll need to reload from there\n let changedParams = Object.entries(currentParams).reduce((memo, [key, value]) => {\n if (key in toParams && toParams[key] !== value) {\n memo[key] = toParams[key]\n }\n\n return memo\n }, {})\n\n // @TODO refactor path traversal into PathFactory\n\n let nearestCommonAncestor =\n current.path.findLast((ancestor) => {\n return target.path.indexOf(ancestor) > -1\n })\n\n // We'll need to reload starting from here if a param changed\n let minStartIndex = target.path.findIndex((route, index) => {\n return route.params.some((param) => param in changedParams)\n })\n\n // Determine which node in the entering target's path to start from\n let enterIndex = (() => {\n let fromAncestor = target.path.indexOf(nearestCommonAncestor) + 1\n\n if (current === target && minStartIndex < 0) {\n return target.path.length - 1\n }\n\n if (minStartIndex < 0 || fromAncestor < minStartIndex) {\n return fromAncestor\n }\n\n return minStartIndex\n })()\n\n this.enterPath = target.path.slice(enterIndex)\n\n // Determine last node in the exiting route's path to exit\n let exitIndex = (() => {\n let enterStart = target.path[enterIndex]\n\n let changedAncestorIndex = current.path.indexOf(enterStart)\n\n if (changedAncestorIndex >= 0) {\n return changedAncestorIndex\n }\n\n return current.path.indexOf(nearestCommonAncestor) + 1\n })()\n\n this.exitPath = current.path.slice(exitIndex).reverse()\n\n this.onStartQueue = new Queue(transitions.onStartHandlers.map((handler) => {\n return handler.bind(handler, target)\n }))\n\n this.exitQueue = new Queue(this.exitPath.map((route) => {\n return route.exit.bind(route)\n }))\n\n this.enterQueue = new Queue(this.enterPath.map((route) => {\n return route.enter.bind(route, toParams)\n }))\n }\n\n run() {\n return this.onStartQueue.flush()\n .then(() => this.exitQueue.flush())\n .then(() => this.enterQueue.flush())\n }\n}\n\nexport default Transition\n","import Transition from './Transition'\n\n/**\n * @name Transitions\n * @description\n * Registers global transition hooks.\n *\n * @TODO\n * - Implement additional transition lifecycle hooks\n * - Support handlers returning Boolean\n * - Write tests\n */\n\nclass Transitions {\n constructor(){\n this.onErrorHandlers = []\n this.onStartHandlers = []\n this.onSuccessHandlers = []\n }\n\n onError(handler) {\n if (typeof handler !== 'function') {\n throw new Error(`Handler must be a function, was '${typeof handler}' instead`)\n }\n\n this.onErrorHandlers.push(handler)\n }\n\n /**\n * @method onStart\n * @description\n * Registers a callback handler called on transition start.\n * Handler may return a promise to cancel route transition.\n *\n * @TODO support returning Boolean to cancel or continue transition.\n *\n * @param {Function} handler\n *\n * @callback handler\n * @param {Route} destination\n */\n\n onStart(handler) {\n if (typeof handler !== 'function') {\n throw new Error(`Handler must be a function, was '${typeof handler}' instead`)\n }\n\n this.onStartHandlers.push(handler)\n }\n\n onSuccess(handler) {\n if (typeof handler !== 'function') {\n throw new Error(`Handler must be a function, was '${typeof handler}' instead`)\n }\n\n this.onSuccessHandlers.push(handler)\n }\n\n create(...args) {\n return new Transition(this, ...args)\n }\n}\n\nexport default Transitions\n","import UrlMatcher from './UrlMatcher'\n\nclass UrlRouter {\n constructor(prefix) {\n this.prefix = prefix || '#!'\n this.rules = []\n this.default = null\n\n this.usePushState = !!(window.history && window.history.pushState)\n }\n\n onChange(hash) {\n let path = hash.replace(this.prefix, '')\n\n for (let rule of this.rules) {\n if (rule(path)) {\n return true\n }\n }\n\n console.warn(`No route handler found for '${path}'`)\n\n if (this.default && path !== this.default) {\n let url = this.prefix + this.default\n\n this.replaceState({}, '', url)\n this.onChange(url)\n }\n }\n\n listen() {\n window.addEventListener(\n this.usePushState ? 'popstate' : 'hashchange',\n () => this.onChange(window.location.hash)\n )\n\n // Handle the current hash\n this.onChange(window.location.hash)\n }\n\n /**\n * @method pushState\n * @description\n * Wraps window.history.pushState.\n *\n * @param {Object} state\n * @param {String} title\n * @param {String} url\n */\n\n pushState(state = {}, title, url) {\n if (this.usePushState) {\n window.history.pushState(state, title, url)\n } else {\n window.location.hash = url\n }\n }\n\n /**\n * @method replaceState\n * @description\n * Wraps window.history.replaceState.\n *\n * @param {Object} state\n * @param {String} title\n * @param {String} url\n */\n\n replaceState(state = {}, title, url) {\n if (this.usePushState) {\n window.history.replaceState(state, title, url)\n } else {\n let href = window.location.href.replace(/(javascript:|#).*$/, '')\n window.location.replace(href + url)\n }\n }\n\n when(url, handler) {\n let matcher = new UrlMatcher(url)\n\n this.rules.push((path) => {\n let result = matcher.exec(path)\n\n if (!result) {\n return false\n }\n\n handler(result)\n\n return true\n })\n }\n\n otherwise(url) {\n this.default = url\n }\n}\n\nexport default UrlRouter\n","import {isObject, isString} from './common'\nimport Current from './Current'\nimport Registry from './Registry'\nimport Transition from './transition/Transition'\nimport Transitions from './transition/Transitions'\nimport UrlRouter from './UrlRouter'\n\nclass Router {\n constructor({prefix} = {}) {\n this.prefix = prefix || '#!'\n\n this.urlRouter = new UrlRouter(prefix)\n this.registry = new Registry(this, this.urlRouter)\n this.transitions = new Transitions()\n\n // @TODO refactor current/previous into a full history stack\n this.current = new Current(this, this.registry.root)\n this.previous = new Current(this, null)\n }\n\n /**\n * @method route\n * @description\n * Registers a route.\n *\n * @param {[String]} name\n * @param {Object} definition\n * @param {Boolean} definition.abstract\n * @param {String} definition.url\n * @param {String} definition.name\n * @param {String} definition.label - For page title, breadcrumbs, etc.\n * @param {String} definition.parent\n * @param {Function} definition.controller\n * @param {Object|Array|*} definition.resolve\n */\n\n route(name, definition = {}) {\n if (isObject(name)) {\n definition = name\n } else {\n definition.name = name\n }\n\n this.registry.register(definition)\n\n return this\n }\n\n /**\n * @method listen\n * @description\n * Starts listening for hash changes to route to.\n */\n\n listen() {\n this.urlRouter.listen()\n }\n\n /**\n * @method href\n * @description\n * Returns the URL for a given route with given params.\n * Params inherit defaults from current params.\n *\n * @param {String|Route} route - Route name or instance\n * @param {Object} [params]\n *\n * @returns {String}\n */\n\n href(route, params = {}) {\n let destination = (isString(route)) ? this.registry.get(route) : route\n\n if (!destination) {\n console.error(`No match found for route '${route}'`)\n\n return this.prefix\n }\n\n params = Object.assign({}, this.current.params, params)\n\n return this.prefix + destination.href(params)\n }\n\n /**\n * @method go\n * @description\n * Programmatically navigate to a route by name, updating URL.\n */\n\n go(name, params = {}) {\n let destination = this.registry.get(name)\n\n if (!destination) {\n throw new Error(`Route '${name}' not found.`)\n }\n\n return this.transitionTo(destination, params, { location: true })\n }\n\n /**\n * @method pushState\n * @description\n * Wraps window.history.pushState.\n *\n * @param {Object} state\n * @param {String} title\n * @param {String} url\n */\n\n pushState(state = {}, title, url) {\n return this.urlRouter.pushState(state, title, url)\n }\n\n /**\n * @name reload\n * @description\n * Reloads current route with new params, optionally with\n * a hard browser refresh.\n *\n * @param {Object} params\n * @param {Boolean} hardRefresh\n */\n\n reload(params = {}, hardRefresh) {\n let route = this.current.route\n\n if (hardRefresh) {\n this.pushState({}, route.title, this.href(route, params))\n\n window.location.reload()\n\n return\n }\n\n return this.transitionTo(route, params, { location: true })\n }\n\n /**\n * @method transitionTo\n * @description\n * Lower-level method for transitioning to a route.\n *\n * @param {Route} route\n * @param {Object} params\n */\n\n transitionTo(route, params = {}, options = {}) {\n // Params inherit current by default\n params = Object.assign({}, this.current.params, params)\n\n let transition = this.transitions.create(\n this.current.route, route, this.current.params, params\n )\n\n if (options.location) {\n this.pushState({}, route.title, this.href(route, params))\n }\n\n let previous = this.current.route\n let previousParams = this.current.params\n\n // @TODO: should current only be set after successful route change?\n this.current.put(route, params)\n\n // @TODO: do transitions need to be queued as well? See test\n // 'Router: go(name): Should not invoke parent controller a\n // second time when go is called synchronously.'\n\n return transition.run()\n .then((result) => {\n for (let handler of this.transitions.onSuccessHandlers) {\n handler(this.current)\n }\n\n this.previous.put(previous, previousParams)\n\n return this.current\n }).catch((error) => {\n this.current.put(previous, previousParams)\n\n this.pushState({}, this.current.route.title, this.current.url())\n\n for (let handler of this.transitions.onErrorHandlers) {\n handler(error)\n }\n\n // Continue propagating the error down the promise chain\n throw error\n })\n }\n\n}\n\nexport default Router\n"],"names":["isObject","x","isString","Current","router","current","route","params","UrlMatcher","urlPattern","pattern","pathPattern","queryPattern","item","paramName","path","match","result","index","param","PARAMS","Route","definition","abstract","controller","name","parent","resolve","title","url","urlMatcher","query","isFirst","paramValue","getResolve","value","isPlainObject","resolveObject","obj","keys","key","values","memo","proto","Registry","urlRouter","parentName","isRoot","Queue","queue","first","next","Transition","transitions","target","currentParams","toParams","changedParams","nearestCommonAncestor","ancestor","minStartIndex","enterIndex","fromAncestor","exitIndex","enterStart","changedAncestorIndex","handler","Transitions","args","UrlRouter","prefix","hash","rule","state","href","matcher","Router","destination","hardRefresh","options","transition","previous","previousParams","error"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kcrwfrd/trouter",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Client-side router with a tree of handlers.",
|
|
6
|
+
"main": "dist/trouter.umd.js",
|
|
7
|
+
"module": "dist/trouter.js",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/trouter.js",
|
|
11
|
+
"require": "./dist/trouter.umd.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"test": "vitest run",
|
|
19
|
+
"build": "vite build",
|
|
20
|
+
"dev": "vitest",
|
|
21
|
+
"prepublishOnly": "npm run build"
|
|
22
|
+
},
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public"
|
|
25
|
+
},
|
|
26
|
+
"author": "Kevin Crawford",
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"jsdom": "^28.0.0",
|
|
30
|
+
"vite": "^7.0.0",
|
|
31
|
+
"vitest": "^4.0.0"
|
|
32
|
+
}
|
|
33
|
+
}
|