@openelement/core 0.41.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +36 -0
- package/package.json +124 -0
- package/src/binding-activation.d.ts +2 -0
- package/src/binding-activation.js +254 -0
- package/src/binding-descriptor.d.ts +79 -0
- package/src/binding-descriptor.js +9 -0
- package/src/context.d.ts +32 -0
- package/src/context.js +76 -0
- package/src/csr.d.ts +13 -0
- package/src/csr.js +14 -0
- package/src/dsd-hydration-events.d.ts +2 -0
- package/src/dsd-hydration-events.js +13 -0
- package/src/dsd-hydration.d.ts +40 -0
- package/src/dsd-hydration.js +48 -0
- package/src/errors.d.ts +54 -0
- package/src/errors.js +113 -0
- package/src/event-hydration.d.ts +12 -0
- package/src/event-hydration.js +118 -0
- package/src/event-marker.d.ts +7 -0
- package/src/event-marker.js +54 -0
- package/src/html-escape.d.ts +29 -0
- package/src/html-escape.js +126 -0
- package/src/hydrate.d.ts +15 -0
- package/src/hydrate.js +15 -0
- package/src/index.d.ts +58 -0
- package/src/index.js +46 -0
- package/src/island-transform.d.ts +14 -0
- package/src/island-transform.js +60 -0
- package/src/island.d.ts +59 -0
- package/src/island.js +342 -0
- package/src/isr-runtime.d.ts +28 -0
- package/src/isr-runtime.js +99 -0
- package/src/isr.d.ts +22 -0
- package/src/isr.js +41 -0
- package/src/jsx-render-dom.d.ts +22 -0
- package/src/jsx-render-dom.js +376 -0
- package/src/jsx-runtime.d.ts +58 -0
- package/src/jsx-runtime.js +99 -0
- package/src/jsx-types.d.ts +46 -0
- package/src/logger.d.ts +15 -0
- package/src/logger.js +24 -0
- package/src/prop.d.ts +24 -0
- package/src/prop.js +160 -0
- package/src/registry.d.ts +17 -0
- package/src/registry.js +219 -0
- package/src/render-dsd-stream.d.ts +46 -0
- package/src/render-dsd-stream.js +86 -0
- package/src/render-dsd.d.ts +27 -0
- package/src/render-dsd.js +315 -0
- package/src/render-ir.d.ts +32 -0
- package/src/render-ir.js +245 -0
- package/src/runtime.d.ts +9 -0
- package/src/runtime.js +16 -0
- package/src/security.d.ts +1 -0
- package/src/security.js +40 -0
- package/src/signal-context.d.ts +15 -0
- package/src/signal-context.js +59 -0
- package/src/static.d.ts +35 -0
- package/src/static.js +34 -0
- package/src/style-sheet.d.ts +9 -0
- package/src/style-sheet.js +56 -0
- package/src/tag-utils.d.ts +11 -0
- package/src/tag-utils.js +28 -0
- package/src/vnode.d.ts +15 -0
- package/src/vnode.js +31 -0
package/src/context.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @openelement/core - Request Context
|
|
3
|
+
* Provides a per-request context object that flows through SSR rendering
|
|
4
|
+
* and is accessible to islands and layout components.
|
|
5
|
+
*
|
|
6
|
+
* Web Standards alignment:
|
|
7
|
+
* - Built on standard Request/URL APIs
|
|
8
|
+
* - Minimal framework overhead - only what's needed for SSR + Islands
|
|
9
|
+
*/ import { createLogger } from './logger.js';
|
|
10
|
+
import { formatError } from './errors.js';
|
|
11
|
+
const log = createLogger('core');
|
|
12
|
+
/**
|
|
13
|
+
* Extract route params from a pathname using a route pattern.
|
|
14
|
+
* e.g., pattern '/posts/:id' + pathname '/posts/123' -> { id: '123' }
|
|
15
|
+
*
|
|
16
|
+
* Uses WHATWG URLPattern API - available in:
|
|
17
|
+
* ✅ Deno 1.33+ (native, no flags)
|
|
18
|
+
* ✅ Node.js 19+ (--experimental-url-pattern)
|
|
19
|
+
* ✅ Bun (native)
|
|
20
|
+
* ✅ All modern browsers
|
|
21
|
+
*/ export function extractParams(pattern, pathname) {
|
|
22
|
+
try {
|
|
23
|
+
const urlPattern = new URLPattern({
|
|
24
|
+
pathname: pattern
|
|
25
|
+
});
|
|
26
|
+
const match = urlPattern.exec({
|
|
27
|
+
pathname,
|
|
28
|
+
protocol: 'https',
|
|
29
|
+
hostname: 'localhost'
|
|
30
|
+
});
|
|
31
|
+
return match?.pathname?.groups ?? {};
|
|
32
|
+
} catch (err) {
|
|
33
|
+
log.error(`URLPattern failed for pattern "${pattern}" on pathname "${pathname}": ${formatError(err)}`);
|
|
34
|
+
return {};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Parse URL search params into a plain object.
|
|
39
|
+
* Uses standard URLSearchParams - zero framework magic.
|
|
40
|
+
* Supports multi-value keys (e.g., ?tag=a&tag=b -> { tag: ['a', 'b'] }).
|
|
41
|
+
*/ export function parseQuery(url) {
|
|
42
|
+
const query = {};
|
|
43
|
+
// v0.14.3: Simplified - use `key in query` instead of separate `seen` Set
|
|
44
|
+
url.searchParams.forEach((value, key)=>{
|
|
45
|
+
if (key in query) {
|
|
46
|
+
const existing = query[key];
|
|
47
|
+
// M-02 fix: Use Array.isArray check instead of fragile type assertion
|
|
48
|
+
query[key] = Array.isArray(existing) ? [
|
|
49
|
+
...existing,
|
|
50
|
+
value
|
|
51
|
+
] : [
|
|
52
|
+
existing,
|
|
53
|
+
value
|
|
54
|
+
];
|
|
55
|
+
} else {
|
|
56
|
+
query[key] = value;
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
return query;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Create a fresh SsrContext for a request.
|
|
63
|
+
* This is the single source of truth for per-request state.
|
|
64
|
+
*/ export function createSsrContext(route, url, options = {}) {
|
|
65
|
+
return {
|
|
66
|
+
route,
|
|
67
|
+
url,
|
|
68
|
+
params: extractParams(route.path, url.pathname),
|
|
69
|
+
query: parseQuery(url),
|
|
70
|
+
islands: [],
|
|
71
|
+
status: 200,
|
|
72
|
+
data: {},
|
|
73
|
+
requestId: options.requestId
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vaG9tZS9ydW5uZXIvd29yay9vcGVuZWxlbWVudC9vcGVuZWxlbWVudC9wYWNrYWdlcy9jb3JlL3NyYy9jb250ZXh0LnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQG9wZW5lbGVtZW50L2NvcmUgLSBSZXF1ZXN0IENvbnRleHRcbiAqIFByb3ZpZGVzIGEgcGVyLXJlcXVlc3QgY29udGV4dCBvYmplY3QgdGhhdCBmbG93cyB0aHJvdWdoIFNTUiByZW5kZXJpbmdcbiAqIGFuZCBpcyBhY2Nlc3NpYmxlIHRvIGlzbGFuZHMgYW5kIGxheW91dCBjb21wb25lbnRzLlxuICpcbiAqIFdlYiBTdGFuZGFyZHMgYWxpZ25tZW50OlxuICogLSBCdWlsdCBvbiBzdGFuZGFyZCBSZXF1ZXN0L1VSTCBBUElzXG4gKiAtIE1pbmltYWwgZnJhbWV3b3JrIG92ZXJoZWFkIC0gb25seSB3aGF0J3MgbmVlZGVkIGZvciBTU1IgKyBJc2xhbmRzXG4gKi9cblxuaW1wb3J0IHR5cGUgeyBSb3V0ZUVudHJ5IH0gZnJvbSAnQG9wZW5lbGVtZW50L3Byb3RvY29sL2ZyYW1ld29yayc7XG5pbXBvcnQgdHlwZSB7IElzbGFuZERlc2NyaXB0b3IsIFNzckNvbnRleHQgfSBmcm9tICdAb3BlbmVsZW1lbnQvcHJvdG9jb2wvY29udGV4dCc7XG5leHBvcnQgdHlwZSB7IElzbGFuZERlc2NyaXB0b3IsIFNzckNvbnRleHQgfTtcbmltcG9ydCB7IGNyZWF0ZUxvZ2dlciB9IGZyb20gJy4vbG9nZ2VyLmpzJztcbmltcG9ydCB7IGZvcm1hdEVycm9yIH0gZnJvbSAnLi9lcnJvcnMuanMnO1xuXG5jb25zdCBsb2cgPSBjcmVhdGVMb2dnZXIoJ2NvcmUnKTtcblxuLyoqXG4gKiBFeHRyYWN0IHJvdXRlIHBhcmFtcyBmcm9tIGEgcGF0aG5hbWUgdXNpbmcgYSByb3V0ZSBwYXR0ZXJuLlxuICogZS5nLiwgcGF0dGVybiAnL3Bvc3RzLzppZCcgKyBwYXRobmFtZSAnL3Bvc3RzLzEyMycgLT4geyBpZDogJzEyMycgfVxuICpcbiAqIFVzZXMgV0hBVFdHIFVSTFBhdHRlcm4gQVBJIC0gYXZhaWxhYmxlIGluOlxuICogICDinIUgRGVubyAxLjMzKyAobmF0aXZlLCBubyBmbGFncylcbiAqICAg4pyFIE5vZGUuanMgMTkrICgtLWV4cGVyaW1lbnRhbC11cmwtcGF0dGVybilcbiAqICAg4pyFIEJ1biAobmF0aXZlKVxuICogICDinIUgQWxsIG1vZGVybiBicm93c2Vyc1xuICovXG5leHBvcnQgZnVuY3Rpb24gZXh0cmFjdFBhcmFtcyhcbiAgcGF0dGVybjogc3RyaW5nLFxuICBwYXRobmFtZTogc3RyaW5nLFxuKTogUmVjb3JkPHN0cmluZywgc3RyaW5nPiB7XG4gIHRyeSB7XG4gICAgY29uc3QgdXJsUGF0dGVybiA9IG5ldyBVUkxQYXR0ZXJuKHsgcGF0aG5hbWU6IHBhdHRlcm4gfSk7XG4gICAgY29uc3QgbWF0Y2ggPSB1cmxQYXR0ZXJuLmV4ZWMoe1xuICAgICAgcGF0aG5hbWUsXG4gICAgICBwcm90b2NvbDogJ2h0dHBzJyxcbiAgICAgIGhvc3RuYW1lOiAnbG9jYWxob3N0JyxcbiAgICB9KTtcbiAgICByZXR1cm4gKG1hdGNoPy5wYXRobmFtZT8uZ3JvdXBzID8/IHt9KSBhcyBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+O1xuICB9IGNhdGNoIChlcnIpIHtcbiAgICBsb2cuZXJyb3IoXG4gICAgICBgVVJMUGF0dGVybiBmYWlsZWQgZm9yIHBhdHRlcm4gXCIke3BhdHRlcm59XCIgb24gcGF0aG5hbWUgXCIke3BhdGhuYW1lfVwiOiAke2Zvcm1hdEVycm9yKGVycil9YCxcbiAgICApO1xuICAgIHJldHVybiB7fTtcbiAgfVxufVxuXG4vKipcbiAqIFBhcnNlIFVSTCBzZWFyY2ggcGFyYW1zIGludG8gYSBwbGFpbiBvYmplY3QuXG4gKiBVc2VzIHN0YW5kYXJkIFVSTFNlYXJjaFBhcmFtcyAtIHplcm8gZnJhbWV3b3JrIG1hZ2ljLlxuICogU3VwcG9ydHMgbXVsdGktdmFsdWUga2V5cyAoZS5nLiwgP3RhZz1hJnRhZz1iIC0+IHsgdGFnOiBbJ2EnLCAnYiddIH0pLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VRdWVyeSh1cmw6IFVSTCk6IFJlY29yZDxzdHJpbmcsIHN0cmluZyB8IHN0cmluZ1tdPiB7XG4gIGNvbnN0IHF1ZXJ5OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmcgfCBzdHJpbmdbXT4gPSB7fTtcbiAgLy8gdjAuMTQuMzogU2ltcGxpZmllZCAtIHVzZSBga2V5IGluIHF1ZXJ5YCBpbnN0ZWFkIG9mIHNlcGFyYXRlIGBzZWVuYCBTZXRcbiAgdXJsLnNlYXJjaFBhcmFtcy5mb3JFYWNoKCh2YWx1ZSwga2V5KSA9PiB7XG4gICAgaWYgKGtleSBpbiBxdWVyeSkge1xuICAgICAgY29uc3QgZXhpc3RpbmcgPSBxdWVyeVtrZXldO1xuICAgICAgLy8gTS0wMiBmaXg6IFVzZSBBcnJheS5pc0FycmF5IGNoZWNrIGluc3RlYWQgb2YgZnJhZ2lsZSB0eXBlIGFzc2VydGlvblxuICAgICAgcXVlcnlba2V5XSA9IEFycmF5LmlzQXJyYXkoZXhpc3RpbmcpID8gWy4uLmV4aXN0aW5nLCB2YWx1ZV0gOiBbZXhpc3RpbmcsIHZhbHVlXTtcbiAgICB9IGVsc2Uge1xuICAgICAgcXVlcnlba2V5XSA9IHZhbHVlO1xuICAgIH1cbiAgfSk7XG4gIHJldHVybiBxdWVyeTtcbn1cblxuLyoqXG4gKiBDcmVhdGUgYSBmcmVzaCBTc3JDb250ZXh0IGZvciBhIHJlcXVlc3QuXG4gKiBUaGlzIGlzIHRoZSBzaW5nbGUgc291cmNlIG9mIHRydXRoIGZvciBwZXItcmVxdWVzdCBzdGF0ZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZVNzckNvbnRleHQoXG4gIHJvdXRlOiBSb3V0ZUVudHJ5LFxuICB1cmw6IFVSTCxcbiAgb3B0aW9uczoge1xuICAgIHJlcXVlc3RJZD86IHN0cmluZztcbiAgfSA9IHt9LFxuKTogU3NyQ29udGV4dCB7XG4gIHJldHVybiB7XG4gICAgcm91dGUsXG4gICAgdXJsLFxuICAgIHBhcmFtczogZXh0cmFjdFBhcmFtcyhyb3V0ZS5wYXRoLCB1cmwucGF0aG5hbWUpLFxuICAgIHF1ZXJ5OiBwYXJzZVF1ZXJ5KHVybCksXG4gICAgaXNsYW5kczogW10sXG4gICAgc3RhdHVzOiAyMDAsXG4gICAgZGF0YToge30sXG4gICAgcmVxdWVzdElkOiBvcHRpb25zLnJlcXVlc3RJZCxcbiAgfTtcbn1cbiJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Q0FRQyxHQUtELFNBQVMsWUFBWSxRQUFRLGNBQWM7QUFDM0MsU0FBUyxXQUFXLFFBQVEsY0FBYztBQUUxQyxNQUFNLE1BQU0sYUFBYTtBQUV6Qjs7Ozs7Ozs7O0NBU0MsR0FDRCxPQUFPLFNBQVMsY0FDZCxPQUFlLEVBQ2YsUUFBZ0I7RUFFaEIsSUFBSTtJQUNGLE1BQU0sYUFBYSxJQUFJLFdBQVc7TUFBRSxVQUFVO0lBQVE7SUFDdEQsTUFBTSxRQUFRLFdBQVcsSUFBSSxDQUFDO01BQzVCO01BQ0EsVUFBVTtNQUNWLFVBQVU7SUFDWjtJQUNBLE9BQVEsT0FBTyxVQUFVLFVBQVUsQ0FBQztFQUN0QyxFQUFFLE9BQU8sS0FBSztJQUNaLElBQUksS0FBSyxDQUNQLENBQUMsK0JBQStCLEVBQUUsUUFBUSxlQUFlLEVBQUUsU0FBUyxHQUFHLEVBQUUsWUFBWSxNQUFNO0lBRTdGLE9BQU8sQ0FBQztFQUNWO0FBQ0Y7QUFFQTs7OztDQUlDLEdBQ0QsT0FBTyxTQUFTLFdBQVcsR0FBUTtFQUNqQyxNQUFNLFFBQTJDLENBQUM7RUFDbEQsMEVBQTBFO0VBQzFFLElBQUksWUFBWSxDQUFDLE9BQU8sQ0FBQyxDQUFDLE9BQU87SUFDL0IsSUFBSSxPQUFPLE9BQU87TUFDaEIsTUFBTSxXQUFXLEtBQUssQ0FBQyxJQUFJO01BQzNCLHNFQUFzRTtNQUN0RSxLQUFLLENBQUMsSUFBSSxHQUFHLE1BQU0sT0FBTyxDQUFDLFlBQVk7V0FBSTtRQUFVO09BQU0sR0FBRztRQUFDO1FBQVU7T0FBTTtJQUNqRixPQUFPO01BQ0wsS0FBSyxDQUFDLElBQUksR0FBRztJQUNmO0VBQ0Y7RUFDQSxPQUFPO0FBQ1Q7QUFFQTs7O0NBR0MsR0FDRCxPQUFPLFNBQVMsaUJBQ2QsS0FBaUIsRUFDakIsR0FBUSxFQUNSLFVBRUksQ0FBQyxDQUFDO0VBRU4sT0FBTztJQUNMO0lBQ0E7SUFDQSxRQUFRLGNBQWMsTUFBTSxJQUFJLEVBQUUsSUFBSSxRQUFRO0lBQzlDLE9BQU8sV0FBVztJQUNsQixTQUFTLEVBQUU7SUFDWCxRQUFRO0lBQ1IsTUFBTSxDQUFDO0lBQ1AsV0FBVyxRQUFRLFNBQVM7RUFDOUI7QUFDRiJ9
|
package/src/csr.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @openelement/core/csr - Client-side rendering runtime surface.
|
|
3
|
+
*
|
|
4
|
+
* Includes the static rendering surface plus the full DOM renderer and event
|
|
5
|
+
* hydration helpers. Used for CSR fallbacks and pure islands.
|
|
6
|
+
*
|
|
7
|
+
* ADR-0109 Phase 1: split @openelement/core into static, hydrate, and csr.
|
|
8
|
+
*/ export * from "./static.js";
|
|
9
|
+
export type { BindingDescriptor, BindingDispose, BindingLifecycle } from "./binding-descriptor.js";
|
|
10
|
+
export { applyBindingDescriptor } from "./binding-activation.js";
|
|
11
|
+
export { applyProps, collectPropBindings, renderToDom } from "./jsx-render-dom.js";
|
|
12
|
+
export { collectEventBindings, eventRecordsToDescriptors, hydrateEventMarkers } from "./event-hydration.js";
|
|
13
|
+
export type { EventBinding, EventBindingRecord } from "./event-hydration.js";
|
package/src/csr.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @openelement/core/csr - Client-side rendering runtime surface.
|
|
3
|
+
*
|
|
4
|
+
* Includes the static rendering surface plus the full DOM renderer and event
|
|
5
|
+
* hydration helpers. Used for CSR fallbacks and pure islands.
|
|
6
|
+
*
|
|
7
|
+
* ADR-0109 Phase 1: split @openelement/core into static, hydrate, and csr.
|
|
8
|
+
*/ export * from './static.js';
|
|
9
|
+
export { applyBindingDescriptor } from './binding-activation.js';
|
|
10
|
+
// Full DOM renderer
|
|
11
|
+
export { applyProps, collectPropBindings, renderToDom } from './jsx-render-dom.js';
|
|
12
|
+
// Event hydration (DOM-specific parts not already in static.ts)
|
|
13
|
+
export { collectEventBindings, eventRecordsToDescriptors, hydrateEventMarkers } from './event-hydration.js';
|
|
14
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vaG9tZS9ydW5uZXIvd29yay9vcGVuZWxlbWVudC9vcGVuZWxlbWVudC9wYWNrYWdlcy9jb3JlL3NyYy9jc3IudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAb3BlbmVsZW1lbnQvY29yZS9jc3IgLSBDbGllbnQtc2lkZSByZW5kZXJpbmcgcnVudGltZSBzdXJmYWNlLlxuICpcbiAqIEluY2x1ZGVzIHRoZSBzdGF0aWMgcmVuZGVyaW5nIHN1cmZhY2UgcGx1cyB0aGUgZnVsbCBET00gcmVuZGVyZXIgYW5kIGV2ZW50XG4gKiBoeWRyYXRpb24gaGVscGVycy4gVXNlZCBmb3IgQ1NSIGZhbGxiYWNrcyBhbmQgcHVyZSBpc2xhbmRzLlxuICpcbiAqIEFEUi0wMTA5IFBoYXNlIDE6IHNwbGl0IEBvcGVuZWxlbWVudC9jb3JlIGludG8gc3RhdGljLCBoeWRyYXRlLCBhbmQgY3NyLlxuICovXG5cbmV4cG9ydCAqIGZyb20gJy4vc3RhdGljLmpzJztcblxuLy8gQmluZGluZyBsYXllclxuZXhwb3J0IHR5cGUgeyBCaW5kaW5nRGVzY3JpcHRvciwgQmluZGluZ0Rpc3Bvc2UsIEJpbmRpbmdMaWZlY3ljbGUgfSBmcm9tICcuL2JpbmRpbmctZGVzY3JpcHRvci5qcyc7XG5leHBvcnQgeyBhcHBseUJpbmRpbmdEZXNjcmlwdG9yIH0gZnJvbSAnLi9iaW5kaW5nLWFjdGl2YXRpb24uanMnO1xuXG4vLyBGdWxsIERPTSByZW5kZXJlclxuZXhwb3J0IHsgYXBwbHlQcm9wcywgY29sbGVjdFByb3BCaW5kaW5ncywgcmVuZGVyVG9Eb20gfSBmcm9tICcuL2pzeC1yZW5kZXItZG9tLmpzJztcblxuLy8gRXZlbnQgaHlkcmF0aW9uIChET00tc3BlY2lmaWMgcGFydHMgbm90IGFscmVhZHkgaW4gc3RhdGljLnRzKVxuZXhwb3J0IHtcbiAgY29sbGVjdEV2ZW50QmluZGluZ3MsXG4gIGV2ZW50UmVjb3Jkc1RvRGVzY3JpcHRvcnMsXG4gIGh5ZHJhdGVFdmVudE1hcmtlcnMsXG59IGZyb20gJy4vZXZlbnQtaHlkcmF0aW9uLmpzJztcbmV4cG9ydCB0eXBlIHsgRXZlbnRCaW5kaW5nLCBFdmVudEJpbmRpbmdSZWNvcmQgfSBmcm9tICcuL2V2ZW50LWh5ZHJhdGlvbi5qcyc7XG4iXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Q0FPQyxHQUVELGNBQWMsY0FBYztBQUk1QixTQUFTLHNCQUFzQixRQUFRLDBCQUEwQjtBQUVqRSxvQkFBb0I7QUFDcEIsU0FBUyxVQUFVLEVBQUUsbUJBQW1CLEVBQUUsV0FBVyxRQUFRLHNCQUFzQjtBQUVuRixnRUFBZ0U7QUFDaEUsU0FDRSxvQkFBb0IsRUFDcEIseUJBQXlCLEVBQ3pCLG1CQUFtQixRQUNkLHVCQUF1QiJ9
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function bindHydrateEvents(root, host, events, signal) {
|
|
2
|
+
for (const desc of events){
|
|
3
|
+
if (desc.method.startsWith('__')) continue;
|
|
4
|
+
const handler = Reflect.get(host, desc.method);
|
|
5
|
+
if (typeof handler !== 'function') continue;
|
|
6
|
+
for (const el of root.querySelectorAll(desc.selector)){
|
|
7
|
+
el.addEventListener(desc.event, handler.bind(host), {
|
|
8
|
+
signal
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vaG9tZS9ydW5uZXIvd29yay9vcGVuZWxlbWVudC9vcGVuZWxlbWVudC9wYWNrYWdlcy9jb3JlL3NyYy9kc2QtaHlkcmF0aW9uLWV2ZW50cy50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgdHlwZSB7IEh5ZHJhdGVFdmVudERlc2NyaXB0b3IgfSBmcm9tICdAb3BlbmVsZW1lbnQvcHJvdG9jb2wvZnJhbWV3b3JrJztcblxuZXhwb3J0IGZ1bmN0aW9uIGJpbmRIeWRyYXRlRXZlbnRzKFxuICByb290OiBQYXJlbnROb2RlLFxuICBob3N0OiBvYmplY3QsXG4gIGV2ZW50czogcmVhZG9ubHkgSHlkcmF0ZUV2ZW50RGVzY3JpcHRvcltdLFxuICBzaWduYWw6IEFib3J0U2lnbmFsLFxuKTogdm9pZCB7XG4gIGZvciAoY29uc3QgZGVzYyBvZiBldmVudHMpIHtcbiAgICBpZiAoZGVzYy5tZXRob2Quc3RhcnRzV2l0aCgnX18nKSkgY29udGludWU7XG4gICAgY29uc3QgaGFuZGxlciA9IFJlZmxlY3QuZ2V0KGhvc3QsIGRlc2MubWV0aG9kKTtcbiAgICBpZiAodHlwZW9mIGhhbmRsZXIgIT09ICdmdW5jdGlvbicpIGNvbnRpbnVlO1xuXG4gICAgZm9yIChjb25zdCBlbCBvZiByb290LnF1ZXJ5U2VsZWN0b3JBbGwoZGVzYy5zZWxlY3RvcikpIHtcbiAgICAgIGVsLmFkZEV2ZW50TGlzdGVuZXIoZGVzYy5ldmVudCwgaGFuZGxlci5iaW5kKGhvc3QpIGFzIEV2ZW50TGlzdGVuZXIsIHsgc2lnbmFsIH0pO1xuICAgIH1cbiAgfVxufVxuIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUVBLE9BQU8sU0FBUyxrQkFDZCxJQUFnQixFQUNoQixJQUFZLEVBQ1osTUFBeUMsRUFDekMsTUFBbUI7RUFFbkIsS0FBSyxNQUFNLFFBQVEsT0FBUTtJQUN6QixJQUFJLEtBQUssTUFBTSxDQUFDLFVBQVUsQ0FBQyxPQUFPO0lBQ2xDLE1BQU0sVUFBVSxRQUFRLEdBQUcsQ0FBQyxNQUFNLEtBQUssTUFBTTtJQUM3QyxJQUFJLE9BQU8sWUFBWSxZQUFZO0lBRW5DLEtBQUssTUFBTSxNQUFNLEtBQUssZ0JBQWdCLENBQUMsS0FBSyxRQUFRLEVBQUc7TUFDckQsR0FBRyxnQkFBZ0IsQ0FBQyxLQUFLLEtBQUssRUFBRSxRQUFRLElBQUksQ0FBQyxPQUF3QjtRQUFFO01BQU87SUFDaEY7RUFDRjtBQUNGIn0=
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DSD Hydration contract — shared interface for all adapter packages.
|
|
3
|
+
* ADR-0079: Extracted from adapter-lit/vanilla/react.
|
|
4
|
+
*/ export interface DsdHydration {
|
|
5
|
+
_dsdHydrated: boolean;
|
|
6
|
+
_hydrateEvents(): void;
|
|
7
|
+
}
|
|
8
|
+
export type Constructor<T = HTMLElement> = new(...args: unknown[]) => T;
|
|
9
|
+
import type { HydrateEventDescriptor } from '@openelement/protocol/framework';
|
|
10
|
+
/**
|
|
11
|
+
* Shared DSD createRenderRoot logic.
|
|
12
|
+
*
|
|
13
|
+
* Detects a pre-populated shadow root (from SSR DSD), marks the element as
|
|
14
|
+
* hydrated, and returns the existing shadow root. Otherwise attaches a new
|
|
15
|
+
* open shadow root.
|
|
16
|
+
*
|
|
17
|
+
* Accepts `HTMLElement` and internally casts to `DsdHydration` to set the
|
|
18
|
+
* `_dsdHydrated` flag. This allows callers where `_dsdHydrated` is declared
|
|
19
|
+
* as `protected` in their mixin class hierarchy.
|
|
20
|
+
*
|
|
21
|
+
* Extracted from adapter-lit / adapter-react / adapter-vanilla to avoid
|
|
22
|
+
* triplicate identical implementations.
|
|
23
|
+
*/ export declare function createDsdRenderRoot(element: HTMLElement): ShadowRoot;
|
|
24
|
+
/**
|
|
25
|
+
* Shared _hydrateEvents logic.
|
|
26
|
+
*
|
|
27
|
+
* Reads `hydrateEvents` from the constructor, creates an AbortController,
|
|
28
|
+
* and binds event listeners on the element's shadow root via bindHydrateEvents.
|
|
29
|
+
*
|
|
30
|
+
* Returns the AbortController so the caller can store it (e.g. in a private
|
|
31
|
+
* `_hydrateAbortController` field) and abort listeners on disconnect.
|
|
32
|
+
*
|
|
33
|
+
* Accepts `HTMLElement` and internally casts to `DsdHydration` to avoid
|
|
34
|
+
* accessibility conflicts with `protected` members in caller classes.
|
|
35
|
+
*
|
|
36
|
+
* Extracted from adapter-lit / adapter-react / adapter-vanilla to avoid
|
|
37
|
+
* triplicate identical implementations.
|
|
38
|
+
*/ export declare function hydrateDsdEvents(element: HTMLElement, ctor: {
|
|
39
|
+
hydrateEvents?: readonly HydrateEventDescriptor[];
|
|
40
|
+
}): AbortController | undefined;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DSD Hydration contract — shared interface for all adapter packages.
|
|
3
|
+
* ADR-0079: Extracted from adapter-lit/vanilla/react.
|
|
4
|
+
*/ import { bindHydrateEvents } from './dsd-hydration-events.js';
|
|
5
|
+
/**
|
|
6
|
+
* Shared DSD createRenderRoot logic.
|
|
7
|
+
*
|
|
8
|
+
* Detects a pre-populated shadow root (from SSR DSD), marks the element as
|
|
9
|
+
* hydrated, and returns the existing shadow root. Otherwise attaches a new
|
|
10
|
+
* open shadow root.
|
|
11
|
+
*
|
|
12
|
+
* Accepts `HTMLElement` and internally casts to `DsdHydration` to set the
|
|
13
|
+
* `_dsdHydrated` flag. This allows callers where `_dsdHydrated` is declared
|
|
14
|
+
* as `protected` in their mixin class hierarchy.
|
|
15
|
+
*
|
|
16
|
+
* Extracted from adapter-lit / adapter-react / adapter-vanilla to avoid
|
|
17
|
+
* triplicate identical implementations.
|
|
18
|
+
*/ export function createDsdRenderRoot(element) {
|
|
19
|
+
if (element.shadowRoot && element.shadowRoot.childElementCount > 0) {
|
|
20
|
+
return element.shadowRoot;
|
|
21
|
+
}
|
|
22
|
+
return element.attachShadow({
|
|
23
|
+
mode: 'open'
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Shared _hydrateEvents logic.
|
|
28
|
+
*
|
|
29
|
+
* Reads `hydrateEvents` from the constructor, creates an AbortController,
|
|
30
|
+
* and binds event listeners on the element's shadow root via bindHydrateEvents.
|
|
31
|
+
*
|
|
32
|
+
* Returns the AbortController so the caller can store it (e.g. in a private
|
|
33
|
+
* `_hydrateAbortController` field) and abort listeners on disconnect.
|
|
34
|
+
*
|
|
35
|
+
* Accepts `HTMLElement` and internally casts to `DsdHydration` to avoid
|
|
36
|
+
* accessibility conflicts with `protected` members in caller classes.
|
|
37
|
+
*
|
|
38
|
+
* Extracted from adapter-lit / adapter-react / adapter-vanilla to avoid
|
|
39
|
+
* triplicate identical implementations.
|
|
40
|
+
*/ export function hydrateDsdEvents(element, ctor) {
|
|
41
|
+
if (!element.shadowRoot) return undefined;
|
|
42
|
+
const events = ctor.hydrateEvents || [];
|
|
43
|
+
if (events.length === 0) return undefined;
|
|
44
|
+
const controller = new AbortController();
|
|
45
|
+
bindHydrateEvents(element.shadowRoot, element, events, controller.signal);
|
|
46
|
+
return controller;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vaG9tZS9ydW5uZXIvd29yay9vcGVuZWxlbWVudC9vcGVuZWxlbWVudC9wYWNrYWdlcy9jb3JlL3NyYy9kc2QtaHlkcmF0aW9uLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogRFNEIEh5ZHJhdGlvbiBjb250cmFjdCDigJQgc2hhcmVkIGludGVyZmFjZSBmb3IgYWxsIGFkYXB0ZXIgcGFja2FnZXMuXG4gKiBBRFItMDA3OTogRXh0cmFjdGVkIGZyb20gYWRhcHRlci1saXQvdmFuaWxsYS9yZWFjdC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBEc2RIeWRyYXRpb24ge1xuICBfZHNkSHlkcmF0ZWQ6IGJvb2xlYW47XG4gIF9oeWRyYXRlRXZlbnRzKCk6IHZvaWQ7XG59XG5cbmV4cG9ydCB0eXBlIENvbnN0cnVjdG9yPFQgPSBIVE1MRWxlbWVudD4gPSBuZXcgKC4uLmFyZ3M6IHVua25vd25bXSkgPT4gVDtcblxuaW1wb3J0IHsgYmluZEh5ZHJhdGVFdmVudHMgfSBmcm9tICcuL2RzZC1oeWRyYXRpb24tZXZlbnRzLmpzJztcbmltcG9ydCB0eXBlIHsgSHlkcmF0ZUV2ZW50RGVzY3JpcHRvciB9IGZyb20gJ0BvcGVuZWxlbWVudC9wcm90b2NvbC9mcmFtZXdvcmsnO1xuXG4vKipcbiAqIFNoYXJlZCBEU0QgY3JlYXRlUmVuZGVyUm9vdCBsb2dpYy5cbiAqXG4gKiBEZXRlY3RzIGEgcHJlLXBvcHVsYXRlZCBzaGFkb3cgcm9vdCAoZnJvbSBTU1IgRFNEKSwgbWFya3MgdGhlIGVsZW1lbnQgYXNcbiAqIGh5ZHJhdGVkLCBhbmQgcmV0dXJucyB0aGUgZXhpc3Rpbmcgc2hhZG93IHJvb3QuIE90aGVyd2lzZSBhdHRhY2hlcyBhIG5ld1xuICogb3BlbiBzaGFkb3cgcm9vdC5cbiAqXG4gKiBBY2NlcHRzIGBIVE1MRWxlbWVudGAgYW5kIGludGVybmFsbHkgY2FzdHMgdG8gYERzZEh5ZHJhdGlvbmAgdG8gc2V0IHRoZVxuICogYF9kc2RIeWRyYXRlZGAgZmxhZy4gVGhpcyBhbGxvd3MgY2FsbGVycyB3aGVyZSBgX2RzZEh5ZHJhdGVkYCBpcyBkZWNsYXJlZFxuICogYXMgYHByb3RlY3RlZGAgaW4gdGhlaXIgbWl4aW4gY2xhc3MgaGllcmFyY2h5LlxuICpcbiAqIEV4dHJhY3RlZCBmcm9tIGFkYXB0ZXItbGl0IC8gYWRhcHRlci1yZWFjdCAvIGFkYXB0ZXItdmFuaWxsYSB0byBhdm9pZFxuICogdHJpcGxpY2F0ZSBpZGVudGljYWwgaW1wbGVtZW50YXRpb25zLlxuICovXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlRHNkUmVuZGVyUm9vdChlbGVtZW50OiBIVE1MRWxlbWVudCk6IFNoYWRvd1Jvb3Qge1xuICBpZiAoZWxlbWVudC5zaGFkb3dSb290ICYmIGVsZW1lbnQuc2hhZG93Um9vdC5jaGlsZEVsZW1lbnRDb3VudCA+IDApIHtcbiAgICByZXR1cm4gZWxlbWVudC5zaGFkb3dSb290O1xuICB9XG4gIHJldHVybiBlbGVtZW50LmF0dGFjaFNoYWRvdyh7IG1vZGU6ICdvcGVuJyB9KTtcbn1cblxuLyoqXG4gKiBTaGFyZWQgX2h5ZHJhdGVFdmVudHMgbG9naWMuXG4gKlxuICogUmVhZHMgYGh5ZHJhdGVFdmVudHNgIGZyb20gdGhlIGNvbnN0cnVjdG9yLCBjcmVhdGVzIGFuIEFib3J0Q29udHJvbGxlcixcbiAqIGFuZCBiaW5kcyBldmVudCBsaXN0ZW5lcnMgb24gdGhlIGVsZW1lbnQncyBzaGFkb3cgcm9vdCB2aWEgYmluZEh5ZHJhdGVFdmVudHMuXG4gKlxuICogUmV0dXJucyB0aGUgQWJvcnRDb250cm9sbGVyIHNvIHRoZSBjYWxsZXIgY2FuIHN0b3JlIGl0IChlLmcuIGluIGEgcHJpdmF0ZVxuICogYF9oeWRyYXRlQWJvcnRDb250cm9sbGVyYCBmaWVsZCkgYW5kIGFib3J0IGxpc3RlbmVycyBvbiBkaXNjb25uZWN0LlxuICpcbiAqIEFjY2VwdHMgYEhUTUxFbGVtZW50YCBhbmQgaW50ZXJuYWxseSBjYXN0cyB0byBgRHNkSHlkcmF0aW9uYCB0byBhdm9pZFxuICogYWNjZXNzaWJpbGl0eSBjb25mbGljdHMgd2l0aCBgcHJvdGVjdGVkYCBtZW1iZXJzIGluIGNhbGxlciBjbGFzc2VzLlxuICpcbiAqIEV4dHJhY3RlZCBmcm9tIGFkYXB0ZXItbGl0IC8gYWRhcHRlci1yZWFjdCAvIGFkYXB0ZXItdmFuaWxsYSB0byBhdm9pZFxuICogdHJpcGxpY2F0ZSBpZGVudGljYWwgaW1wbGVtZW50YXRpb25zLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaHlkcmF0ZURzZEV2ZW50cyhcbiAgZWxlbWVudDogSFRNTEVsZW1lbnQsXG4gIGN0b3I6IHsgaHlkcmF0ZUV2ZW50cz86IHJlYWRvbmx5IEh5ZHJhdGVFdmVudERlc2NyaXB0b3JbXSB9LFxuKTogQWJvcnRDb250cm9sbGVyIHwgdW5kZWZpbmVkIHtcbiAgaWYgKCFlbGVtZW50LnNoYWRvd1Jvb3QpIHJldHVybiB1bmRlZmluZWQ7XG5cbiAgY29uc3QgZXZlbnRzID0gY3Rvci5oeWRyYXRlRXZlbnRzIHx8IFtdO1xuICBpZiAoZXZlbnRzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIHVuZGVmaW5lZDtcblxuICBjb25zdCBjb250cm9sbGVyID0gbmV3IEFib3J0Q29udHJvbGxlcigpO1xuICBiaW5kSHlkcmF0ZUV2ZW50cyhlbGVtZW50LnNoYWRvd1Jvb3QsIGVsZW1lbnQsIGV2ZW50cywgY29udHJvbGxlci5zaWduYWwpO1xuICByZXR1cm4gY29udHJvbGxlcjtcbn1cbiJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7O0NBR0MsR0FRRCxTQUFTLGlCQUFpQixRQUFRLDRCQUE0QjtBQUc5RDs7Ozs7Ozs7Ozs7OztDQWFDLEdBQ0QsT0FBTyxTQUFTLG9CQUFvQixPQUFvQjtFQUN0RCxJQUFJLFFBQVEsVUFBVSxJQUFJLFFBQVEsVUFBVSxDQUFDLGlCQUFpQixHQUFHLEdBQUc7SUFDbEUsT0FBTyxRQUFRLFVBQVU7RUFDM0I7RUFDQSxPQUFPLFFBQVEsWUFBWSxDQUFDO0lBQUUsTUFBTTtFQUFPO0FBQzdDO0FBRUE7Ozs7Ozs7Ozs7Ozs7O0NBY0MsR0FDRCxPQUFPLFNBQVMsaUJBQ2QsT0FBb0IsRUFDcEIsSUFBMkQ7RUFFM0QsSUFBSSxDQUFDLFFBQVEsVUFBVSxFQUFFLE9BQU87RUFFaEMsTUFBTSxTQUFTLEtBQUssYUFBYSxJQUFJLEVBQUU7RUFDdkMsSUFBSSxPQUFPLE1BQU0sS0FBSyxHQUFHLE9BQU87RUFFaEMsTUFBTSxhQUFhLElBQUk7RUFDdkIsa0JBQWtCLFFBQVEsVUFBVSxFQUFFLFNBQVMsUUFBUSxXQUFXLE1BQU07RUFDeEUsT0FBTztBQUNUIn0=
|
package/src/errors.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @openelement/core — Unified Error Architecture (ADR-0053 / SOP-011).
|
|
3
|
+
*/ import type { RenderError as ProtocolRenderError } from '@openelement/protocol/render';
|
|
4
|
+
/** Well-known error code constants for reference. String values are always accepted. */ export declare const ErrorCode: {
|
|
5
|
+
readonly SSR_RENDER_ERROR: 'SSR_RENDER_ERROR';
|
|
6
|
+
readonly ISLAND_RENDER_ERROR: 'ISLAND_RENDER_ERROR';
|
|
7
|
+
readonly PROP_VALIDATION_ERROR: 'PROP_VALIDATION_ERROR';
|
|
8
|
+
readonly TAG_VALIDATION_ERROR: 'TAG_VALIDATION_ERROR';
|
|
9
|
+
readonly NAVIGATION_ERROR: 'NAVIGATION_ERROR';
|
|
10
|
+
readonly BUILD_ERROR: 'BUILD_ERROR';
|
|
11
|
+
readonly RENDER_ERROR: 'RENDER_ERROR';
|
|
12
|
+
readonly BOUNDARY_CAUGHT: 'BOUNDARY_CAUGHT';
|
|
13
|
+
readonly UNKNOWN: 'UNKNOWN';
|
|
14
|
+
};
|
|
15
|
+
/** Error message prefix for all openElement errors. */ export declare const ERROR_PREFIX: '[openElement]';
|
|
16
|
+
/** Format an unknown thrown value as a human-readable string. */ export declare function formatError(e: unknown): string;
|
|
17
|
+
import type { ErrorPhase, ErrorSeverity } from '@openelement/protocol/errors';
|
|
18
|
+
export type { ErrorPhase, ErrorSeverity };
|
|
19
|
+
export interface OpenElementErrorOptions {
|
|
20
|
+
cause?: Error;
|
|
21
|
+
code?: string;
|
|
22
|
+
statusCode?: number;
|
|
23
|
+
severity?: ErrorSeverity;
|
|
24
|
+
phase?: ErrorPhase;
|
|
25
|
+
recoverable?: boolean;
|
|
26
|
+
}
|
|
27
|
+
export declare class OpenElementError extends Error {
|
|
28
|
+
public readonly code: string;
|
|
29
|
+
public readonly severity: ErrorSeverity;
|
|
30
|
+
public readonly phase: ErrorPhase;
|
|
31
|
+
public readonly recoverable: boolean;
|
|
32
|
+
public readonly statusCode?: number;
|
|
33
|
+
constructor(message: string, options?: OpenElementErrorOptions);
|
|
34
|
+
toJSON(): Record<string, unknown>;
|
|
35
|
+
}
|
|
36
|
+
export declare class SsrRenderError extends OpenElementError {
|
|
37
|
+
public readonly componentPath: string;
|
|
38
|
+
public readonly sourceError: Error;
|
|
39
|
+
constructor(componentPath: string, sourceError: Error);
|
|
40
|
+
}
|
|
41
|
+
export declare class RenderError extends OpenElementError implements ProtocolRenderError {
|
|
42
|
+
public readonly componentPath: string;
|
|
43
|
+
public readonly tagName: string;
|
|
44
|
+
constructor(componentPath: string, message: string, code?: string, tagName?: string, cause?: Error);
|
|
45
|
+
}
|
|
46
|
+
export declare class PropValidationError extends OpenElementError {
|
|
47
|
+
public readonly propertyName: string;
|
|
48
|
+
public readonly receivedValue: unknown;
|
|
49
|
+
constructor(propertyName: string, receivedValue: unknown, cause?: Error);
|
|
50
|
+
}
|
|
51
|
+
import type { ErrorTelemetryHook } from '@openelement/protocol/errors';
|
|
52
|
+
export type { ErrorTelemetryHook };
|
|
53
|
+
export declare function setErrorTelemetryHook(hook: ErrorTelemetryHook): void;
|
|
54
|
+
export declare function reportError(error: OpenElementError): void;
|
package/src/errors.js
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @openelement/core — Unified Error Architecture (ADR-0053 / SOP-011).
|
|
3
|
+
*/ /** Well-known error code constants for reference. String values are always accepted. */ // ponytail: duplicated from protocol to avoid cross-package runtime import in SSG bundles
|
|
4
|
+
export const ErrorCode = {
|
|
5
|
+
SSR_RENDER_ERROR: 'SSR_RENDER_ERROR',
|
|
6
|
+
ISLAND_RENDER_ERROR: 'ISLAND_RENDER_ERROR',
|
|
7
|
+
PROP_VALIDATION_ERROR: 'PROP_VALIDATION_ERROR',
|
|
8
|
+
TAG_VALIDATION_ERROR: 'TAG_VALIDATION_ERROR',
|
|
9
|
+
NAVIGATION_ERROR: 'NAVIGATION_ERROR',
|
|
10
|
+
BUILD_ERROR: 'BUILD_ERROR',
|
|
11
|
+
RENDER_ERROR: 'RENDER_ERROR',
|
|
12
|
+
BOUNDARY_CAUGHT: 'BOUNDARY_CAUGHT',
|
|
13
|
+
UNKNOWN: 'UNKNOWN'
|
|
14
|
+
};
|
|
15
|
+
/** Error message prefix for all openElement errors. */ export const ERROR_PREFIX = '[openElement]';
|
|
16
|
+
// ─── Error formatting helper ────────────────────────────────────────
|
|
17
|
+
/** Format an unknown thrown value as a human-readable string. */ export function formatError(e) {
|
|
18
|
+
return e instanceof Error ? e.message : String(e);
|
|
19
|
+
}
|
|
20
|
+
export class OpenElementError extends Error {
|
|
21
|
+
code;
|
|
22
|
+
severity;
|
|
23
|
+
phase;
|
|
24
|
+
recoverable;
|
|
25
|
+
statusCode;
|
|
26
|
+
constructor(message, options = {}){
|
|
27
|
+
super(message, options.cause ? {
|
|
28
|
+
cause: options.cause
|
|
29
|
+
} : undefined);
|
|
30
|
+
this.name = 'OpenElementError';
|
|
31
|
+
this.code = options.code ?? ErrorCode.UNKNOWN;
|
|
32
|
+
this.severity = options.severity ?? 'error';
|
|
33
|
+
this.phase = options.phase ?? 'unknown';
|
|
34
|
+
this.recoverable = options.recoverable ?? false;
|
|
35
|
+
this.statusCode = options.statusCode;
|
|
36
|
+
}
|
|
37
|
+
toJSON() {
|
|
38
|
+
return {
|
|
39
|
+
name: this.name,
|
|
40
|
+
code: this.code,
|
|
41
|
+
message: this.message,
|
|
42
|
+
severity: this.severity,
|
|
43
|
+
phase: this.phase,
|
|
44
|
+
recoverable: this.recoverable,
|
|
45
|
+
statusCode: this.statusCode,
|
|
46
|
+
cause: this.cause instanceof Error ? this.cause.message : this.cause
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// ─── SsrRenderError (backward compat) ────────────────────────────────
|
|
51
|
+
export class SsrRenderError extends OpenElementError {
|
|
52
|
+
componentPath;
|
|
53
|
+
sourceError;
|
|
54
|
+
constructor(componentPath, sourceError){
|
|
55
|
+
super(`SSR render failed: ${componentPath}`, {
|
|
56
|
+
code: 'SSR_RENDER_ERROR',
|
|
57
|
+
severity: 'error',
|
|
58
|
+
phase: 'ssr',
|
|
59
|
+
recoverable: false,
|
|
60
|
+
cause: sourceError
|
|
61
|
+
});
|
|
62
|
+
this.name = 'SsrRenderError';
|
|
63
|
+
this.componentPath = componentPath;
|
|
64
|
+
this.sourceError = sourceError;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// ─── New ADR-0053 error classes ─────────────────────────────────────
|
|
68
|
+
export class RenderError extends OpenElementError {
|
|
69
|
+
componentPath;
|
|
70
|
+
tagName;
|
|
71
|
+
constructor(componentPath, message, code = 'RENDER_ERROR', tagName = '', cause){
|
|
72
|
+
super(message, {
|
|
73
|
+
code,
|
|
74
|
+
severity: 'error',
|
|
75
|
+
phase: 'render',
|
|
76
|
+
recoverable: true,
|
|
77
|
+
cause
|
|
78
|
+
});
|
|
79
|
+
this.name = 'RenderError';
|
|
80
|
+
this.componentPath = componentPath;
|
|
81
|
+
this.tagName = tagName;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
export class PropValidationError extends OpenElementError {
|
|
85
|
+
propertyName;
|
|
86
|
+
receivedValue;
|
|
87
|
+
constructor(propertyName, receivedValue, cause){
|
|
88
|
+
super(`@prop validation failed for "${propertyName}"`, {
|
|
89
|
+
code: 'PROP_VALIDATION_ERROR',
|
|
90
|
+
severity: 'warning',
|
|
91
|
+
phase: 'validation',
|
|
92
|
+
recoverable: true,
|
|
93
|
+
cause
|
|
94
|
+
});
|
|
95
|
+
this.name = 'PropValidationError';
|
|
96
|
+
this.propertyName = propertyName;
|
|
97
|
+
this.receivedValue = receivedValue;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
let _telemetryHook;
|
|
101
|
+
export function setErrorTelemetryHook(hook) {
|
|
102
|
+
_telemetryHook = hook;
|
|
103
|
+
}
|
|
104
|
+
export function reportError(error) {
|
|
105
|
+
if (_telemetryHook) {
|
|
106
|
+
try {
|
|
107
|
+
_telemetryHook(error);
|
|
108
|
+
} catch {}
|
|
109
|
+
} else {
|
|
110
|
+
console.error(`[openElement:${error.code}] ${error.message}`);
|
|
111
|
+
}
|
|
112
|
+
} // ─── SSR Error Context ──────────────────────────────────────────────
|
|
113
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vaG9tZS9ydW5uZXIvd29yay9vcGVuZWxlbWVudC9vcGVuZWxlbWVudC9wYWNrYWdlcy9jb3JlL3NyYy9lcnJvcnMudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAb3BlbmVsZW1lbnQvY29yZSDigJQgVW5pZmllZCBFcnJvciBBcmNoaXRlY3R1cmUgKEFEUi0wMDUzIC8gU09QLTAxMSkuXG4gKi9cblxuaW1wb3J0IHR5cGUgeyBSZW5kZXJFcnJvciBhcyBQcm90b2NvbFJlbmRlckVycm9yIH0gZnJvbSAnQG9wZW5lbGVtZW50L3Byb3RvY29sL3JlbmRlcic7XG5cbi8qKiBXZWxsLWtub3duIGVycm9yIGNvZGUgY29uc3RhbnRzIGZvciByZWZlcmVuY2UuIFN0cmluZyB2YWx1ZXMgYXJlIGFsd2F5cyBhY2NlcHRlZC4gKi9cbi8vIHBvbnl0YWlsOiBkdXBsaWNhdGVkIGZyb20gcHJvdG9jb2wgdG8gYXZvaWQgY3Jvc3MtcGFja2FnZSBydW50aW1lIGltcG9ydCBpbiBTU0cgYnVuZGxlc1xuZXhwb3J0IGNvbnN0IEVycm9yQ29kZSA9IHtcbiAgU1NSX1JFTkRFUl9FUlJPUjogJ1NTUl9SRU5ERVJfRVJST1InLFxuICBJU0xBTkRfUkVOREVSX0VSUk9SOiAnSVNMQU5EX1JFTkRFUl9FUlJPUicsXG4gIFBST1BfVkFMSURBVElPTl9FUlJPUjogJ1BST1BfVkFMSURBVElPTl9FUlJPUicsXG4gIFRBR19WQUxJREFUSU9OX0VSUk9SOiAnVEFHX1ZBTElEQVRJT05fRVJST1InLFxuICBOQVZJR0FUSU9OX0VSUk9SOiAnTkFWSUdBVElPTl9FUlJPUicsXG4gIEJVSUxEX0VSUk9SOiAnQlVJTERfRVJST1InLFxuICBSRU5ERVJfRVJST1I6ICdSRU5ERVJfRVJST1InLFxuICBCT1VOREFSWV9DQVVHSFQ6ICdCT1VOREFSWV9DQVVHSFQnLFxuICBVTktOT1dOOiAnVU5LTk9XTicsXG59IGFzIGNvbnN0O1xuXG4vKiogRXJyb3IgbWVzc2FnZSBwcmVmaXggZm9yIGFsbCBvcGVuRWxlbWVudCBlcnJvcnMuICovXG5leHBvcnQgY29uc3QgRVJST1JfUFJFRklYID0gJ1tvcGVuRWxlbWVudF0nO1xuXG4vLyDilIDilIDilIAgRXJyb3IgZm9ybWF0dGluZyBoZWxwZXIg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbi8qKiBGb3JtYXQgYW4gdW5rbm93biB0aHJvd24gdmFsdWUgYXMgYSBodW1hbi1yZWFkYWJsZSBzdHJpbmcuICovXG5leHBvcnQgZnVuY3Rpb24gZm9ybWF0RXJyb3IoZTogdW5rbm93bik6IHN0cmluZyB7XG4gIHJldHVybiBlIGluc3RhbmNlb2YgRXJyb3IgPyBlLm1lc3NhZ2UgOiBTdHJpbmcoZSk7XG59XG5cbi8vIOKUgOKUgOKUgCBUeXBlcyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuaW1wb3J0IHR5cGUgeyBFcnJvclBoYXNlLCBFcnJvclNldmVyaXR5IH0gZnJvbSAnQG9wZW5lbGVtZW50L3Byb3RvY29sL2Vycm9ycyc7XG5leHBvcnQgdHlwZSB7IEVycm9yUGhhc2UsIEVycm9yU2V2ZXJpdHkgfTtcblxuLy8g4pSA4pSA4pSAIEJhc2UgRXJyb3Ig4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbmV4cG9ydCBpbnRlcmZhY2UgT3BlbkVsZW1lbnRFcnJvck9wdGlvbnMge1xuICBjYXVzZT86IEVycm9yO1xuICBjb2RlPzogc3RyaW5nO1xuICBzdGF0dXNDb2RlPzogbnVtYmVyO1xuICBzZXZlcml0eT86IEVycm9yU2V2ZXJpdHk7XG4gIHBoYXNlPzogRXJyb3JQaGFzZTtcbiAgcmVjb3ZlcmFibGU/OiBib29sZWFuO1xufVxuXG5leHBvcnQgY2xhc3MgT3BlbkVsZW1lbnRFcnJvciBleHRlbmRzIEVycm9yIHtcbiAgcHVibGljIHJlYWRvbmx5IGNvZGU6IHN0cmluZztcbiAgcHVibGljIHJlYWRvbmx5IHNldmVyaXR5OiBFcnJvclNldmVyaXR5O1xuICBwdWJsaWMgcmVhZG9ubHkgcGhhc2U6IEVycm9yUGhhc2U7XG4gIHB1YmxpYyByZWFkb25seSByZWNvdmVyYWJsZTogYm9vbGVhbjtcbiAgcHVibGljIHJlYWRvbmx5IHN0YXR1c0NvZGU/OiBudW1iZXI7XG5cbiAgY29uc3RydWN0b3IobWVzc2FnZTogc3RyaW5nLCBvcHRpb25zOiBPcGVuRWxlbWVudEVycm9yT3B0aW9ucyA9IHt9KSB7XG4gICAgc3VwZXIobWVzc2FnZSwgb3B0aW9ucy5jYXVzZSA/IHsgY2F1c2U6IG9wdGlvbnMuY2F1c2UgfSA6IHVuZGVmaW5lZCk7XG4gICAgdGhpcy5uYW1lID0gJ09wZW5FbGVtZW50RXJyb3InO1xuICAgIHRoaXMuY29kZSA9IG9wdGlvbnMuY29kZSA/PyBFcnJvckNvZGUuVU5LTk9XTjtcbiAgICB0aGlzLnNldmVyaXR5ID0gb3B0aW9ucy5zZXZlcml0eSA/PyAnZXJyb3InO1xuICAgIHRoaXMucGhhc2UgPSBvcHRpb25zLnBoYXNlID8/ICd1bmtub3duJztcbiAgICB0aGlzLnJlY292ZXJhYmxlID0gb3B0aW9ucy5yZWNvdmVyYWJsZSA/PyBmYWxzZTtcbiAgICB0aGlzLnN0YXR1c0NvZGUgPSBvcHRpb25zLnN0YXR1c0NvZGU7XG4gIH1cblxuICB0b0pTT04oKTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4ge1xuICAgIHJldHVybiB7XG4gICAgICBuYW1lOiB0aGlzLm5hbWUsXG4gICAgICBjb2RlOiB0aGlzLmNvZGUsXG4gICAgICBtZXNzYWdlOiB0aGlzLm1lc3NhZ2UsXG4gICAgICBzZXZlcml0eTogdGhpcy5zZXZlcml0eSxcbiAgICAgIHBoYXNlOiB0aGlzLnBoYXNlLFxuICAgICAgcmVjb3ZlcmFibGU6IHRoaXMucmVjb3ZlcmFibGUsXG4gICAgICBzdGF0dXNDb2RlOiB0aGlzLnN0YXR1c0NvZGUsXG4gICAgICBjYXVzZTogdGhpcy5jYXVzZSBpbnN0YW5jZW9mIEVycm9yID8gdGhpcy5jYXVzZS5tZXNzYWdlIDogdGhpcy5jYXVzZSxcbiAgICB9O1xuICB9XG59XG5cbi8vIOKUgOKUgOKUgCBTc3JSZW5kZXJFcnJvciAoYmFja3dhcmQgY29tcGF0KSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuZXhwb3J0IGNsYXNzIFNzclJlbmRlckVycm9yIGV4dGVuZHMgT3BlbkVsZW1lbnRFcnJvciB7XG4gIHB1YmxpYyByZWFkb25seSBjb21wb25lbnRQYXRoOiBzdHJpbmc7XG4gIHB1YmxpYyByZWFkb25seSBzb3VyY2VFcnJvcjogRXJyb3I7XG5cbiAgY29uc3RydWN0b3IoY29tcG9uZW50UGF0aDogc3RyaW5nLCBzb3VyY2VFcnJvcjogRXJyb3IpIHtcbiAgICBzdXBlcihgU1NSIHJlbmRlciBmYWlsZWQ6ICR7Y29tcG9uZW50UGF0aH1gLCB7XG4gICAgICBjb2RlOiAnU1NSX1JFTkRFUl9FUlJPUicsXG4gICAgICBzZXZlcml0eTogJ2Vycm9yJyxcbiAgICAgIHBoYXNlOiAnc3NyJyxcbiAgICAgIHJlY292ZXJhYmxlOiBmYWxzZSxcbiAgICAgIGNhdXNlOiBzb3VyY2VFcnJvcixcbiAgICB9KTtcbiAgICB0aGlzLm5hbWUgPSAnU3NyUmVuZGVyRXJyb3InO1xuICAgIHRoaXMuY29tcG9uZW50UGF0aCA9IGNvbXBvbmVudFBhdGg7XG4gICAgdGhpcy5zb3VyY2VFcnJvciA9IHNvdXJjZUVycm9yO1xuICB9XG59XG5cbi8vIOKUgOKUgOKUgCBOZXcgQURSLTAwNTMgZXJyb3IgY2xhc3NlcyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuZXhwb3J0IGNsYXNzIFJlbmRlckVycm9yIGV4dGVuZHMgT3BlbkVsZW1lbnRFcnJvciBpbXBsZW1lbnRzIFByb3RvY29sUmVuZGVyRXJyb3Ige1xuICBwdWJsaWMgcmVhZG9ubHkgY29tcG9uZW50UGF0aDogc3RyaW5nO1xuICBwdWJsaWMgcmVhZG9ubHkgdGFnTmFtZTogc3RyaW5nO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIGNvbXBvbmVudFBhdGg6IHN0cmluZyxcbiAgICBtZXNzYWdlOiBzdHJpbmcsXG4gICAgY29kZSA9ICdSRU5ERVJfRVJST1InLFxuICAgIHRhZ05hbWUgPSAnJyxcbiAgICBjYXVzZT86IEVycm9yLFxuICApIHtcbiAgICBzdXBlcihtZXNzYWdlLCB7XG4gICAgICBjb2RlLFxuICAgICAgc2V2ZXJpdHk6ICdlcnJvcicsXG4gICAgICBwaGFzZTogJ3JlbmRlcicsXG4gICAgICByZWNvdmVyYWJsZTogdHJ1ZSxcbiAgICAgIGNhdXNlLFxuICAgIH0pO1xuICAgIHRoaXMubmFtZSA9ICdSZW5kZXJFcnJvcic7XG4gICAgdGhpcy5jb21wb25lbnRQYXRoID0gY29tcG9uZW50UGF0aDtcbiAgICB0aGlzLnRhZ05hbWUgPSB0YWdOYW1lO1xuICB9XG59XG5cbmV4cG9ydCBjbGFzcyBQcm9wVmFsaWRhdGlvbkVycm9yIGV4dGVuZHMgT3BlbkVsZW1lbnRFcnJvciB7XG4gIHB1YmxpYyByZWFkb25seSBwcm9wZXJ0eU5hbWU6IHN0cmluZztcbiAgcHVibGljIHJlYWRvbmx5IHJlY2VpdmVkVmFsdWU6IHVua25vd247XG5cbiAgY29uc3RydWN0b3IocHJvcGVydHlOYW1lOiBzdHJpbmcsIHJlY2VpdmVkVmFsdWU6IHVua25vd24sIGNhdXNlPzogRXJyb3IpIHtcbiAgICBzdXBlcihgQHByb3AgdmFsaWRhdGlvbiBmYWlsZWQgZm9yIFwiJHtwcm9wZXJ0eU5hbWV9XCJgLCB7XG4gICAgICBjb2RlOiAnUFJPUF9WQUxJREFUSU9OX0VSUk9SJyxcbiAgICAgIHNldmVyaXR5OiAnd2FybmluZycsXG4gICAgICBwaGFzZTogJ3ZhbGlkYXRpb24nLFxuICAgICAgcmVjb3ZlcmFibGU6IHRydWUsXG4gICAgICBjYXVzZSxcbiAgICB9KTtcbiAgICB0aGlzLm5hbWUgPSAnUHJvcFZhbGlkYXRpb25FcnJvcic7XG4gICAgdGhpcy5wcm9wZXJ0eU5hbWUgPSBwcm9wZXJ0eU5hbWU7XG4gICAgdGhpcy5yZWNlaXZlZFZhbHVlID0gcmVjZWl2ZWRWYWx1ZTtcbiAgfVxufVxuXG4vLyDilIDilIDilIAgRXJyb3IgVGVsZW1ldHJ5IOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG5pbXBvcnQgdHlwZSB7IEVycm9yVGVsZW1ldHJ5SG9vayB9IGZyb20gJ0BvcGVuZWxlbWVudC9wcm90b2NvbC9lcnJvcnMnO1xuZXhwb3J0IHR5cGUgeyBFcnJvclRlbGVtZXRyeUhvb2sgfTtcblxubGV0IF90ZWxlbWV0cnlIb29rOiBFcnJvclRlbGVtZXRyeUhvb2sgfCB1bmRlZmluZWQ7XG5cbmV4cG9ydCBmdW5jdGlvbiBzZXRFcnJvclRlbGVtZXRyeUhvb2soaG9vazogRXJyb3JUZWxlbWV0cnlIb29rKTogdm9pZCB7XG4gIF90ZWxlbWV0cnlIb29rID0gaG9vaztcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHJlcG9ydEVycm9yKGVycm9yOiBPcGVuRWxlbWVudEVycm9yKTogdm9pZCB7XG4gIGlmIChfdGVsZW1ldHJ5SG9vaykge1xuICAgIHRyeSB7XG4gICAgICBfdGVsZW1ldHJ5SG9vayhlcnJvcik7XG4gICAgfSBjYXRjaCB7IC8qIG11c3Qgbm90IHRocm93ICovIH1cbiAgfSBlbHNlIHtcbiAgICBjb25zb2xlLmVycm9yKGBbb3BlbkVsZW1lbnQ6JHtlcnJvci5jb2RlfV0gJHtlcnJvci5tZXNzYWdlfWApO1xuICB9XG59XG5cbi8vIOKUgOKUgOKUgCBTU1IgRXJyb3IgQ29udGV4dCDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcbiJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Q0FFQyxHQUlELHNGQUFzRixHQUN0RiwwRkFBMEY7QUFDMUYsT0FBTyxNQUFNLFlBQVk7RUFDdkIsa0JBQWtCO0VBQ2xCLHFCQUFxQjtFQUNyQix1QkFBdUI7RUFDdkIsc0JBQXNCO0VBQ3RCLGtCQUFrQjtFQUNsQixhQUFhO0VBQ2IsY0FBYztFQUNkLGlCQUFpQjtFQUNqQixTQUFTO0FBQ1gsRUFBVztBQUVYLHFEQUFxRCxHQUNyRCxPQUFPLE1BQU0sZUFBZSxnQkFBZ0I7QUFFNUMsdUVBQXVFO0FBRXZFLCtEQUErRCxHQUMvRCxPQUFPLFNBQVMsWUFBWSxDQUFVO0VBQ3BDLE9BQU8sYUFBYSxRQUFRLEVBQUUsT0FBTyxHQUFHLE9BQU87QUFDakQ7QUFrQkEsT0FBTyxNQUFNLHlCQUF5QjtFQUNwQixLQUFhO0VBQ2IsU0FBd0I7RUFDeEIsTUFBa0I7RUFDbEIsWUFBcUI7RUFDckIsV0FBb0I7RUFFcEMsWUFBWSxP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
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { EventBindingDescriptor } from "./binding-descriptor.js";
|
|
2
|
+
export { createEventMarkerContext, eventMarkerId, eventTypeFromProp, serializeEventMarkers } from "./event-marker.js";
|
|
3
|
+
export type { EventMarkerContext } from "./event-marker.js";
|
|
4
|
+
export interface EventBindingRecord {
|
|
5
|
+
id: string;
|
|
6
|
+
type: string;
|
|
7
|
+
handler: EventListener;
|
|
8
|
+
}
|
|
9
|
+
/** Hydration-time event binding contract (mirrors BindingDescriptor). */ export type EventBinding = EventBindingDescriptor;
|
|
10
|
+
export declare function collectEventBindings(node: unknown): Map<string, EventBindingRecord[]>;
|
|
11
|
+
export declare function eventRecordsToDescriptors(el: Element, records: EventBindingRecord[], owner?: unknown): EventBinding[];
|
|
12
|
+
export declare function hydrateEventMarkers(root: Element | ShadowRoot, bindings: Map<string, EventBindingRecord[]>, cleanupBag: Array<() => void>, owner?: unknown): void;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Marker-based event hydration for SSR VNode output.
|
|
3
|
+
*
|
|
4
|
+
* SSR emits deterministic `data-eid` markers. During DSD upgrade,
|
|
5
|
+
* DsdElement renders the same VNode tree in memory, collects event handlers in
|
|
6
|
+
* the same traversal order, and binds them to matching DOM markers without
|
|
7
|
+
* replacing the existing DSD DOM.
|
|
8
|
+
*/ import { FOR_TAG, Fragment, SHOW_TAG } from './jsx-runtime.js';
|
|
9
|
+
import { isSignalLike } from '@openelement/signal';
|
|
10
|
+
import { isComponentCtor, isVNode } from './vnode.js';
|
|
11
|
+
import { DATA_EID } from '@openelement/protocol/hydration-markers';
|
|
12
|
+
import { applyBindingDescriptor } from './binding-activation.js';
|
|
13
|
+
import { eventMarkerId, eventTypeFromProp } from './event-marker.js';
|
|
14
|
+
// Re-export pure marker helpers so existing consumers keep working.
|
|
15
|
+
export { createEventMarkerContext, eventMarkerId, eventTypeFromProp, serializeEventMarkers } from './event-marker.js';
|
|
16
|
+
export function collectEventBindings(node) {
|
|
17
|
+
const bindings = new Map();
|
|
18
|
+
let count = 0;
|
|
19
|
+
const visit = (value)=>{
|
|
20
|
+
if (value == null || value === false || typeof value === 'string' || typeof value === 'number') {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
if (isSignalLike(value)) {
|
|
24
|
+
visit(value.value);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (!isVNode(value)) return;
|
|
28
|
+
const { tag, props, children } = value;
|
|
29
|
+
if (tag === Fragment || typeof tag === 'symbol' && String(tag) === 'Symbol(openelement.fragment)') {
|
|
30
|
+
for (const child of children)visit(child);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
if (tag === SHOW_TAG || tag === 'show') {
|
|
34
|
+
const whenVal = isSignalLike(props?.when) ? props.when.value : props?.when;
|
|
35
|
+
const target = whenVal ? children[0] : children[1];
|
|
36
|
+
visit(target);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if (tag === FOR_TAG || tag === 'fore') {
|
|
40
|
+
const items = isSignalLike(props?.each) ? props.each.value : props?.each;
|
|
41
|
+
const renderFn = children[0];
|
|
42
|
+
if (Array.isArray(items) && typeof renderFn === 'function') {
|
|
43
|
+
items.forEach((item, i)=>visit(renderFn(item, i)));
|
|
44
|
+
}
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (isComponentCtor(tag)) {
|
|
48
|
+
try {
|
|
49
|
+
const instance = new tag();
|
|
50
|
+
for (const [k, v] of Object.entries(props)){
|
|
51
|
+
instance[k] = v;
|
|
52
|
+
}
|
|
53
|
+
visit(instance.render());
|
|
54
|
+
} catch {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (typeof tag === 'function') {
|
|
60
|
+
try {
|
|
61
|
+
visit(tag({
|
|
62
|
+
...props,
|
|
63
|
+
children
|
|
64
|
+
}));
|
|
65
|
+
} catch {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const records = [];
|
|
71
|
+
for (const [key, value] of Object.entries(props ?? {})){
|
|
72
|
+
const type = eventTypeFromProp(key);
|
|
73
|
+
if (type && typeof value === 'function') {
|
|
74
|
+
records.push({
|
|
75
|
+
id: '',
|
|
76
|
+
type,
|
|
77
|
+
handler: value
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// Visit children before assigning an ID to this element so the order
|
|
82
|
+
// matches SSR (renderToNode serializes children first).
|
|
83
|
+
for (const child of children)visit(child);
|
|
84
|
+
if (records.length > 0) {
|
|
85
|
+
const id = eventMarkerId(count++);
|
|
86
|
+
bindings.set(id, records.map((record)=>({
|
|
87
|
+
...record,
|
|
88
|
+
id
|
|
89
|
+
})));
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
visit(node);
|
|
93
|
+
return bindings;
|
|
94
|
+
}
|
|
95
|
+
export function eventRecordsToDescriptors(el, records, owner) {
|
|
96
|
+
return records.map((record)=>{
|
|
97
|
+
const handler = owner && typeof record.handler === 'function' ? record.handler.bind(owner) : record.handler;
|
|
98
|
+
return {
|
|
99
|
+
kind: 'event',
|
|
100
|
+
el,
|
|
101
|
+
type: record.type,
|
|
102
|
+
handler
|
|
103
|
+
};
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
export function hydrateEventMarkers(root, bindings, cleanupBag, owner) {
|
|
107
|
+
for (const el of root.querySelectorAll(`[${DATA_EID}]`)){
|
|
108
|
+
const id = el.getAttribute(DATA_EID);
|
|
109
|
+
if (!id) continue;
|
|
110
|
+
const records = bindings.get(id);
|
|
111
|
+
if (!records) continue;
|
|
112
|
+
for (const desc of eventRecordsToDescriptors(el, records, owner)){
|
|
113
|
+
const dispose = applyBindingDescriptor(desc, {});
|
|
114
|
+
cleanupBag.push(dispose);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vaG9tZS9ydW5uZXIvd29yay9vcGVuZWxlbWVudC9vcGVuZWxlbWVudC9wYWNrYWdlcy9jb3JlL3NyYy9ldmVudC1oeWRyYXRpb24udHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBNYXJrZXItYmFzZWQgZXZlbnQgaHlkcmF0aW9uIGZvciBTU1IgVk5vZGUgb3V0cHV0LlxuICpcbiAqIFNTUiBlbWl0cyBkZXRlcm1pbmlzdGljIGBkYXRhLWVpZGAgbWFya2Vycy4gRHVyaW5nIERTRCB1cGdyYWRlLFxuICogRHNkRWxlbWVudCByZW5kZXJzIHRoZSBzYW1lIFZOb2RlIHRyZWUgaW4gbWVtb3J5LCBjb2xsZWN0cyBldmVudCBoYW5kbGVycyBpblxuICogdGhlIHNhbWUgdHJhdmVyc2FsIG9yZGVyLCBhbmQgYmluZHMgdGhlbSB0byBtYXRjaGluZyBET00gbWFya2VycyB3aXRob3V0XG4gKiByZXBsYWNpbmcgdGhlIGV4aXN0aW5nIERTRCBET00uXG4gKi9cblxuaW1wb3J0IHsgRk9SX1RBRywgRnJhZ21lbnQsIFNIT1dfVEFHIH0gZnJvbSAnLi9qc3gtcnVudGltZS5qcyc7XG5pbXBvcnQgeyBpc1NpZ25hbExpa2UgfSBmcm9tICdAb3BlbmVsZW1lbnQvc2lnbmFsJztcbmltcG9ydCB7IGlzQ29tcG9uZW50Q3RvciwgaXNWTm9kZSB9IGZyb20gJy4vdm5vZGUuanMnO1xuaW1wb3J0IHR5cGUgeyBSZW5kZXJGbiwgVk5vZGUgfSBmcm9tICdAb3BlbmVsZW1lbnQvcHJvdG9jb2wvdm5vZGUnO1xuaW1wb3J0IHsgREFUQV9FSUQgfSBmcm9tICdAb3BlbmVsZW1lbnQvcHJvdG9jb2wvaHlkcmF0aW9uLW1hcmtlcnMnO1xuaW1wb3J0IHsgYXBwbHlCaW5kaW5nRGVzY3JpcHRvciB9IGZyb20gJy4vYmluZGluZy1hY3RpdmF0aW9uLmpzJztcbmltcG9ydCB0eXBlIHsgRXZlbnRCaW5kaW5nRGVzY3JpcHRvciB9IGZyb20gJy4vYmluZGluZy1kZXNjcmlwdG9yLmpzJztcbmltcG9ydCB7IGV2ZW50TWFya2VySWQsIGV2ZW50VHlwZUZyb21Qcm9wIH0gZnJvbSAnLi9ldmVudC1tYXJrZXIuanMnO1xuXG4vLyBSZS1leHBvcnQgcHVyZSBtYXJrZXIgaGVscGVycyBzbyBleGlzdGluZyBjb25zdW1lcnMga2VlcCB3b3JraW5nLlxuZXhwb3J0IHtcbiAgY3JlYXRlRXZlbnRNYXJrZXJDb250ZXh0LFxuICBldmVudE1hcmtlcklkLFxuICBldmVudFR5cGVGcm9tUHJvcCxcbiAgc2VyaWFsaXplRXZlbnRNYXJrZXJzLFxufSBmcm9tICcuL2V2ZW50LW1hcmtlci5qcyc7XG5leHBvcnQgdHlwZSB7IEV2ZW50TWFya2VyQ29udGV4dCB9IGZyb20gJy4vZXZlbnQtbWFya2VyLmpzJztcblxuZXhwb3J0IGludGVyZmFjZSBFdmVudEJpbmRpbmdSZWNvcmQge1xuICBpZDogc3RyaW5nO1xuICB0eXBlOiBzdHJpbmc7XG4gIGhhbmRsZXI6IEV2ZW50TGlzdGVuZXI7XG59XG5cbi8qKiBIeWRyYXRpb24tdGltZSBldmVudCBiaW5kaW5nIGNvbnRyYWN0IChtaXJyb3JzIEJpbmRpbmdEZXNjcmlwdG9yKS4gKi9cbmV4cG9ydCB0eXBlIEV2ZW50QmluZGluZyA9IEV2ZW50QmluZGluZ0Rlc2NyaXB0b3I7XG5cbmV4cG9ydCBmdW5jdGlvbiBjb2xsZWN0RXZlbnRCaW5kaW5ncyhub2RlOiB1bmtub3duKTogTWFwPHN0cmluZywgRXZlbnRCaW5kaW5nUmVjb3JkW10+IHtcbiAgY29uc3QgYmluZGluZ3MgPSBuZXcgTWFwPHN0cmluZywgRXZlbnRCaW5kaW5nUmVjb3JkW10+KCk7XG4gIGxldCBjb3VudCA9IDA7XG5cbiAgY29uc3QgdmlzaXQgPSAodmFsdWU6IHVua25vd24pOiB2b2lkID0+IHtcbiAgICBpZiAoXG4gICAgICB2YWx1ZSA9PSBudWxsIHx8IHZhbHVlID09PSBmYWxzZSB8fCB0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnIHx8IHR5cGVvZiB2YWx1ZSA9PT0gJ251bWJlcidcbiAgICApIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKGlzU2lnbmFsTGlrZSh2YWx1ZSkpIHtcbiAgICAgIHZpc2l0KCh2YWx1ZSBhcyB7IHZhbHVlOiB1bmtub3duIH0pLnZhbHVlKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKCFpc1ZOb2RlKHZhbHVlKSkgcmV0dXJuO1xuXG4gICAgY29uc3QgeyB0YWcsIHByb3BzLCBjaGlsZHJlbiB9ID0gdmFsdWUgYXMgVk5vZGU7XG5cbiAgICBpZiAoXG4gICAgICB0YWcgPT09IEZyYWdtZW50IHx8XG4gICAgICAodHlwZW9mIHRhZyA9PT0gJ3N5bWJvbCcgJiYgU3RyaW5nKHRhZykgPT09ICdTeW1ib2wob3BlbmVsZW1lbnQuZnJhZ21lbnQpJylcbiAgICApIHtcbiAgICAgIGZvciAoY29uc3QgY2hpbGQgb2YgY2hpbGRyZW4pIHZpc2l0KGNoaWxkKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAodGFnID09PSBTSE9XX1RBRyB8fCB0YWcgPT09ICdzaG93Jykge1xuICAgICAgY29uc3Qgd2hlblZhbCA9IGlzU2lnbmFsTGlrZShwcm9wcz8ud2hlbilcbiAgICAgICAgPyAocHJvcHMhLndoZW4gYXMgeyB2YWx1ZTogdW5rbm93biB9KS52YWx1ZVxuICAgICAgICA6IHByb3BzPy53aGVuO1xuICAgICAgY29uc3QgdGFyZ2V0ID0gd2hlblZhbCA/IGNoaWxkcmVuWzBdIDogY2hpbGRyZW5bMV07XG4gICAgICB2aXNpdCh0YXJnZXQpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmICh0YWcgPT09IEZPUl9UQUcgfHwgdGFnID09PSAnZm9yZScpIHtcbiAgICAgIGNvbnN0IGl0ZW1zID0gKGlzU2lnbmFsTGlrZShwcm9wcz8uZWFjaClcbiAgICAgICAgPyAocHJvcHMhLmVhY2ggYXMgeyB2YWx1ZTogdW5rbm93biB9KS52YWx1ZVxuICAgICAgICA6IHByb3BzPy5lYWNoKSBhcyB1bmtub3duW107XG4gICAgICBjb25zdCByZW5kZXJGbiA9IGNoaWxkcmVuWzBdIGFzIFJlbmRlckZuO1xuICAgICAgaWYgKEFycmF5LmlzQXJyYXkoaXRlbXMpICYmIHR5cGVvZiByZW5kZXJGbiA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICBpdGVtcy5mb3JFYWNoKChpdGVtLCBpKSA9PlxuICAgICAgICAgIHZpc2l0KHJlbmRlckZuKGl0ZW0sIGkpKVxuICAgICAgICApO1xuICAgICAgfVxuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChpc0NvbXBvbmVudEN0b3IodGFnKSkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgaW5zdGFuY2UgPSBuZXcgdGFnKCk7XG4gICAgICAgIGZvciAoY29uc3QgW2ssIHZdIG9mIE9iamVjdC5lbnRyaWVzKHByb3BzKSkge1xuICAgICAgICAgIChpbnN0YW5jZSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPilba10gPSB2O1xuICAgICAgICB9XG4gICAgICAgIHZpc2l0KGluc3RhbmNlLnJlbmRlcigpKTtcbiAgICAgIH0gY2F0Y2gge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHR5cGVvZiB0YWcgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIHZpc2l0KCh0YWcgYXMgKHByb3BzOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPikgPT4gdW5rbm93bikoeyAuLi5wcm9wcywgY2hpbGRyZW4gfSkpO1xuICAgICAgfSBjYXRjaCB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCByZWNvcmRzOiBFdmVudEJpbmRpbmdSZWNvcmRbXSA9IFtdO1xuICAgIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKHByb3BzID8/IHt9KSkge1xuICAgICAgY29uc3QgdHlwZSA9IGV2ZW50VHlwZUZyb21Qcm9wKGtleSk7XG4gICAgICBpZiAodHlwZSAmJiB0eXBlb2YgdmFsdWUgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgcmVjb3Jkcy5wdXNoKHtcbiAgICAgICAgICBpZDogJycsXG4gICAgICAgICAgdHlwZSxcbiAgICAgICAgICBoYW5kbGVyOiB2YWx1ZSBhcyBFdmVudExpc3RlbmVyLFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBWaXNpdCBjaGlsZHJlbiBiZWZvcmUgYXNzaWduaW5nIGFuIElEIHRvIHRoaXMgZWxlbWVudCBzbyB0aGUgb3JkZXJcbiAgICAvLyBtYXRjaGVzIFNTUiAocmVuZGVyVG9Ob2RlIHNlcmlhbGl6ZXMgY2hpbGRyZW4gZmlyc3QpLlxuICAgIGZvciAoY29uc3QgY2hpbGQgb2YgY2hpbGRyZW4pIHZpc2l0KGNoaWxkKTtcblxuICAgIGlmIChyZWNvcmRzLmxlbmd0aCA+IDApIHtcbiAgICAgIGNvbnN0IGlkID0gZXZlbnRNYXJrZXJJZChjb3VudCsrKTtcbiAgICAgIGJpbmRpbmdzLnNldChpZCwgcmVjb3Jkcy5tYXAoKHJlY29yZCkgPT4gKHsgLi4ucmVjb3JkLCBpZCB9KSkpO1xuICAgIH1cbiAgfTtcblxuICB2aXNpdChub2RlKTtcbiAgcmV0dXJuIGJpbmRpbmdzO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZXZlbnRSZWNvcmRzVG9EZXNjcmlwdG9ycyhcbiAgZWw6IEVsZW1lbnQsXG4gIHJlY29yZHM6IEV2ZW50QmluZGluZ1JlY29yZFtdLFxuICBvd25lcj86IHVua25vd24sXG4pOiBFdmVudEJpbmRpbmdbXSB7XG4gIHJldHVybiByZWNvcmRzLm1hcCgocmVjb3JkKSA9PiB7XG4gICAgY29uc3QgaGFuZGxlciA9IG93bmVyICYmIHR5cGVvZiByZWNvcmQuaGFuZGxlciA9PT0gJ2Z1bmN0aW9uJ1xuICAgICAgPyAocmVjb3JkLmhhbmRsZXIgYXMgRXZlbnRMaXN0ZW5lcikuYmluZChvd25lcilcbiAgICAgIDogcmVjb3JkLmhhbmRsZXIgYXMgRXZlbnRMaXN0ZW5lcjtcbiAgICByZXR1cm4ge1xuICAgICAga2luZDogJ2V2ZW50JyxcbiAgICAgIGVsLFxuICAgICAgdHlwZTogcmVjb3JkLnR5cGUsXG4gICAgICBoYW5kbGVyLFxuICAgIH07XG4gIH0pO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gaHlkcmF0ZUV2ZW50TWFya2VycyhcbiAgcm9vdDogRWxlbWVudCB8IFNoYWRvd1Jvb3QsXG4gIGJpbmRpbmdzOiBNYXA8c3RyaW5nLCBFdmVudEJpbmRpbmdSZWNvcmRbXT4sXG4gIGNsZWFudXBCYWc6IEFycmF5PCgpID0+IHZvaWQ+LFxuICBvd25lcj86IHVua25vd24sXG4pOiB2b2lkIHtcbiAgZm9yIChjb25zdCBlbCBvZiByb290LnF1ZXJ5U2VsZWN0b3JBbGwoYFske0RBVEFfRUlEfV1gKSkge1xuICAgIGNvbnN0IGlkID0gZWwuZ2V0QXR0cmlidXRlKERBVEFfRUlEKTtcbiAgICBpZiAoIWlkKSBjb250aW51ZTtcbiAgICBjb25zdCByZWNvcmRzID0gYmluZGluZ3MuZ2V0KGlkKTtcbiAgICBpZiAoIXJlY29yZHMpIGNvbnRpbnVlO1xuICAgIGZvciAoY29uc3QgZGVzYyBvZiBldmVudFJlY29yZHNUb0Rlc2NyaXB0b3JzKGVsLCByZWNvcmRzLCBvd25lcikpIHtcbiAgICAgIGNvbnN0IGRpc3Bvc2UgPSBhcHBseUJpbmRpbmdEZXNjcmlwdG9yKGRlc2MsIHt9KTtcbiAgICAgIGNsZWFudXBCYWcucHVzaChkaXNwb3NlKTtcbiAgICB9XG4gIH1cbn1cbiJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7OztDQU9DLEdBRUQsU0FBUyxPQUFPLEVBQUUsUUFBUSxFQUFFLFFBQVEsUUFBUSxtQkFBbUI7QUFDL0QsU0FBUyxZQUFZLFFBQVEsc0JBQXNCO0FBQ25ELFNBQVMsZUFBZSxFQUFFLE9BQU8sUUFBUSxhQUFhO0FBRXRELFNBQVMsUUFBUSxRQUFRLDBDQUEwQztBQUNuRSxTQUFTLHNCQUFzQixRQUFRLDBCQUEw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
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface EventMarkerContext {
|
|
2
|
+
nextId(): string;
|
|
3
|
+
}
|
|
4
|
+
export declare function createEventMarkerContext(): EventMarkerContext;
|
|
5
|
+
export declare function eventMarkerId(index: number): string;
|
|
6
|
+
export declare function eventTypeFromProp(prop: string): string | null;
|
|
7
|
+
export declare function serializeEventMarkers(props: Record<string, unknown> | undefined, context: EventMarkerContext): string;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @openelement/core - Deterministic event marker generation for SSR output.
|
|
3
|
+
*
|
|
4
|
+
* Pure, side-effect-free helper used by the SSR renderer to emit `data-eid`
|
|
5
|
+
* markers. This module intentionally does NOT depend on the DOM binding layer
|
|
6
|
+
* so that static-only bundles can use it without pulling in hydration code.
|
|
7
|
+
*
|
|
8
|
+
* Hydration-time binding logic lives in `event-hydration.ts`.
|
|
9
|
+
*
|
|
10
|
+
* @module @openelement/core/event-marker
|
|
11
|
+
*/ import { DATA_EID } from '@openelement/protocol/hydration-markers';
|
|
12
|
+
const EVENT_PROP_RE = /^on[A-Z]/;
|
|
13
|
+
const EVENT_TYPE_ALIASES = {
|
|
14
|
+
Dblclick: 'dblclick',
|
|
15
|
+
DoubleClick: 'dblclick',
|
|
16
|
+
FocusIn: 'focusin',
|
|
17
|
+
FocusOut: 'focusout',
|
|
18
|
+
MouseEnter: 'mouseenter',
|
|
19
|
+
MouseLeave: 'mouseleave',
|
|
20
|
+
PointerCancel: 'pointercancel',
|
|
21
|
+
PointerDown: 'pointerdown',
|
|
22
|
+
PointerEnter: 'pointerenter',
|
|
23
|
+
PointerLeave: 'pointerleave',
|
|
24
|
+
PointerMove: 'pointermove',
|
|
25
|
+
PointerOut: 'pointerout',
|
|
26
|
+
PointerOver: 'pointerover',
|
|
27
|
+
PointerUp: 'pointerup'
|
|
28
|
+
};
|
|
29
|
+
export function createEventMarkerContext() {
|
|
30
|
+
let count = 0;
|
|
31
|
+
return {
|
|
32
|
+
nextId () {
|
|
33
|
+
return eventMarkerId(count++);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export function eventMarkerId(index) {
|
|
38
|
+
return `e${index}`;
|
|
39
|
+
}
|
|
40
|
+
export function eventTypeFromProp(prop) {
|
|
41
|
+
if (!EVENT_PROP_RE.test(prop)) return null;
|
|
42
|
+
const eventName = prop.slice(2);
|
|
43
|
+
return EVENT_TYPE_ALIASES[eventName] ?? eventName.toLowerCase();
|
|
44
|
+
}
|
|
45
|
+
export function serializeEventMarkers(props, context) {
|
|
46
|
+
if (!props) return '';
|
|
47
|
+
for (const [key, value] of Object.entries(props)){
|
|
48
|
+
if (eventTypeFromProp(key) && typeof value === 'function') {
|
|
49
|
+
return ` ${DATA_EID}="${context.nextId()}"`;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return '';
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vaG9tZS9ydW5uZXIvd29yay9vcGVuZWxlbWVudC9vcGVuZWxlbWVudC9wYWNrYWdlcy9jb3JlL3NyYy9ldmVudC1tYXJrZXIudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAb3BlbmVsZW1lbnQvY29yZSAtIERldGVybWluaXN0aWMgZXZlbnQgbWFya2VyIGdlbmVyYXRpb24gZm9yIFNTUiBvdXRwdXQuXG4gKlxuICogUHVyZSwgc2lkZS1lZmZlY3QtZnJlZSBoZWxwZXIgdXNlZCBieSB0aGUgU1NSIHJlbmRlcmVyIHRvIGVtaXQgYGRhdGEtZWlkYFxuICogbWFya2Vycy4gVGhpcyBtb2R1bGUgaW50ZW50aW9uYWxseSBkb2VzIE5PVCBkZXBlbmQgb24gdGhlIERPTSBiaW5kaW5nIGxheWVyXG4gKiBzbyB0aGF0IHN0YXRpYy1vbmx5IGJ1bmRsZXMgY2FuIHVzZSBpdCB3aXRob3V0IHB1bGxpbmcgaW4gaHlkcmF0aW9uIGNvZGUuXG4gKlxuICogSHlkcmF0aW9uLXRpbWUgYmluZGluZyBsb2dpYyBsaXZlcyBpbiBgZXZlbnQtaHlkcmF0aW9uLnRzYC5cbiAqXG4gKiBAbW9kdWxlIEBvcGVuZWxlbWVudC9jb3JlL2V2ZW50LW1hcmtlclxuICovXG5cbmltcG9ydCB7IERBVEFfRUlEIH0gZnJvbSAnQG9wZW5lbGVtZW50L3Byb3RvY29sL2h5ZHJhdGlvbi1tYXJrZXJzJztcblxuY29uc3QgRVZFTlRfUFJPUF9SRSA9IC9eb25bQS1aXS87XG5jb25zdCBFVkVOVF9UWVBFX0FMSUFTRVM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gIERibGNsaWNrOiAnZGJsY2xpY2snLFxuICBEb3VibGVDbGljazogJ2RibGNsaWNrJyxcbiAgRm9jdXNJbjogJ2ZvY3VzaW4nLFxuICBGb2N1c091dDogJ2ZvY3Vzb3V0JyxcbiAgTW91c2VFbnRlcjogJ21vdXNlZW50ZXInLFxuICBNb3VzZUxlYXZlOiAnbW91c2VsZWF2ZScsXG4gIFBvaW50ZXJDYW5jZWw6ICdwb2ludGVyY2FuY2VsJyxcbiAgUG9pbnRlckRvd246ICdwb2ludGVyZG93bicsXG4gIFBvaW50ZXJFbnRlcjogJ3BvaW50ZXJlbnRlcicsXG4gIFBvaW50ZXJMZWF2ZTogJ3BvaW50ZXJsZWF2ZScsXG4gIFBvaW50ZXJNb3ZlOiAncG9pbnRlcm1vdmUnLFxuICBQb2ludGVyT3V0OiAncG9pbnRlcm91dCcsXG4gIFBvaW50ZXJPdmVyOiAncG9pbnRlcm92ZXInLFxuICBQb2ludGVyVXA6ICdwb2ludGVydXAnLFxufTtcblxuZXhwb3J0IGludGVyZmFjZSBFdmVudE1hcmtlckNvbnRleHQge1xuICBuZXh0SWQoKTogc3RyaW5nO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlRXZlbnRNYXJrZXJDb250ZXh0KCk6IEV2ZW50TWFya2VyQ29udGV4dCB7XG4gIGxldCBjb3VudCA9IDA7XG4gIHJldHVybiB7XG4gICAgbmV4dElkKCk6IHN0cmluZyB7XG4gICAgICByZXR1cm4gZXZlbnRNYXJrZXJJZChjb3VudCsrKTtcbiAgICB9LFxuICB9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZXZlbnRNYXJrZXJJZChpbmRleDogbnVtYmVyKTogc3RyaW5nIHtcbiAgcmV0dXJuIGBlJHtpbmRleH1gO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZXZlbnRUeXBlRnJvbVByb3AocHJvcDogc3RyaW5nKTogc3RyaW5nIHwgbnVsbCB7XG4gIGlmICghRVZFTlRfUFJPUF9SRS50ZXN0KHByb3ApKSByZXR1cm4gbnVsbDtcbiAgY29uc3QgZXZlbnROYW1lID0gcHJvcC5zbGljZSgyKTtcbiAgcmV0dXJuIEVWRU5UX1RZUEVfQUxJQVNFU1tldmVudE5hbWVdID8/IGV2ZW50TmFtZS50b0xvd2VyQ2FzZSgpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gc2VyaWFsaXplRXZlbnRNYXJrZXJzKFxuICBwcm9wczogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfCB1bmRlZmluZWQsXG4gIGNvbnRleHQ6IEV2ZW50TWFya2VyQ29udGV4dCxcbik6IHN0cmluZyB7XG4gIGlmICghcHJvcHMpIHJldHVybiAnJztcbiAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMocHJvcHMpKSB7XG4gICAgaWYgKGV2ZW50VHlwZUZyb21Qcm9wKGtleSkgJiYgdHlwZW9mIHZhbHVlID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICByZXR1cm4gYCAke0RBVEFfRUlEfT1cIiR7Y29udGV4dC5uZXh0SWQoKX1cImA7XG4gICAgfVxuICB9XG4gIHJldHVybiAnJztcbn1cbiJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7OztDQVVDLEdBRUQsU0FBUyxRQUFRLFFBQVEsMENBQTBDO0FBRW5FLE1BQU0sZ0JBQWdCO0FBQ3RCLE1BQU0scUJBQTZDO0VBQ2pELFVBQVU7RUFDVixhQUFhO0VBQ2IsU0FBUztFQUNULFVBQVU7RUFDVixZQUFZO0VBQ1osWUFBWTtFQUNaLGVBQWU7RUFDZixhQUFhO0VBQ2IsY0FBYztFQUNkLGNBQWM7RUFDZCxhQUFhO0VBQ2IsWUFBWTtFQUNaLGFBQWE7RUFDYixXQUFXO0FBQ2I7QUFNQSxPQUFPLFNBQVM7RUFDZCxJQUFJLFFBQVE7RUFDWixPQUFPO0lBQ0w7TUFDRSxPQUFPLGNBQWM7SUFDdkI7RUFDRjtBQUNGO0FBRUEsT0FBTyxTQUFTLGNBQWMsS0FBYTtFQUN6QyxPQUFPLENBQUMsQ0FBQyxFQUFFLE9BQU87QUFDcEI7QUFFQSxPQUFPLFNBQVMsa0JBQWtCLElBQVk7RUFDNUMsSUFBSSxDQUFDLGNBQWMsSUFBSSxDQUFDLE9BQU8sT0FBTztFQUN0QyxNQUFNLFlBQVksS0FBSyxLQUFLLENBQUM7RUFDN0IsT0FBTyxrQkFBa0IsQ0FBQyxVQUFVLElBQUksVUFBVSxXQUFXO0FBQy9EO0FBRUEsT0FBTyxTQUFTLHNCQUNkLEtBQTBDLEVBQzFDLE9BQTJCO0VBRTNCLElBQUksQ0FBQyxPQUFPLE9BQU87RUFDbkIsS0FBSyxNQUFNLENBQUMsS0FBSyxNQUFNLElBQUksT0FBTyxPQUFPLENBQUMsT0FBUTtJQUNoRCxJQUFJLGtCQUFrQixRQUFRLE9BQU8sVUFBVSxZQUFZO01BQ3pELE9BQU8sQ0FBQyxDQUFDLEVBQUUsU0FBUyxFQUFFLEVBQUUsUUFBUSxNQUFNLEdBQUcsQ0FBQyxDQUFDO0lBQzdDO0VBQ0Y7RUFDQSxPQUFPO0FBQ1QifQ==
|