From 5f204d5f171b27e78eeeb20395de117eb2331675 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 3 Feb 2023 14:17:24 +0100 Subject: [PATCH] create extension class --- .../create-extension-class.function.ts | 27 +++++++++++++++++++ .../create-extension-element.function.ts | 6 ++--- .../has-default-export.function.ts | 4 +-- ...s-manifest-class-instance-type.function.ts | 7 +++++ .../is-manifest-classable-type.function.ts | 8 ++++++ .../libs/extensions-registry/models.ts | 5 ++++ 6 files changed, 51 insertions(+), 6 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/libs/extensions-api/create-extension-class.function.ts create mode 100644 src/Umbraco.Web.UI.Client/libs/extensions-api/is-manifest-class-instance-type.function.ts create mode 100644 src/Umbraco.Web.UI.Client/libs/extensions-api/is-manifest-classable-type.function.ts diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-api/create-extension-class.function.ts b/src/Umbraco.Web.UI.Client/libs/extensions-api/create-extension-class.function.ts new file mode 100644 index 0000000000..cd5c3e1b58 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/extensions-api/create-extension-class.function.ts @@ -0,0 +1,27 @@ +import type { ClassConstructor, ManifestClass } from '../models'; +import { hasDefaultExport } from './has-default-export.function'; +import { isManifestClassConstructorType } from './is-manifest-class-instance-type.function'; +import { loadExtension } from './load-extension.function'; + +//TODO: Write tests for this method: +export async function createExtensionClass(manifest: ManifestClass): Promise { + + const js = await loadExtension(manifest); + + if (isManifestClassConstructorType(manifest)) { + return new manifest.class() as T; + } + + if (js) { + if (hasDefaultExport>(js)) { + return new js.default(); + } + + console.error('-- Extension did not succeed creating an class instance, missing a default export of the served JavaScript file', manifest); + + return undefined; + } + + console.error('-- Extension did not succeed creating an class instance, missing a default export or `class` in the manifest.', manifest); + return undefined; +} diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-api/create-extension-element.function.ts b/src/Umbraco.Web.UI.Client/libs/extensions-api/create-extension-element.function.ts index 9bdf96dc5c..2cd7f10c0d 100644 --- a/src/Umbraco.Web.UI.Client/libs/extensions-api/create-extension-element.function.ts +++ b/src/Umbraco.Web.UI.Client/libs/extensions-api/create-extension-element.function.ts @@ -1,10 +1,10 @@ -import type { ManifestElement } from '../models'; +import type { HTMLElementConstructor, ManifestElement } from '../models'; import { hasDefaultExport } from './has-default-export.function'; import { isManifestElementNameType } from './is-manifest-element-name-type.function'; import { loadExtension } from './load-extension.function'; export async function createExtensionElement(manifest: ManifestElement): Promise { - + //TODO: Write tests for these extension options: const js = await loadExtension(manifest); @@ -15,7 +15,7 @@ export async function createExtensionElement(manifest: ManifestElement): Promise // TODO: Do we need this except for the default() loader? if (js) { - if (hasDefaultExport(js)) { + if (hasDefaultExport(js)) { // created by default class return new js.default(); } diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-api/has-default-export.function.ts b/src/Umbraco.Web.UI.Client/libs/extensions-api/has-default-export.function.ts index de21ac631b..2353e38f4c 100644 --- a/src/Umbraco.Web.UI.Client/libs/extensions-api/has-default-export.function.ts +++ b/src/Umbraco.Web.UI.Client/libs/extensions-api/has-default-export.function.ts @@ -1,5 +1,3 @@ -import type { HTMLElementConstructor } from '../models'; - -export function hasDefaultExport(object: unknown): object is { default: HTMLElementConstructor } { +export function hasDefaultExport(object: unknown): object is { default: ConstructorType } { return typeof object === 'object' && object !== null && 'default' in object; } diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-api/is-manifest-class-instance-type.function.ts b/src/Umbraco.Web.UI.Client/libs/extensions-api/is-manifest-class-instance-type.function.ts new file mode 100644 index 0000000000..a66cd5de85 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/extensions-api/is-manifest-class-instance-type.function.ts @@ -0,0 +1,7 @@ +import type { ManifestClass, ManifestClassWithClassConstructor } from '../models'; + +export function isManifestClassConstructorType(manifest: unknown): manifest is ManifestClassWithClassConstructor { + return ( + typeof manifest === 'object' && manifest !== null && (manifest as ManifestClass).class !== undefined + ); +} diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-api/is-manifest-classable-type.function.ts b/src/Umbraco.Web.UI.Client/libs/extensions-api/is-manifest-classable-type.function.ts new file mode 100644 index 0000000000..e6f247b3f4 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/extensions-api/is-manifest-classable-type.function.ts @@ -0,0 +1,8 @@ +import { isManifestJSType } from './is-manifest-js-type.function'; +import { isManifestLoaderType } from './is-manifest-loader-type.function'; +import { isManifestClassConstructorType } from './is-manifest-class-instance-type.function'; +import type { ManifestBase, ManifestClass } from '@umbraco-cms/extensions-registry'; + +export function isManifestClassableType(manifest: ManifestBase): manifest is ManifestClass { + return isManifestClassConstructorType(manifest) || isManifestLoaderType(manifest) || isManifestJSType(manifest); +} diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/models.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/models.ts index daaef92105..bd71c6c25b 100644 --- a/src/Umbraco.Web.UI.Client/libs/extensions-registry/models.ts +++ b/src/Umbraco.Web.UI.Client/libs/extensions-registry/models.ts @@ -98,6 +98,11 @@ export interface ManifestClass extends ManifestWithLoader { class?: ClassConstructor; //loader?: () => Promise; } + +export interface ManifestClassWithClassConstructor extends ManifestClass { + class: ClassConstructor; +} + export interface ManifestElement extends ManifestWithLoader { type: ManifestStandardTypes; js?: string;