@cascateer/core 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,4 @@
1
+ export { Future } from "./Future";
2
+ export { ComputedSignal, Signal } from "./Signal";
3
+ export { TapObservable } from "./TapObservable";
4
+ export { TransformSubject } from "./TransformSubject";
@@ -0,0 +1,6 @@
1
+ import { OperatorFunction, scan } from "rxjs";
2
+
3
+ export const concat =
4
+ <T>(): OperatorFunction<T | T[], T[]> =>
5
+ (source) =>
6
+ source.pipe(scan((acc, curr) => acc.concat(curr), new Array<T>()));
@@ -0,0 +1,23 @@
1
+ import { fromEvent, map, Observable, OperatorFunction } from "rxjs";
2
+ import { property } from "../lib";
3
+
4
+ export const exchangeWith =
5
+ <InMessage, OutMessage>(
6
+ port: MessagePort,
7
+ ): OperatorFunction<OutMessage, InMessage> =>
8
+ (messages) =>
9
+ new Observable<InMessage>((subscriber) => {
10
+ fromEvent<MessageEvent<any>>(port, "message")
11
+ .pipe(map(property("data")))
12
+ .subscribe(subscriber);
13
+
14
+ port.start();
15
+
16
+ subscriber.add({
17
+ unsubscribe: () => port.close(),
18
+ });
19
+
20
+ return messages.subscribe({
21
+ next: (message) => port.postMessage(message),
22
+ });
23
+ });
@@ -0,0 +1,11 @@
1
+ import { OperatorFunction, from, map, mergeMap } from "rxjs";
2
+
3
+ export const flatMap =
4
+ <T, U>(
5
+ project: (value: T, index: number) => U | U[],
6
+ ): OperatorFunction<T, U> =>
7
+ (source) =>
8
+ source.pipe(
9
+ map(project),
10
+ mergeMap((value) => from(Array.isArray(value) ? value : [value])),
11
+ );
@@ -0,0 +1,15 @@
1
+ export { concat } from "./concat";
2
+ export { exchangeWith } from "./exchangeWith";
3
+ export { flatMap } from "./flatMap";
4
+ export {
5
+ multicast,
6
+ type MulticastAction,
7
+ type MulticastActionMessage,
8
+ type MulticastClientMessage,
9
+ type MulticastConnectMessageData,
10
+ type MulticastHostMessage,
11
+ type MulticastSubject,
12
+ } from "./multicast";
13
+ export { sequence } from "./sequence";
14
+ export { tapSubscription } from "./tapSubscription";
15
+ export { transform } from "./transform";
@@ -0,0 +1,99 @@
1
+ import { concatMap, shareReplay, startWith, UnaryFunction } from "rxjs";
2
+ import { v4 } from "uuid";
3
+ import SharedWorker from "../multicast?sharedworker";
4
+ import { ComputedSignal, TransformSubject } from "../observable";
5
+ import { exchangeWith, transform } from "../operators";
6
+ import { Transform } from "../types";
7
+
8
+ interface MulticastBaseMessage<Type, Data> {
9
+ id: string;
10
+ previousId?: string;
11
+ type: Type;
12
+ data: Data;
13
+ sameOrigin?: boolean;
14
+ origin?: MessagePort;
15
+ }
16
+
17
+ interface MulticastActions<Data> {
18
+ seedAction: {
19
+ predicate: () => Data;
20
+ data: {
21
+ seed: Data;
22
+ };
23
+ };
24
+ transformAction: {
25
+ predicate: Transform<Data>;
26
+ data: {
27
+ key: string;
28
+ args: unknown;
29
+ };
30
+ };
31
+ }
32
+
33
+ type MulticastBaseActionMessage<
34
+ Data,
35
+ Type extends keyof MulticastActions<Data>,
36
+ > = MulticastBaseMessage<Type, MulticastActions<Data>[Type]["data"]>;
37
+
38
+ export type MulticastActionMessage<Data> =
39
+ | MulticastBaseActionMessage<Data, "seedAction">
40
+ | MulticastBaseActionMessage<Data, "transformAction">;
41
+
42
+ export type MulticastAction<
43
+ Data,
44
+ Type extends keyof MulticastActions<Data> = keyof MulticastActions<Data>,
45
+ > = MulticastActionMessage<Data> &
46
+ {
47
+ [T in Type]: {
48
+ type: T;
49
+ target?: ComputedSignal<Data>;
50
+ predicate: MulticastActions<Data>[T]["predicate"];
51
+ callback?: UnaryFunction<Data, void>;
52
+ };
53
+ }[Type];
54
+
55
+ export interface MulticastConnectMessageData<Seed> {
56
+ key: string;
57
+ seed: Seed;
58
+ }
59
+
60
+ type MulticastConnectMessage<Seed = any> = MulticastBaseMessage<
61
+ "connect",
62
+ MulticastConnectMessageData<Seed>
63
+ >;
64
+
65
+ export type MulticastHostMessage = MulticastActionMessage<any>;
66
+ export type MulticastClientMessage =
67
+ | MulticastActionMessage<any>
68
+ | MulticastConnectMessage;
69
+
70
+ type MulticastMessage = MulticastHostMessage | MulticastClientMessage;
71
+
72
+ type MulticastMessageConstructor<Message extends MulticastMessage> =
73
+ UnaryFunction<Record<"key" | "id", string>, Promise<Message>>;
74
+
75
+ export interface MulticastSubject extends TransformSubject<
76
+ MulticastMessageConstructor<MulticastClientMessage>,
77
+ MulticastHostMessage
78
+ > {}
79
+
80
+ export const multicast = <Seed>(
81
+ key: Promise<string>,
82
+ seed: Seed,
83
+ ): MulticastSubject =>
84
+ transform((messages) =>
85
+ messages.pipe(
86
+ startWith(
87
+ ({ key, id }): MulticastConnectMessage => ({
88
+ id,
89
+ type: "connect",
90
+ data: { key, seed },
91
+ }),
92
+ ),
93
+ concatMap((message) => key.then((key) => message({ key, id: v4() }))),
94
+ exchangeWith<MulticastHostMessage, MulticastClientMessage>(
95
+ new SharedWorker().port,
96
+ ),
97
+ shareReplay({ refCount: false }),
98
+ ),
99
+ );
@@ -0,0 +1,23 @@
1
+ import { map, OperatorFunction, scan } from "rxjs";
2
+
3
+ export const sequence =
4
+ <Input, Output>(
5
+ predicate: (inputs: [Input, ...Input[]], outputs: Output[]) => Output,
6
+ ): OperatorFunction<Input, Output> =>
7
+ (source) =>
8
+ source.pipe(
9
+ scan(
10
+ ({ inputs, outputs }, input) => ({
11
+ inputs: [input],
12
+ outputs: [predicate([input, ...inputs], outputs)],
13
+ }),
14
+ { inputs: new Array<Input>(), outputs: new Array<Output>() },
15
+ ),
16
+ map(({ outputs }) => {
17
+ if (!(0 in outputs)) {
18
+ throw new Error();
19
+ }
20
+
21
+ return outputs[0];
22
+ }),
23
+ );
@@ -0,0 +1,11 @@
1
+ import { MonoTypeOperatorFunction, NextObserver, tap } from "rxjs";
2
+
3
+ export const tapSubscription =
4
+ <T>(observer?: NextObserver<boolean>): MonoTypeOperatorFunction<T> =>
5
+ (source) =>
6
+ source.pipe(
7
+ tap({
8
+ subscribe: () => observer?.next(true),
9
+ unsubscribe: () => observer?.next(false),
10
+ }),
11
+ );
@@ -0,0 +1,7 @@
1
+ import { Observable, Subject, UnaryFunction } from "rxjs";
2
+ import { TransformSubject } from "../observable";
3
+
4
+ export const transform = <T, U = T>(
5
+ project: UnaryFunction<Subject<T>, Observable<U>>,
6
+ target?: Subject<T>,
7
+ ) => new TransformSubject(project, target);
package/src/slice.ts ADDED
@@ -0,0 +1,274 @@
1
+ import { Dictionary, mapValues } from "lodash";
2
+ import { defer, map, share, UnaryFunction } from "rxjs";
3
+ import { createFragment } from ".";
4
+ import { ApiAdapter, ApiEffect } from "./api";
5
+ import {
6
+ ComponentConstructor,
7
+ ComponentsAdapter,
8
+ ComponentsProvider,
9
+ } from "./component";
10
+ import { defineCustomElement } from "./dom";
11
+ import { ExtendableDictionary } from "./lib";
12
+ import { ComputedSignal } from "./observable";
13
+ import { multicast, MulticastSubject } from "./operators";
14
+ import { StoreAdapter, StoreProvider } from "./store";
15
+ import { TerminalAdapter, TerminalEffect, TerminalProvider } from "./terminal";
16
+ import { Action } from "./types";
17
+
18
+ interface SliceConfig<
19
+ Data,
20
+ StoreSignals extends Dictionary<ComputedSignal<any>>,
21
+ StoreActions extends Dictionary<Action<any, any>>,
22
+ ApiEffects extends Dictionary<ApiEffect<any, any>>,
23
+ ApiActions extends Dictionary<Action<any, any>>,
24
+ TerminalEffects extends Dictionary<TerminalEffect<any, any>>,
25
+ TerminalActions extends Dictionary<Action<any, any>>,
26
+ Components extends Dictionary<ComponentConstructor<any>>,
27
+ > {
28
+ data: Data;
29
+ store: UnaryFunction<
30
+ {
31
+ StoreProvider: {
32
+ new (): StoreProvider<Data>;
33
+ };
34
+ },
35
+ StoreAdapter<StoreSignals, StoreActions>
36
+ >;
37
+ api: ApiAdapter<ApiEffects, ApiActions>;
38
+ terminal: UnaryFunction<
39
+ {
40
+ TerminalProvider: {
41
+ new (): TerminalProvider<
42
+ StoreSignals,
43
+ StoreActions,
44
+ ApiEffects,
45
+ ApiActions
46
+ >;
47
+ };
48
+ },
49
+ TerminalAdapter<TerminalEffects, TerminalActions>
50
+ >;
51
+ components: UnaryFunction<
52
+ {
53
+ ComponentsProvider: {
54
+ new (): ComponentsProvider<
55
+ StoreSignals,
56
+ StoreActions,
57
+ TerminalEffects,
58
+ TerminalActions
59
+ >;
60
+ };
61
+ },
62
+ ComponentsAdapter<Components>
63
+ >;
64
+ render: UnaryFunction<
65
+ {
66
+ [K in keyof Components]: ReturnType<
67
+ <
68
+ Props extends Components[K] extends ComponentConstructor<infer Props>
69
+ ? Props
70
+ : never,
71
+ >() => JSX.Component<Props>
72
+ >;
73
+ },
74
+ JSX.Element
75
+ >;
76
+ }
77
+
78
+ export const createSlice = <
79
+ Data,
80
+ StoreSignals extends Dictionary<ComputedSignal<any>>,
81
+ StoreActions extends Dictionary<Action<any, any>>,
82
+ ApiEffects extends Dictionary<ApiEffect<any, any>>,
83
+ ApiActions extends Dictionary<Action<any, any>>,
84
+ TerminalEffects extends Dictionary<TerminalEffect<any, any>>,
85
+ TerminalActions extends Dictionary<Action<any, any>>,
86
+ Components extends Dictionary<ComponentConstructor<any>>,
87
+ >(
88
+ config: SliceConfig<
89
+ Data,
90
+ StoreSignals,
91
+ StoreActions,
92
+ ApiEffects,
93
+ ApiActions,
94
+ TerminalEffects,
95
+ TerminalActions,
96
+ Components
97
+ >,
98
+ ) => config;
99
+
100
+ export class Slice<
101
+ Data,
102
+ StoreSignals extends Dictionary<ComputedSignal<any>>,
103
+ StoreActions extends Dictionary<Action<any, any>>,
104
+ ApiEffects extends Dictionary<ApiEffect<any, any>>,
105
+ ApiActions extends Dictionary<Action<any, any>>,
106
+ TerminalEffects extends Dictionary<TerminalEffect<any, any>>,
107
+ TerminalActions extends Dictionary<Action<any, any>>,
108
+ Components extends Dictionary<ComponentConstructor<any>>,
109
+ > {
110
+ private store: StoreAdapter<StoreSignals, StoreActions>;
111
+ private terminal: TerminalAdapter<TerminalEffects, TerminalActions>;
112
+
113
+ actions: MulticastSubject;
114
+ render: () => JSX.Element;
115
+
116
+ constructor(
117
+ public key: Promise<string>,
118
+ {
119
+ data,
120
+ store,
121
+ api,
122
+ terminal,
123
+ components,
124
+ render,
125
+ }: SliceConfig<
126
+ Data,
127
+ StoreSignals,
128
+ StoreActions,
129
+ ApiEffects,
130
+ ApiActions,
131
+ TerminalEffects,
132
+ TerminalActions,
133
+ Components
134
+ >,
135
+ ) {
136
+ this.store = store({
137
+ StoreProvider: ((context) =>
138
+ class extends StoreProvider<Data> {
139
+ constructor() {
140
+ super(context);
141
+ }
142
+ })({
143
+ actions: (this.actions = multicast(key, data)),
144
+ }),
145
+ });
146
+
147
+ this.terminal = terminal({
148
+ TerminalProvider: ((context) =>
149
+ class extends TerminalProvider<
150
+ StoreSignals,
151
+ StoreActions,
152
+ ApiEffects,
153
+ ApiActions
154
+ > {
155
+ constructor() {
156
+ super(context);
157
+ }
158
+ })({ api, store: this.store }),
159
+ });
160
+
161
+ this.render = () =>
162
+ createFragment({
163
+ children: defer(() => key).pipe(
164
+ map(
165
+ (key) =>
166
+ new (defineCustomElement(`${key}-slice`))(
167
+ render(
168
+ mapValues(
169
+ components({
170
+ ComponentsProvider: ((context) =>
171
+ class extends ComponentsProvider<
172
+ StoreSignals,
173
+ StoreActions,
174
+ TerminalEffects,
175
+ TerminalActions
176
+ > {
177
+ constructor() {
178
+ super(context);
179
+ }
180
+ })({ store: this.store, terminal: this.terminal }),
181
+ }).components,
182
+ (componentConstructor) =>
183
+ componentConstructor.predicate(key),
184
+ ),
185
+ ),
186
+ ),
187
+ ),
188
+ share(),
189
+ ),
190
+ });
191
+ }
192
+ }
193
+
194
+ export class SliceAdapter<
195
+ Slices extends Dictionary<Slice<any, any, any, any, any, any, any, any>>,
196
+ > {
197
+ constructor(public slices: Slices) {}
198
+ }
199
+
200
+ export class ExtendableSliceAdapter<
201
+ Slices extends Dictionary<Slice<any, any, any, any, any, any, any, any>>,
202
+ > {
203
+ complete(): SliceAdapter<Slices> {
204
+ return new SliceAdapter(this.extendableSlices.complete());
205
+ }
206
+
207
+ constructor(
208
+ private extendableSlices: ExtendableDictionary<
209
+ Slice<any, any, any, any, any, any, any, any>,
210
+ Slices
211
+ >,
212
+ ) {}
213
+
214
+ provideSlices<
215
+ MoreSlices extends Dictionary<
216
+ Slice<any, any, any, any, any, any, any, any>
217
+ >,
218
+ >(
219
+ slices: UnaryFunction<
220
+ {
221
+ slice: <
222
+ Data,
223
+ StoreSignals extends Dictionary<ComputedSignal<any>>,
224
+ StoreActions extends Dictionary<Action<any, any>>,
225
+ ApiEffects extends Dictionary<ApiEffect<any, any>>,
226
+ ApiActions extends Dictionary<Action<any, any>>,
227
+ TerminalEffects extends Dictionary<TerminalEffect<any, any>>,
228
+ TerminalActions extends Dictionary<Action<any, any>>,
229
+ Components extends Dictionary<ComponentConstructor<any>>,
230
+ >(
231
+ constructor: UnaryFunction<
232
+ void,
233
+ SliceConfig<
234
+ Data,
235
+ StoreSignals,
236
+ StoreActions,
237
+ ApiEffects,
238
+ ApiActions,
239
+ TerminalEffects,
240
+ TerminalActions,
241
+ Components
242
+ >
243
+ >,
244
+ ) => Slice<
245
+ Data,
246
+ StoreSignals,
247
+ StoreActions,
248
+ ApiEffects,
249
+ ApiActions,
250
+ TerminalEffects,
251
+ TerminalActions,
252
+ Components
253
+ >;
254
+ },
255
+ MoreSlices
256
+ >,
257
+ ) {
258
+ return new ExtendableSliceAdapter(
259
+ this.extendableSlices.extend(
260
+ () =>
261
+ ({ property }) =>
262
+ slices({
263
+ slice: (config) => property((key) => new Slice(key, config())),
264
+ }),
265
+ ),
266
+ );
267
+ }
268
+ }
269
+
270
+ export class SliceProvider extends ExtendableSliceAdapter<{}> {
271
+ constructor() {
272
+ super(new ExtendableDictionary({}));
273
+ }
274
+ }