From 0c1e727ac30b59dd45e7f17a1533ad8be0684984 Mon Sep 17 00:00:00 2001 From: Philippe Clesca Date: Tue, 5 Sep 2023 11:50:55 -0400 Subject: [PATCH 01/12] internal systems overhaul init --- .trunk/trunk.yaml | 2 +- docs/docs/api-reference/batch.mdx | 2 +- .../plexus-core/src/collection/collection.ts | 57 +++++++++----- packages/plexus-core/src/instance/engine.ts | 16 ++-- packages/plexus-core/src/instance/runtime.ts | 68 ++++++++++------- packages/plexus-core/src/storage.ts | 1 + packages/tsconfig.shared.json | 3 +- tests/api.test.ts | 1 + tests/basic.test.ts | 21 ++++-- tests/computed.test.ts | 14 +++- tests/controller.test.ts | 2 +- tests/efficiency.test.ts | 75 +++++++++++-------- tests/scope.test.ts | 2 +- tests/state.test.ts | 31 ++++---- tests/test-utils.tsx | 32 ++++---- 15 files changed, 202 insertions(+), 125 deletions(-) diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index 4dd9df70..264c59a4 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -1,6 +1,6 @@ version: 0.1 cli: - version: 1.14.0 + version: 1.14.2 plugins: sources: - id: trunk diff --git a/docs/docs/api-reference/batch.mdx b/docs/docs/api-reference/batch.mdx index 6f1d9fae..9c236338 100644 --- a/docs/docs/api-reference/batch.mdx +++ b/docs/docs/api-reference/batch.mdx @@ -29,7 +29,7 @@ Run a function. During that function's execution, any state changes will be batc ## .batch(fn) -

The batch function allows you to run a series of actions in a single transaction

+

The batch function allows you to run a series of reactive actions in a single transaction

| Param | Type | Description | diff --git a/packages/plexus-core/src/collection/collection.ts b/packages/plexus-core/src/collection/collection.ts index 9ee05409..7dbc3590 100644 --- a/packages/plexus-core/src/collection/collection.ts +++ b/packages/plexus-core/src/collection/collection.ts @@ -305,7 +305,7 @@ export class CollectionInstance< return Array.from(addedKeys.values()) } const collectFn = ( - data_: typeof data, + dataToCollect: typeof data, groups?: KeyOfMap[] | KeyOfMap, startedFromInnerBatch?: boolean ) => { @@ -325,13 +325,13 @@ export class CollectionInstance< 'debug', `Batched collect call fulfilled for collection ${this.instanceId}` ) - return collectFn(data_, groups, true) + return collectFn(dataToCollect, groups, true) }) return this } const addedKeys: any[] = collectItems( - Array.isArray(data_) ? data_ : [data_] + Array.isArray(dataToCollect) ? dataToCollect : [dataToCollect] ) const defaultGroupName = @@ -355,12 +355,19 @@ export class CollectionInstance< } this._internalStore._internalCalledGroupCollect = false } + // we only need to call back if the instance is not batching if (this.config.useBatching) { + // this.instance().runtime.startBatching() this.instance().runtime.batch(() => collectFn(data, groups)) } else { collectFn(data, groups) } + + // if (this.config.useBatching) { + // this.instance().runtime.endBatching() + // } + this.mount() return this } @@ -788,10 +795,29 @@ export class CollectionInstance< this._internalStore._data.delete(key) } // if an array, iterate through the keys and remove them each - if (Array.isArray(keys)) { - keys.forEach(rm) - } else { - rm(keys) + keys = Array.isArray(keys) ? keys : [keys] + + // if the instance is batching and this collection has batching enabled, add this action to the batchedSetters + if ( + // this.instance().runtime.isBatching && + this.config.useBatching + ) { + this.instance().runtime.log( + 'debug', + `Batching an delete call for collection ${this.instanceId}` + ) + this.instance().runtime.startBatching() + } + // run this remove call + for (const key of keys) { + rm(key) + } + if (this.config.useBatching) { + this.instance().runtime.endBatching() + this.instance().runtime.log( + 'debug', + `Batched delete call fulfilled for collection ${this.instanceId}` + ) } this.mount() return this @@ -836,10 +862,9 @@ export class CollectionInstance< } // if an array, iterate through the keys and remove them from each associated group - if (Array.isArray(keys)) { - keys.forEach(rm) - } else { - rm(keys) + keys = Array.isArray(keys) ? keys : [keys] + for (let key of keys) { + rm(key) } return this // ! This is commented out because the user may still want to keep the data in the collection. If they want to completely delete the data, they should use `.delete()` @@ -856,13 +881,9 @@ export class CollectionInstance< clear(groupNames?: KeyOfMap | KeyOfMap[]): this { // this means we want to clear a group, not the whole collection if (groupNames) { - if (Array.isArray(groupNames)) { - groupNames.forEach( - (groupName) => - this.isCreatedGroup(groupName) && this.getGroup(groupName).clear() - ) - } else { - this.isCreatedGroup(groupNames) && this.getGroup(groupNames).clear() + groupNames = Array.isArray(groupNames) ? groupNames : [groupNames] + for (const groupName of groupNames) { + this.isCreatedGroup(groupName) && this.getGroup(groupName).clear() } } else { this.delete(Array.from(this._internalStore._data.keys())) diff --git a/packages/plexus-core/src/instance/engine.ts b/packages/plexus-core/src/instance/engine.ts index 35af1b31..38d15ba0 100644 --- a/packages/plexus-core/src/instance/engine.ts +++ b/packages/plexus-core/src/instance/engine.ts @@ -20,13 +20,19 @@ export class EventEngine { halt() { this.batching = true return () => { - this.batching = false - this.pendingEventPayloads.forEach((args, eventId) => { - this.emit(eventId, args) - }) - this.pendingEventPayloads.clear() + this.release() } } + /** + * Emit all stored concatenated events and resume normal event emitting. + */ + release() { + this.batching = false + this.pendingEventPayloads.forEach((args, eventId) => { + this.emit(eventId, args) + }) + this.pendingEventPayloads.clear() + } on(eventId: string, listener: PlexusInternalWatcher, origin?: string) { if (!eventId || eventId === '') { diff --git a/packages/plexus-core/src/instance/runtime.ts b/packages/plexus-core/src/instance/runtime.ts index 0e2156c7..ee51897f 100644 --- a/packages/plexus-core/src/instance/runtime.ts +++ b/packages/plexus-core/src/instance/runtime.ts @@ -213,7 +213,7 @@ export class RuntimeInstance { } /** - * The batch function allows you to run a series of actions in a single transaction + * The batch function allows you to run a series of reactive actions in a single transaction * @param {Function} fn The function to run */ batch any | Promise>( @@ -227,40 +227,22 @@ export class RuntimeInstance { return fn() } - // hold the reactivity engine and start storing changes - // const unhalt = this.engine.halt() - this.batching = true + this.startBatching() this.instance().runtime.log('info', 'Batch function started!') - const releaseBatch = () => { - // if we aren't batching anymore, just return - if (this.batching === false) { - return - } - // stop storing changes and emit the changes - this.batching = false - // call all the pending functions and clear the array - this.batchedCalls.forEach((pendingFn) => pendingFn()) - this.batchedCalls.length = 0 - - // release the reactivity engine - // unhalt() - - this.instance().runtime.log('info', 'Batch function completed!') - } // run the function. If it returns a promise, wait for it to resolve - const prom = fn() - if (prom instanceof Promise) { + const pendingResponse = fn() + if (pendingResponse instanceof Promise) { return new Promise>(async (resolve, reject) => { // wait for the promise to resolve - const value = await prom + const value = await pendingResponse // release the batch - releaseBatch() + this.endBatching() // resolve the promise, return the value of the promise return resolve(value) }) as ReturnType } - releaseBatch() - return prom + this.endBatching() + return pendingResponse } /** @@ -270,6 +252,40 @@ export class RuntimeInstance { get isBatching() { return this.batching } + + /** + * Release the batch + * @returns {void} + */ + endBatching() { + // if we aren't batching anymore, just return + if (this.batching === false) { + return + } + // stop storing changes and emit the changes + this.batching = false + // call all the pending functions and clear the array + this.batchedCalls.forEach((pendingFn) => pendingFn()) + this.batchedCalls.length = 0 + + // release the reactivity engine + // this.engine.release() + + this.instance().runtime.log('info', 'Batch function completed!') + } + /** + * Begin batching any calls to the runtime + * @private + * @returns {Function(): void} A function to release the batch + */ + startBatching() { + this.batching = true + // hold the reactivity engine and start storing changes + // this.engine.halt() + return () => { + this.endBatching() + } + } } /** * Create a runtime for an instance NOTE: NOT FOR PUBLIC USE diff --git a/packages/plexus-core/src/storage.ts b/packages/plexus-core/src/storage.ts index dd8052f5..b96d51e9 100644 --- a/packages/plexus-core/src/storage.ts +++ b/packages/plexus-core/src/storage.ts @@ -179,6 +179,7 @@ export class StorageInstance { } } + // ! This might be broken? Definitely need to rethink storage procedures sync(checkValue?: any) { this.instance().runtime.log('info', 'Syncing storage...') this._internalStore.tracking.forEach(async (object) => { diff --git a/packages/tsconfig.shared.json b/packages/tsconfig.shared.json index d9c73a41..823161d1 100644 --- a/packages/tsconfig.shared.json +++ b/packages/tsconfig.shared.json @@ -11,6 +11,7 @@ "noImplicitAny": false, "noImplicitThis": true, "skipLibCheck": true, - "esModuleInterop": true + "esModuleInterop": true, + "stripInternal": true } } diff --git a/tests/api.test.ts b/tests/api.test.ts index 253a4597..495615f0 100644 --- a/tests/api.test.ts +++ b/tests/api.test.ts @@ -1,5 +1,6 @@ import { beforeEach, afterEach, describe, test, expect } from 'vitest' import { api, PlexusApi } from '@plexusjs/api' +// only imported here to make sure it works in testing environment (node), not needed by user import 'isomorphic-fetch' // if(globalThis.fetch === undefined) globalThis.fetch = fetch as any as (input: RequestInfo, init?: RequestInit) => Promise; diff --git a/tests/basic.test.ts b/tests/basic.test.ts index 5079473f..096d9b87 100644 --- a/tests/basic.test.ts +++ b/tests/basic.test.ts @@ -2,14 +2,20 @@ import { describe, test } from 'vitest' import { DEFAULT_DECAY_RATE, arrayState, + objectState, + stringState, decayingUsers, myCollection, myCollectionUndefined, - objectState, - stringState, } from './test-utils' import { instance, state } from '@plexusjs/core' +beforeEach(() => { + stringState.reset() + objectState.reset() + arrayState.reset() +}) + describe('Collections Core Functionality', () => { test('Can create collection', () => { expect(myCollection.value.length).toBe(0) @@ -68,19 +74,20 @@ describe('State Core Functionality', () => { test('Checking state().set()', () => { // check .set(value: object) - objectState.set({ a: { b: false } }) + objectState.set({ a: { a2: false } }) // check if the object is actually merged and children props do get overwritten - expect(objectState.value.a?.b).toBe(false) + expect(objectState.value.a?.a2).toBe(false) }) test('Checking state().patch()', () => { + objectState.set({ a: { a1: true, a2: true }, b: true }) // can the object deep merge? - objectState.patch({ a: { b: false } }) - expect(objectState.value.a?.a).toBe(true) + objectState.patch({ a: { a2: false } }) + expect(objectState.value.a?.a1).toBe(true) // check that other value is still there expect(objectState.value.b).toBe(true) // changed intended value - expect(objectState.value.a?.b).toBe(false) + expect(objectState.value.a?.a2).toBe(false) // console.log(arrayState.value) // check array deep merge diff --git a/tests/computed.test.ts b/tests/computed.test.ts index 08fa41f3..3f0f54b8 100644 --- a/tests/computed.test.ts +++ b/tests/computed.test.ts @@ -50,7 +50,11 @@ const core = { }, [collections.books.getGroup('all')]), numOfReadingReactiveToAll: computed(() => { - console.log('numOfReadingReactiveToAll compute...') + console.log( + 'numOfReadingReactiveToAll compute...', + collections.books.getGroup('READING').value.length, + collections.books.getGroup('all').value.length + ) return collections.books.getGroup('READING').value.length }, [collections.books.getGroup('all')]), } @@ -129,9 +133,14 @@ describe('Testing Computed State Function', () => { }) test('Computed can watch a default collection group', () => { instance({ logLevel: 'debug' }) + // start watching the reading group collections.books.getGroup('READING')?.watch((v) => { console.log('READING changed to: ', v) }) + collections.books.getGroup('all')?.watch((v) => { + console.log('ALL changed to: ', v) + }) + // start watching the computed state that is watching the reading group core.numOfReadingReactiveToAll.watch((v) => { console.log('numOfReadingReactiveToAll.value changed to: ', v) }) @@ -152,7 +161,8 @@ describe('Testing Computed State Function', () => { core.numOfReadingReactiveToAll.value, core.collections.books.size, core.collections.books.getGroup('READING')?.size, - core.collections.books.getGroup('all')?.size + core.collections.books.getGroup('all')?.size, + core.collections.books.getGroup('all').value ) expect(core.numOfReadingReactiveToAll.value).toBe(0) diff --git a/tests/controller.test.ts b/tests/controller.test.ts index 3050cad8..b4fb42e9 100644 --- a/tests/controller.test.ts +++ b/tests/controller.test.ts @@ -1,4 +1,4 @@ -import { beforeEach, afterEach, describe, test, expect } from 'vitest' +import { beforeEach, afterEach, describe, test, expect, } from 'vitest' import { batchAction, diff --git a/tests/efficiency.test.ts b/tests/efficiency.test.ts index 3ef5c0bd..50154172 100644 --- a/tests/efficiency.test.ts +++ b/tests/efficiency.test.ts @@ -1,6 +1,12 @@ import { beforeEach, afterEach, describe, test, expect } from 'vitest' // import { collection, PlexusCollectionInstance } from '@plexusjs/core' -import { Appointment, appointments, User, usersLite, users } from './test-utils' +import { + AppointmentType, + appointments, + UserType, + usersLite, + users, +} from './test-utils' import { randFirstName, @@ -25,7 +31,7 @@ const users1kRelated = Array.from( id: randUuid(), firstName: randFirstName(), appointmentId: randUuid(), - } as User) + } as UserType) ) const appointments1kRelated = users1kRelated.map( @@ -35,7 +41,7 @@ const appointments1kRelated = users1kRelated.map( userId: user.id, date: randFutureDate().getTime(), name: randBook().title, - } as Appointment) + } as AppointmentType) ) // check the .cache directory for the generated data. If it doesn't exist, it will be generated. Need users1k.json, users10k.json, users10kRelated.json, appointments10kRelated.json @@ -52,39 +58,46 @@ afterEach(() => { describe('Efficiency tests for ', () => { test('The speed of a plexus collection collecting more than a thousand randomly generated objects into multiple groups', () => { - instance({ logLevel: 'debug' }) + instance({ logLevel: 'warn' }) console.log('Starting test...') - console.log('items in collection:', users1k.length) + console.log(`${users1k.length} items being adding to collection`) + + usersLite?.watchGroup('firstNames', (v) => { + console.log('items in Collection updated:', v.length) + }) usersLite.collect(users1k, ['firstNames']) console.log('items in collection:', usersLite.value.length) expect(usersLite.value.length).toBe(1000) + console.log( + 'items in firstNames group:', + usersLite.getGroup('firstNames').value + ) expect(usersLite.groups.firstNames.value.length).toBe(1000) - - instance({ logLevel: undefined }) - }) - test('Testing the same as above but with an absurd amount of data', () => { - instance({ logLevel: 'debug' }) - console.log('Starting test...') - console.log('items in collection:', users10k.length) - usersLite.collect(users10k, ['firstNames']) - console.log('items in collection:', usersLite.value.length) - // const group1 = collectionInstance.group('appointmentId') - // const group2 = collectionInstance.group('name') - // expect(group1.value.length).toBe(1000) - // expect(group2.value.length).toBe(1000) - instance({ logLevel: undefined }) - }) - test('An absurd amount of related data', () => { - instance({ logLevel: 'debug' }) - console.log('Starting test...') - console.log('items in collection:', users10k.length) - users.collect(users1kRelated, ['main']) - appointments.collect(appointments1kRelated, ['main']) - console.log('items in collection:', users.value.length) - // const group1 = collectionInstance.group('appointmentId') - // const group2 = collectionInstance.group('name') - // expect(group1.value.length).toBe(1000) - // expect(group2.value.length).toBe(1000) instance({ logLevel: undefined }) }) + // test('Testing the same as above but with an absurd amount of data', () => { + // instance({ logLevel: 'debug' }) + // console.log('Starting test...') + // console.log('items in collection:', users10k.length) + // usersLite.collect(users10k, ['firstNames']) + // console.log('items in collection:', usersLite.value.length) + // // const group1 = collectionInstance.group('appointmentId') + // // const group2 = collectionInstance.group('name') + // // expect(group1.value.length).toBe(1000) + // // expect(group2.value.length).toBe(1000) + // instance({ logLevel: undefined }) + // }) + // test('An absurd amount of related data', () => { + // instance({ logLevel: 'debug' }) + // console.log('Starting test...') + // console.log('items in collection:', users10k.length) + // users.collect(users1kRelated, ['main']) + // appointments.collect(appointments1kRelated, ['main']) + // console.log('items in collection:', users.value.length) + // // const group1 = collectionInstance.group('appointmentId') + // // const group2 = collectionInstance.group('name') + // // expect(group1.value.length).toBe(1000) + // // expect(group2.value.length).toBe(1000) + // instance({ logLevel: undefined }) + // }) }) diff --git a/tests/scope.test.ts b/tests/scope.test.ts index f115ca50..4d7b8948 100644 --- a/tests/scope.test.ts +++ b/tests/scope.test.ts @@ -1,5 +1,5 @@ import { beforeEach, afterEach, describe, test, expect } from 'vitest' -import { appointments, UserLite, usersLite } from './test-utils' +import { appointments, UserLiteType, usersLite } from './test-utils' import { randFirstName, randUuid } from '@ngneat/falso' import { instance, scope } from '@plexusjs/core' diff --git a/tests/state.test.ts b/tests/state.test.ts index 0907c4ea..a48e426e 100644 --- a/tests/state.test.ts +++ b/tests/state.test.ts @@ -2,15 +2,14 @@ import { beforeEach, afterEach, describe, test, expect } from 'vitest' import { instance, state } from '@plexusjs/core' import { + initialStateValues, + stateWithFetchFnTest, arrayState, booleanState, - initialStateValues, objectState, - stateWithFetchFnTest, stringState, } from './test-utils' -// TODO Disallow null as initial value beforeEach(() => { booleanState.reset() stringState.reset() @@ -39,30 +38,30 @@ describe('Testing State Function', () => { test('Checking state nextValue', () => { // check .set(value: object) - objectState.set({ a: { b: false } }) - objectState.nextValue = { a: { b: true } } + objectState.set({ a: { a2: false } }) + objectState.nextValue = { a: { a2: true } } // check if the object is actually merged and children props do get overwritten - expect(objectState.value.a?.b).toBe(false) + expect(objectState.value.a?.a2).toBe(false) objectState.set() - expect(objectState.value.a?.b).toBe(true) + expect(objectState.value.a?.a2).toBe(true) console.log(objectState.value, objectState.nextValue) expect(objectState.nextValue).toStrictEqual(objectState.value) }) test('Checking state.reset()', () => { // check .set(value: object) - objectState.set({ a: { b: false } }) + objectState.set({ a: { a2: false } }) objectState.reset() // check if the object is actually merged and children props do get overwritten - expect(objectState.value.a?.b).toBe(true) + expect(objectState.value.a?.a2).toBe(true) }) test('Checking state.undo() & state.redo()', () => { - objectState.set({ a: { b: false } }) + objectState.set({ a: { a2: false } }) objectState.undo() expect(objectState.value).toStrictEqual(initialStateValues.object) objectState.redo() - expect(objectState.value).toStrictEqual({ a: { b: false } }) + expect(objectState.value).toStrictEqual({ a: { a2: false } }) }) test('Checking state history functionality', () => { @@ -70,9 +69,9 @@ describe('Testing State Function', () => { console.log('Got an update from history change!') }) objectState.history() - objectState.set({ a: { b: false } }) - console.log('1: checking', objectState.value, 'vs.', { a: { b: false } }) - expect(objectState.value).toStrictEqual({ a: { b: false } }) + objectState.set({ a: { a2: false } }) + console.log('1: checking', objectState.value, 'vs.', { a: { a2: false } }) + expect(objectState.value).toStrictEqual({ a: { a2: false } }) objectState.undo() console.log( '2: checking', @@ -82,8 +81,8 @@ describe('Testing State Function', () => { ) expect(objectState.value).toStrictEqual(initialStateValues.object) objectState.redo() - console.log('3: checking', objectState.value, 'vs.', { a: { b: false } }) - expect(objectState.value).toStrictEqual({ a: { b: false } }) + console.log('3: checking', objectState.value, 'vs.', { a: { a2: false } }) + expect(objectState.value).toStrictEqual({ a: { a2: false } }) // checking if the history is working for primitives stringState.history() diff --git a/tests/test-utils.tsx b/tests/test-utils.tsx index e468d97f..fa50fc53 100644 --- a/tests/test-utils.tsx +++ b/tests/test-utils.tsx @@ -2,6 +2,8 @@ import React, { ReactElement } from 'react' import { render, RenderOptions } from '@testing-library/react' import { collection } from '@plexusjs/core' import { state } from '@plexusjs/core' +// re-export everything +export * from '@testing-library/react' const AllTheProviders = ({ children }) => { return <>{children} @@ -12,33 +14,31 @@ const customRender = ( options?: Omit ) => render(ui, { wrapper: AllTheProviders, ...options }) -// re-export everything -export * from '@testing-library/react' // override render method export { customRender as render } -export type User = { +export type UserType = { id: string firstName: string appointmentId: string } -export type UserLite = { +export type UserLiteType = { id: string firstName: string } -export type UserLiteExplicitIdName = { +export type UserLiteExplicitIdNameType = { userId: string firstName: string } -export type Appointment = { +export type AppointmentType = { id: string name: string date: number userId: string } -export type ObjectStateExample = Partial<{ - a: { a?: boolean; b?: boolean } +export type ComplexObjectType = Partial<{ + a: { a1?: boolean; a2?: boolean } b: boolean c: { b?: boolean } }> @@ -47,17 +47,18 @@ export type ObjectStateExample = Partial<{ export const initialStateValues = { boolean: true, string: 'Hello Plexus!', - object: { a: { a: true, b: true }, b: true }, + object: { a: { a1: true, a2: true }, b: true }, array: [ { item: 'Hello', item2: { subitem: 'World' } }, { item: 'Goodbye', item2: { subitem: 'People' } }, ], null: null, } + export const booleanState = state(true) export const stringState = state('Hello Plexus!') export const stringStateStartingWithNull = state(null) -export const objectState = state(initialStateValues.object) +export const objectState = state(initialStateValues.object) export const arrayState = state<{ item?: string; item2?: { subitem?: string } }[]>( initialStateValues.array ) @@ -65,7 +66,7 @@ export const arrayState = state<{ item?: string; item2?: { subitem?: string } }[ export const stateWithFetchFnTest = state(() => { return 'some sort of data' }) -export const users = collection({ +export const users = collection({ primaryKey: 'id', name: 'users', foreignKeys: { @@ -76,12 +77,13 @@ export const users = collection({ }, }).createSelector('batched') -export const usersLite = collection({ +export const usersLite = collection({ primaryKey: 'id', name: 'userslite', + defaultGroup: 'all', }).createSelector('batched') -export const uniqueGroups = collection({ +export const uniqueGroups = collection({ primaryKey: 'userId', name: 'userslite', defaultGroup: 'upcoming', @@ -89,7 +91,7 @@ export const uniqueGroups = collection({ }).createSelector('batched') export const DEFAULT_DECAY_RATE = 12_000 -export const decayingUsers = collection({ +export const decayingUsers = collection({ primaryKey: 'userId', name: 'userslite', defaultGroup: 'upcoming', @@ -97,7 +99,7 @@ export const decayingUsers = collection({ decay: DEFAULT_DECAY_RATE }).createSelector('batched') -export const appointments = collection({ +export const appointments = collection({ primaryKey: 'id', name: 'appointments', defaultGroup: 'upcoming', From 4f01727c5a3c31ce425ec8d3fe090829971b25ad Mon Sep 17 00:00:00 2001 From: Philippe Clesca Date: Thu, 7 Sep 2023 23:16:52 -0400 Subject: [PATCH 02/12] idk, --- .../api-reference/PlexusActionHelpers.mdx | 14 - docs/docs/api-reference/batch.mdx | 4 +- docs/docs/api-reference/onCatch.mdx | 34 + jest.config.ts | 13 - package.json | 8 +- packages/plexus-core/src/action.ts | 223 +-- .../plexus-core/src/collection/collection.ts | 82 +- packages/plexus-core/src/collection/data.ts | 4 +- packages/plexus-core/src/error.ts | 14 + packages/plexus-core/src/instance/engine.ts | 40 +- packages/plexus-core/src/preaction.ts | 24 +- packages/plexus-utils/src/shared/index.ts | 10 +- tests/action.test.ts | 8 +- tests/edgecases.test.tsx | 126 +- tests/efficiency.test.ts | 84 +- tests/timed.test.ts | 96 +- yarn.lock | 1236 +---------------- 17 files changed, 509 insertions(+), 1511 deletions(-) create mode 100644 docs/docs/api-reference/onCatch.mdx delete mode 100644 jest.config.ts create mode 100644 packages/plexus-core/src/error.ts diff --git a/docs/docs/api-reference/PlexusActionHelpers.mdx b/docs/docs/api-reference/PlexusActionHelpers.mdx index 33ad36d9..fb2cd5f3 100644 --- a/docs/docs/api-reference/PlexusActionHelpers.mdx +++ b/docs/docs/api-reference/PlexusActionHelpers.mdx @@ -12,7 +12,6 @@ The action helpers for a defined plexus action - [.onCatch(handler, useGlobal)](#PlexusActionHelpers+onCatch) - [.runErrorHandlers()](#PlexusActionHelpers+runErrorHandlers) - [.ignoreInit()](#PlexusActionHelpers+ignoreInit) - - [.batch(fn)](#PlexusActionHelpers+batch) @@ -51,16 +50,3 @@ The action helpers for a defined plexus action ### .ignoreInit()

