@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.
@@ -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":"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"}
@@ -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
+ }