Merge pull request #3804 from NoelDeMartin/MOBILE-4272
MOBILE-4272: Rollback async handlers
This commit is contained in:
		
						commit
						9a6c1bb3af
					
				@ -15,7 +15,9 @@
 | 
				
			|||||||
import { APP_INITIALIZER, NgModule } from '@angular/core';
 | 
					import { APP_INITIALIZER, NgModule } from '@angular/core';
 | 
				
			||||||
import { AddonWorkshopAssessmentStrategyDelegate } from '../../services/assessment-strategy-delegate';
 | 
					import { AddonWorkshopAssessmentStrategyDelegate } from '../../services/assessment-strategy-delegate';
 | 
				
			||||||
import { CoreSharedModule } from '@/core/shared.module';
 | 
					import { CoreSharedModule } from '@/core/shared.module';
 | 
				
			||||||
import { getAssessmentStrategyHandlerInstance } from '@addons/mod/workshop/assessment/accumulative/services/handler';
 | 
					import {
 | 
				
			||||||
 | 
					    AddonModWorkshopAssessmentStrategyAccumulativeHandler,
 | 
				
			||||||
 | 
					} from '@addons/mod/workshop/assessment/accumulative/services/handler-lazy';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@NgModule({
 | 
					@NgModule({
 | 
				
			||||||
    imports: [
 | 
					    imports: [
 | 
				
			||||||
@ -26,7 +28,12 @@ import { getAssessmentStrategyHandlerInstance } from '@addons/mod/workshop/asses
 | 
				
			|||||||
            provide: APP_INITIALIZER,
 | 
					            provide: APP_INITIALIZER,
 | 
				
			||||||
            multi: true,
 | 
					            multi: true,
 | 
				
			||||||
            useValue: () => {
 | 
					            useValue: () => {
 | 
				
			||||||
                AddonWorkshopAssessmentStrategyDelegate.registerHandler(getAssessmentStrategyHandlerInstance());
 | 
					                // TODO use async instances
 | 
				
			||||||
 | 
					                // AddonWorkshopAssessmentStrategyDelegate.registerHandler(getAssessmentStrategyHandlerInstance());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                AddonWorkshopAssessmentStrategyDelegate.registerHandler(
 | 
				
			||||||
 | 
					                    AddonModWorkshopAssessmentStrategyAccumulativeHandler.instance,
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
 | 
				
			|||||||
@ -15,7 +15,7 @@
 | 
				
			|||||||
import { CoreSharedModule } from '@/core/shared.module';
 | 
					import { CoreSharedModule } from '@/core/shared.module';
 | 
				
			||||||
import { APP_INITIALIZER, NgModule } from '@angular/core';
 | 
					import { APP_INITIALIZER, NgModule } from '@angular/core';
 | 
				
			||||||
import { AddonWorkshopAssessmentStrategyDelegate } from '../../services/assessment-strategy-delegate';
 | 
					import { AddonWorkshopAssessmentStrategyDelegate } from '../../services/assessment-strategy-delegate';
 | 
				
			||||||
import { getAssessmentStrategyHandlerInstance } from './services/handler';
 | 
					import { AddonModWorkshopAssessmentStrategyCommentsHandler } from '@addons/mod/workshop/assessment/comments/services/handler-lazy';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@NgModule({
 | 
					@NgModule({
 | 
				
			||||||
    imports: [
 | 
					    imports: [
 | 
				
			||||||
@ -26,7 +26,10 @@ import { getAssessmentStrategyHandlerInstance } from './services/handler';
 | 
				
			|||||||
            provide: APP_INITIALIZER,
 | 
					            provide: APP_INITIALIZER,
 | 
				
			||||||
            multi: true,
 | 
					            multi: true,
 | 
				
			||||||
            useValue: () => {
 | 
					            useValue: () => {
 | 
				
			||||||
                AddonWorkshopAssessmentStrategyDelegate.registerHandler(getAssessmentStrategyHandlerInstance());
 | 
					                // TODO use async instances
 | 
				
			||||||
 | 
					                // AddonWorkshopAssessmentStrategyDelegate.registerHandler(getAssessmentStrategyHandlerInstance());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                AddonWorkshopAssessmentStrategyDelegate.registerHandler(AddonModWorkshopAssessmentStrategyCommentsHandler.instance);
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
 | 
				
			|||||||
@ -15,7 +15,9 @@
 | 
				
			|||||||
import { CoreSharedModule } from '@/core/shared.module';
 | 
					import { CoreSharedModule } from '@/core/shared.module';
 | 
				
			||||||
import { APP_INITIALIZER, NgModule } from '@angular/core';
 | 
					import { APP_INITIALIZER, NgModule } from '@angular/core';
 | 
				
			||||||
import { AddonWorkshopAssessmentStrategyDelegate } from '../../services/assessment-strategy-delegate';
 | 
					import { AddonWorkshopAssessmentStrategyDelegate } from '../../services/assessment-strategy-delegate';
 | 
				
			||||||
import { getAssessmentStrategyHandlerInstance } from './services/handler';
 | 
					import {
 | 
				
			||||||
 | 
					    AddonModWorkshopAssessmentStrategyNumErrorsHandler,
 | 
				
			||||||
 | 
					} from '@addons/mod/workshop/assessment/numerrors/services/handler-lazy';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@NgModule({
 | 
					@NgModule({
 | 
				
			||||||
    imports: [
 | 
					    imports: [
 | 
				
			||||||
@ -26,7 +28,12 @@ import { getAssessmentStrategyHandlerInstance } from './services/handler';
 | 
				
			|||||||
            provide: APP_INITIALIZER,
 | 
					            provide: APP_INITIALIZER,
 | 
				
			||||||
            multi: true,
 | 
					            multi: true,
 | 
				
			||||||
            useValue: () => {
 | 
					            useValue: () => {
 | 
				
			||||||
                AddonWorkshopAssessmentStrategyDelegate.registerHandler(getAssessmentStrategyHandlerInstance());
 | 
					                // TODO use async instances
 | 
				
			||||||
 | 
					                // AddonWorkshopAssessmentStrategyDelegate.registerHandler(getAssessmentStrategyHandlerInstance());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                AddonWorkshopAssessmentStrategyDelegate.registerHandler(
 | 
				
			||||||
 | 
					                    AddonModWorkshopAssessmentStrategyNumErrorsHandler.instance,
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
 | 
				
			|||||||
@ -15,7 +15,7 @@
 | 
				
			|||||||
import { CoreSharedModule } from '@/core/shared.module';
 | 
					import { CoreSharedModule } from '@/core/shared.module';
 | 
				
			||||||
import { APP_INITIALIZER, NgModule } from '@angular/core';
 | 
					import { APP_INITIALIZER, NgModule } from '@angular/core';
 | 
				
			||||||
import { AddonWorkshopAssessmentStrategyDelegate } from '../../services/assessment-strategy-delegate';
 | 
					import { AddonWorkshopAssessmentStrategyDelegate } from '../../services/assessment-strategy-delegate';
 | 
				
			||||||
import { getAssessmentStrategyHandlerInstance } from './services/handler';
 | 
					import { AddonModWorkshopAssessmentStrategyRubricHandler } from '@addons/mod/workshop/assessment/rubric/services/handler-lazy';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@NgModule({
 | 
					@NgModule({
 | 
				
			||||||
    imports: [
 | 
					    imports: [
 | 
				
			||||||
@ -26,7 +26,10 @@ import { getAssessmentStrategyHandlerInstance } from './services/handler';
 | 
				
			|||||||
            provide: APP_INITIALIZER,
 | 
					            provide: APP_INITIALIZER,
 | 
				
			||||||
            multi: true,
 | 
					            multi: true,
 | 
				
			||||||
            useValue: () => {
 | 
					            useValue: () => {
 | 
				
			||||||
                AddonWorkshopAssessmentStrategyDelegate.registerHandler(getAssessmentStrategyHandlerInstance());
 | 
					                // TODO use async instances
 | 
				
			||||||
 | 
					                // AddonWorkshopAssessmentStrategyDelegate.registerHandler(getAssessmentStrategyHandlerInstance());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                AddonWorkshopAssessmentStrategyDelegate.registerHandler(AddonModWorkshopAssessmentStrategyRubricHandler.instance);
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
 | 
				
			|||||||
@ -27,8 +27,8 @@ import { AddonModWorkshopIndexLinkHandler } from './services/handlers/index-link
 | 
				
			|||||||
import { AddonModWorkshopListLinkHandler } from './services/handlers/list-link';
 | 
					import { AddonModWorkshopListLinkHandler } from './services/handlers/list-link';
 | 
				
			||||||
import { AddonModWorkshopModuleHandler } from './services/handlers/module';
 | 
					import { AddonModWorkshopModuleHandler } from './services/handlers/module';
 | 
				
			||||||
import { ADDON_MOD_WORKSHOP_COMPONENT, ADDON_MOD_WORKSHOP_PAGE_NAME } from '@addons/mod/workshop/constants';
 | 
					import { ADDON_MOD_WORKSHOP_COMPONENT, ADDON_MOD_WORKSHOP_PAGE_NAME } from '@addons/mod/workshop/constants';
 | 
				
			||||||
import { getCronHandlerInstance } from '@addons/mod/workshop/services/handlers/sync-cron';
 | 
					import { AddonModWorkshopPrefetchHandler } from '@addons/mod/workshop/services/handlers/prefetch-lazy';
 | 
				
			||||||
import { getPrefetchHandlerInstance } from '@addons/mod/workshop/services/handlers/prefetch';
 | 
					import { AddonModWorkshopSyncCronHandler } from '@addons/mod/workshop/services/handlers/sync-cron-lazy';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Get workshop services.
 | 
					 * Get workshop services.
 | 
				
			||||||
@ -85,9 +85,13 @@ const routes: Routes = [
 | 
				
			|||||||
            provide: APP_INITIALIZER,
 | 
					            provide: APP_INITIALIZER,
 | 
				
			||||||
            multi: true,
 | 
					            multi: true,
 | 
				
			||||||
            useValue: () => {
 | 
					            useValue: () => {
 | 
				
			||||||
 | 
					                // TODO use async instances
 | 
				
			||||||
 | 
					                // CoreCourseModulePrefetchDelegate.registerHandler(getPrefetchHandlerInstance());
 | 
				
			||||||
 | 
					                // CoreCronDelegate.register(getCronHandlerInstance());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                CoreCourseModuleDelegate.registerHandler(AddonModWorkshopModuleHandler.instance);
 | 
					                CoreCourseModuleDelegate.registerHandler(AddonModWorkshopModuleHandler.instance);
 | 
				
			||||||
                CoreCourseModulePrefetchDelegate.registerHandler(getPrefetchHandlerInstance());
 | 
					                CoreCourseModulePrefetchDelegate.registerHandler(AddonModWorkshopPrefetchHandler.instance);
 | 
				
			||||||
                CoreCronDelegate.register(getCronHandlerInstance());
 | 
					                CoreCronDelegate.register(AddonModWorkshopSyncCronHandler.instance);
 | 
				
			||||||
                CoreContentLinksDelegate.registerHandler(AddonModWorkshopIndexLinkHandler.instance);
 | 
					                CoreContentLinksDelegate.registerHandler(AddonModWorkshopIndexLinkHandler.instance);
 | 
				
			||||||
                CoreContentLinksDelegate.registerHandler(AddonModWorkshopListLinkHandler.instance);
 | 
					                CoreContentLinksDelegate.registerHandler(AddonModWorkshopListLinkHandler.instance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -15,7 +15,7 @@
 | 
				
			|||||||
import { Injectable } from '@angular/core';
 | 
					import { Injectable } from '@angular/core';
 | 
				
			||||||
import { makeSingleton } from '@singletons';
 | 
					import { makeSingleton } from '@singletons';
 | 
				
			||||||
import { CorePlatform } from '@services/platform';
 | 
					import { CorePlatform } from '@services/platform';
 | 
				
			||||||
import { AsyncInstance, asyncInstance } from '@/core/utils/async-instance';
 | 
					import { AsyncInstance, AsyncObject, asyncInstance } from '@/core/utils/async-instance';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Native plugin manager.
 | 
					 * Native plugin manager.
 | 
				
			||||||
@ -23,7 +23,7 @@ import { AsyncInstance, asyncInstance } from '@/core/utils/async-instance';
 | 
				
			|||||||
@Injectable({ providedIn: 'root' })
 | 
					@Injectable({ providedIn: 'root' })
 | 
				
			||||||
export class CoreNativeService {
 | 
					export class CoreNativeService {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private plugins: Partial<Record<keyof MoodleAppPlugins, AsyncInstance>> = {};
 | 
					    private plugins: Partial<Record<keyof MoodleAppPlugins, AsyncInstance<AsyncObject>>> = {};
 | 
				
			||||||
    private mocks: Partial<Record<keyof MoodleAppPlugins, MoodleAppPlugins[keyof MoodleAppPlugins]>> = {};
 | 
					    private mocks: Partial<Record<keyof MoodleAppPlugins, MoodleAppPlugins[keyof MoodleAppPlugins]>> = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 | 
				
			|||||||
@ -14,19 +14,19 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { CorePromisedValue } from '@classes/promised-value';
 | 
					import { CorePromisedValue } from '@classes/promised-value';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// eslint-disable-next-line @typescript-eslint/ban-types
 | 
					 | 
				
			||||||
type AsyncObject = object;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Create a wrapper to hold an asynchronous instance.
 | 
					 * Create a wrapper to hold an asynchronous instance.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @param lazyConstructor Constructor to use the first time the instance is needed.
 | 
					 * @param lazyConstructor Constructor to use the first time the instance is needed.
 | 
				
			||||||
 * @returns Asynchronous instance wrapper.
 | 
					 * @returns Asynchronous instance wrapper.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
function createAsyncInstanceWrapper<TEagerInstance extends AsyncObject, TInstance extends TEagerInstance>(
 | 
					function createAsyncInstanceWrapper<
 | 
				
			||||||
    lazyConstructor?: () => TInstance | Promise<TInstance>,
 | 
					    TLazyInstance extends TEagerInstance,
 | 
				
			||||||
): AsyncInstanceWrapper<TEagerInstance, TInstance> {
 | 
					    TEagerInstance extends AsyncObject = Partial<TLazyInstance>
 | 
				
			||||||
    let promisedInstance: CorePromisedValue<TInstance> | null = null;
 | 
					>(
 | 
				
			||||||
 | 
					    lazyConstructor?: () => TLazyInstance | Promise<TLazyInstance>,
 | 
				
			||||||
 | 
					): AsyncInstanceWrapper<TLazyInstance, TEagerInstance> {
 | 
				
			||||||
 | 
					    let promisedInstance: CorePromisedValue<TLazyInstance> | null = null;
 | 
				
			||||||
    let eagerInstance: TEagerInstance;
 | 
					    let eagerInstance: TEagerInstance;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
@ -90,20 +90,36 @@ function createAsyncInstanceWrapper<TEagerInstance extends AsyncObject, TInstanc
 | 
				
			|||||||
    };
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Check whether the given value is a method.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param value Value.
 | 
				
			||||||
 | 
					 * @returns Whether the given value is a method.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					function isMethod(value: unknown): value is (...args: unknown[]) => unknown {
 | 
				
			||||||
 | 
					    return typeof value === 'function';
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Asynchronous instance wrapper.
 | 
					 * Asynchronous instance wrapper.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
export interface AsyncInstanceWrapper<TEagerInstance extends AsyncObject, TInstance extends TEagerInstance> {
 | 
					export interface AsyncInstanceWrapper<
 | 
				
			||||||
    instance?: TInstance;
 | 
					    TLazyInstance extends TEagerInstance,
 | 
				
			||||||
 | 
					    TEagerInstance extends AsyncObject = Partial<TLazyInstance>
 | 
				
			||||||
 | 
					> {
 | 
				
			||||||
 | 
					    instance?: TLazyInstance;
 | 
				
			||||||
    eagerInstance?: TEagerInstance;
 | 
					    eagerInstance?: TEagerInstance;
 | 
				
			||||||
    getInstance(): Promise<TInstance>;
 | 
					    getInstance(): Promise<TLazyInstance>;
 | 
				
			||||||
    getProperty<P extends keyof TInstance>(property: P): Promise<TInstance[P]>;
 | 
					    getProperty<P extends keyof TLazyInstance>(property: P): Promise<TLazyInstance[P]>;
 | 
				
			||||||
    setInstance(instance: TInstance): void;
 | 
					    setInstance(instance: TLazyInstance): void;
 | 
				
			||||||
    setEagerInstance(eagerInstance: TEagerInstance): void;
 | 
					    setEagerInstance(eagerInstance: TEagerInstance): void;
 | 
				
			||||||
    setLazyConstructor(lazyConstructor: () => TInstance | Promise<TInstance>): void;
 | 
					    setLazyConstructor(lazyConstructor: () => TLazyInstance | Promise<TLazyInstance>): void;
 | 
				
			||||||
    resetInstance(): void;
 | 
					    resetInstance(): void;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// eslint-disable-next-line @typescript-eslint/ban-types
 | 
				
			||||||
 | 
					export type AsyncObject = object;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Asynchronous version of a method.
 | 
					 * Asynchronous version of a method.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@ -121,9 +137,9 @@ export type AsyncMethod<T> =
 | 
				
			|||||||
 * All methods are converted to their asynchronous version, and properties are available asynchronously using
 | 
					 * All methods are converted to their asynchronous version, and properties are available asynchronously using
 | 
				
			||||||
 * the getProperty method.
 | 
					 * the getProperty method.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
export type AsyncInstance<TEagerInstance extends AsyncObject = AsyncObject, TInstance extends TEagerInstance = TEagerInstance> =
 | 
					export type AsyncInstance<TLazyInstance extends TEagerInstance, TEagerInstance extends AsyncObject = Partial<TLazyInstance>> =
 | 
				
			||||||
    AsyncInstanceWrapper<TEagerInstance, TInstance> & TEagerInstance & {
 | 
					    AsyncInstanceWrapper<TLazyInstance, TEagerInstance> & {
 | 
				
			||||||
        [k in keyof TInstance]: AsyncMethod<TInstance[k]>;
 | 
					        [k in keyof TLazyInstance]: AsyncMethod<TLazyInstance[k]>;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@ -133,10 +149,10 @@ export type AsyncInstance<TEagerInstance extends AsyncObject = AsyncObject, TIns
 | 
				
			|||||||
 * @param lazyConstructor Constructor to use the first time the instance is needed.
 | 
					 * @param lazyConstructor Constructor to use the first time the instance is needed.
 | 
				
			||||||
 * @returns Asynchronous instance.
 | 
					 * @returns Asynchronous instance.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
export function asyncInstance<TEagerInstance extends AsyncObject, TInstance extends TEagerInstance = TEagerInstance>(
 | 
					export function asyncInstance<TLazyInstance extends TEagerInstance, TEagerInstance extends AsyncObject = Partial<TLazyInstance>>(
 | 
				
			||||||
    lazyConstructor?: () => TInstance | Promise<TInstance>,
 | 
					    lazyConstructor?: () => TLazyInstance | Promise<TLazyInstance>,
 | 
				
			||||||
): AsyncInstance<TEagerInstance, TInstance> {
 | 
					): AsyncInstance<TLazyInstance, TEagerInstance> {
 | 
				
			||||||
    const wrapper = createAsyncInstanceWrapper<TEagerInstance, TInstance>(lazyConstructor);
 | 
					    const wrapper = createAsyncInstanceWrapper<TLazyInstance, TEagerInstance>(lazyConstructor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return new Proxy(wrapper, {
 | 
					    return new Proxy(wrapper, {
 | 
				
			||||||
        get: (target, property, receiver) => {
 | 
					        get: (target, property, receiver) => {
 | 
				
			||||||
@ -144,8 +160,12 @@ export function asyncInstance<TEagerInstance extends AsyncObject, TInstance exte
 | 
				
			|||||||
                return Reflect.get(target, property, receiver);
 | 
					                return Reflect.get(target, property, receiver);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (wrapper.instance && property in wrapper.instance) {
 | 
					            if (wrapper.instance) {
 | 
				
			||||||
                return Reflect.get(wrapper.instance, property, receiver);
 | 
					                const value = Reflect.get(wrapper.instance, property, receiver);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                return isMethod(value)
 | 
				
			||||||
 | 
					                    ? async (...args: unknown[]) => value.call(wrapper.instance, ...args)
 | 
				
			||||||
 | 
					                    : value;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (wrapper.eagerInstance && property in wrapper.eagerInstance) {
 | 
					            if (wrapper.eagerInstance && property in wrapper.eagerInstance) {
 | 
				
			||||||
@ -154,9 +174,14 @@ export function asyncInstance<TEagerInstance extends AsyncObject, TInstance exte
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            return async (...args: unknown[]) => {
 | 
					            return async (...args: unknown[]) => {
 | 
				
			||||||
                const instance = await wrapper.getInstance();
 | 
					                const instance = await wrapper.getInstance();
 | 
				
			||||||
 | 
					                const method = Reflect.get(instance, property, receiver);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                return instance[property](...args);
 | 
					                if (!isMethod(method)) {
 | 
				
			||||||
 | 
					                    throw new Error(`'${property.toString()}' is not a function`);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                return method.call(instance, ...args);
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
    }) as AsyncInstance<TEagerInstance, TInstance>;
 | 
					    }) as AsyncInstance<TLazyInstance, TEagerInstance>;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										94
									
								
								src/core/utils/tests/async-instance.test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								src/core/utils/tests/async-instance.test.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,94 @@
 | 
				
			|||||||
 | 
					// (C) Copyright 2015 Moodle Pty Ltd.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					// you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					// You may obtain a copy of the License at
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//     http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					// distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					// See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					// limitations under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { AsyncInstance, asyncInstance } from '@/core/utils/async-instance';
 | 
				
			||||||
 | 
					import { expectAnyType, expectSameTypes } from '@/testing/utils';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe('AsyncInstance', () => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it('initializes instances lazily', async () => {
 | 
				
			||||||
 | 
					        const asyncService = asyncInstance(() => new LazyService());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        expect(asyncService.instance).toBe(undefined);
 | 
				
			||||||
 | 
					        expect(await asyncService.hello()).toEqual('Hi there!');
 | 
				
			||||||
 | 
					        expect(asyncService.instance).toBeInstanceOf(LazyService);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it('does not initialize instance for eager properties', async () => {
 | 
				
			||||||
 | 
					        const asyncService = asyncInstance(() => new LazyService());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        asyncService.setEagerInstance(new EagerService());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        expect(asyncService.instance).toBeUndefined();
 | 
				
			||||||
 | 
					        expect(asyncService.answer).toEqual(42);
 | 
				
			||||||
 | 
					        expect(asyncService.instance).toBeUndefined();
 | 
				
			||||||
 | 
					        expect(await asyncService.hello()).toEqual('Hi there!');
 | 
				
			||||||
 | 
					        expect(asyncService.instance).toBeInstanceOf(LazyService);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it('preserves undefined properties after initialization', async () => {
 | 
				
			||||||
 | 
					        const asyncService = asyncInstance(() => new LazyService()) as { thisDoesNotExist?: () => Promise<void>};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        await expect(asyncService.thisDoesNotExist?.()).rejects.toBeInstanceOf(Error);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        expect(asyncService.thisDoesNotExist).toBeUndefined();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it('restricts types hierarchy', () => {
 | 
				
			||||||
 | 
					        type GetInstances<T> = T extends AsyncInstance<infer TLazyInstance, infer TEagerInstance>
 | 
				
			||||||
 | 
					            ? { eager: TEagerInstance; lazy: TLazyInstance }
 | 
				
			||||||
 | 
					            : never;
 | 
				
			||||||
 | 
					        type GetEagerInstance<T> = GetInstances<T>['eager'];
 | 
				
			||||||
 | 
					        type GetLazyInstance<T> = GetInstances<T>['lazy'];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        expectSameTypes<GetLazyInstance<AsyncInstance<LazyService>>, LazyService>(true);
 | 
				
			||||||
 | 
					        expectSameTypes<GetEagerInstance<AsyncInstance<LazyService>>, Partial<LazyService>>(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        expectSameTypes<GetLazyInstance<AsyncInstance<LazyService, EagerService>>, LazyService>(true);
 | 
				
			||||||
 | 
					        expectSameTypes<GetEagerInstance<AsyncInstance<LazyService, EagerService>>, EagerService>(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // @ts-expect-error LazyService should extend FakeEagerService.
 | 
				
			||||||
 | 
					        expectAnyType<AsyncInstance<LazyService, FakeEagerService>>();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it('makes methods asynchronous', () => {
 | 
				
			||||||
 | 
					        expectSameTypes<AsyncInstance<LazyService>['hello'], () => Promise<string>>(true);
 | 
				
			||||||
 | 
					        expectSameTypes<AsyncInstance<LazyService>['goodbye'], () => Promise<string>>(true);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class EagerService {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    answer = 42;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class FakeEagerService {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    answer = '42';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class LazyService extends EagerService {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    hello(): string {
 | 
				
			||||||
 | 
					        return 'Hi there!';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async goodbye(): Promise<string> {
 | 
				
			||||||
 | 
					        return 'Sayonara!';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -18,6 +18,11 @@
 | 
				
			|||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
 | 
					// eslint-disable-next-line @typescript-eslint/no-explicit-any
 | 
				
			||||||
export type Constructor<T> = { new(...args: any[]): T };
 | 
					export type Constructor<T> = { new(...args: any[]): T };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Helper type to infer whether two types are exactly the same.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? true : false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Helper type to flatten complex types.
 | 
					 * Helper type to flatten complex types.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
				
			|||||||
@ -34,6 +34,7 @@ import { CoreIonLoadingElement } from '@classes/ion-loading';
 | 
				
			|||||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
 | 
					import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
 | 
				
			||||||
import { DefaultUrlSerializer, UrlSerializer } from '@angular/router';
 | 
					import { DefaultUrlSerializer, UrlSerializer } from '@angular/router';
 | 
				
			||||||
import { CoreUtils, CoreUtilsProvider } from '@services/utils/utils';
 | 
					import { CoreUtils, CoreUtilsProvider } from '@services/utils/utils';
 | 
				
			||||||
 | 
					import { Equal } from '@/core/utils/types';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
abstract class WrapperComponent<U> {
 | 
					abstract class WrapperComponent<U> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -421,3 +422,12 @@ export function mockTranslate(translations: Record<string, string> = {}): void {
 | 
				
			|||||||
        },
 | 
					        },
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function expectSameTypes<A, B>(equal: Equal<A, B>): () => void {
 | 
				
			||||||
 | 
					    return () => expect(equal).toBe(true);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// eslint-disable-next-line @typescript-eslint/no-unused-vars
 | 
				
			||||||
 | 
					export function expectAnyType<T>(): () => void {
 | 
				
			||||||
 | 
					    return () => expect(true).toBe(true);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user