Ignore the default halt for preActions

- - - -### .batch(fn) - -

- Run a function. During that function's execution, any state changes will be - batched and only applied once the function has finished. -

- -| Param | Description | -| ----- | ------------------------------------- | -| fn |

The function to run in a batch

| diff --git a/docs/docs/api-reference/batch.mdx b/docs/docs/api-reference/batch.mdx index 6109cd07..51d6a523 100644 --- a/docs/docs/api-reference/batch.mdx +++ b/docs/docs/api-reference/batch.mdx @@ -19,9 +19,9 @@ Run a function. During that function's execution, any state changes will be batc | ----- | ------------------------------------- | | fn |

The function to run in a batch

| - + -## .batch(fn) +## batch(fn)

Run a function. During that function's execution, any state changes will be diff --git a/docs/docs/api-reference/onCatch.mdx b/docs/docs/api-reference/onCatch.mdx new file mode 100644 index 00000000..cac7262a --- /dev/null +++ b/docs/docs/api-reference/onCatch.mdx @@ -0,0 +1,34 @@ +--- +title: onCatch +--- + +[![view on npm](http://img.shields.io/npm/v/@plexusjs/core.svg)](https://www.npmjs.org/package/@plexusjs/core) + +Add a new error handler for this action. This will catch any errors that occur during the execution of this action and prevent a crash. + + + +## onCatch(handler?) + +

+ Add a new error handler for this action. This will catch any errors that occur + during the execution of this action and prevent a crash. +

+ +| Param | Description | +| -------- | ---------------------------------------------------------------------------------- | +| handler? |

A function that will be called when an error occurs; omit to fail silently.

| + + + +## .onCatch(handler, useGlobal) + +

+ Add a new error handler for this action. This will catch any errors that occur + during the execution of this action and prevent a crash. +

+ +| Param | Default | Description | +| --------- | ----------------- | ---------------------------------------------------------------------------------- | +| handler | |

A function that will be called when an error occurs; omit to fail silently.

| +| useGlobal | true |

Should the global error handler be used? (default: true)

