broad implementation

This commit is contained in:
Niels Lyngsø
2023-03-17 08:39:09 +01:00
parent 6470c7a148
commit 2bcf11f930
4 changed files with 73 additions and 64 deletions

View File

@@ -61,7 +61,7 @@ describe('UmbExtensionRegistry', () => {
it('should get an extension by alias', (done) => {
const alias = 'Umb.Test.Section.1';
extensionRegistry
.getByAlias(alias)
.getByTypeAndAlias('section', alias)
.subscribe((extension) => {
expect(extension?.alias).to.eq(alias);
done();
@@ -85,31 +85,29 @@ describe('UmbExtensionRegistry', () => {
});
// TODO: What kind of weighting would we like to use?
/*
it('should return extensions ordered by weight', (done) => {
extensionRegistry
.extensionsOfType(type)
.subscribe((extensions) => {
expect(extensions?.[0]?.weight).to.eq(200);
expect(extensions?.[0]?.weight).to.eq(1);
expect(extensions?.[1]?.weight).to.eq(25);
expect(extensions?.[2]?.weight).to.eq(1);
expect(extensions?.[2]?.weight).to.eq(200);
done();
})
.unsubscribe();
});
*/
});
});
describe('UmbExtensionRegistry with kinds', () => {
let extensionRegistry: UmbExtensionRegistry;
let kinds: Array<ManifestKind>;
let manifests: Array<ManifestTypes>;
let manifests: Array<ManifestTypes | ManifestKind>;
beforeEach(() => {
extensionRegistry = new UmbExtensionRegistry();
kinds = [
manifests = [
{
type: 'kind',
matchType: 'section',
matchKind: 'test-kind',
manifest: {
@@ -117,8 +115,6 @@ describe('UmbExtensionRegistry with kinds', () => {
elementName: 'my-kind-element',
},
},
];
manifests = [
{
type: 'section',
kind: 'test-kind',
@@ -161,13 +157,12 @@ describe('UmbExtensionRegistry with kinds', () => {
},
];
kinds.forEach((kind) => extensionRegistry.defineKind(kind));
manifests.forEach((manifest) => extensionRegistry.register(manifest));
});
it('should merge with kinds', (done) => {
extensionRegistry
.getByTypeWithKinds('section')
.extensionsOfType('section')
.subscribe((extensions) => {
expect(extensions).to.have.lengthOf(3);
expect(extensions?.[0]?.elementName).to.eq('my-kind-element');

View File

@@ -1,4 +1,4 @@
import { BehaviorSubject, withLatestFrom, map, Observable } from 'rxjs';
import { BehaviorSubject, withLatestFrom, map, find, Observable } from 'rxjs';
import type {
ManifestTypes,
ManifestTypeMap,
@@ -16,11 +16,6 @@ export class UmbExtensionRegistry {
// TODO: Use UniqueBehaviorSubject, as we don't want someone to edit data of extensions.
private _extensions = new BehaviorSubject<Array<ManifestBase>>([]);
public readonly extensions = this._extensions.asObservable();
/*
public readonly entryPoints = this._extensions.pipe(
map((extensions) => extensions.filter((e) => e.type === 'entrypoint'))
);
*/
private _kinds = new BehaviorSubject<Array<ManifestKind>>([]);
public readonly kinds = this._kinds.asObservable();
@@ -35,16 +30,21 @@ export class UmbExtensionRegistry {
this._kinds.next(nextData);
}
register(manifest: ManifestTypes, rootHost?: UmbControllerHostInterface): void {
const extensionsValues = this._extensions.getValue();
const extension = extensionsValues.find((extension) => extension.alias === manifest.alias);
if (extension) {
console.error(`Extension with alias ${manifest.alias} is already registered`);
register(manifest: ManifestTypes | ManifestKind, rootHost?: UmbControllerHostInterface): void {
if (manifest.type === 'kind') {
this.defineKind(manifest as ManifestKind);
return;
}
this._extensions.next([...extensionsValues, manifest]);
const extensionsValues = this._extensions.getValue();
const extension = extensionsValues.find((extension) => extension.alias === (manifest as ManifestTypes).alias);
if (extension) {
console.error(`Extension with alias ${(manifest as ManifestTypes).alias} is already registered`);
return;
}
this._extensions.next([...extensionsValues, manifest as ManifestTypes]);
// If entrypoint extension, we should load and run it immediately
if (manifest.type === 'entrypoint') {
@@ -75,25 +75,48 @@ export class UmbExtensionRegistry {
return values.some((ext) => ext.alias === alias);
}
/*
getByAlias(alias: string) {
// TODO: make pipes prettier/simpler/reuseable
return this.extensions.pipe(map((extensions) => extensions.find((extension) => extension.alias === alias) || null));
}
*/
kindsOfType<Key extends keyof ManifestTypeMap | string>(type: Key) {
private _kindsOfType<Key extends keyof ManifestTypeMap | string>(type: Key) {
return this.kinds.pipe(map((kinds) => kinds.filter((kind) => kind.matchType === type)));
// TODO: DisctinctUntilChanged by using aliases?
}
private _extensionsOfType<Key extends keyof ManifestTypeMap | string>(type: Key) {
return this.extensions.pipe(map((exts) => exts.filter((ext) => ext.type === type)));
// TODO: DisctinctUntilChanged by using aliases?
}
private _kindsOfTypes(types: string[]) {
return this.kinds.pipe(map((kinds) => kinds.filter((kind) => types.indexOf(kind.matchType) !== -1)));
// TODO: DisctinctUntilChanged by using aliases?
}
private _extensionsOfTypes<ExtensionType = ManifestBase>(types: string[]): Observable<Array<ExtensionType>> {
return this.extensions.pipe(map((exts) => exts.filter((ext) => types.indexOf(ext.type) !== -1))) as Observable<
Array<ExtensionType>
>;
// TODO: DisctinctUntilChanged by using aliases?
}
getByTypeWithKinds<Key extends keyof ManifestTypeMap | string, T = SpecificManifestTypeOrManifestBase<Key>>(
type: Key
getByTypeAndAlias<Key extends keyof ManifestTypeMap | string, T = SpecificManifestTypeOrManifestBase<Key>>(
type: Key,
alias: string
) {
/*
return this.extensionsOfType(type).pipe(
map((extensions) => extensions.find((extension) => extension.alias === alias) || null)
);
*/
return this.extensionsOfType(type).pipe(
withLatestFrom(this.kindsOfType(type)),
return this.extensions.pipe(
map((exts) => exts.find((ext) => ext.type === type && ext.alias === alias)),
withLatestFrom(this._kindsOfType(type)),
map(([ext, kinds]) => {
return ext ? { ...kinds.find((kind) => kind.matchKind === ext.kind)?.manifest, ...ext } : undefined;
})
) as Observable<T | undefined>;
}
extensionsOfType<Key extends keyof ManifestTypeMap | string, T = SpecificManifestTypeOrManifestBase<Key>>(type: Key) {
return this._extensionsOfType(type).pipe(
withLatestFrom(this._kindsOfType(type)),
map(([exts, kinds]) =>
exts
.map((ext) => {
@@ -103,40 +126,30 @@ export class UmbExtensionRegistry {
)
) as Observable<Array<T>>;
//
// TODO: DisctinctUntilChanged by using aliases?
}
getByTypeAndAlias<Key extends keyof ManifestTypeMap | string, T = SpecificManifestTypeOrManifestBase<Key>>(
type: Key,
alias: string
) {
/*
return this.extensionsOfType(type).pipe(
map((extensions) => extensions.find((extension) => extension.alias === alias) || null)
);
*/
return this.extensions.pipe(
map((exts) =>
exts.filter((ext) => ext.type === type && ext.alias === alias).sort((a, b) => (a.weight || 0) - (b.weight || 0))
extensionsOfTypes<ExtensionTypes = ManifestBase>(types: string[]): Observable<Array<ExtensionTypes>> {
return this._extensionsOfTypes(types).pipe(
withLatestFrom(this._kindsOfTypes(types)),
map(([exts, kinds]) =>
exts
.map((ext) => {
return { ...kinds.find((kind) => kind.matchKind === ext.kind)?.manifest, ...ext };
})
.sort((a, b) => (a.weight || 0) - (b.weight || 0))
)
) as Observable<Array<T>>;
) as Observable<Array<ExtensionTypes>>;
//
// TODO: DisctinctUntilChanged by using aliases?
}
extensionsOfType<Key extends keyof ManifestTypeMap | string, T = SpecificManifestTypeOrManifestBase<Key>>(type: Key) {
return this.extensions.pipe(map((exts) => exts.filter((ext) => ext.type === type))) as Observable<Array<T>>;
//.sort((a, b) => (b.weight || 0) - (a.weight || 0))
}
extensionsOfTypes<ExtensionType = ManifestBase>(types: string[]): Observable<Array<ExtensionType>> {
return this.extensions.pipe(
map((exts) =>
exts.filter((ext) => types.indexOf(ext.type) !== -1).sort((a, b) => (a.weight || 0) - (b.weight || 0))
)
) as Observable<Array<ExtensionType>>;
//
}
extensionsSortedByTypeAndWeight<ExtensionType = ManifestBase>(): Observable<Array<ExtensionType>> {
// TODO: consider moving this method to the extension view?
/**
* Gets all the extensions registrations, but does not merge with kinds.
* @returns
*/
extensionRegistrationsSortedByTypeAndWeight<ExtensionType = ManifestBase>(): Observable<Array<ExtensionType>> {
return this.extensions.pipe(
map((exts) =>
exts.sort((a, b) => {

View File

@@ -105,6 +105,7 @@ export interface ManifestBase {
}
export interface ManifestKind {
type: 'kind';
matchType: string;
matchKind: string;
manifest: Partial<ManifestTypes>;