@equinor/fusion-framework-module-bookmark 4.0.4 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/README.md +42 -0
- package/dist/esm/__tests__/mock/bookmark-mock.test.js +151 -0
- package/dist/esm/__tests__/mock/bookmark-mock.test.js.map +1 -0
- package/dist/esm/mock/BookmarkMockClient.js +281 -0
- package/dist/esm/mock/BookmarkMockClient.js.map +1 -0
- package/dist/esm/mock/BookmarkMockConfigurator.js +138 -0
- package/dist/esm/mock/BookmarkMockConfigurator.js.map +1 -0
- package/dist/esm/mock/index.js +26 -0
- package/dist/esm/mock/index.js.map +1 -0
- package/dist/esm/mock/module.js +42 -0
- package/dist/esm/mock/module.js.map +1 -0
- package/dist/esm/version.js +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/__tests__/mock/bookmark-mock.test.d.ts +1 -0
- package/dist/types/mock/BookmarkMockClient.d.ts +121 -0
- package/dist/types/mock/BookmarkMockConfigurator.d.ts +86 -0
- package/dist/types/mock/index.d.ts +25 -0
- package/dist/types/mock/module.d.ts +43 -0
- package/dist/types/version.d.ts +1 -1
- package/package.json +20 -11
- package/src/__tests__/mock/bookmark-mock.test.ts +199 -0
- package/src/mock/BookmarkMockClient.ts +310 -0
- package/src/mock/BookmarkMockConfigurator.ts +159 -0
- package/src/mock/index.ts +25 -0
- package/src/mock/module.ts +64 -0
- package/src/version.ts +1 -1
- package/vitest.config.ts +11 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,36 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## 4.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- f663b46: Add a purpose-built mock, exported from a new `/mock` subpath (`@equinor/fusion-framework-module-bookmark/mock`).
|
|
8
|
+
|
|
9
|
+
`enableBookmarkMock` swaps in an in-memory `IBookmarkClient` behind the real `BookmarkModuleConfigurator`, `BookmarkProvider`, and store flows — create, update, delete, and favourite calls all reach the mock client through the real flow logic, not a stand-in. `BookmarkMockConfigurator` adds a bookmark-domain vocabulary for seeding state:
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
import { enableBookmarkMock } from '@equinor/fusion-framework-module-bookmark/mock';
|
|
13
|
+
|
|
14
|
+
enableBookmarkMock(configurator, (builder) => {
|
|
15
|
+
builder.setBookmarks([
|
|
16
|
+
{
|
|
17
|
+
id: 'bookmark-1',
|
|
18
|
+
name: 'My Bookmark',
|
|
19
|
+
appKey: 'my-app',
|
|
20
|
+
payload: {},
|
|
21
|
+
created: new Date(),
|
|
22
|
+
createdBy: { id: 'mock-user', name: 'Mock User' },
|
|
23
|
+
},
|
|
24
|
+
]);
|
|
25
|
+
builder.setCurrentBookmark('bookmark-1');
|
|
26
|
+
builder.setFavorite('bookmark-1', true);
|
|
27
|
+
});
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The whole real builder API stays available, including `setClient`, so an explicit call to it still replaces the mock client outright. When no real `app`/`context` module is registered alongside the mock, `resolve.application`/`resolve.context` fall back to trivial resolvers automatically, since the module's config schema requires both.
|
|
31
|
+
|
|
32
|
+
Related: equinor/fusion-core-tasks#1667.
|
|
33
|
+
|
|
3
34
|
## 4.0.4
|
|
4
35
|
|
|
5
36
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -232,6 +232,48 @@ enableBookmark(configurator, (builder) => {
|
|
|
232
232
|
});
|
|
233
233
|
```
|
|
234
234
|
|
|
235
|
+
## Testing
|
|
236
|
+
|
|
237
|
+
Import from `@equinor/fusion-framework-module-bookmark/mock` to seed bookmarks in-process instead of calling a real API. The real `BookmarkModuleConfigurator`, `BookmarkProvider`, and store flows still run — only `IBookmarkClient` is substituted with an in-memory implementation.
|
|
238
|
+
|
|
239
|
+
### Defaults
|
|
240
|
+
|
|
241
|
+
- The in-memory client starts with no bookmarks or favorites.
|
|
242
|
+
- No current bookmark is selected unless `setCurrentBookmark` names a seeded bookmark.
|
|
243
|
+
- Create, update, delete, and favorite operations mutate the in-memory client through the real provider flows.
|
|
244
|
+
- Without real `app` or `context` modules, deterministic fallback resolvers satisfy the bookmark config schema.
|
|
245
|
+
|
|
246
|
+
```ts
|
|
247
|
+
import { enableBookmarkMock } from '@equinor/fusion-framework-module-bookmark/mock';
|
|
248
|
+
|
|
249
|
+
enableBookmarkMock(configurator, (builder) => {
|
|
250
|
+
builder.setBookmarks([
|
|
251
|
+
{
|
|
252
|
+
id: 'bookmark-1',
|
|
253
|
+
name: 'My Bookmark',
|
|
254
|
+
appKey: 'my-app',
|
|
255
|
+
payload: {},
|
|
256
|
+
created: new Date(),
|
|
257
|
+
createdBy: { id: 'mock-user', name: 'Mock User' },
|
|
258
|
+
},
|
|
259
|
+
]);
|
|
260
|
+
builder.setCurrentBookmark('bookmark-1');
|
|
261
|
+
builder.setFavorite('bookmark-1', true);
|
|
262
|
+
});
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
`setBookmarks` seeds the bookmarks `getAllBookmarks`/`getBookmarkById`/`getBookmarkData` resolve. `setCurrentBookmark` declares which seeded bookmark `currentBookmark`/`currentBookmark$` report as active on initialization. `setFavorite` seeds `isBookmarkInFavorites`. Create, update, delete, and favourite calls all reach the in-memory client through the real flows — nothing is stubbed out.
|
|
266
|
+
|
|
267
|
+
The whole real builder API stays available, including `setClient`, so an explicit call to it still replaces the mock client outright:
|
|
268
|
+
|
|
269
|
+
```ts
|
|
270
|
+
enableBookmarkMock(configurator, (builder) => {
|
|
271
|
+
builder.setClient(myOwnBookmarkClient);
|
|
272
|
+
});
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
If no real `app` or `context` module is registered alongside the mock, `resolve.application`/`resolve.context` fall back to trivial resolvers automatically, since the module's config schema requires both. Registering a real `app`/`context` module still wins.
|
|
276
|
+
|
|
235
277
|
## Error Handling
|
|
236
278
|
|
|
237
279
|
The module exposes two error classes:
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { firstValueFrom, from } from 'rxjs';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import { ModulesConfigurator } from '@equinor/fusion-framework-module';
|
|
4
|
+
import { BookmarkModuleConfigurator } from '../../BookmarkModuleConfigurator';
|
|
5
|
+
import { BookmarkProvider } from '../../BookmarkProvider';
|
|
6
|
+
import { module as realModule } from '../../bookmark-module';
|
|
7
|
+
import { BookmarkMockClient, BookmarkMockConfigurator, bookmarkMockModule, enableBookmarkMock, } from '../../mock';
|
|
8
|
+
/** A fully-formed seeded bookmark, so tests only override what they care about. */
|
|
9
|
+
const createBookmark = (overrides = {}) => ({
|
|
10
|
+
id: 'bookmark-1',
|
|
11
|
+
name: 'My Bookmark',
|
|
12
|
+
appKey: 'test-app',
|
|
13
|
+
created: new Date('2024-01-01T00:00:00.000Z'),
|
|
14
|
+
createdBy: { id: 'seed-user', name: 'Seed User' },
|
|
15
|
+
...overrides,
|
|
16
|
+
});
|
|
17
|
+
/**
|
|
18
|
+
* Initializes the mock module through the real module system.
|
|
19
|
+
*
|
|
20
|
+
* @remarks
|
|
21
|
+
* Deliberately avoids hand-building initialization arguments — faking the
|
|
22
|
+
* module system is the very cost this mock removes.
|
|
23
|
+
*
|
|
24
|
+
* @param configure - Optional callback to seed bookmarks, current bookmark, or favorites.
|
|
25
|
+
* @returns The `IBookmarkProvider` the module produced.
|
|
26
|
+
*/
|
|
27
|
+
const initializeMockWith = async (configure) => {
|
|
28
|
+
const configurator = new ModulesConfigurator([]);
|
|
29
|
+
enableBookmarkMock(configurator, configure);
|
|
30
|
+
const instances = await configurator.initialize();
|
|
31
|
+
return instances.bookmark;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Resolves the first value of an `IBookmarkProvider` call.
|
|
35
|
+
*
|
|
36
|
+
* @remarks
|
|
37
|
+
* `IBookmarkProvider`'s methods are typed as `ObservableInput`, not `Observable`,
|
|
38
|
+
* so this wraps with `from()` before handing off to `firstValueFrom`.
|
|
39
|
+
*
|
|
40
|
+
* @template T - The value the observable input emits.
|
|
41
|
+
* @param input - The observable input to resolve.
|
|
42
|
+
* @returns A promise resolving to the first emitted value.
|
|
43
|
+
*/
|
|
44
|
+
const firstValue = (input) => firstValueFrom(from(input));
|
|
45
|
+
describe('bookmarkMockModule', () => {
|
|
46
|
+
it('changes nothing but the configurator', () => {
|
|
47
|
+
expect(bookmarkMockModule.name).toBe(realModule.name);
|
|
48
|
+
expect(bookmarkMockModule.version).toBe(realModule.version);
|
|
49
|
+
// The production initializer, untouched — the mock has no lifecycle of its own
|
|
50
|
+
expect(bookmarkMockModule.initialize).toBe(realModule.initialize);
|
|
51
|
+
});
|
|
52
|
+
it('builds a real BookmarkModuleConfigurator, so the whole builder stays available', () => {
|
|
53
|
+
const configurator = bookmarkMockModule.configure?.();
|
|
54
|
+
expect(configurator).toBeInstanceOf(BookmarkModuleConfigurator);
|
|
55
|
+
expect(configurator).toBeInstanceOf(BookmarkMockConfigurator);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
describe('enableBookmarkMock', () => {
|
|
59
|
+
it('produces the real BookmarkProvider, not a stand-in', async () => {
|
|
60
|
+
const provider = await initializeMockWith();
|
|
61
|
+
expect(provider).toBeInstanceOf(BookmarkProvider);
|
|
62
|
+
});
|
|
63
|
+
it('replaces a bookmark module that is already registered', async () => {
|
|
64
|
+
// A FrameworkConfigurator pre-registers the real bookmark module, so the
|
|
65
|
+
// mock is only useful if registering it afterwards wins
|
|
66
|
+
const configurator = new ModulesConfigurator([realModule]);
|
|
67
|
+
enableBookmarkMock(configurator, (builder) => {
|
|
68
|
+
builder.setBookmarks([createBookmark()]);
|
|
69
|
+
});
|
|
70
|
+
const instances = await configurator.initialize();
|
|
71
|
+
const provider = instances.bookmark;
|
|
72
|
+
const bookmarks = await firstValue(provider.getAllBookmarks());
|
|
73
|
+
expect(bookmarks).toHaveLength(1);
|
|
74
|
+
});
|
|
75
|
+
it('reflects seeded bookmarks with no real HTTP', async () => {
|
|
76
|
+
const seeded = createBookmark();
|
|
77
|
+
const provider = await initializeMockWith((builder) => {
|
|
78
|
+
builder.setBookmarks([seeded]);
|
|
79
|
+
});
|
|
80
|
+
const bookmarks = await firstValue(provider.getAllBookmarks());
|
|
81
|
+
expect(bookmarks.map((b) => b.id)).toEqual([seeded.id]);
|
|
82
|
+
});
|
|
83
|
+
it('reflects the seeded current bookmark', async () => {
|
|
84
|
+
const seeded = createBookmark();
|
|
85
|
+
const provider = await initializeMockWith((builder) => {
|
|
86
|
+
builder.setBookmarks([seeded]);
|
|
87
|
+
builder.setCurrentBookmark(seeded.id);
|
|
88
|
+
});
|
|
89
|
+
expect(provider.currentBookmark?.id).toBe(seeded.id);
|
|
90
|
+
});
|
|
91
|
+
it('leaves the current bookmark unset when none is seeded', async () => {
|
|
92
|
+
const provider = await initializeMockWith((builder) => {
|
|
93
|
+
builder.setBookmarks([createBookmark()]);
|
|
94
|
+
});
|
|
95
|
+
expect(provider.currentBookmark).toBeNull();
|
|
96
|
+
});
|
|
97
|
+
it('reflects a seeded favorite', async () => {
|
|
98
|
+
const seeded = createBookmark();
|
|
99
|
+
const provider = await initializeMockWith((builder) => {
|
|
100
|
+
builder.setBookmarks([seeded]);
|
|
101
|
+
builder.setFavorite(seeded.id, true);
|
|
102
|
+
});
|
|
103
|
+
await expect(firstValue(provider.isBookmarkInFavorites(seeded.id))).resolves.toBe(true);
|
|
104
|
+
});
|
|
105
|
+
it('creates a bookmark through the real create flow', async () => {
|
|
106
|
+
const provider = await initializeMockWith();
|
|
107
|
+
// without a payload generator, generatePayload() never emits and the create
|
|
108
|
+
// flow would hang forever waiting on it
|
|
109
|
+
provider.addPayloadGenerator(() => { });
|
|
110
|
+
const created = await firstValue(provider.createBookmark({ name: 'New Bookmark', appKey: 'test-app' }));
|
|
111
|
+
expect(created.name).toBe('New Bookmark');
|
|
112
|
+
const bookmarks = await firstValue(provider.getAllBookmarks());
|
|
113
|
+
expect(bookmarks.map((b) => b.id)).toContain(created.id);
|
|
114
|
+
});
|
|
115
|
+
it('updates a bookmark through the real update flow', async () => {
|
|
116
|
+
const seeded = createBookmark();
|
|
117
|
+
const provider = await initializeMockWith((builder) => {
|
|
118
|
+
builder.setBookmarks([seeded]);
|
|
119
|
+
});
|
|
120
|
+
// the update reducer only applies to bookmarks already tracked in the store,
|
|
121
|
+
// so fetch once first to seed it
|
|
122
|
+
await firstValue(provider.getAllBookmarks());
|
|
123
|
+
const updated = await firstValue(provider.updateBookmark(seeded.id, { name: 'Renamed' }, { excludePayloadGeneration: true }));
|
|
124
|
+
expect(updated.name).toBe('Renamed');
|
|
125
|
+
});
|
|
126
|
+
it('surfaces a missing bookmark as an observable error through the real fetch flow', async () => {
|
|
127
|
+
const provider = await initializeMockWith();
|
|
128
|
+
await expect(firstValue(provider.getBookmark('missing-bookmark'))).rejects.toThrow();
|
|
129
|
+
});
|
|
130
|
+
it('deletes a bookmark through the real delete flow', async () => {
|
|
131
|
+
const seeded = createBookmark();
|
|
132
|
+
const provider = await initializeMockWith((builder) => {
|
|
133
|
+
builder.setBookmarks([seeded]);
|
|
134
|
+
});
|
|
135
|
+
await firstValue(provider.deleteBookmark(seeded.id));
|
|
136
|
+
const bookmarks = await firstValue(provider.getAllBookmarks());
|
|
137
|
+
expect(bookmarks.map((b) => b.id)).not.toContain(seeded.id);
|
|
138
|
+
});
|
|
139
|
+
it('lets setClient() replace the mock client outright', async () => {
|
|
140
|
+
const ownClient = new BookmarkMockClient();
|
|
141
|
+
ownClient.setBookmarks([createBookmark({ id: 'own-bookmark' })]);
|
|
142
|
+
const provider = await initializeMockWith((builder) => {
|
|
143
|
+
// the escape hatch is inherited unchanged from BookmarkModuleConfigurator
|
|
144
|
+
builder.setBookmarks([createBookmark({ id: 'ignored-bookmark' })]);
|
|
145
|
+
builder.setClient(ownClient);
|
|
146
|
+
});
|
|
147
|
+
const bookmarks = await firstValue(provider.getAllBookmarks());
|
|
148
|
+
expect(bookmarks.map((b) => b.id)).toEqual(['own-bookmark']);
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
//# sourceMappingURL=bookmark-mock.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bookmark-mock.test.js","sourceRoot":"","sources":["../../../../src/__tests__/mock/bookmark-mock.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,IAAI,EAAwB,MAAM,MAAM,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAEvE,OAAO,EAAE,0BAA0B,EAAE,MAAM,kCAAkC,CAAC;AAC9E,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE1D,OAAO,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAG7D,OAAO,EACL,kBAAkB,EAClB,wBAAwB,EACxB,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,YAAY,CAAC;AAEpB,mFAAmF;AACnF,MAAM,cAAc,GAAG,CAAC,SAAS,GAAsB,EAAE,EAAY,EAAE,CAAC,CAAC;IACvE,EAAE,EAAE,YAAY;IAChB,IAAI,EAAE,aAAa;IACnB,MAAM,EAAE,UAAU;IAClB,OAAO,EAAE,IAAI,IAAI,CAAC,0BAA0B,CAAC;IAC7C,SAAS,EAAE,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,EAAE;IACjD,GAAG,SAAS;CACb,CAAC,CAAC;AAEH;;;;;;;;;GASG;AACH,MAAM,kBAAkB,GAAG,KAAK,EAC9B,SAAuD,EAC3B,EAAE;IAC9B,MAAM,YAAY,GAAG,IAAI,mBAAmB,CAAC,EAAE,CAAC,CAAC;IACjD,kBAAkB,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;IAC5C,MAAM,SAAS,GAAG,MAAM,YAAY,CAAC,UAAU,EAAE,CAAC;IAClD,OAAQ,SAAwD,CAAC,QAAQ,CAAC;AAC5E,CAAC,CAAC;AAEF;;;;;;;;;;GAUG;AACH,MAAM,UAAU,GAAG,CAAI,KAAyB,EAAc,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;AAE7F,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACtD,MAAM,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAC5D,+EAA+E;QAC/E,MAAM,CAAC,kBAAkB,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gFAAgF,EAAE,GAAG,EAAE;QACxF,MAAM,YAAY,GAAG,kBAAkB,CAAC,SAAS,EAAE,EAAE,CAAC;QAEtD,MAAM,CAAC,YAAY,CAAC,CAAC,cAAc,CAAC,0BAA0B,CAAC,CAAC;QAChE,MAAM,CAAC,YAAY,CAAC,CAAC,cAAc,CAAC,wBAAwB,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,EAAE,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;QAClE,MAAM,QAAQ,GAAG,MAAM,kBAAkB,EAAE,CAAC;QAE5C,MAAM,CAAC,QAAQ,CAAC,CAAC,cAAc,CAAC,gBAAgB,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,KAAK,IAAI,EAAE;QACrE,yEAAyE;QACzE,wDAAwD;QACxD,MAAM,YAAY,GAAG,IAAI,mBAAmB,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;QAC3D,kBAAkB,CAAC,YAAY,EAAE,CAAC,OAAO,EAAE,EAAE;YAC3C,OAAO,CAAC,YAAY,CAAC,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;QAEH,MAAM,SAAS,GAAG,MAAM,YAAY,CAAC,UAAU,EAAE,CAAC;QAClD,MAAM,QAAQ,GAAI,SAAwD,CAAC,QAAQ,CAAC;QAEpF,MAAM,SAAS,GAAG,MAAM,UAAU,CAAC,QAAQ,CAAC,eAAe,EAAE,CAAC,CAAC;QAC/D,MAAM,CAAC,SAAS,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;QAC3D,MAAM,MAAM,GAAG,cAAc,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,MAAM,kBAAkB,CAAC,CAAC,OAAO,EAAE,EAAE;YACpD,OAAO,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;QACjC,CAAC,CAAC,CAAC;QAEH,MAAM,SAAS,GAAG,MAAM,UAAU,CAAC,QAAQ,CAAC,eAAe,EAAE,CAAC,CAAC;QAC/D,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;QACpD,MAAM,MAAM,GAAG,cAAc,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,MAAM,kBAAkB,CAAC,CAAC,OAAO,EAAE,EAAE;YACpD,OAAO,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;YAC/B,OAAO,CAAC,kBAAkB,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACxC,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,QAAQ,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,KAAK,IAAI,EAAE;QACrE,MAAM,QAAQ,GAAG,MAAM,kBAAkB,CAAC,CAAC,OAAO,EAAE,EAAE;YACpD,OAAO,CAAC,YAAY,CAAC,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4BAA4B,EAAE,KAAK,IAAI,EAAE;QAC1C,MAAM,MAAM,GAAG,cAAc,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,MAAM,kBAAkB,CAAC,CAAC,OAAO,EAAE,EAAE;YACpD,OAAO,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;YAC/B,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;QAEH,MAAM,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,qBAAqB,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;QAC/D,MAAM,QAAQ,GAAG,MAAM,kBAAkB,EAAE,CAAC;QAC5C,4EAA4E;QAC5E,wCAAwC;QACxC,QAAQ,CAAC,mBAAmB,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAEvC,MAAM,OAAO,GAAG,MAAM,UAAU,CAC9B,QAAQ,CAAC,cAAc,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CACtE,CAAC;QAEF,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC1C,MAAM,SAAS,GAAG,MAAM,UAAU,CAAC,QAAQ,CAAC,eAAe,EAAE,CAAC,CAAC;QAC/D,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;QAC/D,MAAM,MAAM,GAAG,cAAc,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,MAAM,kBAAkB,CAAC,CAAC,OAAO,EAAE,EAAE;YACpD,OAAO,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;QACjC,CAAC,CAAC,CAAC;QACH,6EAA6E;QAC7E,iCAAiC;QACjC,MAAM,UAAU,CAAC,QAAQ,CAAC,eAAe,EAAE,CAAC,CAAC;QAE7C,MAAM,OAAO,GAAG,MAAM,UAAU,CAC9B,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,wBAAwB,EAAE,IAAI,EAAE,CAAC,CAC5F,CAAC;QAEF,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gFAAgF,EAAE,KAAK,IAAI,EAAE;QAC9F,MAAM,QAAQ,GAAG,MAAM,kBAAkB,EAAE,CAAC;QAE5C,MAAM,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,WAAW,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;IACvF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;QAC/D,MAAM,MAAM,GAAG,cAAc,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,MAAM,kBAAkB,CAAC,CAAC,OAAO,EAAE,EAAE;YACpD,OAAO,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;QACjC,CAAC,CAAC,CAAC;QAEH,MAAM,UAAU,CAAC,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;QAErD,MAAM,SAAS,GAAG,MAAM,UAAU,CAAC,QAAQ,CAAC,eAAe,EAAE,CAAC,CAAC;QAC/D,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mDAAmD,EAAE,KAAK,IAAI,EAAE;QACjE,MAAM,SAAS,GAAG,IAAI,kBAAkB,EAAE,CAAC;QAC3C,SAAS,CAAC,YAAY,CAAC,CAAC,cAAc,CAAC,EAAE,EAAE,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,CAAC;QAEjE,MAAM,QAAQ,GAAG,MAAM,kBAAkB,CAAC,CAAC,OAAO,EAAE,EAAE;YACpD,0EAA0E;YAC1E,OAAO,CAAC,YAAY,CAAC,CAAC,cAAc,CAAC,EAAE,EAAE,EAAE,kBAAkB,EAAE,CAAC,CAAC,CAAC,CAAC;YACnE,OAAO,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;QAEH,MAAM,SAAS,GAAG,MAAM,UAAU,CAAC,QAAQ,CAAC,eAAe,EAAE,CAAC,CAAC;QAC/D,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import { of, throwError } from 'rxjs';
|
|
2
|
+
import { v4 as generateGUID } from 'uuid';
|
|
3
|
+
/** Attributed to every bookmark the mock client creates or updates. */
|
|
4
|
+
const mockUser = { id: 'mock-user', name: 'Mock User' };
|
|
5
|
+
/**
|
|
6
|
+
* Strips the `payload` field from a bookmark, mirroring what the real
|
|
7
|
+
* `BookmarkClient` does before returning a {@link BookmarkWithoutData}.
|
|
8
|
+
*
|
|
9
|
+
* @param bookmark - The bookmark to strip.
|
|
10
|
+
* @returns The bookmark without its payload.
|
|
11
|
+
*/
|
|
12
|
+
const stripPayload = (bookmark) => {
|
|
13
|
+
const { payload: _payload, ...rest } = bookmark;
|
|
14
|
+
return rest;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Checks whether a seeded bookmark matches the given {@link BookmarksFilter}.
|
|
18
|
+
*
|
|
19
|
+
* @remarks
|
|
20
|
+
* `appKey`, `contextId`, and `sourceSystem` are checked, mirroring what the real
|
|
21
|
+
* `BookmarkProvider` resolves and passes through as a filter (`BookmarkProvider.getAllBookmarks`
|
|
22
|
+
* always includes `sourceSystem`, so it must be matched even though it's rarely set explicitly).
|
|
23
|
+
*
|
|
24
|
+
* @param bookmark - The seeded bookmark to test.
|
|
25
|
+
* @param filter - The filter to match against, if any.
|
|
26
|
+
* @returns `true` when the bookmark satisfies every constraint in `filter`.
|
|
27
|
+
*/
|
|
28
|
+
const matchesFilter = (bookmark, filter) => {
|
|
29
|
+
// no filter means every seeded bookmark matches
|
|
30
|
+
if (!filter)
|
|
31
|
+
return true;
|
|
32
|
+
// an appKey constraint excludes bookmarks attributed to a different app
|
|
33
|
+
if (filter.appKey && bookmark.appKey !== filter.appKey)
|
|
34
|
+
return false;
|
|
35
|
+
// a contextId constraint excludes bookmarks attributed to a different context
|
|
36
|
+
if (filter.contextId && bookmark.context?.id !== filter.contextId)
|
|
37
|
+
return false;
|
|
38
|
+
// a sourceSystem constraint excludes bookmarks attributed to a different source system
|
|
39
|
+
if (filter.sourceSystem) {
|
|
40
|
+
const { identifier, name, subSystem } = filter.sourceSystem;
|
|
41
|
+
// an identifier constraint excludes bookmarks attributed to a different source system identifier
|
|
42
|
+
if (identifier && bookmark.sourceSystem?.identifier !== identifier)
|
|
43
|
+
return false;
|
|
44
|
+
// a name constraint excludes bookmarks attributed to a different source system name
|
|
45
|
+
if (name !== undefined && bookmark.sourceSystem?.name !== name)
|
|
46
|
+
return false;
|
|
47
|
+
// a subSystem constraint excludes bookmarks attributed to a different source sub-system
|
|
48
|
+
if (subSystem !== undefined && bookmark.sourceSystem?.subSystem !== subSystem)
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
return true;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Runs `fn` synchronously and reports the outcome as an {@link ObservableInput},
|
|
55
|
+
* so a mock method can `throw` for a "not found" case exactly like the async
|
|
56
|
+
* real client would reject.
|
|
57
|
+
*
|
|
58
|
+
* @template T - The value `fn` produces.
|
|
59
|
+
* @param fn - The synchronous operation to run.
|
|
60
|
+
* @returns An observable emitting `fn`'s result, or erroring with what it threw.
|
|
61
|
+
*/
|
|
62
|
+
const resultOf = (fn) => {
|
|
63
|
+
try {
|
|
64
|
+
return of(fn());
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
return throwError(() => error);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* In-memory {@link IBookmarkClient} backed by a `Map` of seeded bookmarks and a
|
|
72
|
+
* `Set` of favorite ids.
|
|
73
|
+
*
|
|
74
|
+
* @remarks
|
|
75
|
+
* Used by {@link BookmarkMockConfigurator} to swap out the real API client
|
|
76
|
+
* while leaving `BookmarkProvider` and the `bookmark-flows/` epics running
|
|
77
|
+
* unmodified — every create, update, delete, and favorite call still goes
|
|
78
|
+
* through the real flow logic, only the underlying data source is in-memory.
|
|
79
|
+
*/
|
|
80
|
+
export class BookmarkMockClient {
|
|
81
|
+
#bookmarks = new Map();
|
|
82
|
+
#favorites = new Set();
|
|
83
|
+
/**
|
|
84
|
+
* Replaces the seeded bookmarks with the given collection, keyed by `id`.
|
|
85
|
+
*
|
|
86
|
+
* @param items - The bookmarks to seed. Replaces any previously seeded bookmarks.
|
|
87
|
+
*/
|
|
88
|
+
setBookmarks(items) {
|
|
89
|
+
this.#bookmarks = new Map(Array.from(items, (item) => [item.id, item]));
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Marks a seeded bookmark as a favorite, or clears it.
|
|
93
|
+
*
|
|
94
|
+
* @param bookmarkId - The id of the bookmark to update.
|
|
95
|
+
* @param isFavorite - `true` to favorite the bookmark, `false` to clear it.
|
|
96
|
+
*/
|
|
97
|
+
setFavorite(bookmarkId, isFavorite) {
|
|
98
|
+
// track favorites as a set membership rather than a boolean field on the bookmark
|
|
99
|
+
if (isFavorite) {
|
|
100
|
+
this.#favorites.add(bookmarkId);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
this.#favorites.delete(bookmarkId);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Looks up a seeded bookmark by id without going through the `ObservableInput` API.
|
|
108
|
+
*
|
|
109
|
+
* @param bookmarkId - The id of the bookmark to look up.
|
|
110
|
+
* @returns The seeded bookmark, or `undefined` when no bookmark was seeded for that id.
|
|
111
|
+
*/
|
|
112
|
+
getBookmark(bookmarkId) {
|
|
113
|
+
return this.#bookmarks.get(bookmarkId);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Looks up a seeded bookmark by id, throwing when none was seeded.
|
|
117
|
+
*
|
|
118
|
+
* @param bookmarkId - The id of the bookmark to look up.
|
|
119
|
+
* @returns The seeded bookmark.
|
|
120
|
+
* @throws {Error} When no bookmark was seeded for `bookmarkId`.
|
|
121
|
+
*/
|
|
122
|
+
#requireBookmark(bookmarkId) {
|
|
123
|
+
const bookmark = this.#bookmarks.get(bookmarkId);
|
|
124
|
+
// fail loudly so a missing seed reads as a test setup bug, not a silent no-op
|
|
125
|
+
if (!bookmark) {
|
|
126
|
+
throw new Error(`BookmarkMockClient: no bookmark seeded for id '${bookmarkId}'`);
|
|
127
|
+
}
|
|
128
|
+
return bookmark;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Returns every seeded bookmark that matches `filter`, without its payload.
|
|
132
|
+
*
|
|
133
|
+
* @remarks
|
|
134
|
+
* The real client strips payloads from list results (see `BookmarkClient.getAllBookmarks`),
|
|
135
|
+
* so the mock does the same here even though the interface's declared return type is `Bookmark[]`.
|
|
136
|
+
*
|
|
137
|
+
* @param filter - Optional constraints to narrow the returned bookmarks.
|
|
138
|
+
* @returns The matching bookmarks, without their payloads.
|
|
139
|
+
*/
|
|
140
|
+
getAllBookmarks(filter) {
|
|
141
|
+
return resultOf(() => Array.from(this.#bookmarks.values())
|
|
142
|
+
// only bookmarks matching every constraint in `filter` are returned
|
|
143
|
+
.filter((bookmark) => matchesFilter(bookmark, filter))
|
|
144
|
+
// list results never include payloads, mirroring the real client
|
|
145
|
+
.map(stripPayload));
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Returns a seeded bookmark by id, without its payload.
|
|
149
|
+
*
|
|
150
|
+
* @param bookmarkId - The id of the bookmark to look up.
|
|
151
|
+
* @returns The bookmark without its payload.
|
|
152
|
+
* @throws {Error} When no bookmark was seeded for `bookmarkId`.
|
|
153
|
+
*/
|
|
154
|
+
getBookmarkById(bookmarkId) {
|
|
155
|
+
return resultOf(() => stripPayload(this.#requireBookmark(bookmarkId)));
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Returns the payload data of a seeded bookmark.
|
|
159
|
+
*
|
|
160
|
+
* @template T - The shape of the bookmark's payload.
|
|
161
|
+
* @param bookmarkId - The id of the bookmark to look up.
|
|
162
|
+
* @returns The bookmark's payload.
|
|
163
|
+
* @throws {Error} When no bookmark was seeded for `bookmarkId`.
|
|
164
|
+
*/
|
|
165
|
+
getBookmarkData(bookmarkId) {
|
|
166
|
+
return resultOf(() => this.#requireBookmark(bookmarkId).payload);
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Replaces the payload data of a seeded bookmark.
|
|
170
|
+
*
|
|
171
|
+
* @template T - The shape of the bookmark's payload.
|
|
172
|
+
* @param bookmarkId - The id of the bookmark to update.
|
|
173
|
+
* @param data - The new payload data.
|
|
174
|
+
* @returns The payload that was set.
|
|
175
|
+
* @throws {Error} When no bookmark was seeded for `bookmarkId`.
|
|
176
|
+
*/
|
|
177
|
+
setBookmarkData(bookmarkId, data) {
|
|
178
|
+
return resultOf(() => {
|
|
179
|
+
const existing = this.#requireBookmark(bookmarkId);
|
|
180
|
+
this.#bookmarks.set(bookmarkId, { ...existing, payload: data ?? undefined });
|
|
181
|
+
return data;
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Marks a seeded bookmark as a favorite.
|
|
186
|
+
*
|
|
187
|
+
* @param bookmarkId - The id of the bookmark to favorite.
|
|
188
|
+
* @returns `true` once the bookmark is marked as a favorite.
|
|
189
|
+
* @throws {Error} When no bookmark was seeded for `bookmarkId`.
|
|
190
|
+
*/
|
|
191
|
+
addBookmarkToFavorites(bookmarkId) {
|
|
192
|
+
return resultOf(() => {
|
|
193
|
+
this.#requireBookmark(bookmarkId);
|
|
194
|
+
this.#favorites.add(bookmarkId);
|
|
195
|
+
return true;
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Clears a seeded bookmark's favorite status.
|
|
200
|
+
*
|
|
201
|
+
* @param bookmarkId - The id of the bookmark to unfavorite.
|
|
202
|
+
* @returns `true` once the bookmark is no longer a favorite.
|
|
203
|
+
*/
|
|
204
|
+
removeBookmarkFromFavorites(bookmarkId) {
|
|
205
|
+
return resultOf(() => {
|
|
206
|
+
this.#favorites.delete(bookmarkId);
|
|
207
|
+
return true;
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Checks whether a seeded bookmark is currently a favorite.
|
|
212
|
+
*
|
|
213
|
+
* @param bookmarkId - The id of the bookmark to check.
|
|
214
|
+
* @returns `true` when the bookmark is a favorite.
|
|
215
|
+
*/
|
|
216
|
+
isBookmarkFavorite(bookmarkId) {
|
|
217
|
+
return of(this.#favorites.has(bookmarkId));
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Seeds a new bookmark from create input, generating its id and audit fields.
|
|
221
|
+
*
|
|
222
|
+
* @template T - The shape of the bookmark's payload.
|
|
223
|
+
* @param bookmark - The data to create the bookmark from.
|
|
224
|
+
* @returns The created bookmark.
|
|
225
|
+
*/
|
|
226
|
+
createBookmark(bookmark) {
|
|
227
|
+
return resultOf(() => {
|
|
228
|
+
// `contextId` is a plain id on the client input, but a `{ id }` object on the bookmark itself
|
|
229
|
+
const { contextId, ...rest } = bookmark;
|
|
230
|
+
// merge the create input with generated audit fields and a normalized context
|
|
231
|
+
const created = {
|
|
232
|
+
...rest,
|
|
233
|
+
id: generateGUID(),
|
|
234
|
+
created: new Date(),
|
|
235
|
+
createdBy: mockUser,
|
|
236
|
+
...(contextId ? { context: { id: contextId } } : {}),
|
|
237
|
+
};
|
|
238
|
+
this.#bookmarks.set(created.id, created);
|
|
239
|
+
return created;
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Applies updates to a seeded bookmark, stamping new audit fields.
|
|
244
|
+
*
|
|
245
|
+
* @template T - The shape of the bookmark's payload.
|
|
246
|
+
* @param bookmarkId - The id of the bookmark to update.
|
|
247
|
+
* @param updates - The fields to update.
|
|
248
|
+
* @returns The updated bookmark.
|
|
249
|
+
* @throws {Error} When no bookmark was seeded for `bookmarkId`.
|
|
250
|
+
*/
|
|
251
|
+
updateBookmark(bookmarkId, updates) {
|
|
252
|
+
return resultOf(() => {
|
|
253
|
+
const existing = this.#requireBookmark(bookmarkId);
|
|
254
|
+
// merge the updates onto the existing bookmark, then stamp new audit fields
|
|
255
|
+
const updated = {
|
|
256
|
+
...existing,
|
|
257
|
+
...updates,
|
|
258
|
+
// `payload: null` clears data on a BookmarkUpdate, so normalize it to `undefined` like setBookmarkData does
|
|
259
|
+
payload: updates.payload === null ? undefined : (updates.payload ?? existing.payload),
|
|
260
|
+
updated: new Date(),
|
|
261
|
+
updatedBy: mockUser,
|
|
262
|
+
};
|
|
263
|
+
this.#bookmarks.set(bookmarkId, updated);
|
|
264
|
+
return updated;
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Removes a seeded bookmark and clears its favorite status.
|
|
269
|
+
*
|
|
270
|
+
* @param bookmarkId - The id of the bookmark to delete.
|
|
271
|
+
* @returns `true` when a bookmark was seeded for `bookmarkId` and was removed.
|
|
272
|
+
*/
|
|
273
|
+
deleteBookmark(bookmarkId) {
|
|
274
|
+
return resultOf(() => {
|
|
275
|
+
const existed = this.#bookmarks.delete(bookmarkId);
|
|
276
|
+
this.#favorites.delete(bookmarkId);
|
|
277
|
+
return existed;
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
//# sourceMappingURL=BookmarkMockClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BookmarkMockClient.js","sourceRoot":"","sources":["../../../src/mock/BookmarkMockClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,UAAU,EAAwB,MAAM,MAAM,CAAC;AAC5D,OAAO,EAAE,EAAE,IAAI,YAAY,EAAE,MAAM,MAAM,CAAC;AAU1C,uEAAuE;AACvE,MAAM,QAAQ,GAAiB,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;AAEtE;;;;;;GAMG;AACH,MAAM,YAAY,GAAG,CAAC,QAAkB,EAAuB,EAAE;IAC/D,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,GAAG,QAAQ,CAAC;IAChD,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,aAAa,GAAG,CAAC,QAAkB,EAAE,MAAwB,EAAW,EAAE;IAC9E,gDAAgD;IAChD,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACzB,wEAAwE;IACxE,IAAI,MAAM,CAAC,MAAM,IAAI,QAAQ,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IACrE,8EAA8E;IAC9E,IAAI,MAAM,CAAC,SAAS,IAAI,QAAQ,CAAC,OAAO,EAAE,EAAE,KAAK,MAAM,CAAC,SAAS;QAAE,OAAO,KAAK,CAAC;IAChF,uFAAuF;IACvF,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;QACxB,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC,YAAY,CAAC;QAC5D,iGAAiG;QACjG,IAAI,UAAU,IAAI,QAAQ,CAAC,YAAY,EAAE,UAAU,KAAK,UAAU;YAAE,OAAO,KAAK,CAAC;QACjF,oFAAoF;QACpF,IAAI,IAAI,KAAK,SAAS,IAAI,QAAQ,CAAC,YAAY,EAAE,IAAI,KAAK,IAAI;YAAE,OAAO,KAAK,CAAC;QAC7E,wFAAwF;QACxF,IAAI,SAAS,KAAK,SAAS,IAAI,QAAQ,CAAC,YAAY,EAAE,SAAS,KAAK,SAAS;YAAE,OAAO,KAAK,CAAC;IAC9F,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,QAAQ,GAAG,CAAI,EAAW,EAAsB,EAAE;IACtD,IAAI,CAAC;QACH,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;IAClB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,UAAU,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC;AACH,CAAC,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,OAAO,kBAAkB;IAC7B,UAAU,GAAG,IAAI,GAAG,EAAoB,CAAC;IACzC,UAAU,GAAG,IAAI,GAAG,EAAU,CAAC;IAE/B;;;;OAIG;IACI,YAAY,CAAC,KAAyB;QAC3C,IAAI,CAAC,UAAU,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IAC1E,CAAC;IAED;;;;;OAKG;IACI,WAAW,CAAC,UAAkB,EAAE,UAAmB;QACxD,kFAAkF;QAClF,IAAI,UAAU,EAAE,CAAC;YACf,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAClC,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QACrC,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACI,WAAW,CAAC,UAAkB;QACnC,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACzC,CAAC;IAED;;;;;;OAMG;IACH,gBAAgB,CAAC,UAAkB;QACjC,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACjD,8EAA8E;QAC9E,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CAAC,kDAAkD,UAAU,GAAG,CAAC,CAAC;QACnF,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED;;;;;;;;;OASG;IACI,eAAe,CAAC,MAAwB;QAC7C,OAAO,QAAQ,CACb,GAAG,EAAE,CACH,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC;YAClC,oEAAoE;aACnE,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;YACtD,iEAAiE;aAChE,GAAG,CAAC,YAAY,CAAoB,CAC1C,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACI,eAAe,CAAC,UAAkB;QACvC,OAAO,QAAQ,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IACzE,CAAC;IAED;;;;;;;OAOG;IACI,eAAe,CAAyB,UAAkB;QAC/D,OAAO,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC,OAAY,CAAC,CAAC;IACxE,CAAC;IAED;;;;;;;;OAQG;IACI,eAAe,CACpB,UAAkB,EAClB,IAAO;QAEP,OAAO,QAAQ,CAAC,GAAG,EAAE;YACnB,MAAM,QAAQ,GAAG,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC;YACnD,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,UAAU,EAAE,EAAE,GAAG,QAAQ,EAAE,OAAO,EAAE,IAAI,IAAI,SAAS,EAAE,CAAC,CAAC;YAC7E,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;;OAMG;IACI,sBAAsB,CAAC,UAAkB;QAC9C,OAAO,QAAQ,CAAC,GAAG,EAAE;YACnB,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC;YAClC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;YAChC,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;OAKG;IACI,2BAA2B,CAAC,UAAkB;QACnD,OAAO,QAAQ,CAAC,GAAG,EAAE;YACnB,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YACnC,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;OAKG;IACI,kBAAkB,CAAC,UAAkB;QAC1C,OAAO,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC;IAC7C,CAAC;IAED;;;;;;OAMG;IACI,cAAc,CACnB,QAAwB;QAExB,OAAO,QAAQ,CAAC,GAAG,EAAE;YACnB,8FAA8F;YAC9F,MAAM,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,GAAG,QAAQ,CAAC;YACxC,8EAA8E;YAC9E,MAAM,OAAO,GAAgB;gBAC3B,GAAG,IAAI;gBACP,EAAE,EAAE,YAAY,EAAE;gBAClB,OAAO,EAAE,IAAI,IAAI,EAAE;gBACnB,SAAS,EAAE,QAAQ;gBACnB,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACrD,CAAC;YACF,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YACzC,OAAO,OAAO,CAAC;QACjB,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;;OAQG;IACI,cAAc,CACnB,UAAkB,EAClB,OAA0B;QAE1B,OAAO,QAAQ,CAAC,GAAG,EAAE;YACnB,MAAM,QAAQ,GAAG,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC;YACnD,4EAA4E;YAC5E,MAAM,OAAO,GAAgB;gBAC3B,GAAG,QAAQ;gBACX,GAAG,OAAO;gBACV,4GAA4G;gBAC5G,OAAO,EAAE,OAAO,CAAC,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,IAAI,QAAQ,CAAC,OAAO,CAAC;gBACrF,OAAO,EAAE,IAAI,IAAI,EAAE;gBACnB,SAAS,EAAE,QAAQ;aACL,CAAC;YACjB,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YACzC,OAAO,OAAO,CAAC;QACjB,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;OAKG;IACI,cAAc,CAAC,UAAkB;QACtC,OAAO,QAAQ,CAAC,GAAG,EAAE;YACnB,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YACnD,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YACnC,OAAO,OAAO,CAAC;QACjB,CAAC,CAAC,CAAC;IACL,CAAC;CACF"}
|