| diff --git a/jest.config.ts b/jest.config.ts deleted file mode 100644 index 50d511c3..00000000 --- a/jest.config.ts +++ /dev/null @@ -1,13 +0,0 @@ -module.exports = { - preset: 'ts-jest', - testEnvironment: 'node', - rootDir: 'tests', - transform: { - '^.+\\.ts?$': 'ts-jest', - }, - globals: { - 'ts-jest': { - tsconfig: 'tsconfig.test.json', - }, - }, -} diff --git a/package.json b/package.json index 837e0701..762c59d5 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "bootstrap": "lerna bootstrap --use-workspaces", "build": "lerna run build", "postbuild": "yarn docs:generate:ref", - "dev": "lerna run build && lerna watch -- lerna run build --since", + "dev": "lerna run build && lerna watch -- lerna run build --scope=$LERNA_PACKAGE_NAME", "prereleaseOnly": "pinst --disable && echo '🚀 Publishing...'", "release-canary": "lerna run build && lerna publish --preid canary --no-private --yes --force-publish --canary", "release-stable": "lerna run build && lerna publish --preid canary --no-private --yes --force-publish", @@ -41,7 +41,6 @@ "@testing-library/react": "^14.0.0", "@trunkio/launcher": "^1.2.3", "@types/fs-readdir-recursive": "^1.1.0", - "@types/jest": "^27.4.0", "@types/jsdoc-to-markdown": "^7.0.3", "@types/node": "^18.11.11", "@types/react": "^18.0.17", @@ -50,11 +49,9 @@ "@types/recursive-readdir": "^2.2.1", "@vitejs/plugin-react": "^4.0.4", "@vitest/ui": "^0.34.2", - "babel-jest": "^27.4.6", "chalk": "4", "fs-readdir-recursive": "^1.1.0", "happy-dom": "^10.10.4", - "jest": "^27.4.7", "jsdoc-babel": "^0.5.0", "jsdoc-to-markdown": "^8.0.0", "jsdom": "^20.0.1", @@ -68,9 +65,8 @@ "react-dom": "^18", "react-test-renderer": "^18.2.0", "recursive-readdir": "^2.2.3", - "ts-jest": "^27.1.2", "ts-node": "^10.9.1", - "typescript": "^5.1.6", + "typescript": "^5.2.2", "vite": "^4.4.9", "vitest": "^0.34.2", "yargs": "^17.4.1" diff --git a/packages/plexus-core/src/action.ts b/packages/plexus-core/src/action.ts index fd141cd6..3a21cadc 100644 --- a/packages/plexus-core/src/action.ts +++ b/packages/plexus-core/src/action.ts @@ -1,4 +1,6 @@ +import { isAsyncFunction } from '@plexusjs/utils' import { PlexusInstance, instance } from './instance/instance' +import { PlexusError } from './error' type ErrorHandler = (error: any) => unknown export interface PlexusActionHooks { @@ -7,9 +9,7 @@ export interface PlexusActionHooks { * Ignore the default hault preActions */ ignoreInit(): void - batch( - fn: () => ReturnType - ): ReturnType | Promise + batch(fn: () => ReturnType): ReturnType } /** * The action helpers for a defined plexus action @@ -66,46 +66,40 @@ class PlexusActionHelpers { this._skipInit = true } - /** - * Run a function. During that function's execution, any state changes will be batched and only applied once the function has finished. - * @param fn The function to run in a batch - */ - batch unknown | Promise>( - fn: BatchFunction - ): ReturnType { - return this.instance().runtime.batch(fn) - } - /** * @internal * Eject the external functions object returned to the user in the first argument of the action function */ get hooks(): PlexusActionHooks { - const onCatch = (handler?: ErrorHandler, useGlobal = true): void => { - return this.onCatch(handler, useGlobal) - } - const ignoreInit = (): void => { - return this.ignoreInit() - } - const batch = ( - batchedActions: () => ReturnType | Promise - ) => { - return this.batch(batchedActions) - } return { /** * Add a new error handler for this action. This will catch any errors that occur during the execution of this action and prevent a crash. * @param handler? A function that will be called when an error occurs; omit to fail silently. * */ - onCatch, - ignoreInit, - batch, + onCatch: (handler?: ErrorHandler, useGlobal = true): void => { + return this.onCatch(handler, useGlobal) + }, + ignoreInit: (): void => { + return this.ignoreInit() + }, + /** + * Run a function. During that function's execution, any state changes will be batched and only applied once the function has finished. + * @param fn The function to run in a batch + */ + batch: (batchFn: () => BatchResponse): BatchResponse => { + return this.instance().runtime.batch(batchFn) + }, } } } -export type FunctionType = (helpers: PlexusActionHooks, ...args: any[]) => any +export type FunctionArgs = [helpers: PlexusActionHooks, ...args: any[]] +export type InnerFunctionArgs = [helpers?: PlexusActionHooks, ...args: any[]] + +export type FunctionType = ( + ...args: FunctionArgs +) => Response | Promise export type InnerFunction = ResultFn extends ( helpers: PlexusActionHooks, @@ -117,72 +111,28 @@ export type InnerFunction = ResultFn extends ( // export type PlexusAction = (fn: FunctionType) => (...args: any) => ReturnData | Promise export type PlexusAction = typeof _action -export function _action( +export function _action( instance: () => PlexusInstance, - fn: Fn, + fn: (...args: FunctionArgs) => Response, + batched?: boolean +): (...args: InnerFunctionArgs) => Response + +export function _action( + instance: () => PlexusInstance, + fn: (...args: FunctionArgs) => Promise, + batched?: boolean +): (...args: InnerFunctionArgs) => Promise + +export function _action( + instance: () => PlexusInstance, + fn: (...args: FunctionArgs) => Promise | Response, batched?: boolean ) { const helpers = new PlexusActionHelpers(instance) - if (fn.constructor.name === 'Function') { - function newAction(...args) { - try { - // if the instance is not ready, wait for it to be - // !NOTE: this is probably not a good way to do this, but it works for now - if (!instance().ready && !helpers._skipInit) { - let hold = true - while (hold) { - instance().runtime.runInit(() => { - hold = false - }) - } - } - // if the action is batched, run it in a batch - if (batched) { - return instance().runtime.batch(() => { - return fn(helpers.hooks, ...args) - }) - } - // run the function - return fn(helpers.hooks, ...args) - } catch (e) { - // only return the error if there is no handler - if (!helpers.catchError && !instance()._globalCatch) throw e - helpers.runErrorHandlers(e) - // otherwise run the handler and return null - return null - } - } - // return the proxy function - return newAction as InnerFunction - // return proxyFn as InnerFunction - } else if (fn.constructor.name === 'AsyncFunction') { - const newAction = async (...args) => { - try { - // if the instance is not ready, wait for it to be - if (!instance().ready && !helpers._skipInit) { - await instance().runtime.runInit() - } - // if the action is batched, run it in a batch - if (batched) { - return instance().runtime.batch(() => { - return fn(helpers.hooks, ...args) - }) - } - // run the function - return await fn(helpers.hooks, ...args) - } catch (e) { - // only return the error if there is no handler - if (!helpers.catchError && !instance()._globalCatch) throw e - helpers.runErrorHandlers(e) - // otherwise run the handler and return null - return null - } - } - // return the proxy function - return newAction as InnerFunction - // return proxyFn as InnerFunction - } else { + console.log('function constructor', fn.constructor.name, isAsyncFunction(fn)) + + if (typeof fn !== 'function') { console.warn( '%cPlexus WARN:%c An action must be of type Function.', 'color: #f00;', @@ -190,6 +140,81 @@ export function _action( ) throw new Error('An action must be of type Function.') } + + function newAction(...args) { + try { + // if the instance is not ready, wait for it to be + // !NOTE: this is probably not a good way to do this, but it works for now + if (!instance().ready && !helpers._skipInit) { + let hold = true + while (hold) { + instance().runtime.runInit(() => { + hold = false + }) + } + } + console.log('hewhewhewhewhewh', batched, args, 'hewhewhewhewhewh') + // if the action is batched, run it in a batch + if (batched) { + return instance().runtime.batch(() => fn(helpers.hooks, ...args)) + } + // run the function + return fn(helpers.hooks, ...args) + } catch (e) { + // only return the error if there is no handler + + if (!helpers.catchError && !instance()._globalCatch) { + if (e instanceof PlexusError) throw e + if (e instanceof Error) { + throw new PlexusError( + `An error occurred during the execution of an action (${e.message})`, + { origin: 'action', stack: e.stack } + ) + } + } + helpers.runErrorHandlers(e) + + // otherwise run the handler and return null + // TODO: return a PlexusError; needs to be a package wide change + return new PlexusError( + 'An error occurred during the execution of an action', + { origin: 'action' } + ) + return + } + } + // return the proxy function + return newAction + // return proxyFn as InnerFunction + + // const newAction = async (...args) => { + // try { + // // if the instance is not ready, wait for it to be + // if (!instance().ready && !helpers._skipInit) { + // await instance().runtime.runInit() + // } + // // if the action is batched, run it in a batch + // console.log('(async)hewhewhewhewhewh', batched, 'hewhewhewhewhewh') + // if (batched) { + // console.log('using a batch in an async action...') + // return instance().runtime.batch(async () => { + // console.log('running the async action in a batch') + // return await fn(helpers.hooks, ...args) + // }) + // } + // // run the function + // return await fn(helpers.hooks, ...args) + // } catch (e) { + // // only return the error if there is no handler + // if (!helpers.catchError && !instance()._globalCatch) throw e + // helpers.runErrorHandlers(e) + // // otherwise run the handler and return null + // return null + // } + // } + // // return the proxy function + // return newAction as InnerFunction + // // return proxyFn as InnerFunction } /** @@ -197,8 +222,14 @@ export function _action( * @param fn The Plexus action function to run * @returns The intended return value of fn, or null if an error is caught */ -export function action(fn: Fn) { - return _action(() => instance(), fn) +export function action(fn: (...args: FunctionArgs) => Response) +export function action( + fn: (...args: FunctionArgs) => Promise +) +export function action( + fn: (...args: FunctionArgs) => Promise | Response +) { + return _action(() => instance(), fn) } /** @@ -206,6 +237,12 @@ export function action(fn: Fn) { * @param fn The Plexus action function to run * @returns The intended return value of fn, or null if an error is caught */ -export function batchAction(fn: Fn) { - return _action(() => instance(), fn, true) +export function batchAction(fn: (...args: FunctionArgs) => Response) +export function batchAction( + fn: (...args: FunctionArgs) => Promise +) +export function batchAction( + fn: (...args: FunctionArgs) => Promise | Response +) { + return _action(() => instance(), fn, true) } diff --git a/packages/plexus-core/src/collection/collection.ts b/packages/plexus-core/src/collection/collection.ts index 69c03739..2642e1f1 100644 --- a/packages/plexus-core/src/collection/collection.ts +++ b/packages/plexus-core/src/collection/collection.ts @@ -310,25 +310,25 @@ export class CollectionInstance< startedFromInnerBatch?: boolean ) => { // if the instance is batching and this collection has batching enabled, add this action to the batchedSetters - if ( - this.instance().runtime.isBatching && - this.config.useBatching && - !startedFromInnerBatch - ) { - this.instance().runtime.log( - 'debug', - `Batching an collect call for collection ${this.instanceId}` - ) - // store this in the batchedSetters for execution once batching is over - this.instance().runtime.batchedCalls.push(() => { - this.instance().runtime.log( - 'debug', - `Batched collect call fulfilled for collection ${this.instanceId}` - ) - return collectFn(dataToCollect, groups, true) - }) - return this - } + // if ( + // this.instance().runtime.isBatching && + // this.config.useBatching && + // !startedFromInnerBatch + // ) { + // this.instance().runtime.log( + // 'debug', + // `Batching an collect call for collection ${this.instanceId}` + // ) + // // store this in the batchedSetters for execution once batching is over + // this.instance().runtime.batchedCalls.push(() => { + // this.instance().runtime.log( + // 'debug', + // `Batched collect call fulfilled for collection ${this.instanceId}` + // ) + // return collectFn(dataToCollect, groups, true) + // }) + // return this + // } const addedKeys: any[] = collectItems( Array.isArray(dataToCollect) ? dataToCollect : [dataToCollect] @@ -348,6 +348,7 @@ export class CollectionInstance< groupsNorm.filter((name) => name !== defaultGroupName) ) } + // if the default group name is truthy, add the item to the default group if (this.config.defaultGroup) { this._internalStore._internalCalledGroupCollect = true // if it is not (undefined or some other string), add to group @@ -357,7 +358,8 @@ export class CollectionInstance< } // we only need to call back if the instance is not batching if (this.config.useBatching) { - this.instance().runtime.batch(() => collectFn(data, groups)) + // this.instance().runtime.batch(() => collectFn(data, groups)) + collectFn(data, groups) } else { collectFn(data, groups) } @@ -686,25 +688,25 @@ export class CollectionInstance< startedFromInnerBatch?: boolean ) => { // if the instance is batching and this collection has batching enabled, add this action to the batchedSetters - if ( - this.instance().runtime.isBatching && - this.config.useBatching && - !startedFromInnerBatch - ) { - this.instance().runtime.log( - 'debug', - `Collection Batching started for addToGroups` - ) - // store this in the batchedSetters for execution once batching is over - this.instance().runtime.batchedCalls.push(() => { - this.instance().runtime.log( - 'debug', - `Collection Batching completed for addToGroups` - ) - return addToGroup(keys, groupName, true) - }) - return this - } + // if ( + // this.instance().runtime.isBatching && + // this.config.useBatching && + // !startedFromInnerBatch + // ) { + // this.instance().runtime.log( + // 'debug', + // `Collection Batching started for addToGroups` + // ) + // // store this in the batchedSetters for execution once batching is over + // this.instance().runtime.batchedCalls.push(() => { + // this.instance().runtime.log( + // 'debug', + // `Collection Batching completed for addToGroups` + // ) + // return addToGroup(keys, groupName, true) + // }) + // return this + // } if (this.config.uniqueGroups && groupName !== this.config.defaultGroup) { for (const key of keys) { const currentGroups = this.getGroupsOf(key, { @@ -836,6 +838,8 @@ export class CollectionInstance< } // if an array, iterate through the keys and remove them from each associated group + // this.instance().runtime.engine.halt() + // const release = this.instance().runtime.engine.halt() this.instance().runtime.batch(() => { for (let key of keys) { rm(key) diff --git a/packages/plexus-core/src/collection/data.ts b/packages/plexus-core/src/collection/data.ts index 54e654b3..7f90341d 100644 --- a/packages/plexus-core/src/collection/data.ts +++ b/packages/plexus-core/src/collection/data.ts @@ -25,7 +25,7 @@ interface PlexusDataStore { } export type PlexusDataInstance< - DataType extends Record = Record + DataType extends Record = Record, > = CollectionData export type DataKey = string @@ -38,7 +38,7 @@ type DataObjectType = Record & { */ export class CollectionData< DataType extends DataObjectType = any, - PK extends string = string + PK extends string = string, > extends WatchableMutable { private primaryKey: PK readonly key: string diff --git a/packages/plexus-core/src/error.ts b/packages/plexus-core/src/error.ts new file mode 100644 index 00000000..86cf47b7 --- /dev/null +++ b/packages/plexus-core/src/error.ts @@ -0,0 +1,14 @@ +export class PlexusError extends Error { + public name = 'PlexusError' + public error = true + constructor( + message: string, + public options?: Partial<{ code: string; origin: string; stack: string }> + ) { + super(message) + } + // custom error format for logging and debugging + toString() { + return `PlexusError: ${this.message} (${this.options?.code ?? 'NO_CODE'})` + } +} diff --git a/packages/plexus-core/src/instance/engine.ts b/packages/plexus-core/src/instance/engine.ts index 5ce875e1..98de0ac4 100644 --- a/packages/plexus-core/src/instance/engine.ts +++ b/packages/plexus-core/src/instance/engine.ts @@ -1,13 +1,15 @@ -import { deepClone, deepMerge } from '@plexusjs/utils' +import { deepMerge } from '@plexusjs/utils' import { PlexusInternalWatcher } from '../types' export interface EngineEventReceiver { from: string listener: PlexusInternalWatcher } + +type EventPayload = { key: String; value: any } export class EventEngine { private batching: boolean = false events: Map> - pendingEventPayloads: Map + pendingEventPayloads: Map constructor() { this.events = new Map() @@ -18,6 +20,7 @@ export class EventEngine { * Pause and store all events until the return function is called. Once called, all events will be emitted. */ halt() { + console.log('halting') this.batching = true return () => this.release() } @@ -26,9 +29,15 @@ export class EventEngine { */ release() { this.batching = false - this.pendingEventPayloads.forEach((args, eventId) => { - this.emit(eventId, args) - }) + if (this.pendingEventPayloads.size === 0) return + // if (this.batching === false) return + Array.from(this.pendingEventPayloads.entries()).forEach( + ([eventId, args]) => { + console.log('releasing', eventId, args) + + this.emit(eventId, args) + } + ) this.pendingEventPayloads.clear() } @@ -89,21 +98,26 @@ export class EventEngine { this.events.delete(eventId) } } - emit(eventId: string, args: any) { + emit(eventId: string, args: EventPayload) { // this.schedule.addTask(() => { // if we're batching, store the event payload if (this.batching) { - this.pendingEventPayloads.set( + const pendingPayload = this.pendingEventPayloads.get(eventId) + + const eventPayload = pendingPayload + ? deepMerge(pendingPayload, args) + : args + console.log( + 'Emit occured while batching enabled', eventId, - deepMerge( - this.pendingEventPayloads.has(eventId) - ? this.pendingEventPayloads.get(eventId) - : args, - args - ) + pendingPayload, + this.events.get(eventId), + eventPayload ) + this.pendingEventPayloads.set(eventId, eventPayload) return } + console.log('Emitting', eventId, args) // run the event listeners for this event id this.events .get(eventId) diff --git a/packages/plexus-core/src/preaction.ts b/packages/plexus-core/src/preaction.ts index da9e4d36..48bc69c7 100644 --- a/packages/plexus-core/src/preaction.ts +++ b/packages/plexus-core/src/preaction.ts @@ -1,12 +1,17 @@ import { PlexusInstance, instance } from './instance/instance' -import { FunctionType, _action } from './action' +import { + FunctionArgs, + FunctionType, + InnerFunctionArgs, + _action, +} from './action' import { genUID } from '@plexusjs/utils' type ErrorHandler = (error: any) => unknown export interface PlexusPreActionConfig { lazy?: boolean } -export class PreActionInstance { +export class PreActionInstance { private _internalStore = { _ran: false, _id: genUID(), @@ -15,7 +20,7 @@ export class PreActionInstance { /** * The action associated with this PreAction */ - action: ReturnType + action: (...args: InnerFunctionArgs) => Promise | Response /** * The internal id of the PreAction */ @@ -25,10 +30,10 @@ export class PreActionInstance { constructor( private instance: () => PlexusInstance, - fn: Fn, + fn: (...args: FunctionArgs) => Response | Promise, config: PlexusPreActionConfig = {} ) { - this.action = _action(instance, fn) + this.action = _action(instance, fn) instance()._inits.set(this.id, this) if (!config.lazy) { this.run() @@ -60,15 +65,14 @@ export class PreActionInstance { return result } } -export type PlexusPreAction = - PreActionInstance +export type PlexusPreAction = PreActionInstance -export function _preaction( +export function _preaction( instance: () => PlexusInstance, - fn: Fn, + fn: (...args: FunctionArgs) => Response | Promise, config?: PlexusPreActionConfig ) { - return new PreActionInstance(instance, fn, config) + return new PreActionInstance(instance, fn, config) } /** diff --git a/packages/plexus-utils/src/shared/index.ts b/packages/plexus-utils/src/shared/index.ts index 4919ab2e..e74fe318 100644 --- a/packages/plexus-utils/src/shared/index.ts +++ b/packages/plexus-utils/src/shared/index.ts @@ -6,9 +6,9 @@ export const genUID = () => Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15) -export const isAsyncFunction = ( - fn: (...args: any[]) => unknown | Promise -) => +export const isAsyncFunction = ( + fn: (...args: any[]) => ReturnedValue | Promise +): fn is () => Promise => typeof fn === 'function' && - fn.constructor.name === 'AsyncFunction' && - fn[Symbol.toStringTag] === 'AsyncFunction' + (fn.constructor.name === 'AsyncFunction' || + fn[Symbol.toStringTag] === 'AsyncFunction') diff --git a/tests/action.test.ts b/tests/action.test.ts index f858409a..69976a56 100644 --- a/tests/action.test.ts +++ b/tests/action.test.ts @@ -74,10 +74,12 @@ describe('Testing Action Function', () => { test(`Can handle async errors`, async () => { const myAction = action(async ({ onCatch }) => { - onCatch(console.error) - return await new Promise((resolve, reject) => + onCatch(() => { + console.log('error caught successfully!') + }) + return await new Promise((resolve, reject) => { setTimeout(() => reject(new Error('test error')), 100) - ) + }) }) const data = await myAction() expect(data).toBeDefined() diff --git a/tests/edgecases.test.tsx b/tests/edgecases.test.tsx index 5e421046..79fdafea 100644 --- a/tests/edgecases.test.tsx +++ b/tests/edgecases.test.tsx @@ -7,6 +7,7 @@ import { batch, action, computed, + state, } from '@plexusjs/core' import { appointments, users, waitFor } from './test-utils' @@ -19,60 +20,79 @@ beforeEach(() => { describe('Collection Relations', () => { // this is caused by collection groups having automatic batching. Maybe an issue with nested batch calls? A race condition? - test('Batching the `collect` method of related collections', async () => { - instance({ logLevel: 'debug' }) - const myAction = action(async ({ batch, onCatch }) => { - onCatch(console.error) - - await batch(async () => { - // #here gets stuck - users.collect({ - id: '1', - firstName: 'John', - appointmentId: '1', - }) - users.selectors.batched.select('1') - appointments.collect({ - id: '1', - name: 'test', - date: 123, - userId: '1', - }) + test( + 'Batching the `collect` method of related collections', + async () => { + instance({ logLevel: 'debug' }) + await new Promise((resolve) => { + setTimeout(() => { + console.log('0 timeout done!') + resolve('') + }, 0) + }) + const myAction = action(async ({ batch, onCatch }) => { + onCatch(console.error) + + return await batch(async function () { + console.log('Batching Function Start!') + + users.collect({ + id: '1', + firstName: 'John', + appointmentId: '1', + }) + users.selectors.batched.select('1') + appointments.collect({ + id: '1', + name: 'test', + date: 123, + userId: '1', + }) - // #hereEnd - dummyCollection.collect({ id: 'test' }) + dummyCollection.collect({ id: 'test' }) + return new Promise((resolve) => { + setTimeout(() => { + console.log('timeout done!') + resolve('') + }, 500) + }) + + }) + // return new Promise((resolve) => { + // setTimeout(() => { + // console.log('timeout done!') + // resolve(val) + // }, 500) + // }) - await new Promise((resolve) => - setTimeout(() => { - resolve('') - console.log('Batched Function Complete!') - }, 500) - ) }) - }) - // the related collection value state should be undefined or something because the batch function hasn't finished yet - expect(users.getItemValue('1')?.firstName).toBeFalsy() - // purposely not waiting for the async action to finish - myAction() - // the related collection value state should be undefined or something because the batch function hasn't finished yet - expect(users.getItemValue('1')?.firstName).toBeFalsy() - - await waitFor( - () => { - expect(dummyCollection.keys.length).toBe(1) - expect(users.getItem('1').value?.firstName).toBe('John') - expect(users.selectors.batched.value?.firstName).toBe('John') - console.log('batch successful', users.getItemValue('1')?.firstName) - console.log('batch successful', users.selectors.batched.value) - }, - { timeout: 1000 } - ) - }) + // the related collection value state should be undefined or something because the batch function hasn't finished yet + expect(users.getItemValue('1')?.firstName).toBeFalsy() + + // purposely not waiting for the async action to finish + myAction() + // #here gets stuck + // the related collection value state should be undefined because the batch function hasn't finished yet + expect(users.getItemValue('1')?.firstName).toBeFalsy() + + await waitFor( + () => { + expect(dummyCollection.keys.length).toBe(1) + expect(users.getItem('1').value?.firstName).toBe('John') + expect(users.selectors.batched.value?.firstName).toBe('John') + console.log('batch successful', users.getItemValue('1')?.firstName) + console.log('batch successful', users.selectors.batched.value) + }, + { timeout: 1000 } + ) + }, + { timeout: 10000 } + ) test('Batching race condition with selectors', () => { - batch(() => {}) + batch(() => { }) }) }) @@ -87,4 +107,16 @@ describe('Weird Edge Cases', () => { myCollection.collect({ id: '1', name: 'test' }) expect(myComputed.value).toBe('test') }) + + test('Batching a state set', () => { + const myState = state('') + const myAction = action(({ batch }) => { + batch(() => { + myState.set('test') + }) + }) + + myAction() + expect(myState.value).toBe('test') + }) }) diff --git a/tests/efficiency.test.ts b/tests/efficiency.test.ts index cf2e845b..d4eabfce 100644 --- a/tests/efficiency.test.ts +++ b/tests/efficiency.test.ts @@ -51,40 +51,52 @@ afterEach(() => { }) describe('Efficiency tests for ', () => { - test('The speed of a plexus collection collecting more than a thousand randomly generated objects into multiple groups', () => { - instance({ logLevel: 'debug' }) - console.log('Starting test...') - console.log('items in collection:', users1k.length) - usersLite.collect(users1k, ['firstNames']) - console.log('items in collection:', usersLite.value.length) - expect(usersLite.value.length).toBe(1000) - expect(usersLite.groups.firstNames.value.length).toBe(1000) - - instance({ logLevel: undefined }) - }) - test('Testing the same as above but with an absurd amount of data', () => { - instance({ logLevel: 'debug' }) - console.log('Starting test...') - console.log('items in collection:', users10k.length) - usersLite.collect(users10k, ['firstNames']) - console.log('items in collection:', usersLite.value.length) - // const group1 = collectionInstance.group('appointmentId') - // const group2 = collectionInstance.group('name') - // expect(group1.value.length).toBe(1000) - // expect(group2.value.length).toBe(1000) - instance({ logLevel: undefined }) - }) - test('An absurd amount of related data', () => { - instance({ logLevel: 'debug' }) - console.log('Starting test...') - console.log('items in collection:', users10k.length) - users.collect(users1kRelated, ['main']) - appointments.collect(appointments1kRelated, ['main']) - console.log('items in collection:', users.value.length) - // const group1 = collectionInstance.group('appointmentId') - // const group2 = collectionInstance.group('name') - // expect(group1.value.length).toBe(1000) - // expect(group2.value.length).toBe(1000) - instance({ logLevel: undefined }) - }) + // test('The speed of a plexus collection collecting more than a thousand randomly generated objects into multiple groups', () => { + // instance({ logLevel: 'debug' }) + // console.log('Starting test...') + // console.log('items in collection:', users1k.length) + // usersLite.collect(users1k, ['firstNames']) + // console.log('items in collection:', usersLite.value.length) + // expect(usersLite.value.length).toBe(1000) + // expect(usersLite.groups.firstNames.value.length).toBe(1000) + // instance({ logLevel: undefined }) + // }) + // test('Testing the same as above but with an absurd amount of data', () => { + // instance({ logLevel: 'debug' }) + // console.log('Starting test...') + // console.log('items in collection:', users10k.length) + // usersLite.collect(users10k, ['firstNames']) + // console.log('items in collection:', usersLite.value.length) + // // const group1 = collectionInstance.group('appointmentId') + // // const group2 = collectionInstance.group('name') + // // expect(group1.value.length).toBe(1000) + // // expect(group2.value.length).toBe(1000) + // instance({ logLevel: undefined }) + // }) + // test('An absurd amount of related data', () => { + // instance({ logLevel: 'debug' }) + // console.log('Starting test...') + // console.log('items in collection:', users10k.length) + // users.collect(users1kRelated, ['main']) + // appointments.collect(appointments1kRelated, ['main']) + // console.log('items in collection:', users.value.length) + // // const group1 = collectionInstance.group('appointmentId') + // // const group2 = collectionInstance.group('name') + // // expect(group1.value.length).toBe(1000) + // // expect(group2.value.length).toBe(1000) + // instance({ logLevel: undefined }) + // }) + // test('An absurd amount of related data', () => { + // instance({ logLevel: 'debug' }) + // console.log('Starting test...') + // console.log('items in collection:', users10k.length) + // users.collect(users1kRelated, ['main']) + // appointments.collect(appointments1kRelated, ['main']) + // console.log('items in collection:', users.value.length) + // // const group1 = collectionInstance.group('appointmentId') + // // const group2 = collectionInstance.group('name') + // // expect(group1.value.length).toBe(1000) + // // expect(group2.value.length).toBe(1000) + // instance({ logLevel: undefined }) + // }) }) diff --git a/tests/timed.test.ts b/tests/timed.test.ts index a3b04037..12768842 100644 --- a/tests/timed.test.ts +++ b/tests/timed.test.ts @@ -2,52 +2,52 @@ import { describe, test } from 'vitest' import { DEFAULT_DECAY_RATE, decayingUsers } from './test-utils' describe('Ephemeral Collection data', () => { - test( - 'Does decaying data work?', - (ctx) => - new Promise((resolve) => { - decayingUsers.collect({ firstName: 'Bill', userId: '0' }) - expect(decayingUsers.value.length).toBe(1) - expect(decayingUsers.value[0].firstName).toBe('Bill') - expect(decayingUsers.value[0].userId).toBe('0') - setTimeout(() => { - expect(decayingUsers.value.length).toBe(0) - console.log('done! Thing is decayed!') - resolve(true) - }, DEFAULT_DECAY_RATE + 10) - }), - DEFAULT_DECAY_RATE + 100 - ) - test( - 'Does decaying data refresh on set?', - (ctx) => - new Promise((resolve) => { - decayingUsers.collect({ firstName: 'Bill', userId: '0' }) - expect(decayingUsers.value.length).toBe(1) - expect(decayingUsers.value[0].firstName).toBe('Bill') - expect(decayingUsers.value[0].userId).toBe('0') - // recollecting should reset the decay timer - setTimeout(() => { - expect(decayingUsers.value.length).toBe(1) - decayingUsers.collect({ firstName: 'Bill', userId: '0' }) - }, DEFAULT_DECAY_RATE - 10) - // so if we wait a bit, it should still be there - setTimeout(() => { - console.log('wtfff') - expect(decayingUsers.value.length).toBe(1) - }, DEFAULT_DECAY_RATE + 10) - // and then it should decay past the decay rate - setTimeout( - () => { - expect(decayingUsers.value.length).toBe(0) - console.log('done! Thing is decayed!') - resolve(true) - }, - DEFAULT_DECAY_RATE * 2 + 10 - ) - }), - { - timeout: DEFAULT_DECAY_RATE * 2 + 100, - } - ) + // test( + // 'Does decaying data work?', + // (ctx) => + // new Promise((resolve) => { + // decayingUsers.collect({ firstName: 'Bill', userId: '0' }) + // expect(decayingUsers.value.length).toBe(1) + // expect(decayingUsers.value[0].firstName).toBe('Bill') + // expect(decayingUsers.value[0].userId).toBe('0') + // setTimeout(() => { + // expect(decayingUsers.value.length).toBe(0) + // console.log('done! Thing is decayed!') + // resolve(true) + // }, DEFAULT_DECAY_RATE + 10) + // }), + // DEFAULT_DECAY_RATE + 100 + // ) + // test( + // 'Does decaying data refresh on set?', + // (ctx) => + // new Promise((resolve) => { + // decayingUsers.collect({ firstName: 'Bill', userId: '0' }) + // expect(decayingUsers.value.length).toBe(1) + // expect(decayingUsers.value[0].firstName).toBe('Bill') + // expect(decayingUsers.value[0].userId).toBe('0') + // // recollecting should reset the decay timer + // setTimeout(() => { + // expect(decayingUsers.value.length).toBe(1) + // decayingUsers.collect({ firstName: 'Bill', userId: '0' }) + // }, DEFAULT_DECAY_RATE - 10) + // // so if we wait a bit, it should still be there + // setTimeout(() => { + // console.log('wtfff') + // expect(decayingUsers.value.length).toBe(1) + // }, DEFAULT_DECAY_RATE + 10) + // // and then it should decay past the decay rate + // setTimeout( + // () => { + // expect(decayingUsers.value.length).toBe(0) + // console.log('done! Thing is decayed!') + // resolve(true) + // }, + // DEFAULT_DECAY_RATE * 2 + 10 + // ) + // }), + // { + // timeout: DEFAULT_DECAY_RATE * 2 + 100, + // } + // ) }) diff --git a/yarn.lock b/yarn.lock index 7e2f0495..e092173b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -159,7 +159,7 @@ "@nicolo-ribaudo/chokidar-2" "2.1.8-no-fsevents.3" chokidar "^3.4.0" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.0", "@babel/code-frame@^7.18.6", "@babel/code-frame@^7.8.3": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.16.0", "@babel/code-frame@^7.18.6", "@babel/code-frame@^7.8.3": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== @@ -218,7 +218,7 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.18.6", "@babel/core@^7.19.6", "@babel/core@^7.20.5", "@babel/core@^7.7.2", "@babel/core@^7.8.0": +"@babel/core@^7.18.6", "@babel/core@^7.19.6", "@babel/core@^7.20.5": version "7.21.0" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.21.0.tgz#1341aefdcc14ccc7553fcc688dd8986a2daffc13" integrity sha512-PuxUbxcW6ZYe656yL3EAhpy7qXKq0DmYsrJLpbB8XrsCP9Nm+XCg9XFMb5vIDliPD7+U/+M+QJlH17XOcB7eXA== @@ -260,7 +260,7 @@ json5 "^2.2.2" semver "^6.3.1" -"@babel/generator@^7.12.5", "@babel/generator@^7.18.7", "@babel/generator@^7.21.0", "@babel/generator@^7.21.1", "@babel/generator@^7.7.2": +"@babel/generator@^7.12.5", "@babel/generator@^7.18.7", "@babel/generator@^7.21.0", "@babel/generator@^7.21.1": version "7.21.1" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.21.1.tgz#951cc626057bc0af2c35cd23e9c64d384dea83dd" integrity sha512-1lT45bAYlQhFn/BHivJs43AiW2rg3/UbLyShGfF3C0KmHvO5fSghWd5kBJy30kpRRucGzXStvnnCFniCR2kXAA== @@ -740,7 +740,7 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.12.7", "@babel/parser@^7.14.7", "@babel/parser@^7.18.8", "@babel/parser@^7.20.15", "@babel/parser@^7.20.7", "@babel/parser@^7.21.0", "@babel/parser@^7.21.2": +"@babel/parser@^7.12.7", "@babel/parser@^7.18.8", "@babel/parser@^7.20.15", "@babel/parser@^7.20.7", "@babel/parser@^7.21.0", "@babel/parser@^7.21.2": version "7.21.2" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.21.2.tgz#dacafadfc6d7654c3051a66d6fe55b6cb2f2a0b3" integrity sha512-URpaIJQwEkEC2T9Kn+Ai6Xe/02iNaVCuT/PtoRz3GPVJVDpPd7mLo+VddTbhCRU9TXqW5mSrQfXZyi8kDKOVpQ== @@ -948,14 +948,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-bigint@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" - integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-class-properties@^7.12.13", "@babel/plugin-syntax-class-properties@^7.8.3": +"@babel/plugin-syntax-class-properties@^7.12.13": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== @@ -1011,7 +1004,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-syntax-import-meta@^7.10.4", "@babel/plugin-syntax-import-meta@^7.8.3": +"@babel/plugin-syntax-import-meta@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== @@ -1046,7 +1039,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== @@ -1060,7 +1053,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-numeric-separator@^7.10.4", "@babel/plugin-syntax-numeric-separator@^7.8.3": +"@babel/plugin-syntax-numeric-separator@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== @@ -1095,14 +1088,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-syntax-top-level-await@^7.14.5", "@babel/plugin-syntax-top-level-await@^7.8.3": +"@babel/plugin-syntax-top-level-await@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-syntax-typescript@^7.20.0", "@babel/plugin-syntax-typescript@^7.7.2": +"@babel/plugin-syntax-typescript@^7.20.0": version "7.20.0" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz#4e9a0cfc769c85689b77a2e642d24e9f697fc8c7" integrity sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ== @@ -2106,7 +2099,7 @@ dependencies: regenerator-runtime "^0.14.0" -"@babel/template@^7.12.7", "@babel/template@^7.18.10", "@babel/template@^7.20.7", "@babel/template@^7.3.3": +"@babel/template@^7.12.7", "@babel/template@^7.18.10", "@babel/template@^7.20.7": version "7.20.7" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.20.7.tgz#a15090c2839a83b02aa996c0b4994005841fd5a8" integrity sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw== @@ -2124,7 +2117,7 @@ "@babel/parser" "^7.22.5" "@babel/types" "^7.22.5" -"@babel/traverse@^7.12.9", "@babel/traverse@^7.18.8", "@babel/traverse@^7.20.5", "@babel/traverse@^7.20.7", "@babel/traverse@^7.21.0", "@babel/traverse@^7.21.2", "@babel/traverse@^7.7.2": +"@babel/traverse@^7.12.9", "@babel/traverse@^7.18.8", "@babel/traverse@^7.20.5", "@babel/traverse@^7.20.7", "@babel/traverse@^7.21.0", "@babel/traverse@^7.21.2": version "7.21.2" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.21.2.tgz#ac7e1f27658750892e815e60ae90f382a46d8e75" integrity sha512-ts5FFU/dSUPS13tv8XiEObDu9K+iagEKME9kAbaP7r0Y9KtZJZ+NGndDvWoRAYNpeWafbpFeki3q9QoMD6gxyw== @@ -2172,7 +2165,7 @@ debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.12.7", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.20.0", "@babel/types@^7.20.2", "@babel/types@^7.20.5", "@babel/types@^7.20.7", "@babel/types@^7.21.0", "@babel/types@^7.21.2", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4": +"@babel/types@^7.12.7", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.20.0", "@babel/types@^7.20.2", "@babel/types@^7.20.5", "@babel/types@^7.20.7", "@babel/types@^7.21.0", "@babel/types@^7.21.2", "@babel/types@^7.4.4": version "7.21.2" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.21.2.tgz#92246f6e00f91755893c2876ad653db70c8310d1" integrity sha512-3wRZSs7jiFaB8AjxiiD+VqN5DTG2iRvJGQ+qYFrs/654lg6kGTQWIOFjlBo5RaXuAZjBmP3+OQH4dmhqiiyYxw== @@ -2199,11 +2192,6 @@ "@babel/helper-validator-identifier" "^7.22.5" to-fast-properties "^2.0.0" -"@bcoe/v8-coverage@^0.2.3": - version "0.2.3" - resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" - integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== - "@colors/colors@1.5.0": version "1.5.0" resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" @@ -2817,130 +2805,6 @@ wrap-ansi "^8.1.0" wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" -"@istanbuljs/load-nyc-config@^1.0.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" - integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== - dependencies: - camelcase "^5.3.1" - find-up "^4.1.0" - get-package-type "^0.1.0" - js-yaml "^3.13.1" - resolve-from "^5.0.0" - -"@istanbuljs/schema@^0.1.2": - version "0.1.3" - resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" - integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== - -"@jest/console@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-27.5.1.tgz#260fe7239602fe5130a94f1aa386eff54b014bba" - integrity sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg== - dependencies: - "@jest/types" "^27.5.1" - "@types/node" "*" - chalk "^4.0.0" - jest-message-util "^27.5.1" - jest-util "^27.5.1" - slash "^3.0.0" - -"@jest/core@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-27.5.1.tgz#267ac5f704e09dc52de2922cbf3af9edcd64b626" - integrity sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ== - dependencies: - "@jest/console" "^27.5.1" - "@jest/reporters" "^27.5.1" - "@jest/test-result" "^27.5.1" - "@jest/transform" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/node" "*" - ansi-escapes "^4.2.1" - chalk "^4.0.0" - emittery "^0.8.1" - exit "^0.1.2" - graceful-fs "^4.2.9" - jest-changed-files "^27.5.1" - jest-config "^27.5.1" - jest-haste-map "^27.5.1" - jest-message-util "^27.5.1" - jest-regex-util "^27.5.1" - jest-resolve "^27.5.1" - jest-resolve-dependencies "^27.5.1" - jest-runner "^27.5.1" - jest-runtime "^27.5.1" - jest-snapshot "^27.5.1" - jest-util "^27.5.1" - jest-validate "^27.5.1" - jest-watcher "^27.5.1" - micromatch "^4.0.4" - rimraf "^3.0.0" - slash "^3.0.0" - strip-ansi "^6.0.0" - -"@jest/environment@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-27.5.1.tgz#d7425820511fe7158abbecc010140c3fd3be9c74" - integrity sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA== - dependencies: - "@jest/fake-timers" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/node" "*" - jest-mock "^27.5.1" - -"@jest/fake-timers@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-27.5.1.tgz#76979745ce0579c8a94a4678af7a748eda8ada74" - integrity sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ== - dependencies: - "@jest/types" "^27.5.1" - "@sinonjs/fake-timers" "^8.0.1" - "@types/node" "*" - jest-message-util "^27.5.1" - jest-mock "^27.5.1" - jest-util "^27.5.1" - -"@jest/globals@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-27.5.1.tgz#7ac06ce57ab966566c7963431cef458434601b2b" - integrity sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q== - dependencies: - "@jest/environment" "^27.5.1" - "@jest/types" "^27.5.1" - expect "^27.5.1" - -"@jest/reporters@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-27.5.1.tgz#ceda7be96170b03c923c37987b64015812ffec04" - integrity sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw== - dependencies: - "@bcoe/v8-coverage" "^0.2.3" - "@jest/console" "^27.5.1" - "@jest/test-result" "^27.5.1" - "@jest/transform" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/node" "*" - chalk "^4.0.0" - collect-v8-coverage "^1.0.0" - exit "^0.1.2" - glob "^7.1.2" - graceful-fs "^4.2.9" - istanbul-lib-coverage "^3.0.0" - istanbul-lib-instrument "^5.1.0" - istanbul-lib-report "^3.0.0" - istanbul-lib-source-maps "^4.0.0" - istanbul-reports "^3.1.3" - jest-haste-map "^27.5.1" - jest-resolve "^27.5.1" - jest-util "^27.5.1" - jest-worker "^27.5.1" - slash "^3.0.0" - source-map "^0.6.0" - string-length "^4.0.1" - terminal-link "^2.0.0" - v8-to-istanbul "^8.1.0" - "@jest/schemas@^29.4.3": version "29.4.3" resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.4.3.tgz#39cf1b8469afc40b6f5a2baaa146e332c4151788" @@ -2955,67 +2819,6 @@ dependencies: "@sinclair/typebox" "^0.27.8" -"@jest/source-map@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-27.5.1.tgz#6608391e465add4205eae073b55e7f279e04e8cf" - integrity sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg== - dependencies: - callsites "^3.0.0" - graceful-fs "^4.2.9" - source-map "^0.6.0" - -"@jest/test-result@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-27.5.1.tgz#56a6585fa80f7cdab72b8c5fc2e871d03832f5bb" - integrity sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag== - dependencies: - "@jest/console" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/istanbul-lib-coverage" "^2.0.0" - collect-v8-coverage "^1.0.0" - -"@jest/test-sequencer@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz#4057e0e9cea4439e544c6353c6affe58d095745b" - integrity sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ== - dependencies: - "@jest/test-result" "^27.5.1" - graceful-fs "^4.2.9" - jest-haste-map "^27.5.1" - jest-runtime "^27.5.1" - -"@jest/transform@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-27.5.1.tgz#6c3501dcc00c4c08915f292a600ece5ecfe1f409" - integrity sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw== - dependencies: - "@babel/core" "^7.1.0" - "@jest/types" "^27.5.1" - babel-plugin-istanbul "^6.1.1" - chalk "^4.0.0" - convert-source-map "^1.4.0" - fast-json-stable-stringify "^2.0.0" - graceful-fs "^4.2.9" - jest-haste-map "^27.5.1" - jest-regex-util "^27.5.1" - jest-util "^27.5.1" - micromatch "^4.0.4" - pirates "^4.0.4" - slash "^3.0.0" - source-map "^0.6.1" - write-file-atomic "^3.0.0" - -"@jest/types@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.5.1.tgz#3c79ec4a8ba61c170bf937bcf9e98a9df175ec80" - integrity sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^3.0.0" - "@types/node" "*" - "@types/yargs" "^16.0.0" - chalk "^4.0.0" - "@jest/types@^29.5.0": version "29.5.0" resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.5.0.tgz#f59ef9b031ced83047c67032700d8c807d6e1593" @@ -3918,20 +3721,6 @@ resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== -"@sinonjs/commons@^1.7.0": - version "1.8.6" - resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.6.tgz#80c516a4dc264c2a69115e7578d62581ff455ed9" - integrity sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ== - dependencies: - type-detect "4.0.8" - -"@sinonjs/fake-timers@^8.0.1": - version "8.1.0" - resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz#3fdc2b6cb58935b21bfb8d1625eb1300484316e7" - integrity sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg== - dependencies: - "@sinonjs/commons" "^1.7.0" - "@slorber/static-site-generator-webpack-plugin@^4.0.7": version "4.0.7" resolved "https://registry.yarnpkg.com/@slorber/static-site-generator-webpack-plugin/-/static-site-generator-webpack-plugin-4.0.7.tgz#fc1678bddefab014e2145cbe25b3ce4e1cfc36f3" @@ -4077,11 +3866,6 @@ "@testing-library/dom" "^9.0.0" "@types/react-dom" "^18.0.0" -"@tootallnate/once@1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" - integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== - "@tootallnate/once@2": version "2.0.0" resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf" @@ -4140,39 +3924,6 @@ resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-5.0.1.tgz#3286741fb8f1e1580ac28784add4c7a1d49bdfbc" integrity sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q== -"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14": - version "7.20.0" - resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.0.tgz#61bc5a4cae505ce98e1e36c5445e4bee060d8891" - integrity sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ== - dependencies: - "@babel/parser" "^7.20.7" - "@babel/types" "^7.20.7" - "@types/babel__generator" "*" - "@types/babel__template" "*" - "@types/babel__traverse" "*" - -"@types/babel__generator@*": - version "7.6.4" - resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.4.tgz#1f20ce4c5b1990b37900b63f050182d28c2439b7" - integrity sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg== - dependencies: - "@babel/types" "^7.0.0" - -"@types/babel__template@*": - version "7.4.1" - resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.1.tgz#3d1a48fd9d6c0edfd56f2ff578daed48f36c8969" - integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g== - dependencies: - "@babel/parser" "^7.1.0" - "@babel/types" "^7.0.0" - -"@types/babel__traverse@*", "@types/babel__traverse@^7.0.4", "@types/babel__traverse@^7.0.6": - version "7.18.3" - resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.18.3.tgz#dfc508a85781e5698d5b33443416b6268c4b3e8d" - integrity sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w== - dependencies: - "@babel/types" "^7.3.0" - "@types/body-parser@*": version "1.19.2" resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0" @@ -4270,13 +4021,6 @@ resolved "https://registry.yarnpkg.com/@types/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#c0840685ec3bc77487329924685f53c786ad690f" integrity sha512-bod4N8d1d0qF2GV4j79jdh0MZEki3rJ093a0Hx3zHhlHK6jctkA0zfux1tu9sOfET2IMKTrbxAk8o0z8aJTA+g== -"@types/graceful-fs@^4.1.2": - version "4.1.6" - resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.6.tgz#e14b2576a1c25026b7f02ede1de3b84c3a1efeae" - integrity sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw== - dependencies: - "@types/node" "*" - "@types/hast@^2.0.0": version "2.3.4" resolved "https://registry.yarnpkg.com/@types/hast/-/hast-2.3.4.tgz#8aa5ef92c117d20d974a82bdfb6a648b08c0bafc" @@ -4301,7 +4045,7 @@ dependencies: "@types/node" "*" -"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": version "2.0.4" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== @@ -4320,14 +4064,6 @@ dependencies: "@types/istanbul-lib-report" "*" -"@types/jest@^27.4.0": - version "27.5.2" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-27.5.2.tgz#ec49d29d926500ffb9fd22b84262e862049c026c" - integrity sha512-mpT8LJJ4CMeeahobofYWIjFo0xonRS/HfxnVEPMPFSQdGUt1uHCnoPT7Zhb+sjDU2wz0oKV0OLUR0WzrHNgfeA== - dependencies: - jest-matcher-utils "^27.0.0" - pretty-format "^27.0.0" - "@types/jsdoc-to-markdown@^7.0.3": version "7.0.3" resolved "https://registry.yarnpkg.com/@types/jsdoc-to-markdown/-/jsdoc-to-markdown-7.0.3.tgz#30212d81ca8405e660ff51613b4d627be230c4e2" @@ -4403,11 +4139,6 @@ resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-5.0.3.tgz#e7b5aebbac150f8b5fdd4a46e7f0bd8e65e19109" integrity sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw== -"@types/prettier@^2.1.5": - version "2.7.2" - resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.2.tgz#6c2324641cc4ba050a8c710b2b251b377581fbf0" - integrity sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg== - "@types/prop-types@*": version "15.7.5" resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf" @@ -4534,11 +4265,6 @@ dependencies: "@types/node" "*" -"@types/stack-utils@^2.0.0": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" - integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== - "@types/unist@*", "@types/unist@^2.0.0", "@types/unist@^2.0.2", "@types/unist@^2.0.3": version "2.0.6" resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d" @@ -4561,13 +4287,6 @@ resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== -"@types/yargs@^16.0.0": - version "16.0.5" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.5.tgz#12cc86393985735a283e387936398c2f9e5f88e3" - integrity sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ== - dependencies: - "@types/yargs-parser" "*" - "@types/yargs@^17.0.8": version "17.0.22" resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.22.tgz#7dd37697691b5f17d020f3c63e7a45971ff71e9a" @@ -4921,7 +4640,7 @@ JSONStream@^1.3.5: jsonparse "^1.2.0" through ">=2.2.7 <3" -abab@^2.0.3, abab@^2.0.5, abab@^2.0.6: +abab@^2.0.5, abab@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291" integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA== @@ -4949,14 +4668,6 @@ acorn-dynamic-import@^4.0.0: resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz#482210140582a36b83c3e342e1cfebcaa9240948" integrity sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw== -acorn-globals@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45" - integrity sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg== - dependencies: - acorn "^7.1.1" - acorn-walk "^7.1.1" - acorn-globals@^7.0.0: version "7.0.1" resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-7.0.1.tgz#0dbf05c44fa7c94332914c02066d5beff62c40c3" @@ -4989,7 +4700,7 @@ acorn-node@^1.8.2: acorn-walk "^7.0.0" xtend "^4.0.2" -acorn-walk@^7.0.0, acorn-walk@^7.1.1: +acorn-walk@^7.0.0: version "7.2.0" resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== @@ -5004,12 +4715,12 @@ acorn@^6.1.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6" integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== -acorn@^7.0.0, acorn@^7.1.1: +acorn@^7.0.0: version "7.4.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== -acorn@^8.0.4, acorn@^8.1.0, acorn@^8.2.4, acorn@^8.4.1, acorn@^8.5.0, acorn@^8.7.1, acorn@^8.8.1: +acorn@^8.0.4, acorn@^8.1.0, acorn@^8.4.1, acorn@^8.5.0, acorn@^8.7.1, acorn@^8.8.1: version "8.8.2" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a" integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== @@ -5184,7 +4895,7 @@ ansi-styles@^6.1.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== -anymatch@^3.0.3, anymatch@~3.1.2: +anymatch@~3.1.2: version "3.1.3" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== @@ -5366,20 +5077,6 @@ axios@^1.0.0: form-data "^4.0.0" proxy-from-env "^1.1.0" -babel-jest@^27.4.6, babel-jest@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-27.5.1.tgz#a1bf8d61928edfefd21da27eb86a695bfd691444" - integrity sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg== - dependencies: - "@jest/transform" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/babel__core" "^7.1.14" - babel-plugin-istanbul "^6.1.1" - babel-preset-jest "^27.5.1" - chalk "^4.0.0" - graceful-fs "^4.2.9" - slash "^3.0.0" - babel-loader@^8.2.5: version "8.3.0" resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.3.0.tgz#124936e841ba4fe8176786d6ff28add1f134d6a8" @@ -5429,27 +5126,6 @@ babel-plugin-extract-import-names@1.6.22: dependencies: "@babel/helper-plugin-utils" "7.10.4" -babel-plugin-istanbul@^6.1.1: - version "6.1.1" - resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" - integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@istanbuljs/load-nyc-config" "^1.0.0" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-instrument "^5.0.4" - test-exclude "^6.0.0" - -babel-plugin-jest-hoist@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz#9be98ecf28c331eb9f5df9c72d6f89deb8181c2e" - integrity sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ== - dependencies: - "@babel/template" "^7.3.3" - "@babel/types" "^7.3.3" - "@types/babel__core" "^7.0.0" - "@types/babel__traverse" "^7.0.6" - babel-plugin-macros@^2.8.0: version "2.8.0" resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz#0f958a7cc6556b1e65344465d99111a1e5e10138" @@ -5514,32 +5190,6 @@ babel-plugin-transform-typescript-metadata@^0.3.1: dependencies: "@babel/helper-plugin-utils" "^7.0.0" -babel-preset-current-node-syntax@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" - integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== - dependencies: - "@babel/plugin-syntax-async-generators" "^7.8.4" - "@babel/plugin-syntax-bigint" "^7.8.3" - "@babel/plugin-syntax-class-properties" "^7.8.3" - "@babel/plugin-syntax-import-meta" "^7.8.3" - "@babel/plugin-syntax-json-strings" "^7.8.3" - "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-syntax-numeric-separator" "^7.8.3" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - "@babel/plugin-syntax-top-level-await" "^7.8.3" - -babel-preset-jest@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz#91f10f58034cb7989cb4f962b69fa6eef6a6bc81" - integrity sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag== - dependencies: - babel-plugin-jest-hoist "^27.5.1" - babel-preset-current-node-syntax "^1.0.0" - bail@^1.0.0: version "1.0.5" resolved "https://registry.yarnpkg.com/bail/-/bail-1.0.5.tgz#b6fa133404a392cbc1f8c4bf63f5953351e7a776" @@ -5677,11 +5327,6 @@ braces@^3.0.2, braces@~3.0.2: dependencies: fill-range "^7.0.1" -browser-process-hrtime@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" - integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== - browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.18.1, browserslist@^4.21.3, browserslist@^4.21.4, browserslist@^4.21.5: version "4.21.5" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.5.tgz#75c5dae60063ee641f977e00edd3cfb2fb7af6a7" @@ -5702,20 +5347,6 @@ browserslist@^4.21.9: node-releases "^2.0.12" update-browserslist-db "^1.0.11" -bs-logger@0.x: - version "0.2.6" - resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" - integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== - dependencies: - fast-json-stable-stringify "2.x" - -bser@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" - integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== - dependencies: - node-int64 "^0.4.0" - buble@0.19.6: version "0.19.6" resolved "https://registry.yarnpkg.com/buble/-/buble-0.19.6.tgz#915909b6bd5b11ee03b1c885ec914a8b974d34d3" @@ -5952,11 +5583,6 @@ chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -char-regex@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" - integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== - character-entities-legacy@^1.0.0: version "1.1.4" resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz#94bc1845dce70a5bb9d2ecc748725661293d8fc1" @@ -6042,11 +5668,6 @@ ci-info@^3.2.0, ci-info@^3.6.1: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.8.0.tgz#81408265a5380c929f0bc665d62256628ce9ef91" integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw== -cjs-module-lexer@^1.0.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" - integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== - clean-css@^5.2.2, clean-css@^5.3.0: version "5.3.2" resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.3.2.tgz#70ecc7d4d4114921f5d298349ff86a31a9975224" @@ -6144,11 +5765,6 @@ cmd-shim@6.0.1: resolved "https://registry.yarnpkg.com/cmd-shim/-/cmd-shim-6.0.1.tgz#a65878080548e1dca760b3aea1e21ed05194da9d" integrity sha512-S9iI9y0nKR4hwEQsVWpyxld/6kRfGepGfzff83FcaiEBpmvlbA2nnGe7Cylgrx2f/p1P5S5wpRm9oL8z1PbS3Q== -co@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" - integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== - collapse-white-space@^1.0.2: version "1.0.6" resolved "https://registry.yarnpkg.com/collapse-white-space/-/collapse-white-space-1.0.6.tgz#e63629c0016665792060dbbeb79c42239d2c5287" @@ -6162,11 +5778,6 @@ collect-all@^1.0.4: stream-connect "^1.0.2" stream-via "^1.0.4" -collect-v8-coverage@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" - integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg== - color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -6479,7 +6090,7 @@ conventional-recommended-bump@7.0.1: git-semver-tags "^5.0.0" meow "^8.1.2" -convert-source-map@^1.1.0, convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: +convert-source-map@^1.1.0, convert-source-map@^1.7.0: version "1.9.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== @@ -6863,11 +6474,6 @@ csso@^5.0.5: dependencies: css-tree "~2.2.0" -cssom@^0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" - integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw== - cssom@^0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.5.0.tgz#d254fa92cd8b6fbd83811b9fbaed34663cc17c36" @@ -6895,15 +6501,6 @@ dargs@^7.0.0: resolved "https://registry.yarnpkg.com/dargs/-/dargs-7.0.0.tgz#04015c41de0bcb69ec84050f3d9be0caf8d6d5cc" integrity sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg== -data-urls@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" - integrity sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ== - dependencies: - abab "^2.0.3" - whatwg-mimetype "^2.3.0" - whatwg-url "^8.0.0" - data-urls@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-3.0.2.tgz#9cf24a477ae22bcef5cd5f6f0bfbc1d2d3be9143" @@ -6952,7 +6549,7 @@ decamelize@^1.1.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== -decimal.js@^10.2.1, decimal.js@^10.4.2: +decimal.js@^10.4.2: version "10.4.3" resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23" integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA== @@ -6964,7 +6561,7 @@ decompress-response@^3.3.0: dependencies: mimic-response "^1.0.0" -dedent@0.7.0, dedent@^0.7.0: +dedent@0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" integrity sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA== @@ -7107,11 +6704,6 @@ detect-indent@^5.0.0: resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d" integrity sha512-rlpvsxUtM0PQvy9iZe640/IWwWYyBsTApREbA1pHOpmOUIl9MkP/U4z7vTtg4Oaojvqhxt7sdufnT0EzGaR31g== -detect-newline@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" - integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== - detect-node@^2.0.4: version "2.1.0" resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" @@ -7147,11 +6739,6 @@ didyoumean@^1.2.2: resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037" integrity sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw== -diff-sequences@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.5.1.tgz#eaecc0d327fd68c8d9672a1e64ab8dccb2ef5327" - integrity sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ== - diff-sequences@^29.4.3: version "29.4.3" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.4.3.tgz#9314bc1fabe09267ffeca9cbafc457d8499a13f2" @@ -7247,13 +6834,6 @@ domelementtype@^2.0.1, domelementtype@^2.2.0, domelementtype@^2.3.0: resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d" integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== -domexception@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" - integrity sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg== - dependencies: - webidl-conversions "^5.0.0" - domexception@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/domexception/-/domexception-4.0.0.tgz#4ad1be56ccadc86fc76d033353999a8037d03673" @@ -7355,11 +6935,6 @@ electron-to-chromium@^1.4.431: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.455.tgz#81fe4353ac970eb971c07088c8da8b7f6280ddc9" integrity sha512-8tgdX0Odl24LtmLwxotpJCVjIndN559AvaOtd67u+2mo+IDsgsTF580NB+uuDCqsHw8yFg53l5+imFV9Fw3cbA== -emittery@^0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.8.1.tgz#bb23cc86d03b30aa75a7f734819dee2e1ba70860" - integrity sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg== - emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" @@ -7646,21 +7221,6 @@ execa@5.0.0, execa@^5.0.0: signal-exit "^3.0.3" strip-final-newline "^2.0.0" -exit@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" - integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== - -expect@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/expect/-/expect-27.5.1.tgz#83ce59f1e5bdf5f9d2b94b61d2050db48f3fef74" - integrity sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw== - dependencies: - "@jest/types" "^27.5.1" - jest-get-type "^27.5.1" - jest-matcher-utils "^27.5.1" - jest-message-util "^27.5.1" - express@^4.17.3: version "4.18.2" resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59" @@ -7768,7 +7328,7 @@ fast-glob@^3.3.0: merge2 "^1.3.0" micromatch "^4.0.4" -fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: +fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== @@ -7799,13 +7359,6 @@ faye-websocket@^0.11.3: dependencies: websocket-driver ">=0.5.1" -fb-watchman@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.2.tgz#e9524ee6b5c77e9e5001af0f85f3adbb8623255c" - integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA== - dependencies: - bser "2.1.1" - fbemitter@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/fbemitter/-/fbemitter-3.0.0.tgz#00b2a1af5411254aab416cd75f9e6289bee4bff3" @@ -8035,15 +7588,6 @@ fork-ts-checker-webpack-plugin@^6.5.0: semver "^7.3.2" tapable "^1.0.0" -form-data@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" - integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - mime-types "^2.1.12" - form-data@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" @@ -8166,7 +7710,7 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@^2.3.2, fsevents@~2.3.2: +fsevents@~2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== @@ -8224,11 +7768,6 @@ get-own-enumerable-property-symbols@^3.0.0: resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664" integrity sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g== -get-package-type@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" - integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== - get-pkg-repo@^4.2.1: version "4.2.1" resolved "https://registry.yarnpkg.com/get-pkg-repo/-/get-pkg-repo-4.2.1.tgz#75973e1c8050c73f48190c52047c4cee3acbf385" @@ -8357,7 +7896,7 @@ glob@^10.2.2: minipass "^5.0.0 || ^6.0.2 || ^7.0.0" path-scurry "^1.10.1" -glob@^7.0.0, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.2.0: +glob@^7.0.0, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.2.0: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -8722,13 +8261,6 @@ hpack.js@^2.1.6: readable-stream "^2.0.1" wbuf "^1.1.0" -html-encoding-sniffer@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" - integrity sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ== - dependencies: - whatwg-encoding "^1.0.5" - html-encoding-sniffer@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz#2cb1a8cf0db52414776e5b2a7a04d5dd98158de9" @@ -8741,11 +8273,6 @@ html-entities@^2.3.2: resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.3.3.tgz#117d7626bece327fc8baace8868fa6f5ef856e46" integrity sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA== -html-escaper@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" - integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== - html-minifier-terser@^6.0.2, html-minifier-terser@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#bfc818934cc07918f6b3669f5774ecdfd48f32ab" @@ -8836,15 +8363,6 @@ http-parser-js@>=0.5.1: resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.8.tgz#af23090d9ac4e24573de6f6aecc9d84a48bf20e3" integrity sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q== -http-proxy-agent@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" - integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== - dependencies: - "@tootallnate/once" "1" - agent-base "6" - debug "4" - http-proxy-agent@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz#5129800203520d434f142bc78ff3c170800f2b43" @@ -8977,7 +8495,7 @@ import-lazy@^2.1.0: resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" integrity sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A== -import-local@3.1.0, import-local@^3.0.2: +import-local@3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== @@ -9235,11 +8753,6 @@ is-fullwidth-code-point@^3.0.0: resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== -is-generator-fn@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" - integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== - is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: version "4.0.3" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" @@ -9501,48 +9014,6 @@ isomorphic-fetch@^3.0.0: node-fetch "^2.6.1" whatwg-fetch "^3.4.1" -istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" - integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== - -istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" - integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== - dependencies: - "@babel/core" "^7.12.3" - "@babel/parser" "^7.14.7" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-coverage "^3.2.0" - semver "^6.3.0" - -istanbul-lib-report@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" - integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== - dependencies: - istanbul-lib-coverage "^3.0.0" - make-dir "^3.0.0" - supports-color "^7.1.0" - -istanbul-lib-source-maps@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" - integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== - dependencies: - debug "^4.1.1" - istanbul-lib-coverage "^3.0.0" - source-map "^0.6.1" - -istanbul-reports@^3.1.3: - version "3.1.5" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.5.tgz#cc9a6ab25cb25659810e4785ed9d9fb742578bae" - integrity sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w== - dependencies: - html-escaper "^2.0.0" - istanbul-lib-report "^3.0.0" - jackspeak@^2.0.3: version "2.2.1" resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.2.1.tgz#655e8cf025d872c9c03d3eb63e8f0c024fef16a6" @@ -9562,88 +9033,6 @@ jake@^10.8.5: filelist "^1.0.1" minimatch "^3.0.4" -jest-changed-files@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-27.5.1.tgz#a348aed00ec9bf671cc58a66fcbe7c3dfd6a68f5" - integrity sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw== - dependencies: - "@jest/types" "^27.5.1" - execa "^5.0.0" - throat "^6.0.1" - -jest-circus@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-27.5.1.tgz#37a5a4459b7bf4406e53d637b49d22c65d125ecc" - integrity sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw== - dependencies: - "@jest/environment" "^27.5.1" - "@jest/test-result" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/node" "*" - chalk "^4.0.0" - co "^4.6.0" - dedent "^0.7.0" - expect "^27.5.1" - is-generator-fn "^2.0.0" - jest-each "^27.5.1" - jest-matcher-utils "^27.5.1" - jest-message-util "^27.5.1" - jest-runtime "^27.5.1" - jest-snapshot "^27.5.1" - jest-util "^27.5.1" - pretty-format "^27.5.1" - slash "^3.0.0" - stack-utils "^2.0.3" - throat "^6.0.1" - -jest-cli@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-27.5.1.tgz#278794a6e6458ea8029547e6c6cbf673bd30b145" - integrity sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw== - dependencies: - "@jest/core" "^27.5.1" - "@jest/test-result" "^27.5.1" - "@jest/types" "^27.5.1" - chalk "^4.0.0" - exit "^0.1.2" - graceful-fs "^4.2.9" - import-local "^3.0.2" - jest-config "^27.5.1" - jest-util "^27.5.1" - jest-validate "^27.5.1" - prompts "^2.0.1" - yargs "^16.2.0" - -jest-config@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-27.5.1.tgz#5c387de33dca3f99ad6357ddeccd91bf3a0e4a41" - integrity sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA== - dependencies: - "@babel/core" "^7.8.0" - "@jest/test-sequencer" "^27.5.1" - "@jest/types" "^27.5.1" - babel-jest "^27.5.1" - chalk "^4.0.0" - ci-info "^3.2.0" - deepmerge "^4.2.2" - glob "^7.1.1" - graceful-fs "^4.2.9" - jest-circus "^27.5.1" - jest-environment-jsdom "^27.5.1" - jest-environment-node "^27.5.1" - jest-get-type "^27.5.1" - jest-jasmine2 "^27.5.1" - jest-regex-util "^27.5.1" - jest-resolve "^27.5.1" - jest-runner "^27.5.1" - jest-util "^27.5.1" - jest-validate "^27.5.1" - micromatch "^4.0.4" - parse-json "^5.2.0" - pretty-format "^27.5.1" - slash "^3.0.0" - strip-json-comments "^3.1.1" - "jest-diff@>=29.4.3 < 30": version "29.6.1" resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.6.1.tgz#13df6db0a89ee6ad93c747c75c85c70ba941e545" @@ -9654,291 +9043,11 @@ jest-config@^27.5.1: jest-get-type "^29.4.3" pretty-format "^29.6.1" -jest-diff@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.5.1.tgz#a07f5011ac9e6643cf8a95a462b7b1ecf6680def" - integrity sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw== - dependencies: - chalk "^4.0.0" - diff-sequences "^27.5.1" - jest-get-type "^27.5.1" - pretty-format "^27.5.1" - -jest-docblock@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-27.5.1.tgz#14092f364a42c6108d42c33c8cf30e058e25f6c0" - integrity sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ== - dependencies: - detect-newline "^3.0.0" - -jest-each@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-27.5.1.tgz#5bc87016f45ed9507fed6e4702a5b468a5b2c44e" - integrity sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ== - dependencies: - "@jest/types" "^27.5.1" - chalk "^4.0.0" - jest-get-type "^27.5.1" - jest-util "^27.5.1" - pretty-format "^27.5.1" - -jest-environment-jsdom@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz#ea9ccd1fc610209655a77898f86b2b559516a546" - integrity sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw== - dependencies: - "@jest/environment" "^27.5.1" - "@jest/fake-timers" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/node" "*" - jest-mock "^27.5.1" - jest-util "^27.5.1" - jsdom "^16.6.0" - -jest-environment-node@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-27.5.1.tgz#dedc2cfe52fab6b8f5714b4808aefa85357a365e" - integrity sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw== - dependencies: - "@jest/environment" "^27.5.1" - "@jest/fake-timers" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/node" "*" - jest-mock "^27.5.1" - jest-util "^27.5.1" - -jest-get-type@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.5.1.tgz#3cd613c507b0f7ace013df407a1c1cd578bcb4f1" - integrity sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw== - jest-get-type@^29.4.3: version "29.4.3" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.4.3.tgz#1ab7a5207c995161100b5187159ca82dd48b3dd5" integrity sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg== -jest-haste-map@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-27.5.1.tgz#9fd8bd7e7b4fa502d9c6164c5640512b4e811e7f" - integrity sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng== - dependencies: - "@jest/types" "^27.5.1" - "@types/graceful-fs" "^4.1.2" - "@types/node" "*" - anymatch "^3.0.3" - fb-watchman "^2.0.0" - graceful-fs "^4.2.9" - jest-regex-util "^27.5.1" - jest-serializer "^27.5.1" - jest-util "^27.5.1" - jest-worker "^27.5.1" - micromatch "^4.0.4" - walker "^1.0.7" - optionalDependencies: - fsevents "^2.3.2" - -jest-jasmine2@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz#a037b0034ef49a9f3d71c4375a796f3b230d1ac4" - integrity sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ== - dependencies: - "@jest/environment" "^27.5.1" - "@jest/source-map" "^27.5.1" - "@jest/test-result" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/node" "*" - chalk "^4.0.0" - co "^4.6.0" - expect "^27.5.1" - is-generator-fn "^2.0.0" - jest-each "^27.5.1" - jest-matcher-utils "^27.5.1" - jest-message-util "^27.5.1" - jest-runtime "^27.5.1" - jest-snapshot "^27.5.1" - jest-util "^27.5.1" - pretty-format "^27.5.1" - throat "^6.0.1" - -jest-leak-detector@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz#6ec9d54c3579dd6e3e66d70e3498adf80fde3fb8" - integrity sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ== - dependencies: - jest-get-type "^27.5.1" - pretty-format "^27.5.1" - -jest-matcher-utils@^27.0.0, jest-matcher-utils@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz#9c0cdbda8245bc22d2331729d1091308b40cf8ab" - integrity sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw== - dependencies: - chalk "^4.0.0" - jest-diff "^27.5.1" - jest-get-type "^27.5.1" - pretty-format "^27.5.1" - -jest-message-util@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-27.5.1.tgz#bdda72806da10d9ed6425e12afff38cd1458b6cf" - integrity sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g== - dependencies: - "@babel/code-frame" "^7.12.13" - "@jest/types" "^27.5.1" - "@types/stack-utils" "^2.0.0" - chalk "^4.0.0" - graceful-fs "^4.2.9" - micromatch "^4.0.4" - pretty-format "^27.5.1" - slash "^3.0.0" - stack-utils "^2.0.3" - -jest-mock@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-27.5.1.tgz#19948336d49ef4d9c52021d34ac7b5f36ff967d6" - integrity sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og== - dependencies: - "@jest/types" "^27.5.1" - "@types/node" "*" - -jest-pnp-resolver@^1.2.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e" - integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== - -jest-regex-util@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.5.1.tgz#4da143f7e9fd1e542d4aa69617b38e4a78365b95" - integrity sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg== - -jest-resolve-dependencies@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz#d811ecc8305e731cc86dd79741ee98fed06f1da8" - integrity sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg== - dependencies: - "@jest/types" "^27.5.1" - jest-regex-util "^27.5.1" - jest-snapshot "^27.5.1" - -jest-resolve@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-27.5.1.tgz#a2f1c5a0796ec18fe9eb1536ac3814c23617b384" - integrity sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw== - dependencies: - "@jest/types" "^27.5.1" - chalk "^4.0.0" - graceful-fs "^4.2.9" - jest-haste-map "^27.5.1" - jest-pnp-resolver "^1.2.2" - jest-util "^27.5.1" - jest-validate "^27.5.1" - resolve "^1.20.0" - resolve.exports "^1.1.0" - slash "^3.0.0" - -jest-runner@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-27.5.1.tgz#071b27c1fa30d90540805c5645a0ec167c7b62e5" - integrity sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ== - dependencies: - "@jest/console" "^27.5.1" - "@jest/environment" "^27.5.1" - "@jest/test-result" "^27.5.1" - "@jest/transform" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/node" "*" - chalk "^4.0.0" - emittery "^0.8.1" - graceful-fs "^4.2.9" - jest-docblock "^27.5.1" - jest-environment-jsdom "^27.5.1" - jest-environment-node "^27.5.1" - jest-haste-map "^27.5.1" - jest-leak-detector "^27.5.1" - jest-message-util "^27.5.1" - jest-resolve "^27.5.1" - jest-runtime "^27.5.1" - jest-util "^27.5.1" - jest-worker "^27.5.1" - source-map-support "^0.5.6" - throat "^6.0.1" - -jest-runtime@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-27.5.1.tgz#4896003d7a334f7e8e4a53ba93fb9bcd3db0a1af" - integrity sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A== - dependencies: - "@jest/environment" "^27.5.1" - "@jest/fake-timers" "^27.5.1" - "@jest/globals" "^27.5.1" - "@jest/source-map" "^27.5.1" - "@jest/test-result" "^27.5.1" - "@jest/transform" "^27.5.1" - "@jest/types" "^27.5.1" - chalk "^4.0.0" - cjs-module-lexer "^1.0.0" - collect-v8-coverage "^1.0.0" - execa "^5.0.0" - glob "^7.1.3" - graceful-fs "^4.2.9" - jest-haste-map "^27.5.1" - jest-message-util "^27.5.1" - jest-mock "^27.5.1" - jest-regex-util "^27.5.1" - jest-resolve "^27.5.1" - jest-snapshot "^27.5.1" - jest-util "^27.5.1" - slash "^3.0.0" - strip-bom "^4.0.0" - -jest-serializer@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-27.5.1.tgz#81438410a30ea66fd57ff730835123dea1fb1f64" - integrity sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w== - dependencies: - "@types/node" "*" - graceful-fs "^4.2.9" - -jest-snapshot@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-27.5.1.tgz#b668d50d23d38054a51b42c4039cab59ae6eb6a1" - integrity sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA== - dependencies: - "@babel/core" "^7.7.2" - "@babel/generator" "^7.7.2" - "@babel/plugin-syntax-typescript" "^7.7.2" - "@babel/traverse" "^7.7.2" - "@babel/types" "^7.0.0" - "@jest/transform" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/babel__traverse" "^7.0.4" - "@types/prettier" "^2.1.5" - babel-preset-current-node-syntax "^1.0.0" - chalk "^4.0.0" - expect "^27.5.1" - graceful-fs "^4.2.9" - jest-diff "^27.5.1" - jest-get-type "^27.5.1" - jest-haste-map "^27.5.1" - jest-matcher-utils "^27.5.1" - jest-message-util "^27.5.1" - jest-util "^27.5.1" - natural-compare "^1.4.0" - pretty-format "^27.5.1" - semver "^7.3.2" - -jest-util@^27.0.0, jest-util@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.5.1.tgz#3ba9771e8e31a0b85da48fe0b0891fb86c01c2f9" - integrity sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw== - dependencies: - "@jest/types" "^27.5.1" - "@types/node" "*" - chalk "^4.0.0" - ci-info "^3.2.0" - graceful-fs "^4.2.9" - picomatch "^2.2.3" - jest-util@^29.5.0: version "29.5.0" resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.5.0.tgz#24a4d3d92fc39ce90425311b23c27a6e0ef16b8f" @@ -9963,32 +9072,7 @@ jest-util@^29.6.2: graceful-fs "^4.2.9" picomatch "^2.2.3" -jest-validate@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-27.5.1.tgz#9197d54dc0bdb52260b8db40b46ae668e04df067" - integrity sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ== - dependencies: - "@jest/types" "^27.5.1" - camelcase "^6.2.0" - chalk "^4.0.0" - jest-get-type "^27.5.1" - leven "^3.1.0" - pretty-format "^27.5.1" - -jest-watcher@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-27.5.1.tgz#71bd85fb9bde3a2c2ec4dc353437971c43c642a2" - integrity sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw== - dependencies: - "@jest/test-result" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/node" "*" - ansi-escapes "^4.2.1" - chalk "^4.0.0" - jest-util "^27.5.1" - string-length "^4.0.1" - -jest-worker@^27.4.5, jest-worker@^27.5.1: +jest-worker@^27.4.5: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== @@ -10017,15 +9101,6 @@ jest-worker@^29.4.3: merge-stream "^2.0.0" supports-color "^8.0.0" -jest@^27.4.7: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest/-/jest-27.5.1.tgz#dadf33ba70a779be7a6fc33015843b51494f63fc" - integrity sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ== - dependencies: - "@jest/core" "^27.5.1" - import-local "^3.0.2" - jest-cli "^27.5.1" - joi@^17.6.0: version "17.8.3" resolved "https://registry.yarnpkg.com/joi/-/joi-17.8.3.tgz#d772fe27a87a5cda21aace5cf11eee8671ca7e6f" @@ -10138,39 +9213,6 @@ jsdoc@^4.0.0: strip-json-comments "^3.1.0" underscore "~1.13.2" -jsdom@^16.6.0: - version "16.7.0" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710" - integrity sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw== - dependencies: - abab "^2.0.5" - acorn "^8.2.4" - acorn-globals "^6.0.0" - cssom "^0.4.4" - cssstyle "^2.3.0" - data-urls "^2.0.0" - decimal.js "^10.2.1" - domexception "^2.0.1" - escodegen "^2.0.0" - form-data "^3.0.0" - html-encoding-sniffer "^2.0.1" - http-proxy-agent "^4.0.1" - https-proxy-agent "^5.0.0" - is-potential-custom-element-name "^1.0.1" - nwsapi "^2.2.0" - parse5 "6.0.1" - saxes "^5.0.1" - symbol-tree "^3.2.4" - tough-cookie "^4.0.0" - w3c-hr-time "^1.0.2" - w3c-xmlserializer "^2.0.0" - webidl-conversions "^6.1.0" - whatwg-encoding "^1.0.5" - whatwg-mimetype "^2.3.0" - whatwg-url "^8.5.0" - ws "^7.4.6" - xml-name-validator "^3.0.0" - jsdom@^20.0.1: version "20.0.3" resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-20.0.3.tgz#886a41ba1d4726f67a8858028c99489fed6ad4db" @@ -10248,7 +9290,7 @@ json-stringify-safe@^5.0.1: resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== -json5@2.x, json5@^2.1.2, json5@^2.2.2: +json5@^2.1.2, json5@^2.2.2: version "2.2.3" resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== @@ -10583,7 +9625,7 @@ lodash.ismatch@^4.4.0: resolved "https://registry.yarnpkg.com/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz#756cb5150ca3ba6f11085a78849645f188f85f37" integrity sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g== -lodash.memoize@4.x, lodash.memoize@^4.1.2: +lodash.memoize@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== @@ -10608,7 +9650,7 @@ lodash.uniq@4.5.0, lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ== -lodash@^4.17.10, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0: +lodash@^4.17.10, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -10710,7 +9752,7 @@ make-dir@^2.1.0: pify "^4.0.1" semver "^5.6.0" -make-error@1.x, make-error@^1.1.1: +make-error@^1.1.1: version "1.3.6" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== @@ -10758,13 +9800,6 @@ make-fetch-happen@^11.0.0, make-fetch-happen@^11.0.1, make-fetch-happen@^11.1.1: socks-proxy-agent "^7.0.0" ssri "^10.0.0" -makeerror@1.0.12: - version "1.0.12" - resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" - integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== - dependencies: - tmpl "1.0.5" - map-obj@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" @@ -11202,11 +10237,6 @@ nanoid@^3.3.6: resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== - needle@^3.1.0: version "3.2.0" resolved "https://registry.yarnpkg.com/needle/-/needle-3.2.0.tgz#07d240ebcabfd65c76c03afae7f6defe6469df44" @@ -11284,11 +10314,6 @@ node-gyp@^9.0.0: tar "^6.1.2" which "^2.0.2" -node-int64@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" - integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== - node-machine-id@1.1.12: version "1.1.12" resolved "https://registry.yarnpkg.com/node-machine-id/-/node-machine-id-1.1.12.tgz#37904eee1e59b320bb9c5d6c0a59f3b469cb6267" @@ -11503,7 +10528,7 @@ nth-check@^2.0.1: dependencies: boolbase "^1.0.0" -nwsapi@^2.2.0, nwsapi@^2.2.2: +nwsapi@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.2.tgz#e5418863e7905df67d51ec95938d67bf801f0bb0" integrity sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw== @@ -11946,7 +10971,7 @@ parse-json@^4.0.0: error-ex "^1.3.1" json-parse-better-errors "^1.0.1" -parse-json@^5.0.0, parse-json@^5.2.0: +parse-json@^5.0.0: version "5.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== @@ -11993,7 +11018,7 @@ parse5@4.0.0: resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608" integrity sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA== -parse5@6.0.1, parse5@^6.0.0: +parse5@^6.0.0: version "6.0.1" resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== @@ -12137,11 +11162,6 @@ pinst@^2.1.6: dependencies: fromentries "^1.3.2" -pirates@^4.0.4: - version "4.0.5" - resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b" - integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ== - pkg-dir@^4.1.0, pkg-dir@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" @@ -12767,7 +11787,7 @@ pretty-error@^4.0.0: lodash "^4.17.20" renderkid "^3.0.0" -pretty-format@^27.0.0, pretty-format@^27.0.2, pretty-format@^27.5.1: +pretty-format@^27.0.2: version "27.5.1" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e" integrity sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ== @@ -12830,7 +11850,7 @@ promise@^7.1.1: dependencies: asap "~2.0.3" -prompts@^2.0.1, prompts@^2.4.2: +prompts@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== @@ -13627,12 +12647,7 @@ resolve-pathname@^3.0.0: resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd" integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng== -resolve.exports@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.1.tgz#05cfd5b3edf641571fd46fa608b610dda9ead999" - integrity sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ== - -resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.14.2, resolve@^1.20.0, resolve@^1.22.1, resolve@^1.3.2: +resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.14.2, resolve@^1.22.1, resolve@^1.3.2: version "1.22.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== @@ -13786,13 +12801,6 @@ sax@^1.2.4, sax@~1.2.4: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== -saxes@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" - integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== - dependencies: - xmlchars "^2.2.0" - saxes@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/saxes/-/saxes-6.0.0.tgz#fe5b4a4768df4f14a201b1ba6a65c1f3d9988cc5" @@ -13914,13 +12922,6 @@ semver@7.5.3: dependencies: lru-cache "^6.0.0" -semver@7.x, semver@^7.0.0, semver@^7.1.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8: - version "7.3.8" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" - integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== - dependencies: - lru-cache "^6.0.0" - semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" @@ -13931,6 +12932,13 @@ semver@^6.3.1: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== +semver@^7.0.0, semver@^7.1.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8: + version "7.3.8" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" + integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== + dependencies: + lru-cache "^6.0.0" + semver@~7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" @@ -14225,7 +13233,7 @@ source-map-support@0.5.19: buffer-from "^1.0.0" source-map "^0.6.0" -source-map-support@^0.5.6, source-map-support@~0.5.20: +source-map-support@~0.5.20: version "0.5.21" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== @@ -14345,13 +13353,6 @@ stable@^0.1.8: resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== -stack-utils@^2.0.3: - version "2.0.6" - resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" - integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== - dependencies: - escape-string-regexp "^2.0.0" - stackback@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/stackback/-/stackback-0.0.2.tgz#1ac8a0d9483848d1695e418b6d031a3c3ce68e3b" @@ -14401,14 +13402,6 @@ stream-via@^1.0.4: resolved "https://registry.yarnpkg.com/stream-via/-/stream-via-1.0.4.tgz#8dccbb0ac909328eb8bc8e2a4bd3934afdaf606c" integrity sha512-DBp0lSvX5G9KGRDTkR/R+a29H+Wk2xItOF+MpZLLNDWbEV9tGPnqLPxHEYjmiz8xGtJHRIqmI+hCjmNzqoA4nQ== -string-length@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" - integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== - dependencies: - char-regex "^1.0.2" - strip-ansi "^6.0.0" - "string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" @@ -14579,7 +13572,7 @@ supports-color@^5.3.0, supports-color@^5.5.0: dependencies: has-flag "^3.0.0" -supports-color@^7.0.0, supports-color@^7.1.0: +supports-color@^7.1.0: version "7.2.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== @@ -14593,14 +13586,6 @@ supports-color@^8.0.0: dependencies: has-flag "^4.0.0" -supports-hyperlinks@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz#3943544347c1ff90b15effb03fc14ae45ec10624" - integrity sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA== - dependencies: - has-flag "^4.0.0" - supports-color "^7.0.0" - supports-preserve-symlinks-flag@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" @@ -14724,14 +13709,6 @@ temp-path@^1.0.0: resolved "https://registry.yarnpkg.com/temp-path/-/temp-path-1.0.0.tgz#24b1543973ab442896d9ad367dd9cbdbfafe918b" integrity sha512-TvmyH7kC6ZVTYkqCODjJIbgvu0FKiwQpZ4D1aknE7xpcDf/qEOB8KZEK5ef2pfbVoiBhNWs3yx4y+ESMtNYmlg== -terminal-link@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" - integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ== - dependencies: - ansi-escapes "^4.2.1" - supports-hyperlinks "^2.0.0" - terser-webpack-plugin@^5.1.3, terser-webpack-plugin@^5.3.3: version "5.3.7" resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.7.tgz#ef760632d24991760f339fe9290deb936ad1ffc7" @@ -14774,15 +13751,6 @@ terser@^5.16.8: commander "^2.20.0" source-map-support "~0.5.20" -test-exclude@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" - integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== - dependencies: - "@istanbuljs/schema" "^0.1.2" - glob "^7.1.4" - minimatch "^3.0.4" - test-value@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/test-value/-/test-value-1.1.0.tgz#a09136f72ec043d27c893707c2b159bfad7de93f" @@ -14817,11 +13785,6 @@ text-table@^0.2.0: resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== -throat@^6.0.1: - version "6.0.2" - resolved "https://registry.yarnpkg.com/throat/-/throat-6.0.2.tgz#51a3fbb5e11ae72e2cf74861ed5c8020f89f29fe" - integrity sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ== - through2@^2.0.0: version "2.0.5" resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" @@ -14879,11 +13842,6 @@ tmp@~0.2.1: dependencies: rimraf "^3.0.0" -tmpl@1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" - integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== - to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" @@ -14923,7 +13881,7 @@ touch@^3.1.0: dependencies: nopt "~1.0.10" -tough-cookie@^4.0.0, tough-cookie@^4.1.2: +tough-cookie@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.2.tgz#e53e84b85f24e0b65dd526f46628db6c85f6b874" integrity sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ== @@ -14933,13 +13891,6 @@ tough-cookie@^4.0.0, tough-cookie@^4.1.2: universalify "^0.2.0" url-parse "^1.5.3" -tr46@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240" - integrity sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw== - dependencies: - punycode "^2.1.1" - tr46@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/tr46/-/tr46-3.0.0.tgz#555c4e297a950617e8eeddef633c87d4d9d6cbf9" @@ -14972,20 +13923,6 @@ trough@^1.0.0: resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406" integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA== -ts-jest@^27.1.2: - version "27.1.5" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-27.1.5.tgz#0ddf1b163fbaae3d5b7504a1e65c914a95cff297" - integrity sha512-Xv6jBQPoBEvBq/5i2TeSG9tt/nqkbpcurrEG1b+2yfBrcJelOZF9Ml6dmyMh7bcW9JyFbRYpR5rxROSlBLTZHA== - dependencies: - bs-logger "0.x" - fast-json-stable-stringify "2.x" - jest-util "^27.0.0" - json5 "2.x" - lodash.memoize "4.x" - make-error "1.x" - semver "7.x" - yargs-parser "20.x" - ts-loader@^9.3.1: version "9.4.4" resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-9.4.4.tgz#6ceaf4d58dcc6979f84125335904920884b7cee4" @@ -15059,7 +13996,7 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" -type-detect@4.0.8, type-detect@^4.0.0, type-detect@^4.0.5: +type-detect@^4.0.0, type-detect@^4.0.5: version "4.0.8" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== @@ -15124,7 +14061,7 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== -"typescript@>=3 < 6", typescript@^5.1.6: +"typescript@>=3 < 6": version "5.1.6" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.6.tgz#02f8ac202b6dad2c0dd5e0913745b47a37998274" integrity sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA== @@ -15134,6 +14071,11 @@ typescript@^4.6.3, typescript@^4.9.5: resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== +typescript@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78" + integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w== + typical@^2.4.2, typical@^2.6.0, typical@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/typical/-/typical-2.6.1.tgz#5c080e5d661cbbe38259d2e70a3c7253e873881d" @@ -15488,15 +14430,6 @@ v8-compile-cache@2.3.0: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== -v8-to-istanbul@^8.1.0: - version "8.1.1" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz#77b752fd3975e31bbcef938f85e9bd1c7a8d60ed" - integrity sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.1" - convert-source-map "^1.6.0" - source-map "^0.7.3" - validate-npm-package-license@3.0.4, validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" @@ -15621,20 +14554,6 @@ vlq@^1.0.0: resolved "https://registry.yarnpkg.com/vlq/-/vlq-1.0.1.tgz#c003f6e7c0b4c1edd623fd6ee50bbc0d6a1de468" integrity sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w== -w3c-hr-time@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" - integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== - dependencies: - browser-process-hrtime "^1.0.0" - -w3c-xmlserializer@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a" - integrity sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA== - dependencies: - xml-name-validator "^3.0.0" - w3c-xmlserializer@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz#aebdc84920d806222936e3cdce408e32488a3073" @@ -15663,13 +14582,6 @@ walk-back@^5.1.0: resolved "https://registry.yarnpkg.com/walk-back/-/walk-back-5.1.0.tgz#486d6f29e67f56ab89b952d987028bbb1a4e956c" integrity sha512-Uhxps5yZcVNbLEAnb+xaEEMdgTXl9qAQDzKYejG2AZ7qPwRQ81lozY9ECDbjLPNWm7YsO1IK5rsP1KoQzXAcGA== -walker@^1.0.7: - version "1.0.8" - resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" - integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== - dependencies: - makeerror "1.0.12" - watchpack@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d" @@ -15702,16 +14614,6 @@ webidl-conversions@^3.0.0: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== -webidl-conversions@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" - integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA== - -webidl-conversions@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" - integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== - webidl-conversions@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" @@ -15888,13 +14790,6 @@ websocket-extensions@>=0.1.1: resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== -whatwg-encoding@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" - integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== - dependencies: - iconv-lite "0.4.24" - whatwg-encoding@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz#e7635f597fd87020858626805a2729fa7698ac53" @@ -15907,11 +14802,6 @@ whatwg-fetch@^3.4.1: resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz#dced24f37f2624ed0281725d51d0e2e3fe677f8c" integrity sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA== -whatwg-mimetype@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" - integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== - whatwg-mimetype@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz#5fa1a7623867ff1af6ca3dc72ad6b8a4208beba7" @@ -15933,15 +14823,6 @@ whatwg-url@^5.0.0: tr46 "~0.0.3" webidl-conversions "^3.0.0" -whatwg-url@^8.0.0, whatwg-url@^8.5.0: - version "8.7.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77" - integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg== - dependencies: - lodash "^4.7.0" - tr46 "^2.1.0" - webidl-conversions "^6.1.0" - which-boxed-primitive@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" @@ -16119,7 +15000,7 @@ write-pkg@4.0.0: type-fest "^0.4.1" write-json-file "^3.2.0" -ws@^7.3.1, ws@^7.4.6: +ws@^7.3.1: version "7.5.9" resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== @@ -16141,11 +15022,6 @@ xml-js@^1.6.11: dependencies: sax "^1.2.4" -xml-name-validator@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" - integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== - xml-name-validator@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-4.0.0.tgz#79a006e2e63149a8600f15430f0a4725d1524835" @@ -16186,7 +15062,7 @@ yaml@^1.10.0, yaml@^1.10.2, yaml@^1.7.2: resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== -yargs-parser@20.2.4, yargs-parser@20.x, yargs-parser@^20.2.2, yargs-parser@^20.2.3: +yargs-parser@20.2.4, yargs-parser@^20.2.2, yargs-parser@^20.2.3: version "20.2.4" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== From 8f241ba204f9db20cc402c463e26d6174f9e6d2c Mon Sep 17 00:00:00 2001 From: Philippe Clesca Date: Fri, 8 Sep 2023 12:04:18 -0400 Subject: [PATCH 03/12] ok this basically works --- packages/plexus-core/src/action.ts | 23 +++-- packages/plexus-core/src/instance/runtime.ts | 3 +- packages/plexus-core/src/scope.ts | 27 +++--- packages/plexus-utils/src/shared/index.ts | 9 +- tests/action.test.ts | 12 +-- tests/efficiency.test.ts | 88 ++++++++---------- tests/test-utils.tsx | 2 +- tests/timed.test.ts | 98 ++++++++++---------- 8 files changed, 127 insertions(+), 135 deletions(-) diff --git a/packages/plexus-core/src/action.ts b/packages/plexus-core/src/action.ts index 3a21cadc..38973a67 100644 --- a/packages/plexus-core/src/action.ts +++ b/packages/plexus-core/src/action.ts @@ -111,21 +111,21 @@ export type InnerFunction = ResultFn extends ( // export type PlexusAction = (fn: FunctionType) => (...args: any) => ReturnData | Promise export type PlexusAction = typeof _action -export function _action( +export function _action( instance: () => PlexusInstance, - fn: (...args: FunctionArgs) => Response, + fn: ((...args: FunctionArgs) => Response) & Fn, batched?: boolean ): (...args: InnerFunctionArgs) => Response -export function _action( +export function _action( instance: () => PlexusInstance, - fn: (...args: FunctionArgs) => Promise, + fn: ((...args: FunctionArgs) => Promise) & Fn, batched?: boolean ): (...args: InnerFunctionArgs) => Promise -export function _action( +export function _action( instance: () => PlexusInstance, - fn: (...args: FunctionArgs) => Promise | Response, + fn: ((...args: FunctionArgs) => Promise | Response) & Fn, batched?: boolean ) { const helpers = new PlexusActionHelpers(instance) @@ -153,7 +153,6 @@ export function _action( }) } } - console.log('hewhewhewhewhewh', batched, args, 'hewhewhewhewhewh') // if the action is batched, run it in a batch if (batched) { return instance().runtime.batch(() => fn(helpers.hooks, ...args)) @@ -164,6 +163,7 @@ export function _action( // only return the error if there is no handler if (!helpers.catchError && !instance()._globalCatch) { + console.log('error caught but returning', e) if (e instanceof PlexusError) throw e if (e instanceof Error) { throw new PlexusError( @@ -172,6 +172,7 @@ export function _action( ) } } + console.log('error caught', e) helpers.runErrorHandlers(e) // otherwise run the handler and return null @@ -184,7 +185,7 @@ export function _action( } } // return the proxy function - return newAction + return newAction as InnerFunction // return proxyFn as InnerFunction // const newAction = async (...args) => { @@ -222,10 +223,12 @@ export function _action( * @param fn The Plexus action function to run * @returns The intended return value of fn, or null if an error is caught */ -export function action(fn: (...args: FunctionArgs) => Response) +export function action( + fn: (...args: FunctionArgs) => Response +): (...args: InnerFunctionArgs) => Response export function action( fn: (...args: FunctionArgs) => Promise -) +): (...args: InnerFunctionArgs) => Promise export function action( fn: (...args: FunctionArgs) => Promise | Response ) { diff --git a/packages/plexus-core/src/instance/runtime.ts b/packages/plexus-core/src/instance/runtime.ts index 0e2156c7..7e1705a3 100644 --- a/packages/plexus-core/src/instance/runtime.ts +++ b/packages/plexus-core/src/instance/runtime.ts @@ -238,12 +238,13 @@ export class RuntimeInstance { } // stop storing changes and emit the changes this.batching = false + const unhalt = this.engine.halt() // call all the pending functions and clear the array this.batchedCalls.forEach((pendingFn) => pendingFn()) this.batchedCalls.length = 0 // release the reactivity engine - // unhalt() + unhalt() this.instance().runtime.log('info', 'Batch function completed!') } diff --git a/packages/plexus-core/src/scope.ts b/packages/plexus-core/src/scope.ts index e3e99a89..8638c27d 100644 --- a/packages/plexus-core/src/scope.ts +++ b/packages/plexus-core/src/scope.ts @@ -26,10 +26,7 @@ export class Scope { // private _internalStore: PlexusScopeStore public instance: () => PlexusInstance - constructor( - public name: string, - config?: PlexusScopeConfig - ) { + constructor(public name: string, config?: PlexusScopeConfig) { if (!name || name.length === 0) { throw new Error('Scope name is required') } @@ -93,17 +90,17 @@ export class Scope { * @param fn The Plexus action function to run * @returns The intended return value of fn, or null if an error is caught */ - action(fn: Fn) { - return _action(this.instance, fn) - } - /** - * Generate a Plexus Action - * @param fn The Plexus action function to run - * @returns The intended return value of fn, or null if an error is caught - */ - batchAction(fn: Fn) { - return _action(this.instance, fn, true) - } + // action(fn: Fn) { + // return _action(this.instance, fn) + // } + // /** + // * Generate a Plexus Action + // * @param fn The Plexus action function to run + // * @returns The intended return value of fn, or null if an error is caught + // */ + // batchAction(fn: Fn) { + // return _action(this.instance, fn, true) + // } /** * Run a function. During that function's execution, any state changes will be batched and only applied once the function has finished. * @param fn The function to run in a batch diff --git a/packages/plexus-utils/src/shared/index.ts b/packages/plexus-utils/src/shared/index.ts index e74fe318..a048c50d 100644 --- a/packages/plexus-utils/src/shared/index.ts +++ b/packages/plexus-utils/src/shared/index.ts @@ -6,9 +6,12 @@ export const genUID = () => Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15) -export const isAsyncFunction = ( - fn: (...args: any[]) => ReturnedValue | Promise -): fn is () => Promise => +export const isAsyncFunction = < + ReturnedValue, + Args extends Array = any[] +>( + fn: (...args: Args) => ReturnedValue | Promise +): fn is (...args: Args) => Promise => typeof fn === 'function' && (fn.constructor.name === 'AsyncFunction' || fn[Symbol.toStringTag] === 'AsyncFunction') diff --git a/tests/action.test.ts b/tests/action.test.ts index 69976a56..96946b99 100644 --- a/tests/action.test.ts +++ b/tests/action.test.ts @@ -73,14 +73,14 @@ describe('Testing Action Function', () => { }) test(`Can handle async errors`, async () => { + let counter = 0 const myAction = action(async ({ onCatch }) => { - onCatch(() => { - console.log('error caught successfully!') - }) - return await new Promise((resolve, reject) => { - setTimeout(() => reject(new Error('test error')), 100) - }) + onCatch(console.error) + counter++ + if (counter === 2) throw new Error('test error') }) + + await myAction() const data = await myAction() expect(data).toBeDefined() }) diff --git a/tests/efficiency.test.ts b/tests/efficiency.test.ts index d4eabfce..3ef5c0bd 100644 --- a/tests/efficiency.test.ts +++ b/tests/efficiency.test.ts @@ -25,7 +25,7 @@ const users1kRelated = Array.from( id: randUuid(), firstName: randFirstName(), appointmentId: randUuid(), - }) as User + } as User) ) const appointments1kRelated = users1kRelated.map( @@ -35,7 +35,7 @@ const appointments1kRelated = users1kRelated.map( userId: user.id, date: randFutureDate().getTime(), name: randBook().title, - }) as Appointment + } as Appointment) ) // check the .cache directory for the generated data. If it doesn't exist, it will be generated. Need users1k.json, users10k.json, users10kRelated.json, appointments10kRelated.json @@ -51,52 +51,40 @@ afterEach(() => { }) describe('Efficiency tests for ', () => { - // test('The speed of a plexus collection collecting more than a thousand randomly generated objects into multiple groups', () => { - // instance({ logLevel: 'debug' }) - // console.log('Starting test...') - // console.log('items in collection:', users1k.length) - // usersLite.collect(users1k, ['firstNames']) - // console.log('items in collection:', usersLite.value.length) - // expect(usersLite.value.length).toBe(1000) - // expect(usersLite.groups.firstNames.value.length).toBe(1000) - // instance({ logLevel: undefined }) - // }) - // test('Testing the same as above but with an absurd amount of data', () => { - // instance({ logLevel: 'debug' }) - // console.log('Starting test...') - // console.log('items in collection:', users10k.length) - // usersLite.collect(users10k, ['firstNames']) - // console.log('items in collection:', usersLite.value.length) - // // const group1 = collectionInstance.group('appointmentId') - // // const group2 = collectionInstance.group('name') - // // expect(group1.value.length).toBe(1000) - // // expect(group2.value.length).toBe(1000) - // instance({ logLevel: undefined }) - // }) - // test('An absurd amount of related data', () => { - // instance({ logLevel: 'debug' }) - // console.log('Starting test...') - // console.log('items in collection:', users10k.length) - // users.collect(users1kRelated, ['main']) - // appointments.collect(appointments1kRelated, ['main']) - // console.log('items in collection:', users.value.length) - // // const group1 = collectionInstance.group('appointmentId') - // // const group2 = collectionInstance.group('name') - // // expect(group1.value.length).toBe(1000) - // // expect(group2.value.length).toBe(1000) - // instance({ logLevel: undefined }) - // }) - // test('An absurd amount of related data', () => { - // instance({ logLevel: 'debug' }) - // console.log('Starting test...') - // console.log('items in collection:', users10k.length) - // users.collect(users1kRelated, ['main']) - // appointments.collect(appointments1kRelated, ['main']) - // console.log('items in collection:', users.value.length) - // // const group1 = collectionInstance.group('appointmentId') - // // const group2 = collectionInstance.group('name') - // // expect(group1.value.length).toBe(1000) - // // expect(group2.value.length).toBe(1000) - // instance({ logLevel: undefined }) - // }) + test('The speed of a plexus collection collecting more than a thousand randomly generated objects into multiple groups', () => { + instance({ logLevel: 'debug' }) + console.log('Starting test...') + console.log('items in collection:', users1k.length) + usersLite.collect(users1k, ['firstNames']) + console.log('items in collection:', usersLite.value.length) + expect(usersLite.value.length).toBe(1000) + expect(usersLite.groups.firstNames.value.length).toBe(1000) + + instance({ logLevel: undefined }) + }) + test('Testing the same as above but with an absurd amount of data', () => { + instance({ logLevel: 'debug' }) + console.log('Starting test...') + console.log('items in collection:', users10k.length) + usersLite.collect(users10k, ['firstNames']) + console.log('items in collection:', usersLite.value.length) + // const group1 = collectionInstance.group('appointmentId') + // const group2 = collectionInstance.group('name') + // expect(group1.value.length).toBe(1000) + // expect(group2.value.length).toBe(1000) + instance({ logLevel: undefined }) + }) + test('An absurd amount of related data', () => { + instance({ logLevel: 'debug' }) + console.log('Starting test...') + console.log('items in collection:', users10k.length) + users.collect(users1kRelated, ['main']) + appointments.collect(appointments1kRelated, ['main']) + console.log('items in collection:', users.value.length) + // const group1 = collectionInstance.group('appointmentId') + // const group2 = collectionInstance.group('name') + // expect(group1.value.length).toBe(1000) + // expect(group2.value.length).toBe(1000) + instance({ logLevel: undefined }) + }) }) diff --git a/tests/test-utils.tsx b/tests/test-utils.tsx index db0670fb..0ec5b777 100644 --- a/tests/test-utils.tsx +++ b/tests/test-utils.tsx @@ -88,7 +88,7 @@ export const uniqueGroups = collection({ uniqueGroups: true, }).createSelector('batched') -export const DEFAULT_DECAY_RATE = 12_000 +export const DEFAULT_DECAY_RATE = 1_000 export const decayingUsers = collection({ primaryKey: 'userId', name: 'userslite', diff --git a/tests/timed.test.ts b/tests/timed.test.ts index 12768842..7e369dd6 100644 --- a/tests/timed.test.ts +++ b/tests/timed.test.ts @@ -1,53 +1,53 @@ -import { describe, test } from 'vitest' +import { describe, expect, test } from 'vitest' import { DEFAULT_DECAY_RATE, decayingUsers } from './test-utils' describe('Ephemeral Collection data', () => { - // test( - // 'Does decaying data work?', - // (ctx) => - // new Promise((resolve) => { - // decayingUsers.collect({ firstName: 'Bill', userId: '0' }) - // expect(decayingUsers.value.length).toBe(1) - // expect(decayingUsers.value[0].firstName).toBe('Bill') - // expect(decayingUsers.value[0].userId).toBe('0') - // setTimeout(() => { - // expect(decayingUsers.value.length).toBe(0) - // console.log('done! Thing is decayed!') - // resolve(true) - // }, DEFAULT_DECAY_RATE + 10) - // }), - // DEFAULT_DECAY_RATE + 100 - // ) - // test( - // 'Does decaying data refresh on set?', - // (ctx) => - // new Promise((resolve) => { - // decayingUsers.collect({ firstName: 'Bill', userId: '0' }) - // expect(decayingUsers.value.length).toBe(1) - // expect(decayingUsers.value[0].firstName).toBe('Bill') - // expect(decayingUsers.value[0].userId).toBe('0') - // // recollecting should reset the decay timer - // setTimeout(() => { - // expect(decayingUsers.value.length).toBe(1) - // decayingUsers.collect({ firstName: 'Bill', userId: '0' }) - // }, DEFAULT_DECAY_RATE - 10) - // // so if we wait a bit, it should still be there - // setTimeout(() => { - // console.log('wtfff') - // expect(decayingUsers.value.length).toBe(1) - // }, DEFAULT_DECAY_RATE + 10) - // // and then it should decay past the decay rate - // setTimeout( - // () => { - // expect(decayingUsers.value.length).toBe(0) - // console.log('done! Thing is decayed!') - // resolve(true) - // }, - // DEFAULT_DECAY_RATE * 2 + 10 - // ) - // }), - // { - // timeout: DEFAULT_DECAY_RATE * 2 + 100, - // } - // ) + test( + 'Does decaying data work?', + (ctx) => + new Promise((resolve) => { + decayingUsers.collect({ firstName: 'Bill', userId: '0' }) + expect(decayingUsers.value.length).toBe(1) + expect(decayingUsers.value[0].firstName).toBe('Bill') + expect(decayingUsers.value[0].userId).toBe('0') + setTimeout(() => { + expect(decayingUsers.value.length).toBe(0) + console.log('done! Thing is decayed!') + resolve(true) + }, DEFAULT_DECAY_RATE + 10) + }), + DEFAULT_DECAY_RATE + 100 + ) + test( + 'Does decaying data refresh on set?', + (ctx) => + new Promise((resolve) => { + decayingUsers.collect({ firstName: 'Bill', userId: '0' }) + expect(decayingUsers.value.length).toBe(1) + expect(decayingUsers.value[0].firstName).toBe('Bill') + expect(decayingUsers.value[0].userId).toBe('0') + // recollecting should reset the decay timer + setTimeout(() => { + expect(decayingUsers.value.length).toBe(1) + decayingUsers.collect({ firstName: 'Bill', userId: '0' }) + }, DEFAULT_DECAY_RATE - 10) + // so if we wait a bit, it should still be there + setTimeout(() => { + console.log('wtfff') + expect(decayingUsers.value.length).toBe(1) + }, DEFAULT_DECAY_RATE + 10) + // and then it should decay past the decay rate + setTimeout( + () => { + expect(decayingUsers.value.length).toBe(0) + console.log('done! Thing is decayed!') + resolve(true) + }, + DEFAULT_DECAY_RATE * 2 + 10 + ) + }), + { + timeout: DEFAULT_DECAY_RATE * 2 + 100, + } + ) }) From 6861f779b3bbc55a2728ee348c31b3af4b684204 Mon Sep 17 00:00:00 2001 From: Philippe Clesca Date: Fri, 8 Sep 2023 13:21:34 -0400 Subject: [PATCH 04/12] fix problems with actions --- docs/docs/api-reference/Scope.mdx | 26 ------- docs/docs/api-reference/action.mdx | 12 --- docs/docs/api-reference/batchAction.mdx | 12 --- packages/plexus-core/src/action.ts | 77 +++++++------------ .../plexus-core/src/collection/collection.ts | 6 +- packages/plexus-core/src/index.ts | 2 +- packages/plexus-core/src/preaction.ts | 23 +++--- packages/plexus-core/src/scope.ts | 4 +- packages/plexus-react/src/useLoader.ts | 8 +- packages/plexus-utils/src/shared/index.ts | 2 +- tests/edgecases.test.tsx | 5 +- tests/efficiency.test.ts | 71 +++++++++-------- 12 files changed, 85 insertions(+), 163 deletions(-) diff --git a/docs/docs/api-reference/Scope.mdx b/docs/docs/api-reference/Scope.mdx index 5eba5d6b..40fec2fd 100644 --- a/docs/docs/api-reference/Scope.mdx +++ b/docs/docs/api-reference/Scope.mdx @@ -11,8 +11,6 @@ Create a new PlexusJS plugin - [.computed(item)](#Scope+computed) ⇒ - [.event()](#Scope+event) ⇒ - [.collection(config)](#Scope+collection) ⇒ - - [.action(fn)](#Scope+action) ⇒ - - [.batchAction(fn)](#Scope+batchAction) ⇒ - [.batch(fn)](#Scope+batch) - [.preaction(fn)](#Scope+preaction) ⇒ @@ -60,30 +58,6 @@ Create a new PlexusJS plugin | ------ | ------------------------------------------- | | config |

The configuration for the collection

| - - -### .action(fn) ⇒ - -

Generate a Plexus Action

- -**Returns**:

The intended return value of fn, or null if an error is caught

- -| Param | Description | -| ----- | ---------------------------------------- | -| fn |

The Plexus action function to run

| - - - -### .batchAction(fn) ⇒ - -

Generate a Plexus Action

- -**Returns**:

The intended return value of fn, or null if an error is caught

- -| Param | Description | -| ----- | ---------------------------------------- | -| fn |

The Plexus action function to run

| - ### .batch(fn) diff --git a/docs/docs/api-reference/action.mdx b/docs/docs/api-reference/action.mdx index e2163a0d..f91df733 100644 --- a/docs/docs/api-reference/action.mdx +++ b/docs/docs/api-reference/action.mdx @@ -17,15 +17,3 @@ Generate a Plexus Action | Param | Description | | ----- | ---------------------------------------- | | fn |

The Plexus action function to run

| - - - -## .action(fn) ⇒ - -

Generate a Plexus Action

- -**Returns**:

The intended return value of fn, or null if an error is caught

- -| Param | Description | -| ----- | ---------------------------------------- | -| fn |

The Plexus action function to run

| diff --git a/docs/docs/api-reference/batchAction.mdx b/docs/docs/api-reference/batchAction.mdx index c96274fd..11f36fb6 100644 --- a/docs/docs/api-reference/batchAction.mdx +++ b/docs/docs/api-reference/batchAction.mdx @@ -17,15 +17,3 @@ Generate a Plexus Action | Param | Description | | ----- | ---------------------------------------- | | fn |

The Plexus action function to run

| - - - -## .batchAction(fn) ⇒ - -

Generate a Plexus Action

- -**Returns**:

The intended return value of fn, or null if an error is caught

- -| Param | Description | -| ----- | ---------------------------------------- | -| fn |

The Plexus action function to run

| diff --git a/packages/plexus-core/src/action.ts b/packages/plexus-core/src/action.ts index 38973a67..7fbd4029 100644 --- a/packages/plexus-core/src/action.ts +++ b/packages/plexus-core/src/action.ts @@ -11,6 +11,23 @@ export interface PlexusActionHooks { ignoreInit(): void batch(fn: () => ReturnType): ReturnType } +export type ActionFunction< + Params extends any[] | [] = any[], + Response = any +> = ( + helpers: PlexusActionHooks, + ...args: Params +) => Response | Promise + +export type InnerFunction = InputFn extends ( + helpers: PlexusActionHooks, + ...args: infer Params +) => ReturnType + ? (...args: Params) => ReturnType + : never + +export type PlexusAction = typeof _action + /** * The action helpers for a defined plexus action */ @@ -94,40 +111,11 @@ class PlexusActionHelpers { } } -export type FunctionArgs = [helpers: PlexusActionHooks, ...args: any[]] -export type InnerFunctionArgs = [helpers?: PlexusActionHooks, ...args: any[]] - -export type FunctionType = ( - ...args: FunctionArgs -) => Response | Promise - -export type InnerFunction = ResultFn extends ( - helpers: PlexusActionHooks, - ...args: infer Params -) => ReturnType - ? (...args: Params) => ReturnType - : never - -// export type PlexusAction = (fn: FunctionType) => (...args: any) => ReturnData | Promise -export type PlexusAction = typeof _action - -export function _action( - instance: () => PlexusInstance, - fn: ((...args: FunctionArgs) => Response) & Fn, - batched?: boolean -): (...args: InnerFunctionArgs) => Response - -export function _action( - instance: () => PlexusInstance, - fn: ((...args: FunctionArgs) => Promise) & Fn, - batched?: boolean -): (...args: InnerFunctionArgs) => Promise - -export function _action( +export function _action( instance: () => PlexusInstance, - fn: ((...args: FunctionArgs) => Promise | Response) & Fn, + fn: Fn & ((helpers: PlexusActionHooks, ...args: any[]) => Returns), batched?: boolean -) { +): InnerFunction { const helpers = new PlexusActionHelpers(instance) console.log('function constructor', fn.constructor.name, isAsyncFunction(fn)) @@ -185,8 +173,7 @@ export function _action( } } // return the proxy function - return newAction as InnerFunction - // return proxyFn as InnerFunction + return newAction as InnerFunction // const newAction = async (...args) => { // try { @@ -223,16 +210,8 @@ export function _action( * @param fn The Plexus action function to run * @returns The intended return value of fn, or null if an error is caught */ -export function action( - fn: (...args: FunctionArgs) => Response -): (...args: InnerFunctionArgs) => Response -export function action( - fn: (...args: FunctionArgs) => Promise -): (...args: InnerFunctionArgs) => Promise -export function action( - fn: (...args: FunctionArgs) => Promise | Response -) { - return _action(() => instance(), fn) +export function action(fn: Fn): InnerFunction { + return _action(() => instance(), fn) as InnerFunction } /** @@ -240,12 +219,8 @@ export function action( * @param fn The Plexus action function to run * @returns The intended return value of fn, or null if an error is caught */ -export function batchAction(fn: (...args: FunctionArgs) => Response) -export function batchAction( - fn: (...args: FunctionArgs) => Promise -) -export function batchAction( - fn: (...args: FunctionArgs) => Promise | Response -) { +export function batchAction( + fn: Fn +): InnerFunction { return _action(() => instance(), fn, true) } diff --git a/packages/plexus-core/src/collection/collection.ts b/packages/plexus-core/src/collection/collection.ts index 2642e1f1..329352df 100644 --- a/packages/plexus-core/src/collection/collection.ts +++ b/packages/plexus-core/src/collection/collection.ts @@ -105,7 +105,7 @@ interface PlexusCollectionStore> { export type PlexusCollectionInstance< DataType extends Record = Record, Groups extends GroupMap = GroupMap, - Selectors extends SelectorMap = SelectorMap + Selectors extends SelectorMap = SelectorMap, > = CollectionInstance /** * A Collection Instance @@ -114,7 +114,7 @@ export type PlexusCollectionInstance< export class CollectionInstance< DataTypeInput extends Record, Groups extends GroupMap, - Selectors extends SelectorMap + Selectors extends SelectorMap, // ForeignRefs extends boolean = this['config']['foreignKeys'] extends {} ? true : false > { private _internalStore: PlexusCollectionStore @@ -1078,7 +1078,7 @@ export class CollectionInstance< export function _collection< DataType extends { [key: string]: any }, Groups extends GroupMap = GroupMap, - Selectors extends SelectorMap = SelectorMap + Selectors extends SelectorMap = SelectorMap, >( instance: () => PlexusInstance, _config: PlexusCollectionConfig = { primaryKey: 'id' } as const diff --git a/packages/plexus-core/src/index.ts b/packages/plexus-core/src/index.ts index 8a60c738..b30e505a 100644 --- a/packages/plexus-core/src/index.ts +++ b/packages/plexus-core/src/index.ts @@ -14,7 +14,7 @@ export { PlexusWatchableValueInterpreter } from '@plexusjs/utils' export { action, _action, - FunctionType, + ActionFunction as FunctionType, PlexusAction, PlexusActionHooks, batchAction, diff --git a/packages/plexus-core/src/preaction.ts b/packages/plexus-core/src/preaction.ts index 48bc69c7..aa518470 100644 --- a/packages/plexus-core/src/preaction.ts +++ b/packages/plexus-core/src/preaction.ts @@ -1,8 +1,8 @@ import { PlexusInstance, instance } from './instance/instance' import { - FunctionArgs, - FunctionType, - InnerFunctionArgs, + // FunctionArgs, + ActionFunction, + // InnerFunctionArgs, _action, } from './action' import { genUID } from '@plexusjs/utils' @@ -11,7 +11,7 @@ type ErrorHandler = (error: any) => unknown export interface PlexusPreActionConfig { lazy?: boolean } -export class PreActionInstance { +export class PreActionInstance { private _internalStore = { _ran: false, _id: genUID(), @@ -20,7 +20,7 @@ export class PreActionInstance { /** * The action associated with this PreAction */ - action: (...args: InnerFunctionArgs) => Promise | Response + action: ReturnType /** * The internal id of the PreAction */ @@ -30,7 +30,7 @@ export class PreActionInstance { constructor( private instance: () => PlexusInstance, - fn: (...args: FunctionArgs) => Response | Promise, + fn: Fn, config: PlexusPreActionConfig = {} ) { this.action = _action(instance, fn) @@ -65,14 +65,15 @@ export class PreActionInstance { return result } } -export type PlexusPreAction = PreActionInstance +export type PlexusPreAction = + PreActionInstance -export function _preaction( +export function _preaction( instance: () => PlexusInstance, - fn: (...args: FunctionArgs) => Response | Promise, + fn: Fn, config?: PlexusPreActionConfig ) { - return new PreActionInstance(instance, fn, config) + return new PreActionInstance(instance, fn, config) } /** @@ -80,7 +81,7 @@ export function _preaction( * @param fn The Plexus action function to run * @returns The intended return value of fn, or null if an error is caught */ -export function preaction( +export function preaction( fn: Fn, config?: PlexusPreActionConfig ) { diff --git a/packages/plexus-core/src/scope.ts b/packages/plexus-core/src/scope.ts index 8638c27d..8bf5bdc8 100644 --- a/packages/plexus-core/src/scope.ts +++ b/packages/plexus-core/src/scope.ts @@ -1,6 +1,6 @@ import { AlmostAnything, LiteralType, TypeOrReturnType } from '@plexusjs/utils' import { Watchable } from '.' -import { FunctionType, _action } from './action' +import { ActionFunction, _action } from './action' import { PlexusCollectionConfig, _collection } from './collection/collection' import { _computed } from './computed' import { _event } from './event' @@ -115,7 +115,7 @@ export class Scope { * @param fn The Plexus action function to run * @returns The intended return value of fn, or null if an error is caught */ - preaction(fn: Fn, config?: PlexusPreActionConfig) { + preaction(fn: Fn, config?: PlexusPreActionConfig) { return _preaction(this.instance, fn, config) } } diff --git a/packages/plexus-react/src/useLoader.ts b/packages/plexus-react/src/useLoader.ts index c2ff8982..1190017d 100644 --- a/packages/plexus-react/src/useLoader.ts +++ b/packages/plexus-react/src/useLoader.ts @@ -1,5 +1,5 @@ import { PlexusAction, Watchable } from '@plexusjs/core' -import { FunctionType, InnerFunction } from '@plexusjs/core/dist/action' +import { ActionFunction, InnerFunction } from '@plexusjs/core/dist/action' import { useEffect, useState } from 'react' import { usePlexus, PlexusValue, PlexusValueArray } from './usePlexus' @@ -17,19 +17,19 @@ export type PlexusLoaderOptions = { } // Singleton argument -export function useLoader( +export function useLoader( watchables: V, action: InnerFunction, options?: PlexusLoaderOptions ): PlexusLoaderReturn> // array argument -export function useLoader( +export function useLoader( watchables: V | [], action: InnerFunction, options?: PlexusLoaderOptions ): PlexusLoaderReturn> -export function useLoader( +export function useLoader( watchables: (typeof usePlexus.arguments)[0], action: InnerFunction, options?: PlexusLoaderOptions diff --git a/packages/plexus-utils/src/shared/index.ts b/packages/plexus-utils/src/shared/index.ts index a048c50d..79c91211 100644 --- a/packages/plexus-utils/src/shared/index.ts +++ b/packages/plexus-utils/src/shared/index.ts @@ -8,7 +8,7 @@ export const genUID = () => export const isAsyncFunction = < ReturnedValue, - Args extends Array = any[] + Args extends Array = any[], >( fn: (...args: Args) => ReturnedValue | Promise ): fn is (...args: Args) => Promise => diff --git a/tests/edgecases.test.tsx b/tests/edgecases.test.tsx index 79fdafea..3f2ec3f4 100644 --- a/tests/edgecases.test.tsx +++ b/tests/edgecases.test.tsx @@ -56,7 +56,6 @@ describe('Collection Relations', () => { resolve('') }, 500) }) - }) // return new Promise((resolve) => { // setTimeout(() => { @@ -64,10 +63,8 @@ describe('Collection Relations', () => { // resolve(val) // }, 500) // }) - }) - // the related collection value state should be undefined or something because the batch function hasn't finished yet expect(users.getItemValue('1')?.firstName).toBeFalsy() @@ -92,7 +89,7 @@ describe('Collection Relations', () => { ) test('Batching race condition with selectors', () => { - batch(() => { }) + batch(() => {}) }) }) diff --git a/tests/efficiency.test.ts b/tests/efficiency.test.ts index 3ef5c0bd..e040292a 100644 --- a/tests/efficiency.test.ts +++ b/tests/efficiency.test.ts @@ -51,40 +51,39 @@ afterEach(() => { }) describe('Efficiency tests for ', () => { - test('The speed of a plexus collection collecting more than a thousand randomly generated objects into multiple groups', () => { - instance({ logLevel: 'debug' }) - console.log('Starting test...') - console.log('items in collection:', users1k.length) - usersLite.collect(users1k, ['firstNames']) - console.log('items in collection:', usersLite.value.length) - expect(usersLite.value.length).toBe(1000) - expect(usersLite.groups.firstNames.value.length).toBe(1000) - - instance({ logLevel: undefined }) - }) - test('Testing the same as above but with an absurd amount of data', () => { - instance({ logLevel: 'debug' }) - console.log('Starting test...') - console.log('items in collection:', users10k.length) - usersLite.collect(users10k, ['firstNames']) - console.log('items in collection:', usersLite.value.length) - // const group1 = collectionInstance.group('appointmentId') - // const group2 = collectionInstance.group('name') - // expect(group1.value.length).toBe(1000) - // expect(group2.value.length).toBe(1000) - instance({ logLevel: undefined }) - }) - test('An absurd amount of related data', () => { - instance({ logLevel: 'debug' }) - console.log('Starting test...') - console.log('items in collection:', users10k.length) - users.collect(users1kRelated, ['main']) - appointments.collect(appointments1kRelated, ['main']) - console.log('items in collection:', users.value.length) - // const group1 = collectionInstance.group('appointmentId') - // const group2 = collectionInstance.group('name') - // expect(group1.value.length).toBe(1000) - // expect(group2.value.length).toBe(1000) - instance({ logLevel: undefined }) - }) + // test('The speed of a plexus collection collecting more than a thousand randomly generated objects into multiple groups', () => { + // // instance({ logLevel: 'debug' }) + // console.log('Starting test...') + // console.log('items in collection:', users1k.length) + // usersLite.collect(users1k, ['firstNames']) + // console.log('items in collection:', usersLite.value.length) + // expect(usersLite.value.length).toBe(1000) + // expect(usersLite.groups.firstNames.value.length).toBe(1000) + // // instance({ logLevel: undefined }) + // }) + // test('Testing the same as above but with an absurd amount of data', () => { + // // instance({ logLevel: 'debug' }) + // console.log('Starting test...') + // console.log('items in collection:', users10k.length) + // usersLite.collect(users10k, ['firstNames']) + // console.log('items in collection:', usersLite.value.length) + // // const group1 = collectionInstance.group('appointmentId') + // // const group2 = collectionInstance.group('name') + // // expect(group1.value.length).toBe(1000) + // // expect(group2.value.length).toBe(1000) + // // instance({ logLevel: undefined }) + // }) + // test('An absurd amount of related data', () => { + // // instance({ logLevel: 'debug' }) + // console.log('Starting test...') + // console.log('items in collection:', users10k.length) + // users.collect(users1kRelated, ['main']) + // appointments.collect(appointments1kRelated, ['main']) + // console.log('items in collection:', users.value.length) + // // const group1 = collectionInstance.group('appointmentId') + // // const group2 = collectionInstance.group('name') + // // expect(group1.value.length).toBe(1000) + // // expect(group2.value.length).toBe(1000) + // // instance({ logLevel: undefined }) + // }) }) From 3e7eaa4807001e628a4b52fb0ba750af289e92c3 Mon Sep 17 00:00:00 2001 From: Philippe Clesca Date: Fri, 8 Sep 2023 13:33:09 -0400 Subject: [PATCH 05/12] maybe? --- packages/plexus-core/src/action.ts | 3 +-- tests/action.test.ts | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/plexus-core/src/action.ts b/packages/plexus-core/src/action.ts index 7fbd4029..fb31a6be 100644 --- a/packages/plexus-core/src/action.ts +++ b/packages/plexus-core/src/action.ts @@ -169,11 +169,10 @@ export function _action( 'An error occurred during the execution of an action', { origin: 'action' } ) - return } } // return the proxy function - return newAction as InnerFunction + return newAction as InnerFunction // const newAction = async (...args) => { // try { diff --git a/tests/action.test.ts b/tests/action.test.ts index 96946b99..a7384f92 100644 --- a/tests/action.test.ts +++ b/tests/action.test.ts @@ -69,6 +69,7 @@ describe('Testing Action Function', () => { ) }) const data = await myAction() + console.log(data) expect(data).toBe(successMsg) }) @@ -80,7 +81,7 @@ describe('Testing Action Function', () => { if (counter === 2) throw new Error('test error') }) - await myAction() + myAction() const data = await myAction() expect(data).toBeDefined() }) From f3012847ac8c43e50d95f236fc4b046fd9b74a2f Mon Sep 17 00:00:00 2001 From: Philippe Clesca Date: Fri, 8 Sep 2023 17:21:40 -0400 Subject: [PATCH 06/12] revamped actions --- packages/plexus-core/src/action.ts | 135 +++++++++++++---------------- 1 file changed, 60 insertions(+), 75 deletions(-) diff --git a/packages/plexus-core/src/action.ts b/packages/plexus-core/src/action.ts index fb31a6be..32961689 100644 --- a/packages/plexus-core/src/action.ts +++ b/packages/plexus-core/src/action.ts @@ -1,14 +1,24 @@ import { isAsyncFunction } from '@plexusjs/utils' import { PlexusInstance, instance } from './instance/instance' -import { PlexusError } from './error' +import { PlexusError, handlePlexusError } from './error' type ErrorHandler = (error: any) => unknown export interface PlexusActionHooks { + /** + * Add a new error handler for this action. This will catch any errors that occur during the execution of this action and prevent a crash. + * @param handler? A function that will be called when an error occurs; omit to fail silently. + * @param {boolean}useGlobal Should the global error handler be used? (default: true) + * + */ onCatch(handler?: ErrorHandler, useGlobal?: boolean): void /** * Ignore the default hault preActions */ ignoreInit(): void + /** + * Run a function. During that function's execution, any state changes will be batched and only applied once the function has finished. + * @param fn The function to run in a batch + */ batch(fn: () => ReturnType): ReturnType } export type ActionFunction< @@ -89,21 +99,12 @@ class PlexusActionHelpers { */ get hooks(): PlexusActionHooks { return { - /** - * Add a new error handler for this action. This will catch any errors that occur during the execution of this action and prevent a crash. - * @param handler? A function that will be called when an error occurs; omit to fail silently. - * - */ onCatch: (handler?: ErrorHandler, useGlobal = true): void => { return this.onCatch(handler, useGlobal) }, ignoreInit: (): void => { return this.ignoreInit() }, - /** - * Run a function. During that function's execution, any state changes will be batched and only applied once the function has finished. - * @param fn The function to run in a batch - */ batch: (batchFn: () => BatchResponse): BatchResponse => { return this.instance().runtime.batch(batchFn) }, @@ -118,8 +119,6 @@ export function _action( ): InnerFunction { const helpers = new PlexusActionHelpers(instance) - console.log('function constructor', fn.constructor.name, isAsyncFunction(fn)) - if (typeof fn !== 'function') { console.warn( '%cPlexus WARN:%c An action must be of type Function.', @@ -128,80 +127,66 @@ export function _action( ) throw new Error('An action must be of type Function.') } - + /** + * if the instance is not ready, wait for it to be + * */ + const runInit = () => { + if (!instance().ready && !helpers._skipInit) { + if (isAsyncFunction(fn)) { + // async call; just return the promise + return instance().runtime.runInit() + } + // sync call + let hold = true + while (hold) { + instance().runtime.runInit(() => { + hold = false + }) + } + } + } + // we NEED this conditional. I tried to make this fit into one function definition instead of two, but it didn't work; async error catching flops for some reason. + if (isAsyncFunction(fn)) { + return async function newAction(...args) { + try { + await runInit() + // if the action is batched, run it in a batch + return batched + ? await instance().runtime.batch( + async () => await fn(helpers.hooks, ...args) + ) + : await fn(helpers.hooks, ...args) + } catch (e) { + // only return the error if there is no handler + if (!helpers.catchError && !instance()._globalCatch) { + throw handlePlexusError(e) + } + helpers.runErrorHandlers(e) + // otherwise run the handler + return handlePlexusError(e) + } + } as InnerFunction + } function newAction(...args) { try { // if the instance is not ready, wait for it to be - // !NOTE: this is probably not a good way to do this, but it works for now - if (!instance().ready && !helpers._skipInit) { - let hold = true - while (hold) { - instance().runtime.runInit(() => { - hold = false - }) - } - } - // if the action is batched, run it in a batch - if (batched) { - return instance().runtime.batch(() => fn(helpers.hooks, ...args)) - } - // run the function - return fn(helpers.hooks, ...args) + runInit() + // if the action is batched, run it in a batch; otherwise run it normally + return batched + ? instance().runtime.batch(() => fn(helpers.hooks, ...args)) + : fn(helpers.hooks, ...args) } catch (e) { // only return the error if there is no handler - if (!helpers.catchError && !instance()._globalCatch) { - console.log('error caught but returning', e) - if (e instanceof PlexusError) throw e - if (e instanceof Error) { - throw new PlexusError( - `An error occurred during the execution of an action (${e.message})`, - { origin: 'action', stack: e.stack } - ) - } + throw handlePlexusError(e) } - console.log('error caught', e) helpers.runErrorHandlers(e) - - // otherwise run the handler and return null - // TODO: return a PlexusError; needs to be a package wide change - return new PlexusError( - 'An error occurred during the execution of an action', - { origin: 'action' } - ) + // otherwise run the handler + return handlePlexusError(e) } } // return the proxy function return newAction as InnerFunction - - // const newAction = async (...args) => { - // try { - // // if the instance is not ready, wait for it to be - // if (!instance().ready && !helpers._skipInit) { - // await instance().runtime.runInit() - // } - // // if the action is batched, run it in a batch - // console.log('(async)hewhewhewhewhewh', batched, 'hewhewhewhewhewh') - // if (batched) { - // console.log('using a batch in an async action...') - // return instance().runtime.batch(async () => { - // console.log('running the async action in a batch') - // return await fn(helpers.hooks, ...args) - // }) - // } - // // run the function - // return await fn(helpers.hooks, ...args) - // } catch (e) { - // // only return the error if there is no handler - // if (!helpers.catchError && !instance()._globalCatch) throw e - // helpers.runErrorHandlers(e) - // // otherwise run the handler and return null - // return null - // } - // } - // // return the proxy function - // return newAction as InnerFunction - // // return proxyFn as InnerFunction } /** @@ -210,7 +195,7 @@ export function _action( * @returns The intended return value of fn, or null if an error is caught */ export function action(fn: Fn): InnerFunction { - return _action(() => instance(), fn) as InnerFunction + return _action(() => instance(), fn) } /** From d51c497491828119d5a345d9e8c0d651791d1782 Mon Sep 17 00:00:00 2001 From: Philippe Clesca Date: Fri, 8 Sep 2023 17:21:51 -0400 Subject: [PATCH 07/12] plexus errors --- packages/plexus-core/src/error.ts | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/packages/plexus-core/src/error.ts b/packages/plexus-core/src/error.ts index 86cf47b7..4d8cc01a 100644 --- a/packages/plexus-core/src/error.ts +++ b/packages/plexus-core/src/error.ts @@ -1,3 +1,5 @@ +import { PlexusInstance } from './instance/instance' + export class PlexusError extends Error { public name = 'PlexusError' public error = true @@ -12,3 +14,25 @@ export class PlexusError extends Error { return `PlexusError: ${this.message} (${this.options?.code ?? 'NO_CODE'})` } } +export function handlePlexusError(e: unknown | Error | string): PlexusError { + if (typeof e === 'string') { + return new PlexusError(e) + } + + // error-like objects + if (e instanceof PlexusError) return e + if (e instanceof Error) { + return new PlexusError( + `An error occurred during the execution of an action (${e.message})`, + { origin: 'action', stack: e.stack } + ) + } + + // generic error + return new PlexusError( + 'An error occurred during the execution of an action', + { + origin: 'action', + } + ) +} From 769571239599b416d969f2deac40910a28cbad9c Mon Sep 17 00:00:00 2001 From: Philippe Clesca Date: Fri, 8 Sep 2023 17:35:10 -0400 Subject: [PATCH 08/12] Everything works --- .../plexus-core/src/collection/collection.ts | 39 +++++----- packages/plexus-core/src/collection/group.ts | 6 +- packages/plexus-core/src/instance/engine.ts | 44 +++++++----- packages/plexus-core/src/instance/instance.ts | 2 +- packages/plexus-core/src/instance/runtime.ts | 72 +++++++++++-------- packages/plexus-core/src/scope.ts | 2 +- packages/plexus-core/src/watchable.ts | 3 +- tests/efficiency.test.ts | 22 +++--- 8 files changed, 103 insertions(+), 87 deletions(-) diff --git a/packages/plexus-core/src/collection/collection.ts b/packages/plexus-core/src/collection/collection.ts index ad6b5798..0a84f5be 100644 --- a/packages/plexus-core/src/collection/collection.ts +++ b/packages/plexus-core/src/collection/collection.ts @@ -320,13 +320,13 @@ export class CollectionInstance< // `Batching an collect call for collection ${this.instanceId}` // ) // // store this in the batchedSetters for execution once batching is over - // this.instance().runtime.batchedCalls.push(() => { - // this.instance().runtime.log( - // 'debug', - // `Batched collect call fulfilled for collection ${this.instanceId}` - // ) - // return collectFn(dataToCollect, groups, true) - // }) + // // this.instance().runtime.batchedCalls.push(() => { + // // this.instance().runtime.log( + // // 'debug', + // // `Batched collect call fulfilled for collection ${this.instanceId}` + // // ) + // // return collectFn(dataToCollect, groups, true) + // // }) // return this // } @@ -787,19 +787,15 @@ export class CollectionInstance< * @returns {this} The new Collection Instance */ delete(keys: DataKey | DataKey[]): this { - // the function to remove the data - const rm = (key: DataKey) => { + // if an array, iterate through the keys and remove them each + keys = Array.isArray(keys) ? keys : [keys] + for (let key of keys) { // key = this.config.keyTransform(key) key = `${key}` this._internalStore._data.get(key)?.clean() this.removeFromGroups(key, this.getGroupsOf(key)) this._internalStore._data.delete(key) } - // if an array, iterate through the keys and remove them each - keys = Array.isArray(keys) ? keys : [keys] - for (const key of keys) { - rm(key) - } this.mount() return this } @@ -834,21 +830,18 @@ export class CollectionInstance< if (!keys.length || !groups.length) return this this.mount() - const rm = (key) => { - key = `${key}` - for (let groupName of groups) { - if (this.isCreatedGroup(groupName)) { - this._internalStore._groups.get(groupName)?.remove(key) - } - } - } // if an array, iterate through the keys and remove them from each associated group // this.instance().runtime.engine.halt() // const release = this.instance().runtime.engine.halt() this.instance().runtime.batch(() => { for (let key of keys) { - rm(key) + key = `${key}` + for (let groupName of groups) { + if (this.isCreatedGroup(groupName)) { + this._internalStore._groups.get(groupName)?.remove(key) + } + } } }) return this diff --git a/packages/plexus-core/src/collection/group.ts b/packages/plexus-core/src/collection/group.ts index 6de7e633..982ba8da 100644 --- a/packages/plexus-core/src/collection/group.ts +++ b/packages/plexus-core/src/collection/group.ts @@ -28,7 +28,7 @@ interface CollectionGroupStore { * A group of data */ export class CollectionGroup< - DataType extends Record = any, + DataType extends Record = any > extends Watchable { private _internalStore: CollectionGroupStore private collection: () => PlexusCollectionInstance @@ -85,6 +85,7 @@ export class CollectionGroup< this.instance().runtime.broadcast(this.id, this.value) } private rebuildDataWatchers(startedFromInnerBatch?: boolean) { + // this.instance().runtime.batch(() => { this.instance().runtime.log( 'info', `Group ${this.instanceId} rebuilding data watcher connections...` @@ -106,6 +107,7 @@ export class CollectionGroup< if (destroyer) this._internalStore._dataWatcherDestroyers.add(destroyer) this.runWatchers() + // }) } /** * Check if the group contains the given item @@ -142,7 +144,9 @@ export class CollectionGroup< this._internalStore._includedKeys.add(key) } if (newKeysAdded) { + // this.instance().runtime.batch(() => { this.rebuildDataWatchers() + // }) } return this } diff --git a/packages/plexus-core/src/instance/engine.ts b/packages/plexus-core/src/instance/engine.ts index 98de0ac4..22faec2a 100644 --- a/packages/plexus-core/src/instance/engine.ts +++ b/packages/plexus-core/src/instance/engine.ts @@ -7,7 +7,8 @@ export interface EngineEventReceiver { type EventPayload = { key: String; value: any } export class EventEngine { - private batching: boolean = false + private halted: boolean = false + private halts: number = 0 events: Map> pendingEventPayloads: Map @@ -20,24 +21,30 @@ export class EventEngine { * Pause and store all events until the return function is called. Once called, all events will be emitted. */ halt() { - console.log('halting') - this.batching = true + this.halts++ + if (!this.halted) console.log('halting engine...') + + this.halted = true return () => this.release() } /** * Emit all stored concatenated events and resume normal event emitting. */ release() { - this.batching = false + this.halts-- + if (this.halts > 0) return () => null + this.halted = false if (this.pendingEventPayloads.size === 0) return // if (this.batching === false) return - Array.from(this.pendingEventPayloads.entries()).forEach( - ([eventId, args]) => { - console.log('releasing', eventId, args) - - this.emit(eventId, args) - } + const pendingEntries = Array.from(this.pendingEventPayloads.entries()) + console.log( + `releasing ${pendingEntries.length} (${this.pendingEventPayloads.size}) events` ) + for (const [eventId, args] of pendingEntries) { + console.log(`releasing ${eventId} stored payload`) + this.emit(eventId, args) + } + this.pendingEventPayloads.clear() } @@ -101,23 +108,22 @@ export class EventEngine { emit(eventId: string, args: EventPayload) { // this.schedule.addTask(() => { // if we're batching, store the event payload - if (this.batching) { + if (this.halted) { const pendingPayload = this.pendingEventPayloads.get(eventId) const eventPayload = pendingPayload ? deepMerge(pendingPayload, args) : args - console.log( - 'Emit occured while batching enabled', - eventId, - pendingPayload, - this.events.get(eventId), - eventPayload - ) + // console.log( + // 'Emit occured while batching enabled', + // eventId, + // pendingPayload, + // this.events.get(eventId), + // eventPayload + // ) this.pendingEventPayloads.set(eventId, eventPayload) return } - console.log('Emitting', eventId, args) // run the event listeners for this event id this.events .get(eventId) diff --git a/packages/plexus-core/src/instance/instance.ts b/packages/plexus-core/src/instance/instance.ts index 620ba5d6..46710d88 100644 --- a/packages/plexus-core/src/instance/instance.ts +++ b/packages/plexus-core/src/instance/instance.ts @@ -219,6 +219,6 @@ export function instance( */ export function batch any | Promise = any>( fn: BatchFunction -): ReturnType { +): ReturnType | null { return instance().runtime.batch(fn) } diff --git a/packages/plexus-core/src/instance/runtime.ts b/packages/plexus-core/src/instance/runtime.ts index 2849fdff..8e50d8ac 100644 --- a/packages/plexus-core/src/instance/runtime.ts +++ b/packages/plexus-core/src/instance/runtime.ts @@ -26,6 +26,8 @@ export class RuntimeInstance { private initializing = false private initsCompleted = 0 private batching: boolean = false + // private batchPromise: Promise | null = null + private batchesInProgress: number = 0 batchedCalls: Array<() => any> = [] schedule: Scheduler @@ -213,39 +215,27 @@ export class RuntimeInstance { } /** - * The batch function allows you to run a series of reactive actions in a single transaction + * The batch function allows you to run a series of reactive actions in a single transaction. + * If there is already a batch in progress, the function will be added to the batch and run when the batch is released. * @param {Function} fn The function to run */ batch any | Promise>( fn: BatchFunction - ): ReturnType { + ): ReturnType | null { if (!fn) { throw new Error('You must provide a function to run in the batch') } - // if we are already batching, just run the function + // if we are already batching, add the function to the array and return if (this.batching) { - return fn() + // return fn() + console.log('Already batching something, ') + // ++this.batchesInProgress + this.batchedCalls.push(() => fn()) + return null } - this.startBatching() - this.instance().runtime.log('info', 'Batch function started!') - const releaseBatch = () => { - // if we aren't batching anymore, just return - if (this.batching === false) { - return - } - // stop storing changes and emit the changes - this.batching = false - const unhalt = this.engine.halt() - // call all the pending functions and clear the array - this.batchedCalls.forEach((pendingFn) => pendingFn()) - this.batchedCalls.length = 0 - - // release the reactivity engine - unhalt() + const release = this.startBatching() - this.instance().runtime.log('info', 'Batch function completed!') - } // run the function. If it returns a promise, wait for it to resolve const pendingResponse = fn() if (pendingResponse instanceof Promise) { @@ -253,12 +243,12 @@ export class RuntimeInstance { // wait for the promise to resolve const value = await pendingResponse // release the batch - this.endBatching() + release() // resolve the promise, return the value of the promise return resolve(value) }) as ReturnType } - this.endBatching() + release() return pendingResponse } @@ -274,20 +264,38 @@ export class RuntimeInstance { * Release the batch * @returns {void} */ - endBatching() { + private endBatching() { // if we aren't batching anymore, just return if (this.batching === false) { return } - // stop storing changes and emit the changes - this.batching = false + // decrement the number of batches in progress + --this.batchesInProgress + // if there are still batches in progress, just return + if (this.batchesInProgress > 0) { + console.log( + `Aborting batch end because ${this.batchesInProgress} batches are still in progress` + ) + return + } + + const unhalt = this.engine.halt() + console.log(`batchedCalls ${this.batchesInProgress}`, this.batchedCalls) // call all the pending functions and clear the array - this.batchedCalls.forEach((pendingFn) => pendingFn()) + this.batching = false + const v = this.batchesInProgress + for (const pendingFn of this.batchedCalls) { + pendingFn() + console.log( + `Running pending function with ${this.batchesInProgress} others in progress` + ) + } + this.batchedCalls.length = 0 // release the reactivity engine - // this.engine.release() - + unhalt() + // if(this.batchesInProgress === 0) { unhalt() } this.instance().runtime.log('info', 'Batch function completed!') } /** @@ -295,10 +303,12 @@ export class RuntimeInstance { * @private * @returns {Function(): void} A function to release the batch */ - startBatching() { + private startBatching() { this.batching = true + ++this.batchesInProgress // hold the reactivity engine and start storing changes // this.engine.halt() + this.instance().runtime.log('info', 'Batch function started!') return () => { this.endBatching() } diff --git a/packages/plexus-core/src/scope.ts b/packages/plexus-core/src/scope.ts index 8bf5bdc8..67baa008 100644 --- a/packages/plexus-core/src/scope.ts +++ b/packages/plexus-core/src/scope.ts @@ -107,7 +107,7 @@ export class Scope { */ batch any | Promise = any>( fn: BatchFunction - ): ReturnType { + ): ReturnType | null { return this.instance().runtime.batch(fn) } /** diff --git a/packages/plexus-core/src/watchable.ts b/packages/plexus-core/src/watchable.ts index 667a28c5..f5bb3401 100644 --- a/packages/plexus-core/src/watchable.ts +++ b/packages/plexus-core/src/watchable.ts @@ -116,7 +116,8 @@ export class WatchableMutable extends Watchable { */ set(newValue?: PlexusWatchableValueInterpreter): this { if (this.instance().runtime.isBatching) { - this.instance().runtime.batchedCalls.push(() => this.set(newValue)) + // this.instance().runtime.batchedCalls.push(() => this.set(newValue)) + this.instance().runtime.batch(() => this.set(newValue)) return this } this.loading = true diff --git a/tests/efficiency.test.ts b/tests/efficiency.test.ts index 661289a7..c8224f2a 100644 --- a/tests/efficiency.test.ts +++ b/tests/efficiency.test.ts @@ -57,16 +57,18 @@ afterEach(() => { }) describe('Efficiency tests for ', () => { - // test('The speed of a plexus collection collecting more than a thousand randomly generated objects into multiple groups', () => { - // // instance({ logLevel: 'debug' }) - // console.log('Starting test...') - // console.log('items in collection:', users1k.length) - // usersLite.collect(users1k, ['firstNames']) - // console.log('items in collection:', usersLite.value.length) - // expect(usersLite.value.length).toBe(1000) - // expect(usersLite.groups.firstNames.value.length).toBe(1000) - // // instance({ logLevel: undefined }) - // }) + test('The speed of a plexus collection collecting more than a thousand randomly generated objects into multiple groups', () => { + instance({ logLevel: 'debug' }) + console.log('Starting test...') + console.log(`${users1k.length} items being pulled into collection`) + usersLite.collect(users1k.slice(0, 30), ['firstNames']) + // expect(usersLite.size).toBe(1000) + console.log('items in collection:', usersLite.size) + expect(usersLite.size).toBe(1000) + // expect(usersLite.value.length).toBe(1000) + // expect(usersLite.groups.firstNames.value.length).toBe(1000) + instance({ logLevel: undefined }) + }) // test('Testing the same as above but with an absurd amount of data', () => { // // instance({ logLevel: 'debug' }) // console.log('Starting test...') From 6ccd0d4ec89e9ec6425bc49df90d75faa4edfba4 Mon Sep 17 00:00:00 2001 From: Philippe Clesca Date: Fri, 8 Sep 2023 18:40:32 -0400 Subject: [PATCH 09/12] finalized --- .../plexus-core/src/collection/collection.ts | 19 ------ packages/plexus-core/src/instance/engine.ts | 24 +++---- packages/plexus-core/src/instance/runtime.ts | 36 +++++----- tests/efficiency.test.ts | 65 ++++++++++--------- 4 files changed, 63 insertions(+), 81 deletions(-) diff --git a/packages/plexus-core/src/collection/collection.ts b/packages/plexus-core/src/collection/collection.ts index 0a84f5be..5ea688cc 100644 --- a/packages/plexus-core/src/collection/collection.ts +++ b/packages/plexus-core/src/collection/collection.ts @@ -310,25 +310,6 @@ export class CollectionInstance< startedFromInnerBatch?: boolean ) => { // if the instance is batching and this collection has batching enabled, add this action to the batchedSetters - // if ( - // this.instance().runtime.isBatching && - // this.config.useBatching && - // !startedFromInnerBatch - // ) { - // this.instance().runtime.log( - // 'debug', - // `Batching an collect call for collection ${this.instanceId}` - // ) - // // store this in the batchedSetters for execution once batching is over - // // this.instance().runtime.batchedCalls.push(() => { - // // this.instance().runtime.log( - // // 'debug', - // // `Batched collect call fulfilled for collection ${this.instanceId}` - // // ) - // // return collectFn(dataToCollect, groups, true) - // // }) - // return this - // } const addedKeys: any[] = collectItems( Array.isArray(dataToCollect) ? dataToCollect : [dataToCollect] diff --git a/packages/plexus-core/src/instance/engine.ts b/packages/plexus-core/src/instance/engine.ts index 22faec2a..62642948 100644 --- a/packages/plexus-core/src/instance/engine.ts +++ b/packages/plexus-core/src/instance/engine.ts @@ -1,5 +1,6 @@ import { deepMerge } from '@plexusjs/utils' import { PlexusInternalWatcher } from '../types' +import { PlexusInstance } from './instance' export interface EngineEventReceiver { from: string listener: PlexusInternalWatcher @@ -12,7 +13,7 @@ export class EventEngine { events: Map> pendingEventPayloads: Map - constructor() { + constructor(public instance: () => PlexusInstance) { this.events = new Map() this.pendingEventPayloads = new Map() } @@ -22,8 +23,7 @@ export class EventEngine { */ halt() { this.halts++ - if (!this.halted) console.log('halting engine...') - + if (!this.halted) this.instance().runtime.log('debug', 'Halting engine...') this.halted = true return () => this.release() } @@ -36,12 +36,13 @@ export class EventEngine { this.halted = false if (this.pendingEventPayloads.size === 0) return // if (this.batching === false) return - const pendingEntries = Array.from(this.pendingEventPayloads.entries()) - console.log( - `releasing ${pendingEntries.length} (${this.pendingEventPayloads.size}) events` + this.instance().runtime.log( + 'debug', + `Releasing Engine; collected (${this.pendingEventPayloads.size}) payloads` ) - for (const [eventId, args] of pendingEntries) { - console.log(`releasing ${eventId} stored payload`) + for (const [eventId, args] of Array.from( + this.pendingEventPayloads.entries() + )) { this.emit(eventId, args) } @@ -114,13 +115,6 @@ export class EventEngine { const eventPayload = pendingPayload ? deepMerge(pendingPayload, args) : args - // console.log( - // 'Emit occured while batching enabled', - // eventId, - // pendingPayload, - // this.events.get(eventId), - // eventPayload - // ) this.pendingEventPayloads.set(eventId, eventPayload) return } diff --git a/packages/plexus-core/src/instance/runtime.ts b/packages/plexus-core/src/instance/runtime.ts index 8e50d8ac..a7c35897 100644 --- a/packages/plexus-core/src/instance/runtime.ts +++ b/packages/plexus-core/src/instance/runtime.ts @@ -37,7 +37,7 @@ export class RuntimeInstance { protected config: Partial = {} ) { this.instance = instance - this._engine = new EventEngine() + this._engine = new EventEngine(this.instance) this.schedule = new Scheduler(`${config.name}_runtime`) } /** @@ -227,8 +227,10 @@ export class RuntimeInstance { } // if we are already batching, add the function to the array and return if (this.batching) { - // return fn() - console.log('Already batching something, ') + this.log( + 'debug', + 'Already batching something, adding a function to the list of batched things...' + ) // ++this.batchesInProgress this.batchedCalls.push(() => fn()) return null @@ -273,30 +275,30 @@ export class RuntimeInstance { --this.batchesInProgress // if there are still batches in progress, just return if (this.batchesInProgress > 0) { - console.log( + this.log( + 'debug', `Aborting batch end because ${this.batchesInProgress} batches are still in progress` ) return } - - const unhalt = this.engine.halt() - console.log(`batchedCalls ${this.batchesInProgress}`, this.batchedCalls) + this.engine.halt() + this.log( + 'debug', + `Executing batch (${this.batchedCalls.length} calls)`, + this.batchedCalls + ) // call all the pending functions and clear the array this.batching = false - const v = this.batchesInProgress - for (const pendingFn of this.batchedCalls) { + while (this.batchedCalls.length > 0) { + const pendingFn = this.batchedCalls.shift() + if (!pendingFn) continue pendingFn() - console.log( - `Running pending function with ${this.batchesInProgress} others in progress` - ) } - this.batchedCalls.length = 0 - // release the reactivity engine - unhalt() + this.engine.release() // if(this.batchesInProgress === 0) { unhalt() } - this.instance().runtime.log('info', 'Batch function completed!') + this.log('info', 'Batch function completed!') } /** * Begin batching any calls to the runtime @@ -308,7 +310,7 @@ export class RuntimeInstance { ++this.batchesInProgress // hold the reactivity engine and start storing changes // this.engine.halt() - this.instance().runtime.log('info', 'Batch function started!') + this.log('info', 'Batch function started!') return () => { this.endBatching() } diff --git a/tests/efficiency.test.ts b/tests/efficiency.test.ts index c8224f2a..bbf5958b 100644 --- a/tests/efficiency.test.ts +++ b/tests/efficiency.test.ts @@ -56,42 +56,47 @@ afterEach(() => { appointments.clear() }) +const LG_SIZE = 5000 +const MD_SIZE = 1000 +const SM_SIZE = 100 + describe('Efficiency tests for ', () => { test('The speed of a plexus collection collecting more than a thousand randomly generated objects into multiple groups', () => { instance({ logLevel: 'debug' }) console.log('Starting test...') - console.log(`${users1k.length} items being pulled into collection`) - usersLite.collect(users1k.slice(0, 30), ['firstNames']) + const data = users10k.slice(0, MD_SIZE) + console.log(`${data.length} items being pulled into collection`) + usersLite.collect(data.slice(0, MD_SIZE), ['firstNames']) // expect(usersLite.size).toBe(1000) console.log('items in collection:', usersLite.size) - expect(usersLite.size).toBe(1000) - // expect(usersLite.value.length).toBe(1000) - // expect(usersLite.groups.firstNames.value.length).toBe(1000) + expect(usersLite.size).toBe(MD_SIZE) + expect(usersLite.value.length).toBe(MD_SIZE) + expect(usersLite.groups.firstNames.value.length).toBe(MD_SIZE) instance({ logLevel: undefined }) }) - // test('Testing the same as above but with an absurd amount of data', () => { - // // instance({ logLevel: 'debug' }) - // console.log('Starting test...') - // console.log('items in collection:', users10k.length) - // usersLite.collect(users10k, ['firstNames']) - // console.log('items in collection:', usersLite.value.length) - // // const group1 = collectionInstance.group('appointmentId') - // // const group2 = collectionInstance.group('name') - // // expect(group1.value.length).toBe(1000) - // // expect(group2.value.length).toBe(1000) - // // instance({ logLevel: undefined }) - // }) - // test('An absurd amount of related data', () => { - // // instance({ logLevel: 'debug' }) - // console.log('Starting test...') - // console.log('items in collection:', users10k.length) - // users.collect(users1kRelated, ['main']) - // appointments.collect(appointments1kRelated, ['main']) - // console.log('items in collection:', users.value.length) - // // const group1 = collectionInstance.group('appointmentId') - // // const group2 = collectionInstance.group('name') - // // expect(group1.value.length).toBe(1000) - // // expect(group2.value.length).toBe(1000) - // // instance({ logLevel: undefined }) - // }) + test('Testing the same as above but with an absurd amount of data', () => { + // instance({ logLevel: 'debug' }) + console.log('Starting test...') + const data = users10k.slice(0, LG_SIZE) + console.log('items in collection:', data.length) + usersLite.collect(data.slice(0, LG_SIZE), ['firstNames']) + console.log('items in collection:', usersLite.value.length) + // const group1 = collectionInstance.group('appointmentId') + // const group2 = collectionInstance.group('name') + // expect(group1.value.length).toBe(1000) + // expect(group2.value.length).toBe(1000) + // instance({ logLevel: undefined }) + }) + test('An absurd amount of related data', () => { + // instance({ logLevel: 'debug' }) + console.log('Starting test...') + users.collect(users1kRelated, ['main']) + appointments.collect(appointments1kRelated, ['main']) + console.log('items in collection:', users.value.length) + // const group1 = collectionInstance.group('appointmentId') + // const group2 = collectionInstance.group('name') + // expect(group1.value.length).toBe(1000) + // expect(group2.value.length).toBe(1000) + // instance({ logLevel: undefined }) + }) }) From 0fd05d33f38aa2bdf1f88111e24aac28937a351f Mon Sep 17 00:00:00 2001 From: Philippe Clesca Date: Fri, 8 Sep 2023 19:41:57 -0400 Subject: [PATCH 10/12] fixed controllers too --- packages/plexus-core/src/error.ts | 22 +++--- .../plexus-core/src/instance/controller.ts | 76 ++++++++++++++----- tests/controller.test.ts | 21 ++--- 3 files changed, 82 insertions(+), 37 deletions(-) diff --git a/packages/plexus-core/src/error.ts b/packages/plexus-core/src/error.ts index 4d8cc01a..06fcd917 100644 --- a/packages/plexus-core/src/error.ts +++ b/packages/plexus-core/src/error.ts @@ -1,22 +1,26 @@ import { PlexusInstance } from './instance/instance' +type PlexusErrorOptions = { code: string; source: string; stack: string } + export class PlexusError extends Error { public name = 'PlexusError' public error = true - constructor( - message: string, - public options?: Partial<{ code: string; origin: string; stack: string }> - ) { + constructor(message: string, public options?: Partial) { super(message) } // custom error format for logging and debugging toString() { - return `PlexusError: ${this.message} (${this.options?.code ?? 'NO_CODE'})` + return `PlexusError${ + this.options?.source ? `(${this.options.source})` : '' + }${this.options?.code ? `[${this.options?.code}]` : ''}: ${this.message}` } } -export function handlePlexusError(e: unknown | Error | string): PlexusError { +export function handlePlexusError( + e: unknown | Error | string, + options?: Partial +): PlexusError { if (typeof e === 'string') { - return new PlexusError(e) + return new PlexusError(e, options) } // error-like objects @@ -24,7 +28,7 @@ export function handlePlexusError(e: unknown | Error | string): PlexusError { if (e instanceof Error) { return new PlexusError( `An error occurred during the execution of an action (${e.message})`, - { origin: 'action', stack: e.stack } + { ...options, stack: e.stack } ) } @@ -32,7 +36,7 @@ export function handlePlexusError(e: unknown | Error | string): PlexusError { return new PlexusError( 'An error occurred during the execution of an action', { - origin: 'action', + ...options, } ) } diff --git a/packages/plexus-core/src/instance/controller.ts b/packages/plexus-core/src/instance/controller.ts index 8f488f1c..55f464d7 100644 --- a/packages/plexus-core/src/instance/controller.ts +++ b/packages/plexus-core/src/instance/controller.ts @@ -1,5 +1,6 @@ import type { PlexusCollectionInstance } from '../collection/collection' import type { PlexusComputedStateInstance } from '../computed' +import { handlePlexusError } from '../error' import type { PlexusEventInstance } from '../event' import type { PlexusStateInstance } from '../state' import { PlexusInstance, instance } from './instance' @@ -13,56 +14,93 @@ type PlexusItem = type PlexusRecord = { [key: string]: T | PlexusItem } + +type PlexusIdMap = { + [key: string]: T | string +} +type ControllerOptions> = { + instance: () => PlexusInstance + id: string + data: OriginalObject +} /** * Plexus Controller can be used to create a controller for a module within your plexus core. * Pass an object that can be many layers deep. Each key is the name of a plexus item (state, action, etc) and the value is the instance of the item. */ export class ControllerInstance> { - public readonly name: string - public readonly path: string + private readonly id: string + private path: string | null = null public readonly instance: () => PlexusInstance protected readonly moduleStore: OriginalObject - private linkedIds: Map = new Map() + private linkedIds: Record< + string, + string | ControllerInstance> + > = Object.freeze({}) - constructor( - instance: () => PlexusInstance, - name: string, - data: OriginalObject - ) { - this.name = name - this.path = name + constructor(public name: string, options: ControllerOptions) { + const { instance, id, data } = options + this.id = id this.instance = instance this.moduleStore = data this.create(data) } - static parseObject(name: string, data: PlexusRecord) { + + static parseModule(data: PlexusRecord) { const names = Object.keys(data) + const values = names.map((name) => this.parseItem(name, data)) + return Object.fromEntries(values) + } + + static parseItem(name: string, data: PlexusRecord) { const item = data[name] - const id = item.id + if (item instanceof ControllerInstance) { + return [name, item.linkedIds] + } + const id: string = item?.id if (!id) { - throw new Error( - `Plexus Controller: ${this.name} - ${name} is missing an id` - ) + throw handlePlexusError(`${name} is missing an id`, { + source: this.name, + }) } item.name = name - return [name, [id]] + return [name, id] } /** * Intake data, get the object id's, link them to the name, assign the names to the instance in the key's value, and save the mapping to the controller * @param data */ create(data: OriginalObject) { - const mapping = ControllerInstance.parseObject(this.name, data) + const mapping = ControllerInstance.parseModule(data) - // this.linkedIds = new Map(mapping) + this.linkedIds = Object.freeze({ ...mapping }) } get module() { return this.moduleStore as OriginalObject } } +export function controller>( + name: string, + data: OriginalObject +) export function controller>( data: OriginalObject +) +export function controller>( + nameOrData: string | OriginalObject, + data?: OriginalObject ) { - return new ControllerInstance(() => instance(), instance().genId(), data) + const id = instance().genId() + if (typeof nameOrData === 'string') { + return new ControllerInstance(nameOrData, { + instance: () => instance(), + id, + data: data || {}, + }) + } + return new ControllerInstance(id, { + instance: () => instance(), + id, + data: nameOrData, + }) } diff --git a/tests/controller.test.ts b/tests/controller.test.ts index b4fb42e9..8f9daf6a 100644 --- a/tests/controller.test.ts +++ b/tests/controller.test.ts @@ -1,4 +1,4 @@ -import { beforeEach, afterEach, describe, test, expect, } from 'vitest' +import { beforeEach, afterEach, describe, test, expect } from 'vitest' import { batchAction, @@ -20,14 +20,17 @@ beforeEach(() => { }) describe('Controller Basics', () => { - // test('can a controller be used', () => { - // const myModule = controller({ - // myState: state('hey there'), - // }).export() - - // expect(myModule.myState).toBeDefined() - // expect(myModule.myState.value).toBe('hey there') - // }) + test('can a controller be used', () => { + const myController = controller('myController', { + myState: state('hey there'), + }) + const myModule = myController.module + + expect(myModule.myState).toBeDefined() + expect(myModule.myState.value).toBe('hey there') + + expect(myController.name).toBe('myController') + }) test('can a controller be used with .module', () => { const myModule = controller({ myState: state('hey there'), From 9eab39c5c41236ce05f98d048889829d4d1a34c6 Mon Sep 17 00:00:00 2001 From: Philippe Clesca Date: Fri, 8 Sep 2023 19:53:20 -0400 Subject: [PATCH 11/12] optimize test case --- .github/workflows/tests.yml | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 3c6b03f4..85430c12 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -13,27 +13,20 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 - name: Cache node modules id: cache-yarn - uses: actions/cache@v3 - env: - cache-name: cache-node-module + uses: actions/cache@v2 with: - path: ~/.cache/yarn - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/yarn.lock') }} + path: | + ~/.cache/yarn + node_modules + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock', '**/package.json') }} restore-keys: | - ${{ runner.os }}-build-${{ env.cache-name }}- - ${{ runner.os }}-build- - ${{ runner.os }}- - - - if: ${{ steps.cache-yarn.outputs.cache-hit != 'true' }} - name: List the state of node modules - continue-on-error: true - run: yarn list + ${{ runner.os }}-yarn- - name: Install Dependencies - run: yarn install + run: yarn install --frozen-lockfile - name: Yarn Build run: yarn build From 7a73e0b5020b210d1e6eb2e3f0ab4b41e9f3f2b9 Mon Sep 17 00:00:00 2001 From: Philippe Clesca Date: Fri, 8 Sep 2023 19:56:26 -0400 Subject: [PATCH 12/12] imrpoved actions --- .github/workflows/build.yml | 1 - .github/workflows/npm-publish-canary.yml | 2 +- .github/workflows/npm-publish-stable.yml | 8 +++++--- .github/workflows/tests.yml | 2 ++ .github/workflows/trunk-nightly.yml | 4 +++- .github/workflows/trunk-pr.yml | 4 +++- 6 files changed, 14 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 23273f5f..9443a9d0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,7 +21,6 @@ jobs: path: | ~/.cache/yarn node_modules - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/yarn.lock') }} restore-keys: | ${{ runner.os }}-build-${{ env.cache-name }}- diff --git a/.github/workflows/npm-publish-canary.yml b/.github/workflows/npm-publish-canary.yml index 99892f78..fcd1b07f 100644 --- a/.github/workflows/npm-publish-canary.yml +++ b/.github/workflows/npm-publish-canary.yml @@ -21,7 +21,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 registry-url: https://npm.pkg.github.com/ - name: Cache node modules id: cache-yarn diff --git a/.github/workflows/npm-publish-stable.yml b/.github/workflows/npm-publish-stable.yml index b32c8b1a..bc2148d2 100644 --- a/.github/workflows/npm-publish-stable.yml +++ b/.github/workflows/npm-publish-stable.yml @@ -15,7 +15,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 - run: yarn test publish-gpr: @@ -28,7 +28,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 registry-url: https://npm.pkg.github.com/ - name: Cache node modules @@ -37,7 +37,9 @@ jobs: env: cache-name: cache-node-module with: - path: ~/.cache/yarn + path: | + ~/.cache/yarn + node_modules key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/yarn.lock') }} restore-keys: | ${{ runner.os }}-build-${{ env.cache-name }}- diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 85430c12..38948214 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -17,6 +17,8 @@ jobs: - name: Cache node modules id: cache-yarn uses: actions/cache@v2 + env: + cache-name: cache-node-module with: path: | ~/.cache/yarn diff --git a/.github/workflows/trunk-nightly.yml b/.github/workflows/trunk-nightly.yml index 4e380744..2b61abbd 100644 --- a/.github/workflows/trunk-nightly.yml +++ b/.github/workflows/trunk-nightly.yml @@ -23,7 +23,9 @@ jobs: env: cache-name: cache-node-module with: - path: ~/.npm + path: | + ~/.cache/yarn + node_modules key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/yarn.lock') }} restore-keys: | ${{ runner.os }}-build-${{ env.cache-name }}- diff --git a/.github/workflows/trunk-pr.yml b/.github/workflows/trunk-pr.yml index c7a21ca7..a550b4d3 100644 --- a/.github/workflows/trunk-pr.yml +++ b/.github/workflows/trunk-pr.yml @@ -18,7 +18,9 @@ jobs: env: cache-name: cache-node-module with: - path: ~/.npm + path: | + ~/.cache/yarn + node_modules key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/yarn.lock') }} restore-keys: | ${{ runner.os }}-build-${{ env.cache-name }}-