@monimesl/dot-core 0.1.0-alpha.2
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/README.md +1 -0
- package/dist/index.d.ts +427 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +445 -0
- package/dist/index.js.map +1 -0
- package/package.json +43 -0
package/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# @monimesl/dot-core
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
//#region src/event/core.d.ts
|
|
2
|
+
interface DotEvent<Detail = unknown> {
|
|
3
|
+
readonly type: string;
|
|
4
|
+
readonly detail: Detail;
|
|
5
|
+
}
|
|
6
|
+
export declare function createEvent<Detail = Record<string, never>>(type: string, detail?: Detail): DotEvent<Detail>;
|
|
7
|
+
//#endregion
|
|
8
|
+
//#region src/view/component.d.ts
|
|
9
|
+
interface PropTypes {
|
|
10
|
+
string: string;
|
|
11
|
+
number: number;
|
|
12
|
+
boolean: boolean;
|
|
13
|
+
any: unknown;
|
|
14
|
+
}
|
|
15
|
+
type PropType = keyof PropTypes | readonly string[];
|
|
16
|
+
type PropValue<T extends PropType> = T extends readonly string[] ? T[number] : T extends keyof PropTypes ? PropTypes[T] : never;
|
|
17
|
+
/**
|
|
18
|
+
* - `none`: no children
|
|
19
|
+
* - `text`: text and inline components (such as `Text`).
|
|
20
|
+
* - `elements`: any components, but raw text must be wrapped in an inline component.
|
|
21
|
+
*/
|
|
22
|
+
type ChildrenType = 'none' | 'text' | 'elements';
|
|
23
|
+
/**
|
|
24
|
+
* Describes a UI component independently of any renderer. The compiler checks `.dml` markup
|
|
25
|
+
* against it, and each renderer maps it to its own elements.
|
|
26
|
+
*/
|
|
27
|
+
interface ComponentManifest<Name extends string = string, Props extends Record<string, PropType> = Record<string, PropType>, Events extends string = string, Children extends ChildrenType = ChildrenType> {
|
|
28
|
+
readonly name: Name;
|
|
29
|
+
readonly props: Props;
|
|
30
|
+
readonly events: readonly Events[];
|
|
31
|
+
readonly children: Children;
|
|
32
|
+
readonly inline?: boolean;
|
|
33
|
+
}
|
|
34
|
+
export declare function defineComponent<const Name extends string, const Props extends Record<string, PropType> = Record<never, PropType>, const Events extends string = never, const Children extends ChildrenType = ChildrenType>(manifest: {
|
|
35
|
+
name: Name;
|
|
36
|
+
props?: Props;
|
|
37
|
+
events?: readonly Events[];
|
|
38
|
+
children: Children;
|
|
39
|
+
inline?: boolean;
|
|
40
|
+
}): ComponentManifest<Name, Props, Events, Children>;
|
|
41
|
+
type EventProp<Event extends string> = `on${Capitalize<Event>}`;
|
|
42
|
+
export declare function eventProp<Event extends string>(event: Event): EventProp<Event>;
|
|
43
|
+
export declare function isEventProp(name: string): boolean;
|
|
44
|
+
export declare function eventName(prop: string): string;
|
|
45
|
+
/**
|
|
46
|
+
* The props a renderer's implementation of `M` receives, with `Children` as its node type. Every
|
|
47
|
+
* prop is optional and may be `undefined`: markup can omit it, and a binding can evaluate to
|
|
48
|
+
* `undefined` at runtime.
|
|
49
|
+
*/
|
|
50
|
+
type PropsOf<M extends ComponentManifest, Children = never> = { [K in keyof M['props']]?: PropValue<M['props'][K]> | undefined; } & { [E in M['events'][number] as EventProp<E>]?: ((event: DotEvent) => void) | undefined; } & (M['children'] extends 'none' ? unknown : {
|
|
51
|
+
children?: Children | undefined;
|
|
52
|
+
});
|
|
53
|
+
type ComponentRegistry = Readonly<Record<string, ComponentManifest>>;
|
|
54
|
+
export declare function componentRegistry(manifests: Iterable<ComponentManifest>): ComponentRegistry;
|
|
55
|
+
//#endregion
|
|
56
|
+
//#region src/view/components/button.d.ts
|
|
57
|
+
export declare const Button: ComponentManifest<"Button", {
|
|
58
|
+
readonly variant: readonly ["primary", "secondary"];
|
|
59
|
+
readonly disabled: "boolean";
|
|
60
|
+
}, "click", "text">;
|
|
61
|
+
//#endregion
|
|
62
|
+
//#region src/view/components/image.d.ts
|
|
63
|
+
export declare const Image: ComponentManifest<"Image", {
|
|
64
|
+
readonly src: "string";
|
|
65
|
+
readonly alt: "string";
|
|
66
|
+
readonly width: "number";
|
|
67
|
+
readonly height: "number";
|
|
68
|
+
}, "load" | "error", "none">;
|
|
69
|
+
//#endregion
|
|
70
|
+
//#region src/view/components/input.d.ts
|
|
71
|
+
export declare const Input: ComponentManifest<"Input", {
|
|
72
|
+
readonly value: "string";
|
|
73
|
+
readonly placeholder: "string";
|
|
74
|
+
readonly label: "string";
|
|
75
|
+
readonly type: readonly ["text", "number", "email", "phone", "password"];
|
|
76
|
+
readonly maxLength: "number";
|
|
77
|
+
readonly disabled: "boolean";
|
|
78
|
+
}, "change" | "submit", "none">;
|
|
79
|
+
//#endregion
|
|
80
|
+
//#region src/view/components/text.d.ts
|
|
81
|
+
export declare const Text: ComponentManifest<"Text", {
|
|
82
|
+
readonly variant: readonly ["title", "body", "caption"];
|
|
83
|
+
}, never, "text">;
|
|
84
|
+
//#endregion
|
|
85
|
+
//#region src/view/components/view.d.ts
|
|
86
|
+
export declare const View: ComponentManifest<"View", {
|
|
87
|
+
readonly direction: readonly ["column", "row"];
|
|
88
|
+
readonly gap: readonly ["none", "small", "medium", "large"];
|
|
89
|
+
readonly align: readonly ["stretch", "start", "center", "end"];
|
|
90
|
+
readonly variant: readonly ["plain", "card"];
|
|
91
|
+
}, "tap", "elements">;
|
|
92
|
+
//#endregion
|
|
93
|
+
//#region src/view/components/index.d.ts
|
|
94
|
+
export declare const builtinComponents: {
|
|
95
|
+
readonly Button: ComponentManifest<"Button", {
|
|
96
|
+
readonly variant: readonly ["primary", "secondary"];
|
|
97
|
+
readonly disabled: "boolean";
|
|
98
|
+
}, "click", "text">;
|
|
99
|
+
readonly Image: ComponentManifest<"Image", {
|
|
100
|
+
readonly src: "string";
|
|
101
|
+
readonly alt: "string";
|
|
102
|
+
readonly width: "number";
|
|
103
|
+
readonly height: "number";
|
|
104
|
+
}, "load" | "error", "none">;
|
|
105
|
+
readonly Input: ComponentManifest<"Input", {
|
|
106
|
+
readonly value: "string";
|
|
107
|
+
readonly placeholder: "string";
|
|
108
|
+
readonly label: "string";
|
|
109
|
+
readonly type: readonly ["text", "number", "email", "phone", "password"];
|
|
110
|
+
readonly maxLength: "number";
|
|
111
|
+
readonly disabled: "boolean";
|
|
112
|
+
}, "change" | "submit", "none">;
|
|
113
|
+
readonly Text: ComponentManifest<"Text", {
|
|
114
|
+
readonly variant: readonly ["title", "body", "caption"];
|
|
115
|
+
}, never, "text">;
|
|
116
|
+
readonly View: ComponentManifest<"View", {
|
|
117
|
+
readonly direction: readonly ["column", "row"];
|
|
118
|
+
readonly gap: readonly ["none", "small", "medium", "large"];
|
|
119
|
+
readonly align: readonly ["stretch", "start", "center", "end"];
|
|
120
|
+
readonly variant: readonly ["plain", "card"];
|
|
121
|
+
}, "tap", "elements">;
|
|
122
|
+
};
|
|
123
|
+
type BuiltinComponents = typeof builtinComponents;
|
|
124
|
+
export declare const builtinRegistry: Readonly<Record<string, ComponentManifest<string, Record<string, PropType>, string, ChildrenType>>>;
|
|
125
|
+
//#endregion
|
|
126
|
+
//#region src/theme/theme.d.ts
|
|
127
|
+
/**
|
|
128
|
+
* Dot-wide design tokens, set in `defineDot`.
|
|
129
|
+
* Themes cross from the service to the webview as
|
|
130
|
+
* messages, so they must be serializable.
|
|
131
|
+
*/
|
|
132
|
+
interface Theme {
|
|
133
|
+
scheme?: ColorScheme | 'system' | undefined;
|
|
134
|
+
colors?: ThemeColors | undefined;
|
|
135
|
+
radius?: number | undefined;
|
|
136
|
+
}
|
|
137
|
+
interface ThemeColors {
|
|
138
|
+
primary?: SchemeColor | undefined;
|
|
139
|
+
background?: SchemeColor | undefined;
|
|
140
|
+
surface?: SchemeColor | undefined;
|
|
141
|
+
text?: SchemeColor | undefined;
|
|
142
|
+
}
|
|
143
|
+
interface SchemeColor {
|
|
144
|
+
light: string;
|
|
145
|
+
dark: string;
|
|
146
|
+
}
|
|
147
|
+
type ColorScheme = 'light' | 'dark';
|
|
148
|
+
//#endregion
|
|
149
|
+
//#region src/host/context.d.ts
|
|
150
|
+
type AppState = 'active' | 'background';
|
|
151
|
+
interface SystemContext {
|
|
152
|
+
readonly scheme: ColorScheme;
|
|
153
|
+
readonly appState: AppState;
|
|
154
|
+
}
|
|
155
|
+
export declare const DEFAULT_SYSTEM_CONTEXT: SystemContext;
|
|
156
|
+
//#endregion
|
|
157
|
+
//#region src/host/calls.d.ts
|
|
158
|
+
type HostErrorCode = 'unsupported' | 'denied' | 'cancelled' | 'timeout' | 'invalid' | 'failed';
|
|
159
|
+
export declare class HostError extends Error {
|
|
160
|
+
readonly name = "HostError";
|
|
161
|
+
readonly code: HostErrorCode;
|
|
162
|
+
constructor(code: HostErrorCode, message: string);
|
|
163
|
+
}
|
|
164
|
+
interface HostCallOptions {
|
|
165
|
+
timeout?: number | undefined;
|
|
166
|
+
}
|
|
167
|
+
interface HostRequest<T> extends Promise<T> {
|
|
168
|
+
cancel(): void;
|
|
169
|
+
}
|
|
170
|
+
type HostCaller = (method: string, params: unknown, options: HostCallOptions) => HostRequest<unknown>;
|
|
171
|
+
export declare function connectHost(caller: HostCaller | null): void;
|
|
172
|
+
export declare function callHost<Result>(method: string, params: unknown, options?: HostCallOptions): HostRequest<Result>;
|
|
173
|
+
export declare function createHostRequest<Result>(promise: Promise<Result>, cancel?: () => void): HostRequest<Result>;
|
|
174
|
+
//#endregion
|
|
175
|
+
//#region src/page/navigation.d.ts
|
|
176
|
+
export declare const MAX_STACK_DEPTH = 8;
|
|
177
|
+
export declare function isPageId(value: string): boolean;
|
|
178
|
+
type PageLaunchOptions = Readonly<Record<string, string>>;
|
|
179
|
+
type Navigation = {
|
|
180
|
+
readonly action: 'push' | 'replace' | 'reset';
|
|
181
|
+
readonly page: string;
|
|
182
|
+
readonly options: PageLaunchOptions;
|
|
183
|
+
} | {
|
|
184
|
+
readonly action: 'back';
|
|
185
|
+
readonly delta: number;
|
|
186
|
+
};
|
|
187
|
+
interface StackEntry {
|
|
188
|
+
readonly instanceId: number;
|
|
189
|
+
readonly page: string;
|
|
190
|
+
readonly options: PageLaunchOptions;
|
|
191
|
+
}
|
|
192
|
+
export declare class NavigationStack {
|
|
193
|
+
#private;
|
|
194
|
+
readonly limit: number;
|
|
195
|
+
constructor(limit?: number);
|
|
196
|
+
get pages(): readonly StackEntry[];
|
|
197
|
+
get top(): StackEntry | undefined;
|
|
198
|
+
/**
|
|
199
|
+
* Applies a navigation, or refuses it and returns false: a push onto a full stack, or going back
|
|
200
|
+
* from the first page (which the host handles itself, e.g. by closing the dot).
|
|
201
|
+
*/
|
|
202
|
+
apply(navigation: Navigation): boolean;
|
|
203
|
+
}
|
|
204
|
+
//#endregion
|
|
205
|
+
//#region src/protocol/core.d.ts
|
|
206
|
+
type PageState = Record<string, unknown>;
|
|
207
|
+
interface UILayerMessages {
|
|
208
|
+
connect: Record<string, never>;
|
|
209
|
+
load: {
|
|
210
|
+
instanceId: number;
|
|
211
|
+
page: string;
|
|
212
|
+
options: PageLaunchOptions;
|
|
213
|
+
};
|
|
214
|
+
unload: {
|
|
215
|
+
instanceId: number;
|
|
216
|
+
};
|
|
217
|
+
show: {
|
|
218
|
+
instanceId: number;
|
|
219
|
+
};
|
|
220
|
+
hide: {
|
|
221
|
+
instanceId: number;
|
|
222
|
+
};
|
|
223
|
+
event: {
|
|
224
|
+
instanceId: number;
|
|
225
|
+
handler: string;
|
|
226
|
+
event: DotEvent;
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
interface LogicLayerMessages {
|
|
230
|
+
setTheme: {
|
|
231
|
+
theme: Theme;
|
|
232
|
+
};
|
|
233
|
+
initPageState: {
|
|
234
|
+
instanceId: number;
|
|
235
|
+
state: PageState;
|
|
236
|
+
};
|
|
237
|
+
setPageState: {
|
|
238
|
+
instanceId: number;
|
|
239
|
+
patchState: PageState;
|
|
240
|
+
};
|
|
241
|
+
error: {
|
|
242
|
+
instanceId?: number;
|
|
243
|
+
message: string;
|
|
244
|
+
};
|
|
245
|
+
navigate: Navigation & {
|
|
246
|
+
from: number;
|
|
247
|
+
};
|
|
248
|
+
hostCall: {
|
|
249
|
+
id: number;
|
|
250
|
+
method: string;
|
|
251
|
+
params: unknown;
|
|
252
|
+
timeout?: number;
|
|
253
|
+
};
|
|
254
|
+
hostCancel: {
|
|
255
|
+
id: number;
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
interface HostLayerMessages {
|
|
259
|
+
syncStack: {
|
|
260
|
+
pages: readonly StackEntry[];
|
|
261
|
+
limit: number;
|
|
262
|
+
};
|
|
263
|
+
syncSystemContext: SystemContext;
|
|
264
|
+
hostResult: HostResult;
|
|
265
|
+
}
|
|
266
|
+
type HostResult = {
|
|
267
|
+
id: number;
|
|
268
|
+
value: unknown;
|
|
269
|
+
} | {
|
|
270
|
+
id: number;
|
|
271
|
+
error: {
|
|
272
|
+
code: HostErrorCode;
|
|
273
|
+
message: string;
|
|
274
|
+
};
|
|
275
|
+
};
|
|
276
|
+
interface Envelope<Type extends string = string, Payload = unknown> {
|
|
277
|
+
readonly type: Type;
|
|
278
|
+
readonly payload: Payload;
|
|
279
|
+
}
|
|
280
|
+
type MessageMap = object;
|
|
281
|
+
type MessageType<M extends MessageMap> = keyof M & string;
|
|
282
|
+
//#endregion
|
|
283
|
+
//#region src/view/renderer.d.ts
|
|
284
|
+
/**
|
|
285
|
+
* What a renderer provides to a compiled view.
|
|
286
|
+
* `Node` represents the target renderer's native element type (e.g., React elements).
|
|
287
|
+
*/
|
|
288
|
+
interface RenderContext<Node> {
|
|
289
|
+
/**
|
|
290
|
+
* Creates the element for a component type (e.g., `<View>`, `<Text>`).
|
|
291
|
+
*/
|
|
292
|
+
readonly h: (type: string, props: Record<string, unknown> | null, ...children: (Node | string)[]) => Node;
|
|
293
|
+
/**
|
|
294
|
+
* Returns a stable event callback that forwards UI events
|
|
295
|
+
* to the named handler defined in `controller.ts`.
|
|
296
|
+
*/
|
|
297
|
+
readonly on: (handler: string) => (event: DotEvent) => void;
|
|
298
|
+
/**
|
|
299
|
+
* Converts a bound value to the text to display.
|
|
300
|
+
*/
|
|
301
|
+
readonly text: (value: unknown) => string;
|
|
302
|
+
/**
|
|
303
|
+
* Renders a `<For>` control flow loop.
|
|
304
|
+
* - `render` produces the virtual nodes for each item in the list.
|
|
305
|
+
* - `key` provides a stable identity for list diffing where applicable.
|
|
306
|
+
*/
|
|
307
|
+
readonly each: (items: unknown, render: (item: unknown, index: number) => (Node | string)[], key?: (item: unknown, index: number) => unknown) => Node;
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* The export of a compiled view file: a pure function of the page state that imports no renderer
|
|
311
|
+
* code, so any renderer can run it.
|
|
312
|
+
*/
|
|
313
|
+
type ViewRender = <Node>(state: PageState, context: RenderContext<Node>) => Node[];
|
|
314
|
+
//#endregion
|
|
315
|
+
//#region src/view/values.d.ts
|
|
316
|
+
export declare function toText(value: unknown): string;
|
|
317
|
+
export declare function toList(value: unknown): readonly unknown[];
|
|
318
|
+
//#endregion
|
|
319
|
+
//#region src/source/location.d.ts
|
|
320
|
+
interface SourceLocation {
|
|
321
|
+
readonly line: number;
|
|
322
|
+
readonly column: number;
|
|
323
|
+
readonly offset: number;
|
|
324
|
+
}
|
|
325
|
+
export declare function createLocator(source: string): (offset: number) => SourceLocation;
|
|
326
|
+
export declare function locationAt(source: string, offset: number): SourceLocation;
|
|
327
|
+
export declare function locatedMessage(message: string, file?: string, location?: SourceLocation): string;
|
|
328
|
+
//#endregion
|
|
329
|
+
//#region src/source/error.d.ts
|
|
330
|
+
export declare class SourceError extends Error {
|
|
331
|
+
readonly reason: string;
|
|
332
|
+
readonly file: string | undefined;
|
|
333
|
+
readonly loc: SourceLocation | undefined;
|
|
334
|
+
constructor(reason: string, file?: string, location?: SourceLocation);
|
|
335
|
+
}
|
|
336
|
+
//#endregion
|
|
337
|
+
//#region src/event/emitter.d.ts
|
|
338
|
+
type Listener = (...args: never[]) => void;
|
|
339
|
+
export declare class EventEmitter<Events extends { [K in keyof Events]: Listener; }> {
|
|
340
|
+
#private;
|
|
341
|
+
on<K extends keyof Events>(name: K, listener: Events[K]): () => void;
|
|
342
|
+
emit<K extends keyof Events>(name: K, ...args: Parameters<Events[K]>): void;
|
|
343
|
+
}
|
|
344
|
+
//#endregion
|
|
345
|
+
//#region src/protocol/transport.d.ts
|
|
346
|
+
/**
|
|
347
|
+
* A universal bridge for sending and receiving messages,
|
|
348
|
+
* whether across web workers, message ports, or native app boundaries.
|
|
349
|
+
*/
|
|
350
|
+
interface Transport {
|
|
351
|
+
post(message: unknown): void;
|
|
352
|
+
listen(listener: (message: unknown) => void): () => void;
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Adapter interface for anything that acts like
|
|
356
|
+
* 1. a MessagePort (https://developer.mozilla.org/en-US/docs/Web/API/MessagePort) or
|
|
357
|
+
* 2. a Web Worker (https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API)
|
|
358
|
+
*/
|
|
359
|
+
interface TransportAdapter {
|
|
360
|
+
postMessage(message: unknown): void;
|
|
361
|
+
addEventListener(type: 'message', listener: (event: {
|
|
362
|
+
data: unknown;
|
|
363
|
+
}) => void): void;
|
|
364
|
+
removeEventListener(type: 'message', listener: (event: {
|
|
365
|
+
data: unknown;
|
|
366
|
+
}) => void): void;
|
|
367
|
+
}
|
|
368
|
+
export declare function createAdaptorTransport(adapter: TransportAdapter): Transport;
|
|
369
|
+
export declare function createTransportPair(): [Transport, Transport];
|
|
370
|
+
//#endregion
|
|
371
|
+
//#region src/host/host.d.ts
|
|
372
|
+
declare global {
|
|
373
|
+
var __hostTransport: Transport | undefined;
|
|
374
|
+
}
|
|
375
|
+
export declare function hostTransport(): Transport;
|
|
376
|
+
//#endregion
|
|
377
|
+
//#region src/host/permissions.d.ts
|
|
378
|
+
export declare const PERMISSIONS: readonly ["account"];
|
|
379
|
+
type DotPermission = (typeof PERMISSIONS)[number];
|
|
380
|
+
export declare function isPermission(value: string): value is DotPermission;
|
|
381
|
+
//#endregion
|
|
382
|
+
//#region src/host/react.d.ts
|
|
383
|
+
export declare const REACT_HOST_PATH = "/__dot/react/";
|
|
384
|
+
export declare const REACT_HOST_MODULES: {
|
|
385
|
+
readonly react: "react.js";
|
|
386
|
+
readonly 'react/jsx-runtime': "react-jsx-runtime.js";
|
|
387
|
+
readonly 'react-dom/client': "react-dom-client.js";
|
|
388
|
+
};
|
|
389
|
+
export declare function reactHostUrl(dotReactVersion: string, file: string): string;
|
|
390
|
+
export declare function isReactCompatible(hostVersion: string, dotVersion: string): boolean;
|
|
391
|
+
export declare function newestReactOfMajor(versions: readonly string[], major: number): string | undefined;
|
|
392
|
+
//#endregion
|
|
393
|
+
//#region src/page/lifecycle.d.ts
|
|
394
|
+
interface PageHooks {
|
|
395
|
+
onLoad(options: PageLaunchOptions): void | Promise<void>;
|
|
396
|
+
onShow(): void | Promise<void>;
|
|
397
|
+
onHide(): void | Promise<void>;
|
|
398
|
+
onUnload(): void | Promise<void>;
|
|
399
|
+
}
|
|
400
|
+
interface DotHooks {
|
|
401
|
+
onLaunch(): void | Promise<void>;
|
|
402
|
+
onError(error: Error): void;
|
|
403
|
+
}
|
|
404
|
+
export declare const PAGE_HOOKS: readonly (keyof PageHooks)[];
|
|
405
|
+
//#endregion
|
|
406
|
+
//#region src/page/state.d.ts
|
|
407
|
+
export declare function applyChanges<T>(state: T, changes: Partial<T>): T;
|
|
408
|
+
//#endregion
|
|
409
|
+
//#region src/version/semantic-version.d.ts
|
|
410
|
+
export declare const SEMVER_PATTERN: RegExp;
|
|
411
|
+
export declare function isSemanticVersion(value: unknown): value is string;
|
|
412
|
+
export declare function majorVersion(version: string): number;
|
|
413
|
+
export declare function isVersionAtLeast(version: string, minimum: string): boolean;
|
|
414
|
+
export declare function compareVersions(left: string, right: string): number;
|
|
415
|
+
//#endregion
|
|
416
|
+
//#region src/messageChannel.d.ts
|
|
417
|
+
type MessageHandler<Payload> = (payload: Payload) => void;
|
|
418
|
+
export declare class MessageChannel<Outgoing extends MessageMap, Incoming extends MessageMap> {
|
|
419
|
+
#private;
|
|
420
|
+
constructor(transport: Transport);
|
|
421
|
+
send<T extends MessageType<Outgoing>>(type: T, payload: Outgoing[T]): void;
|
|
422
|
+
handle<T extends MessageType<Incoming>>(type: T, handler: MessageHandler<Incoming[T]>): MessageHandler<Incoming[T]> | undefined;
|
|
423
|
+
listen(onError: (error: unknown, message: Envelope) => void): () => void;
|
|
424
|
+
}
|
|
425
|
+
//#endregion
|
|
426
|
+
export type { AppState, BuiltinComponents, ChildrenType, ColorScheme, ComponentManifest, ComponentRegistry, DotEvent, DotHooks, DotPermission, Envelope, EventProp, HostCallOptions, HostCaller, HostErrorCode, HostLayerMessages, HostRequest, HostResult, LogicLayerMessages, MessageHandler, MessageMap, MessageType, Navigation, PageHooks, PageLaunchOptions, PageState, PropType, PropTypes, PropValue, PropsOf, RenderContext, SchemeColor, SourceLocation, StackEntry, SystemContext, Theme, ThemeColors, Transport, TransportAdapter, UILayerMessages, ViewRender };
|
|
427
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/event/core.ts","../src/view/component.ts","../src/view/components/button.ts","../src/view/components/image.ts","../src/view/components/input.ts","../src/view/components/text.ts","../src/view/components/view.ts","../src/view/components/index.ts","../src/theme/theme.ts","../src/host/context.ts","../src/host/calls.ts","../src/page/navigation.ts","../src/protocol/core.ts","../src/view/renderer.ts","../src/view/values.ts","../src/source/location.ts","../src/source/error.ts","../src/event/emitter.ts","../src/protocol/transport.ts","../src/host/host.ts","../src/host/permissions.ts","../src/host/react.ts","../src/page/lifecycle.ts","../src/page/state.ts","../src/version/semantic-version.ts","../src/messageChannel.ts"],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
//#region src/view/component.ts
|
|
2
|
+
function defineComponent(manifest) {
|
|
3
|
+
return {
|
|
4
|
+
props: {},
|
|
5
|
+
events: [],
|
|
6
|
+
...manifest
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
function eventProp(event) {
|
|
10
|
+
return `on${event.charAt(0).toUpperCase()}${event.slice(1)}`;
|
|
11
|
+
}
|
|
12
|
+
function isEventProp(name) {
|
|
13
|
+
const letterAfterOn = name.charAt(2);
|
|
14
|
+
return name.startsWith("on") && letterAfterOn >= "A" && letterAfterOn <= "Z";
|
|
15
|
+
}
|
|
16
|
+
function eventName(prop) {
|
|
17
|
+
const name = prop.slice(2);
|
|
18
|
+
return name.charAt(0).toLowerCase() + name.slice(1);
|
|
19
|
+
}
|
|
20
|
+
function componentRegistry(manifests) {
|
|
21
|
+
const registry = {};
|
|
22
|
+
for (const manifest of manifests) {
|
|
23
|
+
if (manifest.name in registry) throw new Error(`Component <${manifest.name}> is defined twice`);
|
|
24
|
+
registry[manifest.name] = manifest;
|
|
25
|
+
}
|
|
26
|
+
return registry;
|
|
27
|
+
}
|
|
28
|
+
//#endregion
|
|
29
|
+
//#region src/view/values.ts
|
|
30
|
+
function toText(value) {
|
|
31
|
+
switch (typeof value) {
|
|
32
|
+
case "string": return value;
|
|
33
|
+
case "number":
|
|
34
|
+
case "boolean":
|
|
35
|
+
case "bigint": return String(value);
|
|
36
|
+
case "object": return value === null ? "" : JSON.stringify(value);
|
|
37
|
+
default: return "";
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function toList(value) {
|
|
41
|
+
if (Array.isArray(value)) return value;
|
|
42
|
+
if (typeof value === "object" && value !== null && Symbol.iterator in value) return Array.from(value);
|
|
43
|
+
return [];
|
|
44
|
+
}
|
|
45
|
+
//#endregion
|
|
46
|
+
//#region src/source/location.ts
|
|
47
|
+
function createLocator(source) {
|
|
48
|
+
const lineStarts = [0];
|
|
49
|
+
for (let index = 0; index < source.length; index++) if (source[index] === "\n") lineStarts.push(index + 1);
|
|
50
|
+
return (offset) => {
|
|
51
|
+
let low = 0;
|
|
52
|
+
let high = lineStarts.length - 1;
|
|
53
|
+
while (low < high) {
|
|
54
|
+
const middle = Math.floor((low + high + 1) / 2);
|
|
55
|
+
if (lineStarts[middle] <= offset) low = middle;
|
|
56
|
+
else high = middle - 1;
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
line: low + 1,
|
|
60
|
+
column: offset - lineStarts[low] + 1,
|
|
61
|
+
offset
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function locationAt(source, offset) {
|
|
66
|
+
return createLocator(source)(offset);
|
|
67
|
+
}
|
|
68
|
+
function locatedMessage(message, file, location) {
|
|
69
|
+
const where = [
|
|
70
|
+
file,
|
|
71
|
+
location?.line,
|
|
72
|
+
location?.column
|
|
73
|
+
].filter((part) => part !== void 0).join(":");
|
|
74
|
+
return where ? `${where}: ${message}` : message;
|
|
75
|
+
}
|
|
76
|
+
//#endregion
|
|
77
|
+
//#region src/source/error.ts
|
|
78
|
+
var SourceError = class extends Error {
|
|
79
|
+
reason;
|
|
80
|
+
file;
|
|
81
|
+
loc;
|
|
82
|
+
constructor(reason, file, location) {
|
|
83
|
+
super(locatedMessage(reason, file, location));
|
|
84
|
+
this.reason = reason;
|
|
85
|
+
this.file = file;
|
|
86
|
+
this.loc = location;
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
//#endregion
|
|
90
|
+
//#region src/view/components/button.ts
|
|
91
|
+
const Button = defineComponent({
|
|
92
|
+
name: "Button",
|
|
93
|
+
props: {
|
|
94
|
+
variant: ["primary", "secondary"],
|
|
95
|
+
disabled: "boolean"
|
|
96
|
+
},
|
|
97
|
+
events: ["click"],
|
|
98
|
+
children: "text"
|
|
99
|
+
});
|
|
100
|
+
//#endregion
|
|
101
|
+
//#region src/view/components/image.ts
|
|
102
|
+
const Image = defineComponent({
|
|
103
|
+
name: "Image",
|
|
104
|
+
props: {
|
|
105
|
+
src: "string",
|
|
106
|
+
alt: "string",
|
|
107
|
+
width: "number",
|
|
108
|
+
height: "number"
|
|
109
|
+
},
|
|
110
|
+
events: ["load", "error"],
|
|
111
|
+
children: "none"
|
|
112
|
+
});
|
|
113
|
+
//#endregion
|
|
114
|
+
//#region src/view/components/input.ts
|
|
115
|
+
const Input = defineComponent({
|
|
116
|
+
name: "Input",
|
|
117
|
+
props: {
|
|
118
|
+
value: "string",
|
|
119
|
+
placeholder: "string",
|
|
120
|
+
label: "string",
|
|
121
|
+
type: [
|
|
122
|
+
"text",
|
|
123
|
+
"number",
|
|
124
|
+
"email",
|
|
125
|
+
"phone",
|
|
126
|
+
"password"
|
|
127
|
+
],
|
|
128
|
+
maxLength: "number",
|
|
129
|
+
disabled: "boolean"
|
|
130
|
+
},
|
|
131
|
+
events: ["change", "submit"],
|
|
132
|
+
children: "none"
|
|
133
|
+
});
|
|
134
|
+
//#endregion
|
|
135
|
+
//#region src/view/components/text.ts
|
|
136
|
+
const Text = defineComponent({
|
|
137
|
+
name: "Text",
|
|
138
|
+
props: { variant: [
|
|
139
|
+
"title",
|
|
140
|
+
"body",
|
|
141
|
+
"caption"
|
|
142
|
+
] },
|
|
143
|
+
children: "text",
|
|
144
|
+
inline: true
|
|
145
|
+
});
|
|
146
|
+
//#endregion
|
|
147
|
+
//#region src/view/components/view.ts
|
|
148
|
+
const View = defineComponent({
|
|
149
|
+
name: "View",
|
|
150
|
+
props: {
|
|
151
|
+
direction: ["column", "row"],
|
|
152
|
+
gap: [
|
|
153
|
+
"none",
|
|
154
|
+
"small",
|
|
155
|
+
"medium",
|
|
156
|
+
"large"
|
|
157
|
+
],
|
|
158
|
+
align: [
|
|
159
|
+
"stretch",
|
|
160
|
+
"start",
|
|
161
|
+
"center",
|
|
162
|
+
"end"
|
|
163
|
+
],
|
|
164
|
+
variant: ["plain", "card"]
|
|
165
|
+
},
|
|
166
|
+
events: ["tap"],
|
|
167
|
+
children: "elements"
|
|
168
|
+
});
|
|
169
|
+
//#endregion
|
|
170
|
+
//#region src/view/components/index.ts
|
|
171
|
+
const builtinComponents = {
|
|
172
|
+
Button,
|
|
173
|
+
Image,
|
|
174
|
+
Input,
|
|
175
|
+
Text,
|
|
176
|
+
View
|
|
177
|
+
};
|
|
178
|
+
const builtinRegistry = componentRegistry(Object.values(builtinComponents));
|
|
179
|
+
//#endregion
|
|
180
|
+
//#region src/event/emitter.ts
|
|
181
|
+
var EventEmitter = class {
|
|
182
|
+
#listeners = /* @__PURE__ */ new Map();
|
|
183
|
+
on(name, listener) {
|
|
184
|
+
const listeners = this.#listeners.get(name) ?? /* @__PURE__ */ new Set();
|
|
185
|
+
this.#listeners.set(name, listeners);
|
|
186
|
+
listeners.add(listener);
|
|
187
|
+
return () => listeners.delete(listener);
|
|
188
|
+
}
|
|
189
|
+
emit(name, ...args) {
|
|
190
|
+
this.#listeners.get(name)?.forEach((listener) => listener(...args));
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
//#endregion
|
|
194
|
+
//#region src/event/core.ts
|
|
195
|
+
function createEvent(type, detail = {}) {
|
|
196
|
+
return {
|
|
197
|
+
type,
|
|
198
|
+
detail
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
//#endregion
|
|
202
|
+
//#region src/host/host.ts
|
|
203
|
+
function hostTransport() {
|
|
204
|
+
const transport = globalThis.__hostTransport;
|
|
205
|
+
if (!transport) throw new Error("No Dot host found: expected `globalThis.__hostTransport` to be available at runtime. Dots run inside the Dash App, or a simulator via `dotctl dev`.");
|
|
206
|
+
return transport;
|
|
207
|
+
}
|
|
208
|
+
//#endregion
|
|
209
|
+
//#region src/host/context.ts
|
|
210
|
+
const DEFAULT_SYSTEM_CONTEXT = {
|
|
211
|
+
scheme: "light",
|
|
212
|
+
appState: "active"
|
|
213
|
+
};
|
|
214
|
+
//#endregion
|
|
215
|
+
//#region src/host/calls.ts
|
|
216
|
+
var HostError = class extends Error {
|
|
217
|
+
name = "HostError";
|
|
218
|
+
code;
|
|
219
|
+
constructor(code, message) {
|
|
220
|
+
super(message);
|
|
221
|
+
this.code = code;
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
let connectedCaller = null;
|
|
225
|
+
function connectHost(caller) {
|
|
226
|
+
connectedCaller = caller;
|
|
227
|
+
}
|
|
228
|
+
function callHost(method, params, options = {}) {
|
|
229
|
+
if (!connectedCaller) {
|
|
230
|
+
const error = new HostError("unsupported", `No host to run "${method}": host calls run in the service`);
|
|
231
|
+
return createHostRequest(Promise.reject(error));
|
|
232
|
+
}
|
|
233
|
+
return connectedCaller(method, params, options);
|
|
234
|
+
}
|
|
235
|
+
function createHostRequest(promise, cancel = () => {}) {
|
|
236
|
+
const request = promise;
|
|
237
|
+
request.cancel = cancel;
|
|
238
|
+
return request;
|
|
239
|
+
}
|
|
240
|
+
//#endregion
|
|
241
|
+
//#region src/host/permissions.ts
|
|
242
|
+
const PERMISSIONS = ["account"];
|
|
243
|
+
function isPermission(value) {
|
|
244
|
+
return PERMISSIONS.includes(value);
|
|
245
|
+
}
|
|
246
|
+
//#endregion
|
|
247
|
+
//#region src/version/semantic-version.ts
|
|
248
|
+
const SEMVER_PATTERN = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
|
|
249
|
+
function isSemanticVersion(value) {
|
|
250
|
+
return typeof value === "string" && SEMVER_PATTERN.test(value);
|
|
251
|
+
}
|
|
252
|
+
function majorVersion(version) {
|
|
253
|
+
return parseVersion(version).major;
|
|
254
|
+
}
|
|
255
|
+
function isVersionAtLeast(version, minimum) {
|
|
256
|
+
return compareVersions(version, minimum) >= 0;
|
|
257
|
+
}
|
|
258
|
+
function compareVersions(left, right) {
|
|
259
|
+
const leftVersion = parseVersion(left);
|
|
260
|
+
const rightVersion = parseVersion(right);
|
|
261
|
+
const differences = [
|
|
262
|
+
leftVersion.major - rightVersion.major,
|
|
263
|
+
leftVersion.minor - rightVersion.minor,
|
|
264
|
+
leftVersion.patch - rightVersion.patch
|
|
265
|
+
];
|
|
266
|
+
for (const difference of differences) if (difference !== 0) return difference;
|
|
267
|
+
return comparePrereleases(leftVersion.prerelease, rightVersion.prerelease);
|
|
268
|
+
}
|
|
269
|
+
function parseVersion(version) {
|
|
270
|
+
const match = SEMVER_PATTERN.exec(version);
|
|
271
|
+
if (!match) throw new Error(`"${version}" is not a semantic version`);
|
|
272
|
+
const [, major, minor, patch, prerelease] = match;
|
|
273
|
+
return {
|
|
274
|
+
major: Number(major),
|
|
275
|
+
minor: Number(minor),
|
|
276
|
+
patch: Number(patch),
|
|
277
|
+
prerelease: prerelease === void 0 ? [] : prerelease.split(".")
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
function comparePrereleases(left, right) {
|
|
281
|
+
if (left.length === 0 || right.length === 0) return right.length - left.length;
|
|
282
|
+
const shared = Math.min(left.length, right.length);
|
|
283
|
+
for (let index = 0; index < shared; index++) {
|
|
284
|
+
const order = compareIdentifiers(left[index], right[index]);
|
|
285
|
+
if (order !== 0) return order;
|
|
286
|
+
}
|
|
287
|
+
return left.length - right.length;
|
|
288
|
+
}
|
|
289
|
+
function compareIdentifiers(left, right) {
|
|
290
|
+
const leftIsNumber = /^\d+$/.test(left);
|
|
291
|
+
const rightIsNumber = /^\d+$/.test(right);
|
|
292
|
+
if (leftIsNumber && rightIsNumber) return Number(left) - Number(right);
|
|
293
|
+
if (leftIsNumber) return -1;
|
|
294
|
+
if (rightIsNumber) return 1;
|
|
295
|
+
if (left < right) return -1;
|
|
296
|
+
if (left > right) return 1;
|
|
297
|
+
return 0;
|
|
298
|
+
}
|
|
299
|
+
//#endregion
|
|
300
|
+
//#region src/host/react.ts
|
|
301
|
+
const REACT_HOST_PATH = "/__dot/react/";
|
|
302
|
+
const REACT_HOST_MODULES = {
|
|
303
|
+
react: "react.js",
|
|
304
|
+
"react/jsx-runtime": "react-jsx-runtime.js",
|
|
305
|
+
"react-dom/client": "react-dom-client.js"
|
|
306
|
+
};
|
|
307
|
+
function reactHostUrl(dotReactVersion, file) {
|
|
308
|
+
return `${REACT_HOST_PATH}${majorVersion(dotReactVersion)}/${file}`;
|
|
309
|
+
}
|
|
310
|
+
function isReactCompatible(hostVersion, dotVersion) {
|
|
311
|
+
return majorVersion(hostVersion) === majorVersion(dotVersion) && isVersionAtLeast(hostVersion, dotVersion);
|
|
312
|
+
}
|
|
313
|
+
function newestReactOfMajor(versions, major) {
|
|
314
|
+
return versions.filter((version) => majorVersion(version) === major).sort(compareVersions).at(-1);
|
|
315
|
+
}
|
|
316
|
+
//#endregion
|
|
317
|
+
//#region src/protocol/transport.ts
|
|
318
|
+
function createAdaptorTransport(adapter) {
|
|
319
|
+
return {
|
|
320
|
+
post: (message) => adapter.postMessage(message),
|
|
321
|
+
listen(listener) {
|
|
322
|
+
const onMessage = (event) => listener(event.data);
|
|
323
|
+
adapter.addEventListener("message", onMessage);
|
|
324
|
+
return () => adapter.removeEventListener("message", onMessage);
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
function createTransportPair() {
|
|
329
|
+
const firstListeners = /* @__PURE__ */ new Set();
|
|
330
|
+
const secondListeners = /* @__PURE__ */ new Set();
|
|
331
|
+
const createSide = (ownListeners, otherListeners) => ({
|
|
332
|
+
post: (message) => {
|
|
333
|
+
const copy = JSON.parse(JSON.stringify(message));
|
|
334
|
+
otherListeners.forEach((listener) => listener(copy));
|
|
335
|
+
},
|
|
336
|
+
listen(listener) {
|
|
337
|
+
ownListeners.add(listener);
|
|
338
|
+
return () => ownListeners.delete(listener);
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
return [createSide(firstListeners, secondListeners), createSide(secondListeners, firstListeners)];
|
|
342
|
+
}
|
|
343
|
+
const PAGE_HOOKS = Object.keys({
|
|
344
|
+
onLoad: true,
|
|
345
|
+
onShow: true,
|
|
346
|
+
onHide: true,
|
|
347
|
+
onUnload: true
|
|
348
|
+
});
|
|
349
|
+
//#endregion
|
|
350
|
+
//#region src/page/navigation.ts
|
|
351
|
+
const MAX_STACK_DEPTH = 8;
|
|
352
|
+
const PAGE_ID = /^[A-Za-z0-9_-]+(?:\/[A-Za-z0-9_-]+)*$/;
|
|
353
|
+
function isPageId(value) {
|
|
354
|
+
return PAGE_ID.test(value);
|
|
355
|
+
}
|
|
356
|
+
var NavigationStack = class {
|
|
357
|
+
limit;
|
|
358
|
+
#pages = [];
|
|
359
|
+
#nextInstanceId = 1;
|
|
360
|
+
constructor(limit = 8) {
|
|
361
|
+
this.limit = limit;
|
|
362
|
+
}
|
|
363
|
+
get pages() {
|
|
364
|
+
return this.#pages;
|
|
365
|
+
}
|
|
366
|
+
get top() {
|
|
367
|
+
return this.#pages.at(-1);
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Applies a navigation, or refuses it and returns false: a push onto a full stack, or going back
|
|
371
|
+
* from the first page (which the host handles itself, e.g. by closing the dot).
|
|
372
|
+
*/
|
|
373
|
+
apply(navigation) {
|
|
374
|
+
switch (navigation.action) {
|
|
375
|
+
case "push":
|
|
376
|
+
if (this.#pages.length >= this.limit) return false;
|
|
377
|
+
break;
|
|
378
|
+
case "replace":
|
|
379
|
+
this.#pages.pop();
|
|
380
|
+
break;
|
|
381
|
+
case "reset":
|
|
382
|
+
this.#pages = [];
|
|
383
|
+
break;
|
|
384
|
+
case "back": {
|
|
385
|
+
const count = Math.min(navigation.delta, this.#pages.length - 1);
|
|
386
|
+
if (count < 1) return false;
|
|
387
|
+
this.#pages = this.#pages.slice(0, -count);
|
|
388
|
+
return true;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
const { page, options } = navigation;
|
|
392
|
+
this.#pages = [...this.#pages, {
|
|
393
|
+
instanceId: this.#nextInstanceId++,
|
|
394
|
+
page,
|
|
395
|
+
options
|
|
396
|
+
}];
|
|
397
|
+
return true;
|
|
398
|
+
}
|
|
399
|
+
};
|
|
400
|
+
//#endregion
|
|
401
|
+
//#region src/page/state.ts
|
|
402
|
+
function applyChanges(state, changes) {
|
|
403
|
+
const next = { ...state };
|
|
404
|
+
for (const [key, value] of Object.entries(changes)) if (value !== void 0) next[key] = value;
|
|
405
|
+
return next;
|
|
406
|
+
}
|
|
407
|
+
//#endregion
|
|
408
|
+
//#region src/messageChannel.ts
|
|
409
|
+
var MessageChannel = class {
|
|
410
|
+
#transport;
|
|
411
|
+
#handlers = /* @__PURE__ */ new Map();
|
|
412
|
+
constructor(transport) {
|
|
413
|
+
this.#transport = transport;
|
|
414
|
+
}
|
|
415
|
+
send(type, payload) {
|
|
416
|
+
this.#transport.post({
|
|
417
|
+
type,
|
|
418
|
+
payload
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
handle(type, handler) {
|
|
422
|
+
const previous = this.#handlers.get(type);
|
|
423
|
+
this.#handlers.set(type, handler);
|
|
424
|
+
return previous;
|
|
425
|
+
}
|
|
426
|
+
listen(onError) {
|
|
427
|
+
return this.#transport.listen((rawMessage) => {
|
|
428
|
+
const message = rawMessage;
|
|
429
|
+
const handler = this.#handlers.get(message.type);
|
|
430
|
+
if (!handler) {
|
|
431
|
+
onError(/* @__PURE__ */ new Error(`No handler registered for message "${message.type}"`), message);
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
try {
|
|
435
|
+
handler(message.payload);
|
|
436
|
+
} catch (error) {
|
|
437
|
+
onError(error, message);
|
|
438
|
+
}
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
};
|
|
442
|
+
//#endregion
|
|
443
|
+
export { Button, DEFAULT_SYSTEM_CONTEXT, EventEmitter, HostError, Image, Input, MAX_STACK_DEPTH, MessageChannel, NavigationStack, PAGE_HOOKS, PERMISSIONS, REACT_HOST_MODULES, REACT_HOST_PATH, SEMVER_PATTERN, SourceError, Text, View, applyChanges, builtinComponents, builtinRegistry, callHost, compareVersions, componentRegistry, connectHost, createAdaptorTransport, createEvent, createHostRequest, createLocator, createTransportPair, defineComponent, eventName, eventProp, hostTransport, isEventProp, isPageId, isPermission, isReactCompatible, isSemanticVersion, isVersionAtLeast, locatedMessage, locationAt, majorVersion, newestReactOfMajor, reactHostUrl, toList, toText };
|
|
444
|
+
|
|
445
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/view/component.ts","../src/view/values.ts","../src/source/location.ts","../src/source/error.ts","../src/view/components/button.ts","../src/view/components/image.ts","../src/view/components/input.ts","../src/view/components/text.ts","../src/view/components/view.ts","../src/view/components/index.ts","../src/event/emitter.ts","../src/event/core.ts","../src/host/host.ts","../src/host/context.ts","../src/host/calls.ts","../src/host/permissions.ts","../src/version/semantic-version.ts","../src/host/react.ts","../src/protocol/transport.ts","../src/page/lifecycle.ts","../src/page/navigation.ts","../src/page/state.ts","../src/messageChannel.ts"],"sourcesContent":["import type { DotEvent } from '../event/core';\n\nexport interface PropTypes {\n string: string;\n number: number;\n boolean: boolean;\n any: unknown;\n}\n\nexport type PropType = keyof PropTypes | readonly string[];\n\nexport type PropValue<T extends PropType> = T extends readonly string[]\n ? T[number]\n : T extends keyof PropTypes\n ? PropTypes[T]\n : never;\n\n/**\n * - `none`: no children\n * - `text`: text and inline components (such as `Text`).\n * - `elements`: any components, but raw text must be wrapped in an inline component.\n */\nexport type ChildrenType = 'none' | 'text' | 'elements';\n\n/**\n * Describes a UI component independently of any renderer. The compiler checks `.dml` markup\n * against it, and each renderer maps it to its own elements.\n */\nexport interface ComponentManifest<\n Name extends string = string,\n Props extends Record<string, PropType> = Record<string, PropType>,\n Events extends string = string,\n Children extends ChildrenType = ChildrenType,\n> {\n readonly name: Name;\n readonly props: Props;\n // Supported event names; `click` is written `onClick` in markup and received as the `onClick` prop.\n readonly events: readonly Events[];\n readonly children: Children;\n readonly inline?: boolean;\n}\n\nexport function defineComponent<\n const Name extends string,\n const Props extends Record<string, PropType> = Record<never, PropType>,\n const Events extends string = never,\n const Children extends ChildrenType = ChildrenType,\n>(manifest: {\n name: Name;\n props?: Props;\n events?: readonly Events[];\n children: Children;\n inline?: boolean;\n}): ComponentManifest<Name, Props, Events, Children> {\n return { props: {} as Props, events: [], ...manifest };\n}\n\nexport type EventProp<Event extends string> = `on${Capitalize<Event>}`;\n\nexport function eventProp<Event extends string>(event: Event): EventProp<Event> {\n return `on${event.charAt(0).toUpperCase()}${event.slice(1)}` as EventProp<Event>;\n}\n\n// Event props are `on` followed by a capital letter, like `onClick`.\nexport function isEventProp(name: string): boolean {\n const letterAfterOn = name.charAt('on'.length);\n return name.startsWith('on') && letterAfterOn >= 'A' && letterAfterOn <= 'Z';\n}\n\n// The reverse of eventProp: `onClick` -> `click`.\nexport function eventName(prop: string): string {\n const name = prop.slice('on'.length);\n return name.charAt(0).toLowerCase() + name.slice(1);\n}\n\n/**\n * The props a renderer's implementation of `M` receives, with `Children` as its node type. Every\n * prop is optional and may be `undefined`: markup can omit it, and a binding can evaluate to\n * `undefined` at runtime.\n */\nexport type PropsOf<M extends ComponentManifest, Children = never> = {\n [K in keyof M['props']]?: PropValue<M['props'][K]> | undefined;\n} & {\n [E in M['events'][number] as EventProp<E>]?: ((event: DotEvent) => void) | undefined;\n} & (M['children'] extends 'none' ? unknown : { children?: Children | undefined });\n\nexport type ComponentRegistry = Readonly<Record<string, ComponentManifest>>;\n\nexport function componentRegistry(manifests: Iterable<ComponentManifest>): ComponentRegistry {\n const registry: Record<string, ComponentManifest> = {};\n for (const manifest of manifests) {\n if (manifest.name in registry) {\n throw new Error(`Component <${manifest.name}> is defined twice`);\n }\n registry[manifest.name] = manifest;\n }\n return registry;\n}\n","export function toText(value: unknown): string {\n switch (typeof value) {\n case 'string':\n return value;\n case 'number':\n case 'boolean':\n case 'bigint':\n return String(value);\n case 'object':\n return value === null ? '' : JSON.stringify(value);\n default:\n return '';\n }\n}\n\nexport function toList(value: unknown): readonly unknown[] {\n if (Array.isArray(value)) {\n return value;\n }\n if (typeof value === 'object' && value !== null && Symbol.iterator in value) {\n return Array.from(value as Iterable<unknown>);\n }\n return [];\n}\n","export interface SourceLocation {\n readonly line: number;\n readonly column: number;\n readonly offset: number;\n}\n\n// Finds lines by binary search over their start offsets, computed once per source.\nexport function createLocator(source: string): (offset: number) => SourceLocation {\n const lineStarts = [0];\n for (let index = 0; index < source.length; index++) {\n if (source[index] === '\\n') {\n lineStarts.push(index + 1);\n }\n }\n return (offset) => {\n let low = 0;\n let high = lineStarts.length - 1;\n while (low < high) {\n const middle = Math.floor((low + high + 1) / 2);\n if (lineStarts[middle]! <= offset) {\n low = middle;\n } else {\n high = middle - 1;\n }\n }\n return { line: low + 1, column: offset - lineStarts[low]! + 1, offset };\n };\n}\n\nexport function locationAt(source: string, offset: number): SourceLocation {\n return createLocator(source)(offset);\n}\n\nexport function locatedMessage(message: string, file?: string, location?: SourceLocation): string {\n const where = [file, location?.line, location?.column]\n .filter((part) => part !== undefined)\n .join(':');\n return where ? `${where}: ${message}` : message;\n}\n","import type { SourceLocation } from './location';\nimport { locatedMessage } from './location';\n\n// A problem at a place in a source file. The message starts with `file:line:column:`\nexport class SourceError extends Error {\n readonly reason: string;\n readonly file: string | undefined;\n readonly loc: SourceLocation | undefined;\n\n constructor(reason: string, file?: string, location?: SourceLocation) {\n super(locatedMessage(reason, file, location));\n this.reason = reason;\n this.file = file;\n this.loc = location;\n }\n}\n","import { defineComponent } from '../component';\n\nexport const Button = defineComponent({\n name: 'Button',\n props: { variant: ['primary', 'secondary'], disabled: 'boolean' },\n events: ['click'],\n children: 'text',\n});\n","import { defineComponent } from '../component';\n\nexport const Image = defineComponent({\n name: 'Image',\n props: { src: 'string', alt: 'string', width: 'number', height: 'number' },\n events: ['load', 'error'],\n children: 'none',\n});\n","import { defineComponent } from '../component';\n\nexport const Input = defineComponent({\n name: 'Input',\n props: {\n value: 'string',\n placeholder: 'string',\n label: 'string',\n type: ['text', 'number', 'email', 'phone', 'password'],\n maxLength: 'number',\n disabled: 'boolean',\n },\n events: ['change', 'submit'],\n children: 'none',\n});\n","import { defineComponent } from '../component';\n\nexport const Text = defineComponent({\n name: 'Text',\n props: {\n variant: ['title', 'body', 'caption'],\n },\n children: 'text',\n inline: true,\n});\n","import { defineComponent } from '../component';\n\nexport const View = defineComponent({\n name: 'View',\n props: {\n direction: ['column', 'row'],\n gap: ['none', 'small', 'medium', 'large'],\n align: ['stretch', 'start', 'center', 'end'],\n variant: ['plain', 'card'],\n },\n events: ['tap'],\n children: 'elements',\n});\n","import { componentRegistry } from '../component';\nimport { Button } from './button';\nimport { Image } from './image';\nimport { Input } from './input';\nimport { Text } from './text';\nimport { View } from './view';\n\nexport { Button, Image, Input, Text, View };\n\nexport const builtinComponents = { Button, Image, Input, Text, View } as const;\n\nexport type BuiltinComponents = typeof builtinComponents;\n\nexport const builtinRegistry = componentRegistry(Object.values(builtinComponents));\n","type Listener = (...args: never[]) => void;\n\nexport class EventEmitter<Events extends { [K in keyof Events]: Listener }> {\n readonly #listeners = new Map<keyof Events, Set<Listener>>();\n\n on<K extends keyof Events>(name: K, listener: Events[K]): () => void {\n const listeners = this.#listeners.get(name) ?? new Set();\n this.#listeners.set(name, listeners);\n listeners.add(listener);\n return () => listeners.delete(listener);\n }\n\n emit<K extends keyof Events>(name: K, ...args: Parameters<Events[K]>): void {\n const listeners = this.#listeners.get(name) as Set<Events[K]> | undefined;\n listeners?.forEach((listener) => listener(...args));\n }\n}\n","export interface DotEvent<Detail = unknown> {\n readonly type: string;\n readonly detail: Detail;\n}\n\nexport function createEvent<Detail = Record<string, never>>(\n type: string,\n detail: Detail = {} as Detail,\n): DotEvent<Detail> {\n return { type, detail };\n}\n","import type { Transport } from '../protocol/transport';\n\ndeclare global {\n // Installed by the host (the iOS or Android app, or the browser simulator) before Dot starts.\n // noinspection ES6ConvertVarToLetConst\n var __hostTransport: Transport | undefined;\n}\n\n// The transport the host installed. Messages crossing it must be JSON-serializable.\nexport function hostTransport(): Transport {\n const transport = globalThis.__hostTransport;\n if (!transport) {\n throw new Error(\n 'No Dot host found: expected `globalThis.__hostTransport` to be available at runtime. ' +\n 'Dots run inside the Dash App, or a simulator via `dotctl dev`.',\n );\n }\n return transport;\n}\n","import type { ColorScheme } from '../theme/theme';\n\n// `background` while the person is away from Dash: in another app, on the home screen, or with the\n// phone locked.\nexport type AppState = 'active' | 'background';\n\nexport interface SystemContext {\n readonly scheme: ColorScheme;\n readonly appState: AppState;\n}\n\nexport const DEFAULT_SYSTEM_CONTEXT: SystemContext = { scheme: 'light', appState: 'active' };\n","export type HostErrorCode =\n 'unsupported' | 'denied' | 'cancelled' | 'timeout' | 'invalid' | 'failed';\n\nexport class HostError extends Error {\n override readonly name = 'HostError';\n readonly code: HostErrorCode;\n\n constructor(code: HostErrorCode, message: string) {\n super(message);\n this.code = code;\n }\n}\n\nexport interface HostCallOptions {\n timeout?: number | undefined;\n}\n\nexport interface HostRequest<T> extends Promise<T> {\n // Stops waiting: the promise rejects with `cancelled`, and the host stops the work.\n cancel(): void;\n}\n\nexport type HostCaller = (\n method: string,\n params: unknown,\n options: HostCallOptions,\n) => HostRequest<unknown>;\n\nlet connectedCaller: HostCaller | null = null;\n\n// The service connects itself when it starts\nexport function connectHost(caller: HostCaller | null): void {\n connectedCaller = caller;\n}\n\nexport function callHost<Result>(\n method: string,\n params: unknown,\n options: HostCallOptions = {},\n): HostRequest<Result> {\n if (!connectedCaller) {\n const error = new HostError(\n 'unsupported',\n `No host to run \"${method}\": host calls run in the service`,\n );\n return createHostRequest(Promise.reject(error));\n }\n return connectedCaller(method, params, options) as HostRequest<Result>;\n}\n\nexport function createHostRequest<Result>(\n promise: Promise<Result>,\n cancel: () => void = () => {},\n): HostRequest<Result> {\n const request = promise as HostRequest<Result>;\n request.cancel = cancel;\n return request;\n}\n","// What a dot may ask the person for. A dot declares each one it uses in dot.json, with the reason\n// Dash shows the person; a host method that needs one runs only once the person allows it.\n// - `account`: the Dash account the person is logged into: their username (email or phone) and\n// full name.\nexport const PERMISSIONS = ['account'] as const;\n\nexport type DotPermission = (typeof PERMISSIONS)[number];\n\nexport function isPermission(value: string): value is DotPermission {\n return (PERMISSIONS as readonly string[]).includes(value);\n}\n","// A semantic version, as https://semver.org defines it: `1.4.0`, `2.0.0-beta.1`, `1.0.0+build.7`.\nexport const SEMVER_PATTERN =\n /^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$/;\n\ninterface SemanticVersion {\n readonly major: number;\n readonly minor: number;\n readonly patch: number;\n // `[\"beta\", \"1\"]` for `1.0.0-beta.1`; empty for a release.\n readonly prerelease: readonly string[];\n}\n\nexport function isSemanticVersion(value: unknown): value is string {\n return typeof value === 'string' && SEMVER_PATTERN.test(value);\n}\n\nexport function majorVersion(version: string): number {\n return parseVersion(version).major;\n}\n\n// Whether `version` is `minimum` or a later one.\nexport function isVersionAtLeast(version: string, minimum: string): boolean {\n return compareVersions(version, minimum) >= 0;\n}\n\n// Negative when `left` comes before `right`, positive when after, and 0 for the same release.\n// Build metadata, the part after `+`, does not count.\nexport function compareVersions(left: string, right: string): number {\n const leftVersion = parseVersion(left);\n const rightVersion = parseVersion(right);\n const differences = [\n leftVersion.major - rightVersion.major,\n leftVersion.minor - rightVersion.minor,\n leftVersion.patch - rightVersion.patch,\n ];\n for (const difference of differences) {\n if (difference !== 0) {\n return difference;\n }\n }\n return comparePrereleases(leftVersion.prerelease, rightVersion.prerelease);\n}\n\nfunction parseVersion(version: string): SemanticVersion {\n const match = SEMVER_PATTERN.exec(version);\n if (!match) {\n throw new Error(`\"${version}\" is not a semantic version`);\n }\n const [, major, minor, patch, prerelease] = match;\n return {\n major: Number(major),\n minor: Number(minor),\n patch: Number(patch),\n prerelease: prerelease === undefined ? [] : prerelease.split('.'),\n };\n}\n\n// A release comes after its pre-releases (`1.0.0-beta` < `1.0.0`). Between pre-releases, the first\n// identifier that differs decides; if all match, the one with fewer identifiers comes first.\nfunction comparePrereleases(left: readonly string[], right: readonly string[]): number {\n if (left.length === 0 || right.length === 0) {\n return right.length - left.length;\n }\n const shared = Math.min(left.length, right.length);\n for (let index = 0; index < shared; index++) {\n const order = compareIdentifiers(left[index]!, right[index]!);\n if (order !== 0) {\n return order;\n }\n }\n return left.length - right.length;\n}\n\n// Numbers compare as numbers and come before words, which compare as text.\nfunction compareIdentifiers(left: string, right: string): number {\n const leftIsNumber = /^\\d+$/.test(left);\n const rightIsNumber = /^\\d+$/.test(right);\n if (leftIsNumber && rightIsNumber) {\n return Number(left) - Number(right);\n }\n if (leftIsNumber) {\n return -1;\n }\n if (rightIsNumber) {\n return 1;\n }\n if (left < right) {\n return -1;\n }\n if (left > right) {\n return 1;\n }\n return 0;\n}\n","import { compareVersions, isVersionAtLeast, majorVersion } from '../version/semantic-version';\n\n// The host ships React, not each dot: every dot's webview imports these names, and an import map in\n// its index.html points them at the host's copies under `/__dot/react/<major>/`.\nexport const REACT_HOST_PATH = '/__dot/react/';\n\n// Each name a dot's webview imports React by, and the host's file for it.\nexport const REACT_HOST_MODULES = {\n react: 'react.js',\n 'react/jsx-runtime': 'react-jsx-runtime.js',\n 'react-dom/client': 'react-dom-client.js',\n} as const;\n\n// By major version only: the host serves the newest React it has with that major, so it can update\n// React within a major without dots being rebuilt.\nexport function reactHostUrl(dotReactVersion: string, file: string): string {\n return `${REACT_HOST_PATH}${majorVersion(dotReactVersion)}/${file}`;\n}\n\n// A React release only adds to its major version, so a dot runs on the same major at or above the\n// version it was built with. A different major can change or remove what the dot relies on.\nexport function isReactCompatible(hostVersion: string, dotVersion: string): boolean {\n return (\n majorVersion(hostVersion) === majorVersion(dotVersion) &&\n isVersionAtLeast(hostVersion, dotVersion)\n );\n}\n\n// The newest of `versions` with `major`, or undefined when there is none.\nexport function newestReactOfMajor(versions: readonly string[], major: number): string | undefined {\n const matching = versions.filter((version) => majorVersion(version) === major);\n return matching.sort(compareVersions).at(-1);\n}\n","/**\n * A universal bridge for sending and receiving messages,\n * whether across web workers, message ports, or native app boundaries.\n */\nexport interface Transport {\n post(message: unknown): void;\n // Returns a function that removes the listener.\n listen(listener: (message: unknown) => void): () => void;\n}\n\n/**\n * Adapter interface for anything that acts like\n * 1. a MessagePort (https://developer.mozilla.org/en-US/docs/Web/API/MessagePort) or\n * 2. a Web Worker (https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API)\n */\nexport interface TransportAdapter {\n postMessage(message: unknown): void;\n addEventListener(type: 'message', listener: (event: { data: unknown }) => void): void;\n removeEventListener(type: 'message', listener: (event: { data: unknown }) => void): void;\n}\n\nexport function createAdaptorTransport(adapter: TransportAdapter): Transport {\n return {\n post: (message) => adapter.postMessage(message),\n listen(listener) {\n const onMessage = (event: { data: unknown }) => listener(event.data);\n adapter.addEventListener('message', onMessage);\n return () => adapter.removeEventListener('message', onMessage);\n },\n };\n}\n\n// Two transports connected to each other in the same thread, for tests and single-thread setups.\nexport function createTransportPair(): [Transport, Transport] {\n type Listeners = Set<(message: unknown) => void>;\n const firstListeners: Listeners = new Set();\n const secondListeners: Listeners = new Set();\n const createSide = (ownListeners: Listeners, otherListeners: Listeners): Transport => ({\n post: (message) => {\n // Simulate cross-thread memory isolation by cloning the payload\n const copy: unknown = JSON.parse(JSON.stringify(message));\n otherListeners.forEach((listener) => listener(copy));\n },\n listen(listener) {\n ownListeners.add(listener);\n return () => ownListeners.delete(listener);\n },\n });\n return [createSide(firstListeners, secondListeners), createSide(secondListeners, firstListeners)];\n}\n","import type { PageLaunchOptions } from './navigation';\n\nexport interface PageHooks {\n onLoad(options: PageLaunchOptions): void | Promise<void>;\n onShow(): void | Promise<void>;\n onHide(): void | Promise<void>;\n onUnload(): void | Promise<void>;\n}\n\nexport interface DotHooks {\n onLaunch(): void | Promise<void>;\n onError(error: Error): void;\n}\n\n// A record rather than a list, so adding a hook to PageHooks without listing it is a type error.\nconst pageHooks: Record<keyof PageHooks, true> = {\n onLoad: true,\n onShow: true,\n onHide: true,\n onUnload: true,\n};\n\nexport const PAGE_HOOKS = Object.keys(pageHooks) as readonly (keyof PageHooks)[];\n","export const MAX_STACK_DEPTH = 8;\n\nconst PAGE_ID = /^[A-Za-z0-9_-]+(?:\\/[A-Za-z0-9_-]+)*$/;\n\nexport function isPageId(value: string): boolean {\n return PAGE_ID.test(value);\n}\n\nexport type PageLaunchOptions = Readonly<Record<string, string>>;\n\nexport type Navigation =\n | {\n readonly action: 'push' | 'replace' | 'reset';\n readonly page: string;\n readonly options: PageLaunchOptions;\n }\n | { readonly action: 'back'; readonly delta: number };\n\nexport interface StackEntry {\n readonly instanceId: number;\n readonly page: string;\n readonly options: PageLaunchOptions;\n}\n\nexport class NavigationStack {\n readonly limit: number;\n #pages: StackEntry[] = [];\n #nextInstanceId = 1;\n\n constructor(limit = MAX_STACK_DEPTH) {\n this.limit = limit;\n }\n\n get pages(): readonly StackEntry[] {\n return this.#pages;\n }\n\n get top(): StackEntry | undefined {\n return this.#pages.at(-1);\n }\n\n /**\n * Applies a navigation, or refuses it and returns false: a push onto a full stack, or going back\n * from the first page (which the host handles itself, e.g. by closing the dot).\n */\n apply(navigation: Navigation): boolean {\n switch (navigation.action) {\n case 'push':\n if (this.#pages.length >= this.limit) {\n return false;\n }\n break;\n case 'replace':\n this.#pages.pop();\n break;\n case 'reset':\n this.#pages = [];\n break;\n case 'back': {\n const count = Math.min(navigation.delta, this.#pages.length - 1);\n if (count < 1) {\n return false;\n }\n this.#pages = this.#pages.slice(0, -count);\n return true;\n }\n }\n const { page, options } = navigation;\n this.#pages = [...this.#pages, { instanceId: this.#nextInstanceId++, page, options }];\n return true;\n }\n}\n","export function applyChanges<T>(state: T, changes: Partial<T>): T {\n const next = { ...state } as Record<string, unknown>;\n for (const [key, value] of Object.entries(changes)) {\n if (value !== undefined) {\n next[key] = value;\n }\n }\n return next as T;\n}\n","import type { Transport } from './protocol/transport';\nimport type { Envelope, MessageMap, MessageType } from './protocol/core';\n\nexport type MessageHandler<Payload> = (payload: Payload) => void;\n\nexport class MessageChannel<Outgoing extends MessageMap, Incoming extends MessageMap> {\n readonly #transport: Transport;\n readonly #handlers = new Map<string, MessageHandler<never>>();\n\n constructor(transport: Transport) {\n this.#transport = transport;\n }\n\n send<T extends MessageType<Outgoing>>(type: T, payload: Outgoing[T]): void {\n this.#transport.post({ type, payload } satisfies Envelope);\n }\n\n handle<T extends MessageType<Incoming>>(\n type: T,\n handler: MessageHandler<Incoming[T]>,\n ): MessageHandler<Incoming[T]> | undefined {\n const previous = this.#handlers.get(type) as MessageHandler<Incoming[T]> | undefined;\n this.#handlers.set(type, handler);\n return previous;\n }\n\n listen(onError: (error: unknown, message: Envelope) => void): () => void {\n return this.#transport.listen((rawMessage) => {\n const message = rawMessage as Envelope;\n const handler = this.#handlers.get(message.type) as MessageHandler<unknown> | undefined;\n if (!handler) {\n onError(new Error(`No handler registered for message \"${message.type}\"`), message);\n return;\n }\n try {\n handler(message.payload);\n } catch (error) {\n onError(error, message);\n }\n });\n }\n}\n"],"mappings":";AA0CA,SAAgB,gBAKd,UAMmD;CACnD,OAAO;EAAE,OAAO,CAAC;EAAY,QAAQ,CAAC;EAAG,GAAG;CAAS;AACvD;AAIA,SAAgB,UAAgC,OAAgC;CAC9E,OAAO,KAAK,MAAM,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI,MAAM,MAAM,CAAC;AAC3D;AAGA,SAAgB,YAAY,MAAuB;CACjD,MAAM,gBAAgB,KAAK,OAAO,CAAW;CAC7C,OAAO,KAAK,WAAW,IAAI,KAAK,iBAAiB,OAAO,iBAAiB;AAC3E;AAGA,SAAgB,UAAU,MAAsB;CAC9C,MAAM,OAAO,KAAK,MAAM,CAAW;CACnC,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI,KAAK,MAAM,CAAC;AACpD;AAeA,SAAgB,kBAAkB,WAA2D;CAC3F,MAAM,WAA8C,CAAC;CACrD,KAAK,MAAM,YAAY,WAAW;EAChC,IAAI,SAAS,QAAQ,UACnB,MAAM,IAAI,MAAM,cAAc,SAAS,KAAK,mBAAmB;EAEjE,SAAS,SAAS,QAAQ;CAC5B;CACA,OAAO;AACT;;;ACjGA,SAAgB,OAAO,OAAwB;CAC7C,QAAQ,OAAO,OAAf;EACE,KAAK,UACH,OAAO;EACT,KAAK;EACL,KAAK;EACL,KAAK,UACH,OAAO,OAAO,KAAK;EACrB,KAAK,UACH,OAAO,UAAU,OAAO,KAAK,KAAK,UAAU,KAAK;EACnD,SACE,OAAO;CACX;AACF;AAEA,SAAgB,OAAO,OAAoC;CACzD,IAAI,MAAM,QAAQ,KAAK,GACrB,OAAO;CAET,IAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,OAAO,YAAY,OACpE,OAAO,MAAM,KAAK,KAA0B;CAE9C,OAAO,CAAC;AACV;;;AChBA,SAAgB,cAAc,QAAoD;CAChF,MAAM,aAAa,CAAC,CAAC;CACrB,KAAK,IAAI,QAAQ,GAAG,QAAQ,OAAO,QAAQ,SACzC,IAAI,OAAO,WAAW,MACpB,WAAW,KAAK,QAAQ,CAAC;CAG7B,QAAQ,WAAW;EACjB,IAAI,MAAM;EACV,IAAI,OAAO,WAAW,SAAS;EAC/B,OAAO,MAAM,MAAM;GACjB,MAAM,SAAS,KAAK,OAAO,MAAM,OAAO,KAAK,CAAC;GAC9C,IAAI,WAAW,WAAY,QACzB,MAAM;QAEN,OAAO,SAAS;EAEpB;EACA,OAAO;GAAE,MAAM,MAAM;GAAG,QAAQ,SAAS,WAAW,OAAQ;GAAG;EAAO;CACxE;AACF;AAEA,SAAgB,WAAW,QAAgB,QAAgC;CACzE,OAAO,cAAc,MAAM,CAAC,CAAC,MAAM;AACrC;AAEA,SAAgB,eAAe,SAAiB,MAAe,UAAmC;CAChG,MAAM,QAAQ;EAAC;EAAM,UAAU;EAAM,UAAU;CAAM,CAAC,CACnD,QAAQ,SAAS,SAAS,KAAA,CAAS,CAAC,CACpC,KAAK,GAAG;CACX,OAAO,QAAQ,GAAG,MAAM,IAAI,YAAY;AAC1C;;;AClCA,IAAa,cAAb,cAAiC,MAAM;CACrC;CACA;CACA;CAEA,YAAY,QAAgB,MAAe,UAA2B;EACpE,MAAM,eAAe,QAAQ,MAAM,QAAQ,CAAC;EAC5C,KAAK,SAAS;EACd,KAAK,OAAO;EACZ,KAAK,MAAM;CACb;AACF;;;ACbA,MAAa,SAAS,gBAAgB;CACpC,MAAM;CACN,OAAO;EAAE,SAAS,CAAC,WAAW,WAAW;EAAG,UAAU;CAAU;CAChE,QAAQ,CAAC,OAAO;CAChB,UAAU;AACZ,CAAC;;;ACLD,MAAa,QAAQ,gBAAgB;CACnC,MAAM;CACN,OAAO;EAAE,KAAK;EAAU,KAAK;EAAU,OAAO;EAAU,QAAQ;CAAS;CACzE,QAAQ,CAAC,QAAQ,OAAO;CACxB,UAAU;AACZ,CAAC;;;ACLD,MAAa,QAAQ,gBAAgB;CACnC,MAAM;CACN,OAAO;EACL,OAAO;EACP,aAAa;EACb,OAAO;EACP,MAAM;GAAC;GAAQ;GAAU;GAAS;GAAS;EAAU;EACrD,WAAW;EACX,UAAU;CACZ;CACA,QAAQ,CAAC,UAAU,QAAQ;CAC3B,UAAU;AACZ,CAAC;;;ACZD,MAAa,OAAO,gBAAgB;CAClC,MAAM;CACN,OAAO,EACL,SAAS;EAAC;EAAS;EAAQ;CAAS,EACtC;CACA,UAAU;CACV,QAAQ;AACV,CAAC;;;ACPD,MAAa,OAAO,gBAAgB;CAClC,MAAM;CACN,OAAO;EACL,WAAW,CAAC,UAAU,KAAK;EAC3B,KAAK;GAAC;GAAQ;GAAS;GAAU;EAAO;EACxC,OAAO;GAAC;GAAW;GAAS;GAAU;EAAK;EAC3C,SAAS,CAAC,SAAS,MAAM;CAC3B;CACA,QAAQ,CAAC,KAAK;CACd,UAAU;AACZ,CAAC;;;ACHD,MAAa,oBAAoB;CAAE;CAAQ;CAAO;CAAO;CAAM;AAAK;AAIpE,MAAa,kBAAkB,kBAAkB,OAAO,OAAO,iBAAiB,CAAC;;;ACXjF,IAAa,eAAb,MAA4E;CAC1E,6BAAsB,IAAI,IAAiC;CAE3D,GAA2B,MAAS,UAAiC;EACnE,MAAM,YAAY,KAAK,WAAW,IAAI,IAAI,qBAAK,IAAI,IAAI;EACvD,KAAK,WAAW,IAAI,MAAM,SAAS;EACnC,UAAU,IAAI,QAAQ;EACtB,aAAa,UAAU,OAAO,QAAQ;CACxC;CAEA,KAA6B,MAAS,GAAG,MAAmC;EAE1E,KADuB,WAAW,IAAI,IAC9B,CAAC,EAAE,SAAS,aAAa,SAAS,GAAG,IAAI,CAAC;CACpD;AACF;;;ACXA,SAAgB,YACd,MACA,SAAiB,CAAC,GACA;CAClB,OAAO;EAAE;EAAM;CAAO;AACxB;;;ACDA,SAAgB,gBAA2B;CACzC,MAAM,YAAY,WAAW;CAC7B,IAAI,CAAC,WACH,MAAM,IAAI,MACR,qJAEF;CAEF,OAAO;AACT;;;ACPA,MAAa,yBAAwC;CAAE,QAAQ;CAAS,UAAU;AAAS;;;ACR3F,IAAa,YAAb,cAA+B,MAAM;CACnC,OAAyB;CACzB;CAEA,YAAY,MAAqB,SAAiB;EAChD,MAAM,OAAO;EACb,KAAK,OAAO;CACd;AACF;AAiBA,IAAI,kBAAqC;AAGzC,SAAgB,YAAY,QAAiC;CAC3D,kBAAkB;AACpB;AAEA,SAAgB,SACd,QACA,QACA,UAA2B,CAAC,GACP;CACrB,IAAI,CAAC,iBAAiB;EACpB,MAAM,QAAQ,IAAI,UAChB,eACA,mBAAmB,OAAO,iCAC5B;EACA,OAAO,kBAAkB,QAAQ,OAAO,KAAK,CAAC;CAChD;CACA,OAAO,gBAAgB,QAAQ,QAAQ,OAAO;AAChD;AAEA,SAAgB,kBACd,SACA,eAA2B,CAAC,GACP;CACrB,MAAM,UAAU;CAChB,QAAQ,SAAS;CACjB,OAAO;AACT;;;ACrDA,MAAa,cAAc,CAAC,SAAS;AAIrC,SAAgB,aAAa,OAAuC;CAClE,OAAQ,YAAkC,SAAS,KAAK;AAC1D;;;ACTA,MAAa,iBACX;AAUF,SAAgB,kBAAkB,OAAiC;CACjE,OAAO,OAAO,UAAU,YAAY,eAAe,KAAK,KAAK;AAC/D;AAEA,SAAgB,aAAa,SAAyB;CACpD,OAAO,aAAa,OAAO,CAAC,CAAC;AAC/B;AAGA,SAAgB,iBAAiB,SAAiB,SAA0B;CAC1E,OAAO,gBAAgB,SAAS,OAAO,KAAK;AAC9C;AAIA,SAAgB,gBAAgB,MAAc,OAAuB;CACnE,MAAM,cAAc,aAAa,IAAI;CACrC,MAAM,eAAe,aAAa,KAAK;CACvC,MAAM,cAAc;EAClB,YAAY,QAAQ,aAAa;EACjC,YAAY,QAAQ,aAAa;EACjC,YAAY,QAAQ,aAAa;CACnC;CACA,KAAK,MAAM,cAAc,aACvB,IAAI,eAAe,GACjB,OAAO;CAGX,OAAO,mBAAmB,YAAY,YAAY,aAAa,UAAU;AAC3E;AAEA,SAAS,aAAa,SAAkC;CACtD,MAAM,QAAQ,eAAe,KAAK,OAAO;CACzC,IAAI,CAAC,OACH,MAAM,IAAI,MAAM,IAAI,QAAQ,4BAA4B;CAE1D,MAAM,GAAG,OAAO,OAAO,OAAO,cAAc;CAC5C,OAAO;EACL,OAAO,OAAO,KAAK;EACnB,OAAO,OAAO,KAAK;EACnB,OAAO,OAAO,KAAK;EACnB,YAAY,eAAe,KAAA,IAAY,CAAC,IAAI,WAAW,MAAM,GAAG;CAClE;AACF;AAIA,SAAS,mBAAmB,MAAyB,OAAkC;CACrF,IAAI,KAAK,WAAW,KAAK,MAAM,WAAW,GACxC,OAAO,MAAM,SAAS,KAAK;CAE7B,MAAM,SAAS,KAAK,IAAI,KAAK,QAAQ,MAAM,MAAM;CACjD,KAAK,IAAI,QAAQ,GAAG,QAAQ,QAAQ,SAAS;EAC3C,MAAM,QAAQ,mBAAmB,KAAK,QAAS,MAAM,MAAO;EAC5D,IAAI,UAAU,GACZ,OAAO;CAEX;CACA,OAAO,KAAK,SAAS,MAAM;AAC7B;AAGA,SAAS,mBAAmB,MAAc,OAAuB;CAC/D,MAAM,eAAe,QAAQ,KAAK,IAAI;CACtC,MAAM,gBAAgB,QAAQ,KAAK,KAAK;CACxC,IAAI,gBAAgB,eAClB,OAAO,OAAO,IAAI,IAAI,OAAO,KAAK;CAEpC,IAAI,cACF,OAAO;CAET,IAAI,eACF,OAAO;CAET,IAAI,OAAO,OACT,OAAO;CAET,IAAI,OAAO,OACT,OAAO;CAET,OAAO;AACT;;;ACzFA,MAAa,kBAAkB;AAG/B,MAAa,qBAAqB;CAChC,OAAO;CACP,qBAAqB;CACrB,oBAAoB;AACtB;AAIA,SAAgB,aAAa,iBAAyB,MAAsB;CAC1E,OAAO,GAAG,kBAAkB,aAAa,eAAe,EAAE,GAAG;AAC/D;AAIA,SAAgB,kBAAkB,aAAqB,YAA6B;CAClF,OACE,aAAa,WAAW,MAAM,aAAa,UAAU,KACrD,iBAAiB,aAAa,UAAU;AAE5C;AAGA,SAAgB,mBAAmB,UAA6B,OAAmC;CAEjG,OADiB,SAAS,QAAQ,YAAY,aAAa,OAAO,MAAM,KAC1D,CAAC,CAAC,KAAK,eAAe,CAAC,CAAC,GAAG,EAAE;AAC7C;;;ACXA,SAAgB,uBAAuB,SAAsC;CAC3E,OAAO;EACL,OAAO,YAAY,QAAQ,YAAY,OAAO;EAC9C,OAAO,UAAU;GACf,MAAM,aAAa,UAA6B,SAAS,MAAM,IAAI;GACnE,QAAQ,iBAAiB,WAAW,SAAS;GAC7C,aAAa,QAAQ,oBAAoB,WAAW,SAAS;EAC/D;CACF;AACF;AAGA,SAAgB,sBAA8C;CAE5D,MAAM,iCAA4B,IAAI,IAAI;CAC1C,MAAM,kCAA6B,IAAI,IAAI;CAC3C,MAAM,cAAc,cAAyB,oBAA0C;EACrF,OAAO,YAAY;GAEjB,MAAM,OAAgB,KAAK,MAAM,KAAK,UAAU,OAAO,CAAC;GACxD,eAAe,SAAS,aAAa,SAAS,IAAI,CAAC;EACrD;EACA,OAAO,UAAU;GACf,aAAa,IAAI,QAAQ;GACzB,aAAa,aAAa,OAAO,QAAQ;EAC3C;CACF;CACA,OAAO,CAAC,WAAW,gBAAgB,eAAe,GAAG,WAAW,iBAAiB,cAAc,CAAC;AAClG;AC3BA,MAAa,aAAa,OAAO,KAAK;CANpC,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,UAAU;AAG0B,CAAS;;;ACtB/C,MAAa,kBAAkB;AAE/B,MAAM,UAAU;AAEhB,SAAgB,SAAS,OAAwB;CAC/C,OAAO,QAAQ,KAAK,KAAK;AAC3B;AAkBA,IAAa,kBAAb,MAA6B;CAC3B;CACA,SAAuB,CAAC;CACxB,kBAAkB;CAElB,YAAY,QAAA,GAAyB;EACnC,KAAK,QAAQ;CACf;CAEA,IAAI,QAA+B;EACjC,OAAO,KAAK;CACd;CAEA,IAAI,MAA8B;EAChC,OAAO,KAAK,OAAO,GAAG,EAAE;CAC1B;;;;;CAMA,MAAM,YAAiC;EACrC,QAAQ,WAAW,QAAnB;GACE,KAAK;IACH,IAAI,KAAK,OAAO,UAAU,KAAK,OAC7B,OAAO;IAET;GACF,KAAK;IACH,KAAK,OAAO,IAAI;IAChB;GACF,KAAK;IACH,KAAK,SAAS,CAAC;IACf;GACF,KAAK,QAAQ;IACX,MAAM,QAAQ,KAAK,IAAI,WAAW,OAAO,KAAK,OAAO,SAAS,CAAC;IAC/D,IAAI,QAAQ,GACV,OAAO;IAET,KAAK,SAAS,KAAK,OAAO,MAAM,GAAG,CAAC,KAAK;IACzC,OAAO;GACT;EACF;EACA,MAAM,EAAE,MAAM,YAAY;EAC1B,KAAK,SAAS,CAAC,GAAG,KAAK,QAAQ;GAAE,YAAY,KAAK;GAAmB;GAAM;EAAQ,CAAC;EACpF,OAAO;CACT;AACF;;;ACvEA,SAAgB,aAAgB,OAAU,SAAwB;CAChE,MAAM,OAAO,EAAE,GAAG,MAAM;CACxB,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,OAAO,GAC/C,IAAI,UAAU,KAAA,GACZ,KAAK,OAAO;CAGhB,OAAO;AACT;;;ACHA,IAAa,iBAAb,MAAsF;CACpF;CACA,4BAAqB,IAAI,IAAmC;CAE5D,YAAY,WAAsB;EAChC,KAAK,aAAa;CACpB;CAEA,KAAsC,MAAS,SAA4B;EACzE,KAAK,WAAW,KAAK;GAAE;GAAM;EAAQ,CAAoB;CAC3D;CAEA,OACE,MACA,SACyC;EACzC,MAAM,WAAW,KAAK,UAAU,IAAI,IAAI;EACxC,KAAK,UAAU,IAAI,MAAM,OAAO;EAChC,OAAO;CACT;CAEA,OAAO,SAAkE;EACvE,OAAO,KAAK,WAAW,QAAQ,eAAe;GAC5C,MAAM,UAAU;GAChB,MAAM,UAAU,KAAK,UAAU,IAAI,QAAQ,IAAI;GAC/C,IAAI,CAAC,SAAS;IACZ,wBAAQ,IAAI,MAAM,sCAAsC,QAAQ,KAAK,EAAE,GAAG,OAAO;IACjF;GACF;GACA,IAAI;IACF,QAAQ,QAAQ,OAAO;GACzB,SAAS,OAAO;IACd,QAAQ,OAAO,OAAO;GACxB;EACF,CAAC;CACH;AACF"}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@monimesl/dot-core",
|
|
3
|
+
"version": "0.1.0-alpha.2",
|
|
4
|
+
"description": "Dot contracts shared by every layer: protocol, transports, component manifests, view renderer",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"directory": "packages/core",
|
|
9
|
+
"url": "git+https://github.com/monime-lab/dot.git"
|
|
10
|
+
},
|
|
11
|
+
"sideEffects": false,
|
|
12
|
+
"files": [
|
|
13
|
+
"dist"
|
|
14
|
+
],
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"@monimesl/dot-source": "./src/index.ts",
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"import": "./dist/index.js",
|
|
20
|
+
"default": "./dist/index.js"
|
|
21
|
+
},
|
|
22
|
+
"./package.json": "./package.json"
|
|
23
|
+
},
|
|
24
|
+
"main": "./dist/index.js",
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"publint": "^0.3.24",
|
|
28
|
+
"rimraf": "^6.1.3",
|
|
29
|
+
"tsdown": "^0.23.0",
|
|
30
|
+
"typescript": "^5.9.3",
|
|
31
|
+
"vitest": "^5.0.1"
|
|
32
|
+
},
|
|
33
|
+
"publishConfig": {
|
|
34
|
+
"access": "public"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsdown",
|
|
38
|
+
"dev": "tsdown --watch",
|
|
39
|
+
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
40
|
+
"test": "vitest run",
|
|
41
|
+
"clean": "rimraf dist *.tsbuildinfo"
|
|
42
|
+
}
|
|
43
|
+
}
|