@async/framework 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/README.md +153 -24
- package/examples/cache/index.html +3 -3
- package/examples/components/main.js +2 -2
- package/examples/counter/index.html +2 -2
- package/examples/partials/index.html +2 -2
- package/examples/product/index.html +9 -9
- package/examples/router/index.html +2 -2
- package/examples/router/main.js +2 -2
- package/examples/server-call/index.html +2 -2
- package/examples/ssr/index.html +1 -1
- package/examples/ssr/main.js +2 -2
- package/examples/streaming/index.html +2 -2
- package/examples/streaming/main.js +2 -2
- package/package.json +9 -2
- package/src/app.js +73 -53
- package/src/attributes.js +50 -0
- package/src/cache.js +31 -16
- package/src/component.js +11 -4
- package/src/handlers.js +24 -5
- package/src/index.js +2 -0
- package/src/loader.js +71 -45
- package/src/partials.js +11 -4
- package/src/registry-store.js +257 -0
- package/src/router.js +42 -3
- package/src/server.js +12 -4
- package/src/signals.js +32 -10
package/src/app.js
CHANGED
|
@@ -6,17 +6,21 @@ import { createPartialRegistry } from "./partials.js";
|
|
|
6
6
|
import { createRouteRegistry, createRouter } from "./router.js";
|
|
7
7
|
import { createServerRegistry } from "./server.js";
|
|
8
8
|
import { createSignal, createSignalRegistry } from "./signals.js";
|
|
9
|
+
import { createRegistryStore } from "./registry-store.js";
|
|
10
|
+
import { attributeName, normalizeAttributeConfig } from "./attributes.js";
|
|
9
11
|
|
|
10
12
|
const registryTypes = new Set(["signal", "handler", "server", "partial", "route", "component"]);
|
|
11
13
|
|
|
12
14
|
export function defineApp(initial) {
|
|
13
|
-
const
|
|
15
|
+
const registry = createRegistryStore(undefined, { target: "browser" });
|
|
14
16
|
const runtimes = new Set();
|
|
15
17
|
|
|
16
18
|
const app = {
|
|
19
|
+
registry,
|
|
20
|
+
|
|
17
21
|
use(typeOrModule, entries) {
|
|
18
22
|
const normalized = normalizeUse(typeOrModule, entries);
|
|
19
|
-
appendDeclarations(
|
|
23
|
+
appendDeclarations(registry, normalized);
|
|
20
24
|
for (const runtime of runtimes) {
|
|
21
25
|
runtime._applyUse(normalized);
|
|
22
26
|
}
|
|
@@ -24,7 +28,7 @@ export function defineApp(initial) {
|
|
|
24
28
|
},
|
|
25
29
|
|
|
26
30
|
snapshot() {
|
|
27
|
-
return
|
|
31
|
+
return registry.rawSnapshot();
|
|
28
32
|
},
|
|
29
33
|
|
|
30
34
|
start(options = {}) {
|
|
@@ -53,15 +57,16 @@ export function defineApp(initial) {
|
|
|
53
57
|
export function createApp(appOrDefinition = Async, options = {}) {
|
|
54
58
|
const app = isAppHub(appOrDefinition) ? appOrDefinition : defineApp(appOrDefinition ?? {});
|
|
55
59
|
const target = options.target ?? "browser";
|
|
56
|
-
const
|
|
57
|
-
const
|
|
58
|
-
const
|
|
59
|
-
const
|
|
60
|
-
const
|
|
61
|
-
const
|
|
62
|
-
const
|
|
63
|
-
const
|
|
64
|
-
const
|
|
60
|
+
const attributes = normalizeAttributeConfig(options.attributes);
|
|
61
|
+
const registry = options.registry ?? app.registry.view({ target });
|
|
62
|
+
const signals = options.signals ?? createSignalRegistry(undefined, { registry, type: "signal" });
|
|
63
|
+
const handlers = options.handlers ?? createHandlerRegistry(undefined, { registry, type: "handler" });
|
|
64
|
+
const serverCache = createCacheRegistry(undefined, { registry, type: "cache.server" });
|
|
65
|
+
const browserCache = createCacheRegistry(undefined, { registry, type: "cache.browser" });
|
|
66
|
+
const server = options.server ?? createServerRegistry(undefined, { registry, type: "server" });
|
|
67
|
+
const partials = options.partials ?? createPartialRegistry(undefined, { registry, type: "partial" });
|
|
68
|
+
const routes = options.routes ?? createRouteRegistry(undefined, { registry, type: "route" });
|
|
69
|
+
const components = options.components ?? createComponentRegistry(undefined, { registry, type: "component" });
|
|
65
70
|
let loader = options.loader;
|
|
66
71
|
let router = options.router;
|
|
67
72
|
let detach = () => {};
|
|
@@ -73,6 +78,7 @@ export function createApp(appOrDefinition = Async, options = {}) {
|
|
|
73
78
|
|
|
74
79
|
const runtime = {
|
|
75
80
|
app,
|
|
81
|
+
registry,
|
|
76
82
|
target,
|
|
77
83
|
signals,
|
|
78
84
|
handlers,
|
|
@@ -85,6 +91,7 @@ export function createApp(appOrDefinition = Async, options = {}) {
|
|
|
85
91
|
},
|
|
86
92
|
loader,
|
|
87
93
|
router,
|
|
94
|
+
attributes,
|
|
88
95
|
|
|
89
96
|
start() {
|
|
90
97
|
assertActive();
|
|
@@ -99,7 +106,8 @@ export function createApp(appOrDefinition = Async, options = {}) {
|
|
|
99
106
|
signals,
|
|
100
107
|
handlers,
|
|
101
108
|
server,
|
|
102
|
-
cache: browserCache
|
|
109
|
+
cache: browserCache,
|
|
110
|
+
attributes
|
|
103
111
|
});
|
|
104
112
|
runtime.loader = loader;
|
|
105
113
|
|
|
@@ -121,7 +129,8 @@ export function createApp(appOrDefinition = Async, options = {}) {
|
|
|
121
129
|
cache: browserCache,
|
|
122
130
|
partials,
|
|
123
131
|
fetch: options.fetch,
|
|
124
|
-
routeEndpoint: options.routeEndpoint
|
|
132
|
+
routeEndpoint: options.routeEndpoint,
|
|
133
|
+
attributes
|
|
125
134
|
});
|
|
126
135
|
runtime.router = router;
|
|
127
136
|
loader.router = router;
|
|
@@ -148,7 +157,7 @@ export function createApp(appOrDefinition = Async, options = {}) {
|
|
|
148
157
|
const matched = routes.match(url);
|
|
149
158
|
if (!matched) {
|
|
150
159
|
return {
|
|
151
|
-
html: renderDocument("", { status: 404, signals, browserCache, boundary: options.boundary ?? "route" }),
|
|
160
|
+
html: renderDocument("", { status: 404, signals, browserCache, boundary: options.boundary ?? "route", attributes }),
|
|
152
161
|
status: 404,
|
|
153
162
|
signals: signals.snapshot(),
|
|
154
163
|
cache: { browser: browserCache.snapshot() }
|
|
@@ -182,7 +191,7 @@ export function createApp(appOrDefinition = Async, options = {}) {
|
|
|
182
191
|
|
|
183
192
|
const status = result.status ?? 200;
|
|
184
193
|
return {
|
|
185
|
-
html: renderDocument(result.html, { status, signals, browserCache, boundary: result.boundary ?? options.boundary ?? "route" }),
|
|
194
|
+
html: renderDocument(result.html, { status, signals, browserCache, boundary: result.boundary ?? options.boundary ?? "route", attributes }),
|
|
186
195
|
status,
|
|
187
196
|
signals: signals.snapshot(),
|
|
188
197
|
cache: { browser: browserCache.snapshot() }
|
|
@@ -233,16 +242,25 @@ export function createApp(appOrDefinition = Async, options = {}) {
|
|
|
233
242
|
export const Async = defineApp();
|
|
234
243
|
|
|
235
244
|
function applyUseToRuntime(runtime, normalized) {
|
|
236
|
-
runtime.signals.
|
|
237
|
-
runtime.handlers.
|
|
238
|
-
|
|
239
|
-
|
|
245
|
+
applyRegistryUse(runtime.signals, runtime.registry, normalized.signal);
|
|
246
|
+
applyRegistryUse(runtime.handlers, runtime.registry, normalized.handler);
|
|
247
|
+
applyRegistryUse(runtime.server, runtime.registry, normalized.server);
|
|
248
|
+
applyRegistryUse(runtime.partials, runtime.registry, normalized.partial);
|
|
249
|
+
applyRegistryUse(runtime.routes, runtime.registry, normalized.route);
|
|
250
|
+
applyRegistryUse(runtime.components, runtime.registry, normalized.component);
|
|
251
|
+
applyRegistryUse(runtime.browser.cache, runtime.registry, normalized.cache.browser);
|
|
252
|
+
applyRegistryUse(runtime.server.cache, runtime.registry, normalized.cache.server);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function applyRegistryUse(registry, runtimeRegistry, entries) {
|
|
256
|
+
if (!entries || Object.keys(entries).length === 0) {
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
if (registry?.registry === runtimeRegistry) {
|
|
260
|
+
registry._adoptMany?.(entries);
|
|
261
|
+
return;
|
|
240
262
|
}
|
|
241
|
-
|
|
242
|
-
runtime.routes.registerMany(normalized.route);
|
|
243
|
-
runtime.components.registerMany(normalized.component);
|
|
244
|
-
runtime.browser.cache.registerMany(normalized.cache.browser);
|
|
245
|
-
runtime.server.cache.registerMany(normalized.cache.server);
|
|
263
|
+
registry?.registerMany?.(entries);
|
|
246
264
|
}
|
|
247
265
|
|
|
248
266
|
function emptyDeclarations() {
|
|
@@ -267,7 +285,7 @@ function normalizeUse(typeOrModule, entries) {
|
|
|
267
285
|
if (!registryTypes.has(typeOrModule)) {
|
|
268
286
|
throw new Error(`Unknown Async registry type "${typeOrModule}".`);
|
|
269
287
|
}
|
|
270
|
-
normalized[typeOrModule] =
|
|
288
|
+
normalized[typeOrModule] = normalizeEntries(typeOrModule, entries);
|
|
271
289
|
return normalized;
|
|
272
290
|
}
|
|
273
291
|
|
|
@@ -284,7 +302,7 @@ function normalizeUse(typeOrModule, entries) {
|
|
|
284
302
|
if (!registryTypes.has(type)) {
|
|
285
303
|
throw new Error(`Unknown Async registry type "${type}".`);
|
|
286
304
|
}
|
|
287
|
-
normalized[type] =
|
|
305
|
+
normalized[type] = normalizeEntries(type, value);
|
|
288
306
|
}
|
|
289
307
|
|
|
290
308
|
return normalized;
|
|
@@ -292,38 +310,20 @@ function normalizeUse(typeOrModule, entries) {
|
|
|
292
310
|
|
|
293
311
|
function appendDeclarations(target, source) {
|
|
294
312
|
for (const type of registryTypes) {
|
|
295
|
-
addEntries(target
|
|
313
|
+
addEntries(target, type, source[type]);
|
|
296
314
|
}
|
|
297
|
-
addEntries(target
|
|
298
|
-
addEntries(target
|
|
315
|
+
addEntries(target, "cache.browser", source.cache.browser);
|
|
316
|
+
addEntries(target, "cache.server", source.cache.server);
|
|
299
317
|
}
|
|
300
318
|
|
|
301
|
-
function addEntries(
|
|
319
|
+
function addEntries(registry, type, source) {
|
|
302
320
|
for (const [id, value] of Object.entries(source ?? {})) {
|
|
303
|
-
|
|
304
|
-
throw new Error(`${label} "${id}" is already registered.`);
|
|
305
|
-
}
|
|
306
|
-
target[id] = value;
|
|
321
|
+
registry.register(type, id, value);
|
|
307
322
|
}
|
|
308
323
|
}
|
|
309
324
|
|
|
310
|
-
function cloneDeclarations(source) {
|
|
311
|
-
return {
|
|
312
|
-
signal: { ...source.signal },
|
|
313
|
-
handler: { ...source.handler },
|
|
314
|
-
server: { ...source.server },
|
|
315
|
-
partial: { ...source.partial },
|
|
316
|
-
route: { ...source.route },
|
|
317
|
-
component: { ...source.component },
|
|
318
|
-
cache: {
|
|
319
|
-
browser: { ...source.cache.browser },
|
|
320
|
-
server: { ...source.cache.server }
|
|
321
|
-
}
|
|
322
|
-
};
|
|
323
|
-
}
|
|
324
|
-
|
|
325
325
|
function isAppHub(value) {
|
|
326
|
-
return Boolean(value && typeof value.use === "function" && typeof value.snapshot === "function");
|
|
326
|
+
return Boolean(value && typeof value.use === "function" && typeof value.snapshot === "function" && value.registry);
|
|
327
327
|
}
|
|
328
328
|
|
|
329
329
|
function applySnapshot(signals, browserCache, snapshot = {}) {
|
|
@@ -353,6 +353,24 @@ function attachServerCache(server, cache) {
|
|
|
353
353
|
}
|
|
354
354
|
}
|
|
355
355
|
|
|
356
|
+
function normalizeEntries(type, entries = {}) {
|
|
357
|
+
if (type !== "signal") {
|
|
358
|
+
return { ...(entries ?? {}) };
|
|
359
|
+
}
|
|
360
|
+
const normalized = {};
|
|
361
|
+
for (const [id, value] of Object.entries(entries ?? {})) {
|
|
362
|
+
normalized[id] = normalizeSignalDeclaration(value);
|
|
363
|
+
}
|
|
364
|
+
return normalized;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
function normalizeSignalDeclaration(value) {
|
|
368
|
+
if (value && typeof value === "object" && typeof value.subscribe === "function") {
|
|
369
|
+
return value;
|
|
370
|
+
}
|
|
371
|
+
return createSignal(value);
|
|
372
|
+
}
|
|
373
|
+
|
|
356
374
|
function isLocalServerRegistry(server) {
|
|
357
375
|
return typeof server?.registerMany === "function";
|
|
358
376
|
}
|
|
@@ -361,14 +379,16 @@ function shouldStartRouter(routes, options) {
|
|
|
361
379
|
return Boolean(options.routerOptions || options.mode || routes.entries().length > 0);
|
|
362
380
|
}
|
|
363
381
|
|
|
364
|
-
function renderDocument(routeHtml, { signals, browserCache, boundary }) {
|
|
382
|
+
function renderDocument(routeHtml, { signals, browserCache, boundary, attributes }) {
|
|
365
383
|
const snapshot = {
|
|
366
384
|
signals: signals.snapshot(),
|
|
367
385
|
cache: {
|
|
368
386
|
browser: browserCache.snapshot()
|
|
369
387
|
}
|
|
370
388
|
};
|
|
371
|
-
|
|
389
|
+
const boundaryAttr = attributeName(attributes, "async", "boundary");
|
|
390
|
+
const snapshotAttr = attributeName(attributes, "async", "snapshot");
|
|
391
|
+
return `<section ${boundaryAttr}="${escapeAttribute(boundary)}">${routeHtml ?? ""}</section><script type="application/json" ${snapshotAttr}>${escapeScriptJson(snapshot)}</script>`;
|
|
372
392
|
}
|
|
373
393
|
|
|
374
394
|
function escapeAttribute(value) {
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
const defaultPrefixes = Object.freeze({
|
|
2
|
+
async: ["async:"],
|
|
3
|
+
signal: ["signal:"],
|
|
4
|
+
on: ["on:"]
|
|
5
|
+
});
|
|
6
|
+
|
|
7
|
+
export function defineAttributeConfig(config = {}) {
|
|
8
|
+
return normalizeAttributeConfig(config);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function normalizeAttributeConfig(config = {}) {
|
|
12
|
+
return {
|
|
13
|
+
async: normalizePrefixes(config.async, defaultPrefixes.async),
|
|
14
|
+
signal: normalizePrefixes(config.signal, defaultPrefixes.signal),
|
|
15
|
+
on: normalizePrefixes(config.on, defaultPrefixes.on)
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function attributeName(attributes, type, name) {
|
|
20
|
+
return normalizeAttributeConfig(attributes)[type][0] + name;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function readAttribute(element, attributes, type, name) {
|
|
24
|
+
for (const prefix of normalizeAttributeConfig(attributes)[type]) {
|
|
25
|
+
const attr = `${prefix}${name}`;
|
|
26
|
+
if (element.hasAttribute?.(attr)) {
|
|
27
|
+
return element.getAttribute(attr);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function matchAttribute(name, attributes, type) {
|
|
34
|
+
for (const prefix of normalizeAttributeConfig(attributes)[type]) {
|
|
35
|
+
if (name.startsWith(prefix)) {
|
|
36
|
+
return name.slice(prefix.length);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function normalizePrefixes(value, fallback) {
|
|
43
|
+
const prefixes = value == null ? fallback : Array.isArray(value) ? value : [value];
|
|
44
|
+
return prefixes.map((prefix) => {
|
|
45
|
+
if (typeof prefix !== "string" || prefix.length === 0) {
|
|
46
|
+
throw new TypeError("Attribute prefixes must be non-empty strings.");
|
|
47
|
+
}
|
|
48
|
+
return prefix;
|
|
49
|
+
});
|
|
50
|
+
}
|
package/src/cache.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { attachRegistryInspection, createRegistryStore } from "./registry-store.js";
|
|
2
|
+
|
|
1
3
|
const cacheDefinitionKind = Symbol.for("@async/framework.cacheDefinition");
|
|
2
4
|
|
|
3
5
|
export function defineCache(options = {}) {
|
|
@@ -9,11 +11,12 @@ export function defineCache(options = {}) {
|
|
|
9
11
|
};
|
|
10
12
|
}
|
|
11
13
|
|
|
12
|
-
export function createCacheRegistry(initialMap = {}, { now = () => Date.now() } = {}) {
|
|
13
|
-
const
|
|
14
|
-
const
|
|
14
|
+
export function createCacheRegistry(initialMap = {}, { now = () => Date.now(), registry, type = "cache.browser" } = {}) {
|
|
15
|
+
const registryStore = registry ?? createRegistryStore();
|
|
16
|
+
const definitions = registryStore._map(type);
|
|
17
|
+
const entries = registryStore._map(`${type}.entries`);
|
|
15
18
|
|
|
16
|
-
const
|
|
19
|
+
const registryApi = attachRegistryInspection({
|
|
17
20
|
register(id, definition = defineCache()) {
|
|
18
21
|
assertId(id);
|
|
19
22
|
const normalized = normalizeDefinition(definition);
|
|
@@ -26,9 +29,9 @@ export function createCacheRegistry(initialMap = {}, { now = () => Date.now() }
|
|
|
26
29
|
|
|
27
30
|
registerMany(map) {
|
|
28
31
|
for (const [id, definition] of Object.entries(map ?? {})) {
|
|
29
|
-
|
|
32
|
+
registryApi.register(id, definition);
|
|
30
33
|
}
|
|
31
|
-
return
|
|
34
|
+
return registryApi;
|
|
32
35
|
},
|
|
33
36
|
|
|
34
37
|
resolve(id) {
|
|
@@ -64,12 +67,12 @@ export function createCacheRegistry(initialMap = {}, { now = () => Date.now() }
|
|
|
64
67
|
if (typeof fn !== "function") {
|
|
65
68
|
throw new TypeError("cache.getOrSet(key, fn) requires a function.");
|
|
66
69
|
}
|
|
67
|
-
const cached =
|
|
70
|
+
const cached = registryApi.get(key);
|
|
68
71
|
if (cached !== undefined) {
|
|
69
72
|
return cached;
|
|
70
73
|
}
|
|
71
74
|
const value = await fn();
|
|
72
|
-
|
|
75
|
+
registryApi.set(key, value, options);
|
|
73
76
|
return value;
|
|
74
77
|
},
|
|
75
78
|
|
|
@@ -81,20 +84,20 @@ export function createCacheRegistry(initialMap = {}, { now = () => Date.now() }
|
|
|
81
84
|
clear(prefix) {
|
|
82
85
|
if (prefix === undefined) {
|
|
83
86
|
entries.clear();
|
|
84
|
-
return
|
|
87
|
+
return registryApi;
|
|
85
88
|
}
|
|
86
89
|
for (const key of [...entries.keys()]) {
|
|
87
90
|
if (key.startsWith(prefix)) {
|
|
88
91
|
entries.delete(key);
|
|
89
92
|
}
|
|
90
93
|
}
|
|
91
|
-
return
|
|
94
|
+
return registryApi;
|
|
92
95
|
},
|
|
93
96
|
|
|
94
97
|
snapshot() {
|
|
95
98
|
const snapshot = {};
|
|
96
99
|
for (const [key] of entries) {
|
|
97
|
-
const value =
|
|
100
|
+
const value = registryApi.get(key);
|
|
98
101
|
if (value !== undefined) {
|
|
99
102
|
snapshot[key] = value;
|
|
100
103
|
}
|
|
@@ -104,14 +107,26 @@ export function createCacheRegistry(initialMap = {}, { now = () => Date.now() }
|
|
|
104
107
|
|
|
105
108
|
restore(snapshot = {}) {
|
|
106
109
|
for (const [key, value] of Object.entries(snapshot ?? {})) {
|
|
107
|
-
|
|
110
|
+
registryApi.set(key, value);
|
|
108
111
|
}
|
|
109
|
-
return
|
|
112
|
+
return registryApi;
|
|
113
|
+
},
|
|
114
|
+
|
|
115
|
+
entryKeys() {
|
|
116
|
+
return [...entries.keys()];
|
|
117
|
+
},
|
|
118
|
+
|
|
119
|
+
entryEntries() {
|
|
120
|
+
return registryStore.entries(`${type}.entries`);
|
|
121
|
+
},
|
|
122
|
+
|
|
123
|
+
_adoptMany() {
|
|
124
|
+
return registryApi;
|
|
110
125
|
}
|
|
111
|
-
};
|
|
126
|
+
}, registryStore, type);
|
|
112
127
|
|
|
113
|
-
|
|
114
|
-
return
|
|
128
|
+
registryApi.registerMany(initialMap);
|
|
129
|
+
return registryApi;
|
|
115
130
|
|
|
116
131
|
function resolvePolicy(key, explicitId) {
|
|
117
132
|
if (explicitId !== undefined) {
|
package/src/component.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { rawHtml, renderTemplate } from "./html.js";
|
|
2
|
+
import { attachRegistryInspection, createRegistryStore } from "./registry-store.js";
|
|
2
3
|
|
|
3
4
|
const componentKind = Symbol.for("@async/framework.component");
|
|
4
5
|
let componentCounter = 0;
|
|
@@ -16,10 +17,12 @@ export function defineComponent(fn) {
|
|
|
16
17
|
|
|
17
18
|
export const component = defineComponent;
|
|
18
19
|
|
|
19
|
-
export function createComponentRegistry(initialMap = {}) {
|
|
20
|
-
const
|
|
20
|
+
export function createComponentRegistry(initialMap = {}, options = {}) {
|
|
21
|
+
const registryStore = options.registry ?? createRegistryStore();
|
|
22
|
+
const type = options.type ?? "component";
|
|
23
|
+
const entries = registryStore._map(type);
|
|
21
24
|
|
|
22
|
-
const registry = {
|
|
25
|
+
const registry = attachRegistryInspection({
|
|
23
26
|
register(id, Component) {
|
|
24
27
|
if (typeof id !== "string" || id.length === 0) {
|
|
25
28
|
throw new TypeError("Component id must be a non-empty string.");
|
|
@@ -46,8 +49,12 @@ export function createComponentRegistry(initialMap = {}) {
|
|
|
46
49
|
throw new TypeError("Component id must be a non-empty string.");
|
|
47
50
|
}
|
|
48
51
|
return entries.get(id);
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
_adoptMany() {
|
|
55
|
+
return registry;
|
|
49
56
|
}
|
|
50
|
-
};
|
|
57
|
+
}, registryStore, type);
|
|
51
58
|
|
|
52
59
|
registry.registerMany(initialMap);
|
|
53
60
|
return registry;
|
package/src/handlers.js
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
resolveServerCommandArguments,
|
|
5
5
|
unwrapServerResult
|
|
6
6
|
} from "./server.js";
|
|
7
|
+
import { attachRegistryInspection, createRegistryStore } from "./registry-store.js";
|
|
7
8
|
|
|
8
9
|
const builtInTokens = new Set(["preventDefault", "stopPropagation", "stopImmediatePropagation"]);
|
|
9
10
|
const builtInHandlers = {
|
|
@@ -18,10 +19,12 @@ const builtInHandlers = {
|
|
|
18
19
|
}
|
|
19
20
|
};
|
|
20
21
|
|
|
21
|
-
export function createHandlerRegistry(initialMap = {}) {
|
|
22
|
-
const
|
|
22
|
+
export function createHandlerRegistry(initialMap = {}, options = {}) {
|
|
23
|
+
const registryStore = options.registry ?? createRegistryStore();
|
|
24
|
+
const type = options.type ?? "handler";
|
|
25
|
+
const handlers = registryStore._map(type);
|
|
23
26
|
|
|
24
|
-
const registry = {
|
|
27
|
+
const registry = attachRegistryInspection({
|
|
25
28
|
register(id, fn) {
|
|
26
29
|
assertId(id);
|
|
27
30
|
if (typeof fn !== "function") {
|
|
@@ -90,14 +93,30 @@ export function createHandlerRegistry(initialMap = {}) {
|
|
|
90
93
|
}
|
|
91
94
|
|
|
92
95
|
return results;
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
_adoptMany() {
|
|
99
|
+
return registry;
|
|
93
100
|
}
|
|
94
|
-
};
|
|
101
|
+
}, registryStore, type);
|
|
95
102
|
|
|
96
|
-
registry
|
|
103
|
+
registerBuiltIns(registry, handlers);
|
|
97
104
|
registry.registerMany(initialMap);
|
|
98
105
|
return registry;
|
|
99
106
|
}
|
|
100
107
|
|
|
108
|
+
function registerBuiltIns(registry, handlers) {
|
|
109
|
+
for (const [id, fn] of Object.entries(builtInHandlers)) {
|
|
110
|
+
if (!handlers.has(id)) {
|
|
111
|
+
registry.register(id, fn);
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (handlers.get(id) !== fn) {
|
|
115
|
+
throw new Error(`Handler "${id}" is already registered.`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
101
120
|
export function parseHandlerRef(ref) {
|
|
102
121
|
if (typeof ref !== "string" || ref.trim().length === 0) {
|
|
103
122
|
throw new TypeError("Handler ref must be a non-empty string.");
|
package/src/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { asyncSignal } from "./async-signal.js";
|
|
2
2
|
export { Async, createApp, defineApp } from "./app.js";
|
|
3
|
+
export { attributeName, defineAttributeConfig } from "./attributes.js";
|
|
3
4
|
export { createCacheRegistry, defineCache } from "./cache.js";
|
|
4
5
|
export { component, createComponentRegistry, defineComponent } from "./component.js";
|
|
5
6
|
export { delay } from "./delay.js";
|
|
@@ -7,6 +8,7 @@ export { createHandlerRegistry } from "./handlers.js";
|
|
|
7
8
|
export { html } from "./html.js";
|
|
8
9
|
export { AsyncLoader } from "./loader.js";
|
|
9
10
|
export { createPartialRegistry } from "./partials.js";
|
|
11
|
+
export { createRegistryStore } from "./registry-store.js";
|
|
10
12
|
export { createRouteRegistry, createRouter, defineRoute, route } from "./router.js";
|
|
11
13
|
export { createServerProxy, createServerRegistry } from "./server.js";
|
|
12
14
|
export { computed, createSignal, createSignalRegistry, effect, signal } from "./signals.js";
|