/*! * Copyright (c) Microsoft Corporation and contributors. All rights reserved. * Licensed under the MIT License. */ /** * Helper class for lazy initialized values. Ensures the value is only generated once, and remain immutable. * @internal */ export class Lazy { private _value: T | undefined; private _evaluated: boolean = false; /** * Instantiates an instance of Lazy. * @param valueGenerator - The function that will generate the value when value is accessed the first time. */ public constructor(private readonly valueGenerator: () => T) {} /** * Return true if the value as been generated, otherwise false. */ public get evaluated(): boolean { return this._evaluated; } /** * Get the value. If this is the first call the value will be generated. */ public get value(): T { if (!this._evaluated) { this._evaluated = true; this._value = this.valueGenerator(); } // eslint-disable-next-line @typescript-eslint/no-non-null-assertion return this._value!; } } /** * A lazy evaluated promise. The execute function is delayed until * the promise is used, e.g. await, then, catch ... * The execute function is only called once. * All calls are then proxied to the promise returned by the execute method. * @legacy @beta */ export class LazyPromise implements Promise { // eslint-disable-next-line @typescript-eslint/class-literal-property-style public get [Symbol.toStringTag](): string { return "[object LazyPromise]"; } private result: Promise | undefined; public constructor(private readonly execute: () => Promise) {} // eslint-disable-next-line unicorn/no-thenable public async then( // eslint-disable-next-line @rushstack/no-new-null onfulfilled?: ((value: T) => TResult1 | PromiseLike) | null | undefined, // TODO: Use `unknown` instead (API breaking) // eslint-disable-next-line @rushstack/no-new-null, @typescript-eslint/no-explicit-any onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined, ): Promise { // eslint-disable-next-line prefer-rest-params return this.getPromise().then(...arguments); } public async catch( // TODO: Use `unknown` instead (API breaking) // eslint-disable-next-line @rushstack/no-new-null, @typescript-eslint/no-explicit-any onrejected?: ((reason: any) => TResult | PromiseLike) | null | undefined, ): Promise { // eslint-disable-next-line prefer-rest-params return this.getPromise().catch(...arguments); } // eslint-disable-next-line @rushstack/no-new-null public async finally(onfinally?: (() => void) | null | undefined): Promise { // eslint-disable-next-line prefer-rest-params return this.getPromise().finally(...arguments); } private async getPromise(): Promise { // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- using ??= could change behavior if result is a falsy value if (this.result === undefined) { this.result = this.execute(); } return this.result; } }