@manyducks.co/dolla 2.0.0-alpha.39 → 2.0.0-alpha.40

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/index.js CHANGED
@@ -1,336 +1,261 @@
1
- import { a as assertArrayOf, b as assertString, i as isFunction, I as IS_ROUTER, c as atom, d as compose, g as get, s as shallowEqual, e as assertObject, f as isString, h as isObject, P as Passthrough, j as deepEqual, t as typeOf, k as cond, l as html, m as createMatcher, S as Store, n as StoreError, o as assertInstanceOf, p as createMarkup, V as View, q as groupElements, r as constructMarkup, u as noOp, v as okhash } from './markup-PXJjYgl3.js';
2
- export { w as effect, B as list, y as peek, A as portal, x as set, z as strictEqual } from './markup-PXJjYgl3.js';
3
-
4
- function ref(value) {
1
+ var zt = Object.defineProperty;
2
+ var kt = (i) => {
3
+ throw TypeError(i);
4
+ };
5
+ var Bt = (i, t, e) => t in i ? zt(i, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : i[t] = e;
6
+ var w = (i, t, e) => Bt(i, typeof t != "symbol" ? t + "" : t, e), mt = (i, t, e) => t.has(i) || kt("Cannot " + e);
7
+ var a = (i, t, e) => (mt(i, t, "read from private field"), e ? e.call(i) : t.get(i)), u = (i, t, e) => t.has(i) ? kt("Cannot add the same private member more than once") : t instanceof WeakSet ? t.add(i) : t.set(i, e), d = (i, t, e, s) => (mt(i, t, "write to private field"), s ? s.call(i, e) : t.set(i, e), e), f = (i, t, e) => (mt(i, t, "access private method"), e);
8
+ var Rt = (i, t, e, s) => ({
9
+ set _(n) {
10
+ d(i, t, n, e);
11
+ },
12
+ get _() {
13
+ return a(i, t, s);
14
+ }
15
+ });
16
+ import { a as Kt, b as Ft, i as z, I as Ot, c as Ut, d as U, g as E, s as _t, e as Qt, f as M, h as D, P as jt, j as Jt, t as St, k as Xt, l as Mt, m as xt, S as Yt, n as Tt, o as Nt, p as Zt, V as te, q as ee, r as se, u as re, v as ne } from "./markup-DIfh0nwz.js";
17
+ import { w as Ue, B as je, y as Ce, A as Ie, x as Ve, z as De } from "./markup-DIfh0nwz.js";
18
+ function Ne(i) {
5
19
  return function() {
6
- if (arguments.length === 1) {
7
- value = arguments[0];
8
- } else if (arguments.length > 1) {
20
+ if (arguments.length === 1)
21
+ i = arguments[0];
22
+ else if (arguments.length > 1)
9
23
  throw new Error(`Too many arguments. Expected 0 or 1. Got: ${arguments.length}`);
10
- }
11
- return value;
24
+ return i;
12
25
  };
13
26
  }
14
-
15
- function splitPath(path) {
16
- assertString(path, "Expected `path` to be a string. Got type: %t, value: %v");
17
- return path.split("/").map((f) => f.trim()).filter((f) => f !== "");
27
+ function K(i) {
28
+ return Ft(i, "Expected `path` to be a string. Got type: %t, value: %v"), i.split("/").map((t) => t.trim()).filter((t) => t !== "");
18
29
  }
19
- function joinPath(parts) {
20
- assertArrayOf(
21
- (part) => isFunction(part?.toString),
22
- parts,
30
+ function G(i) {
31
+ var e;
32
+ Kt(
33
+ (s) => z(s == null ? void 0 : s.toString),
34
+ i,
23
35
  "Expected `parts` to be an array of objects with a .toString() method. Got type: %t, value: %v"
24
- );
25
- parts = parts.filter((x) => x).flatMap(String);
26
- let joined = parts.shift()?.toString();
27
- if (joined) {
28
- for (const part of parts.map((p) => p.toString())) {
29
- if (part.startsWith(".")) {
30
- joined = resolvePath(joined, part);
31
- } else if (joined[joined.length - 1] !== "/") {
32
- if (part[0] !== "/") {
33
- joined += "/" + part;
34
- } else {
35
- joined += part;
36
- }
37
- } else {
38
- if (part[0] === "/") {
39
- joined += part.slice(1);
40
- } else {
41
- joined += part;
42
- }
43
- }
44
- }
45
- if (joined && joined !== "/" && joined.endsWith("/")) {
46
- joined = joined.slice(0, joined.length - 1);
47
- }
48
- }
49
- return joined ?? "";
36
+ ), i = i.filter((s) => s).flatMap(String);
37
+ let t = (e = i.shift()) == null ? void 0 : e.toString();
38
+ if (t) {
39
+ for (const s of i.map((n) => n.toString()))
40
+ s.startsWith(".") ? t = ct(t, s) : t[t.length - 1] !== "/" ? s[0] !== "/" ? t += "/" + s : t += s : s[0] === "/" ? t += s.slice(1) : t += s;
41
+ t && t !== "/" && t.endsWith("/") && (t = t.slice(0, t.length - 1));
42
+ }
43
+ return t ?? "";
50
44
  }
51
- function resolvePath(base, part) {
52
- assertString(base, "Expected `base` to be a string. Got type: %t, value: %v");
53
- if (part == null) {
54
- part = base;
55
- base = "";
56
- }
57
- if (part.startsWith("/")) {
58
- return part;
59
- }
60
- let resolved = base;
61
- while (true) {
62
- if (part.startsWith("..")) {
63
- for (let i = resolved.length; i > 0; --i) {
64
- if (resolved[i] === "/" || i === 0) {
65
- resolved = resolved.slice(0, i);
66
- part = part.replace(/^\.\.\/?/, "");
45
+ function ct(i, t) {
46
+ if (Ft(i, "Expected `base` to be a string. Got type: %t, value: %v"), t == null && (t = i, i = ""), t.startsWith("/"))
47
+ return t;
48
+ let e = i;
49
+ for (; ; )
50
+ if (t.startsWith("..")) {
51
+ for (let s = e.length; s > 0; --s)
52
+ if (e[s] === "/" || s === 0) {
53
+ e = e.slice(0, s), t = t.replace(/^\.\.\/?/, "");
67
54
  break;
68
55
  }
69
- }
70
- } else if (part.startsWith(".")) {
71
- part = part.replace(/^\.\/?/, "");
72
- } else {
56
+ } else if (t.startsWith("."))
57
+ t = t.replace(/^\.\/?/, "");
58
+ else
73
59
  break;
74
- }
75
- }
76
- return joinPath([resolved, part]);
60
+ return G([e, t]);
77
61
  }
78
- function parseQueryParams(query) {
79
- if (!query) return {};
80
- if (query.startsWith("?")) {
81
- query = query.slice(1);
82
- }
83
- const entries = query.split("&").filter((x) => x.trim() !== "").map((entry) => {
84
- const [key, value] = entry.split("=").map((x) => x.trim());
85
- if (value.toLowerCase() === "true") {
86
- return [key, true];
87
- }
88
- if (value.toLowerCase() === "false") {
89
- return [key, false];
90
- }
91
- if (!isNaN(Number(value))) {
92
- return [key, Number(value)];
93
- }
94
- return [key, value];
62
+ function ae(i) {
63
+ if (!i) return {};
64
+ i.startsWith("?") && (i = i.slice(1));
65
+ const t = i.split("&").filter((e) => e.trim() !== "").map((e) => {
66
+ const [s, n] = e.split("=").map((r) => r.trim());
67
+ return n.toLowerCase() === "true" ? [s, !0] : n.toLowerCase() === "false" ? [s, !1] : isNaN(Number(n)) ? [s, n] : [s, Number(n)];
95
68
  });
96
- return Object.fromEntries(entries);
69
+ return Object.fromEntries(t);
97
70
  }
98
- function matchRoutes(routes, url, options = {}) {
99
- const [path, query] = url.split("?");
100
- const parts = splitPath(path);
101
- routes: for (const route of routes) {
102
- const { fragments } = route;
103
- const hasWildcard = fragments[fragments.length - 1]?.type === 3 /* Wildcard */;
104
- if (!hasWildcard && fragments.length !== parts.length) {
105
- continue routes;
106
- }
107
- if (options.willMatch && !options.willMatch(route)) {
108
- continue routes;
109
- }
110
- const matched = [];
111
- fragments: for (let i = 0; i < fragments.length; i++) {
112
- const part = parts[i];
113
- const frag = fragments[i];
114
- if (part == null && frag.type !== 3 /* Wildcard */) {
115
- continue routes;
116
- }
117
- switch (frag.type) {
118
- case 1 /* Literal */:
119
- if (frag.name.toLowerCase() === part.toLowerCase()) {
120
- matched.push(frag);
71
+ function Ct(i, t, e = {}) {
72
+ var o;
73
+ const [s, n] = t.split("?"), r = K(s);
74
+ t: for (const c of i) {
75
+ const { fragments: l } = c;
76
+ if (!(((o = l[l.length - 1]) == null ? void 0 : o.type) === 3) && l.length !== r.length || e.willMatch && !e.willMatch(c))
77
+ continue t;
78
+ const v = [];
79
+ e: for (let h = 0; h < l.length; h++) {
80
+ const x = r[h], k = l[h];
81
+ if (x == null && k.type !== 3)
82
+ continue t;
83
+ switch (k.type) {
84
+ case 1:
85
+ if (k.name.toLowerCase() === x.toLowerCase()) {
86
+ v.push(k);
121
87
  break;
122
- } else {
123
- continue routes;
124
- }
125
- case 2 /* Param */:
126
- matched.push({ ...frag, value: part });
88
+ } else
89
+ continue t;
90
+ case 2:
91
+ v.push({ ...k, value: x });
92
+ break;
93
+ case 3:
94
+ v.push({ ...k, value: r.slice(h).join("/") });
95
+ break e;
96
+ case 4:
97
+ if (isNaN(Number(x)))
98
+ continue t;
99
+ v.push({ ...k, value: Number(x) });
127
100
  break;
128
- case 3 /* Wildcard */:
129
- matched.push({ ...frag, value: parts.slice(i).join("/") });
130
- break fragments;
131
- case 4 /* NumericParam */:
132
- if (!isNaN(Number(part))) {
133
- matched.push({ ...frag, value: Number(part) });
134
- break;
135
- } else {
136
- continue routes;
137
- }
138
101
  default:
139
- throw new Error(`Unknown fragment type: ${frag.type}`);
140
- }
141
- }
142
- const params = {};
143
- for (const frag of matched) {
144
- if (frag.type === 2 /* Param */) {
145
- params[frag.name] = decodeURIComponent(frag.value);
146
- }
147
- if (frag.type === 4 /* NumericParam */) {
148
- params[frag.name] = frag.value;
149
- }
150
- if (frag.type === 3 /* Wildcard */) {
151
- params.wildcard = "/" + decodeURIComponent(frag.value);
102
+ throw new Error(`Unknown fragment type: ${k.type}`);
152
103
  }
153
104
  }
105
+ const $ = {};
106
+ for (const h of v)
107
+ h.type === 2 && ($[h.name] = decodeURIComponent(h.value)), h.type === 4 && ($[h.name] = h.value), h.type === 3 && ($.wildcard = "/" + decodeURIComponent(h.value));
154
108
  return {
155
- path: "/" + matched.map((f) => f.value).join("/"),
156
- pattern: "/" + fragments.map((f) => {
157
- if (f.type === 2 /* Param */) {
158
- return `{${f.name}}`;
159
- }
160
- if (f.type === 4 /* NumericParam */) {
161
- return `{#${f.name}}`;
162
- }
163
- return f.name;
164
- }).join("/"),
165
- params,
166
- query: parseQueryParams(query),
167
- meta: route.meta
109
+ path: "/" + v.map((h) => h.value).join("/"),
110
+ pattern: "/" + l.map((h) => h.type === 2 ? `{${h.name}}` : h.type === 4 ? `{#${h.name}}` : h.name).join("/"),
111
+ params: $,
112
+ query: ae(n),
113
+ meta: c.meta
168
114
  };
169
115
  }
170
116
  }
171
- function sortRoutes(routes) {
172
- const withoutParams = [];
173
- const withNumericParams = [];
174
- const withParams = [];
175
- const wildcard = [];
176
- for (const route of routes) {
177
- const { fragments } = route;
178
- if (fragments.some((f) => f.type === 3 /* Wildcard */)) {
179
- wildcard.push(route);
180
- } else if (fragments.some((f) => f.type === 4 /* NumericParam */)) {
181
- withNumericParams.push(route);
182
- } else if (fragments.some((f) => f.type === 2 /* Param */)) {
183
- withParams.push(route);
184
- } else {
185
- withoutParams.push(route);
186
- }
187
- }
188
- const bySizeDesc = (a, b) => {
189
- if (a.fragments.length > b.fragments.length) {
190
- return -1;
191
- } else {
192
- return 1;
193
- }
194
- };
195
- withoutParams.sort(bySizeDesc);
196
- withNumericParams.sort(bySizeDesc);
197
- withParams.sort(bySizeDesc);
198
- wildcard.sort(bySizeDesc);
199
- return [...withoutParams, ...withNumericParams, ...withParams, ...wildcard];
117
+ function ie(i) {
118
+ const t = [], e = [], s = [], n = [];
119
+ for (const o of i) {
120
+ const { fragments: c } = o;
121
+ c.some(
122
+ (l) => l.type === 3
123
+ /* Wildcard */
124
+ ) ? n.push(o) : c.some(
125
+ (l) => l.type === 4
126
+ /* NumericParam */
127
+ ) ? e.push(o) : c.some(
128
+ (l) => l.type === 2
129
+ /* Param */
130
+ ) ? s.push(o) : t.push(o);
131
+ }
132
+ const r = (o, c) => o.fragments.length > c.fragments.length ? -1 : 1;
133
+ return t.sort(r), e.sort(r), s.sort(r), n.sort(r), [...t, ...e, ...s, ...n];
200
134
  }
201
- function patternToFragments(pattern) {
202
- const parts = splitPath(pattern);
203
- const fragments = [];
204
- for (let i = 0; i < parts.length; i++) {
205
- const part = parts[i];
206
- if (part === "*") {
207
- if (i !== parts.length - 1) {
208
- throw new Error(`Wildcard must be at the end of a pattern. Received: ${pattern}`);
209
- }
210
- fragments.push({
211
- type: 3 /* Wildcard */,
135
+ function oe(i) {
136
+ const t = K(i), e = [];
137
+ for (let s = 0; s < t.length; s++) {
138
+ const n = t[s];
139
+ if (n === "*") {
140
+ if (s !== t.length - 1)
141
+ throw new Error(`Wildcard must be at the end of a pattern. Received: ${i}`);
142
+ e.push({
143
+ type: 3,
212
144
  name: "*",
213
145
  value: null
214
146
  });
215
- } else if (part.at(0) === "{" && part.at(-1) === "}") {
216
- fragments.push({
217
- type: part[1] === "#" ? 4 /* NumericParam */ : 2 /* Param */,
218
- name: part[1] === "#" ? part.slice(2, -1) : part.slice(1, -1),
219
- value: null
220
- });
221
- } else {
222
- fragments.push({
223
- type: 1 /* Literal */,
224
- name: part,
225
- value: part
226
- });
227
- }
147
+ } else n.at(0) === "{" && n.at(-1) === "}" ? e.push({
148
+ type: n[1] === "#" ? 4 : 2,
149
+ name: n[1] === "#" ? n.slice(2, -1) : n.slice(1, -1),
150
+ value: null
151
+ }) : e.push({
152
+ type: 1,
153
+ name: n,
154
+ value: n
155
+ });
228
156
  }
229
- return fragments;
157
+ return e;
230
158
  }
231
-
232
- function createRouter(options) {
233
- return new Router(options);
159
+ function Pe(i) {
160
+ return new he(i);
234
161
  }
235
- const ROUTER_MOUNT = Symbol.for("DollaRouterMountMethod");
236
- const ROUTER_UNMOUNT = Symbol.for("DollaRouterUnmountMethod");
237
- function _isRouter(value) {
238
- return value?.[IS_ROUTER] === true;
162
+ const It = Symbol.for("DollaRouterMountMethod"), Vt = Symbol.for("DollaRouterUnmountMethod");
163
+ function pt(i) {
164
+ return (i == null ? void 0 : i[Ot]) === !0;
239
165
  }
240
- async function _mountRouter(router, dolla) {
241
- return router[ROUTER_MOUNT](dolla);
166
+ async function le(i, t) {
167
+ return i[It](t);
242
168
  }
243
- async function _unmountRouter(router) {
244
- return router[ROUTER_UNMOUNT]();
169
+ async function ce(i) {
170
+ return i[Vt]();
245
171
  }
246
- class Router {
247
- [IS_ROUTER] = true;
248
- #dolla;
249
- #logger;
250
- #layerId = 0;
251
- #activeLayers = [];
252
- #routes = [];
253
- #isMounted = false;
254
- /**
255
- * Use hash routing when true. Configured in router options.
256
- */
257
- #hash = false;
258
- // Callbacks that need to be called on unmount.
259
- #unsubscribers = [];
260
- /**
261
- * The current match object.
262
- */
263
- #match = atom();
264
- /**
265
- * The currently matched route pattern, if any.
266
- */
267
- pattern = compose(() => get(this.#match)?.pattern);
268
- /**
269
- * The current URL path.
270
- */
271
- path = compose(() => get(this.#match)?.path ?? window.location.pathname);
272
- /**
273
- * The current named path params.
274
- */
275
- params = compose(() => get(this.#match)?.params ?? {}, { equals: shallowEqual });
276
- /**
277
- * The current query params. Changes to this object will be reflected in the URL.
278
- */
279
- query = compose(() => get(this.#match)?.query ?? {}, { equals: shallowEqual });
280
- constructor(options) {
281
- assertObject(options, "Options must be an object. Got: %t");
282
- if (options.hash) {
283
- this.#hash = true;
284
- }
285
- this.#routes = sortRoutes(
286
- options.routes.flatMap((route) => this.#prepareRoute(route)).map((route) => ({
287
- pattern: route.pattern,
288
- meta: route.meta,
289
- fragments: patternToFragments(route.pattern)
172
+ var Lt, Q, S, ht, T, W, J, j, C, N, m, wt, Dt, qt, B, Gt, gt, yt;
173
+ class he {
174
+ constructor(t) {
175
+ u(this, m);
176
+ w(this, Lt, !0);
177
+ u(this, Q);
178
+ u(this, S);
179
+ u(this, ht, 0);
180
+ u(this, T, []);
181
+ u(this, W, []);
182
+ u(this, J, !1);
183
+ /**
184
+ * Use hash routing when true. Configured in router options.
185
+ */
186
+ u(this, j, !1);
187
+ // Callbacks that need to be called on unmount.
188
+ u(this, C, []);
189
+ /**
190
+ * The current match object.
191
+ */
192
+ u(this, N, Ut());
193
+ /**
194
+ * The currently matched route pattern, if any.
195
+ */
196
+ w(this, "pattern", U(() => {
197
+ var t;
198
+ return (t = E(a(this, N))) == null ? void 0 : t.pattern;
199
+ }));
200
+ /**
201
+ * The current URL path.
202
+ */
203
+ w(this, "path", U(() => {
204
+ var t;
205
+ return ((t = E(a(this, N))) == null ? void 0 : t.path) ?? window.location.pathname;
206
+ }));
207
+ /**
208
+ * The current named path params.
209
+ */
210
+ w(this, "params", U(() => {
211
+ var t;
212
+ return ((t = E(a(this, N))) == null ? void 0 : t.params) ?? {};
213
+ }, { equals: _t }));
214
+ /**
215
+ * The current query params. Changes to this object will be reflected in the URL.
216
+ */
217
+ w(this, "query", U(() => {
218
+ var t;
219
+ return ((t = E(a(this, N))) == null ? void 0 : t.query) ?? {};
220
+ }, { equals: _t }));
221
+ Qt(t, "Options must be an object. Got: %t"), t.hash && d(this, j, !0), d(this, W, ie(
222
+ t.routes.flatMap((e) => f(this, m, yt).call(this, e)).map((e) => ({
223
+ pattern: e.pattern,
224
+ meta: e.meta,
225
+ fragments: oe(e.pattern)
290
226
  }))
291
- );
292
- assertValidRedirects(this.#routes);
227
+ )), pe(a(this, W));
293
228
  }
294
- async [ROUTER_MOUNT](dolla) {
295
- this.#dolla = dolla;
296
- this.#logger = dolla.createLogger("Dolla.router");
297
- const onPopState = () => {
298
- this.#updateRoute();
229
+ async [(Lt = Ot, It)](t) {
230
+ d(this, Q, t), d(this, S, t.createLogger("Dolla.router"));
231
+ const e = () => {
232
+ f(this, m, B).call(this);
299
233
  };
300
- window.addEventListener("popstate", onPopState);
301
- this.#unsubscribers.push(() => window.removeEventListener("popstate", onPopState));
302
- const rootElement = dolla.getRootElement();
303
- this.#unsubscribers.push(
304
- catchLinks(rootElement, (anchor) => {
305
- let href = anchor.getAttribute("href");
306
- this.#logger.info("intercepted click on <a> tag", anchor);
307
- if (!/^https?:\/\/|^\//.test(href)) {
308
- href = joinPath([window.location.pathname, href]);
309
- }
310
- this.#push(href);
234
+ window.addEventListener("popstate", e), a(this, C).push(() => window.removeEventListener("popstate", e));
235
+ const s = t.getRootElement();
236
+ a(this, C).push(
237
+ de(s, (n) => {
238
+ let r = n.getAttribute("href");
239
+ a(this, S).info("intercepted click on <a> tag", n), /^https?:\/\/|^\//.test(r) || (r = G([window.location.pathname, r])), f(this, m, wt).call(this, r);
311
240
  })
312
- );
313
- this.#logger.info("will intercept clicks on <a> tags within root element", rootElement);
314
- this.#isMounted = true;
315
- await this.#updateRoute();
241
+ ), a(this, S).info("will intercept clicks on <a> tags within root element", s), d(this, J, !0), await f(this, m, B).call(this);
316
242
  }
317
- async [ROUTER_UNMOUNT]() {
318
- for (const callback of this.#unsubscribers) {
319
- callback();
320
- }
321
- this.#unsubscribers = [];
243
+ async [Vt]() {
244
+ for (const t of a(this, C))
245
+ t();
246
+ d(this, C, []);
322
247
  }
323
248
  /**
324
249
  * Navigate backward. Pass a number of steps to hit the back button that many times.
325
250
  */
326
- back(steps = 1) {
327
- window.history.go(-steps);
251
+ back(t = 1) {
252
+ window.history.go(-t);
328
253
  }
329
254
  /**
330
255
  * Navigate forward. Pass a number of steps to hit the forward button that many times.
331
256
  */
332
- forward(steps = 1) {
333
- window.history.go(steps);
257
+ forward(t = 1) {
258
+ window.history.go(t);
334
259
  }
335
260
  /**
336
261
  * Navigates to another route.
@@ -339,741 +264,483 @@ class Router {
339
264
  * router.go("/login"); // navigate to `/login`
340
265
  * router.go["/users", 215], { replace: true }); // replace current history entry with `/users/215`
341
266
  */
342
- go(path, options = {}) {
343
- let joined;
344
- if (Array.isArray(path)) {
345
- joined = joinPath(path);
346
- } else {
347
- joined = path.toString();
348
- }
349
- joined = resolvePath(window.location.pathname, joined);
350
- if (options.preserveQuery) {
351
- joined += window.location.search;
352
- }
353
- if (options.replace) {
354
- this.#replace(joined);
355
- } else {
356
- this.#push(joined);
357
- }
358
- }
359
- #push(href, state) {
360
- this.#logger?.info("(push)", href);
361
- window.history.pushState(state, "", this.#hash ? "/#" + href : href);
362
- this.#updateRoute(href);
363
- }
364
- #replace(href, state) {
365
- this.#logger?.info("(replace)", href);
366
- window.history.replaceState(state, "", this.#hash ? "/#" + href : href);
367
- this.#updateRoute(href);
368
- }
369
- #getCurrentURL() {
370
- if (this.#hash) {
371
- return new URL(window.location.hash.slice(1), window.location.origin);
372
- } else {
373
- return new URL(window.location.pathname, window.location.origin);
374
- }
375
- }
376
- /**
377
- * Run when the location changes. Diffs and mounts new routes and updates
378
- * the $path, $route, $params and $query states accordingly.
379
- */
380
- async #updateRoute(href) {
381
- const logger = this.#logger;
382
- const rootView = this.#dolla?.getRootView();
383
- const url = href ? new URL(href, window.location.origin) : this.#getCurrentURL();
384
- const { match, journey } = await this.#resolveRoute(url);
385
- if (match) {
386
- const oldPattern = this.pattern.value;
387
- this.#match.value = match;
388
- if (rootView && match.pattern !== oldPattern) {
389
- this.#mountRoute(rootView, match);
390
- }
391
- } else {
392
- if (this.#isMounted) {
393
- logger.crash(new NoRouteError(`Failed to match route '${url.pathname}'`));
394
- }
395
- }
396
- return { match, journey };
397
- }
398
- /**
399
- * Takes a matched route and mounts it.
400
- */
401
- #mountRoute(rootView, match) {
402
- const layers = match.meta.layers;
403
- for (let i = 0; i < layers.length; i++) {
404
- const matchedLayer = layers[i];
405
- const activeLayer = this.#activeLayers[i];
406
- if (activeLayer?.id !== matchedLayer.id) {
407
- this.#activeLayers = this.#activeLayers.slice(0, i);
408
- activeLayer?.view.unmount();
409
- const parentLayer = this.#activeLayers.at(-1);
410
- const parent2 = parentLayer?.view ?? rootView;
411
- const view = parent2.setChildView(matchedLayer.view);
412
- this.#activeLayers.push({ id: matchedLayer.id, view });
413
- }
414
- }
267
+ go(t, e = {}) {
268
+ let s;
269
+ Array.isArray(t) ? s = G(t) : s = t.toString(), s = ct(window.location.pathname, s), e.preserveQuery && (s += window.location.search), e.replace ? f(this, m, Dt).call(this, s) : f(this, m, wt).call(this, s);
415
270
  }
416
- /**
417
- * Takes a URL and finds a match, following redirects.
418
- */
419
- async #resolveRoute(url, journey = []) {
420
- const match = matchRoutes(this.#routes, url.pathname);
421
- if (!match) {
422
- return {
423
- match: null,
424
- journey: [...journey, { kind: "miss", message: `no match for '${url.pathname}'` }]
271
+ }
272
+ Q = new WeakMap(), S = new WeakMap(), ht = new WeakMap(), T = new WeakMap(), W = new WeakMap(), J = new WeakMap(), j = new WeakMap(), C = new WeakMap(), N = new WeakMap(), m = new WeakSet(), wt = function(t, e) {
273
+ var s;
274
+ (s = a(this, S)) == null || s.info("(push)", t), window.history.pushState(e, "", a(this, j) ? "/#" + t : t), f(this, m, B).call(this, t);
275
+ }, Dt = function(t, e) {
276
+ var s;
277
+ (s = a(this, S)) == null || s.info("(replace)", t), window.history.replaceState(e, "", a(this, j) ? "/#" + t : t), f(this, m, B).call(this, t);
278
+ }, qt = function() {
279
+ return a(this, j) ? new URL(window.location.hash.slice(1), window.location.origin) : new URL(window.location.pathname, window.location.origin);
280
+ }, B = async function(t) {
281
+ var c;
282
+ const e = a(this, S), s = (c = a(this, Q)) == null ? void 0 : c.getRootView(), n = t ? new URL(t, window.location.origin) : f(this, m, qt).call(this), { match: r, journey: o } = await f(this, m, gt).call(this, n);
283
+ if (r) {
284
+ const l = this.pattern.value;
285
+ a(this, N).value = r, s && r.pattern !== l && f(this, m, Gt).call(this, s, r);
286
+ } else
287
+ a(this, J) && e.crash(new we(`Failed to match route '${n.pathname}'`));
288
+ return { match: r, journey: o };
289
+ }, /**
290
+ * Takes a matched route and mounts it.
291
+ */
292
+ Gt = function(t, e) {
293
+ const s = e.meta.layers;
294
+ for (let n = 0; n < s.length; n++) {
295
+ const r = s[n], o = a(this, T)[n];
296
+ if ((o == null ? void 0 : o.id) !== r.id) {
297
+ d(this, T, a(this, T).slice(0, n)), o == null || o.view.unmount();
298
+ const c = a(this, T).at(-1), p = ((c == null ? void 0 : c.view) ?? t).setChildView(r.view);
299
+ a(this, T).push({ id: r.id, view: p });
300
+ }
301
+ }
302
+ }, gt = async function(t, e = []) {
303
+ const s = Ct(a(this, W), t.pathname);
304
+ if (!s)
305
+ return {
306
+ match: null,
307
+ journey: [...e, { kind: "miss", message: `no match for '${t.pathname}'` }]
308
+ };
309
+ let n = s.meta.redirect;
310
+ if (s.meta.beforeMatch && await s.meta.beforeMatch({
311
+ // TODO: Allow setting context variables from here? Would apply to the context of the matched view.
312
+ redirect: (r) => {
313
+ n = r;
314
+ }
315
+ }), n != null) {
316
+ let r;
317
+ if (M(n))
318
+ r = me(n, s.params);
319
+ else if (z(n)) {
320
+ const o = {
321
+ path: s.path,
322
+ pattern: s.pattern,
323
+ params: s.params,
324
+ query: s.query
425
325
  };
426
- }
427
- let redirect = match.meta.redirect;
428
- if (match.meta.beforeMatch) {
429
- await match.meta.beforeMatch({
430
- // TODO: Allow setting context variables from here? Would apply to the context of the matched view.
431
- redirect: (path) => {
432
- redirect = path;
433
- }
434
- });
435
- }
436
- if (redirect != null) {
437
- let path;
438
- if (isString(redirect)) {
439
- path = replaceParams(redirect, match.params);
440
- } else if (isFunction(redirect)) {
441
- const redirectContext = {
442
- path: match.path,
443
- pattern: match.pattern,
444
- params: match.params,
445
- query: match.query
446
- };
447
- path = await redirect(redirectContext);
448
- if (!isString(path)) {
449
- throw new Error(`Redirect function must return a path to redirect to.`);
450
- }
451
- if (!path.startsWith("/")) {
452
- path = resolvePath(match.path, path);
453
- }
454
- } else {
455
- throw new TypeError(`Redirect must either be a path string or a function.`);
326
+ if (r = await n(o), !M(r))
327
+ throw new Error("Redirect function must return a path to redirect to.");
328
+ r.startsWith("/") || (r = ct(s.path, r));
329
+ } else
330
+ throw new TypeError("Redirect must either be a path string or a function.");
331
+ return f(this, m, gt).call(this, new URL(r, window.location.origin), [
332
+ ...e,
333
+ { kind: "redirect", message: `redirecting '${s.path}' -> '${r}'` }
334
+ ]);
335
+ } else
336
+ return { match: s, journey: [...e, { kind: "match", message: `matched route '${s.path}'` }] };
337
+ }, /**
338
+ * Parses a route definition object into a set of matchable routes.
339
+ *
340
+ * @param route - Route config object.
341
+ * @param layers - Array of parent layers. Passed when this function calls itself on nested routes.
342
+ */
343
+ yt = function(t, e = [], s = []) {
344
+ if (!D(t) || !M(t.path))
345
+ throw new TypeError(`Route configs must be objects with a 'path' string property. Got: ${t}`);
346
+ if (t.redirect && t.routes)
347
+ throw new Error("Route cannot have both a 'redirect' and nested 'routes'.");
348
+ if (t.redirect && t.view)
349
+ throw new Error("Route cannot have both a 'redirect' and a 'view'.");
350
+ if (!t.view && !t.routes && !t.redirect)
351
+ throw new Error("Route must have a 'view', a 'redirect', or a set of nested 'routes'.");
352
+ let n = [];
353
+ for (const l of e)
354
+ n.push(...K(l.path));
355
+ n.push(...K(t.path)), n[n.length - 1] === "*" && n.pop();
356
+ const r = [];
357
+ if (t.redirect) {
358
+ let l = t.redirect;
359
+ return M(l) && (l = ct(G(n), l), l.startsWith("/") || (l = "/" + l)), r.push({
360
+ pattern: "/" + G([...n, ...K(t.path)]),
361
+ meta: {
362
+ redirect: l
456
363
  }
457
- return this.#resolveRoute(new URL(path, window.location.origin), [
458
- ...journey,
459
- { kind: "redirect", message: `redirecting '${match.path}' -> '${path}'` }
460
- ]);
461
- } else {
462
- return { match, journey: [...journey, { kind: "match", message: `matched route '${match.path}'` }] };
463
- }
464
- }
465
- /**
466
- * Parses a route definition object into a set of matchable routes.
467
- *
468
- * @param route - Route config object.
469
- * @param layers - Array of parent layers. Passed when this function calls itself on nested routes.
470
- */
471
- #prepareRoute(route, parents = [], layers = []) {
472
- if (!isObject(route) || !isString(route.path)) {
473
- throw new TypeError(`Route configs must be objects with a 'path' string property. Got: ${route}`);
474
- }
475
- if (route.redirect && route.routes) {
476
- throw new Error(`Route cannot have both a 'redirect' and nested 'routes'.`);
477
- } else if (route.redirect && route.view) {
478
- throw new Error(`Route cannot have both a 'redirect' and a 'view'.`);
479
- } else if (!route.view && !route.routes && !route.redirect) {
480
- throw new Error(`Route must have a 'view', a 'redirect', or a set of nested 'routes'.`);
481
- }
482
- let parts = [];
483
- for (const parent2 of parents) {
484
- parts.push(...splitPath(parent2.path));
485
- }
486
- parts.push(...splitPath(route.path));
487
- if (parts[parts.length - 1] === "*") {
488
- parts.pop();
489
- }
490
- const routes = [];
491
- if (route.redirect) {
492
- let redirect = route.redirect;
493
- if (isString(redirect)) {
494
- redirect = resolvePath(joinPath(parts), redirect);
495
- if (!redirect.startsWith("/")) {
496
- redirect = "/" + redirect;
497
- }
364
+ }), r;
365
+ }
366
+ let o = jt;
367
+ if (z(t.view))
368
+ o = t.view;
369
+ else if (t.view)
370
+ throw new TypeError(`Route '${t.path}' expected a view function or undefined. Got: ${t.view}`);
371
+ const c = { id: Rt(this, ht)._++, view: o };
372
+ if (t.routes)
373
+ for (const l of t.routes)
374
+ r.push(...f(this, m, yt).call(this, l, [...e, t], [...s, c]));
375
+ else
376
+ r.push({
377
+ pattern: parent ? G([...e.map((l) => l.path), t.path]) : t.path,
378
+ meta: {
379
+ pattern: t.path,
380
+ layers: [...s, c],
381
+ beforeMatch: t.beforeMatch
498
382
  }
499
- routes.push({
500
- pattern: "/" + joinPath([...parts, ...splitPath(route.path)]),
501
- meta: {
502
- redirect
503
- }
504
- });
505
- return routes;
506
- }
507
- let view = Passthrough;
508
- if (isFunction(route.view)) {
509
- view = route.view;
510
- } else if (route.view) {
511
- throw new TypeError(`Route '${route.path}' expected a view function or undefined. Got: ${route.view}`);
512
- }
513
- const layer = { id: this.#layerId++, view };
514
- if (route.routes) {
515
- for (const subroute of route.routes) {
516
- routes.push(...this.#prepareRoute(subroute, [...parents, route], [...layers, layer]));
517
- }
518
- } else {
519
- routes.push({
520
- pattern: parent ? joinPath([...parents.map((p) => p.path), route.path]) : route.path,
521
- meta: {
522
- pattern: route.path,
523
- layers: [...layers, layer],
524
- beforeMatch: route.beforeMatch
525
- }
526
- });
527
- }
528
- return routes;
529
- }
530
- }
531
- const safeExternalLink = /(noopener|noreferrer) (noopener|noreferrer)/;
532
- const protocolLink = /^[\w-_]+:/;
533
- function catchLinks(root, callback, _window = window) {
534
- function traverse(node) {
535
- if (!node || node === root) {
536
- return null;
537
- }
538
- if (node.localName !== "a" || node.href === void 0) {
539
- return traverse(node.parentNode);
540
- }
541
- return node;
542
- }
543
- function handler(e) {
544
- if (e.button && e.button !== 0 || e.ctrlKey || e.metaKey || e.altKey || e.shiftKey || e.defaultPrevented) {
545
- return;
546
- }
547
- const anchor = traverse(e.target);
548
- if (!anchor) {
549
- return;
550
- }
551
- if (_window.location.protocol !== anchor.protocol || _window.location.hostname !== anchor.hostname || _window.location.port !== anchor.port || anchor.hasAttribute("data-router-ignore") || anchor.hasAttribute("download") || anchor.getAttribute("target") === "_blank" && safeExternalLink.test(anchor.getAttribute("rel")) || protocolLink.test(anchor.getAttribute("href"))) {
383
+ });
384
+ return r;
385
+ };
386
+ const ue = /(noopener|noreferrer) (noopener|noreferrer)/, fe = /^[\w-_]+:/;
387
+ function de(i, t, e = window) {
388
+ function s(r) {
389
+ return !r || r === i ? null : r.localName !== "a" || r.href === void 0 ? s(r.parentNode) : r;
390
+ }
391
+ function n(r) {
392
+ if (r.button && r.button !== 0 || r.ctrlKey || r.metaKey || r.altKey || r.shiftKey || r.defaultPrevented)
552
393
  return;
553
- }
554
- e.preventDefault();
555
- callback(anchor);
394
+ const o = s(r.target);
395
+ o && (e.location.protocol !== o.protocol || e.location.hostname !== o.hostname || e.location.port !== o.port || o.hasAttribute("data-router-ignore") || o.hasAttribute("download") || o.getAttribute("target") === "_blank" && ue.test(o.getAttribute("rel")) || fe.test(o.getAttribute("href")) || (r.preventDefault(), t(o)));
556
396
  }
557
- root.addEventListener("click", handler);
558
- return function cancel() {
559
- root.removeEventListener("click", handler);
397
+ return i.addEventListener("click", n), function() {
398
+ i.removeEventListener("click", n);
560
399
  };
561
400
  }
562
- function replaceParams(path, params) {
563
- for (const key in params) {
564
- const value = params[key].toString();
565
- path = path.replace(`{${key}}`, value).replace(`{#${key}}`, value);
401
+ function me(i, t) {
402
+ for (const e in t) {
403
+ const s = t[e].toString();
404
+ i = i.replace(`{${e}}`, s).replace(`{#${e}}`, s);
566
405
  }
567
- return path;
406
+ return i;
568
407
  }
569
- function assertValidRedirects(routes) {
570
- for (const route of routes) {
571
- if (route.meta.redirect) {
572
- let redirectPath;
573
- if (isFunction(route.meta.redirect)) ; else if (isString(route.meta.redirect)) {
574
- redirectPath = route.meta.redirect;
575
- const match = matchRoutes(routes, redirectPath, {
576
- willMatch(r) {
577
- return r !== route;
408
+ function pe(i) {
409
+ for (const t of i)
410
+ if (t.meta.redirect) {
411
+ let e;
412
+ if (!z(t.meta.redirect)) if (M(t.meta.redirect)) {
413
+ if (e = t.meta.redirect, !Ct(i, e, {
414
+ willMatch(n) {
415
+ return n !== t;
578
416
  }
579
- });
580
- if (!match) {
581
- throw new Error(`Found a redirect to an undefined URL. From '${route.pattern}' to '${route.meta.redirect}'`);
582
- }
583
- } else {
584
- throw new TypeError(`Expected a string or redirect function. Got: ${route.meta.redirect}`);
585
- }
417
+ }))
418
+ throw new Error(`Found a redirect to an undefined URL. From '${t.pattern}' to '${t.meta.redirect}'`);
419
+ } else
420
+ throw new TypeError(`Expected a string or redirect function. Got: ${t.meta.redirect}`);
586
421
  }
587
- }
588
422
  }
589
- class NoRouteError extends Error {
423
+ class we extends Error {
590
424
  }
591
-
592
- class HTTP {
593
- #middleware = [];
594
- #fetch = getDefaultFetch();
425
+ var I, ut, R, _;
426
+ class ge {
427
+ constructor() {
428
+ u(this, R);
429
+ u(this, I, []);
430
+ u(this, ut, ye());
431
+ }
595
432
  /**
596
433
  * Adds a new middleware that will apply to subsequent requests.
597
434
  * Returns a function to remove this middleware.
598
435
  *
599
436
  * @param middleware - A middleware function that will intercept requests.
600
437
  */
601
- use(fn) {
602
- this.#middleware.push(fn);
603
- return () => {
604
- this.#middleware.splice(this.#middleware.indexOf(fn), 1);
438
+ use(t) {
439
+ return a(this, I).push(t), () => {
440
+ a(this, I).splice(a(this, I).indexOf(t), 1);
605
441
  };
606
442
  }
607
- async get(uri, options) {
608
- return this.#request("get", uri, options);
443
+ async get(t, e) {
444
+ return f(this, R, _).call(this, "get", t, e);
609
445
  }
610
- async put(uri, options) {
611
- return this.#request("put", uri, options);
446
+ async put(t, e) {
447
+ return f(this, R, _).call(this, "put", t, e);
612
448
  }
613
- async patch(uri, options) {
614
- return this.#request("patch", uri, options);
449
+ async patch(t, e) {
450
+ return f(this, R, _).call(this, "patch", t, e);
615
451
  }
616
- async post(uri, options) {
617
- return this.#request("post", uri, options);
452
+ async post(t, e) {
453
+ return f(this, R, _).call(this, "post", t, e);
618
454
  }
619
- async delete(uri, options) {
620
- return this.#request("delete", uri, options);
455
+ async delete(t, e) {
456
+ return f(this, R, _).call(this, "delete", t, e);
621
457
  }
622
- async head(uri, options) {
623
- return this.#request("head", uri, options);
458
+ async head(t, e) {
459
+ return f(this, R, _).call(this, "head", t, e);
624
460
  }
625
- async options(uri, options) {
626
- return this.#request("options", uri, options);
461
+ async options(t, e) {
462
+ return f(this, R, _).call(this, "options", t, e);
627
463
  }
628
- async trace(uri, options) {
629
- return this.#request("trace", uri, options);
630
- }
631
- async #request(method, uri, options) {
632
- const runner = new Runner({
633
- ...options,
634
- method,
635
- uri,
636
- middleware: this.#middleware,
637
- fetch: this.#fetch
638
- });
639
- return runner.fetch();
464
+ async trace(t, e) {
465
+ return f(this, R, _).call(this, "trace", t, e);
640
466
  }
641
467
  }
642
- function getDefaultFetch() {
643
- if (typeof window !== "undefined" && window.fetch) {
468
+ I = new WeakMap(), ut = new WeakMap(), R = new WeakSet(), _ = async function(t, e, s) {
469
+ return new Ee({
470
+ ...s,
471
+ method: t,
472
+ uri: e,
473
+ middleware: a(this, I),
474
+ fetch: a(this, ut)
475
+ }).fetch();
476
+ };
477
+ function ye() {
478
+ if (typeof window < "u" && window.fetch)
644
479
  return window.fetch.bind(window);
645
- }
646
- if (typeof global !== "undefined" && global.fetch) {
480
+ if (typeof global < "u" && global.fetch)
647
481
  return global.fetch.bind(global);
648
- }
649
482
  throw new Error("Running in neither browser nor node. Please run this app in one of the supported environments.");
650
483
  }
651
- class HTTPResponseError extends Error {
652
- response;
653
- constructor(response) {
654
- const { status, statusText, method, url } = response;
655
- const message = `${status} ${statusText}: Request failed (${method.toUpperCase()} ${url.toString()})`;
656
- super(message);
657
- this.response = response;
484
+ class be extends Error {
485
+ constructor(e) {
486
+ const { status: s, statusText: n, method: r, url: o } = e, c = `${s} ${n}: Request failed (${r.toUpperCase()} ${o.toString()})`;
487
+ super(c);
488
+ w(this, "response");
489
+ this.response = e;
658
490
  }
659
491
  }
660
- class Request {
661
- method;
662
- url;
663
- headers = new Headers();
664
- body;
492
+ class ve {
493
+ constructor(t) {
494
+ w(this, "method");
495
+ w(this, "url");
496
+ w(this, "headers", new Headers());
497
+ w(this, "body");
498
+ this.method = t.method, this.body = t.body, t.uri.startsWith("http") ? this.url = new URL(t.uri) : this.url = new URL(t.uri, window.location.origin), this._applyHeaders(t.headers), this._applyQueryParams(t.query);
499
+ }
665
500
  get isSameOrigin() {
666
501
  return this.url.origin === window.location.origin;
667
502
  }
668
- constructor(config) {
669
- this.method = config.method;
670
- this.body = config.body;
671
- if (config.uri.startsWith("http")) {
672
- this.url = new URL(config.uri);
673
- } else {
674
- this.url = new URL(config.uri, window.location.origin);
675
- }
676
- this._applyHeaders(config.headers);
677
- this._applyQueryParams(config.query);
678
- }
679
- _applyHeaders(headers) {
680
- if (headers == null) return;
681
- if (headers instanceof Map || headers instanceof Headers) {
682
- headers.forEach((value, key) => {
683
- this.headers.set(key, value);
684
- });
685
- } else if (isObject(headers)) {
686
- for (const name in headers) {
687
- const value = headers[name];
688
- if (value instanceof Date) {
689
- this.headers.set(name, value.toISOString());
690
- } else if (value != null) {
691
- this.headers.set(name, String(value));
503
+ _applyHeaders(t) {
504
+ if (t != null)
505
+ if (t instanceof Map || t instanceof Headers)
506
+ t.forEach((e, s) => {
507
+ this.headers.set(s, e);
508
+ });
509
+ else if (D(t))
510
+ for (const e in t) {
511
+ const s = t[e];
512
+ s instanceof Date ? this.headers.set(e, s.toISOString()) : s != null && this.headers.set(e, String(s));
692
513
  }
693
- }
694
- } else {
695
- throw new TypeError(`Unknown headers type. Got: ${headers}`);
696
- }
697
- }
698
- _applyQueryParams(query) {
699
- if (query == null) return;
700
- if (query instanceof Map || query instanceof URLSearchParams) {
701
- query.forEach((value, key) => {
702
- this.url.searchParams.set(key, value);
703
- });
704
- } else if (isObject(query)) {
705
- for (const name in query) {
706
- const value = query[name];
707
- if (value instanceof Date) {
708
- this.url.searchParams.set(name, value.toISOString());
709
- } else if (value != null) {
710
- this.url.searchParams.set(name, String(value));
514
+ else
515
+ throw new TypeError(`Unknown headers type. Got: ${t}`);
516
+ }
517
+ _applyQueryParams(t) {
518
+ if (t != null)
519
+ if (t instanceof Map || t instanceof URLSearchParams)
520
+ t.forEach((e, s) => {
521
+ this.url.searchParams.set(s, e);
522
+ });
523
+ else if (D(t))
524
+ for (const e in t) {
525
+ const s = t[e];
526
+ s instanceof Date ? this.url.searchParams.set(e, s.toISOString()) : s != null && this.url.searchParams.set(e, String(s));
711
527
  }
712
- }
713
- } else {
714
- throw new TypeError(`Unknown query params type. Got: ${query}`);
715
- }
528
+ else
529
+ throw new TypeError(`Unknown query params type. Got: ${t}`);
716
530
  }
717
531
  }
718
- class Runner {
719
- _middleware;
720
- _fetch;
721
- _request;
722
- _response;
723
- constructor(config) {
724
- this._middleware = config.middleware;
725
- this._fetch = config.fetch;
726
- this._request = new Request(config);
532
+ class Ee {
533
+ constructor(t) {
534
+ w(this, "_middleware");
535
+ w(this, "_fetch");
536
+ w(this, "_request");
537
+ w(this, "_response");
538
+ this._middleware = t.middleware, this._fetch = t.fetch, this._request = new ve(t);
727
539
  }
728
540
  async fetch() {
729
541
  if (this._middleware.length > 0) {
730
- const mount = (index = 0) => {
731
- const current = this._middleware[index];
732
- const next = this._middleware[index + 1] ? mount(index + 1) : this._handler.bind(this);
733
- return async () => current(this._request, async () => {
734
- await next();
735
- return this._response;
736
- });
542
+ const t = (e = 0) => {
543
+ const s = this._middleware[e], n = this._middleware[e + 1] ? t(e + 1) : this._handler.bind(this);
544
+ return async () => s(this._request, async () => (await n(), this._response));
737
545
  };
738
- await mount()();
739
- } else {
546
+ await t()();
547
+ } else
740
548
  await this._handler();
741
- }
742
- if (this._response.status < 200 || this._response.status >= 400) {
743
- throw new HTTPResponseError(this._response);
744
- }
549
+ if (this._response.status < 200 || this._response.status >= 400)
550
+ throw new be(this._response);
745
551
  return this._response;
746
552
  }
747
553
  // This is the function that performs the actual request after the final middleware.
748
554
  async _handler() {
749
- let reqBody;
750
- const req = this._request;
751
- if (!req.headers.has("content-type") && isObject(req.body)) {
752
- req.headers.set("content-type", "application/json");
753
- reqBody = JSON.stringify(req.body);
754
- } else {
755
- reqBody = req.body;
756
- }
757
- const fetched = await this._fetch(req.url.toString(), {
758
- method: req.method,
759
- headers: req.headers,
760
- body: reqBody
761
- });
762
- const contentType = fetched.headers.get("content-type");
763
- let body;
764
- if (contentType?.includes("application/json")) {
765
- body = await fetched.json();
766
- } else if (contentType?.includes("application/x-www-form-urlencoded")) {
767
- body = await fetched.formData();
768
- } else {
769
- body = await fetched.text();
770
- }
771
- this._response = {
772
- method: req.method,
773
- url: req.url,
774
- status: fetched.status,
775
- statusText: fetched.statusText,
776
- headers: fetched.headers,
777
- body
555
+ let t;
556
+ const e = this._request;
557
+ !e.headers.has("content-type") && D(e.body) ? (e.headers.set("content-type", "application/json"), t = JSON.stringify(e.body)) : t = e.body;
558
+ const s = await this._fetch(e.url.toString(), {
559
+ method: e.method,
560
+ headers: e.headers,
561
+ body: t
562
+ }), n = s.headers.get("content-type");
563
+ let r;
564
+ n != null && n.includes("application/json") ? r = await s.json() : n != null && n.includes("application/x-www-form-urlencoded") ? r = await s.formData() : r = await s.text(), this._response = {
565
+ method: e.method,
566
+ url: e.url,
567
+ status: s.status,
568
+ statusText: s.statusText,
569
+ headers: s.headers,
570
+ body: r
778
571
  };
779
572
  }
780
573
  }
781
-
782
- class Translation {
783
- dolla;
784
- config;
785
- #isLoaded = false;
786
- #templates = /* @__PURE__ */ new Map();
787
- constructor(config, dolla) {
788
- this.config = config;
789
- this.dolla = dolla;
574
+ var ft, A, q, bt, Wt;
575
+ class $e {
576
+ constructor(t, e) {
577
+ u(this, q);
578
+ w(this, "dolla");
579
+ w(this, "config");
580
+ u(this, ft, !1);
581
+ u(this, A, /* @__PURE__ */ new Map());
582
+ this.config = t, this.dolla = e;
790
583
  }
791
584
  async load() {
792
- let strings;
793
- if (!this.#isLoaded) {
794
- if (isObject(this.config.strings)) {
795
- strings = this.config.strings;
796
- } else if (isFunction(this.config.fetch)) {
797
- strings = await this.config.fetch();
798
- if (!isObject(strings)) {
799
- throw new Error(`Fetch function did not return an object of language strings: ${strings}`);
800
- }
801
- } else if (isString(this.config.path)) {
802
- const res = await fetch(this.config.path);
803
- if (res.ok) {
804
- const body = await res.json();
805
- if (isObject(body)) {
806
- strings = body;
807
- } else {
585
+ let t;
586
+ if (!a(this, ft)) {
587
+ if (D(this.config.strings))
588
+ t = this.config.strings;
589
+ else if (z(this.config.fetch)) {
590
+ if (t = await this.config.fetch(), !D(t))
591
+ throw new Error(`Fetch function did not return an object of language strings: ${t}`);
592
+ } else if (M(this.config.path)) {
593
+ const e = await fetch(this.config.path);
594
+ if (e.ok) {
595
+ const s = await e.json();
596
+ if (D(s))
597
+ t = s;
598
+ else
808
599
  throw new Error(
809
- `Language path '${this.config.path}' did not return an object of language strings: ${body}`
600
+ `Language path '${this.config.path}' did not return an object of language strings: ${s}`
810
601
  );
811
- }
812
- } else {
813
- throw new Error(`HTTP request failed.`);
814
- }
815
- }
816
- }
817
- if (strings) {
818
- const entries = this.#compile(strings);
819
- for (const entry of entries) {
820
- this.#templates.set(entry[0], entry[1]);
602
+ } else
603
+ throw new Error("HTTP request failed.");
821
604
  }
822
- } else {
823
- throw new Error(`Language could not be loaded.`);
824
605
  }
606
+ if (t) {
607
+ const e = f(this, q, bt).call(this, t);
608
+ for (const s of e)
609
+ a(this, A).set(s[0], s[1]);
610
+ } else
611
+ throw new Error("Language could not be loaded.");
825
612
  }
826
- getTemplate(selector) {
827
- return this.#templates.get(selector) ?? {
828
- segments: [{ type: 0 /* Static */, text: `[MISSING: ${selector}]` }]
613
+ getTemplate(t) {
614
+ return a(this, A).get(t) ?? {
615
+ segments: [{ type: 0, text: `[MISSING: ${t}]` }]
829
616
  };
830
617
  }
831
- hasTemplate(selector) {
832
- return this.#templates.has(selector);
618
+ hasTemplate(t) {
619
+ return a(this, A).has(t);
833
620
  }
834
- #compile(strings, path = []) {
835
- const entries = [];
836
- for (const key in strings) {
837
- switch (typeOf(strings[key])) {
838
- case "string":
839
- entries.push([[...path, key].join("."), this.#parseTemplate(strings[key])]);
840
- break;
841
- case "object":
842
- entries.push(...this.#compile(strings[key], [...path, key]));
843
- break;
844
- default:
845
- throw new Error(
846
- `Expected to find a string or object at ${[...path, key].join(".")}. Got: ${typeOf(strings[key])}`
847
- );
848
- }
621
+ }
622
+ ft = new WeakMap(), A = new WeakMap(), q = new WeakSet(), bt = function(t, e = []) {
623
+ const s = [];
624
+ for (const n in t)
625
+ switch (St(t[n])) {
626
+ case "string":
627
+ s.push([[...e, n].join("."), f(this, q, Wt).call(this, t[n])]);
628
+ break;
629
+ case "object":
630
+ s.push(...f(this, q, bt).call(this, t[n], [...e, n]));
631
+ break;
632
+ default:
633
+ throw new Error(
634
+ `Expected to find a string or object at ${[...e, n].join(".")}. Got: ${St(t[n])}`
635
+ );
849
636
  }
850
- return entries;
851
- }
852
- #parseTemplate(template) {
853
- let Loc;
854
- ((Loc2) => {
855
- Loc2[Loc2["Static"] = 0] = "Static";
856
- Loc2[Loc2["ValueName"] = 1] = "ValueName";
857
- Loc2[Loc2["FormatName"] = 2] = "FormatName";
858
- Loc2[Loc2["FormatOptionName"] = 3] = "FormatOptionName";
859
- Loc2[Loc2["FormatOptionValue"] = 4] = "FormatOptionValue";
860
- Loc2[Loc2["FormatOptionEnd"] = 5] = "FormatOptionEnd";
861
- })(Loc || (Loc = {}));
862
- const parsed = {
863
- segments: []
864
- };
865
- let buffer = "";
866
- let i = 0;
867
- let loc = 0 /* Static */;
868
- let segment;
869
- let format;
870
- let formatOptionName;
871
- const startSegment = () => {
872
- segment = {
873
- type: 1 /* Variable */,
874
- name: "",
875
- formats: []
876
- };
637
+ return s;
638
+ }, Wt = function(t) {
639
+ let e;
640
+ ((h) => {
641
+ h[h.Static = 0] = "Static", h[h.ValueName = 1] = "ValueName", h[h.FormatName = 2] = "FormatName", h[h.FormatOptionName = 3] = "FormatOptionName", h[h.FormatOptionValue = 4] = "FormatOptionValue", h[h.FormatOptionEnd = 5] = "FormatOptionEnd";
642
+ })(e || (e = {}));
643
+ const s = {
644
+ segments: []
645
+ };
646
+ let n = "", r = 0, o = 0, c, l, p;
647
+ const v = () => {
648
+ c = {
649
+ type: 1,
650
+ name: "",
651
+ formats: []
877
652
  };
878
- const startFormat = () => {
879
- format = {
880
- name: "",
881
- options: {}
882
- };
653
+ }, $ = () => {
654
+ l = {
655
+ name: "",
656
+ options: {}
883
657
  };
884
- while (i < template.length) {
885
- if (loc !== 0 /* Static */ && template[i] === " ") {
886
- i++;
887
- continue;
888
- }
889
- switch (loc) {
890
- case 0 /* Static */:
891
- if (template[i] === "{" && template[i + 1] === "{") {
892
- loc = 1 /* ValueName */;
893
- i += 2;
894
- if (buffer.length > 0) {
895
- parsed.segments.push({ type: 0 /* Static */, text: buffer });
896
- buffer = "";
897
- }
898
- startSegment();
899
- } else {
900
- buffer += template[i];
901
- i++;
902
- }
903
- break;
904
- case 1 /* ValueName */:
905
- if (template[i] === "|") {
906
- loc = 2 /* FormatName */;
907
- i += 1;
908
- segment.name = buffer;
909
- buffer = "";
910
- startFormat();
911
- } else if (template[i] === "}" && template[i + 1] === "}") {
912
- loc = 0 /* Static */;
913
- i += 2;
914
- segment.name = buffer;
915
- buffer = "";
916
- parsed.segments.push(segment);
917
- } else {
918
- buffer += template[i];
919
- i++;
920
- }
921
- break;
922
- case 2 /* FormatName */:
923
- if (template[i] === "(") {
924
- loc = 3 /* FormatOptionName */;
925
- i += 1;
926
- format.name = buffer;
927
- buffer = "";
928
- } else if (template[i] === "}" && template[i + 1] === "}") {
929
- loc = 0 /* Static */;
930
- i += 2;
931
- segment.formats.push(format);
932
- parsed.segments.push(segment);
933
- } else {
934
- buffer += template[i];
935
- i++;
936
- }
937
- break;
938
- case 3 /* FormatOptionName */:
939
- if (template[i] === ")") ; else if (template[i] === ":") {
940
- loc = 4 /* FormatOptionValue */;
941
- i += 1;
942
- formatOptionName = buffer;
943
- buffer = "";
944
- } else if (template[i] === "}" && template[i + 1] === "}") ; else {
945
- buffer += template[i];
946
- i++;
947
- }
948
- break;
949
- case 4 /* FormatOptionValue */:
950
- if (template[i] === ")") {
951
- loc = 5 /* FormatOptionEnd */;
952
- i += 1;
953
- format.options[formatOptionName] = buffer;
954
- buffer = "";
955
- segment.formats.push(format);
956
- } else if (template[i] === ",") {
957
- loc = 3 /* FormatOptionName */;
958
- i += 1;
959
- format.options[formatOptionName] = buffer;
960
- buffer = "";
961
- } else if (template[i] === "}" && template[i + 1] === "}") ; else {
962
- buffer += template[i];
963
- i++;
964
- }
965
- break;
966
- case 5 /* FormatOptionEnd */:
967
- if (template[i] === "|") {
968
- loc = 2 /* FormatName */;
969
- i += 1;
970
- startFormat();
971
- } else if (template[i] === "}" && template[i + 1] === "}") {
972
- loc = 0 /* Static */;
973
- i += 2;
974
- parsed.segments.push(segment);
975
- } else ;
976
- break;
977
- }
978
- }
979
- if (loc === 0 /* Static */ && buffer.length > 0) {
980
- parsed.segments.push({ type: 0 /* Static */, text: buffer });
981
- }
982
- return parsed;
658
+ };
659
+ for (; r < t.length; ) {
660
+ if (o !== 0 && t[r] === " ") {
661
+ r++;
662
+ continue;
663
+ }
664
+ switch (o) {
665
+ case 0:
666
+ t[r] === "{" && t[r + 1] === "{" ? (o = 1, r += 2, n.length > 0 && (s.segments.push({ type: 0, text: n }), n = ""), v()) : (n += t[r], r++);
667
+ break;
668
+ case 1:
669
+ t[r] === "|" ? (o = 2, r += 1, c.name = n, n = "", $()) : t[r] === "}" && t[r + 1] === "}" ? (o = 0, r += 2, c.name = n, n = "", s.segments.push(c)) : (n += t[r], r++);
670
+ break;
671
+ case 2:
672
+ t[r] === "(" ? (o = 3, r += 1, l.name = n, n = "") : t[r] === "}" && t[r + 1] === "}" ? (o = 0, r += 2, c.formats.push(l), s.segments.push(c)) : (n += t[r], r++);
673
+ break;
674
+ case 3:
675
+ t[r] === ")" || (t[r] === ":" ? (o = 4, r += 1, p = n, n = "") : t[r] === "}" && t[r + 1] === "}" || (n += t[r], r++));
676
+ break;
677
+ case 4:
678
+ t[r] === ")" ? (o = 5, r += 1, l.options[p] = n, n = "", c.formats.push(l)) : t[r] === "," ? (o = 3, r += 1, l.options[p] = n, n = "") : t[r] === "}" && t[r + 1] === "}" || (n += t[r], r++);
679
+ break;
680
+ case 5:
681
+ t[r] === "|" ? (o = 2, r += 1, $()) : t[r] === "}" && t[r + 1] === "}" && (o = 0, r += 2, s.segments.push(c));
682
+ break;
683
+ }
684
+ }
685
+ return o === 0 && n.length > 0 && s.segments.push({ type: 0, text: n }), s;
686
+ };
687
+ var X, P, g, Y, Z, tt, b, y, At, vt, Et, $t, Ht;
688
+ class ke {
689
+ constructor(t) {
690
+ u(this, y);
691
+ u(this, X);
692
+ u(this, P);
693
+ u(this, g, /* @__PURE__ */ new Map());
694
+ u(this, Y, []);
695
+ u(this, Z, /* @__PURE__ */ new Map());
696
+ u(this, tt, "auto");
697
+ u(this, b, Ut(""));
698
+ d(this, X, t), d(this, P, t.createLogger("Dolla.i18n")), this.addFormat("number", (e, s, n) => f(this, y, vt).call(this, Number(s), n)), this.addFormat("datetime", (e, s, n) => f(this, y, Et).call(this, s, n)), this.addFormat("list", (e, s, n) => f(this, y, $t).call(this, s, n)), t.beforeMount(async () => {
699
+ a(this, g).size > 0 && await this.setLocale(a(this, tt));
700
+ });
983
701
  }
984
- }
985
- class I18n {
986
- #dolla;
987
- #logger;
988
- #translations = /* @__PURE__ */ new Map();
989
- #cache = [];
990
- #formats = /* @__PURE__ */ new Map();
991
- #initialLocale = "auto";
992
- #locale = atom("");
993
702
  get locale() {
994
- return this.#locale;
995
- }
996
- constructor(dolla) {
997
- this.#dolla = dolla;
998
- this.#logger = dolla.createLogger("Dolla.i18n");
999
- this.addFormat("number", (_, value, options) => {
1000
- return this.#formatNumber(Number(value), options);
1001
- });
1002
- this.addFormat("datetime", (_, value, options) => {
1003
- return this.#formatDateTime(value, options);
1004
- });
1005
- this.addFormat("list", (_, value, options) => {
1006
- return this.#formatList(value, options);
1007
- });
1008
- dolla.beforeMount(async () => {
1009
- if (this.#translations.size > 0) {
1010
- await this.setLocale(this.#initialLocale);
1011
- }
1012
- });
703
+ return a(this, b);
1013
704
  }
1014
705
  get locales() {
1015
- return [...this.#translations.keys()];
1016
- }
1017
- setup(options) {
1018
- options.translations.forEach((entry) => {
1019
- this.#translations.set(entry.locale, new Translation(entry, this.#dolla));
1020
- });
1021
- if (options.locale && options.locale !== "auto") {
1022
- const isRegistered = options.translations.some((entry) => entry.locale === options.locale);
1023
- if (!isRegistered) {
1024
- throw new Error(`Initial locale '${options.locale}' is not registered in the locales array.`);
1025
- }
1026
- this.#initialLocale = options.locale;
1027
- }
1028
- this.#logger.info(
1029
- `${this.#translations.size} language${this.#translations.size === 1 ? "" : "s"} supported: '${[...this.#translations.keys()].join("', '")}'`
706
+ return [...a(this, g).keys()];
707
+ }
708
+ setup(t) {
709
+ if (t.translations.forEach((e) => {
710
+ a(this, g).set(e.locale, new $e(e, a(this, X)));
711
+ }), t.locale && t.locale !== "auto") {
712
+ if (!t.translations.some((s) => s.locale === t.locale))
713
+ throw new Error(`Initial locale '${t.locale}' is not registered in the locales array.`);
714
+ d(this, tt, t.locale);
715
+ }
716
+ a(this, P).info(
717
+ `${a(this, g).size} language${a(this, g).size === 1 ? "" : "s"} supported: '${[...a(this, g).keys()].join("', '")}'`
1030
718
  );
1031
719
  }
1032
- async setLocale(name) {
1033
- let realName;
1034
- if (name === "auto") {
1035
- let names = [];
1036
- if (typeof navigator !== "undefined") {
1037
- const nav = navigator;
1038
- if (nav.languages?.length > 0) {
1039
- names.push(...nav.languages);
1040
- } else if (nav.language) {
1041
- names.push(nav.language);
1042
- } else if (nav.browserLanguage) {
1043
- names.push(nav.browserLanguage);
1044
- } else if (nav.userLanguage) {
1045
- names.push(nav.userLanguage);
1046
- }
1047
- }
1048
- for (const name2 of names) {
1049
- if (this.#translations.has(name2)) {
1050
- realName = name2;
1051
- }
1052
- }
1053
- } else {
1054
- if (this.#translations.has(name)) {
1055
- realName = name;
1056
- }
1057
- }
1058
- if (realName == null) {
1059
- const firstLanguage = this.#translations.keys().next().value;
1060
- if (firstLanguage) {
1061
- realName = firstLanguage;
720
+ async setLocale(t) {
721
+ var n;
722
+ let e;
723
+ if (t === "auto") {
724
+ let r = [];
725
+ if (typeof navigator < "u") {
726
+ const o = navigator;
727
+ ((n = o.languages) == null ? void 0 : n.length) > 0 ? r.push(...o.languages) : o.language ? r.push(o.language) : o.browserLanguage ? r.push(o.browserLanguage) : o.userLanguage && r.push(o.userLanguage);
1062
728
  }
1063
- }
1064
- if (!realName || !this.#translations.has(realName)) {
1065
- throw new Error(`Locale '${name}' has no translation.`);
1066
- }
1067
- const translation = this.#translations.get(realName);
729
+ for (const o of r)
730
+ a(this, g).has(o) && (e = o);
731
+ } else
732
+ a(this, g).has(t) && (e = t);
733
+ if (e == null) {
734
+ const r = a(this, g).keys().next().value;
735
+ r && (e = r);
736
+ }
737
+ if (!e || !a(this, g).has(e))
738
+ throw new Error(`Locale '${t}' has no translation.`);
739
+ const s = a(this, g).get(e);
1068
740
  try {
1069
- await translation.load();
1070
- this.#cache = [];
1071
- this.#locale.value = realName;
1072
- this.#logger.info("set language to " + realName);
1073
- } catch (error) {
1074
- if (error instanceof Error) {
1075
- this.#logger.crash(error);
1076
- }
741
+ await s.load(), d(this, Y, []), a(this, b).value = e, a(this, P).info("set language to " + e);
742
+ } catch (r) {
743
+ r instanceof Error && a(this, P).crash(r);
1077
744
  }
1078
745
  }
1079
746
  /**
@@ -1085,71 +752,18 @@ class I18n {
1085
752
  * @example
1086
753
  * const $value = t("your.key.here", { count: 5 });
1087
754
  */
1088
- t(selector, options) {
1089
- if (this === void 0) {
755
+ t(t, e) {
756
+ if (this === void 0)
1090
757
  throw new Error(
1091
758
  `The 't' function cannot be destructured. If you need a standalone version you can import it like so: 'import { t } from "@manyducks.co/dolla"'`
1092
759
  );
1093
- }
1094
- return compose(() => {
1095
- const values = {};
1096
- for (const key in options) {
1097
- values[key] = get(options[key]);
1098
- }
1099
- return this.#getValue(get(this.#locale), selector, values);
760
+ return U(() => {
761
+ const s = {};
762
+ for (const n in e)
763
+ s[n] = E(e[n]);
764
+ return f(this, y, At).call(this, E(a(this, b)), t, s);
1100
765
  });
1101
766
  }
1102
- #getValue(locale, selector, options) {
1103
- const cached = this.#getCached(selector, options);
1104
- if (cached) return cached;
1105
- const translation = this.#translations.get(locale);
1106
- if (options.context != null) {
1107
- selector += "_" + options.context;
1108
- }
1109
- if (options.count != null) {
1110
- if (options.ordinal) {
1111
- const exact = `${selector}_ordinal_(=${options.count})`;
1112
- if (translation.hasTemplate(exact)) {
1113
- selector = exact;
1114
- } else {
1115
- selector += "_ordinal_" + new Intl.PluralRules(locale, { type: "ordinal" }).select(options.count);
1116
- }
1117
- } else {
1118
- const exact = `${selector}_(=${options.count})`;
1119
- if (translation.hasTemplate(exact)) {
1120
- selector = exact;
1121
- } else {
1122
- selector += "_" + new Intl.PluralRules(locale).select(options.count);
1123
- }
1124
- }
1125
- }
1126
- const template = translation.getTemplate(selector);
1127
- let output = "";
1128
- for (const segment of template.segments) {
1129
- if (segment.type === 0 /* Static */) {
1130
- output += segment.text;
1131
- } else if (segment.type === 1 /* Variable */) {
1132
- let value = resolve(options, segment.name);
1133
- const formats = options.formatOverrides?.[segment.name] ?? [...segment.formats];
1134
- if (segment.name === "count" && formats.length === 0) {
1135
- formats.push({ name: "number", options: {} });
1136
- }
1137
- for (const format of formats) {
1138
- const fn = this.#formats.get(format.name);
1139
- if (fn == null) {
1140
- const error = new Error(
1141
- `Failed to load format '${format.name}' when processing '${selector}', template: ${template}`
1142
- );
1143
- this.#logger.crash(error);
1144
- throw error;
1145
- }
1146
- value = fn(locale, value, format.options);
1147
- }
1148
- output += value;
1149
- }
1150
- }
1151
- return output;
1152
- }
1153
767
  /**
1154
768
  * Add a custom format callback.
1155
769
  *
@@ -1164,8 +778,8 @@ class I18n {
1164
778
  *
1165
779
  * t("greeting", {name: "world"}); // State<"Hello, WORLD!">
1166
780
  */
1167
- addFormat(name, callback) {
1168
- this.#formats.set(name, callback);
781
+ addFormat(t, e) {
782
+ a(this, Z).set(t, e);
1169
783
  }
1170
784
  /**
1171
785
  * Creates an `Intl.Collator` configured for the current locale.
@@ -1173,22 +787,16 @@ class I18n {
1173
787
  *
1174
788
  * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Collator/Collator#options
1175
789
  */
1176
- collator(options) {
1177
- return new Intl.Collator(this.#locale.value, options);
790
+ collator(t) {
791
+ return new Intl.Collator(a(this, b).value, t);
1178
792
  }
1179
793
  /**
1180
794
  * Formats a number for the current locale. Uses `Intl.NumberFormat` under the hood.
1181
795
  *
1182
796
  * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#options
1183
797
  */
1184
- number(count, options) {
1185
- return compose(() => {
1186
- get(this.#locale);
1187
- return this.#formatNumber(get(count), options);
1188
- });
1189
- }
1190
- #formatNumber(count, options) {
1191
- return new Intl.NumberFormat(this.#locale.value, options).format(count);
798
+ number(t, e) {
799
+ return U(() => (E(a(this, b)), f(this, y, vt).call(this, E(t), e)));
1192
800
  }
1193
801
  /**
1194
802
  * Formats a date for the current locale. Uses `Intl.DateTimeFormat` under the hood.
@@ -1199,14 +807,8 @@ class I18n {
1199
807
  * const date = new Date();
1200
808
  * const $formatted = Dolla.i18n.dateTime(date, { dateFormat: "short" });
1201
809
  */
1202
- dateTime(date, options) {
1203
- return compose(() => {
1204
- get(this.#locale);
1205
- return this.#formatDateTime(get(date), options);
1206
- });
1207
- }
1208
- #formatDateTime(date, options) {
1209
- return new Intl.DateTimeFormat(this.#locale.value, options).format(isString(date) ? new Date(date) : date);
810
+ dateTime(t, e) {
811
+ return U(() => (E(a(this, b)), f(this, y, Et).call(this, E(t), e)));
1210
812
  }
1211
813
  /**
1212
814
  * Formats a list for the current locale. Uses `Intl.ListFormat` under the hood.
@@ -1217,41 +819,69 @@ class I18n {
1217
819
  * const list = new Date();
1218
820
  * const $formatted = Dolla.i18n.list(list, { });
1219
821
  */
1220
- list(list, options) {
1221
- return compose(() => {
1222
- get(this.#locale);
1223
- return this.#formatList(get(list), options);
1224
- });
1225
- }
1226
- #formatList(list, options) {
1227
- return new Intl.ListFormat(this.#locale.value, options).format(list);
1228
- }
1229
- // relativeTime(): State<string> {
1230
- // }
1231
- #getCached(key, values) {
1232
- for (const entry of this.#cache) {
1233
- if (entry[0] === key && deepEqual(entry[1], values)) {
1234
- return entry[2];
1235
- }
1236
- }
822
+ list(t, e) {
823
+ return U(() => (E(a(this, b)), f(this, y, $t).call(this, E(t), e)));
1237
824
  }
1238
825
  }
1239
- function resolve(object, key) {
1240
- const parsed = String(key).split(/[\.\[\]]/).filter((part) => part.trim() !== "");
1241
- let value = object;
1242
- while (parsed.length > 0) {
1243
- const part = parsed.shift();
1244
- if (value != null) {
1245
- value = value[part];
826
+ X = new WeakMap(), P = new WeakMap(), g = new WeakMap(), Y = new WeakMap(), Z = new WeakMap(), tt = new WeakMap(), b = new WeakMap(), y = new WeakSet(), At = function(t, e, s) {
827
+ var l;
828
+ const n = f(this, y, Ht).call(this, e, s);
829
+ if (n) return n;
830
+ const r = a(this, g).get(t);
831
+ if (s.context != null && (e += "_" + s.context), s.count != null)
832
+ if (s.ordinal) {
833
+ const p = `${e}_ordinal_(=${s.count})`;
834
+ r.hasTemplate(p) ? e = p : e += "_ordinal_" + new Intl.PluralRules(t, { type: "ordinal" }).select(s.count);
1246
835
  } else {
1247
- value = void 0;
1248
- }
1249
- }
1250
- return value;
836
+ const p = `${e}_(=${s.count})`;
837
+ r.hasTemplate(p) ? e = p : e += "_" + new Intl.PluralRules(t).select(s.count);
838
+ }
839
+ const o = r.getTemplate(e);
840
+ let c = "";
841
+ for (const p of o.segments)
842
+ if (p.type === 0)
843
+ c += p.text;
844
+ else if (p.type === 1) {
845
+ let v = Re(s, p.name);
846
+ const $ = ((l = s.formatOverrides) == null ? void 0 : l[p.name]) ?? [...p.formats];
847
+ p.name === "count" && $.length === 0 && $.push({ name: "number", options: {} });
848
+ for (const h of $) {
849
+ const x = a(this, Z).get(h.name);
850
+ if (x == null) {
851
+ const k = new Error(
852
+ `Failed to load format '${h.name}' when processing '${e}', template: ${o}`
853
+ );
854
+ throw a(this, P).crash(k), k;
855
+ }
856
+ v = x(t, v, h.options);
857
+ }
858
+ c += v;
859
+ }
860
+ return c;
861
+ }, vt = function(t, e) {
862
+ return new Intl.NumberFormat(a(this, b).value, e).format(t);
863
+ }, Et = function(t, e) {
864
+ return new Intl.DateTimeFormat(a(this, b).value, e).format(M(t) ? new Date(t) : t);
865
+ }, $t = function(t, e) {
866
+ return new Intl.ListFormat(a(this, b).value, e).format(t);
867
+ }, // relativeTime(): State<string> {
868
+ // }
869
+ Ht = function(t, e) {
870
+ for (const s of a(this, Y))
871
+ if (s[0] === t && Jt(s[1], e))
872
+ return s[2];
873
+ };
874
+ function Re(i, t) {
875
+ const e = String(t).split(/[\.\[\]]/).filter((n) => n.trim() !== "");
876
+ let s = i;
877
+ for (; e.length > 0; ) {
878
+ const n = e.shift();
879
+ s != null ? s = s[n] : s = void 0;
880
+ }
881
+ return s;
1251
882
  }
1252
-
1253
- function DefaultCrashView(props) {
1254
- return html`
883
+ function _e(i) {
884
+ return Mt`
1255
885
  <div
1256
886
  style=${{
1257
887
  backgroundColor: "#880000",
@@ -1264,8 +894,8 @@ function DefaultCrashView(props) {
1264
894
  >
1265
895
  <h1 style=${{ marginBottom: "0.5rem" }}>The app has crashed</h1>
1266
896
  <p style=${{ marginBottom: "0.25rem" }}>
1267
- <span style=${{ fontFamily: "monospace" }}>${props.loggerName}</span>
1268
- ${cond(props.uid, html`<span style=${{ fontFamily: "monospace", opacity: 0.5 }}> [uid: ${props.uid}]</span>`)}
897
+ <span style=${{ fontFamily: "monospace" }}>${i.loggerName}</span>
898
+ ${Xt(i.uid, Mt`<span style=${{ fontFamily: "monospace", opacity: 0.5 }}> [uid: ${i.uid}]</span>`)}
1269
899
  ${" "}says:
1270
900
  </p>
1271
901
  <blockquote
@@ -1288,276 +918,250 @@ function DefaultCrashView(props) {
1288
918
  fontWeight: "bold"
1289
919
  }}
1290
920
  >
1291
- ${props.error.name}
921
+ ${i.error.name}
1292
922
  </span>
1293
- ${props.error.message}
923
+ ${i.error.message}
1294
924
  </blockquote>
1295
925
 
1296
926
  <p>Please see the browser console for details.</p>
1297
927
  </div>
1298
928
  `;
1299
929
  }
1300
-
1301
- class Dolla {
1302
- // TODO: Take these off the global Dolla object.
1303
- http;
1304
- i18n;
1305
- #isMounted = false;
1306
- #env = "production";
1307
- #rootElement;
1308
- #rootView;
1309
- #crashView = DefaultCrashView;
1310
- #router;
1311
- #beforeMountCallbacks = [];
1312
- #onMountCallbacks = [];
1313
- #beforeUnmountCallbacks = [];
1314
- #onUnmountCallbacks = [];
1315
- #rootElementContext = {
1316
- root: this,
1317
- stores: /* @__PURE__ */ new Map(),
1318
- viewName: "Dolla"
1319
- };
1320
- #loggles = {
1321
- info: "development",
1322
- log: "development",
1323
- warn: "development",
1324
- error: true
1325
- };
1326
- #match = createMatcher("*,-Dolla.*");
1327
- // Registration functions for modules.
1328
- // All modules will be registered before mount.
1329
- #modules = [];
930
+ var L, et, F, V, st, H, rt, nt, at, it, O, ot, lt, dt;
931
+ class Se {
1330
932
  constructor() {
1331
- this.http = new HTTP();
1332
- this.i18n = new I18n(this);
933
+ // TODO: Take these off the global Dolla object.
934
+ w(this, "http");
935
+ w(this, "i18n");
936
+ u(this, L, !1);
937
+ u(this, et, "production");
938
+ u(this, F);
939
+ u(this, V);
940
+ u(this, st, _e);
941
+ u(this, H);
942
+ u(this, rt, []);
943
+ u(this, nt, []);
944
+ u(this, at, []);
945
+ u(this, it, []);
946
+ u(this, O, {
947
+ root: this,
948
+ stores: /* @__PURE__ */ new Map(),
949
+ viewName: "Dolla"
950
+ });
951
+ u(this, ot, {
952
+ info: "development",
953
+ log: "development",
954
+ warn: "development",
955
+ error: !0
956
+ });
957
+ u(this, lt, xt("*,-Dolla.*"));
958
+ // Registration functions for modules.
959
+ // All modules will be registered before mount.
960
+ u(this, dt, []);
961
+ this.http = new ge(), this.i18n = new ke(this);
1333
962
  }
1334
963
  /**
1335
964
  * True when the app is connected to a DOM node and displayed to the user.
1336
965
  */
1337
966
  get isMounted() {
1338
- return this.#isMounted;
967
+ return a(this, L);
1339
968
  }
1340
969
  /**
1341
970
  * Get the current environment that this app is running in.
1342
971
  * Environment affects which log messages will print and how much debugging info is included in the DOM.
1343
972
  */
1344
973
  getEnv() {
1345
- return this.#env;
974
+ return a(this, et);
1346
975
  }
1347
976
  /**
1348
977
  * Sets the environment that this app is running in.
1349
978
  * Environment affects which log messages will print and how much debugging info is included in the DOM.
1350
979
  */
1351
- setEnv(value) {
1352
- this.#env = value;
980
+ setEnv(t) {
981
+ d(this, et, t);
1353
982
  }
1354
983
  /**
1355
984
  * Sets the view that will be shown when the `crash` method is called on any logger.
1356
985
  * When a crash is reported the app will be unmounted and replaced with this crash page.
1357
986
  */
1358
- setCrashView(view) {
1359
- this.#crashView = view;
987
+ setCrashView(t) {
988
+ d(this, st, t);
1360
989
  }
1361
990
  /**
1362
991
  * Returns the HTMLElement Dolla is mounted to. This will return undefined until Dolla.mount() is called.
1363
992
  */
1364
993
  getRootElement() {
1365
- return this.#rootElement;
994
+ return a(this, F);
1366
995
  }
1367
996
  /**
1368
997
  * Returns the top level view Dolla is rendering inside the root element. This will return undefined until Dolla.mount() is called.
1369
998
  */
1370
999
  getRootView() {
1371
- return this.#rootView;
1372
- }
1373
- provide(store, options) {
1374
- const instance = new Store(store, options);
1375
- const attached = instance.attach(this.#rootElementContext);
1376
- if (!attached) {
1377
- let name = store.name ? `'${store.name}'` : "this store";
1378
- console.warn(`An instance of ${name} was already attached to this context.`);
1379
- return this.get(store);
1380
- } else {
1381
- return instance.value;
1000
+ return a(this, V);
1001
+ }
1002
+ provide(t, e) {
1003
+ const s = new Yt(t, e);
1004
+ if (s.attach(a(this, O)))
1005
+ return s.value;
1006
+ {
1007
+ let r = t.name ? `'${t.name}'` : "this store";
1008
+ return console.warn(`An instance of ${r} was already attached to this context.`), this.get(t);
1382
1009
  }
1383
1010
  }
1384
1011
  /**
1385
1012
  * Gets the nearest instance of a store. Throws an error if the store isn't provided higher in the tree.
1386
1013
  */
1387
- get(store) {
1388
- if (isFunction(store)) {
1389
- const instance = this.#rootElementContext.stores.get(store);
1390
- if (instance == null) {
1391
- throw new StoreError(`Store not found on this context.`);
1392
- } else {
1393
- return instance.value;
1394
- }
1395
- } else {
1396
- throw new StoreError(`Invalid store.`);
1397
- }
1398
- }
1399
- async mount(target, root) {
1400
- if (this.#isMounted) {
1401
- throw new Error(`Dolla is already mounted.`);
1402
- }
1403
- if (isString(target)) {
1404
- const match = document.querySelector(target);
1405
- assertInstanceOf(HTMLElement, match, `Selector '${target}' did not match any element.`);
1406
- this.#rootElement = match;
1407
- } else {
1408
- assertInstanceOf(HTMLElement, target, "Expected an HTML element or a selector string. Got type: %t, value: %v");
1409
- this.#rootElement = target;
1410
- }
1411
- if (_isRouter(root)) {
1412
- this.#router = root;
1413
- }
1414
- const view = _isRouter(root) ? Passthrough : root;
1415
- const rootViewMarkup = createMarkup(view);
1416
- this.#rootView = this.constructView(rootViewMarkup.type, rootViewMarkup.props);
1417
- await Promise.all(this.#modules.map((register) => register()));
1418
- if (_isRouter(root)) {
1419
- await _mountRouter(root, this);
1420
- }
1421
- await Promise.all(this.#beforeMountCallbacks.map((callback) => callback()));
1422
- this.#rootView.mount(this.#rootElement);
1423
- this.#isMounted = true;
1424
- for (const store of this.#rootElementContext.stores.values()) {
1425
- store.handleMount();
1426
- }
1427
- for (const callback of this.#onMountCallbacks) {
1428
- callback();
1429
- }
1014
+ get(t) {
1015
+ if (z(t)) {
1016
+ const e = a(this, O).stores.get(t);
1017
+ if (e == null)
1018
+ throw new Tt("Store not found on this context.");
1019
+ return e.value;
1020
+ } else
1021
+ throw new Tt("Invalid store.");
1022
+ }
1023
+ async mount(t, e) {
1024
+ if (a(this, L))
1025
+ throw new Error("Dolla is already mounted.");
1026
+ if (M(t)) {
1027
+ const r = document.querySelector(t);
1028
+ Nt(HTMLElement, r, `Selector '${t}' did not match any element.`), d(this, F, r);
1029
+ } else
1030
+ Nt(HTMLElement, t, "Expected an HTML element or a selector string. Got type: %t, value: %v"), d(this, F, t);
1031
+ pt(e) && d(this, H, e);
1032
+ const s = pt(e) ? jt : e, n = Zt(s);
1033
+ d(this, V, this.constructView(n.type, n.props)), await Promise.all(a(this, dt).map((r) => r())), pt(e) && await le(e, this), await Promise.all(a(this, rt).map((r) => r())), a(this, V).mount(a(this, F)), d(this, L, !0);
1034
+ for (const r of a(this, O).stores.values())
1035
+ r.handleMount();
1036
+ for (const r of a(this, nt))
1037
+ r();
1430
1038
  }
1431
1039
  async unmount() {
1432
- if (!this.#isMounted) return;
1433
- await Promise.all(this.#beforeUnmountCallbacks.map((callback) => callback()));
1434
- this.#rootView?.unmount(false);
1435
- if (this.#router) {
1436
- await _unmountRouter(this.#router);
1437
- }
1438
- this.#isMounted = false;
1439
- for (const callback of this.#onUnmountCallbacks) {
1440
- callback();
1040
+ var t;
1041
+ if (a(this, L)) {
1042
+ await Promise.all(a(this, at).map((e) => e())), (t = a(this, V)) == null || t.unmount(!1), a(this, H) && await ce(a(this, H)), d(this, L, !1);
1043
+ for (const e of a(this, it))
1044
+ e();
1441
1045
  }
1442
1046
  }
1443
1047
  /**
1444
1048
  * Registers a `callback` to run after `Dolla.mount` is called, before the app is mounted. If `callback` returns a Promise,
1445
1049
  * it will be awaited before mounting finishes. Use this to perform initial setup before the app is displayed to the user.
1446
1050
  */
1447
- beforeMount(callback) {
1448
- this.#beforeMountCallbacks.push(callback);
1051
+ beforeMount(t) {
1052
+ a(this, rt).push(t);
1449
1053
  }
1450
1054
  /**
1451
1055
  * Registers a `callback` to run after the app is mounted.
1452
1056
  */
1453
- onMount(callback) {
1454
- this.#onMountCallbacks.push(callback);
1057
+ onMount(t) {
1058
+ a(this, nt).push(t);
1455
1059
  }
1456
1060
  /**
1457
1061
  * Registers a `callback` to run after `Dolla.unmount` is called, before the app is unmounted. If `callback` returns a Promise,
1458
1062
  * it will be awaited before unmounting finishes. Use this to perform cleanup.
1459
1063
  */
1460
- beforeUnmount(callback) {
1461
- this.#beforeUnmountCallbacks.push(callback);
1064
+ beforeUnmount(t) {
1065
+ a(this, at).push(t);
1462
1066
  }
1463
1067
  /**
1464
1068
  * Registers a `callback` to run after the app is unmounted.
1465
1069
  */
1466
- onUnmount(callback) {
1467
- this.#onUnmountCallbacks.push(callback);
1070
+ onUnmount(t) {
1071
+ a(this, it).push(t);
1468
1072
  }
1469
1073
  /**
1470
1074
  * Update log type toggles. Values that are not passed will remain unchanged.
1471
1075
  */
1472
- setLoggles(options) {
1473
- for (const key in options) {
1474
- const value = options[key];
1475
- if (value) {
1476
- this.#loggles[key] = value;
1477
- }
1478
- }
1479
- }
1480
- setLogFilter(filter) {
1481
- this.#match = createMatcher(filter);
1482
- }
1483
- createLogger(name, options) {
1484
- const _console = options?.console ?? getDefaultConsole();
1485
- const self = this;
1486
- const loggles = this.#loggles;
1487
- const bind = (method) => {
1488
- if (loggles[method] === false || isString(loggles[method]) && loggles[method] !== self.getEnv() || !this.#match(name)) {
1489
- return noOp;
1490
- } else {
1491
- let label = `%c${name}`;
1492
- if (options?.uid) {
1493
- label += ` %c[uid: %c${options.uid}%c]`;
1494
- } else {
1495
- label += `%c%c%c`;
1496
- }
1497
- return _console[method].bind(
1498
- _console,
1499
- label,
1500
- `color:${okhash(label)};font-weight:bold`,
1501
- `color:#777`,
1502
- `color:#aaa`,
1503
- `color:#777`
1076
+ setLoggles(t) {
1077
+ for (const e in t) {
1078
+ const s = t[e];
1079
+ s && (a(this, ot)[e] = s);
1080
+ }
1081
+ }
1082
+ setLogFilter(t) {
1083
+ d(this, lt, xt(t));
1084
+ }
1085
+ createLogger(t, e) {
1086
+ const s = (e == null ? void 0 : e.console) ?? Me(), n = this, r = a(this, ot), o = (c) => {
1087
+ if (r[c] === !1 || M(r[c]) && r[c] !== n.getEnv() || !a(this, lt).call(this, t))
1088
+ return re;
1089
+ {
1090
+ let l = `%c${t}`;
1091
+ return e != null && e.uid ? l += ` %c[uid: %c${e.uid}%c]` : l += "%c%c%c", s[c].bind(
1092
+ s,
1093
+ l,
1094
+ `color:${ne(l)};font-weight:bold`,
1095
+ "color:#777",
1096
+ "color:#aaa",
1097
+ "color:#777"
1504
1098
  );
1505
1099
  }
1506
1100
  };
1507
1101
  return {
1508
- setName(newName) {
1509
- name = newName;
1510
- return this;
1102
+ setName(c) {
1103
+ return t = c, this;
1511
1104
  },
1512
1105
  get info() {
1513
- return bind("info");
1106
+ return o("info");
1514
1107
  },
1515
1108
  get log() {
1516
- return bind("log");
1109
+ return o("log");
1517
1110
  },
1518
1111
  get warn() {
1519
- return bind("warn");
1112
+ return o("warn");
1520
1113
  },
1521
1114
  get error() {
1522
- return bind("error");
1115
+ return o("error");
1523
1116
  },
1524
- crash(error) {
1525
- if (self.isMounted) {
1526
- self.unmount();
1527
- const crashPage = self.constructView(self.#crashView, {
1528
- error,
1529
- loggerName: name,
1530
- uid: options?.uid
1531
- });
1532
- crashPage.mount(self.#rootElement);
1533
- }
1117
+ crash(c) {
1118
+ n.isMounted && (n.unmount(), n.constructView(a(n, st), {
1119
+ error: c,
1120
+ loggerName: t,
1121
+ uid: e == null ? void 0 : e.uid
1122
+ }).mount(a(n, F)));
1534
1123
  }
1535
1124
  };
1536
1125
  }
1537
1126
  /**
1538
1127
  *
1539
1128
  */
1540
- constructView(view, props, children = []) {
1541
- return new View(this.#rootElementContext, view, props, children);
1129
+ constructView(t, e, s = []) {
1130
+ return new te(a(this, O), t, e, s);
1542
1131
  }
1543
1132
  /**
1544
1133
  *
1545
1134
  */
1546
- constructMarkup(markup) {
1547
- return groupElements(constructMarkup(this.#rootElementContext, markup));
1135
+ constructMarkup(t) {
1136
+ return ee(se(a(this, O), t));
1548
1137
  }
1549
1138
  }
1550
- function getDefaultConsole() {
1551
- if (typeof window !== "undefined" && window.console) {
1139
+ L = new WeakMap(), et = new WeakMap(), F = new WeakMap(), V = new WeakMap(), st = new WeakMap(), H = new WeakMap(), rt = new WeakMap(), nt = new WeakMap(), at = new WeakMap(), it = new WeakMap(), O = new WeakMap(), ot = new WeakMap(), lt = new WeakMap(), dt = new WeakMap();
1140
+ function Me() {
1141
+ if (typeof window < "u" && window.console)
1552
1142
  return window.console;
1553
- }
1554
- if (typeof global !== "undefined" && global.console) {
1143
+ if (typeof global < "u" && global.console)
1555
1144
  return global.console;
1556
- }
1557
1145
  }
1558
-
1559
- const dolla = new Dolla();
1560
- const t = dolla.i18n.t.bind(dolla.i18n);
1561
-
1562
- export { atom, compose, cond, createMarkup, createRouter, deepEqual, dolla as default, get, html, ref, shallowEqual, t };
1146
+ const Pt = new Se(), Le = Pt.i18n.t.bind(Pt.i18n);
1147
+ export {
1148
+ Ut as atom,
1149
+ U as compose,
1150
+ Xt as cond,
1151
+ Zt as createMarkup,
1152
+ Pe as createRouter,
1153
+ Jt as deepEqual,
1154
+ Pt as default,
1155
+ Ue as effect,
1156
+ E as get,
1157
+ Mt as html,
1158
+ je as list,
1159
+ Ce as peek,
1160
+ Ie as portal,
1161
+ Ne as ref,
1162
+ Ve as set,
1163
+ _t as shallowEqual,
1164
+ De as strictEqual,
1165
+ Le as t
1166
+ };
1563
1167
  //# sourceMappingURL=index.js.map