Embed the discriminator method in ContextToken

This commit is contained in:
Niels Lyngsø
2023-08-23 15:08:01 +02:00
parent d43c5a85b4
commit d93ac1c694
3 changed files with 42 additions and 32 deletions

View File

@@ -1,5 +1,6 @@
import { expect, oneEvent } from '@open-wc/testing';
import { UmbContextProvider } from '../provide/context-provider.js';
import { UmbContextToken } from '../token/context-token.js';
import { UmbContextConsumer } from './context-consumer.js';
import { UmbContextRequestEventImplementation, umbContextRequestEventType } from './context-request.event.js';
@@ -111,10 +112,14 @@ describe('UmbContextConsumer with discriminator test', () => {
it('discriminator determines the instance type', async () => {
const localConsumer = new UmbContextConsumer(document.body, testContextAlias, (instance: A) => { console.log(instance)}, discriminator);
const localConsumer = new UmbContextConsumer(
document.body,
new UmbContextToken(testContextAlias, discriminator),
(instance: A) => { console.log(instance)}
);
localConsumer.hostConnected();
// This bit of code is just to make sure the type is correct.
// This bit of code is not really a test but it serves as a TypeScript type test, making sure the given type is matches the one given from the Discriminator method.
type TestType = Exclude<(typeof localConsumer.instance), undefined> extends A ? true : never;
const test: TestType = true;
expect(test).to.be.true;
@@ -131,14 +136,13 @@ describe('UmbContextConsumer with discriminator test', () => {
const localConsumer = new UmbContextConsumer(
element,
testContextAlias,
new UmbContextToken(testContextAlias, discriminator),
(_instance) => {
expect(_instance.prop).to.eq('value from provider');
done();
localConsumer.hostDisconnected();
provider.hostDisconnected();
},
discriminator
}
);
localConsumer.hostConnected();
});
@@ -152,11 +156,10 @@ describe('UmbContextConsumer with discriminator test', () => {
const localConsumer = new UmbContextConsumer(
element,
testContextAlias,
new UmbContextToken(testContextAlias, badDiscriminator),
(_instance) => {
expect(_instance.prop).to.eq('this must not happen!');
},
badDiscriminator
}
);
localConsumer.hostConnected();

View File

@@ -1,4 +1,4 @@
import { UmbContextToken } from '../token/context-token.js';
import { UmbContextDiscriminator, UmbContextToken } from '../token/context-token.js';
import {
isUmbContextProvideEventType,
//isUmbContextUnprovidedEventType,
@@ -7,25 +7,23 @@ import {
} from '../provide/context-provide.event.js';
import { UmbContextRequestEventImplementation, UmbContextCallback } from './context-request.event.js';
export type UmbContextDiscriminator<T, DiscriminatorResult extends T = T> = (instance: T) => instance is DiscriminatorResult;
/**
* @export
* @class UmbContextConsumer
*/
export class UmbContextConsumer<T = unknown, D extends T = T> {
#callback?: UmbContextCallback<D>;
#promise?: Promise<D>;
#promiseResolver?: (instance: D) => void;
export class UmbContextConsumer<BaseType = unknown, DiscriminatedType extends BaseType = BaseType> {
#callback?: UmbContextCallback<DiscriminatedType>;
#promise?: Promise<DiscriminatedType>;
#promiseResolver?: (instance: DiscriminatedType) => void;
#instance?: D;
#instance?: DiscriminatedType;
get instance() {
return this.#instance;
}
#contextAlias: string;
#discriminator?: UmbContextDiscriminator<T, D>;
#discriminator?: UmbContextDiscriminator<BaseType, DiscriminatedType>;
/**
* Creates an instance of UmbContextConsumer.
@@ -36,13 +34,12 @@ export class UmbContextConsumer<T = unknown, D extends T = T> {
*/
constructor(
protected hostElement: EventTarget,
contextAlias: string | UmbContextToken<T>,
callback?: UmbContextCallback<D>,
discriminator?: UmbContextDiscriminator<T, D>
contextAlias: string | UmbContextToken<BaseType, DiscriminatedType>,
callback?: UmbContextCallback<DiscriminatedType>
) {
this.#contextAlias = contextAlias.toString();
this.#callback = callback;
this.#discriminator = discriminator;
this.#discriminator = (contextAlias as any).getDiscriminator?.();
}
@@ -51,7 +48,7 @@ export class UmbContextConsumer<T = unknown, D extends T = T> {
The reason for such would be to have some who are more specific than others. For example, some might just need the current workspace-context, others might need the closest handling a certain entityType.
As I'm writing this is not relevant, but I wanted to keep the idea as we have had some circumstance that might be solved with this approach.
*/
protected _onResponse = (instance: T) => {
protected _onResponse = (instance: BaseType) => {
if (this.#instance === instance) {
return;
}
@@ -61,11 +58,11 @@ export class UmbContextConsumer<T = unknown, D extends T = T> {
this.setInstance(instance);
}
} else {
this.setInstance(instance as D);
this.setInstance(instance as DiscriminatedType);
}
};
protected setInstance(instance: D) {
protected setInstance(instance: DiscriminatedType) {
this.#instance = instance;
this.#callback?.(instance);
if (instance !== undefined) {
@@ -77,7 +74,7 @@ export class UmbContextConsumer<T = unknown, D extends T = T> {
public asPromise() {
return (
this.#promise ??
(this.#promise = new Promise<D>((resolve) => {
(this.#promise = new Promise<DiscriminatedType>((resolve) => {
this.#instance ? resolve(this.#instance) : (this.#promiseResolver = resolve);
}))
);

View File

@@ -1,4 +1,9 @@
export class UmbContextToken<T = unknown> {
export type UmbContextDiscriminator<BaseType, DiscriminatorResult extends BaseType = BaseType> = (instance: BaseType) => instance is DiscriminatorResult;
export class UmbContextToken<BaseType = unknown, DiscriminatedType extends BaseType = BaseType> {
#discriminator: UmbContextDiscriminator<BaseType, DiscriminatedType> | undefined;
/**
* Get the type of the token
*
@@ -8,15 +13,18 @@ export class UmbContextToken<T = unknown> {
* @example `typeof MyToken.TYPE`
* @returns undefined
*/
readonly TYPE: T = undefined as never;
readonly TYPE: DiscriminatedType = undefined as never;
/**
* @param alias Unique identifier for the token,
* @param _desc Description for the token,
* used only for debugging purposes,
* it should but does not need to be unique
* @param alias Unique identifier for the token
*/
constructor(protected alias: string, protected _desc?: string) {}
constructor(protected alias: string, discriminator?: UmbContextDiscriminator<BaseType, DiscriminatedType>) {
this.#discriminator = discriminator;
}
getDiscriminator(): UmbContextDiscriminator<BaseType, DiscriminatedType> | undefined {
return this.#discriminator;
}
/**
* This method must always return the unique alias of the token since that
@@ -27,4 +35,6 @@ export class UmbContextToken<T = unknown> {
toString(): string {
return this.alias;
}
}