@byloth/core 2.1.2 → 2.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core.cjs +2 -2
- package/dist/core.cjs.map +1 -1
- package/dist/core.esm.js +263 -235
- package/dist/core.esm.js.map +1 -1
- package/dist/core.global.js +2 -2
- package/dist/core.global.js.map +1 -1
- package/dist/core.umd.cjs +2 -2
- package/dist/core.umd.cjs.map +1 -1
- package/package.json +6 -6
- package/src/index.ts +1 -1
- package/src/models/aggregators/aggregated-async-iterator.ts +1 -1
- package/src/models/aggregators/aggregated-iterator.ts +1 -1
- package/src/models/aggregators/reduced-iterator.ts +1 -1
- package/src/models/callbacks/callable-object.ts +1 -2
- package/src/models/callbacks/publisher.ts +85 -13
- package/src/models/callbacks/switchable-callback.ts +1 -1
- package/src/models/callbacks/types.ts +13 -0
- package/src/models/collections/map-view.ts +6 -2
- package/src/models/collections/set-view.ts +7 -2
- package/src/models/collections/types.ts +1 -0
- package/src/models/iterators/smart-async-iterator.ts +1 -1
- package/src/models/iterators/smart-iterator.ts +1 -1
- package/src/models/json/json-storage.ts +3 -3
- package/src/models/promises/deferred-promise.ts +7 -2
- package/src/models/promises/smart-promise.ts +1 -1
- package/src/models/timers/clock.ts +2 -8
- package/src/models/timers/countdown.ts +2 -3
- package/src/models/timers/game-loop.ts +4 -8
- package/src/utils/date.ts +1 -2
package/dist/core.global.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.global.js","sources":["../src/helpers.ts","../src/models/exceptions/core.ts","../src/models/exceptions/index.ts","../src/models/iterators/smart-iterator.ts","../src/models/aggregators/reduced-iterator.ts","../src/models/aggregators/aggregated-async-iterator.ts","../src/models/iterators/smart-async-iterator.ts","../src/models/aggregators/aggregated-iterator.ts","../src/models/callbacks/callable-object.ts","../src/models/callbacks/publisher.ts","../src/models/callbacks/switchable-callback.ts","../src/models/collections/map-view.ts","../src/models/collections/set-view.ts","../src/models/json/json-storage.ts","../src/models/promises/smart-promise.ts","../src/models/promises/deferred-promise.ts","../src/models/promises/timed-promise.ts","../src/utils/date.ts","../src/models/timers/game-loop.ts","../src/models/timers/clock.ts","../src/models/timers/countdown.ts","../src/utils/curve.ts","../src/utils/random.ts","../src/utils/async.ts","../src/utils/dom.ts","../src/utils/iterator.ts","../src/utils/math.ts","../src/utils/string.ts","../src/index.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/ban-ts-comment */\n\n/**\n * An utility constant that indicates whether the current environment is a browser.\n */\n// @ts-ignore\nexport const isBrowser = ((typeof window !== \"undefined\") && (typeof window.document !== \"undefined\"));\n\n/**\n * An utility constant that indicates whether the current environment is a Node.js runtime.\n */\n// @ts-ignore\nexport const isNode = ((typeof process !== \"undefined\") && !!(process.versions?.node));\n\n/**\n * An utility constant that indicates whether the current environment is a Web Worker.\n */\n// @ts-ignore\nexport const isWorker = ((typeof self === \"object\") && (self.constructor?.name === \"DedicatedWorkerGlobalScope\"));\n","/**\n * A class representing an exception, subclass of the native {@link Error} class. \n * It's the base class for any other further exception.\n *\n * It allows to chain exceptions together, tracking the initial cause of an error and\n * storing its stack trace while providing a clear and friendly message to the user.\n *\n * ---\n *\n * @example\n * ```ts\n * try { loadGameSaves(); }\n * catch (error)\n * {\n * throw new Exception(\"The game saves may be corrupted. Try to restart the game.\", error);\n * // Uncaught Exception: The game saves may be corrupted. Try to restart the game.\n * // at /src/game/index.ts:37:15\n * // at /src/main.ts:23:17\n * //\n * // Caused by SyntaxError: Unexpected end of JSON input\n * // at /src/models/saves.ts:47:17\n * // at /src/game/index.ts:12:9\n * // at /src/main.ts:23:17\n * }\n * ```\n */\nexport default class Exception extends Error\n{\n /**\n * A static method to convert a generic caught error, ensuring it's an instance of the {@link Exception} class.\n *\n * ---\n *\n * @example\n * ```ts\n * try { [...] }\n * catch (error)\n * {\n * const exc = Exception.FromUnknown(error);\n *\n * [...]\n * }\n * ```\n *\n * ---\n *\n * @param error The caught error to convert.\n *\n * @returns An instance of the {@link Exception} class.\n */\n public static FromUnknown(error: unknown): Exception\n {\n if (error instanceof Exception)\n {\n return error;\n }\n if (error instanceof Error)\n {\n const exc = new Exception(error.message);\n\n exc.stack = error.stack;\n exc.name = error.name;\n\n return exc;\n }\n\n return new Exception(`${error}`);\n }\n\n /**\n * Initializes a new instance of the {@link Exception} class.\n *\n * ---\n *\n * @example\n * ```ts\n * throw new Exception(\"An error occurred while processing the request.\");\n * ```\n *\n * ---\n *\n * @param message The message that describes the error.\n * @param cause The previous caught error that caused this one, if any.\n * @param name The name of the exception. Default is `\"Exception\"`.\n */\n public constructor(message: string, cause?: unknown, name = \"Exception\")\n {\n super(message);\n\n this.cause = cause;\n this.name = name;\n\n if (cause)\n {\n if (cause instanceof Error)\n {\n this.stack += `\\n\\nCaused by ${cause.stack}`;\n }\n else\n {\n this.stack += `\\n\\nCaused by ${cause}`;\n }\n }\n }\n\n public readonly [Symbol.toStringTag]: string = \"Exception\";\n}\n\n/**\n * An utility class representing that kind of situation where the program should never reach. \n * Also commonly used to satisfy the type-system, but not part of a real feasible scenario.\n *\n * It provides a clear and friendly message by default.\n *\n * ---\n *\n * @example\n * ```ts\n * function checkCase(value: \"A\" | \"B\" | \"C\"): 1 | 2 | 3\n * {\n * switch (value)\n * {\n * case \"A\": return 1;\n * case \"B\": return 2;\n * case \"C\": return 3;\n * default: throw new FatalErrorException();\n * }\n * }\n * ```\n */\nexport class FatalErrorException extends Exception\n{\n /**\n * Initializes a new instance of the {@link FatalErrorException} class.\n *\n * ---\n *\n * @example\n * ```ts\n * throw new FatalErrorException(\"This error should never happen. Please, contact the support team.\");\n * ```\n *\n * ---\n *\n * @param message The message that describes the error.\n * @param cause The previous caught error that caused this one, if any.\n * @param name The name of the exception. Default is `\"FatalErrorException\"`.\n */\n public constructor(message?: string, cause?: unknown, name = \"FatalErrorException\")\n {\n if (message === undefined)\n {\n message = \"The program has encountered an unrecoverable error and cannot continue as expected. \" +\n \"Please, try again later. If the problem persists, contact the support team.\";\n }\n\n super(message, cause, name);\n }\n\n public override readonly [Symbol.toStringTag]: string = \"FatalErrorException\";\n}\n\n/**\n * An utility class representing a situation where a feature isn't implemented yet. \n * It's commonly used as a placeholder for future implementations.\n *\n * It provides a clear and friendly message by default.\n *\n * ---\n *\n * @example\n * ```ts\n * class Database\n * {\n * public async connect(): Promise<void>\n * {\n * throw new NotImplementedException();\n * }\n * }\n * ```\n */\nexport class NotImplementedException extends FatalErrorException\n{\n /**\n * Initializes a new instance of the {@link NotImplementedException} class.\n *\n * ---\n *\n * @example\n * ```ts\n * throw new NotImplementedException(\"This method hasn't been implemented yet. Check back later.\");\n * ```\n *\n * ---\n *\n * @param message The message that describes the error.\n * @param cause The previous caught error that caused this one, if any.\n * @param name The name of the exception. Default is `\"NotImplementedException\"`.\n */\n public constructor(message?: string, cause?: unknown, name = \"NotImplementedException\")\n {\n if (message === undefined)\n {\n message = \"This feature isn't implemented yet. Please, try again later.\";\n }\n\n super(message, cause, name);\n }\n\n public override readonly [Symbol.toStringTag]: string = \"NotImplementedException\";\n}\n","import Exception from \"./core.js\";\n\n/**\n * A class representing a generic exception that can be thrown when a file\n * operation fails, such as reading, writing, copying, moving, deleting, etc...\n *\n * It can also be used to catch all file-related exceptions at once.\n *\n * ---\n *\n * @example\n * ```ts\n * try { [...] }\n * catch (error)\n * {\n * if (error instanceof FileException)\n * {\n * // A file-related exception occurred. Handle it...\n * }\n * }\n * ```\n */\nexport class FileException extends Exception\n{\n /**\n * Initializes a new instance of the {@link FileException} class.\n *\n * ---\n *\n * @example\n * ```ts\n * throw new FileException(\"An error occurred while trying to read the file.\");\n * ```\n *\n * ---\n *\n * @param message The message that describes the error.\n * @param cause The previous caught error that caused this one, if any.\n * @param name The name of the exception. Default is `\"FileException\"`.\n */\n public constructor(message: string, cause?: unknown, name = \"FileException\")\n {\n super(message, cause, name);\n }\n\n public override readonly [Symbol.toStringTag]: string = \"FileException\";\n}\n\n/**\n * A class representing an exception that can be thrown when a file already exists.\n *\n * ---\n *\n * @example\n * ```ts\n * import { existsSync } from \"node:fs\";\n *\n * if (existsSync(\"file.txt\"))\n * {\n * throw new FileExistsException(\"The file named 'file.txt' already exists.\");\n * }\n * ```\n */\nexport class FileExistsException extends FileException\n{\n /**\n * Initializes a new instance of the {@link FileExistsException} class.\n *\n * ---\n *\n * @example\n * ```ts\n * throw new FileExistsException(\"The file named 'data.json' already exists on the server.\");\n * ```\n *\n * ---\n *\n * @param message The message that describes the error.\n * @param cause The previous caught error that caused this one, if any.\n * @param name The name of the exception. Default is `\"FileExistsException\"`.\n */\n public constructor(message: string, cause?: unknown, name = \"FileExistsException\")\n {\n super(message, cause, name);\n }\n\n public override readonly [Symbol.toStringTag]: string = \"FileExistsException\";\n}\n\n/**\n * A class representing an exception that can be thrown when a file isn't found.\n *\n * ---\n *\n * @example\n * ```ts\n * import { existsSync } from \"node:fs\";\n *\n * if (!existsSync(\"file.txt\"))\n * {\n * throw new FileNotFoundException(\"The file named 'file.txt' wasn't found.\");\n * }\n * ```\n */\nexport class FileNotFoundException extends FileException\n{\n /**\n * Initializes a new instance of the {@link FileNotFoundException} class.\n *\n * ---\n *\n * @example\n * ```ts\n * throw new FileNotFoundException(\"The file named 'data.json' wasn't found on the server.\");\n * ```\n *\n * ---\n *\n * @param message The message that describes the error.\n * @param cause The previous caught error that caused this one, if any.\n * @param name The name of the exception. Default is `\"FileNotFoundException\"`.\n */\n public constructor(message: string, cause?: unknown, name = \"FileNotFoundException\")\n {\n super(message, cause, name);\n }\n\n public override readonly [Symbol.toStringTag]: string = \"FileNotFoundException\";\n}\n\n/**\n * A class representing an exception that can be thrown when a key is invalid or not found. \n * It's commonly used when working with dictionaries, maps, objects, sets, etc...\n *\n * ---\n *\n * @example\n * ```ts\n * const map = new Map<string, number>();\n * if (!map.has(\"hash\"))\n * {\n * throw new KeyException(\"The key 'hash' wasn't found in the collection.\");\n * }\n * ```\n */\nexport class KeyException extends Exception\n{\n /**\n * Initializes a new instance of the {@link KeyException} class.\n *\n * ---\n *\n * @example\n * ```ts\n * throw new KeyException(\"The 'id' key wasn't found in the dictionary.\");\n * ```\n *\n * ---\n *\n * @param message The message that describes the error.\n * @param cause The previous caught error that caused this one, if any.\n * @param name The name of the exception. Default is `\"KeyException\"`.\n */\n public constructor(message: string, cause?: unknown, name = \"KeyException\")\n {\n super(message, cause, name);\n }\n\n public override readonly [Symbol.toStringTag]: string = \"KeyException\";\n}\n\n/**\n * A class representing an exception that can be thrown when a network operation fails. \n * It's commonly used when it's unable to connect to a server or when a request times out.\n *\n * ---\n *\n * @example\n * ```ts\n * import axios, { isAxiosError } from \"axios\";\n *\n * try { await axios.get(\"https://api.example.com/data\"); }\n * catch (error)\n * {\n * if (isAxiosError(error) && !error.response)\n * {\n * throw new NetworkException(\n * \"Unable to establish a connection to the server. \" +\n * \"Please, check your internet connection and try again.\"\n * );\n * }\n * }\n * ```\n */\nexport class NetworkException extends Exception\n{\n /**\n * Initializes a new instance of the {@link NetworkException} class.\n *\n * ---\n *\n * @example\n * ```ts\n * throw new NetworkException(\"Couldn't connect to the server. Please, try again later.\");\n * ```\n *\n * ---\n *\n * @param message The message that describes the error.\n * @param cause The previous caught error that caused this one, if any.\n * @param name The name of the exception. Default is `\"NetworkException\"`.\n */\n public constructor(message: string, cause?: unknown, name = \"NetworkException\")\n {\n super(message, cause, name);\n }\n\n public override readonly [Symbol.toStringTag]: string = \"NetworkException\";\n}\n\n/**\n * A class representing an exception that can be thrown when a permission is denied. \n * It's commonly used when an user tries to access a restricted resource or perform a forbidden action.\n *\n * ---\n *\n * @example\n * ```ts\n * const $user = useUserStore();\n * if (!$user.isAdmin)\n * {\n * throw new PermissionException(\"You don't have permission to perform this action.\");\n * }\n * ```\n */\nexport class PermissionException extends Exception\n{\n /**\n * Initializes a new instance of the {@link PermissionException} class.\n *\n * ---\n *\n * @example\n * ```ts\n * throw new PermissionException(\"You don't have permission to access this resource.\");\n * ```\n *\n * ---\n *\n * @param message The message that describes the error.\n * @param cause The previous caught error that caused this one, if any.\n * @param name The name of the exception. Default is `\"PermissionException\"`.\n */\n public constructor(message: string, cause?: unknown, name = \"PermissionException\")\n {\n super(message, cause, name);\n }\n\n public override readonly [Symbol.toStringTag]: string = \"PermissionException\";\n}\n\n/**\n * A class representing an exception that can be thrown when a reference is invalid or not found. \n * It's commonly used when a variable is `null`, `undefined` or when an object doesn't exist.\n *\n * ---\n *\n * @example\n * ```ts\n * const $el = document.getElementById(\"app\");\n * if ($el === null)\n * {\n * throw new ReferenceException(\"The element with the ID 'app' wasn't found in the document.\");\n * }\n * ```\n */\nexport class ReferenceException extends Exception\n{\n /**\n * Initializes a new instance of the {@link ReferenceException} class.\n *\n * ---\n *\n * @example\n * ```ts\n * throw new ReferenceException(\"The 'canvas' element wasn't found in the document.\");\n * ```\n *\n * ---\n *\n * @param message The message that describes the error.\n * @param cause The previous caught error that caused this one, if any.\n * @param name The name of the exception. Default is `\"ReferenceException\"`.\n */\n public constructor(message: string, cause?: unknown, name = \"ReferenceException\")\n {\n super(message, cause, name);\n }\n\n public override readonly [Symbol.toStringTag]: string = \"ReferenceException\";\n}\n\n/**\n * A class representing an exception that can be thrown when a runtime error occurs. \n * It's commonly used when an unexpected condition is encountered during the execution of a program.\n *\n * ---\n *\n * @example\n * ```ts\n * let status: \"enabled\" | \"disabled\" = \"enabled\";\n *\n * function enable(): void\n * {\n * if (status === \"enabled\") { throw new RuntimeException(\"The feature is already enabled.\"); }\n * status = \"enabled\";\n * }\n * ```\n */\nexport class RuntimeException extends Exception\n{\n /**\n * Initializes a new instance of the {@link RuntimeException} class.\n *\n * ---\n *\n * @example\n * ```ts\n * throw new RuntimeException(\"The received input seems to be malformed or corrupted.\");\n * ```\n *\n * ---\n *\n * @param message The message that describes the error.\n * @param cause The previous caught error that caused this one, if any.\n * @param name The name of the exception. Default is `\"RuntimeException\"`.\n */\n public constructor(message: string, cause?: unknown, name = \"RuntimeException\")\n {\n super(message, cause, name);\n }\n\n public override readonly [Symbol.toStringTag]: string = \"RuntimeException\";\n}\n\n/**\n * A class representing an exception that can be thrown when an environment\n * isn't properly configured or when a required variable isn't set. \n * It can also be used when the environment on which the program is running is unsupported.\n *\n * ---\n *\n * @example\n * ```ts\n * if (!navigator.geolocation)\n * {\n * throw new EnvironmentException(\"The Geolocation API isn't supported in this environment.\");\n * }\n * ```\n */\nexport class EnvironmentException extends RuntimeException\n{\n /**\n * Initializes a new instance of the {@link EnvironmentException} class.\n *\n * ---\n *\n * @example\n * ```ts\n * throw new EnvironmentException(\"The required environment variable 'API_KEY' isn't set.\");\n * ```\n *\n * ---\n *\n * @param message The message that describes the error.\n * @param cause The previous caught error that caused this one, if any.\n * @param name The name of the exception. Default is `\"EnvironmentException\"`.\n */\n public constructor(message: string, cause?: unknown, name = \"EnvironmentException\")\n {\n super(message, cause, name);\n }\n\n public override readonly [Symbol.toStringTag]: string = \"EnvironmentException\";\n}\n\n/**\n * A class representing an exception that can be thrown when a timeout occurs. \n * It's commonly used when a task takes too long to complete or when a request times out.\n *\n * ---\n *\n * @example\n * ```ts\n * const timeoutId = setTimeout(() => { throw new TimeoutException(\"The request timed out.\"); }, 5_000);\n * const response = await fetch(\"https://api.example.com/data\");\n *\n * clearTimeout(timeoutId);\n * ```\n */\nexport class TimeoutException extends Exception\n{\n /**\n * Initializes a new instance of the {@link TimeoutException} class.\n *\n * ---\n *\n * @example\n * ```ts\n * throw new TimeoutException(\"The task took too long to complete.\");\n * ```\n *\n * ---\n *\n * @param message The message that describes the error.\n * @param cause The previous caught error that caused this one, if any.\n * @param name The name of the exception. Default is `\"TimeoutException\"`.\n */\n public constructor(message: string, cause?: unknown, name = \"TimeoutException\")\n {\n super(message, cause, name);\n }\n\n public override readonly [Symbol.toStringTag]: string = \"TimeoutException\";\n}\n\n/**\n * A class representing an exception that can be thrown when a type is invalid or not supported. \n * It's commonly used when a function receives an unexpected type of argument.\n *\n * ---\n *\n * @example\n * ```ts\n * function greet(name: string): void\n * {\n * if (typeof name !== \"string\")\n * {\n * throw new TypeException(\"The 'name' argument must be a valid string.\");\n * }\n * }\n * ```\n */\nexport class TypeException extends Exception\n{\n /**\n * Initializes a new instance of the {@link TypeException} class.\n *\n * ---\n *\n * @example\n * ```ts\n * throw new TypeException(\"The 'username' argument must be a valid string.\");\n * ```\n *\n * ---\n *\n * @param message The message that describes the error.\n * @param cause The previous caught error that caused this one, if any.\n * @param name The name of the exception. Default is `\"TypeException\"`.\n */\n public constructor(message: string, cause?: unknown, name = \"TypeException\")\n {\n super(message, cause, name);\n }\n\n public override readonly [Symbol.toStringTag]: string = \"TypeException\";\n}\n\n/**\n * A class representing an exception that can be thrown when a value is invalid. \n * It's commonly used when a function receives an unexpected value as an argument.\n *\n * ---\n *\n * @example\n * ```ts\n * function setVolume(value: number): void\n * {\n * if (value < 0)\n * {\n * throw new ValueException(\"The 'value' argument must be greater than or equal to 0.\");\n * }\n * }\n * ```\n */\nexport class ValueException extends Exception\n{\n /**\n * Initializes a new instance of the {@link ValueException} class.\n *\n * ---\n *\n * @example\n * ```ts\n * throw new ValueException(\"The 'grade' argument cannot be negative.\");\n * ```\n *\n * ---\n *\n * @param message The message that describes the error.\n * @param cause The previous caught error that caused this one, if any.\n * @param name The name of the exception. Default is `\"ValueException\"`.\n */\n public constructor(message: string, cause?: unknown, name = \"ValueException\")\n {\n super(message, cause, name);\n }\n\n public override readonly [Symbol.toStringTag]: string = \"ValueException\";\n}\n\n/**\n * A class representing an exception that can be thrown when a value is out of range. \n * It's commonly used when a function receives an unexpected value as an argument.\n *\n * ---\n *\n * @example\n * ```ts\n * function setVolume(value: number): void\n * {\n * if ((value < 0) || (value > 100))\n * {\n * throw new RangeException(\"The 'value' argument must be between 0 and 100.\");\n * }\n * }\n * ```\n */\nexport class RangeException extends ValueException\n{\n /**\n * Initializes a new instance of the {@link RangeException} class.\n *\n * ---\n *\n * @example\n * ```ts\n * throw new RangeException(\"The 'percentage' argument must be between 0 and 100.\");\n * ```\n *\n * ---\n *\n * @param message The message that describes the error.\n * @param cause The previous caught error that caused this one, if any.\n * @param name The name of the exception. Default is `\"RangeException\"`.\n */\n public constructor(message: string, cause?: unknown, name = \"RangeException\")\n {\n super(message, cause, name);\n }\n\n public override readonly [Symbol.toStringTag]: string = \"RangeException\";\n}\n\nexport { Exception };\nexport { FatalErrorException, NotImplementedException } from \"./core.js\";\n","import AggregatedIterator from \"../aggregators/aggregated-iterator.js\";\nimport { ValueException } from \"../exceptions/index.js\";\n\nimport type { GeneratorFunction, Iteratee, TypeGuardPredicate, Reducer, IteratorLike } from \"./types.js\";\n\n/**\n * A wrapper class representing an enhanced and instantiable version\n * of the native {@link Iterable} & {@link Iterator} interfaces.\n *\n * It provides a set of utility methods to better manipulate and\n * transform iterators in a functional and highly performant way. \n * It takes inspiration from the native {@link Array} methods like\n * {@link Array.map}, {@link Array.filter}, {@link Array.reduce}, etc...\n *\n * The class is lazy, meaning that the transformations are applied\n * only when the resulting iterator is materialized, not before. \n * This allows to chain multiple transformations without\n * the need to iterate over the elements multiple times.\n *\n * ---\n *\n * @example\n * ```ts\n * const result = new SmartIterator<number>([\"-5\", \"-4\", \"-3\", \"-2\", \"-1\", \"0\", \"1\", \"2\", \"3\", \"4\", \"5\"])\n * .map(Number)\n * .map((value) => value + Math.ceil(Math.abs(value / 2)))\n * .filter((value) => value >= 0)\n * .map((value) => value + 1)\n * .reduce((acc, value) => acc + value);\n *\n * console.log(result); // 31\n * ```\n *\n * ---\n *\n * @template T The type of elements in the iterator.\n * @template R The type of the final result of the iterator. Default is `void`.\n * @template N The type of the argument required by the `next` method. Default is `undefined`.\n */\nexport default class SmartIterator<T, R = void, N = undefined> implements Iterator<T, R, N>\n{\n /**\n * The native {@link Iterator} object that is being wrapped by this instance.\n */\n protected _iterator: Iterator<T, R, N>;\n\n /**\n * Initializes a new instance of the {@link SmartIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<string>([\"A\", \"B\", \"C\"]);\n * ```\n *\n * ---\n *\n * @param iterable The iterable object to wrap.\n */\n public constructor(iterable: Iterable<T, R, N>);\n\n /**\n * Initializes a new instance of the {@link SmartIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number, void, number>({\n * _sum: 0, _count: 0,\n *\n * next: function(value: number)\n * {\n * this._sum += value;\n * this._count += 1;\n *\n * return { done: false, value: this._sum / this._count };\n * }\n * })\n * ```\n *\n * ---\n *\n * @param iterator The iterator object to wrap.\n */\n public constructor(iterator: Iterator<T, R, N>);\n\n /**\n * Initializes a new instance of the {@link SmartIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number>(function* ()\n * {\n * for (let i = 2; i < 65_536; i *= 2) { yield (i - 1); }\n * });\n * ```\n *\n * ---\n *\n * @param generatorFn The generator function to wrap.\n */\n public constructor(generatorFn: GeneratorFunction<T, R, N>);\n\n /**\n * Initializes a new instance of the {@link SmartIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator(values);\n * ```\n *\n * ---\n *\n * @param argument The iterable, iterator or generator function to wrap.\n */\n public constructor(argument: IteratorLike<T, R, N> | GeneratorFunction<T, R, N>);\n public constructor(argument: IteratorLike<T, R, N> | GeneratorFunction<T, R, N>)\n {\n if (argument instanceof Function)\n {\n this._iterator = argument();\n }\n else if (Symbol.iterator in argument)\n {\n this._iterator = argument[Symbol.iterator]() as Iterator<T, R, N>;\n }\n else\n {\n this._iterator = argument;\n }\n }\n\n /**\n * Determines whether all elements of the iterator satisfy a given condition.\n * See also {@link SmartIterator.some}.\n *\n * This method will iterate over all elements of the iterator checking if they satisfy the condition. \n * Once a single element doesn't satisfy the condition, the method will return `false` immediately.\n *\n * This may lead to an unknown final state of the iterator, which may be entirely or partially consumed. \n * For this reason, it's recommended to consider it as consumed in any case and to not use it anymore. \n * Consider using {@link SmartIterator.find} instead.\n *\n * If the iterator is infinite and every element satisfies the condition, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number>([-2, -1, 0, 1, 2]);\n * const result = iterator.every((value) => value < 0);\n *\n * console.log(result); // false\n * ```\n *\n * ---\n *\n * @param predicate The condition to check for each element of the iterator.\n *\n * @returns `true` if all elements satisfy the condition, `false` otherwise.\n */\n public every(predicate: Iteratee<T, boolean>): boolean\n {\n let index = 0;\n\n while (true)\n {\n const result = this._iterator.next();\n\n if (result.done) { return true; }\n if (!(predicate(result.value, index))) { return false; }\n\n index += 1;\n }\n }\n\n /**\n * Determines whether any element of the iterator satisfies a given condition.\n * See also {@link SmartIterator.every}.\n *\n * This method will iterate over all elements of the iterator checking if they satisfy the condition. \n * Once a single element satisfies the condition, the method will return `true` immediately.\n *\n * This may lead to an unknown final state of the iterator, which may be entirely or partially consumed. \n * For this reason, it's recommended to consider it as consumed in any case and to not use it anymore. \n * Consider using {@link SmartIterator.find} instead.\n *\n * If the iterator is infinite and no element satisfies the condition, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number>([-2, -1, 0, 1, 2]);\n * const result = iterator.some((value) => value < 0);\n *\n * console.log(result); // true\n * ```\n *\n * ---\n *\n * @param predicate The condition to check for each element of the iterator.\n *\n * @returns `true` if any element satisfies the condition, `false` otherwise.\n */\n public some(predicate: Iteratee<T, boolean>): boolean\n {\n let index = 0;\n\n while (true)\n {\n const result = this._iterator.next();\n\n if (result.done) { return false; }\n if (predicate(result.value, index)) { return true; }\n\n index += 1;\n }\n }\n\n /**\n * Filters the elements of the iterator using a given condition.\n *\n * This method will iterate over all elements of the iterator checking if they satisfy the condition. \n * If the condition is met, the element will be included in the new iterator.\n *\n * Since the iterator is lazy, the filtering process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number>([-2, -1, 0, 1, 2]);\n * const result = iterator.filter((value) => value < 0);\n *\n * console.log(result.toArray()); // [-2, -1]\n * ```\n *\n * ---\n *\n * @param predicate The condition to check for each element of the iterator.\n *\n * @returns A new {@link SmartIterator} containing only the elements that satisfy the condition.\n */\n public filter(predicate: Iteratee<T, boolean>): SmartIterator<T, R>;\n\n /**\n * Filters the elements of the iterator using a given condition.\n *\n * This method will iterate over all elements of the iterator checking if they satisfy the condition. \n * If the condition is met, the element will be included in the new iterator.\n *\n * Since the iterator is lazy, the filtering process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number | string>([-2, \"-1\", \"0\", 1, \"2\"]);\n * const result = iterator.filter<number>((value) => typeof value === \"number\");\n *\n * console.log(result.toArray()); // [-2, 1]\n * ```\n *\n * ---\n *\n * @template S\n * The type of the elements that satisfy the condition. \n * This allows the type-system to infer the correct type of the new iterator.\n *\n * It must be a subtype of the original type of the elements.\n *\n * @param predicate The type guard condition to check for each element of the iterator.\n *\n * @returns A new {@link SmartIterator} containing only the elements that satisfy the condition.\n */\n public filter<S extends T>(predicate: TypeGuardPredicate<T, S>): SmartIterator<S, R>;\n public filter(predicate: Iteratee<T, boolean>): SmartIterator<T, R>\n {\n const iterator = this._iterator;\n\n return new SmartIterator<T, R>(function* ()\n {\n let index = 0;\n while (true)\n {\n const result = iterator.next();\n if (result.done) { return result.value; }\n if (predicate(result.value, index)) { yield result.value; }\n\n index += 1;\n }\n });\n }\n\n /**\n * Maps the elements of the iterator using a given transformation function.\n *\n * This method will iterate over all elements of the iterator applying the transformation function. \n * The result of each transformation will be included in the new iterator.\n *\n * Since the iterator is lazy, the mapping process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number>([-2, -1, 0, 1, 2]);\n * const result = iterator.map((value) => Math.abs(value));\n *\n * console.log(result.toArray()); // [2, 1, 0, 1, 2]\n * ```\n *\n * ---\n *\n * @template V The type of the elements after the transformation.\n *\n * @param iteratee The transformation function to apply to each element of the iterator.\n *\n * @returns A new {@link SmartIterator} containing the transformed elements.\n */\n public map<V>(iteratee: Iteratee<T, V>): SmartIterator<V, R>\n {\n const iterator = this._iterator;\n\n return new SmartIterator<V, R>(function* ()\n {\n let index = 0;\n while (true)\n {\n const result = iterator.next();\n if (result.done) { return result.value; }\n\n yield iteratee(result.value, index);\n\n index += 1;\n }\n });\n }\n\n /**\n * Reduces the elements of the iterator using a given reducer function. \n * This method will consume the entire iterator in the process.\n *\n * It will iterate over all elements of the iterator applying the reducer function. \n * The result of each iteration will be passed as the accumulator to the next one.\n *\n * The first accumulator value will be the first element of the iterator. \n * The last accumulator value will be the final result of the reduction.\n *\n * Also note that:\n * - If an empty iterator is provided, a {@link ValueException} will be thrown.\n * - If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number>([1, 2, 3, 4, 5]);\n * const result = iterator.reduce((acc, value) => acc + value);\n *\n * console.log(result); // 15\n * ```\n *\n * ---\n *\n * @param reducer The reducer function to apply to each element of the iterator.\n *\n * @returns The final result of the reduction.\n */\n public reduce(reducer: Reducer<T, T>): T;\n\n /**\n * Reduces the elements of the iterator using a given reducer function. \n * This method will consume the entire iterator in the process.\n *\n * It will iterate over all elements of the iterator applying the reducer function. \n * The result of each iteration will be passed as the accumulator to the next one.\n *\n * The first accumulator value will be the provided initial value. \n * The last accumulator value will be the final result of the reduction.\n *\n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number>([1, 2, 3, 4, 5]);\n * const result = iterator.reduce((acc, value) => acc + value, 10);\n *\n * console.log(result); // 25\n * ```\n *\n * ---\n *\n * @template A The type of the accumulator value which will also be the type of the final result of the reduction.\n *\n * @param reducer The reducer function to apply to each element of the iterator.\n * @param initialValue The initial value of the accumulator.\n *\n * @returns The final result of the reduction.\n */\n public reduce<A>(reducer: Reducer<T, A>, initialValue: A): A;\n public reduce<A>(reducer: Reducer<T, A>, initialValue?: A): A\n {\n let index = 0;\n let accumulator = initialValue;\n if (accumulator === undefined)\n {\n const result = this._iterator.next();\n if (result.done) { throw new ValueException(\"Cannot reduce an empty iterator without an initial value.\"); }\n\n accumulator = (result.value as unknown) as A;\n index += 1;\n }\n\n while (true)\n {\n const result = this._iterator.next();\n if (result.done) { return accumulator; }\n\n accumulator = reducer(accumulator, result.value, index);\n\n index += 1;\n }\n }\n\n /**\n * Flattens the elements of the iterator using a given transformation function.\n *\n * This method will iterate over all elements of the iterator applying the transformation function. \n * The result of each transformation will be flattened into the new iterator.\n *\n * Since the iterator is lazy, the flattening process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number[]>([[-2, -1], 0, 1, 2, [3, 4, 5]]);\n * const result = iterator.flatMap((value) => value);\n *\n * console.log(result.toArray()); // [-2, -1, 0, 1, 2, 3, 4, 5]\n * ```\n *\n * ---\n *\n * @template V The type of the elements after the transformation.\n *\n * @param iteratee The transformation function to apply to each element of the iterator.\n *\n * @returns A new {@link SmartIterator} containing the flattened elements.\n */\n public flatMap<V>(iteratee: Iteratee<T, V | readonly V[]>): SmartIterator<V, R>\n {\n const iterator = this._iterator;\n\n return new SmartIterator<V, R>(function* ()\n {\n let index = 0;\n while (true)\n {\n const result = iterator.next();\n if (result.done) { return result.value; }\n\n const elements = iteratee(result.value, index);\n if (elements instanceof Array)\n {\n for (const value of elements) { yield value; }\n }\n else { yield elements; }\n\n index += 1;\n }\n });\n }\n\n /**\n * Drops a given number of elements at the beginning of the iterator. \n * The remaining elements will be included in a new iterator.\n * See also {@link SmartIterator.take}.\n *\n * Since the iterator is lazy, the dropping process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * Only the dropped elements will be consumed in the process. \n * The rest of the iterator will be consumed only once the new one is.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number>([-2, -1, 0, 1, 2]);\n * const result = iterator.drop(3);\n *\n * console.log(result.toArray()); // [1, 2]\n * ```\n *\n * ---\n *\n * @param count The number of elements to drop.\n *\n * @returns A new {@link SmartIterator} containing the remaining elements.\n */\n public drop(count: number): SmartIterator<T, R | undefined>\n {\n const iterator = this._iterator;\n\n return new SmartIterator<T, R | undefined>(function* ()\n {\n let index = 0;\n while (index < count)\n {\n const result = iterator.next();\n if (result.done) { return; }\n\n index += 1;\n }\n\n while (true)\n {\n const result = iterator.next();\n if (result.done) { return result.value; }\n\n yield result.value;\n }\n });\n }\n\n /**\n * Takes a given number of elements at the beginning of the iterator. \n * These elements will be included in a new iterator.\n * See also {@link SmartIterator.drop}.\n *\n * Since the iterator is lazy, the taking process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * Only the taken elements will be consumed from the original iterator. \n * The rest of the original iterator will be available for further consumption.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number>([-2, -1, 0, 1, 2]);\n * const result = iterator.take(3);\n *\n * console.log(result.toArray()); // [-2, -1, 0]\n * console.log(iterator.toArray()); // [1, 2]\n * ```\n *\n * ---\n *\n * @param limit The number of elements to take.\n *\n * @returns A new {@link SmartIterator} containing the taken elements.\n */\n public take(limit: number): SmartIterator<T, R | undefined>\n {\n const iterator = this._iterator;\n\n return new SmartIterator<T, R | undefined>(function* ()\n {\n let index = 0;\n while (index < limit)\n {\n const result = iterator.next();\n if (result.done) { return result.value; }\n\n yield result.value;\n\n index += 1;\n }\n\n return;\n });\n }\n\n /**\n * Finds the first element of the iterator that satisfies a given condition.\n *\n * This method will iterate over all elements of the iterator checking if they satisfy the condition. \n * The first element that satisfies the condition will be returned immediately.\n *\n * Only the elements that are necessary to find the first\n * satisfying one will be consumed from the original iterator. \n * The rest of the original iterator will be available for further consumption.\n *\n * Also note that:\n * - If no element satisfies the condition, `undefined` will be returned once the entire iterator is consumed.\n * - If the iterator is infinite and no element satisfies the condition, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number>([-2, -1, 0, 1, 2]);\n * const result = iterator.find((value) => value > 0);\n *\n * console.log(result); // 1\n * ```\n *\n * ---\n *\n * @param predicate The condition to check for each element of the iterator.\n *\n * @returns The first element that satisfies the condition, `undefined` otherwise.\n */\n public find(predicate: Iteratee<T, boolean>): T | undefined;\n\n /**\n * Finds the first element of the iterator that satisfies a given condition.\n *\n * This method will iterate over all elements of the iterator checking if they satisfy the condition. \n * The first element that satisfies the condition will be returned immediately.\n *\n * Only the elements that are necessary to find the first\n * satisfying one will be consumed from the original iterator. \n * The rest of the original iterator will be available for further consumption.\n *\n * Also note that:\n * - If no element satisfies the condition, `undefined` will be returned once the entire iterator is consumed.\n * - If the iterator is infinite and no element satisfies the condition, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number | string>([-2, \"-1\", \"0\", 1, \"2\"]);\n * const result = iterator.find<number>((value) => typeof value === \"number\");\n *\n * console.log(result); // -2\n * ```\n *\n * ---\n *\n * @template S\n * The type of the element that satisfies the condition. \n * This allows the type-system to infer the correct type of the result.\n *\n * It must be a subtype of the original type of the elements.\n *\n * @param predicate The type guard condition to check for each element of the iterator.\n *\n * @returns The first element that satisfies the condition, `undefined` otherwise.\n */\n public find<S extends T>(predicate: TypeGuardPredicate<T, S>): S | undefined;\n public find(predicate: Iteratee<T, boolean>): T | undefined\n {\n let index = 0;\n\n while (true)\n {\n const result = this._iterator.next();\n\n if (result.done) { return; }\n if (predicate(result.value, index)) { return result.value; }\n\n index += 1;\n }\n }\n\n /**\n * Enumerates the elements of the iterator. \n * Each element is be paired with its index in a new iterator.\n *\n * Since the iterator is lazy, the enumeration process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<string>([\"A\", \"M\", \"N\", \"Z\"]);\n * const result = iterator.enumerate();\n *\n * console.log(result.toArray()); // [[0, \"A\"], [1, \"M\"], [2, \"N\"], [3, \"Z\"]]\n * ```\n *\n * ---\n *\n * @returns A new {@link SmartIterator} containing the enumerated elements.\n */\n public enumerate(): SmartIterator<[number, T], R>\n {\n return this.map((value, index) => [index, value]);\n }\n\n /**\n * Removes all duplicate elements from the iterator. \n * The first occurrence of each element will be kept.\n *\n * Since the iterator is lazy, the deduplication process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number>([1, 1, 2, 3, 2, 3, 4, 5, 5, 4]);\n * const result = iterator.unique();\n *\n * console.log(result.toArray()); // [1, 2, 3, 4, 5]\n * ```\n *\n * ---\n *\n * @returns A new {@link SmartIterator} containing only the unique elements.\n */\n public unique(): SmartIterator<T, R>\n {\n const iterator = this._iterator;\n\n return new SmartIterator<T, R>(function* ()\n {\n const values = new Set<T>();\n while (true)\n {\n const result = iterator.next();\n if (result.done) { return result.value; }\n if (values.has(result.value)) { continue; }\n values.add(result.value);\n\n yield result.value;\n }\n });\n }\n\n /**\n * Counts the number of elements in the iterator. \n * This method will consume the entire iterator in the process.\n *\n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number>([1, 2, 3, 4, 5]);\n * const result = iterator.count();\n *\n * console.log(result); // 5\n * ```\n *\n * ---\n *\n * @returns The number of elements in the iterator.\n */\n public count(): number\n {\n let index = 0;\n\n while (true)\n {\n const result = this._iterator.next();\n if (result.done) { return index; }\n\n index += 1;\n }\n }\n\n /**\n * Iterates over all elements of the iterator. \n * The elements are passed to the function along with their index.\n *\n * This method will consume the entire iterator in the process. \n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number>([\"A\", \"M\", \"N\", \"Z\"]);\n * iterator.forEach((value, index) =>\n * {\n * console.log(`${index}: ${value}`); // \"0: A\", \"1: M\", \"2: N\", \"3: Z\"\n * }\n * ```\n *\n * ---\n *\n * @param iteratee The function to apply to each element of the iterator.\n */\n public forEach(iteratee: Iteratee<T>): void\n {\n let index = 0;\n\n while (true)\n {\n const result = this._iterator.next();\n if (result.done) { return; }\n\n iteratee(result.value, index);\n\n index += 1;\n }\n }\n\n /**\n * Advances the iterator to the next element and returns the result. \n * If the iterator requires it, a value must be provided to be passed to the next element.\n *\n * Once the iterator is done, the method will return an object with the `done` property set to `true`.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number>([1, 2, 3, 4, 5]);\n *\n * let result = iterator.next();\n * while (!result.done)\n * {\n * console.log(result.value); // 1, 2, 3, 4, 5\n *\n * result = iterator.next();\n * }\n *\n * console.log(result); // { done: true, value: undefined }\n * ```\n *\n * ---\n *\n * @param values The value to pass to the next element, if required.\n *\n * @returns The result of the iteration, containing the value of the operation.\n */\n public next(...values: N extends undefined ? [] : [N]): IteratorResult<T, R>\n {\n return this._iterator.next(...values);\n }\n\n /**\n * An utility method that may be used to close the iterator gracefully,\n * free the resources and perform any cleanup operation. \n * It may also be used to signal the end or to compute a specific final result of the iteration process.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number>({\n * _index: 0,\n * next: function()\n * {\n * return { done: false, value: this._index += 1 };\n * },\n * return: function() { console.log(\"Closing the iterator...\"); }\n * });\n *\n * for (const value of iterator)\n * {\n * if (value > 5) { break; } // Closing the iterator...\n *\n * console.log(value); // 1, 2, 3, 4, 5\n * }\n * ```\n *\n * ---\n *\n * @param value The final value of the iterator.\n *\n * @returns The result of the iterator.\n */\n public return(value?: R): IteratorResult<T, R>\n {\n if (this._iterator.return) { return this._iterator.return(value); }\n\n return { done: true, value: value as R };\n }\n\n /**\n * An utility method that may be used to close the iterator due to an error,\n * free the resources and perform any cleanup operation. \n * It may also be used to signal that an error occurred during the iteration process or to handle it.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number>({\n * _index: 0,\n * next: function()\n * {\n * return { done: this._index > 10, value: this._index += 1 };\n * },\n * throw: function(error)\n * {\n * console.warn(error.message);\n *\n * this._index = 0;\n * }\n * });\n *\n * for (const value of iterator) // 1, 2, 3, 4, 5, \"The index is too high.\", 1, 2, 3, 4, 5, ...\n * {\n * try\n * {\n * if (value > 5) { throw new Error(\"The index is too high.\"); }\n *\n * console.log(value); // 1, 2, 3, 4, 5\n * }\n * catch (error) { iterator.throw(error); }\n * }\n * ```\n *\n * ---\n *\n * @param error The error to throw into the iterator.\n *\n * @returns The final result of the iterator.\n */\n public throw(error: unknown): IteratorResult<T, R>\n {\n if (this._iterator.throw) { return this._iterator.throw(error); }\n\n throw error;\n }\n\n /**\n * An utility method that aggregates the elements of the iterator using a given key function. \n * The elements will be grouped by the resulting keys in a new specialized iterator.\n * See {@link AggregatedIterator}.\n *\n * Since the iterator is lazy, the grouping process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * the new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number>([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);\n * const result = iterator.groupBy<string>((value) => value % 2 === 0 ? \"even\" : \"odd\");\n *\n * console.log(result.toObject()); // { odd: [1, 3, 5, 7, 9], even: [2, 4, 6, 8, 10] }\n * ```\n *\n * ---\n *\n * @template K The type of the keys used to group the elements.\n *\n * @param iteratee The key function to apply to each element of the iterator.\n *\n * @returns A new instance of the {@link AggregatedIterator} class containing the grouped elements.\n */\n public groupBy<K extends PropertyKey>(iteratee: Iteratee<T, K>): AggregatedIterator<K, T>\n {\n return new AggregatedIterator(this.map((element, index) =>\n {\n const key = iteratee(element, index);\n\n return [key, element] as [K, T];\n }));\n }\n\n /**\n * Materializes the iterator into an array. \n * This method will consume the entire iterator in the process.\n *\n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator(function* ()\n * {\n * for (let i = 0; i < 5; i += 1) { yield i; }\n * });\n * const result = iterator.toArray();\n *\n * console.log(result); // [0, 1, 2, 3, 4]\n * ```\n *\n * ---\n *\n * @returns The {@link Array} containing all elements of the iterator.\n */\n public toArray(): T[]\n {\n return Array.from(this as Iterable<T>);\n }\n\n public readonly [Symbol.toStringTag]: string = \"SmartIterator\";\n\n public [Symbol.iterator](): SmartIterator<T, R, N> { return this; }\n}\n","import { ValueException } from \"../exceptions/index.js\";\nimport { SmartIterator } from \"../iterators/index.js\";\nimport type { GeneratorFunction } from \"../iterators/types.js\";\n\nimport AggregatedIterator from \"./aggregated-iterator.js\";\nimport type { KeyedIteratee, KeyedReducer, KeyedTypeGuardPredicate } from \"./types.js\";\n\n/**\n * A class representing an aggregated iterator that has been reduced in a lazy and optimized way.\n *\n * It's part of the {@link AggregatedIterator} and {@link AggregatedAsyncIterator} implementations,\n * providing a way to reduce them into a single value or another aggregated iterable. \n * For this reason, it isn't recommended to instantiate this class directly\n * (although it's still possible), but rather use the reducing methods provided by the aggregated iterators.\n *\n * It isn't directly iterable, just like its parent class, and needs to specify on what you want to iterate. \n * See the {@link ReducedIterator.keys}, {@link ReducedIterator.entries}\n * & {@link ReducedIterator.values} methods. \n * It does, however, provide the same set of methods to perform\n * operations and transformation on the elements of the iterator, \n * having also the knowledge and context of the groups to which\n * they belong, allowing to handle them in a grouped manner.\n *\n * This is particularly useful when you have group elements and\n * need perform specific operations on the reduced elements.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .count();\n *\n * console.log(results.toObject()); // { odd: 4, even: 4 }\n * ```\n *\n * ---\n *\n * @template K The type of the key used to group the elements.\n * @template T The type of the elements in the iterator.\n */\nexport default class ReducedIterator<K extends PropertyKey, T>\n{\n /**\n * The internal {@link SmartIterator} object that holds the reduced elements.\n */\n protected _elements: SmartIterator<[K, T]>;\n\n /**\n * Initializes a new instance of the {@link ReducedIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new ReducedIterator<string, number>([[\"A\", 1], [\"B\", 2], [\"C\", 4]]);\n * ```\n *\n * ---\n *\n * @param iterable A reduced iterable object.\n */\n public constructor(iterable: Iterable<[K, T]>);\n\n /**\n * Initializes a new instance of the {@link ReducedIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new ReducedIterator<string, number>({\n * _index: 0,\n * next: () =>\n * {\n * if (this._index >= 3) { return { done: true, value: undefined }; }\n * this._index += 1;\n *\n * return { done: false, value: [[\"A\", \"B\", \"C\"][this._index], (this._index + 1)] };\n * }\n * });\n * ```\n *\n * ---\n *\n * @param iterator An reduced iterator object.\n */\n public constructor(iterator: Iterator<[K, T]>);\n\n /**\n * Initializes a new instance of the {@link ReducedIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * import { range, Random } from \"@byloth/core\";\n *\n * const results = new ReducedIterator<string, number>(function* ()\n * {\n * for (const index of range(3))\n * {\n * yield [[\"A\", \"B\", \"C\"][index], (index + 1)];\n * }\n * });\n * ```\n *\n * ---\n *\n * @param generatorFn A generator function that produces the reduced elements.\n */\n public constructor(generatorFn: GeneratorFunction<[K, T]>);\n\n /**\n * Initializes a new instance of the {@link ReducedIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new ReducedIterator(reducedValues);\n * ```\n *\n * ---\n *\n * @param argument An iterable, iterator or generator function that produces the reduced elements.\n */\n public constructor(argument: Iterable<[K, T]> | Iterator<[K, T]> | GeneratorFunction<[K, T]>);\n public constructor(argument: Iterable<[K, T]> | Iterator<[K, T]> | GeneratorFunction<[K, T]>)\n {\n this._elements = new SmartIterator(argument);\n }\n\n /**\n * Determines whether all elements of the reduced iterator satisfy the given condition.\n * See also {@link ReducedIterator.some}.\n *\n * This method will iterate over all the elements of the iterator checking if they satisfy the condition. \n * Once a single element doesn't satisfy the condition, the method will return `false` immediately.\n *\n * This may lead to an unknown final state of the iterator, which may be entirely or partially consumed. \n * For this reason, it's recommended to consider it as consumed in any case and to not use it anymore. \n * Consider using {@link ReducedIterator.find} instead.\n *\n * If the iterator is infinite and every element satisfies the condition, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value)\n * .every((key, value) => value > 0);\n *\n * console.log(results); // true\n * ```\n *\n * ---\n *\n * @param predicate The condition to check for each element of the iterator.\n *\n * @returns `true` if all elements satisfy the condition, `false` otherwise.\n */\n public every(predicate: KeyedIteratee<K, T, boolean>): boolean\n {\n for (const [index, [key, element]] of this._elements.enumerate())\n {\n if (!(predicate(key, element, index))) { return false; }\n }\n\n return true;\n }\n\n /**\n * Determines whether any element of the reduced iterator satisfies the given condition.\n * See also {@link ReducedIterator.every}.\n *\n * This method will iterate over all the elements of the iterator checking if they satisfy the condition. \n * Once a single element satisfies the condition, the method will return `true` immediately.\n *\n * This may lead to an unknown final state of the iterator, which may be entirely or partially consumed. \n * For this reason, it's recommended to consider it as consumed in any case and to not use it anymore. \n * Consider using {@link ReducedIterator.find} instead.\n *\n * If the iterator is infinite and no element satisfies the condition, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value)\n * .some((key, value) => value > 0);\n *\n * console.log(results); // true\n * ```\n *\n * ---\n *\n * @param predicate The condition to check for each element of the iterator.\n *\n * @returns `true` if any element satisfies the condition, `false` otherwise.\n */\n public some(predicate: KeyedIteratee<K, T, boolean>): boolean\n {\n for (const [index, [key, element]] of this._elements.enumerate())\n {\n if (predicate(key, element, index)) { return true; }\n }\n\n return false;\n }\n\n /**\n * Filters the elements of the reduced iterator using a given condition.\n *\n * This method will iterate over all the elements of the iterator checking if they satisfy the condition. \n * If the condition is met, the element will be included in the new iterator.\n *\n * Since the iterator is lazy, the filtering process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value)\n * .filter((key, value) => value > 0);\n *\n * console.log(results.toObject()); // { odd: 4, even: 16 }\n * ```\n *\n * ---\n *\n * @param predicate The condition to check for each element of the iterator.\n *\n * @returns A new {@link ReducedIterator} containing only the elements that satisfy the condition.\n */\n public filter(predicate: KeyedIteratee<K, T, boolean>): ReducedIterator<K, T>;\n\n /**\n * Filters the elements of the reduced iterator using a given type guard predicate.\n *\n * This method will iterate over all the elements of the iterator checking if they satisfy the condition. \n * If the condition is met, the element will be included in the new iterator.\n *\n * Since the iterator is lazy, the filtering process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number | string>([-3, -1, \"0\", \"2\", 3, 5, \"6\", \"8\"])\n * .groupBy((value) => Number(value) % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value)\n * .filter<number>((key, value) => typeof value === \"number\");\n *\n * console.log(results.toObject()); // { odd: 4 }\n * ```\n *\n * ---\n *\n * @template S\n * The type of the elements that satisfy the condition. \n * This allows the type-system to infer the correct type of the iterator.\n *\n * It must be a subtype of the original type of the elements.\n *\n * @param predicate The type guard condition to check for each element of the iterator.\n *\n * @returns A new {@link ReducedIterator} containing only the elements that satisfy the condition.\n */\n public filter<S extends T>(predicate: KeyedTypeGuardPredicate<K, T, S>): ReducedIterator<K, S>;\n public filter(predicate: KeyedIteratee<K, T, boolean>): ReducedIterator<K, T>\n {\n const elements = this._elements.enumerate();\n\n return new ReducedIterator(function* ()\n {\n for (const [index, [key, element]] of elements)\n {\n if (predicate(key, element, index)) { yield [key, element]; }\n }\n });\n }\n\n /**\n * Maps the elements of the reduced iterator using a given transformation function.\n *\n * This method will iterate over all the elements of the iterator applying the transformation function. \n * The result of the transformation will be included in the new iterator.\n *\n * Since the iterator is lazy, the mapping process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value)\n * .map((key, value) => value * 2);\n *\n * console.log(results.toObject()); // { odd: 8, even: 32 }\n * ```\n *\n * ---\n *\n * @template V The type of the elements after the transformation.\n *\n * @param iteratee The transformation function to apply to each element of the iterator.\n *\n * @returns A new {@link ReducedIterator} containing the transformed elements.\n */\n public map<V>(iteratee: KeyedIteratee<K, T, V>): ReducedIterator<K, V>\n {\n const elements = this._elements.enumerate();\n\n return new ReducedIterator(function* ()\n {\n for (const [index, [key, element]] of elements)\n {\n yield [key, iteratee(key, element, index)];\n }\n });\n }\n\n /**\n * Reduces the elements of the reduced iterator using a given reducer function. \n * This method will consume the entire iterator in the process.\n *\n * It will iterate over all the elements of the iterator applying the reducer function. \n * The result of each iteration will be passed as the accumulator to the next one.\n *\n * The first accumulator value will be the first element of the iterator. \n * The last accumulator value will be the final result of the reduction.\n *\n * Also note that:\n * - If an empty iterator is provided, a {@link ValueException} will be thrown.\n * - If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const result = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value)\n * .reduce((key, accumulator, value) => accumulator + value);\n *\n * console.log(result); // 20\n * ```\n *\n * ---\n *\n * @param reducer The reducer function to apply to the elements of the iterator.\n *\n * @returns The final value after reducing all the elements of the iterator.\n */\n public reduce(reducer: KeyedReducer<K, T, T>): T;\n\n /**\n * Reduces the elements of the reduced iterator using a given reducer function. \n * This method will consume the entire iterator in the process.\n *\n * It will iterate over all the elements of the iterator applying the reducer function. \n * The result of each iteration will be passed as the accumulator to the next one.\n *\n * The first accumulator value will be the provided initial value. \n * The last accumulator value will be the final result of the reduction.\n *\n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const result = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value)\n * .reduce((key, { value }, currentValue) => ({ value: value + currentValue }), { value: 0 });\n *\n * console.log(result); // { value: 20 }\n * ```\n *\n * ---\n *\n * @template A The type of the accumulator value which will also be the type of the final result of the reduction.\n *\n * @param reducer The reducer function to apply to the elements of the iterator.\n * @param initialValue The initial value of the accumulator.\n *\n * @returns The final result of the reduction.\n */\n public reduce<A>(reducer: KeyedReducer<K, T, A>, initialValue: A): A;\n public reduce<A>(reducer: KeyedReducer<K, T, A>, initialValue?: A): A\n {\n let index = 0;\n let accumulator = initialValue;\n if (accumulator === undefined)\n {\n const result = this._elements.next();\n if (result.done) { throw new ValueException(\"Cannot reduce an empty iterator without an initial value.\"); }\n\n accumulator = (result.value[1] as unknown) as A;\n index += 1;\n }\n\n for (const [key, element] of this._elements)\n {\n accumulator = reducer(key, accumulator, element, index);\n\n index += 1;\n }\n\n return accumulator;\n }\n\n /**\n * Flattens the elements of the reduced iterator using a given transformation function.\n *\n * This method will iterate over all the elements of the iterator applying the transformation function. \n * The result of each transformation will be flattened into the new iterator.\n *\n * Since the iterator is lazy, the flattening process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator.concat([value]), () => [])\n * .flatMap((key, value) => value);\n *\n * console.log(results.toObject()); // { odd: [-3, -1, 3, 5], even: [0, 2, 6, 8] }\n * ```\n *\n * ---\n *\n * @template V The type of the elements after the transformation.\n *\n * @param iteratee The transformation function to apply to each element of the iterator.\n *\n * @returns A new {@link AggregatedIterator} containing the flattened elements.\n */\n public flatMap<V>(iteratee: KeyedIteratee<K, T, V | readonly V[]>): AggregatedIterator<K, V>\n {\n const elements = this._elements.enumerate();\n\n return new AggregatedIterator(function* ()\n {\n for (const [index, [key, element]] of elements)\n {\n const values = iteratee(key, element, index);\n\n if (values instanceof Array)\n {\n for (const value of values) { yield [key, value]; }\n }\n else { yield [key, values]; }\n }\n });\n }\n\n /**\n * Drops a given number of elements at the beginning of the reduced iterator. \n * The remaining elements will be included in the new iterator.\n * See also {@link ReducedIterator.take}.\n *\n * Since the iterator is lazy, the dropping process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * Only the dropped elements will be consumed in the process. \n * The rest of the iterator will be consumed once the new iterator is.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator.concat(value), () => [])\n * .drop(1);\n *\n * console.log(results.toObject()); // { even: [0, 2, 6, 8] }\n * ```\n *\n * ---\n *\n * @param count The number of elements to drop.\n *\n * @returns A new {@link ReducedIterator} containing the remaining elements.\n */\n public drop(count: number): ReducedIterator<K, T>\n {\n const elements = this._elements.enumerate();\n\n return new ReducedIterator(function* ()\n {\n for (const [index, [key, element]] of elements)\n {\n if (index >= count) { yield [key, element]; }\n }\n });\n }\n\n /**\n * Takes a given number of elements at the beginning of the reduced iterator. \n * The elements will be included in the new iterator.\n * See also {@link ReducedIterator.drop}.\n *\n * Since the iterator is lazy, the taking process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * Only the taken elements will be consumed from the original reduced iterator. \n * The rest of the original reduced iterator will be available for further consumption.\n *\n * ---\n *\n * @example\n * ```ts\n * const reduced = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator.concat(value), () => []);\n *\n * const results = iterator.take(1);\n *\n * console.log(results.toObject()); // { odd: [-3, -1, 3, 5] }\n * console.log(reduced.toObject()); // { even: [0, 2, 6, 8] }\n * ```\n *\n * ---\n *\n * @param limit The number of elements to take.\n *\n * @returns A new {@link ReducedIterator} containing the taken elements.\n */\n public take(limit: number): ReducedIterator<K, T>\n {\n const elements = this._elements.enumerate();\n\n return new ReducedIterator(function* ()\n {\n for (const [index, [key, element]] of elements)\n {\n if (index >= limit) { break; }\n yield [key, element];\n }\n });\n }\n\n /**\n * Finds the first element of the reduced iterator that satisfies the given condition.\n *\n * This method will iterate over all the elements of the iterator checking if they satisfy the condition. \n * The first element that satisfies the condition will be returned immediately.\n *\n * Only the elements that are necessary to find the first\n * satisfying one will be consumed from the original iterator. \n * The rest of the iterator will be available for further consumption.\n *\n * Also note that:\n * - If no element satisfies the condition, `undefined` will be returned once the entire iterator is consumed.\n * - If the iterator is infinite and no element satisfies the condition, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -3, -1, 0, 1, 2, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value)\n * .find((key, value) => value > 0);\n *\n * console.log(results); // 16\n * ```\n *\n * ---\n *\n * @param predicate The condition to check for each element of the iterator.\n *\n * @returns The first element that satisfies the condition, `undefined` otherwise.\n */\n public find(predicate: KeyedIteratee<K, T, boolean>): T | undefined;\n\n /**\n * Finds the first element of the reduced iterator that satisfies the given type guard predicate.\n *\n * This method will iterate over all the elements of the iterator checking if they satisfy the condition. \n * The first element that satisfies the condition will be returned immediately.\n *\n * Only the elements that are necessary to find the first\n * satisfying one will be consumed from the original iterator. \n * The rest of the iterator will be available for further consumption.\n *\n * Also note that:\n * - If no element satisfies the condition, `undefined` will be returned once the entire iterator is consumed.\n * - If the iterator is infinite and no element satisfies the condition, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number | string>([\"-3\", -3, \"-1\", 0, 1, 2, \"5\", 6, 8])\n * .groupBy((value) => Number(value) % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value)\n * .find<number>((key, value) => typeof value === \"number\");\n *\n * console.log(results); // 16\n * ```\n *\n * ---\n *\n * @template S\n * The type of the elements that satisfy the condition. \n * This allows the type-system to infer the correct type of the result.\n *\n * It must be a subtype of the original type of the elements.\n *\n * @param predicate The type guard condition to check for each element of the iterator.\n *\n * @returns The first element that satisfies the condition, `undefined` otherwise.\n */\n public find<S extends T>(predicate: KeyedTypeGuardPredicate<K, T, S>): S | undefined;\n public find(predicate: KeyedIteratee<K, T, boolean>): T | undefined\n {\n for (const [index, [key, element]] of this._elements.enumerate())\n {\n if (predicate(key, element, index)) { return element; }\n }\n\n return undefined;\n }\n\n /**\n * Enumerates the elements of the reduced iterator. \n * Each element is paired with its index in a new iterator.\n *\n * Since the iterator is lazy, the enumeration process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new ReducedIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value)\n * .enumerate();\n *\n * console.log(results.toObject()); // [[0, 4], [1, 16]]\n * ```\n *\n * ---\n *\n * @returns A new {@link ReducedIterator} object containing the enumerated elements.\n */\n public enumerate(): ReducedIterator<K, [number, T]>\n {\n return this.map((_, element, index) => [index, element]);\n }\n\n /**\n * Removes all duplicate elements from the reduced iterator. \n * The first occurrence of each element will be kept.\n *\n * Since the iterator is lazy, the deduplication process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new ReducedIterator<number>([-3, -1, 0, 2, 3, 6, -3, -1, 1, 5, 6, 8, 7, 2])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .map((key, value) => Math.abs(value))\n * .reduce((key, accumulator, value) => accumulator + value)\n * .unique();\n *\n * console.log(results.toObject()); // { odd: 24 }\n *\n * @returns A new {@link ReducedIterator} containing only the unique elements.\n */\n public unique(): ReducedIterator<K, T>\n {\n const elements = this._elements;\n\n return new ReducedIterator(function* ()\n {\n const values = new Set<T>();\n for (const [key, element] of elements)\n {\n if (values.has(element)) { continue; }\n values.add(element);\n\n yield [key, element];\n }\n });\n }\n\n /**\n * Counts the number of elements in the reduced iterator. \n * This method will consume the entire iterator in the process.\n *\n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value)\n * .count();\n *\n * console.log(results); // 2\n * ```\n *\n * ---\n *\n * @returns The number of elements in the iterator.\n */\n public count(): number\n {\n let index = 0;\n\n for (const _ of this._elements) { index += 1; }\n\n return index;\n }\n\n /**\n * Iterates over all elements of the reduced iterator. \n * The elements are passed to the function along with their key and index.\n *\n * This method will consume the entire iterator in the process. \n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const reduced = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value);\n *\n * reduced.forEach((key, value, index) =>\n * {\n * console.log(`#${index} - ${key}: ${value}`); // \"#0 - odd: 4\", \"#1 - even: 16\"\n * });\n * ```\n *\n * ---\n *\n * @param iteratee The function to apply to each element of the reduced iterator.\n */\n public forEach(iteratee: KeyedIteratee<K, T>): void\n {\n for (const [index, [key, element]] of this._elements.enumerate())\n {\n iteratee(key, element, index);\n }\n }\n\n /**\n * Reaggregates the elements of the reduced iterator. \n * The elements are grouped by a new key computed by the given iteratee function.\n *\n * Since the iterator is lazy, the reorganizing process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, -6, -8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value)\n * .reorganizeBy((key, value) => value > 0 ? \"positive\" : \"negative\");\n *\n * console.log(results.toObject()); // { positive: 4, negative: -12 }\n * ```\n *\n * ---\n *\n * @template J The type of the new keys used to group the elements.\n *\n * @param iteratee The function to determine the new key of each element of the iterator.\n *\n * @returns A new {@link AggregatedIterator} containing the elements reorganized by the new keys.\n */\n public reorganizeBy<J extends PropertyKey>(iteratee: KeyedIteratee<K, T, J>): AggregatedIterator<J, T>\n {\n const elements = this._elements.enumerate();\n\n return new AggregatedIterator(function* ()\n {\n for (const [index, [key, element]] of elements)\n {\n yield [iteratee(key, element, index), element];\n }\n });\n }\n\n /**\n * An utility method that returns a new {@link SmartIterator}\n * object containing all the keys of the iterator.\n *\n * Since the iterator is lazy, the keys will be extracted\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const keys = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value)\n * .keys();\n *\n * console.log(keys.toArray()); // [\"odd\", \"even\"]\n * ```\n *\n * ---\n *\n * @returns A new {@link SmartIterator} containing all the keys of the iterator.\n */\n public keys(): SmartIterator<K>\n {\n const elements = this._elements;\n\n return new SmartIterator<K>(function* ()\n {\n for (const [key] of elements)\n {\n yield key;\n }\n });\n }\n\n /**\n * An utility method that returns a new {@link SmartIterator}\n * object containing all the entries of the iterator. \n * Each entry is a tuple containing the key and the element.\n *\n * Since the iterator is lazy, the entries will be extracted\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const entries = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value)\n * .entries();\n *\n * console.log(entries.toArray()); // [[\"odd\", 4], [\"even\", 16]]\n * ```\n *\n * ---\n *\n * @returns A new {@link SmartIterator} containing all the entries of the iterator.\n */\n public entries(): SmartIterator<[K, T]>\n {\n return this._elements;\n }\n\n /**\n * An utility method that returns a new {@link SmartIterator}\n * object containing all the values of the iterator.\n *\n * Since the iterator is lazy, the values will be extracted\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const values = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value)\n * .values();\n *\n * console.log(values.toArray()); // [4, 16]\n * ```\n *\n * ---\n *\n * @returns A new {@link SmartIterator} containing all the values of the iterator.\n */\n public values(): SmartIterator<T>\n {\n const elements = this._elements;\n\n return new SmartIterator<T>(function* ()\n {\n for (const [_, element] of elements)\n {\n yield element;\n }\n });\n }\n\n /**\n * Materializes the iterator into an array. \n * This method will consume the entire iterator in the process.\n *\n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const reduced = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value);\n *\n * console.log(reduced.toArray()); // [4, 16]\n * ```\n *\n * ---\n *\n * @returns The {@link Array} containing all elements of the iterator.\n */\n public toArray(): T[]\n {\n return Array.from(this.values());\n }\n\n /**\n * Materializes the iterator into a map. \n * This method will consume the entire iterator in the process.\n *\n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const reduced = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value);\n *\n * console.log(reduced.toMap()); // Map(2) { \"odd\" => 4, \"even\" => 16 }\n * ```\n *\n * ---\n *\n * @returns The {@link Map} containing all elements of the iterator.\n */\n public toMap(): Map<K, T>\n {\n return new Map(this.entries());\n }\n\n /**\n * Materializes the iterator into an object. \n * This method will consume the entire iterator in the process.\n *\n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const reduced = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value);\n *\n * console.log(reduced.toObject()); // { odd: 4, even: 16 }\n * ```\n *\n * ---\n *\n * @returns The {@link Object} containing all elements of the iterator.\n */\n public toObject(): Record<K, T>\n {\n return Object.fromEntries(this.entries()) as Record<K, T>;\n }\n\n public readonly [Symbol.toStringTag]: string = \"ReducedIterator\";\n}\n","import { SmartAsyncIterator } from \"../iterators/index.js\";\nimport type {\n GeneratorFunction,\n AsyncGeneratorFunction,\n MaybeAsyncGeneratorFunction,\n MaybeAsyncIteratorLike\n\n} from \"../iterators/types.js\";\nimport type { MaybePromise } from \"../types.js\";\n\nimport ReducedIterator from \"./reduced-iterator.js\";\nimport type { MaybeAsyncKeyedIteratee, MaybeAsyncKeyedReducer } from \"./types.js\";\n\n/**\n * A class representing an iterator that aggregates elements in a lazy and optimized way.\n *\n * It's part of the {@link SmartAsyncIterator} implementation,\n * providing a way to group elements of an iterable by key. \n * For this reason, it isn't recommended to instantiate this class directly\n * (although it's still possible), but rather use the {@link SmartAsyncIterator.groupBy} method.\n *\n * It isn't directly iterable like its parent class but rather needs to specify on what you want to iterate. \n * See the {@link AggregatedAsyncIterator.keys}, {@link AggregatedAsyncIterator.entries}\n * & {@link AggregatedAsyncIterator.values} methods. \n * It does, however, provide the same set of methods to perform\n * operations and transformations on the elements of the iterator,\n * having also the knowledge and context of the groups to which\n * they belong, allowing to handle them in a grouped manner.\n *\n * This is particularly useful when you need to group elements and\n * then perform specific operations on the groups themselves.\n *\n * ---\n *\n * @example\n * ```ts\n * const elements = fetch([...]); // Promise<[-3, -1, 0, 2, 3, 5, 6, 8]>;\n * const results = new SmartAsyncIterator(elements)\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .count();\n *\n * console.log(await results.toObject()); // { odd: 4, even: 4 }\n * ```\n *\n * ---\n *\n * @template K The type of the keys used to group the elements.\n * @template T The type of the elements to aggregate.\n */\nexport default class AggregatedAsyncIterator<K extends PropertyKey, T>\n{\n /**\n * The internal {@link SmartAsyncIterator} object that holds the elements to aggregate.\n */\n protected _elements: SmartAsyncIterator<[K, T]>;\n\n /**\n * Initializes a new instance of the {@link AggregatedAsyncIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new AggregatedAsyncIterator<string, number>([[\"A\", 1], [\"B\", 2], [\"A\", 3], [\"C\", 4], [\"B\", 5]]);\n * ```\n *\n * ---\n *\n * @param iterable The iterable to aggregate.\n */\n public constructor(iterable: Iterable<[K, T]>);\n\n /**\n * Initializes a new instance of the {@link AggregatedAsyncIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const elements = fetch([...]); // Promise<[[\"A\", 1], [\"B\", 2], [\"A\", 3], [\"C\", 4], [\"B\", 5]]>\n * const iterator = new AggregatedAsyncIterator<string, number>(elements);\n * ```\n *\n * ---\n *\n * @param iterable The iterable to aggregate.\n */\n public constructor(iterable: AsyncIterable<[K, T]>);\n\n /**\n * Initializes a new instance of the {@link AggregatedAsyncIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * import { Random } from \"@byloth/core\";\n *\n * const iterator = new AggregatedAsyncIterator<string, number>({\n * _index: 0,\n * next: () =>\n * {\n * if (this._index >= 5) { return { done: true, value: undefined }; }\n * this._index += 1;\n *\n * return { done: false, value: [Random.Choice([\"A\", \"B\", \"C\"]), (this._index + 1)] };\n * }\n * });\n * ```\n *\n * ---\n *\n * @param iterator The iterator to aggregate.\n */\n public constructor(iterator: Iterator<[K, T]>);\n\n /**\n * Initializes a new instance of the {@link AggregatedAsyncIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * import { Random } from \"@byloth/core\";\n *\n * const iterator = new AggregatedAsyncIterator<string, number>({\n * _index: 0,\n * next: async () =>\n * {\n * if (this._index >= 5) { return { done: true, value: undefined }; }\n * this._index += 1;\n *\n * return { done: false, value: [Random.Choice([\"A\", \"B\", \"C\"]), (this._index + 1)] };\n * }\n * });\n * ```\n *\n * ---\n *\n * @param iterator The iterator to aggregate.\n */\n public constructor(iterator: AsyncIterator<[K, T]>);\n\n /**\n * Initializes a new instance of the {@link AggregatedAsyncIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * import { range, Random } from \"@byloth/core\";\n *\n * const iterator = new AggregatedAsyncIterator<string, number>(function* ()\n * {\n * for (const index of range(5))\n * {\n * yield [Random.Choice([\"A\", \"B\", \"C\"]), (index + 1)];\n * }\n * });\n * ```\n *\n * ---\n *\n * @param generatorFn The generator function to aggregate.\n */\n public constructor(generatorFn: GeneratorFunction<[K, T]>);\n\n /**\n * Initializes a new instance of the {@link AggregatedAsyncIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * import { range, Random } from \"@byloth/core\";\n *\n * const iterator = new AggregatedAsyncIterator<string, number>(async function* ()\n * {\n * for await (const index of range(5))\n * {\n * yield [Random.Choice([\"A\", \"B\", \"C\"]), (index + 1)];\n * }\n * });\n * ```\n *\n * ---\n *\n * @param generatorFn The generator function to aggregate.\n */\n public constructor(generatorFn: AsyncGeneratorFunction<[K, T]>);\n\n /**\n * Initializes a new instance of the {@link AggregatedAsyncIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new AggregatedAsyncIterator(asyncKeyedValues);\n * ```\n *\n * ---\n *\n * @param argument The iterable, iterator or generator function to aggregate.\n */\n public constructor(argument: MaybeAsyncIteratorLike<[K, T]> | MaybeAsyncGeneratorFunction<[K, T]>);\n public constructor(argument: MaybeAsyncIteratorLike<[K, T]> | MaybeAsyncGeneratorFunction<[K, T]>)\n {\n this._elements = new SmartAsyncIterator(argument);\n }\n\n /**\n * Determines whether all elements of each group of the iterator satisfy a given condition.\n * See also {@link AggregatedAsyncIterator.some}. \n * This method will consume the entire iterator in the process.\n *\n * It will iterate over all elements of the iterator checjing if they satisfy the condition. \n * Once a single element of one group doesn't satisfy the condition,\n * the result for the respective group will be `false`.\n *\n * Eventually, it will return a new {@link ReducedIterator}\n * object that will contain all the boolean results for each group. \n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .every(async (key, value) => value >= 0);\n *\n * console.log(await results.toObject()); // { odd: false, even: true }\n * ```\n *\n * ---\n *\n * @param predicate The condition to check for each element of the iterator.\n *\n * @returns\n * A {@link Promise} resolving to a new {@link ReducedIterator} containing the boolean results for each group.\n */\n public async every(predicate: MaybeAsyncKeyedIteratee<K, T, boolean>): Promise<ReducedIterator<K, boolean>>\n {\n const values = new Map<K, [number, boolean]>();\n\n for await (const [key, element] of this._elements)\n {\n const [index, result] = values.get(key) ?? [0, true];\n\n if (!(result)) { continue; }\n\n values.set(key, [index + 1, await predicate(key, element, index)]);\n }\n\n return new ReducedIterator(function* ()\n {\n for (const [key, [_, result]] of values) { yield [key, result]; }\n });\n }\n\n /**\n * Determines whether any element of each group of the iterator satisfies a given condition.\n * See also {@link AggregatedAsyncIterator.every}. \n * This method will consume the entire iterator in the process.\n *\n * It will iterate over all elements of the iterator checjing if they satisfy the condition. \n * Once a single element of one group satisfies the condition,\n * the result for the respective group will be `true`.\n *\n * Eventually, it will return a new {@link ReducedIterator}\n * object that will contain all the boolean results for each group. \n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartAsyncIterator<number>([-5, -4, -3, -2, -1, 0])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .some(async (key, value) => value >= 0);\n *\n * console.log(await results.toObject()); // { odd: false, even: true }\n * ```\n *\n * ---\n *\n * @param predicate The condition to check for each element of the iterator.\n *\n * @returns\n * A {@link Promise} resolving to a new {@link ReducedIterator} containing the boolean results for each group.\n */\n public async some(predicate: MaybeAsyncKeyedIteratee<K, T, boolean>): Promise<ReducedIterator<K, boolean>>\n {\n const values = new Map<K, [number, boolean]>();\n\n for await (const [key, element] of this._elements)\n {\n const [index, result] = values.get(key) ?? [0, false];\n\n if (result) { continue; }\n\n values.set(key, [index + 1, await predicate(key, element, index)]);\n }\n\n return new ReducedIterator(function* ()\n {\n for (const [key, [_, result]] of values) { yield [key, result]; }\n });\n }\n\n /**\n * Filters the elements of the iterator based on a given condition.\n *\n * This method will iterate over all elements of the iterator checking if they satisfy the condition. \n * If the condition is met, the element will be included in the new iterator.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .filter(async (key, value) => value >= 0);\n *\n * console.log(await results.toObject()); // { odd: [3, 5], even: [0, 2, 6, 8] }\n * ```\n *\n * ---\n *\n * @param predicate The condition to check for each element of the iterator.\n *\n * @returns A new {@link AggregatedAsyncIterator} containing the elements that satisfy the condition.\n */\n public filter(predicate: MaybeAsyncKeyedIteratee<K, T, boolean>): AggregatedAsyncIterator<K, T>;\n\n /**\n * Filters the elements of the iterator based on a given condition.\n *\n * This method will iterate over all elements of the iterator checking if they satisfy the condition. \n * If the condition is met, the element will be included in the new iterator.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartAsyncIterator<number>([-3, \"-1\", 0, \"2\", \"3\", 5, 6, \"8\"])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .filter<number>(async (key, value) => typeof value === \"number\");\n *\n * console.log(await results.toObject()); // { odd: [-3, 5], even: [0, 6] }\n * ```\n *\n * ---\n *\n * @template S\n * The type of the elements that satisfy the condition. \n * This allows the type-system to infer the correct type of the new iterator.\n *\n * It must be a subtype of the original type of the elements.\n *\n * @param predicate The type guard condition to check for each element of the iterator.\n *\n * @returns A new {@link AggregatedAsyncIterator} containing the elements that satisfy the condition.\n */\n public filter<S extends T>(predicate: MaybeAsyncKeyedIteratee<K, T, boolean>): AggregatedAsyncIterator<K, S>;\n public filter(predicate: MaybeAsyncKeyedIteratee<K, T, boolean>): AggregatedAsyncIterator<K, T>\n {\n const elements = this._elements;\n\n return new AggregatedAsyncIterator(async function* (): AsyncGenerator<[K, T]>\n {\n const indexes = new Map<K, number>();\n for await (const [key, element] of elements)\n {\n const index = indexes.get(key) ?? 0;\n if (await predicate(key, element, index)) { yield [key, element]; }\n\n indexes.set(key, index + 1);\n }\n });\n }\n\n /**\n * Maps the elements of the iterator using a given transformation function.\n *\n * This method will iterate over all elements of the iterator applying the condition. \n * The result of each transformation will be included in the new iterator.\n *\n * Since the iterator is lazy, the mapping process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .map(async (key, value) => Math.abs(value));\n *\n * console.log(await results.toObject()); // { odd: [3, 1, 3, 5], even: [0, 2, 6, 8] }\n * ```\n *\n * ---\n *\n * @template V The type of the elements after the transformation.\n *\n * @param iteratee The transformation function to apply to each element of the iterator.\n *\n * @returns A new {@link AggregatedAsyncIterator} containing the transformed elements.\n */\n public map<V>(iteratee: MaybeAsyncKeyedIteratee<K, T, V>): AggregatedAsyncIterator<K, V>\n {\n const elements = this._elements;\n\n return new AggregatedAsyncIterator(async function* (): AsyncGenerator<[K, V]>\n {\n const indexes = new Map<K, number>();\n for await (const [key, element] of elements)\n {\n const index = indexes.get(key) ?? 0;\n yield [key, await iteratee(key, element, index)];\n\n indexes.set(key, index + 1);\n }\n });\n }\n\n /**\n * Reduces the elements of the iterator using a given reducer function. \n * This method will consume the entire iterator in the process.\n *\n * It will iterate over all elements of the iterator applying the reducer function. \n * The result of each iteration will be passed as the accumulator to the next one.\n *\n * The first accoumulator value will be the first element of the iterator. \n * The last accumulator value will be the final result of the reduction.\n *\n * Eventually, it will return a new {@link ReducedIterator}\n * object that will contain all the reduced results for each group. \n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce(async (key, accumulator, value) => accumulator + value);\n *\n * console.log(await results.toObject()); // { odd: 4, even: 16 }\n * ```\n *\n * ---\n *\n * @param reducer The reducer function to apply to each element of the iterator.\n *\n * @returns\n * A {@link Promise} resolving to a new {@link ReducedIterator} containing the reduced results for each group.\n */\n public async reduce(reducer: MaybeAsyncKeyedReducer<K, T, T>): Promise<ReducedIterator<K, T>>;\n\n /**\n * Reduces the elements of the iterator using a given reducer function. \n * This method will consume the entire iterator in the process.\n *\n * It will iterate over all elements of the iterator applying the reducer function. \n * The result of each iteration will be passed as the accumulator to the next one.\n *\n * The first accoumulator value will be the provided initial value. \n * The last accumulator value will be the final result of the reduction.\n *\n * Eventually, it will return a new {@link ReducedIterator}\n * object that will contain all the reduced results for each group. \n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce(async (key, accumulator, value) => accumulator + value, 0);\n *\n * console.log(await results.toObject()); // { odd: 4, even: 16 }\n * ```\n *\n * ---\n *\n * @template A The type of the accumulator value which will also be the final result of the reduction.\n *\n * @param reducer The reducer function to apply to each element of the iterator.\n * @param initialValue The initial value for the accumulator.\n *\n * @returns\n * A {@link Promise} resolving to a new {@link ReducedIterator} containing the reduced results for each group.\n */\n public async reduce<A extends PropertyKey>(reducer: MaybeAsyncKeyedReducer<K, T, A>, initialValue: MaybePromise<A>)\n : Promise<ReducedIterator<K, A>>;\n\n /**\n * Reduces the elements of the iterator using a given reducer function. \n * This method will consume the entire iterator in the process.\n *\n * It will iterate over all elements of the iterator applying the reducer function. \n * The result of each iteration will be passed as the accumulator to the next one.\n *\n * The first accoumulator value will be the provided initial value by the given function. \n * The last accumulator value will be the final result of the reduction.\n *\n * Eventually, it will return a new {@link ReducedIterator}\n * object that will contain all the reduced results for each group. \n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce(async (key, { value }, currentValue) => ({ value: value + currentValue }), (key) => ({ value: 0 }));\n *\n * console.log(await results.toObject()); // { odd: { value: 4 }, even: { value: 16 } }\n * ```\n *\n * ---\n *\n * @template A The type of the accumulator value which will also be the final result of the reduction.\n *\n * @param reducer The reducer function to apply to each element of the iterator.\n * @param initialValue The function that provides the initial value for the accumulator.\n *\n * @returns\n * A {@link Promise} resolving to a new {@link ReducedIterator} containing the reduced results for each group.\n */\n public async reduce<A>(reducer: MaybeAsyncKeyedReducer<K, T, A>, initialValue: (key: K) => MaybePromise<A>)\n : Promise<ReducedIterator<K, A>>;\n public async reduce<A>(\n reducer: MaybeAsyncKeyedReducer<K, T, A>, initialValue?: MaybePromise<A> | ((key: K) => MaybePromise<A>)\n ): Promise<ReducedIterator<K, A>>\n {\n const values = new Map<K, [number, A]>();\n\n for await (const [key, element] of this._elements)\n {\n let index: number;\n let accumulator: A;\n\n if (values.has(key)) { [index, accumulator] = values.get(key)!; }\n else if (initialValue !== undefined)\n {\n index = 0;\n\n if (initialValue instanceof Function) { accumulator = await initialValue(key); }\n else { accumulator = await initialValue; }\n }\n else\n {\n values.set(key, [0, (element as unknown) as A]);\n\n continue;\n }\n\n values.set(key, [index + 1, await reducer(key, accumulator, element, index)]);\n }\n\n return new ReducedIterator(function* ()\n {\n for (const [key, [_, accumulator]] of values) { yield [key, accumulator]; }\n });\n }\n\n /**\n * Flattens the elements of the iterator using a given transformation function.\n *\n * This method will iterate over all elements of the iterator applying the transformation function. \n * The result of each transformation will be included in the new iterator.\n *\n * Since the iterator is lazy, the mapping process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartAsyncIterator<number>([[-3, -1], 0, 2, 3, 5, [6, 8]])\n * .groupBy(async (values) =>\n * {\n * const value = values instanceof Array ? values[0] : values;\n * return value % 2 === 0 ? \"even\" : \"odd\";\n * })\n * .flatMap(async (key, values) => values);\n *\n * console.log(await results.toObject()); // { odd: [-3, -1, 3, 5], even: [0, 2, 6, 8] }\n * ```\n *\n * ---\n *\n * @template V The type of the elements after the transformation.\n *\n * @param iteratee The transformation function to apply to each element of the iterator.\n *\n * @returns A new {@link AggregatedAsyncIterator} containing the transformed elements.\n */\n public flatMap<V>(iteratee: MaybeAsyncKeyedIteratee<K, T, V | readonly V[]>): AggregatedAsyncIterator<K, V>\n {\n const elements = this._elements;\n\n return new AggregatedAsyncIterator(async function* (): AsyncGenerator<[K, V]>\n {\n const indexes = new Map<K, number>();\n for await (const [key, element] of elements)\n {\n const index = indexes.get(key) ?? 0;\n const values = await iteratee(key, element, index);\n\n if (values instanceof Array)\n {\n for (const value of values) { yield [key, value]; }\n }\n else { yield [key, values]; }\n\n indexes.set(key, index + 1);\n }\n });\n }\n\n /**\n * Drops a given number of elements from the beginning of each group of the iterator. \n * The remaining elements will be included in the new iterator.\n * See also {@link AggregatedAsyncIterator.take}.\n *\n * Since the iterator is lazy, the dropping process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .drop(2);\n *\n * console.log(await results.toObject()); // { odd: [3, 5], even: [6, 8] }\n * ```\n *\n * ---\n *\n * @param count The number of elements to drop from the beginning of each group.\n *\n * @returns A new {@link AggregatedAsyncIterator} containing the remaining elements.\n */\n public drop(count: number): AggregatedAsyncIterator<K, T>\n {\n const elements = this._elements;\n\n return new AggregatedAsyncIterator(async function* (): AsyncGenerator<[K, T]>\n {\n const indexes = new Map<K, number>();\n for await (const [key, element] of elements)\n {\n const index = indexes.get(key) ?? 0;\n if (index < count)\n {\n indexes.set(key, index + 1);\n\n continue;\n }\n\n yield [key, element];\n }\n });\n }\n\n /**\n * Takes a given number of elements from the beginning of each group of the iterator. \n * The elements will be included in the new iterator.\n * See also {@link AggregatedAsyncIterator.drop}.\n *\n * Since the iterator is lazy, the taking process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .take(2);\n *\n * console.log(await results.toObject()); // { odd: [-3, -1], even: [0, 2] }\n * ```\n *\n * ---\n *\n * @param limit The number of elements to take from the beginning of each group.\n *\n * @returns A new {@link AggregatedAsyncIterator} containing the taken elements.\n */\n public take(limit: number): AggregatedAsyncIterator<K, T>\n {\n const elements = this._elements;\n\n return new AggregatedAsyncIterator(async function* (): AsyncGenerator<[K, T]>\n {\n const indexes = new Map<K, number>();\n for await (const [key, element] of elements)\n {\n const index = indexes.get(key) ?? 0;\n if (index >= limit) { continue; }\n\n yield [key, element];\n\n indexes.set(key, index + 1);\n }\n });\n }\n\n /**\n * Finds the first element of each group of the iterator that satisfies a given condition. \n * This method will consume the entire iterator in the process.\n *\n * It will iterate over all elements of the iterator checking if they satisfy the condition. \n * Once the first element of one group satisfies the condition,\n * the result for the respective group will be the element itself.\n *\n * Eventually, it will return a new {@link ReducedIterator}\n * object that will contain the first element that satisfies the condition for each group. \n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .find(async (key, value) => value > 0);\n *\n * console.log(await results.toObject()); // { odd: 3, even: 2 }\n * ```\n *\n * ---\n *\n * @param predicate The condition to check for each element of the iterator.\n *\n * @returns\n * A {@link Promise} resolving to a new {@link ReducedIterator} containing\n * the first element that satisfies the condition for each group.\n */\n public async find(predicate: MaybeAsyncKeyedIteratee<K, T, boolean>): Promise<ReducedIterator<K, T | undefined>>;\n\n /**\n * Finds the first element of each group of the iterator that satisfies a given condition. \n * This method will consume the entire iterator in the process.\n *\n * It will iterate over all elements of the iterator checking if they satisfy the condition. \n * Once the first element of one group satisfies the condition,\n * the result for the respective group will be the element itself.\n *\n * Eventually, it will return a new {@link ReducedIterator}\n * object that will contain the first element that satisfies the condition for each group. \n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartAsyncIterator<number | string>([-3, \"-1\", 0, \"2\", \"3\", 5, 6, \"8\"])\n * .groupBy(async (value) => Number(value) % 2 === 0 ? \"even\" : \"odd\")\n * .find<number>(async (key, value) => typeof value === \"number\");\n *\n * console.log(await results.toObject()); // { odd: -3, even: 0 }\n * ```\n *\n * ---\n *\n * @template S\n * The type of the elements that satisfy the condition. \n * This allows the type-system to infer the correct type of the new iterator.\n *\n * It must be a subtype of the original type of the elements.\n *\n * @param predicate The type guard condition to check for each element of the iterator.\n *\n * @returns\n * A {@link Promise} resolving to a new {@link ReducedIterator} containing\n * the first element that satisfies the condition for each group.\n */\n public async find<S extends T>(predicate: MaybeAsyncKeyedIteratee<K, T, boolean>)\n : Promise<ReducedIterator<K, S | undefined>>;\n\n public async find(predicate: MaybeAsyncKeyedIteratee<K, T, boolean>): Promise<ReducedIterator<K, T | undefined>>\n {\n const values = new Map<K, [number, T | undefined]>();\n\n for await (const [key, element] of this._elements)\n {\n let [index, finding] = values.get(key) ?? [0, undefined];\n\n if (finding !== undefined) { continue; }\n if (await predicate(key, element, index)) { finding = element; }\n\n values.set(key, [index + 1, finding]);\n }\n\n return new ReducedIterator(function* ()\n {\n for (const [key, [_, finding]] of values) { yield [key, finding]; }\n });\n }\n\n /**\n * Enumerates the elements of the iterator. \n * Each element is paired with its index within the group in the new iterator.\n *\n * Since the iterator is lazy, the enumeration process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartAsyncIterator<number>([-3, 0, 2, -1, 3])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .enumerate();\n *\n * console.log(results.toObject()); // { odd: [[0, -3], [1, -1], [2, 3]], even: [[0, 0], [1, 2]] }\n * ```\n *\n * ---\n *\n * @returns A new {@link AggregatedAsyncIterator} containing the enumerated elements.\n */\n public enumerate(): AggregatedAsyncIterator<K, [number, T]>\n {\n return this.map((key, value, index) => [index, value]);\n }\n\n /**\n * Removes all duplicate elements from within each group of the iterator. \n * The first occurrence of each element will be included in the new iterator.\n *\n * Since the iterator is lazy, the deduplication process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 6, -3, -1, 0, 5, 6, 8, 0, 2])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .unique();\n *\n * console.log(await results.toObject()); // { odd: [-3, -1, 3, 5], even: [0, 2, 6, 8] }\n * ```\n *\n * ---\n *\n * @returns A new {@link AggregatedAsyncIterator} containing only the unique elements.\n */\n public unique(): AggregatedAsyncIterator<K, T>\n {\n const elements = this._elements;\n\n return new AggregatedAsyncIterator(async function* (): AsyncGenerator<[K, T]>\n {\n const keys = new Map<K, Set<T>>();\n for await (const [key, element] of elements)\n {\n const values = keys.get(key) ?? new Set<T>();\n if (values.has(element)) { continue; }\n\n values.add(element);\n keys.set(key, values);\n\n yield [key, element];\n }\n });\n }\n\n /**\n * Counts the number of elements within each group of the iterator. \n * This method will consume the entire iterator in the process.\n *\n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .count();\n *\n * console.log(await results.toObject()); // { odd: 4, even: 4 }\n * ```\n *\n * ---\n *\n * @returns\n * A {@link Promise} resolving to a new {@link ReducedIterator} containing the number of elements for each group.\n */\n public async count(): Promise<ReducedIterator<K, number>>\n {\n const counters = new Map<K, number>();\n\n for await (const [key] of this._elements)\n {\n const count = counters.get(key) ?? 0;\n\n counters.set(key, count + 1);\n }\n\n return new ReducedIterator(function* ()\n {\n for (const [key, count] of counters) { yield [key, count]; }\n });\n }\n\n /**\n * Iterates over the elements of the iterator. \n * The elements are passed to the given iteratee function along with their key and index within the group.\n *\n * This method will consume the entire iterator in the process. \n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const aggregator = new SmartAsyncIterator<number>([-3, 0, 2, -1, 3])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\");\n *\n * await aggregator.forEach(async (key, value, index) =>\n * {\n * console.log(`${index}: ${value}`); // \"0: -3\", \"0: 0\", \"1: 2\", \"1: -1\", \"2: 3\"\n * };\n * ```\n *\n * ---\n *\n * @param iteratee The function to execute for each element of the iterator.\n *\n * @returns A {@link Promise} that will resolve once the iteration is complete.\n */\n public async forEach(iteratee: MaybeAsyncKeyedIteratee<K, T>): Promise<void>\n {\n const indexes = new Map<K, number>();\n\n for await (const [key, element] of this._elements)\n {\n const index = indexes.get(key) ?? 0;\n\n await iteratee(key, element, index);\n\n indexes.set(key, index + 1);\n }\n }\n\n /**\n * Changes the key of each element on which the iterator is aggregated. \n * The new key is determined by the given iteratee function.\n *\n * Since the iterator is lazy, the reorganization process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .map(async (key, value, index) => index % 2 === 0 ? value : -value)\n * .reorganizeBy(async (key, value) => value >= 0 ? \"+\" : \"-\");\n *\n * console.log(await results.toObject()); // { \"+\": [1, 0, 3, 6], \"-\": [-3, -2, -5, -8] }\n * ```\n *\n * ---\n *\n * @template J The type of the new key.\n *\n * @param iteratee The function to determine the new key for each element of the iterator.\n *\n * @returns A new {@link AggregatedAsyncIterator} containing the elements reorganized by the new keys.\n */\n public reorganizeBy<J extends PropertyKey>(iteratee: MaybeAsyncKeyedIteratee<K, T, J>)\n : AggregatedAsyncIterator<J, T>\n {\n const elements = this._elements;\n\n return new AggregatedAsyncIterator(async function* (): AsyncGenerator<[J, T]>\n {\n const indexes = new Map<K, number>();\n for await (const [key, element] of elements)\n {\n const index = indexes.get(key) ?? 0;\n yield [await iteratee(key, element, index), element];\n\n indexes.set(key, index + 1);\n }\n });\n }\n\n /**\n * An utility method that returns a new {@link SmartAsyncIterator}\n * object containing all the keys of the iterator.\n *\n * Since the iterator is lazy, the keys will be extracted\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const keys = new SmartAsyncIterator([-3, Symbol(), \"A\", { }, null, [1 , 2, 3], false])\n * .groupBy(async (value) => typeof value)\n * .keys();\n *\n * console.log(await keys.toArray()); // [\"number\", \"symbol\", \"string\", \"object\", \"boolean\"]\n * ```\n *\n * ---\n *\n * @returns A new {@link SmartAsyncIterator} containing all the keys of the iterator.\n */\n public keys(): SmartAsyncIterator<K>\n {\n const elements = this._elements;\n\n return new SmartAsyncIterator<K>(async function* ()\n {\n const keys = new Set<K>();\n for await (const [key] of elements)\n {\n if (keys.has(key)) { continue; }\n keys.add(key);\n\n yield key;\n }\n });\n }\n\n /**\n * An utility method that returns a new {@link SmartAsyncIterator}\n * object containing all the entries of the iterator. \n * Each entry is a tuple containing the key and the element.\n *\n * Since the iterator is lazy, the entries will be extracted\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const entries = new SmartAsyncIterator<number>([-3, 0, 2, -1, 3])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .entries();\n *\n * console.log(await entries.toArray()); // [[\"odd\", -3], [\"even\", 0], [\"even\", 2], [\"odd\", -1], [\"odd\", 3]]\n * ```\n *\n * ---\n *\n * @returns A new {@link SmartAsyncIterator} containing all the entries of the iterator.\n */\n public entries(): SmartAsyncIterator<[K, T]>\n {\n return this._elements;\n }\n\n /**\n * An utility method that returns a new {@link SmartAsyncIterator}\n * object containing all the values of the iterator.\n *\n * Since the iterator is lazy, the values will be extracted\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const values = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .values();\n *\n * console.log(await values.toArray()); // [-3, -1, 0, 2, 3, 5, 6, 8]\n * ```\n *\n * ---\n *\n * @returns A new {@link SmartAsyncIterator} containing all the values of the iterator.\n */\n public values(): SmartAsyncIterator<T>\n {\n const elements = this._elements;\n\n return new SmartAsyncIterator<T>(async function* ()\n {\n for await (const [_, element] of elements) { yield element; }\n });\n }\n\n /**\n * Materializes the iterator into an array of arrays. \n * This method will consume the entire iterator in the process.\n *\n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const aggregator = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\");\n *\n * console.log(await aggregator.toArray()); // [[-3, -1, 3, 5], [0, 2, 6, 8]]\n * ```\n *\n * ---\n *\n * @returns A {@link Promise} resolving to an {@link Array} containing all the values of the iterator.\n */\n public async toArray(): Promise<T[][]>\n {\n const map = await this.toMap();\n\n return Array.from(map.values());\n }\n\n /**\n * Materializes the iterator into a map. \n * This method will consume the entire iterator in the process.\n *\n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const aggregator = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\");\n *\n * console.log(await aggregator.toMap()); // Map(2) { \"odd\" => [-3, -1, 3, 5], \"even\" => [0, 2, 6, 8] }\n * ```\n *\n * ---\n *\n * @returns A {@link Promise} resolving to a {@link Map} containing all the entries of the iterator.\n */\n public async toMap(): Promise<Map<K, T[]>>\n {\n const groups = new Map<K, T[]>();\n\n for await (const [key, element] of this._elements)\n {\n const value = groups.get(key) ?? [];\n\n value.push(element);\n groups.set(key, value);\n }\n\n return groups;\n }\n\n /**\n * Materializes the iterator into an object. \n * This method will consume the entire iterator in the process.\n *\n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const aggregator = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\");\n *\n * console.log(await aggregator.toObject()); // { odd: [-3, -1, 3, 5], even: [0, 2, 6, 8] }\n * ```\n *\n * ---\n *\n * @returns A {@link Promise} resolving to an object containing all the entries of the iterator.\n */\n public async toObject(): Promise<Record<K, T[]>>\n {\n const groups = { } as Record<K, T[]>;\n\n for await (const [key, element] of this._elements)\n {\n const value = groups[key] ?? [];\n\n value.push(element);\n groups[key] = value;\n }\n\n return groups;\n }\n\n public readonly [Symbol.toStringTag]: string = \"AggregatedAsyncIterator\";\n}\n","import AggregatedAsyncIterator from \"../aggregators/aggregated-async-iterator.js\";\nimport { ValueException } from \"../exceptions/index.js\";\nimport type { MaybePromise } from \"../types.js\";\n\nimport type {\n GeneratorFunction,\n AsyncGeneratorFunction,\n MaybeAsyncGeneratorFunction,\n MaybeAsyncIteratee,\n MaybeAsyncReducer,\n MaybeAsyncIteratorLike\n\n} from \"./types.js\";\n\n/**\n * A wrapper class representing an enhanced and instantiable version\n * of the native {@link AsyncIterable} & {@link AsyncIterator} interfaces.\n *\n * It provides a set of utility methods to better manipulate and transform\n * asynchronous iterators in a functional and highly performant way. \n * It takes inspiration from the native {@link Array} methods like\n * {@link Array.map}, {@link Array.filter}, {@link Array.reduce}, etc...\n *\n * The class is lazy, meaning that the transformations are applied\n * only when the resulting iterator is materialized, not before. \n * This allows to chain multiple transformations without\n * the need to iterate over the elements multiple times.\n *\n * ---\n *\n * @example\n * ```ts\n * const result = new SmartAsyncIterator<number>([\"-5\", \"-4\", \"-3\", \"-2\", \"-1\", \"0\", \"1\", \"2\", \"3\", \"4\", \"5\"])\n * .map((value) => Number(value))\n * .map((value) => value + Math.ceil(Math.abs(value / 2)))\n * .filter((value) => value >= 0)\n * .map((value) => value + 1)\n * .reduce((acc, value) => acc + value);\n *\n * console.log(await result); // 31\n * ```\n *\n * ---\n *\n * @template T The type of elements in the iterator.\n * @template R The type of the final result of the iterator. Default is `void`.\n * @template N The type of the argument passed to the `next` method. Default is `undefined`.\n */\nexport default class SmartAsyncIterator<T, R = void, N = undefined> implements AsyncIterator<T, R, N>\n{\n /**\n * The native {@link AsyncIterator} object that is being wrapped by this instance.\n */\n protected _iterator: AsyncIterator<T, R, N>;\n\n /**\n * Initializes a new instance of the {@link SmartAsyncIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<string>([\"A\", \"B\", \"C\"]);\n * ```\n *\n * ---\n *\n * @param iterable The iterable object to wrap.\n */\n public constructor(iterable: Iterable<T>);\n\n /**\n * Initializes a new instance of the {@link SmartAsyncIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number>([1, 2, 3, 4, 5]);\n * ```\n *\n * ---\n *\n * @param iterable The asynchronous iterable object to wrap.\n */\n public constructor(iterable: AsyncIterable<T>);\n\n /**\n * Initializes a new instance of the {@link SmartAsyncIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number, void, number>({\n * _sum: 0, _count: 0,\n *\n * next: function(value: number)\n * {\n * this._sum += value;\n * this._count += 1;\n *\n * return { done: false, value: this._sum / this._count };\n * }\n * })\n * ```\n *\n * ---\n *\n * @param iterator The iterator object to wrap.\n */\n public constructor(iterator: Iterator<T, R, N>);\n\n /**\n * Initializes a new instance of the {@link SmartAsyncIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number, void, number>({\n * _sum: 0, _count: 0,\n *\n * next: async function(value: number)\n * {\n * this._sum += value;\n * this._count += 1;\n *\n * return { done: false, value: this._sum / this._count };\n * }\n * })\n * ```\n *\n * ---\n *\n * @param iterator The asynchronous iterator object to wrap.\n */\n public constructor(iterator: AsyncIterator<T, R, N>);\n\n /**\n * Initializes a new instance of the {@link SmartAsyncIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number>(function* ()\n * {\n * for (let i = 2; i < 65_536; i *= 2) { yield (i - 1); }\n * });\n * ```\n *\n * ---\n *\n * @param generatorFn The generator function to wrap.\n */\n public constructor(generatorFn: GeneratorFunction<T, R, N>);\n\n /**\n * Initializes a new instance of the {@link SmartAsyncIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number>(async function* ()\n * {\n * for await (let i = 2; i < 65_536; i *= 2) { yield (i - 1); }\n * });\n * ```\n *\n * ---\n *\n * @param generatorFn The asynchronous generator function to wrap.\n */\n public constructor(generatorFn: AsyncGeneratorFunction<T, R, N>);\n\n /**\n * Initializes a new instance of the {@link SmartAsyncIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator(values);\n * ```\n *\n * ---\n *\n * @param argument The synchronous or asynchronous iterable, iterator or generator function to wrap.\n */\n public constructor(argument: MaybeAsyncIteratorLike<T, R, N> | MaybeAsyncGeneratorFunction<T, R, N>);\n public constructor(argument: MaybeAsyncIteratorLike<T, R, N> | MaybeAsyncGeneratorFunction<T, R, N>)\n {\n if (argument instanceof Function)\n {\n const generator = argument();\n if (Symbol.asyncIterator in generator)\n {\n this._iterator = generator;\n }\n else\n {\n this._iterator = (async function* ()\n {\n let next: [] | [N] = [];\n\n while (true)\n {\n const result = generator.next(...next);\n if (result.done) { return result.value; }\n\n next = [yield result.value];\n }\n\n })();\n }\n }\n else if (Symbol.asyncIterator in argument)\n {\n this._iterator = argument[Symbol.asyncIterator]() as AsyncIterator<T, R, N>;\n }\n else if (Symbol.iterator in argument)\n {\n const iterator = argument[Symbol.iterator]();\n this._iterator = (async function* ()\n {\n while (true)\n {\n const result = iterator.next();\n if (result.done) { return result.value; }\n\n yield result.value;\n }\n\n })();\n }\n else\n {\n this._iterator = (async function* ()\n {\n let next: [] | [N] = [];\n\n while (true)\n {\n const result: IteratorResult<T, R> = await argument.next(...next);\n if (result.done) { return result.value; }\n\n next = [yield result.value];\n }\n\n })();\n }\n }\n\n /**\n * Determines whether all elements of the iterator satisfy a given condition.\n * See also {@link SmartAsyncIterator.some}.\n *\n * This method will iterate over all elements of the iterator checking if they satisfy the condition. \n * Once a single element doesn't satisfy the condition, the method will return `false` immediately.\n *\n * This may lead to an unknown final state of the iterator, which may be entirely or partially consumed. \n * For this reason, it's recommended to consider it as consumed in any case and to not use it anymore. \n * Consider using {@link SmartAsyncIterator.find} instead.\n *\n * If the iterator is infinite and every element satisfies the condition, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number>([-2, -1, 0, 1, 2]);\n * const result = await iterator.every(async (value) => value < 0);\n *\n * console.log(result); // false\n * ```\n *\n * ---\n *\n * @param predicate The condition to check for each element of the iterator.\n *\n * @returns\n * A {@link Promise} that will resolve to `true` if all elements satisfy the condition, `false` otherwise.\n */\n public async every(predicate: MaybeAsyncIteratee<T, boolean>): Promise<boolean>\n {\n let index = 0;\n\n while (true)\n {\n const result = await this._iterator.next();\n\n if (result.done) { return true; }\n if (!(await predicate(result.value, index))) { return false; }\n\n index += 1;\n }\n }\n\n /**\n * Determines whether any element of the iterator satisfies a given condition.\n * See also {@link SmartAsyncIterator.every}.\n *\n * This method will iterate over all elements of the iterator checking if they satisfy the condition. \n * Once a single element satisfies the condition, the method will return `true` immediately.\n *\n * This may lead to an unknown final state of the iterator, which may be entirely or partially consumed. \n * For this reason, it's recommended to consider it as consumed in any case and to not use it anymore. \n * Consider using {@link SmartAsyncIterator.find} instead.\n *\n * If the iterator is infinite and no element satisfies the condition, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number>([-2, -1, 0, 1, 2]);\n * const result = await iterator.some(async (value) => value > 0);\n *\n * console.log(result); // true\n * ```\n *\n * ---\n *\n * @param predicate The condition to check for each element of the iterator.\n *\n * @returns\n * A {@link Promise} that will resolve to `true` if any element satisfies the condition, `false` otherwise.\n */\n public async some(predicate: MaybeAsyncIteratee<T, boolean>): Promise<boolean>\n {\n let index = 0;\n\n while (true)\n {\n const result = await this._iterator.next();\n\n if (result.done) { return false; }\n if (await predicate(result.value, index)) { return true; }\n\n index += 1;\n }\n }\n\n /**\n * Filters the elements of the iterator using a given condition.\n *\n * This method will iterate over all elements of the iterator checking if they satisfy the condition. \n * If the condition is met, the element will be included in the new iterator.\n *\n * Since the iterator is lazy, the filtering process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number>([-2, -1, 0, 1, 2]);\n * const result = iterator.filter(async (value) => value < 0);\n *\n * console.log(await result.toArray()); // [-2, -1]\n * ```\n *\n * ---\n *\n * @param predicate The condition to check for each element of the iterator.\n *\n * @returns A new {@link SmartAsyncIterator} containing only the elements that satisfy the condition.\n */\n public filter(predicate: MaybeAsyncIteratee<T, boolean>): SmartAsyncIterator<T, R>;\n\n /**\n * Filters the elements of the iterator using a given condition.\n *\n * This method will iterate over all elements of the iterator checking if they satisfy the condition. \n * If the condition is met, the element will be included in the new iterator.\n *\n * Since the iterator is lazy, the filtering process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number | string>([-2, \"-1\", \"0\", 1, \"2\"]);\n * const result = iterator.filter<number>(async (value) => typeof value === \"number\");\n *\n * console.log(await result.toArray()); // [-2, 1]\n * ```\n *\n * ---\n *\n * @template S\n * The type of the elements that satisfy the condition. \n * This allows the type-system to infer the correct type of the new iterator.\n *\n * It must be a subtype of the original type of the elements.\n *\n * @param predicate The type guard condition to check for each element of the iterator.\n *\n * @returns A new {@link SmartAsyncIterator} containing only the elements that satisfy the condition.\n */\n public filter<S extends T>(predicate: MaybeAsyncIteratee<T, boolean>): SmartAsyncIterator<S, R>;\n public filter(predicate: MaybeAsyncIteratee<T, boolean>): SmartAsyncIterator<T, R>\n {\n const iterator = this._iterator;\n\n return new SmartAsyncIterator<T, R>(async function* ()\n {\n let index = 0;\n while (true)\n {\n const result = await iterator.next();\n if (result.done) { return result.value; }\n if (await predicate(result.value, index)) { yield result.value; }\n\n index += 1;\n }\n });\n }\n\n /**\n * Maps the elements of the iterator using a given transformation function.\n *\n * This method will iterate over all elements of the iterator applying the transformation function. \n * The result of each transformation will be included in the new iterator.\n *\n * Since the iterator is lazy, the mapping process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number>([-2, -1, 0, 1, 2]);\n * const result = iterator.map(async (value) => Math.abs(value));\n *\n * console.log(await result.toArray()); // [2, 1, 0, 1, 2]\n * ```\n *\n * ---\n *\n * @template V The type of the elements after the transformation.\n *\n * @param iteratee The transformation function to apply to each element of the iterator.\n *\n * @returns A new {@link SmartAsyncIterator} containing the transformed elements.\n */\n public map<V>(iteratee: MaybeAsyncIteratee<T, V>): SmartAsyncIterator<V, R>\n {\n const iterator = this._iterator;\n\n return new SmartAsyncIterator<V, R>(async function* ()\n {\n let index = 0;\n while (true)\n {\n const result = await iterator.next();\n if (result.done) { return result.value; }\n\n yield await iteratee(result.value, index);\n\n index += 1;\n }\n });\n }\n\n /**\n * Reduces the elements of the iterator using a given reducer function. \n * This method will consume the entire iterator in the process.\n *\n * It will iterate over all elements of the iterator applying the reducer function. \n * The result of each iteration will be passed as the accumulator to the next one.\n *\n * The first accumulator value will be the first element of the iterator. \n * The last accumulator value will be the final result of the reduction.\n *\n * Also note that:\n * - If an empty iterator is provided, a {@link ValueException} will be thrown.\n * - If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number>([1, 2, 3, 4, 5]);\n * const result = await iterator.reduce(async (acc, value) => acc + value);\n *\n * console.log(result); // 15\n * ```\n *\n * ---\n *\n * @param reducer The reducer function to apply to each element of the iterator.\n *\n * @returns A {@link Promise} that will resolve to the final result of the reduction.\n */\n public async reduce(reducer: MaybeAsyncReducer<T, T>): Promise<T>;\n\n /**\n * Reduces the elements of the iterator using a given reducer function. \n * This method will consume the entire iterator in the process.\n *\n * It will iterate over all elements of the iterator applying the reducer function. \n * The result of each iteration will be passed as the accumulator to the next one.\n *\n * The first accumulator value will be the provided initial value. \n * The last accumulator value will be the final result of the reduction.\n *\n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number>([1, 2, 3, 4, 5]);\n * const result = await iterator.reduce(async (acc, value) => acc + value, 10);\n *\n * console.log(result); // 25\n * ```\n *\n * ---\n *\n * @template A The type of the accumulator value which will also be the type of the final result of the reduction.\n *\n * @param reducer The reducer function to apply to each element of the iterator.\n * @param initialValue The initial value of the accumulator.\n *\n * @returns A {@link Promise} that will resolve to the final result of the reduction.\n */\n public async reduce<A>(reducer: MaybeAsyncReducer<T, A>, initialValue: A): Promise<A>;\n public async reduce<A>(reducer: MaybeAsyncReducer<T, A>, initialValue?: A): Promise<A>\n {\n let index = 0;\n let accumulator = initialValue;\n if (accumulator === undefined)\n {\n const result = await this._iterator.next();\n if (result.done) { throw new ValueException(\"Cannot reduce an empty iterator without an initial value.\"); }\n\n accumulator = (result.value as unknown) as A;\n index += 1;\n }\n\n while (true)\n {\n const result = await this._iterator.next();\n if (result.done) { return accumulator; }\n\n accumulator = await reducer(accumulator, result.value, index);\n\n index += 1;\n }\n }\n\n /**\n * Flattens the elements of the iterator using a given transformation function.\n *\n * This method will iterate over all elements of the iterator applying the transformation function. \n * The result of each transformation will be flattened and included in the new iterator.\n *\n * Since the iterator is lazy, the flattening process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number[]>([[-2, -1], 0, 1, 2, [3, 4, 5]]);\n * const result = iterator.flatMap(async (value) => value);\n *\n * console.log(await result.toArray()); // [-2, -1, 0, 1, 2, 3, 4, 5]\n * ```\n *\n * ---\n *\n * @template V The type of the elements after the transformation.\n *\n * @param iteratee The transformation function to apply to each element of the iterator.\n *\n * @returns A new {@link SmartAsyncIterator} containing the flattened elements.\n */\n public flatMap<V>(iteratee: MaybeAsyncIteratee<T, V | readonly V[]>): SmartAsyncIterator<V, R>\n {\n const iterator = this._iterator;\n\n return new SmartAsyncIterator<V, R>(async function* ()\n {\n let index = 0;\n while (true)\n {\n const result = await iterator.next();\n if (result.done) { return result.value; }\n\n const elements = await iteratee(result.value, index);\n if (elements instanceof Array)\n {\n for (const value of elements) { yield value; }\n }\n else { yield elements; }\n\n index += 1;\n }\n });\n }\n\n /**\n * Drops a given number of elements at the beginning of the iterator. \n * The remaining elements will be included in a new iterator.\n * See also {@link SmartAsyncIterator.take}.\n *\n * Since the iterator is lazy, the dropping process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * Only the dropped elements will be consumed in the process. \n * The rest of the iterator will be consumed only once the new one is.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number>([-2, -1, 0, 1, 2]);\n * const result = iterator.drop(3);\n *\n * console.log(await result.toArray()); // [1, 2]\n * ```\n *\n * ---\n *\n * @param count The number of elements to drop.\n *\n * @returns A new {@link SmartAsyncIterator} containing the remaining elements.\n */\n public drop(count: number): SmartAsyncIterator<T, R | undefined>\n {\n const iterator = this._iterator;\n\n return new SmartAsyncIterator<T, R | undefined>(async function* ()\n {\n let index = 0;\n while (index < count)\n {\n const result = await iterator.next();\n if (result.done) { return; }\n\n index += 1;\n }\n\n while (true)\n {\n const result = await iterator.next();\n if (result.done) { return result.value; }\n\n yield result.value;\n }\n });\n }\n\n /**\n * Takes a given number of elements at the beginning of the iterator. \n * These elements will be included in a new iterator.\n * See also {@link SmartAsyncIterator.drop}.\n *\n * Since the iterator is lazy, the taking process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * Only the taken elements will be consumed from the original iterator. \n * The rest of the original iterator will be available for further consumption.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number>([-2, -1, 0, 1, 2]);\n * const result = iterator.take(3);\n *\n * console.log(await result.toArray()); // [-2, -1, 0]\n * console.log(await iterator.toArray()); // [1, 2]\n * ```\n *\n * ---\n *\n * @param limit The number of elements to take.\n *\n * @returns A new {@link SmartAsyncIterator} containing the taken elements.\n */\n public take(limit: number): SmartAsyncIterator<T, R | undefined>\n {\n const iterator = this._iterator;\n\n return new SmartAsyncIterator<T, R | undefined>(async function* ()\n {\n let index = 0;\n while (index < limit)\n {\n const result = await iterator.next();\n if (result.done) { return result.value; }\n\n yield result.value;\n\n index += 1;\n }\n\n return;\n });\n }\n\n /**\n * Finds the first element of the iterator that satisfies a given condition.\n *\n * This method will iterate over all elements of the iterator checking if they satisfy the condition. \n * The first element that satisfies the condition will be returned immediately.\n *\n * Only the elements that are necessary to find the first\n * satisfying one will be consumed from the original iterator. \n * The rest of the original iterator will be available for further consumption.\n *\n * Also note that:\n * - If no element satisfies the condition, `undefined` will be returned once the entire iterator is consumed.\n * - If the iterator is infinite and no element satisfies the condition, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number>([-2, -1, 0, 1, 2]);\n * const result = await iterator.find(async (value) => value > 0);\n *\n * console.log(result); // 1\n * ```\n *\n * ---\n *\n * @param predicate The condition to check for each element of the iterator.\n *\n * @returns\n * A {@link Promise} that will resolve to the first element that satisfies the condition, `undefined` otherwise.\n */\n public async find(predicate: MaybeAsyncIteratee<T, boolean>): Promise<T | undefined>;\n\n /**\n * Finds the first element of the iterator that satisfies a given condition.\n *\n * This method will iterate over all elements of the iterator checking if they satisfy the condition. \n * The first element that satisfies the condition will be returned immediately.\n *\n * Only the elements that are necessary to find the first\n * satisfying one will be consumed from the original iterator. \n * The rest of the original iterator will be available for further consumption.\n *\n * Also note that:\n * - If no element satisfies the condition, `undefined` will be returned once the entire iterator is consumed.\n * - If the iterator is infinite and no element satisfies the condition, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number | string>([-2, \"-1\", \"0\", 1, \"2\"]);\n * const result = await iterator.find<number>(async (value) => typeof value === \"number\");\n *\n * console.log(result); // -2\n * ```\n *\n * ---\n *\n * @template S\n * The type of the element that satisfies the condition. \n * This allows the type-system to infer the correct type of the result.\n *\n * It must be a subtype of the original type of the elements.\n *\n * @param predicate The type guard condition to check for each element of the iterator.\n *\n * @returns\n * A {@link Promise} that will resolve to the first element that satisfies the condition, `undefined` otherwise. \n */\n public async find<S extends T>(predicate: MaybeAsyncIteratee<T, boolean>): Promise<S | undefined>;\n public async find(predicate: MaybeAsyncIteratee<T, boolean>): Promise<T | undefined>\n {\n let index = 0;\n\n while (true)\n {\n const result = await this._iterator.next();\n\n if (result.done) { return; }\n if (await predicate(result.value, index)) { return result.value; }\n\n index += 1;\n }\n }\n\n /**\n * Enumerates the elements of the iterator. \n * Each element is be paired with its index in a new iterator.\n *\n * Since the iterator is lazy, the enumeration process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<string>([\"A\", \"M\", \"N\", \"Z\"]);\n * const result = iterator.enumerate();\n *\n * for await (const [index, value] of result)\n * {\n * console.log(`${index}: ${value}`); // \"0: A\", \"1: M\", \"2: N\", \"3: Z\"\n * }\n * ```\n *\n * ---\n *\n * @returns A new {@link SmartAsyncIterator} containing the enumerated elements.\n */\n public enumerate(): SmartAsyncIterator<[number, T], R>\n {\n return this.map((value, index) => [index, value]);\n }\n\n /**\n * Removes all duplicate elements from the iterator. \n * The first occurrence of each element will be kept.\n *\n * Since the iterator is lazy, the deduplication process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number>([1, 1, 2, 3, 2, 3, 4, 5, 5, 4]);\n * const result = iterator.unique();\n *\n * console.log(await result.toArray()); // [1, 2, 3, 4, 5]\n * ```\n *\n * ---\n *\n * @returns A new {@link SmartAsyncIterator} containing only the unique elements.\n */\n public unique(): SmartAsyncIterator<T, R>\n {\n const iterator = this._iterator;\n\n return new SmartAsyncIterator<T, R>(async function* ()\n {\n const values = new Set<T>();\n while (true)\n {\n const result = await iterator.next();\n if (result.done) { return result.value; }\n if (values.has(result.value)) { continue; }\n\n values.add(result.value);\n\n yield result.value;\n }\n });\n }\n\n /**\n * Counts the number of elements in the iterator. \n * This method will consume the entire iterator in the process.\n *\n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number>([1, 2, 3, 4, 5]);\n * const result = await iterator.count();\n *\n * console.log(result); // 5\n * ```\n *\n * ---\n *\n * @returns A {@link Promise} that will resolve to the number of elements in the iterator.\n */\n public async count(): Promise<number>\n {\n let index = 0;\n\n while (true)\n {\n const result = await this._iterator.next();\n if (result.done) { return index; }\n\n index += 1;\n }\n }\n\n /**\n * Iterates over all elements of the iterator. \n * The elements are passed to the function along with their index.\n *\n * This method will consume the entire iterator in the process. \n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number>([\"A\", \"M\", \"N\", \"Z\"]);\n * await iterator.forEach(async (value, index) =>\n * {\n * console.log(`${index}: ${value}`); // \"0: A\", \"1: M\", \"2: N\", \"3: Z\"\n * }\n * ```\n *\n * ---\n *\n * @param iteratee The function to apply to each element of the iterator.\n *\n * @returns A {@link Promise} that will resolve once the iteration is complete.\n */\n public async forEach(iteratee: MaybeAsyncIteratee<T>): Promise<void>\n {\n let index = 0;\n\n while (true)\n {\n const result = await this._iterator.next();\n if (result.done) { return; }\n\n await iteratee(result.value, index);\n\n index += 1;\n }\n }\n\n /**\n * Advances the iterator to the next element and returns the result. \n * If the iterator requires it, a value must be provided to be passed to the next element.\n *\n * Once the iterator is done, the method will return an object with the `done` property set to `true`.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number>([1, 2, 3, 4, 5]);\n *\n * let result = await iterator.next();\n * while (!result.done)\n * {\n * console.log(result.value); // 1, 2, 3, 4, 5\n *\n * result = await iterator.next();\n * }\n *\n * console.log(result); // { done: true, value: undefined }\n * ```\n *\n * ---\n *\n * @param values The value to pass to the next element, if required.\n *\n * @returns\n * A {@link Promise} that will resolve to the result of the iteration, containing the value of the operation.\n */\n public next(...values: N extends undefined ? [] : [N]): Promise<IteratorResult<T, R>>\n {\n return this._iterator.next(...values);\n }\n\n /**\n * An utility method that may be used to close the iterator gracefully,\n * free the resources and perform any cleanup operation. \n * It may also be used to signal the end or to compute a specific final result of the iteration process.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number>({\n * _index: 0,\n * next: async function()\n * {\n * return { done: false, value: this._index += 1 };\n * },\n * return: async function() { console.log(\"Closing the iterator...\"); }\n * });\n *\n * for await (const value of iterator)\n * {\n * if (value > 5) { break; } // Closing the iterator...\n *\n * console.log(value); // 1, 2, 3, 4, 5\n * }\n * ```\n *\n * ---\n *\n * @param value The final value of the iterator.\n *\n * @returns A {@link Promise} that will resolve to the final result of the iterator.\n */\n public async return(value?: MaybePromise<R>): Promise<IteratorResult<T, R>>\n {\n const _value = (await value) as R;\n\n if (this._iterator.return) { return await this._iterator.return(_value); }\n\n return { done: true, value: _value };\n }\n\n /**\n * An utility method that may be used to close the iterator due to an error,\n * free the resources and perform any cleanup operation. \n * It may also be used to signal that an error occurred during the iteration process or to handle it.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number>({\n * _index: 0,\n * next: async function()\n * {\n * return { done: this._index > 10, value: this._index += 1 };\n * },\n * throw: async function(error)\n * {\n * console.warn(error.message);\n *\n * this._index = 0;\n * }\n * });\n *\n * for await (const value of iterator) // 1, 2, 3, 4, 5, \"The index is too high.\", 1, 2, 3, 4, 5, ...\n * {\n * try\n * {\n * if (value > 5) { throw new Error(\"The index is too high.\"); }\n *\n * console.log(value); // 1, 2, 3, 4, 5\n * }\n * catch (error) { await iterator.throw(error); }\n * }\n * ```\n *\n * ---\n *\n * @param error The error to throw into the iterator.\n *\n * @returns A {@link Promise} that will resolve to the final result of the iterator.\n */\n public throw(error: unknown): Promise<IteratorResult<T, R>>\n {\n if (this._iterator.throw) { return this._iterator.throw(error); }\n\n throw error;\n }\n\n /**\n * An utility method that aggregates the elements of the iterator using a given key function. \n * The elements will be grouped by the resulting keys in a new specialized iterator.\n * See {@link AggregatedAsyncIterator}.\n *\n * Since the iterator is lazy, the grouping process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * the new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number>([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);\n * const result = iterator.groupBy<string>(async (value) => value % 2 === 0 ? \"even\" : \"odd\");\n *\n * console.log(await result.toObject()); // { odd: [1, 3, 5, 7, 9], even: [2, 4, 6, 8, 10] }\n * ```\n *\n * ---\n *\n * @template K The type of the keys used to group the elements.\n *\n * @param iteratee The key function to apply to each element of the iterator.\n *\n * @returns A new instance of the {@link AggregatedAsyncIterator} class containing the grouped elements.\n */\n public groupBy<K extends PropertyKey>(iteratee: MaybeAsyncIteratee<T, K>): AggregatedAsyncIterator<K, T>\n {\n return new AggregatedAsyncIterator(this.map(async (element, index) =>\n {\n const key = await iteratee(element, index);\n\n return [key, element] as [K, T];\n }));\n }\n\n /**\n * Materializes the iterator into an array. \n * This method will consume the entire iterator in the process.\n *\n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator(async function* ()\n * {\n * for (let i = 0; i < 5; i += 1) { yield i; }\n * });\n * const result = await iterator.toArray();\n *\n * console.log(result); // [0, 1, 2, 3, 4]\n * ```\n *\n * ---\n *\n * @returns A {@link Promise} that will resolve to an array containing all elements of the iterator.\n */\n public toArray(): Promise<T[]>\n {\n return Array.fromAsync(this as AsyncIterable<T>);\n }\n\n public readonly [Symbol.toStringTag]: string = \"SmartAsyncIterator\";\n\n public [Symbol.asyncIterator](): SmartAsyncIterator<T, R, N> { return this; }\n}\n","import { SmartIterator } from \"../iterators/index.js\";\nimport type { GeneratorFunction, IteratorLike } from \"../iterators/types.js\";\n\nimport ReducedIterator from \"./reduced-iterator.js\";\nimport type { KeyedIteratee, KeyedTypeGuardPredicate, KeyedReducer } from \"./types.js\";\n\n/**\n * A class representing an iterator that aggregates elements in a lazy and optimized way.\n *\n * It's part of the {@link SmartIterator} implementation, providing a way to group elements of an iterable by key. \n * For this reason, it isn't recommended to instantiate this class directly\n * (although it's still possible), but rather use the {@link SmartIterator.groupBy} method.\n *\n * It isn't directly iterable like its parent class but rather needs to specify on what you want to iterate. \n * See the {@link AggregatedIterator.keys}, {@link AggregatedIterator.entries}\n * & {@link AggregatedIterator.values} methods. \n * It does, however, provide the same set of methods to perform\n * operations and transformation on the elements of the iterator, \n * having also the knowledge and context of the groups to which\n * they belong, allowing to handle them in a grouped manner.\n *\n * This is particularly useful when you need to group elements and\n * then perform specific operations on the groups themselves.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .count();\n *\n * console.log(results.toObject()); // { odd: 4, even: 4 }\n * ```\n *\n * ---\n *\n * @template K The type of the keys used to group the elements.\n * @template T The type of the elements to aggregate.\n */\nexport default class AggregatedIterator<K extends PropertyKey, T>\n{\n /**\n * The internal {@link SmartIterator} object that holds the elements to aggregate.\n */\n protected _elements: SmartIterator<[K, T]>;\n\n /**\n * Initializes a new instance of the {@link AggregatedIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new AggregatedIterator<string, number>([[\"A\", 1], [\"B\", 2], [\"A\", 3], [\"C\", 4], [\"B\", 5]]);\n * ```\n *\n * ---\n *\n * @param iterable The iterable to aggregate.\n */\n public constructor(iterable: Iterable<[K, T]>);\n\n /**\n * Initializes a new instance of the {@link AggregatedIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * import { Random } from \"@byloth/core\";\n *\n * const iterator = new AggregatedIterator<string, number>({\n * _index: 0,\n * next: () =>\n * {\n * if (this._index >= 5) { return { done: true, value: undefined }; }\n * this._index += 1;\n *\n * return { done: false, value: [Random.Choice([\"A\", \"B\", \"C\"]), (this._index + 1)] };\n * }\n * });\n * ```\n *\n * ---\n *\n * @param iterator The iterator to aggregate.\n */\n public constructor(iterator: Iterator<[K, T]>);\n\n /**\n * Initializes a new instance of the {@link AggregatedIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * import { range, Random } from \"@byloth/core\";\n *\n * const iterator = new AggregatedIterator<string, number>(function* ()\n * {\n * for (const index of range(5))\n * {\n * yield [Random.Choice([\"A\", \"B\", \"C\"]), (index + 1)];\n * }\n * });\n * ```\n *\n * ---\n *\n * @param generatorFn The generator function to aggregate.\n */\n public constructor(generatorFn: GeneratorFunction<[K, T]>);\n\n /**\n * Initializes a new instance of the {@link AggregatedIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new AggregatedIterator(keyedValues);\n * ```\n *\n * ---\n *\n * @param argument The iterable, iterator or generator function to aggregate.\n */\n public constructor(argument: IteratorLike<[K, T]> | GeneratorFunction<[K, T]>);\n public constructor(argument: IteratorLike<[K, T]> | GeneratorFunction<[K, T]>)\n {\n this._elements = new SmartIterator(argument);\n }\n\n /**\n * Determines whether all elements of each group of the iterator satisfy a given condition.\n * See also {@link AggregatedIterator.some}. \n * This method will consume the entire iterator in the process.\n *\n * It will iterate over all elements of the iterator checking if they satisfy the condition. \n * Once a single element of one group doesn't satisfy the condition,\n * the result for the respective group will be `false`.\n *\n * Eventually, it will return a new {@link ReducedIterator}\n * object that will contain all the boolean results for each group. \n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .every((key, value) => value >= 0);\n *\n * console.log(results.toObject()); // { odd: false, even: true }\n * ```\n *\n * ---\n *\n * @param predicate The condition to check for each element of the iterator.\n *\n * @returns A new {@link ReducedIterator} containing the boolean results for each group.\n */\n public every(predicate: KeyedIteratee<K, T, boolean>): ReducedIterator<K, boolean>\n {\n const values = new Map<K, [number, boolean]>();\n\n for (const [key, element] of this._elements)\n {\n const [index, result] = values.get(key) ?? [0, true];\n\n if (!(result)) { continue; }\n\n values.set(key, [index + 1, predicate(key, element, index)]);\n }\n\n return new ReducedIterator(function* ()\n {\n for (const [key, [_, result]] of values) { yield [key, result]; }\n });\n }\n\n /**\n * Determines whether any elements of each group of the iterator satisfy a given condition.\n * See also {@link AggregatedIterator.every}. \n * This method will consume the entire iterator in the process.\n *\n * It will iterate over all elements of the iterator checking if they satisfy the condition. \n * Once a single element of one group satisfies the condition,\n * the result for the respective group will be `true`.\n *\n * Eventually, it will return a new {@link ReducedIterator}\n * object that will contain all the boolean results for each group. \n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-5, -4, -3, -2, -1, 0])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .some((key, value) => value >= 0);\n *\n * console.log(results.toObject()); // { odd: false, even: true }\n * ```\n *\n * ---\n *\n * @param predicate The condition to check for each element of the iterator.\n *\n * @returns A {@link ReducedIterator} containing the boolean results for each group.\n */\n public some(predicate: KeyedIteratee<K, T, boolean>): ReducedIterator<K, boolean>\n {\n const values = new Map<K, [number, boolean]>();\n\n for (const [key, element] of this._elements)\n {\n const [index, result] = values.get(key) ?? [0, false];\n\n if (result) { continue; }\n\n values.set(key, [index + 1, predicate(key, element, index)]);\n }\n\n return new ReducedIterator(function* ()\n {\n for (const [key, [_, result]] of values) { yield [key, result]; }\n });\n }\n\n /**\n * Filters the elements of the iterator using a given condition.\n *\n * This method will iterate over all elements of the iterator checking if they satisfy the condition. \n * If the condition is met, the element will be included in the new iterator.\n *\n * Since the iterator is lazy, the filtering process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .filter((key, value) => value >= 0);\n *\n * console.log(results.toObject()); // { odd: [3, 5], even: [0, 2, 6, 8] }\n * ```\n *\n * ---\n *\n * @param predicate The condition to check for each element of the iterator.\n *\n * @returns A new {@link AggregatedIterator} containing only the elements that satisfy the condition.\n */\n public filter(predicate: KeyedIteratee<K, T, boolean>): AggregatedIterator<K, T>;\n\n /**\n * Filters the elements of the iterator using a given condition.\n *\n * This method will iterate over all elements of the iterator checking if they satisfy the condition. \n * If the condition is met, the element will be included in the new iterator.\n *\n * Since the iterator is lazy, the filtering process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number | string>([-3, \"-1\", 0, \"2\", \"3\", 5, 6, \"8\"])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .filter<number>((key, value) => typeof value === \"number\");\n *\n * console.log(results.toObject()); // { odd: [-3, 5], even: [0, 6] }\n * ```\n *\n * ---\n *\n * @template S\n * The type of the elements that satisfy the condition. \n * This allows the type-system to infer the correct type of the new iterator.\n *\n * It must be a subtype of the original type of the elements.\n *\n * @param predicate The type guard condition to check for each element of the iterator.\n *\n * @returns A new {@link AggregatedIterator} containing only the elements that satisfy the condition.\n */\n public filter<S extends T>(predicate: KeyedTypeGuardPredicate<K, T, S>): AggregatedIterator<K, S>;\n public filter(predicate: KeyedIteratee<K, T, boolean>): AggregatedIterator<K, T>\n {\n const elements = this._elements;\n\n return new AggregatedIterator(function* ()\n {\n const indexes = new Map<K, number>();\n for (const [key, element] of elements)\n {\n const index = indexes.get(key) ?? 0;\n if (predicate(key, element, index)) { yield [key, element]; }\n\n indexes.set(key, index + 1);\n }\n });\n }\n\n /**\n * Maps the elements of the iterator using a given transformation function.\n *\n * This method will iterate over all elements of the iterator applying the transformation function. \n * The result of each transformation will be included in the new iterator.\n *\n * Since the iterator is lazy, the mapping process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .map((key, value) => Math.abs(value));\n *\n * console.log(results.toObject()); // { odd: [3, 1, 3, 5], even: [0, 2, 6, 8] }\n * ```\n *\n * ---\n *\n * @template V The type of the elements after the transformation.\n *\n * @param iteratee The transformation function to apply to each element of the iterator.\n *\n * @returns A new {@link AggregatedIterator} containing the transformed elements.\n */\n public map<V>(iteratee: KeyedIteratee<K, T, V>): AggregatedIterator<K, V>\n {\n const elements = this._elements;\n\n return new AggregatedIterator(function* ()\n {\n const indexes = new Map<K, number>();\n for (const [key, element] of elements)\n {\n const index = indexes.get(key) ?? 0;\n yield [key, iteratee(key, element, index)];\n\n indexes.set(key, index + 1);\n }\n });\n }\n\n /**\n * Reduces the elements of the iterator using a given reducer function. \n * This method will consume the entire iterator in the process.\n *\n * It will iterate over all elements of the iterator applying the reducer function. \n * The result of each iteration will be passed as the accumulator to the next one.\n *\n * The first accumulator value will be the first element of the iterator. \n * The last accumulator value will be the final result of the reduction.\n *\n * Eventually, it will return a new {@link ReducedIterator}\n * object that will contain all the reduced results for each group. \n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value);\n *\n * console.log(results.toObject()); // { odd: 4, even: 16 }\n * ```\n *\n * ---\n *\n * @param reducer The reducer function to apply to each element of the iterator.\n *\n * @returns A new {@link ReducedIterator} containing the reduced results for each group.\n */\n public reduce(reducer: KeyedReducer<K, T, T>): ReducedIterator<K, T>;\n\n /**\n * Reduces the elements of the iterator using a given reducer function. \n * This method will consume the entire iterator in the process.\n *\n * It will iterate over all elements of the iterator applying the reducer function. \n * The result of each iteration will be passed as the accumulator to the next one.\n *\n * The first accumulator value will be the provided initial value. \n * The last accumulator value will be the final result of the reduction.\n *\n * Eventually, it will return a new {@link ReducedIterator}\n * object that will contain all the reduced results for each group. \n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value, 0);\n *\n * console.log(results.toObject()); // { odd: 4, even: 16 }\n * ```\n *\n * ---\n *\n * @template A The type of the accumulator value which will also be the type of the final result of the reduction.\n *\n * @param reducer The reducer function to apply to each element of the iterator.\n * @param initialValue The initial value of the accumulator.\n *\n * @returns A new {@link ReducedIterator} containing the reduced results for each group.\n */\n public reduce<A extends PropertyKey>(reducer: KeyedReducer<K, T, A>, initialValue: A): ReducedIterator<K, A>;\n\n /**\n * Reduces the elements of the iterator using a given reducer function. \n * This method will consume the entire iterator in the process.\n *\n * It will iterate over all elements of the iterator applying the reducer function. \n * The result of each iteration will be passed as the accumulator to the next one.\n *\n * The first accumulator value will be the provided initial value by the given function. \n * The last accumulator value will be the final result of the reduction.\n *\n * Eventually, it will return a new {@link ReducedIterator}\n * object that will contain all the reduced results for each group. \n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, { value }, currentValue) => ({ value: value + currentValue }), (key) => ({ value: 0 }));\n *\n * console.log(results.toObject()); // { odd: { value: 4 }, even: { value: 16 } }\n * ```\n *\n * ---\n *\n * @template A The type of the accumulator value which will also be the type of the final result of the reduction.\n *\n * @param reducer The reducer function to apply to each element of the iterator.\n * @param initialValue The function that provides the initial value for the accumulator.\n *\n * @returns A new {@link ReducedIterator} containing the reduced results for each group.\n */\n public reduce<A>(reducer: KeyedReducer<K, T, A>, initialValue: (key: K) => A): ReducedIterator<K, A>;\n public reduce<A>(reducer: KeyedReducer<K, T, A>, initialValue?: A | ((key: K) => A)): ReducedIterator<K, A>\n {\n const values = new Map<K, [number, A]>();\n\n for (const [key, element] of this._elements)\n {\n let index: number;\n let accumulator: A;\n\n if (values.has(key)) { [index, accumulator] = values.get(key)!; }\n else if (initialValue !== undefined)\n {\n index = 0;\n\n if (initialValue instanceof Function) { accumulator = initialValue(key); }\n else { accumulator = initialValue; }\n }\n else\n {\n values.set(key, [0, (element as unknown) as A]);\n\n continue;\n }\n\n values.set(key, [index + 1, reducer(key, accumulator, element, index)]);\n }\n\n return new ReducedIterator(function* ()\n {\n for (const [key, [_, accumulator]] of values) { yield [key, accumulator]; }\n });\n }\n\n /**\n * Flattens the elements of the iterator using a given transformation function.\n *\n * This method will iterate over all elements of the iterator applying the transformation function. \n * The result of each transformation will be included in the new iterator.\n *\n * Since the iterator is lazy, the flattening process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number[]>([[-3, -1], 0, 2, 3, 5, [6, 8]])\n * .groupBy((values) =>\n * {\n * const value = values instanceof Array ? values[0] : values;\n * return value % 2 === 0 ? \"even\" : \"odd\";\n * })\n * .flatMap((key, values) => values);\n *\n * console.log(results.toObject()); // { odd: [-3, -1, 3, 5], even: [0, 2, 6, 8] }\n * ```\n *\n * ---\n *\n * @template V The type of the elements after the transformation.\n *\n * @param iteratee The transformation function to apply to each element of the iterator.\n *\n * @returns A new {@link AggregatedIterator} containing the transformed elements.\n */\n public flatMap<V>(iteratee: KeyedIteratee<K, T, V | readonly V[]>): AggregatedIterator<K, V>\n {\n const elements = this._elements;\n\n return new AggregatedIterator(function* ()\n {\n const indexes = new Map<K, number>();\n for (const [key, element] of elements)\n {\n const index = indexes.get(key) ?? 0;\n const values = iteratee(key, element, index);\n\n if (values instanceof Array)\n {\n for (const value of values) { yield [key, value]; }\n }\n else { yield [key, values]; }\n\n indexes.set(key, index + 1);\n }\n });\n }\n\n /**\n * Drops a given number of elements from the beginning of each group of the iterator. \n * The remaining elements will be included in the new iterator.\n * See also {@link AggregatedIterator.take}.\n *\n * Since the iterator is lazy, the dropping process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .drop(2);\n *\n * console.log(results.toObject()); // { odd: [3, 5], even: [6, 8] }\n * ```\n *\n * ---\n *\n * @param count The number of elements to drop from the beginning of each group.\n *\n * @returns A new {@link AggregatedIterator} containing the remaining elements.\n */\n public drop(count: number): AggregatedIterator<K, T>\n {\n const elements = this._elements;\n\n return new AggregatedIterator(function* ()\n {\n const indexes = new Map<K, number>();\n for (const [key, element] of elements)\n {\n const index = indexes.get(key) ?? 0;\n if (index < count)\n {\n indexes.set(key, index + 1);\n\n continue;\n }\n\n yield [key, element];\n }\n });\n }\n\n /**\n * Takes a given number of elements from the beginning of each group of the iterator. \n * The elements will be included in the new iterator.\n * See also {@link AggregatedIterator.drop}.\n *\n * Since the iterator is lazy, the taking process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .take(2);\n *\n * console.log(results.toObject()); // { odd: [-3, -1], even: [0, 2] }\n * ```\n *\n * ---\n *\n * @param limit The number of elements to take from the beginning of each group.\n *\n * @returns A new {@link AggregatedIterator} containing the taken elements.\n */\n public take(limit: number): AggregatedIterator<K, T>\n {\n const elements = this._elements;\n\n return new AggregatedIterator(function* ()\n {\n const indexes = new Map<K, number>();\n for (const [key, element] of elements)\n {\n const index = indexes.get(key) ?? 0;\n if (index >= limit) { continue; }\n yield [key, element];\n\n indexes.set(key, index + 1);\n }\n });\n }\n\n /**\n * Finds the first element of each group of the iterator that satisfies a given condition. \n * This method will consume the entire iterator in the process.\n *\n * It will iterate over all elements of the iterator checking if they satisfy the condition. \n * Once the first element of one group satisfies the condition,\n * the result for the respective group will be the element itself.\n *\n * Eventually, it will return a new {@link ReducedIterator}\n * object that will contain the first element that satisfies the condition for each group. \n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .find((key, value) => value > 0);\n *\n * console.log(results.toObject()); // { odd: 3, even: 2 }\n * ```\n *\n * ---\n *\n * @param predicate The condition to check for each element of the iterator.\n *\n * @returns A new {@link ReducedIterator} containing the first element that satisfies the condition for each group.\n */\n public find(predicate: KeyedIteratee<K, T, boolean>): ReducedIterator<K, T | undefined>;\n\n /**\n * Finds the first element of each group of the iterator that satisfies a given condition. \n * This method will consume the entire iterator in the process.\n *\n * It will iterate over all elements of the iterator checking if they satisfy the condition. \n * Once the first element of one group satisfies the condition,\n * the result for the respective group will be the element itself.\n *\n * Eventually, it will return a new {@link ReducedIterator}\n * object that will contain the first element that satisfies the condition for each group. \n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number | string>([-3, \"-1\", 0, \"2\", \"3\", 5, 6, \"8\"])\n * .groupBy((value) => Number(value) % 2 === 0 ? \"even\" : \"odd\")\n * .find<number>((key, value) => typeof value === \"number\");\n *\n * console.log(results.toObject()); // { odd: -3, even: 0 }\n * ```\n *\n * ---\n *\n * @template S\n * The type of the elements that satisfy the condition. \n * This allows the type-system to infer the correct type of the new iterator.\n *\n * It must be a subtype of the original type of the elements.\n *\n * @param predicate The type guard condition to check for each element of the iterator.\n *\n * @returns A new {@link ReducedIterator} containing the first element that satisfies the condition for each group.\n */\n public find<S extends T>(predicate: KeyedTypeGuardPredicate<K, T, S>): ReducedIterator<K, S | undefined>;\n public find(predicate: KeyedIteratee<K, T, boolean>): ReducedIterator<K, T | undefined>\n {\n const values = new Map<K, [number, T | undefined]>();\n\n for (const [key, element] of this._elements)\n {\n let [index, finding] = values.get(key) ?? [0, undefined];\n\n if (finding !== undefined) { continue; }\n if (predicate(key, element, index)) { finding = element; }\n\n values.set(key, [index + 1, finding]);\n }\n\n return new ReducedIterator(function* ()\n {\n for (const [key, [_, finding]] of values) { yield [key, finding]; }\n });\n }\n\n /**\n * Enumerates the elements of the iterator. \n * Each element is paired with its index within the group in a new iterator.\n *\n * Since the iterator is lazy, the enumeration process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, 0, 2, -1, 3])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .enumerate();\n *\n * console.log(results.toObject()); // { odd: [[0, -3], [1, -1], [2, 3]], even: [[0, 0], [1, 2]] }\n * ```\n *\n * ---\n *\n * @returns A new {@link AggregatedIterator} containing the enumerated elements.\n */\n public enumerate(): AggregatedIterator<K, [number, T]>\n {\n return this.map((_, value, index) => [index, value]);\n }\n\n /**\n * Removes all duplicate elements from within each group of the iterator. \n * The first occurrence of each element will be included in the new iterator.\n *\n * Since the iterator is lazy, the deduplication process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 6, -3, -1, 0, 5, 6, 8, 0, 2])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .unique();\n *\n * console.log(results.toObject()); // { odd: [-3, -1, 3, 5], even: [0, 2, 6, 8] }\n * ```\n *\n * ---\n *\n * @returns A new {@link AggregatedIterator} containing only the unique elements.\n */\n public unique(): AggregatedIterator<K, T>\n {\n const elements = this._elements;\n\n return new AggregatedIterator(function* ()\n {\n const keys = new Map<K, Set<T>>();\n for (const [key, element] of elements)\n {\n const values = keys.get(key) ?? new Set<T>();\n if (values.has(element)) { continue; }\n\n values.add(element);\n keys.set(key, values);\n\n yield [key, element];\n }\n });\n }\n\n /**\n * Counts the number of elements within each group of the iterator. \n * This method will consume the entire iterator in the process.\n *\n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .count();\n *\n * console.log(results.toObject()); // { odd: 4, even: 4 }\n * ```\n *\n * ---\n *\n * @returns A new {@link ReducedIterator} containing the number of elements for each group.\n */\n public count(): ReducedIterator<K, number>\n {\n const counters = new Map<K, number>();\n\n for (const [key] of this._elements)\n {\n const count = counters.get(key) ?? 0;\n\n counters.set(key, count + 1);\n }\n\n return new ReducedIterator(function* ()\n {\n for (const [key, count] of counters) { yield [key, count]; }\n });\n }\n\n /**\n * Iterates over the elements of the iterator. \n * The elements are passed to the given iteratee function along with their key and index within the group.\n *\n * This method will consume the entire iterator in the process. \n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const aggregator = new SmartIterator<number>([-3, 0, 2, -1, 3])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\");\n *\n * aggregator.forEach((key, value, index) =>\n * {\n * console.log(`${index}: ${value}`); // \"0: -3\", \"0: 0\", \"1: 2\", \"1: -1\", \"2: 3\"\n * };\n * ```\n *\n * ---\n *\n * @param iteratee The function to execute for each element of the iterator.\n */\n public forEach(iteratee: KeyedIteratee<K, T>): void\n {\n const indexes = new Map<K, number>();\n for (const [key, element] of this._elements)\n {\n const index = indexes.get(key) ?? 0;\n iteratee(key, element, index);\n\n indexes.set(key, index + 1);\n }\n }\n\n /**\n * Changes the key of each element on which the iterator is aggregated. \n * The new key is determined by the given iteratee function.\n *\n * Since the iterator is lazy, the reorganization process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .map((key, value, index) => index % 2 === 0 ? value : -value)\n * .reorganizeBy((key, value) => value >= 0 ? \"+\" : \"-\");\n *\n * console.log(results.toObject()); // { \"+\": [1, 0, 3, 6], \"-\": [-3, -2, -5, -8] }\n * ```\n *\n * ---\n *\n * @template J The type of the new key.\n *\n * @param iteratee The function to determine the new key for each element of the iterator.\n *\n * @returns A new {@link AggregatedIterator} containing the elements reorganized by the new keys.\n */\n public reorganizeBy<J extends PropertyKey>(iteratee: KeyedIteratee<K, T, J>): AggregatedIterator<J, T>\n {\n const elements = this._elements;\n\n return new AggregatedIterator(function* ()\n {\n const indexes = new Map<K, number>();\n for (const [key, element] of elements)\n {\n const index = indexes.get(key) ?? 0;\n yield [iteratee(key, element, index), element];\n\n indexes.set(key, index + 1);\n }\n });\n }\n\n /**\n * An utility method that returns a new {@link SmartIterator}\n * object containing all the keys of the iterator.\n *\n * Since the iterator is lazy, the keys will be extracted\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const keys = new SmartIterator([-3, Symbol(), \"A\", { }, null, [1 , 2, 3], false])\n * .groupBy((value) => typeof value)\n * .keys();\n *\n * console.log(keys.toArray()); // [\"number\", \"symbol\", \"string\", \"object\", \"boolean\"]\n * ```\n *\n * ---\n *\n * @returns A new {@link SmartIterator} containing all the keys of the iterator.\n */\n public keys(): SmartIterator<K>\n {\n const elements = this._elements;\n\n return new SmartIterator<K>(function* ()\n {\n const keys = new Set<K>();\n for (const [key] of elements)\n {\n if (keys.has(key)) { continue; }\n keys.add(key);\n\n yield key;\n }\n });\n }\n\n /**\n * An utility method that returns a new {@link SmartIterator}\n * object containing all the entries of the iterator. \n * Each entry is a tuple containing the key and the element.\n *\n * Since the iterator is lazy, the entries will be extracted\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const entries = new SmartIterator<number>([-3, 0, 2, -1, 3])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .entries();\n *\n * console.log(entries.toArray()); // [[\"odd\", -3], [\"even\", 0], [\"even\", 2], [\"odd\", -1], [\"odd\", 3]]\n * ```\n *\n * ---\n *\n * @returns A new {@link SmartIterator} containing all the entries of the iterator.\n */\n public entries(): SmartIterator<[K, T]>\n {\n return this._elements;\n }\n\n /**\n * An utility method that returns a new {@link SmartIterator}\n * object containing all the values of the iterator.\n *\n * Since the iterator is lazy, the values will be extracted\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const values = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .values();\n *\n * console.log(values.toArray()); // [-3, -1, 0, 2, 3, 5, 6, 8]\n * ```\n *\n * ---\n *\n * @returns A new {@link SmartIterator} containing all the values of the iterator.\n */\n public values(): SmartIterator<T>\n {\n const elements = this._elements;\n\n return new SmartIterator<T>(function* ()\n {\n for (const [_, element] of elements) { yield element; }\n });\n }\n\n /**\n * Materializes the iterator into an array of arrays. \n * This method will consume the entire iterator in the process.\n *\n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const aggregator = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\");\n *\n * console.log(aggregator.toArray()); // [[-3, -1, 3, 5], [0, 2, 6, 8]]\n * ```\n *\n * ---\n *\n * @returns An {@link Array} of arrays containing the elements of the iterator.\n */\n public toArray(): T[][]\n {\n const map = this.toMap();\n\n return Array.from(map.values());\n }\n\n /**\n * Materializes the iterator into a map. \n * This method will consume the entire iterator in the process.\n *\n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const aggregator = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\");\n *\n * console.log(aggregator.toMap()); // Map(2) { \"odd\" => [-3, -1, 3, 5], \"even\" => [0, 2, 6, 8] }\n * ```\n *\n * ---\n *\n * @returns A {@link Map} containing the elements of the iterator.\n */\n public toMap(): Map<K, T[]>\n {\n const groups = new Map<K, T[]>();\n\n for (const [key, element] of this._elements)\n {\n const value = groups.get(key) ?? [];\n\n value.push(element);\n groups.set(key, value);\n }\n\n return groups;\n }\n\n /**\n * Materializes the iterator into an object. \n * This method will consume the entire iterator in the process.\n *\n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const aggregator = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\");\n *\n * console.log(aggregator.toObject()); // { odd: [-3, -1, 3, 5], even: [0, 2, 6, 8] }\n * ```\n *\n * ---\n *\n * @returns An {@link Object} containing the elements of the iterator.\n */\n public toObject(): Record<K, T[]>\n {\n const groups = { } as Record<K, T[]>;\n\n for (const [key, element] of this._elements)\n {\n const value = groups[key] ?? [];\n\n value.push(element);\n groups[key] = value;\n }\n\n return groups;\n }\n\n public readonly [Symbol.toStringTag]: string = \"AggregatedIterator\";\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport type { Callback } from \"./types.js\";\n\nconst SmartFunction = (Function as unknown) as new<A extends unknown[] = [], R = void>(...args: string[])\n => (...args: A) => R;\n\n/**\n * An abstract class that can be used to implement callable objects.\n *\n * ---\n *\n * @example\n * ```ts\n * class ActivableCallback extends CallableObject<(evt: PointerEvent) => void>\n * {\n * public enabled = false;\n * protected _invoke(): void\n * {\n * if (this.enabled) { [...] }\n * }\n * }\n *\n * const callback = new ActivableCallback();\n *\n * window.addEventListener(\"pointerdown\", () => { callback.enabled = true; });\n * window.addEventListener(\"pointermove\", callback);\n * window.addEventListener(\"pointerup\", () => { callback.enabled = false; });\n * ```\n *\n * ---\n *\n * @template T\n * The type signature of the callback function. \n * It must be a function. Default is `(...args: any[]) => any`.\n */\nexport default abstract class CallableObject<T extends Callback<any[], any> = () => void>\n extends SmartFunction<Parameters<T>, ReturnType<T>>\n{\n /**\n * Initializes a new instance of the {@link CallableObject} class.\n */\n public constructor()\n {\n super(`return this._invoke(...arguments);`);\n\n const self = this.bind(this);\n Object.setPrototypeOf(this, self);\n\n return self as this;\n }\n\n /**\n * The method that will be called when the object is invoked. \n * It must be implemented by the derived classes.\n *\n * ---\n *\n * @param args The arguments that have been passed to the object.\n *\n * @returns The return value of the method.\n */\n protected abstract _invoke(...args: Parameters<T>): ReturnType<T>;\n\n public readonly [Symbol.toStringTag]: string = \"CallableObject\";\n}\n","import { ReferenceException } from \"../exceptions/index.js\";\n\nimport type { Callback, CallbackMap } from \"./types.js\";\n\n/**\n * A class implementing the\n * {@link https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern|Publish-subscribe} pattern.\n *\n * It can be used to create a simple event system where objects can subscribe\n * to events and receive notifications when the events are published. \n * It's a simple and efficient way to decouple the objects and make them communicate with each other.\n *\n * Using generics, it's also possible to define the type of the events and the callbacks that can be subscribed to them.\n *\n * ---\n *\n * @example\n * ```ts\n * interface EventsMap\n * {\n * \"player:spawn\": (evt: SpawnEvent) => void;\n * \"player:move\": ({ x, y }: Point) => void;\n * \"player:death\": () => void;\n * }\n *\n * const publisher = new Publisher<EventsMap>();\n *\n * let unsubscribe: () => void;\n * publisher.subscribe(\"player:death\", unsubscribe);\n * publisher.subscribe(\"player:spawn\", (evt) =>\n * {\n * unsubscribe = publisher.subscribe(\"player:move\", ({ x, y }) => { [...] });\n * });\n * ```\n *\n * ---\n *\n * @template T\n * A map containing the names of the emittable events and the\n * related callback signatures that can be subscribed to them. \n * Default is `Record<string, (...args: unknown[]) => unknown>`.\n */\nexport default class Publisher<T extends CallbackMap<T> = CallbackMap>\n{\n /**\n * A map containing all the subscribers for each event.\n *\n * The keys are the names of the events they are subscribed to. \n * The values are the arrays of the subscribers themselves.\n */\n protected _subscribers: Map<string, Callback<unknown[], unknown>[]>;\n\n /**\n * Initializes a new instance of the {@link Publisher} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const publisher = new Publisher();\n * ```\n */\n public constructor()\n {\n this._subscribers = new Map();\n }\n\n /**\n * Unsubscribes all the subscribers from all the events.\n *\n * ---\n *\n * @example\n * ```ts\n * publisher.subscribe(\"player:spawn\", (evt) => { [...] });\n * publisher.subscribe(\"player:move\", (coords) => { [...] });\n * publisher.subscribe(\"player:move\", () => { [...] });\n * publisher.subscribe(\"player:move\", ({ x, y }) => { [...] });\n * publisher.subscribe(\"player:death\", () => { [...] });\n *\n * // All these subscribers are working fine...\n *\n * publisher.clear();\n *\n * // ... but now they're all gone!\n * ```\n */\n public clear(): void\n {\n this._subscribers.clear();\n }\n\n /**\n * Publishes an event to all the subscribers.\n *\n * ---\n *\n * @example\n * ```ts\n * publisher.subscribe(\"player:move\", (coords) => { [...] });\n * publisher.subscribe(\"player:move\", ({ x, y }) => { [...] });\n * publisher.subscribe(\"player:move\", (evt) => { [...] });\n *\n * publisher.publish(\"player:move\", { x: 10, y: 20 });\n * ```\n *\n * ---\n *\n * @template K The key of the map containing the callback signature to publish.\n *\n * @param event The name of the event to publish.\n * @param args The arguments to pass to the subscribers.\n *\n * @returns An array containing the return values of all the subscribers.\n */\n public publish<K extends keyof T>(event: K & string, ...args: Parameters<T[K]>): ReturnType<T[K]>[]\n {\n const subscribers = this._subscribers.get(event);\n if (!(subscribers)) { return []; }\n\n return subscribers.slice()\n .map((subscriber) => subscriber(...args)) as ReturnType<T[K]>[];\n }\n\n /**\n * Subscribes to an event and adds a subscriber to be executed when the event is published.\n *\n * ---\n *\n * @example\n * ```ts\n * let unsubscribe: () => void;\n * publisher.subscribe(\"player:death\", unsubscribe);\n * publisher.subscribe(\"player:spawn\", (evt) =>\n * {\n * unsubscribe = publisher.subscribe(\"player:move\", ({ x, y }) => { [...] });\n * });\n * ```\n *\n * ---\n *\n * @template K The key of the map containing the callback signature to subscribe.\n *\n * @param event The name of the event to subscribe to.\n * @param subscriber The subscriber to execute when the event is published.\n *\n * @returns A function that can be used to unsubscribe the subscriber from the event.\n */\n public subscribe<K extends keyof T>(event: K & string, subscriber: T[K]): () => void\n {\n if (!(this._subscribers.has(event))) { this._subscribers.set(event, []); }\n\n const subscribers = this._subscribers.get(event)!;\n subscribers.push(subscriber);\n\n return () =>\n {\n const index = subscribers.indexOf(subscriber);\n if (index < 0)\n {\n throw new ReferenceException(\"Unable to unsubscribe the required subscriber. \" +\n \"The subscription was already unsubscribed.\");\n }\n\n subscribers.splice(index, 1);\n };\n }\n\n /**\n * Unsubscribes from an event and removes a subscriber from being executed when the event is published.\n *\n * ---\n *\n * @example\n * ```ts\n * const onPlayerMove = ({ x, y }: Point) => { [...] };\n *\n * publisher.subscribe(\"player:spawn\", (evt) => publisher.subscribe(\"player:move\", onPlayerMove));\n * publisher.subscribe(\"player:death\", () => publisher.unsubscribe(\"player:move\", onPlayerMove));\n * ```\n *\n * ---\n *\n * @template K The key of the map containing the callback signature to unsubscribe.\n *\n * @param event The name of the event to unsubscribe from.\n * @param subscriber The subscriber to remove from the event.\n */\n public unsubscribe<K extends keyof T>(event: K & string, subscriber: T[K]): void\n {\n const subscribers = this._subscribers.get(event);\n if (!(subscribers)) { return; }\n\n const index = subscribers.indexOf(subscriber);\n if (index < 0)\n {\n throw new ReferenceException(\"Unable to unsubscribe the required subscriber. \" +\n \"The subscription was already unsubscribed or was never subscribed.\");\n }\n\n subscribers.splice(index, 1);\n }\n\n public readonly [Symbol.toStringTag]: string = \"Publisher\";\n}\n","import { KeyException, NotImplementedException, RuntimeException } from \"../exceptions/index.js\";\n\nimport CallableObject from \"./callable-object.js\";\nimport type { Callback } from \"./types.js\";\n\nconst Disabler = () => { /* ... */ };\n\n/**\n * A class representing a callback that can be switched between multiple implementations.\n *\n * It can be used to implement different behaviors for the same event handler, allowing\n * it to respond to different states without incurring any overhead during execution.\n *\n * ---\n *\n * @example\n * ```ts\n * const onPointerMove = new SwitchableCallback<(evt: PointerEvent) => void>();\n *\n * onPointerMove.register(\"released\", () => { [...] });\n * onPointerMove.register(\"pressed\", () => { [...] });\n *\n * window.addEventListener(\"pointerdown\", () => { onPointerMove.switch(\"pressed\"); });\n * window.addEventListener(\"pointermove\", onPointerMove);\n * window.addEventListener(\"pointerup\", () => { onPointerMove.switch(\"released\"); });\n * ```\n *\n * ---\n *\n * @template T The type signature of the callback. Default is `(...args: any[]) => any`.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport default class SwitchableCallback<T extends Callback<any[], any> = Callback> extends CallableObject<T>\n{\n /**\n * The currently selected implementation of the callback.\n */\n protected _callback: T;\n\n /**\n * All the implementations that have been registered for the callback.\n *\n * The keys are the names of the implementations they were registered with. \n * The values are the implementations themselves.\n */\n protected _callbacks: Map<string, T>;\n\n /**\n * A flag indicating whether the callback is enabled or not.\n *\n * This protected property is the only one that can be modified directly by the derived classes. \n * If you're looking for the public and readonly property, use\n * the {@link SwitchableCallback.isEnabled} getter instead.\n */\n protected _isEnabled: boolean;\n\n /**\n * A flag indicating whether the callback is enabled or not.\n *\n * It indicates whether the callback is currently able to execute the currently selected implementation. \n * If it's disabled, the callback will be invoked without executing anything.\n */\n public get isEnabled(): boolean { return this._isEnabled; }\n\n /**\n * The key that is associated with the currently selected implementation.\n *\n * This protected property is the only one that can be modified directly by the derived classes. \n * If you're looking for the public and readonly property, use the {@link SwitchableCallback.key} getter instead.\n */\n protected _key: string;\n\n /**\n * The key that is associated with the currently selected implementation.\n */\n public get key(): string { return this._key; }\n\n /**\n * The function that will be called by the extended class when the object is invoked as a function.\n */\n protected readonly _invoke: (...args: Parameters<T>) => ReturnType<T>;\n\n /**\n * Initializes a new instance of the {@link SwitchableCallback} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const onPointerMove = new SwitchableCallback<(evt: PointerEvent) => void>();\n * ```\n */\n public constructor();\n\n /**\n * Initializes a new instance of the {@link SwitchableCallback}\n * class with the specified callback enabled by default.\n *\n * ---\n *\n * @example\n * ```ts\n * const onPointerMove = new SwitchableCallback<(evt: PointerEvent) => void>((evt) => { [...] });\n * ```\n *\n * ---\n *\n * @param callback The callback that will be executed when the object is invoked as a function by default.\n * @param key The key that is associated by default to the given callback. Default is `default`.\n */\n public constructor(callback: T, key?: string);\n public constructor(callback?: T, key = \"default\")\n {\n super();\n\n this._callbacks = new Map<string, T>();\n this._isEnabled = true;\n\n if (callback)\n {\n this._callbacks.set(key, callback);\n }\n else\n {\n key = \"\";\n\n callback = ((() =>\n {\n throw new NotImplementedException(\n \"The `SwitchableCallback` has no callback defined yet. \" +\n \"Did you forget to call the `register` method?\"\n );\n\n }) as unknown) as T;\n }\n\n this._key = key;\n\n this._callback = callback;\n this._invoke = (...args: Parameters<T>): ReturnType<T> => this._callback(...args);\n }\n\n /**\n * Enables the callback, allowing it to execute the currently selected implementation.\n *\n * Also note that:\n * - If any implementation has been registered yet, a {@link KeyException} will be thrown. \n * - If any key is given and it doesn't have any associated\n * implementation yet, a {@link KeyException} will be thrown.\n * - If the callback is already enabled, a {@link RuntimeException} will be thrown.\n *\n * ---\n *\n * @example\n * ```ts\n * window.addEventListener(\"pointerdown\", () => { onPointerMove.enable(); });\n * window.addEventListener(\"pointermove\", onPointerMove);\n * ```\n *\n * ---\n *\n * @param key\n * The key that is associated with the implementation to enable. Default is the currently selected implementation.\n */\n public enable(key?: string): void\n {\n if (key === undefined)\n {\n if (!(this._key))\n {\n throw new KeyException(\n \"The `SwitchableCallback` has no callback defined yet. \" +\n \"Did you forget to call the `register` method?\"\n );\n }\n\n key = this._key;\n }\n else if (!(key))\n {\n throw new KeyException(\"The key must be a non-empty string.\");\n }\n else if (!(this._callbacks.has(key)))\n {\n throw new KeyException(`The key '${key}' doesn't yet have any associated callback.`);\n }\n\n if (this._isEnabled)\n {\n throw new RuntimeException(\"The `SwitchableCallback` is already enabled.\");\n }\n\n this._callback = this._callbacks.get(key)!;\n this._isEnabled = true;\n }\n\n /**\n * Disables the callback, allowing it to be invoked without executing any implementation.\n *\n * If the callback is already disabled, a {@link RuntimeException} will be thrown.\n *\n * ---\n *\n * @example\n * ```ts\n * window.addEventListener(\"pointermove\", onPointerMove);\n * window.addEventListener(\"pointerup\", () => { onPointerMove.disable(); });\n * ```\n */\n public disable(): void\n {\n if (!(this._isEnabled))\n {\n throw new RuntimeException(\"The `SwitchableCallback` is already disabled.\");\n }\n\n this._callback = Disabler as T;\n this._isEnabled = false;\n }\n\n /**\n * Registers a new implementation for the callback.\n *\n * Also note that:\n * - If the callback has no other implementation registered yet, this one will be selected as default.\n * - If the key has already been used for another implementation, a {@link KeyException} will be thrown.\n *\n * ---\n *\n * @example\n * ```ts\n * onPointerMove.register(\"pressed\", () => { [...] });\n * onPointerMove.register(\"released\", () => { [...] });\n * ```\n *\n * ---\n *\n * @param key The key that will be associated with the implementation.\n * @param callback The implementation to register.\n */\n public register(key: string, callback: T): void\n {\n if (this._callbacks.size === 0)\n {\n this._key = key;\n this._callback = callback;\n }\n else if (this._callbacks.has(key))\n {\n throw new KeyException(`The key '${key}' has already been used for another callback.`);\n }\n\n this._callbacks.set(key, callback);\n }\n\n /**\n * Unregisters an implementation for the callback.\n *\n * Also note that:\n * - If the key is the currently selected implementation, a {@link KeyException} will be thrown.\n * - If the key has no associated implementation yet, a {@link KeyException} will be thrown.\n *\n * ---\n *\n * @example\n * ```ts\n * onPointerMove.unregister(\"released\");\n * ```\n *\n * ---\n *\n * @param key The key that is associated with the implementation to unregister.\n */\n public unregister(key: string): void\n {\n if (this._key === key)\n {\n throw new KeyException(\"Unable to unregister the currently selected callback.\");\n }\n if (!(this._callbacks.has(key)))\n {\n throw new KeyException(`The key '${key}' doesn't yet have any associated callback.`);\n }\n\n this._callbacks.delete(key);\n }\n\n /**\n * Switches the callback to the implementation associated with the given key.\n *\n * If the key has no associated implementation yet, a {@link KeyException} will be thrown.\n *\n * ---\n *\n * @example\n * ```ts\n * window.addEventListener(\"pointerdown\", () => { onPointerMove.switch(\"pressed\"); });\n * window.addEventListener(\"pointermove\", onPointerMove);\n * window.addEventListener(\"pointerup\", () => { onPointerMove.switch(\"released\"); });\n * ```\n *\n * ---\n *\n * @param key The key that is associated with the implementation to switch to.\n */\n public switch(key: string): void\n {\n if (!(this._callbacks.has(key)))\n {\n throw new KeyException(`The key '${key}' doesn't yet have any associated callback.`);\n }\n\n if (this._key === key) { return; }\n this._key = key;\n\n if (this._isEnabled)\n {\n this._callback = this._callbacks.get(key)!;\n }\n }\n\n public override readonly [Symbol.toStringTag]: string = \"SwitchableCallback\";\n}\n","import Publisher from \"../callbacks/publisher.js\";\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport type SetView from \"./set-view.js\";\nimport type { MapViewEventsMap } from \"./types.js\";\n\n/**\n * A wrapper class around the native {@link Map} class that provides additional functionality\n * for publishing events when entries are added, removed or the collection is cleared. \n * There's also a complementary class that works with the native `Set` class.\n * See also {@link SetView}.\n *\n * ---\n *\n * @example\n * ```ts\n * const map = new MapView<string, number>();\n *\n * map.subscribe(\"entry:add\", (key: string, value: number) => console.log(`Added ${key}: ${value}`));\n * map.set(\"answer\", 42); // Added answer: 42\n * ```\n *\n * ---\n *\n * @template K The type of the keys in the map.\n * @template V The type of the values in the map.\n */\nexport default class MapView<K, V> extends Map<K, V>\n{\n /**\n * The internal {@link Publisher} instance used to publish events.\n */\n protected readonly _publisher: Publisher<MapViewEventsMap<K, V>>;\n\n /**\n * Initializes a new instance of the {@link MapView} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const map = new MapView<string, number>([[\"key1\", 2], [\"key2\", 4], [\"key3\", 8]]);\n * ```\n *\n * ---\n *\n * @param iterable An optional iterable of key-value pairs to initialize the {@link Map} with.\n */\n public constructor(iterable?: Iterable<[K, V]> | null)\n {\n super();\n\n this._publisher = new Publisher();\n\n if (iterable)\n {\n for (const [key, value] of iterable) { this.set(key, value); }\n }\n }\n\n /**\n * Adds a new entry with a specified key and value to the {@link Map}. \n * If an entry with the same key already exists, the entry will be overwritten with the new value.\n *\n * ---\n *\n * @example\n * ```ts\n * const map = new MapView<string, number>();\n * map.set(\"key1\", 2)\n * .set(\"key2\", 4)\n * .set(\"key3\", 8);\n *\n * console.log(map); // MapView { \"key1\" => 2, \"key2\" => 4, \"key3\" => 8 }\n * ```\n *\n * ---\n *\n * @param key The key of the entry to add.\n * @param value The value of the entry to add.\n *\n * @returns The current instance of the {@link MapView} class.\n */\n public override set(key: K, value: V): this\n {\n super.set(key, value);\n\n this._publisher.publish(\"entry:add\", key, value);\n\n return this;\n }\n\n /**\n * Removes an entry with a specified key from the {@link Map}.\n *\n * ---\n *\n * @example\n * ```ts\n * const map = new MapView<string, number>([[\"key1\", 2], [\"key2\", 4], [\"key3\", 8]]);\n * map.delete(\"key2\"); // true\n * map.delete(\"key4\"); // false\n *\n * console.log(map); // MapView { \"key1\" => 2, \"key3\" => 8 }\n * ```\n *\n * ---\n *\n * @param key The key of the entry to remove.\n *\n * @returns `true` if the entry existed and has been removed; otherwise `false` if the entry doesn't exist.\n */\n public override delete(key: K): boolean\n {\n const value = this.get(key);\n if (value === undefined) { return false; }\n\n super.delete(key);\n\n this._publisher.publish(\"entry:remove\", key, value);\n\n return true;\n }\n\n /**\n * Removes all entries from the {@link Map}.\n *\n * ---\n *\n * @example\n * ```ts\n * const map = new MapView<string, number>([[\"key1\", 2], [\"key2\", 4], [\"key3\", 8]]);\n * map.clear();\n *\n * console.log(map); // MapView { }\n * ```\n */\n public override clear(): void\n {\n const size = this.size;\n\n super.clear();\n if (size > 0) { this._publisher.publish(\"collection:clear\"); }\n }\n\n /**\n * Subscribes to an event and adds a callback to be executed when the event is published.\n *\n * ---\n *\n * @example\n * ```ts\n * const map = new MapView<string, number>();\n * const unsubscribe = map.subscribe(\"entry:add\", (key: string, value: number) =>\n * {\n * if (key === \"answer\") { unsubscribe(); }\n * console.log(`Added ${key}: ${value}`);\n * });\n *\n * map.set(\"key1\", 2); // Added key1: 2\n * map.set(\"answer\", 42); // Added answer: 42\n * map.set(\"key2\", 4);\n * map.set(\"key3\", 8);\n * ```\n *\n * ---\n *\n * @template T The key of the map containing the callback signature to subscribe.\n *\n * @param event The name of the event to subscribe to.\n * @param callback The callback to execute when the event is published.\n *\n * @returns A function that can be used to unsubscribe the callback from the event.\n */\n public subscribe<T extends keyof MapViewEventsMap<K, V>>(event: T, callback: MapViewEventsMap<K, V>[T]): () => void\n {\n return this._publisher.subscribe(event, callback);\n }\n\n /**\n * Unsubscribes from an event and removes a callback from being executed when the event is published.\n *\n * ---\n *\n * @example\n * ```ts\n * const callback = (key: string, value: number) => console.log(`Added ${key}: ${value}`);\n * const map = new MapView<string, number>();\n *\n * map.subscribe(\"entry:add\", callback);\n * map.set(\"key1\", 2); // Added key1: 2\n *\n * map.unsubscribe(\"entry:add\", callback);\n * map.set(\"key2\", 4);\n * ```\n *\n * ---\n *\n * @template T The key of the map containing the callback signature to unsubscribe.\n *\n * @param event The name of the event to unsubscribe from.\n * @param callback The callback to remove from the event.\n */\n public unsubscribe<T extends keyof MapViewEventsMap<K, V>>(event: T, callback: MapViewEventsMap<K, V>[T]): void\n {\n this._publisher.unsubscribe(event, callback);\n }\n\n public override readonly [Symbol.toStringTag]: string = \"MapView\";\n}\n","import Publisher from \"../callbacks/publisher.js\";\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport type MapView from \"./map-view.js\";\nimport type { SetViewEventsMap } from \"./types.js\";\n\n/**\n * A wrapper class around the native {@link Set} class that provides additional functionality\n * for publishing events when entries are added, removed or the collection is cleared. \n * There's also a complementary class that works with the native `Map` class.\n * See also {@link MapView}.\n *\n * ---\n *\n * @example\n * ```ts\n * const set = new SetView<number>();\n *\n * set.subscribe(\"entry:add\", (value: number) => console.log(`Added ${value}`));\n * set.add(42); // Added 42\n * ```\n *\n * ---\n *\n * @template T The type of the values in the set.\n */\nexport default class SetView<T> extends Set<T>\n{\n /**\n * The internal {@link Publisher} instance used to publish events.\n */\n protected readonly _publisher: Publisher<SetViewEventsMap<T>>;\n\n /**\n * Initializes a new instance of the {@link SetView} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const set = new SetView<number>([2, 4, 8]);\n * ```\n *\n * ---\n *\n * @param iterable An optional iterable of values to initialize the {@link Set} with.\n */\n public constructor(iterable?: Iterable<T> | null)\n {\n super();\n\n this._publisher = new Publisher();\n\n if (iterable)\n {\n for (const value of iterable) { this.add(value); }\n }\n }\n\n /**\n * Appends a new element with a specified value to the end of the {@link Set}. \n * If the value already exists, it will not be added again.\n *\n * ---\n *\n * @example\n * ```ts\n * const set = new SetView<number>();\n * set.add(2)\n * .add(4)\n * .add(8);\n *\n * console.log(set); // SetView(4) { 2, 4, 8 }\n * ```\n *\n * ---\n *\n * @param value The value to add.\n *\n * @returns The current instance of the {@link SetView} class.\n */\n public override add(value: T): this\n {\n super.add(value);\n\n this._publisher.publish(\"entry:add\", value);\n\n return this;\n }\n\n /**\n * Removes the specified value from the {@link Set}.\n *\n * ---\n *\n * @example\n * ```ts\n * const set = new SetView<number>([2, 4, 8]);\n * set.delete(4); // true\n * set.delete(16); // false\n *\n * console.log(set); // SetView(2) { 2, 8 }\n * ```\n *\n * ---\n *\n * @param value The value to remove.\n *\n * @returns `true` if the entry existed and has been removed; otherwise `false` if the entry doesn't exist.\n */\n public override delete(value: T): boolean\n {\n const result = super.delete(value);\n if (result) { this._publisher.publish(\"entry:remove\", value); }\n\n return result;\n }\n\n /**\n * Removes all entries from the {@link Set}.\n *\n * ---\n *\n * @example\n * ```ts\n * const set = new SetView<number>([2, 4, 8]);\n * set.clear();\n *\n * console.log(set); // SetView(0) { }\n * ```\n */\n public override clear(): void\n {\n const size = this.size;\n\n super.clear();\n if (size > 0) { this._publisher.publish(\"collection:clear\"); }\n }\n\n /**\n * Subscribes to an event and adds a callback to be executed when the event is published.\n *\n * ---\n *\n * @example\n * ```ts\n * const set = new SetView<number>();\n * const unsubscribe = set.subscribe(\"entry:add\", (value: number) =>\n * {\n * if (value === 42) { unsubscribe(); }\n * console.log(`Added ${value}`);\n * });\n *\n * set.add(2); // Added 2\n * set.add(42); // Added 42\n * set.add(4);\n * set.add(8);\n * ```\n *\n * ---\n *\n * @template K The key of the map containing the callback signature to subscribe.\n *\n * @param event The name of the event to subscribe to.\n * @param callback The callback to execute when the event is published.\n *\n * @returns A function that can be used to unsubscribe the callback from the event.\n */\n public subscribe<K extends keyof SetViewEventsMap<T>>(event: K, callback: SetViewEventsMap<T>[K]): () => void\n {\n return this._publisher.subscribe(event, callback);\n }\n\n /**\n * Unsubscribes from an event and removes a callback from being executed when the event is published.\n *\n * ---\n *\n * @example\n * ```ts\n * const callback = (value: number) => console.log(`Added ${value}`);\n * const set = new SetView<number>();\n *\n * set.subscribe(\"entry:add\", callback);\n * set.add(2); // Added 2\n *\n * set.unsubscribe(\"entry:add\", callback);\n * set.add(4);\n * ```\n *\n * ---\n *\n * @template K The key of the map containing the callback signature to unsubscribe.\n *\n * @param event The name of the event to unsubscribe from.\n * @param callback The callback to remove from the event.\n */\n public unsubscribe<K extends keyof SetViewEventsMap<T>>(event: K, callback: SetViewEventsMap<T>[K]): void\n {\n this._publisher.unsubscribe(event, callback);\n }\n\n public override readonly [Symbol.toStringTag]: string = \"SetView\";\n}\n","import { isBrowser } from \"../../helpers.js\";\nimport { EnvironmentException } from \"../exceptions/index.js\";\n\nimport type { JSONValue } from \"./types.js\";\n\n/**\n * A wrapper around the {@link Storage} API to better store and easily retrieve\n * typed JSON values using the classical key-value pair storage system.\n *\n * It allows to handle either the volatile {@link sessionStorage} or the persistent\n * {@link localStorage} at the same time, depending on what's your required use case.\n *\n * ---\n *\n * @example\n * ```ts\n * const jsonStorage = new JSONStorage();\n *\n * jsonStorage.write(\"user:cookieAck\", { value: true, version: \"2023-02-15\" });\n * // ... between sessions ...\n * const cookieAck = jsonStorage.read<{ value: boolean; version: string; }>(\"user:cookieAck\");\n * ```\n */\nexport default class JSONStorage\n{\n /**\n * Whether to prefer the {@link localStorage} over the {@link sessionStorage} when calling an ambivalent method.\n *\n * If `true`, the persistent storage is preferred. If `false`, the volatile storage is preferred. \n * Default is `true`.\n */\n protected _preferPersistence: boolean;\n\n /**\n * A reference to the volatile {@link sessionStorage} storage.\n */\n protected _volatile: Storage;\n\n /**\n * A reference to the persistent {@link localStorage} storage.\n */\n protected _persistent: Storage;\n\n /**\n * Initializes a new instance of the {@link JSONStorage} class. \n * It cannot be instantiated outside of a browser environment or an {@link EnvironmentException} is thrown.\n *\n * ---\n *\n * @example\n * ```ts\n * const jsonStorage = new JSONStorage();\n * ```\n *\n * ---\n *\n * @param preferPersistence\n * Whether to prefer the {@link localStorage} over the {@link sessionStorage} when calling an ambivalent method. \n * If omitted, it defaults to `true` to prefer the persistent storage.\n */\n public constructor(preferPersistence = true)\n {\n if (!(isBrowser))\n {\n throw new EnvironmentException(\n \"The `JSONStorage` class can only be instantiated within a browser environment.\"\n );\n }\n\n this._preferPersistence = preferPersistence;\n\n this._volatile = window.sessionStorage;\n this._persistent = window.localStorage;\n }\n\n protected _get<T extends JSONValue>(storage: Storage, key: string): T | undefined;\n protected _get<T extends JSONValue>(storage: Storage, key: string, defaultValue: T): T;\n protected _get<T extends JSONValue>(storage: Storage, key: string, defaultValue?: T): T | undefined;\n protected _get<T extends JSONValue>(storage: Storage, key: string, defaultValue?: T): T | undefined\n {\n const value = storage.getItem(key);\n if (value)\n {\n try\n {\n return JSON.parse(value);\n }\n catch\n {\n // eslint-disable-next-line no-console\n console.warn(\n `The \"${value}\" value for \"${key}\"` +\n \" property cannot be parsed. Clearing the storage...\");\n\n storage.removeItem(key);\n }\n }\n\n return defaultValue;\n }\n protected _set<T extends JSONValue>(storage: Storage, key: string, newValue?: T): void\n {\n const encodedValue = JSON.stringify(newValue);\n if (encodedValue)\n {\n storage.setItem(key, encodedValue);\n }\n else\n {\n storage.removeItem(key);\n }\n }\n\n /**\n * Retrieves the value with the specified key from the default storage.\n *\n * ---\n *\n * @example\n * ```ts\n * const value: TValue = jsonStorage.get<TValue>(\"key\");\n * ```\n *\n * ---\n *\n * @template T The type of the value to retrieve.\n *\n * @param key The key of the value to retrieve.\n *\n * @returns The value with the specified key or `undefined` if the key doesn't exist.\n */\n public get<T extends JSONValue>(key: string): T | undefined;\n\n /**\n * Retrieves the value with the specified key from the default storage.\n *\n * ---\n *\n * @example\n * ```ts\n * const value: TValue = jsonStorage.get<TValue>(\"key\", defaultValue);\n * ```\n *\n * ---\n *\n * @template T The type of the value to retrieve.\n *\n * @param key The key of the value to retrieve.\n * @param defaultValue The default value to return if the key doesn't exist.\n * @param persistent\n * Whether to prefer the persistent {@link localStorage} over the volatile {@link sessionStorage}. \n * If omitted, it defaults to the `preferPersistence` value set in the constructor.\n *\n * @returns The value with the specified key or the provided default value if the key doesn't exist.\n */\n public get<T extends JSONValue>(key: string, defaultValue: T, persistent?: boolean): T;\n\n /**\n * Retrieves the value with the specified key from the default storage.\n *\n * ---\n *\n * @example\n * ```ts\n * const value: TValue = jsonStorage.get<TValue>(\"key\", obj?.value);\n * ```\n *\n * ---\n *\n * @template T The type of the value to retrieve.\n *\n * @param key The key of the value to retrieve.\n * @param defaultValue The default value to return (which may be `undefined`) if the key doesn't exist.\n * @param persistent\n * Whether to prefer the persistent {@link localStorage} over the volatile {@link sessionStorage}. \n * If omitted, it defaults to the `preferPersistence` value set in the constructor.\n *\n * @returns The value with the specified key or the default value if the key doesn't exist.\n */\n public get<T extends JSONValue>(key: string, defaultValue?: T, persistent?: boolean): T | undefined;\n public get<T extends JSONValue>(key: string, defaultValue?: T, persistent = this._preferPersistence)\n : T | undefined\n {\n const storage = persistent ? this._persistent : this._volatile;\n\n return this._get<T>(storage, key, defaultValue);\n }\n\n /**\n * Retrieves the value with the specified key from the volatile {@link sessionStorage}.\n *\n * ---\n *\n * @example\n * ```ts\n * const value: TValue = jsonStorage.recall<TValue>(\"key\");\n * ```\n *\n * ---\n *\n * @template T The type of the value to retrieve.\n *\n * @param key The key of the value to retrieve.\n *\n * @returns The value with the specified key or `undefined` if the key doesn't exist.\n */\n public recall<T extends JSONValue>(key: string): T | undefined;\n\n /**\n * Retrieves the value with the specified key from the volatile {@link sessionStorage}.\n *\n * ---\n *\n * @example\n * ```ts\n * const value: TValue = jsonStorage.recall<TValue>(\"key\", defaultValue);\n * ```\n *\n * ---\n *\n * @template T The type of the value to retrieve.\n *\n * @param key The key of the value to retrieve.\n * @param defaultValue The default value to return if the key doesn't exist.\n *\n * @returns The value with the specified key or the default value if the key doesn't exist.\n */\n public recall<T extends JSONValue>(key: string, defaultValue: T): T;\n\n /**\n * Retrieves the value with the specified key from the volatile {@link sessionStorage}.\n *\n * ---\n *\n * @example\n * ```ts\n * const value: TValue = jsonStorage.recall<TValue>(\"key\", obj?.value);\n * ```\n *\n * ---\n *\n * @template T The type of the value to retrieve.\n *\n * @param key The key of the value to retrieve.\n * @param defaultValue The default value to return (which may be `undefined`) if the key doesn't exist.\n *\n * @returns The value with the specified key or the default value if the key doesn't exist.\n */\n public recall<T extends JSONValue>(key: string, defaultValue?: T): T | undefined;\n public recall<T extends JSONValue>(key: string, defaultValue?: T): T | undefined\n {\n return this._get<T>(this._volatile, key, defaultValue);\n }\n\n /**\n * Retrieves the value with the specified key looking first in the volatile\n * {@link sessionStorage} and then, if not found, in the persistent {@link localStorage}.\n *\n * ---\n *\n * @example\n * ```ts\n * const value: TValue = jsonStorage.retrieve<TValue>(\"key\");\n * ```\n *\n * ---\n *\n * @template T The type of the value to retrieve.\n *\n * @param key The key of the value to retrieve.\n *\n * @returns The value with the specified key or `undefined` if the key doesn't exist.\n */\n public retrieve<T extends JSONValue>(key: string): T | undefined;\n\n /**\n * Retrieves the value with the specified key looking first in the volatile\n * {@link sessionStorage} and then, if not found, in the persistent {@link localStorage}.\n *\n * ---\n *\n * @example\n * ```ts\n * const value: TValue = jsonStorage.retrieve<TValue>(\"key\", defaultValue);\n * ```\n *\n * ---\n *\n * @template T The type of the value to retrieve.\n *\n * @param key The key of the value to retrieve.\n * @param defaultValue The default value to return if the key doesn't exist.\n *\n * @returns The value with the specified key or the default value if the key doesn't exist.\n */\n public retrieve<T extends JSONValue>(key: string, defaultValue: T): T;\n\n /**\n * Retrieves the value with the specified key looking first in the volatile\n * {@link sessionStorage} and then, if not found, in the persistent {@link localStorage}.\n *\n * ---\n *\n * @example\n * ```ts\n * const value: TValue = jsonStorage.retrieve<TValue>(\"key\", obj?.value);\n * ```\n *\n * ---\n *\n * @template T The type of the value to retrieve.\n *\n * @param key The key of the value to retrieve.\n * @param defaultValue The default value to return (which may be `undefined`) if the key doesn't exist.\n *\n * @returns The value with the specified key or the default value if the key doesn't exist.\n */\n public retrieve<T extends JSONValue>(key: string, defaultValue?: T): T | undefined;\n public retrieve<T extends JSONValue>(key: string, defaultValue?: T): T | undefined\n {\n return this.recall<T>(key) ?? this.read<T>(key, defaultValue);\n }\n\n /**\n * Retrieves the value with the specified key from the persistent {@link localStorage}.\n *\n * ---\n *\n * @example\n * ```ts\n * const value: TValue = jsonStorage.read<TValue>(\"key\");\n * ```\n *\n * ---\n *\n * @template T The type of the value to retrieve.\n *\n * @param key The key of the value to retrieve.\n *\n * @returns The value with the specified key or `undefined` if the key doesn't exist.\n */\n public read<T extends JSONValue>(key: string): T | undefined;\n\n /**\n * Retrieves the value with the specified key from the persistent {@link localStorage}.\n *\n * ---\n *\n * @example\n * ```ts\n * const value: TValue = jsonStorage.read<TValue>(\"key\", defaultValue);\n * ```\n *\n * ---\n *\n * @template T The type of the value to retrieve.\n *\n * @param key The key of the value to retrieve.\n * @param defaultValue The default value to return if the key doesn't exist.\n *\n * @returns The value with the specified key or the default value if the key doesn't exist.\n */\n public read<T extends JSONValue>(key: string, defaultValue: T): T;\n\n /**\n * Retrieves the value with the specified key from the persistent {@link localStorage}.\n *\n * ---\n *\n * @example\n * ```ts\n * const value: TValue = jsonStorage.read<TValue>(\"key\", obj?.value);\n * ```\n *\n * ---\n *\n * @template T The type of the value to retrieve.\n *\n * @param key The key of the value to retrieve.\n * @param defaultValue The default value to return (which may be `undefined`) if the key doesn't exist.\n *\n * @returns The value with the specified key or the default value if the key doesn't exist.\n */\n public read<T extends JSONValue>(key: string, defaultValue?: T): T | undefined;\n public read<T extends JSONValue>(key: string, defaultValue?: T): T | undefined\n {\n return this._get<T>(this._persistent, key, defaultValue);\n }\n\n /**\n * Checks whether the value with the specified key exists within the default storage.\n *\n * ---\n *\n * @example\n * ```ts\n * if (jsonStorage.has(\"key\"))\n * {\n * // The key exists. Do something...\n * }\n * ```\n *\n * ---\n *\n * @param key The key of the value to check.\n * @param persistent\n * Whether to prefer the persistent {@link localStorage} over the volatile {@link sessionStorage}. \n * If omitted, it defaults to the `preferPersistence` value set in the constructor.\n *\n * @returns `true` if the key exists, `false` otherwise.\n */\n public has(key: string, persistent?: boolean): boolean\n {\n const storage = persistent ? this._persistent : this._volatile;\n\n return storage.getItem(key) !== null;\n }\n\n /**\n * Checks whether the value with the specified key exists within the volatile {@link sessionStorage}.\n *\n * ---\n *\n * @example\n * ```ts\n * if (jsonStorage.knows(\"key\"))\n * {\n * // The key exists. Do something...\n * }\n * ```\n *\n * ---\n *\n * @param key The key of the value to check.\n *\n * @returns `true` if the key exists, `false` otherwise.\n */\n public knows(key: string): boolean\n {\n return this._volatile.getItem(key) !== null;\n }\n\n /**\n * Checks whether the value with the specified key exists looking first in the\n * volatile {@link sessionStorage} and then, if not found, in the persistent {@link localStorage}.\n *\n * ---\n *\n * @example\n * ```ts\n * if (jsonStorage.find(\"key\"))\n * {\n * // The key exists. Do something...\n * }\n * ```\n *\n * ---\n *\n * @param key The key of the value to check.\n *\n * @returns `true` if the key exists, `false` otherwise.\n */\n public find(key: string): boolean\n {\n return this.knows(key) ?? this.exists(key);\n }\n\n /**\n * Checks whether the value with the specified key exists within the persistent {@link localStorage}.\n *\n * ---\n *\n * @example\n * ```ts\n * if (jsonStorage.exists(\"key\"))\n * {\n * // The key exists. Do something...\n * }\n * ```\n *\n * ---\n *\n * @param key The key of the value to check.\n *\n * @returns `true` if the key exists, `false` otherwise.\n */\n public exists(key: string): boolean\n {\n return this._persistent.getItem(key) !== null;\n }\n\n /**\n * Sets the value with the specified key in the default storage. \n * If the value is `undefined` or omitted, the key is removed from the storage.\n *\n * ---\n *\n * @example\n * ```ts\n * jsonStorage.set(\"key\");\n * jsonStorage.set(\"key\", value);\n * jsonStorage.set(\"key\", obj?.value);\n * ```\n *\n * ---\n *\n * @template T The type of the value to set.\n *\n * @param key The key of the value to set.\n * @param newValue The new value to set. If it's `undefined` or omitted, the key is removed instead.\n * @param persistent\n * Whether to prefer the persistent {@link localStorage} over the volatile {@link sessionStorage}. \n * If omitted, it defaults to the `preferPersistence` value set in the constructor.\n */\n public set<T extends JSONValue>(key: string, newValue?: T, persistent = this._preferPersistence): void\n {\n const storage = persistent ? this._persistent : this._volatile;\n\n this._set<T>(storage, key, newValue);\n }\n\n /**\n * Sets the value with the specified key in the volatile {@link sessionStorage}. \n * If the value is `undefined` or omitted, the key is removed from the storage.\n *\n * ---\n *\n * @example\n * ```ts\n * jsonStorage.remember(\"key\");\n * jsonStorage.remember(\"key\", value);\n * jsonStorage.remember(\"key\", obj?.value);\n * ```\n *\n * ---\n *\n * @template T The type of the value to set.\n *\n * @param key The key of the value to set.\n * @param newValue The new value to set. If it's `undefined` or omitted, the key is removed instead.\n */\n public remember<T extends JSONValue>(key: string, newValue?: T): void\n {\n this._set<T>(this._volatile, key, newValue);\n }\n\n /**\n * Sets the value with the specified key in the persistent {@link localStorage}. \n * If the value is `undefined` or omitted, the key is removed from the storage.\n *\n * ---\n *\n * @example\n * ```ts\n * jsonStorage.write(\"key\");\n * jsonStorage.write(\"key\", value);\n * jsonStorage.write(\"key\", obj?.value);\n * ```\n *\n * ---\n *\n * @template T The type of the value to set.\n *\n * @param key The key of the value to set.\n * @param newValue The new value to set. If it's `undefined` or omitted, the key is removed instead.\n */\n public write<T extends JSONValue>(key: string, newValue?: T): void\n {\n this._set<T>(this._persistent, key, newValue);\n }\n\n /**\n * Removes the value with the specified key from the default storage.\n *\n * ---\n *\n * @example\n * ```ts\n * jsonStorage.delete(\"key\");\n * ```\n *\n * ---\n *\n * @param key The key of the value to remove.\n * @param persistent\n * Whether to prefer the persistent {@link localStorage} over the volatile {@link sessionStorage}. \n * If omitted, it defaults to the `preferPersistence` value set in the constructor.\n */\n public delete(key: string, persistent?: boolean): void\n {\n const storage = persistent ? this._persistent : this._volatile;\n\n storage.removeItem(key);\n }\n\n /**\n * Removes the value with the specified key from the volatile {@link sessionStorage}.\n *\n * ---\n *\n * @example\n * ```ts\n * jsonStorage.forget(\"key\");\n * ```\n *\n * ---\n *\n * @param key The key of the value to remove.\n */\n public forget(key: string): void\n {\n this._volatile.removeItem(key);\n }\n\n /**\n * Removes the value with the specified key from the persistent {@link localStorage}.\n *\n * ---\n *\n * @example\n * ```ts\n * jsonStorage.erase(\"key\");\n * ```\n *\n * ---\n *\n * @param key The key of the value to remove.\n */\n public erase(key: string): void\n {\n this._persistent.removeItem(key);\n }\n\n /**\n * Removes the value with the specified key from both the\n * volatile {@link sessionStorage} and the persistent {@link localStorage}.\n *\n * ---\n *\n * @example\n * ```ts\n * jsonStorage.clear(\"key\");\n * ```\n *\n * ---\n *\n * @param key The key of the value to remove.\n */\n public clear(key: string): void\n {\n this._volatile.removeItem(key);\n this._persistent.removeItem(key);\n }\n\n public readonly [Symbol.toStringTag]: string = \"JSONStorage\";\n}\n","import type { FulfilledHandler, PromiseExecutor, RejectedHandler } from \"./types.js\";\n\n/**\n * A wrapper class representing an enhanced version of the native {@link Promise} object.\n *\n * It provides additional properties to check the state of the promise itself. \n * The state can be either `pending`, `fulfilled` or `rejected` and is accessible through\n * the {@link SmartPromise.isPending}, {@link SmartPromise.isFulfilled} & {@link SmartPromise.isRejected} properties.\n *\n * ---\n *\n * @example\n * ```ts\n * const promise = new SmartPromise<string>((resolve, reject) =>\n * {\n * setTimeout(() => resolve(\"Hello, World!\"), 1_000);\n * });\n *\n * console.log(promise.isPending); // true\n * console.log(promise.isFulfilled); // false\n *\n * console.log(await promise); // \"Hello, World!\"\n *\n * console.log(promise.isPending); // false\n * console.log(promise.isFulfilled); // true\n * ```\n *\n * ---\n *\n * @template T The type of value the promise will eventually resolve to. Default is `void`.\n */\nexport default class SmartPromise<T = void> implements Promise<T>\n{\n /**\n * Wraps a new {@link SmartPromise} object around an existing native {@link Promise} object.\n *\n * ---\n *\n * @example\n * ```ts\n * const request = fetch(\"https://api.example.com/data\");\n * const smartRequest = SmartPromise.FromPromise(request);\n *\n * console.log(request.isPending); // Throws an error: `isPending` is not a property of `Promise`.\n * console.log(smartRequest.isPending); // true\n *\n * const response = await request;\n * console.log(smartRequest.isFulfilled); // true\n * ```\n *\n * ---\n *\n * @param promise The promise to wrap.\n *\n * @returns A new {@link SmartPromise} object that wraps the provided promise.\n */\n public static FromPromise<T>(promise: Promise<T>): SmartPromise<T>\n {\n return new SmartPromise((resolve, reject) => promise.then(resolve, reject));\n }\n\n /**\n * A flag indicating whether the promise is still pending or not.\n *\n * The protected property is the only one that can be modified directly by the derived classes. \n * If you're looking for the public and readonly property, use the {@link SmartPromise.isPending} getter instead.\n */\n protected _isPending: boolean;\n\n /**\n * A flag indicating whether the promise is still pending or not.\n */\n public get isPending(): boolean\n {\n return this._isPending;\n }\n\n /**\n * A flag indicating whether the promise has been fulfilled or not.\n *\n * The protected property is the only one that can be modified directly by the derived classes. \n * If you're looking for the public and readonly property, use the {@link SmartPromise.isFulfilled} getter instead.\n */\n protected _isFulfilled: boolean;\n\n /**\n * A flag indicating whether the promise has been fulfilled or not.\n */\n public get isFulfilled(): boolean\n {\n return this._isFulfilled;\n }\n\n /**\n * A flag indicating whether the promise has been rejected or not.\n *\n * The protected property is the only one that can be modified directly by the derived classes. \n * If you're looking for the public and readonly property, use the {@link SmartPromise.isRejected} getter instead.\n */\n protected _isRejected: boolean;\n\n /**\n * A flag indicating whether the promise has been rejected or not.\n */\n public get isRejected(): boolean\n {\n return this._isRejected;\n }\n\n /**\n * The native {@link Promise} object wrapped by this instance.\n */\n protected _promise: Promise<T>;\n\n /**\n * Initializes a new instance of the {@link SmartPromise} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const promise = new SmartPromise<string>((resolve, reject) =>\n * {\n * setTimeout(() => resolve(\"Hello, World!\"), 1_000);\n * });\n * ```\n *\n * ---\n *\n * @param executor\n * The function responsible for eventually resolving or rejecting the promise. \n * Similarly to the native {@link Promise} object, it's immediately executed after the promise is created.\n */\n public constructor(executor: PromiseExecutor<T>)\n {\n this._isPending = true;\n this._isFulfilled = false;\n this._isRejected = false;\n\n const _onFulfilled = (result: T): T =>\n {\n this._isPending = false;\n this._isFulfilled = true;\n\n return result;\n };\n const _onRejected = (reason: unknown): never =>\n {\n this._isPending = false;\n this._isRejected = true;\n\n throw reason;\n };\n\n this._promise = new Promise<T>(executor)\n .then(_onFulfilled, _onRejected);\n }\n\n /**\n * Creates a new {@link Promise} identical to the one wrapped by this instance, with a different reference.\n *\n * ---\n *\n * @example\n * ```ts\n * const promise = new SmartPromise<string>((resolve, reject) =>\n * {\n * setTimeout(() => resolve(\"Hello, World!\"), 1_000);\n * });\n *\n * console.log(await promise.then()); // \"Hello, World!\"\n * ```\n *\n * ---\n *\n * @returns A new {@link Promise} identical to the original one.\n */\n public then(onFulfilled?: null): Promise<T>;\n\n /**\n * Attaches a callback that executes right after the promise is fulfilled.\n *\n * The previous result of the promise is passed as the argument to the callback. \n * The callback's return value is considered the new promise's result instead.\n *\n * ---\n *\n * @example\n * ```ts\n * const promise = new SmartPromise<string>((resolve, reject) =>\n * {\n * setTimeout(() => resolve(\"Hello, World!\"), 1_000);\n * });\n *\n * promise.then((result) => console.log(result)); // \"Hello, World!\"\n * ```\n *\n * ---\n *\n * @template F The type of value the new promise will eventually resolve to. Default is `T`.\n *\n * @param onFulfilled The callback to execute once the promise is fulfilled.\n *\n * @returns A new {@link Promise} resolved with the return value of the callback.\n */\n public then<F = T>(onFulfilled: FulfilledHandler<T, F>, onRejected?: null): Promise<F>;\n\n /**\n * Attaches callbacks that executes right after the promise is fulfilled or rejected.\n *\n * The previous result of the promise is passed as the argument to the fulfillment callback. \n * The fulfillment callback's return value is considered the new promise's result instead.\n *\n * If an error is thrown during execution, the rejection callback is then executed instead.\n *\n * Also note that:\n * - If the rejection callback runs properly, the error is considered handled. \n * The rejection callback's return value is considered the new promise's result.\n * - If the rejection callback throws an error, the new promise is rejected with that error.\n *\n * ---\n *\n * @example\n * ```ts\n * const promise = new SmartPromise((resolve, reject) =>\n * {\n * setTimeout(resolve, Math.random() * 1_000);\n * setTimeout(reject, Math.random() * 1_000);\n * });\n *\n * promise.then(() => console.log(\"OK!\"), () => console.log(\"KO!\")); // \"OK!\" or \"KO!\"\n * ```\n *\n * ---\n *\n * @template F The type of value the new promise will eventually resolve to. Default is `T`.\n * @template R The type of value the new promise will eventually resolve to. Default is `never`.\n *\n * @param onFulfilled The callback to execute once the promise is fulfilled.\n * @param onRejected The callback to execute once the promise is rejected.\n *\n * @returns A new {@link Promise} resolved or rejected based on the callbacks.\n */\n public then<F = T, R = never>(onFulfilled: FulfilledHandler<T, F>, onRejected: RejectedHandler<unknown, R>)\n : Promise<F | R>;\n public then<F = T, R = never>(\n onFulfilled?: FulfilledHandler<T, F> | null,\n onRejected?: RejectedHandler<unknown, R> | null): Promise<F | R>\n {\n return this._promise.then(onFulfilled, onRejected);\n }\n\n /**\n * Creates a new {@link Promise} identical to the one wrapped by this instance, with a different reference.\n *\n * ---\n *\n * @example\n * ```ts\n * const promise = new SmartPromise((resolve, reject) =>\n * {\n * setTimeout(() => reject(new Error(\"An unknown error occurred.\")), 1_000);\n * });\n *\n * promise.catch(); // Uncaught Error: An unknown error occurred.\n * ```\n *\n * ---\n *\n * @returns A new {@link Promise} identical to the original one.\n */\n public catch(onRejected?: null): Promise<T>;\n\n /**\n * Attaches a callback to handle the potential rejection of the promise. \n * If it happens, the callback is then executed.\n *\n * Also note that:\n * - If the callback runs properly, the error is considered handled. \n * The callback's return value is considered the new promise's result.\n * - If the callback throws an error, the new promise is rejected with that error.\n *\n * ---\n *\n * @example\n * ```ts\n * const promise = new SmartPromise((resolve, reject) =>\n * {\n * setTimeout(() => reject(new Error(\"An unknown error occurred.\")), 1_000);\n * });\n *\n * promise.catch((reason) => console.error(reason)); // \"Error: An unknown error occurred.\"\n * ```\n *\n * ---\n *\n * @template R The type of value the new promise will eventually resolve to. Default is `T`.\n *\n * @param onRejected The callback to execute once the promise is rejected.\n *\n * @returns A new {@link Promise} able to catch and handle the potential error.\n */\n public catch<R = never>(onRejected: RejectedHandler<unknown, R>): Promise<T | R>;\n public catch<R = never>(onRejected?: RejectedHandler<unknown, R> | null): Promise<T | R>\n {\n return this._promise.catch(onRejected);\n }\n\n /**\n * Attaches a callback that executes right after the promise is settled, regardless of the outcome.\n *\n * ---\n *\n * @example\n * ```ts\n * const promise = new SmartPromise((resolve, reject) =>\n * {\n * setTimeout(resolve, Math.random() * 1_000);\n * setTimeout(reject, Math.random() * 1_000);\n * });\n *\n *\n * promise\n * .then(() => console.log(\"OK!\")) // Logs \"OK!\" if the promise is fulfilled.\n * .catch(() => console.log(\"KO!\")) // Logs \"KO!\" if the promise is rejected.\n * .finally(() => console.log(\"Done!\")); // Always logs \"Done!\".\n * ```\n *\n * ---\n *\n * @param onFinally The callback to execute when once promise is settled.\n *\n * @returns A new {@link Promise} that executes the callback once the promise is settled.\n */\n public finally(onFinally?: (() => void) | null): Promise<T>\n {\n return this._promise.finally(onFinally);\n }\n\n public readonly [Symbol.toStringTag]: string = \"SmartPromise\";\n}\n","import type { PromiseResolver, PromiseRejecter, FulfilledHandler, RejectedHandler } from \"./types.js\";\n\nimport SmartPromise from \"./smart-promise.js\";\n\n/**\n * A class representing a {@link SmartPromise} that can be resolved or rejected from the \"outside\". \n * The `resolve` and `reject` methods are exposed to allow the promise to be settled from another context.\n *\n * It's particularly useful in scenarios where the promise is created and needs to be awaited in one place, \n * while being resolved or rejected in another (e.g. an event handler for an user interaction).\n *\n * This is a change in the approach to promises: instead of defining how the promise will be resolved (or rejected), \n * you define how to handle the resolution (or rejection) when it occurs.\n *\n * ---\n *\n * @example\n * ```ts\n * const promise = new DeferredPromise<string, string[]>((value: string) => value.split(\" \"));\n *\n * promise.then((result) => console.log(result)); // [\"Hello,\", \"World!\"]\n * promise.resolve(\"Hello, World!\");\n * ```\n *\n * ---\n *\n * @template T The type of value the promise expects to initially be resolved with. Default is `void`.\n * @template F\n * The type of value returned by the `onFulfilled` callback. \n * This will be the actual type of value the promise will eventually resolve to. Default is `T`.\n * @template R\n * The type of value possibly returned by the `onRejected` callback. \n * This will be coupled with the type of value the promise will eventually resolve to, if provided. Default is `never`.\n */\nexport default class DeferredPromise<T = void, F = T, R = never> extends SmartPromise<F | R>\n{\n /**\n * The exposed function that allows to resolve the promise.\n *\n * This protected property is the only one that can be modified directly by the derived classes. \n * If you're looking for the public and readonly property, use the {@link DeferredPromise.resolve} getter instead.\n */\n protected _resolve: PromiseResolver<T>;\n\n /**\n * The exposed function that allows to reject the promise.\n */\n public get resolve(): PromiseResolver<T> { return this._resolve; }\n\n /**\n * The exposed function that allows to reject the promise.\n *\n * This protected property is the only one that can be modified directly by the derived classes. \n * If you're looking for the public and readonly property, use the {@link DeferredPromise.reject} getter instead.\n */\n protected _reject: PromiseRejecter;\n\n /**\n * The exposed function that allows to reject the promise.\n */\n public get reject(): PromiseRejecter { return this._reject; }\n\n /**\n * Initializes a new instance of the {@link DeferredPromise} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const promise = new DeferredPromise<string, string[]>((value: string) => value.split(\" \"));\n * ```\n *\n * ---\n *\n * @param onFulfilled The callback to execute once the promise is fulfilled.\n * @param onRejected The callback to execute once the promise is rejected.\n */\n public constructor(onFulfilled?: FulfilledHandler<T, F> | null, onRejected?: RejectedHandler<unknown, R> | null)\n {\n let _resolve: PromiseResolver<T>;\n let _reject: PromiseRejecter;\n\n super((resolve, reject) =>\n {\n // ReferenceError: Must call super constructor in derived class before accessing\n // 'this' or returning from derived constructor.\n //\n _resolve = resolve as PromiseResolver<T>;\n _reject = reject;\n });\n\n this._promise = this._promise.then(onFulfilled as FulfilledHandler<F | R>, onRejected);\n\n this._resolve = _resolve!;\n this._reject = _reject!;\n }\n\n /**\n * Watches another promise and resolves or rejects this promise when the other one is settled.\n *\n * ---\n *\n * @example\n * ```ts\n * const promise = new Promise<string>((resolve) => setTimeout(() => resolve(\"Hello, World!\"), 1_000));\n * const deferred = new DeferredPromise<string, string[]>((value: string) => value.split(\" \"));\n *\n * deferred.then((result) => console.log(result)); // [\"Hello,\", \"World!\"]\n * deferred.watch(promise);\n * ```\n *\n * ---\n *\n * @param otherPromise The promise to watch.\n *\n * @returns The current instance of the {@link DeferredPromise} class.\n */\n public watch(otherPromise: PromiseLike<T>): this\n {\n otherPromise.then(this.resolve, this.reject);\n\n return this;\n }\n\n public override readonly [Symbol.toStringTag]: string = \"DeferredPromise\";\n}\n","import { TimeoutException } from \"../exceptions/index.js\";\n\nimport SmartPromise from \"./smart-promise.js\";\nimport type { MaybePromise, PromiseExecutor } from \"./types.js\";\n\n/**\n * A class representing a {@link SmartPromise} that rejects automatically after a given time. \n * It's useful for operations that must be completed within a certain time frame.\n *\n * If the operation takes longer than the specified time, the promise is rejected with a {@link TimeoutException}.\n *\n * ---\n *\n * @example\n * ```ts\n * const promise = new TimedPromise<string>((resolve, reject) =>\n * {\n * setTimeout(() => resolve(\"Hello, World!\"), Math.random() * 10_000);\n *\n * }, 5_000);\n *\n * promise\n * .then((result) => console.log(result)) // \"Hello, World!\"\n * .catch((error) => console.error(error)); // TimeoutException: The operation has timed out.\n * ```\n *\n * ---\n *\n * @template T The type of value the promise will eventually resolve to. Default is `void`.\n */\nexport default class TimedPromise<T = void> extends SmartPromise<T>\n{\n /**\n * Initializes a new instance of the {@link TimedPromise} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const promise = new TimedPromise<string>((resolve, reject) =>\n * {\n * setTimeout(() => resolve(\"Hello, World!\"), Math.random() * 10_000);\n *\n * }, 5_000);\n * ```\n *\n * ---\n *\n * @param executor\n * The function responsible for eventually resolving or rejecting the promise. \n * Similarly to the native {@link Promise} object, it's immediately executed after the promise is created.\n *\n * @param timeout The maximum time in milliseconds that the operation can take before timing out.\n */\n public constructor(executor: PromiseExecutor<T>, timeout?: number)\n {\n super((resolve, reject) =>\n {\n const _resolve = (result: MaybePromise<T>) =>\n {\n clearTimeout(_timeoutId);\n resolve(result);\n };\n const _reject = (reason: unknown) =>\n {\n clearTimeout(_timeoutId);\n reject(reason);\n };\n\n const _timeout = () => _reject(new TimeoutException(\"The operation has timed out.\"));\n const _timeoutId = setTimeout(_timeout, timeout);\n\n executor(_resolve, _reject);\n });\n }\n\n public override readonly [Symbol.toStringTag]: string = \"TimedPromise\";\n}\n","\nimport { RangeException, SmartIterator } from \"../models/index.js\";\n\n/**\n * An enumeration that represents the time units and their conversion factors. \n * It can be used as utility to express time values in a more\n * readable way or to convert time values between different units.\n *\n * ---\n *\n * @example\n * ```ts\n * setTimeout(() => { [...] }, 5 * TimeUnit.Minute);\n * ```\n */\nexport enum TimeUnit\n{\n /* eslint-disable @typescript-eslint/prefer-literal-enum-member */\n\n /**\n * A millisecond: the base time unit.\n */\n Millisecond = 1,\n\n /**\n * A second: 1000 milliseconds.\n */\n Second = 1_000,\n\n /**\n * A minute: 60 seconds.\n */\n Minute = 60 * Second,\n\n /**\n * An hour: 60 minutes.\n */\n Hour = 60 * Minute,\n\n /**\n * A day: 24 hours.\n */\n Day = 24 * Hour,\n\n /**\n * A week: 7 days.\n */\n Week = 7 * Day,\n\n /**\n * A month: 30 days.\n */\n Month = 30 * Day,\n\n /**\n * A year: 365 days.\n */\n Year = 365 * Day\n}\n\n/**\n * An enumeration that represents the days of the week. \n * It can be used as utility to identify the days of the week when working with dates.\n *\n * ---\n *\n * @example\n * ```ts\n * const today = new Date();\n * if (today.getUTCDay() === WeekDay.Sunday)\n * {\n * // Today is Sunday. Do something...\n * }\n * ```\n */\nexport enum WeekDay\n{\n /**\n * Sunday\n */\n Sunday = 0,\n\n /**\n * Monday\n */\n Monday = 1,\n\n /**\n * Tuesday\n */\n Tuesday = 2,\n\n /**\n * Wednesday\n */\n Wednesday = 3,\n\n /**\n * Thursday\n */\n Thursday = 4,\n\n /**\n * Friday\n */\n Friday = 5,\n\n /**\n * Saturday\n */\n Saturday = 6\n}\n\n/**\n * An utility function that calculates the difference between two dates. \n * The difference can be expressed in different time units.\n *\n * ---\n *\n * @example\n * ```ts\n * const start = new Date(\"2025-01-01\");\n * const end = new Date(\"2025-01-31\");\n *\n * dateDifference(start, end, TimeUnit.Minute); // 43200\n * ```\n *\n * ---\n *\n * @param start The start date.\n * @param end The end date.\n * @param unit The time unit to express the difference. `TimeUnit.Day` by default.\n *\n * @returns The difference between the two dates in the specified time unit.\n */\nexport function dateDifference(start: number | string | Date, end: number | string | Date, unit = TimeUnit.Day): number\n{\n let _round: (value: number) => number;\n\n start = new Date(start);\n end = new Date(end);\n\n if (start < end) { _round = Math.floor; }\n else { _round = Math.ceil; }\n\n return _round((end.getTime() - start.getTime()) / unit);\n}\n\n/**\n * An utility function that generates an iterator over a range of dates. \n * The step between the dates can be expressed in different time units.\n *\n * ---\n *\n * @example\n * ```ts\n * const start = new Date(\"2025-01-01\");\n * const end = new Date(\"2025-01-31\");\n *\n * for (const date of dateRange(start, end, TimeUnit.Week))\n * {\n * date.toISOString().slice(8, 10); // \"01\", \"08\", \"15\", \"22\", \"29\"\n * }\n * ```\n *\n * ---\n *\n * @param start The start date (included).\n * @param end\n * The end date (excluded).\n *\n * Must be greater than the start date. Otherwise, a {@link RangeException} will be thrown.\n *\n * @param step The time unit to express the step between the dates. `TimeUnit.Day` by default.\n *\n * @returns A {@link SmartIterator} object that generates the dates in the range.\n */\nexport function dateRange(start: number | string | Date, end: number | string | Date, step = TimeUnit.Day)\n : SmartIterator<Date>\n{\n start = new Date(start);\n end = new Date(end);\n\n if (start >= end) { throw new RangeException(\"The end date must be greater than the start date.\"); }\n\n return new SmartIterator<Date>(function* ()\n {\n const endTime = end.getTime();\n\n let unixTime: number = start.getTime();\n while (unixTime < endTime)\n {\n yield new Date(unixTime);\n\n unixTime += step;\n }\n });\n}\n\n/**\n * An utility function that rounds a date to the nearest time unit. \n * The rounding can be expressed in different time units.\n *\n * ---\n *\n * @example\n * ```ts\n * const date = new Date(\"2025-01-01T12:34:56.789Z\");\n *\n * dateRound(date, TimeUnit.Hour); // 2025-01-01T12:00:00.000Z\n * ```\n *\n * ---\n *\n * @param date The date to round.\n * @param unit\n * The time unit to express the rounding. `TimeUnit.Day` by default.\n *\n * Must be greater than a millisecond and less than or equal to a day. \n * Otherwise, a {@link RangeException} will be thrown.\n *\n * @returns The rounded date.\n */\nexport function dateRound(date: number | string | Date, unit = TimeUnit.Day): Date\n{\n if (unit <= TimeUnit.Millisecond)\n {\n throw new RangeException(\n \"Rounding a timestamp by milliseconds or less makes no sense.\" +\n \"Use the timestamp value directly instead.\"\n );\n }\n if (unit > TimeUnit.Day)\n {\n throw new RangeException(\n \"Rounding by more than a day leads to unexpected results. \" +\n \"Consider using other methods to round dates by weeks, months or years.\"\n );\n }\n\n date = new Date(date);\n return new Date(Math.floor(date.getTime() / unit) * unit);\n}\n\n/**\n * An utility function that gets the week of a date. \n * The first day of the week can be optionally specified.\n *\n * ---\n *\n * @example\n * ```ts\n * const date = new Date(\"2025-01-01\");\n *\n * getWeek(date, WeekDay.Monday); // 2024-12-30\n * ```\n *\n * ---\n *\n * @param date The date to get the week of.\n * @param firstDay The first day of the week. `WeekDay.Sunday` by default.\n *\n * @returns The first day of the week of the specified date.\n */\nexport function getWeek(date: number | string | Date, firstDay = WeekDay.Sunday): Date\n{\n date = new Date(date);\n\n const startCorrector = 7 - firstDay;\n const weekDayIndex = (date.getUTCDay() + startCorrector) % 7;\n const firstDayTime = date.getTime() - (TimeUnit.Day * weekDayIndex);\n\n return dateRound(new Date(firstDayTime));\n}\n","import type { Interval } from \"../../core/types.js\";\nimport { isBrowser } from \"../../helpers.js\";\n\nimport Publisher from \"../callbacks/publisher.js\";\nimport { FatalErrorException, RuntimeException } from \"../exceptions/index.js\";\nimport type { Callback } from \"../types.js\";\n\ninterface GameLoopEventMap\n{\n start: () => void;\n stop: () => void;\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [key: string]: Callback<any[], any>;\n}\n\n/**\n * A class representing a {@link https://en.wikipedia.org/wiki/Video_game_programming#Game_structure|game loop} pattern\n * that allows to run a function at a specific frame rate.\n *\n * In a browser environment, it uses the native {@link requestAnimationFrame}\n * function to run the callback at the refresh rate of the screen. \n * In a non-browser environment, however, it uses the {@link setInterval}\n * function to run the callback at the specified fixed interval of time.\n *\n * Every time the callback is executed, it receives the\n * elapsed time since the start of the game loop. \n * It's also possible to subscribe to the `start` & `stop` events to receive notifications when they occur.\n *\n * ---\n *\n * @example\n * ```ts\n * const loop = new GameLoop((elapsedTime: number) =>\n * {\n * console.log(`The game loop has been running for ${elapsedTime}ms.`);\n * });\n *\n * loop.onStart(() => { console.log(\"The game loop has started.\"); });\n * loop.onStop(() => { console.log(\"The game loop has stopped.\"); });\n *\n * loop.start();\n * ```\n */\nexport default class GameLoop\n{\n /**\n * The handle of the interval or the animation frame, depending on the environment. \n * It's used to stop the game loop when the {@link GameLoop._stop} method is called.\n */\n protected _handle?: number | Interval;\n\n /**\n * The time when the game loop has started. \n * In addition to indicating the {@link https://en.wikipedia.org/wiki/Unix_time|Unix timestamp}\n * of the start of the game loop, it's also used to calculate the elapsed time.\n *\n * This protected property is the only one that can be modified directly by the derived classes. \n * If you're looking for the public and readonly property, use the {@link GameLoop.startTime} getter instead.\n */\n protected _startTime: number;\n\n /**\n * The time when the game loop has started. \n * In addition to indicating the {@link https://en.wikipedia.org/wiki/Unix_time|Unix timestamp}\n * of the start of the game loop, it's also used to calculate the elapsed time.\n */\n public get startTime(): number\n {\n return this._startTime;\n }\n\n /**\n * A flag indicating whether the game loop is currently running or not.\n *\n * This protected property is the only one that can be modified directly by the derived classes. \n * If you're looking for the public and readonly property, use the {@link GameLoop.isRunning} getter instead.\n */\n protected _isRunning: boolean;\n\n /**\n * A flag indicating whether the game loop is currently running or not.\n */\n public get isRunning(): boolean\n {\n return this._isRunning;\n }\n\n /**\n * The elapsed time since the start of the game loop. \n * It's calculated as the difference between the current time and the {@link GameLoop.startTime}.\n */\n public get elapsedTime(): number\n {\n return performance.now() - this._startTime;\n }\n\n /**\n * The {@link Publisher} object that will be used to publish the events of the game loop.\n */\n protected _publisher: Publisher<GameLoopEventMap>;\n\n /**\n * The internal method actually responsible for starting the game loop.\n *\n * Depending on the current environment, it could use the\n * {@link requestAnimationFrame} or the {@link setInterval} function.\n */\n protected _start: () => void;\n\n /**\n * The internal method actually responsible for stopping the game loop.\n *\n * Depending on the current environment, it could use the\n * {@link cancelAnimationFrame} or the {@link clearInterval} function.\n */\n protected _stop: () => void;\n\n /**\n * Initializes a new instance of the {@link GameLoop} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const loop = new GameLoop((elapsedTime: number) => { [...] });\n * ```\n *\n * ---\n *\n * @param callback The function that will be executed at each iteration of the game loop.\n * @param msIfNotBrowser\n * The interval in milliseconds that will be used if the current environment isn't a browser. Default is `40`.\n */\n public constructor(callback: FrameRequestCallback, msIfNotBrowser = 40)\n {\n this._startTime = 0;\n this._isRunning = false;\n\n if (isBrowser)\n {\n this._start = () =>\n {\n callback(this.elapsedTime);\n\n this._handle = window.requestAnimationFrame(this._start);\n };\n\n this._stop = () => window.cancelAnimationFrame(this._handle as number);\n }\n else\n {\n // eslint-disable-next-line no-console\n console.warn(\n \"Not a browser environment detected. \" +\n `Using setInterval@${msIfNotBrowser}ms instead of requestAnimationFrame...`\n );\n\n this._start = () =>\n {\n this._handle = setInterval(() => callback(this.elapsedTime), msIfNotBrowser);\n };\n\n this._stop = () => clearInterval(this._handle as Interval);\n }\n\n this._publisher = new Publisher();\n }\n\n /**\n * Starts the execution of the game loop.\n *\n * If the game loop is already running, a {@link RuntimeException} will be thrown.\n *\n * ---\n *\n * @example\n * ```ts\n * loop.onStart(() => { [...] }); // This callback will be executed.\n * loop.start();\n * ```\n *\n * ---\n *\n * @param elapsedTime The elapsed time to set as default when the game loop starts. Default is `0`.\n */\n public start(elapsedTime = 0): void\n {\n if (this._isRunning) { throw new RuntimeException(\"The game loop has already been started.\"); }\n\n this._startTime = performance.now() - elapsedTime;\n this._start();\n this._isRunning = true;\n\n this._publisher.publish(\"start\");\n }\n\n /**\n * Stops the execution of the game loop.\n *\n * If the game loop hasn't yet started, a {@link RuntimeException} will be thrown.\n *\n * ---\n *\n * @example\n * ```ts\n * loop.onStop(() => { [...] }); // This callback will be executed.\n * loop.stop();\n * ```\n */\n public stop(): void\n {\n if (!(this._isRunning))\n {\n throw new RuntimeException(\"The game loop had already stopped or hadn't yet started.\");\n }\n if (!(this._handle)) { throw new FatalErrorException(); }\n\n this._stop();\n this._handle = undefined;\n this._isRunning = false;\n\n this._publisher.publish(\"stop\");\n }\n\n /**\n * Subscribes to the `start` event of the game loop.\n *\n * ---\n *\n * @example\n * ```ts\n * loop.onStart(() => { console.log(\"The game loop has started.\"); });\n * ```\n *\n * ---\n *\n * @param callback The function that will be executed when the game loop starts.\n *\n * @returns A function that can be used to unsubscribe from the event.\n */\n public onStart(callback: () => void): () => void\n {\n return this._publisher.subscribe(\"start\", callback);\n }\n\n /**\n * Subscribes to the `stop` event of the game loop.\n *\n * ---\n *\n * @example\n * ```ts\n * loop.onStop(() => { console.log(\"The game loop has stopped.\"); });\n * ```\n *\n * ---\n *\n * @param callback The function that will be executed when the game loop stops.\n *\n * @returns A function that can be used to unsubscribe from the event.\n */\n public onStop(callback: () => void): () => void\n {\n return this._publisher.subscribe(\"stop\", callback);\n }\n\n public readonly [Symbol.toStringTag]: string = \"GameLoop\";\n}\n","import { TimeUnit } from \"../../utils/date.js\";\n\nimport Publisher from \"../callbacks/publisher.js\";\nimport { FatalErrorException, RangeException, RuntimeException } from \"../exceptions/index.js\";\nimport type { Callback } from \"../types.js\";\n\nimport GameLoop from \"./game-loop.js\";\n\ninterface ClockEventMap\n{\n start: () => void;\n stop: () => void;\n tick: (elapsedTime: number) => void;\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [key: string]: Callback<any[], any>;\n}\n\n/**\n * A class representing a clock.\n *\n * It can be started, stopped and, when running, it ticks at a specific frame rate. \n * It's possible to subscribe to these events to receive notifications when they occur.\n *\n * ---\n *\n * @example\n * ```ts\n * const clock = new Clock();\n *\n * clock.onStart(() => { console.log(\"The clock has started.\"); });\n * clock.onTick((elapsedTime) => { console.log(`The clock has ticked at ${elapsedTime}ms.`); });\n * clock.onStop(() => { console.log(\"The clock has stopped.\"); });\n *\n * clock.start();\n * ```\n */\nexport default class Clock extends GameLoop\n{\n /**\n * The {@link Publisher} object that will be used to publish the events of the clock.\n */\n protected override _publisher: Publisher<ClockEventMap>;\n\n /**\n * Initializes a new instance of the {@link Clock} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const clock = new Clock();\n * ```\n *\n * ---\n *\n * @param msIfNotBrowser\n * The interval in milliseconds at which the clock will tick if the environment is not a browser. \n * `TimeUnit.Second` by default.\n */\n public constructor(msIfNotBrowser: number = TimeUnit.Second)\n {\n super((elapsedTime) => this._publisher.publish(\"tick\", elapsedTime), msIfNotBrowser);\n\n this._publisher = new Publisher();\n }\n\n /**\n * Starts the execution of the clock.\n *\n * If the clock is already running, a {@link RuntimeException} will be thrown.\n *\n * ---\n *\n * @example\n * ```ts\n * clock.onStart(() => { [...] }); // This callback will be executed.\n * clock.start();\n * ```\n *\n * ---\n *\n * @param elapsedTime The elapsed time to set as default when the clock starts. Default is `0`.\n */\n public override start(elapsedTime = 0): void\n {\n if (this._isRunning) { throw new RuntimeException(\"The clock has already been started.\"); }\n\n this._startTime = performance.now() - elapsedTime;\n this._start();\n this._isRunning = true;\n\n this._publisher.publish(\"start\");\n }\n\n /**\n * Stops the execution of the clock.\n *\n * If the clock hasn't yet started, a {@link RuntimeException} will be thrown.\n *\n * ---\n *\n * @example\n * ```ts\n * clock.onStop(() => { [...] }); // This callback will be executed.\n * clock.stop();\n * ```\n */\n public override stop(): void\n {\n if (!(this._isRunning)) { throw new RuntimeException(\"The clock had already stopped or hadn't yet started.\"); }\n if (!(this._handle)) { throw new FatalErrorException(); }\n\n this._stop();\n this._handle = undefined;\n this._isRunning = false;\n\n this._publisher.publish(\"stop\");\n }\n\n /**\n * Subscribes to the `tick` event of the clock.\n *\n * ---\n *\n * @example\n * ```ts\n * clock.onTick((elapsedTime) => { [...] }); // This callback will be executed.\n * clock.start();\n * ```\n *\n * ---\n *\n * @param callback The callback that will be executed when the clock ticks.\n * @param tickStep\n * The minimum time in milliseconds that must pass from the previous execution of the callback to the next one.\n *\n * - If it's a positive number, the callback will be executed only if the\n * time passed from the previous execution is greater than this number.\n * - If it's `0`, the callback will be executed every tick without even checking for the time.\n * - If it's a negative number, a {@link RangeException} will be thrown.\n *\n * @returns A function that can be used to unsubscribe from the event.\n */\n public onTick(callback: (elapsedTime: number) => void, tickStep = 0): () => void\n {\n if (tickStep < 0) { throw new RangeException(\"The tick step must be a non-negative number.\"); }\n if (tickStep === 0) { return this._publisher.subscribe(\"tick\", callback); }\n\n let lastTick = 0;\n\n return this._publisher.subscribe(\"tick\", (elapsedTime: number) =>\n {\n if ((elapsedTime - lastTick) < tickStep) { return; }\n\n callback(elapsedTime);\n lastTick = elapsedTime;\n });\n }\n\n public override readonly [Symbol.toStringTag]: string = \"Clock\";\n}\n","import { TimeUnit } from \"../../utils/date.js\";\n\nimport Publisher from \"../callbacks/publisher.js\";\nimport { FatalErrorException, RangeException, RuntimeException } from \"../exceptions/index.js\";\nimport { DeferredPromise, SmartPromise } from \"../promises/index.js\";\nimport type { Callback } from \"../types.js\";\n\nimport GameLoop from \"./game-loop.js\";\n\ninterface CountdownEventMap\n{\n start: () => void;\n stop: (reason: unknown) => void;\n tick: (remainingTime: number) => void;\n expire: () => void;\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [key: string]: Callback<any[], any>;\n}\n\n/**\n * A class representing a countdown.\n *\n * It can be started, stopped, when running it ticks at a specific frame rate and it expires when the time's up. \n * It's possible to subscribe to these events to receive notifications when they occur.\n *\n * ---\n *\n * @example\n * ```ts\n * const countdown = new Countdown(10_000);\n *\n * countdown.onStart(() => { console.log(\"The countdown has started.\"); });\n * countdown.onTick((remainingTime) => { console.log(`The countdown has ${remainingTime}ms remaining.`); });\n * countdown.onStop((reason) => { console.log(`The countdown has stopped because of ${reason}.`); });\n * countdown.onExpire(() => { console.log(\"The countdown has expired.\"); });\n *\n * countdown.start();\n * ```\n */\nexport default class Countdown extends GameLoop\n{\n /**\n * The {@link Publisher} object that will be used to publish the events of the countdown.\n */\n protected override _publisher: Publisher<CountdownEventMap>;\n\n /**\n * The total duration of the countdown in milliseconds.\n *\n * This protected property is the only one that can be modified directly by the derived classes. \n * If you're looking for the public and readonly property, use the {@link Countdown.duration} getter instead.\n */\n protected _duration: number;\n\n /**\n * The total duration of the countdown in milliseconds.\n */\n public get duration(): number\n {\n return this._duration;\n }\n\n /**\n * The remaining time of the countdown in milliseconds. \n * It's calculated as the difference between the total duration and the elapsed time.\n */\n public get remainingTime(): number\n {\n return this._duration - this.elapsedTime;\n }\n\n /**\n * The {@link DeferredPromise} that will be resolved or rejected when the countdown expires or stops.\n */\n protected _deferrer?: DeferredPromise<void>;\n\n /**\n * Initializes a new instance of the {@link Countdown} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const countdown = new Countdown(10_000);\n * ```\n *\n * ---\n *\n * @param duration\n * The total duration of the countdown in milliseconds.\n *\n * @param msIfNotBrowser\n * The interval in milliseconds at which the countdown will tick if the environment is not a browser. \n * `TimeUnit.Second` by default.\n */\n public constructor(duration: number, msIfNotBrowser: number = TimeUnit.Second)\n {\n const callback = () =>\n {\n const remainingTime = this.remainingTime;\n if (remainingTime <= 0)\n {\n this._deferrerStop();\n\n this._publisher.publish(\"tick\", 0);\n this._publisher.publish(\"expire\");\n }\n else\n {\n this._publisher.publish(\"tick\", remainingTime);\n }\n };\n\n super(callback, msIfNotBrowser);\n\n this._publisher = new Publisher();\n this._duration = duration;\n }\n\n /**\n * The internal method actually responsible for stopping the\n * countdown and resolving or rejecting the {@link Countdown._deferrer} promise.\n *\n * ---\n *\n * @param reason\n * The reason why the countdown has stopped.\n *\n * - If it's `undefined`, the promise will be resolved.\n * - If it's a value, the promise will be rejected with that value.\n */\n protected _deferrerStop(reason?: unknown): void\n {\n if (!(this._isRunning)) { throw new RuntimeException(\"The countdown hadn't yet started.\"); }\n if (!(this._deferrer)) { throw new FatalErrorException(); }\n\n this._stop();\n this._handle = undefined;\n this._isRunning = false;\n\n if (reason !== undefined) { this._deferrer.reject(reason); }\n else { this._deferrer.resolve(); }\n\n this._deferrer = undefined;\n }\n\n /**\n * Starts the execution of the countdown.\n *\n * If the countdown is already running, a {@link RuntimeException} will be thrown.\n *\n * ---\n *\n * @example\n * ```ts\n * countdown.onStart(() => { [...] }); // This callback will be executed.\n * countdown.start();\n * ```\n *\n * ---\n *\n * @param remainingTime\n * The remaining time to set as default when the countdown starts. \n * Default is the {@link Countdown.duration} itself.\n *\n * @returns A {@link SmartPromise} that will be resolved or rejected when the countdown expires or stops.\n */\n public override start(remainingTime: number = this.duration): SmartPromise<void>\n {\n if (this._isRunning) { throw new RuntimeException(\"The countdown had already stopped or hadn't yet started.\"); }\n if (this._deferrer) { throw new FatalErrorException(); }\n\n this._deferrer = new DeferredPromise();\n super.start(this.duration - remainingTime);\n\n this._publisher.publish(\"start\");\n\n return this._deferrer;\n }\n\n /**\n * Stops the execution of the countdown.\n *\n * If the countdown hasn't yet started, a {@link RuntimeException} will be thrown.\n *\n * ---\n *\n * @example\n * ```ts\n * countdown.onStop(() => { [...] }); // This callback will be executed.\n * countdown.stop();\n * ```\n *\n * ---\n *\n * @param reason\n * The reason why the countdown has stopped.\n *\n * - If it's `undefined`, the promise will be resolved.\n * - If it's a value, the promise will be rejected with that value.\n */\n public override stop(reason?: unknown): void\n {\n // TODO: Once solved Issues #6 & #10, make the `reason` parameter required.\n // - https://github.com/Byloth/core/issues/6\n // - https://github.com/Byloth/core/issues/10\n //\n this._deferrerStop(reason);\n\n this._publisher.publish(\"stop\", reason);\n }\n\n /**\n * Subscribes to the `expire` event of the countdown.\n *\n * ---\n *\n * @example\n * ```ts\n * countdown.onExpire(() => { [...] }); // This callback will be executed once the countdown has expired.\n * countdown.start();\n * ```\n *\n * ---\n *\n * @param callback The callback that will be executed when the countdown expires.\n *\n * @returns A function that can be used to unsubscribe from the event.\n */\n public onExpire(callback: () => void): () => void\n {\n return this._publisher.subscribe(\"expire\", callback);\n }\n\n /**\n * Subscribes to the `tick` event of the countdown.\n *\n * ---\n *\n * @example\n * ```ts\n * countdown.onTick((remainingTime) => { [...] }); // This callback will be executed.\n * countdown.start();\n * ```\n *\n * ---\n *\n * @param callback The callback that will be executed when the countdown ticks.\n * @param tickStep\n * The minimum time in milliseconds that must pass from the previous execution of the callback to the next one.\n *\n * - If it's a positive number, the callback will be executed only if the\n * time passed from the previous execution is greater than this number.\n * - If it's `0`, the callback will be executed every tick without even checking for the time.\n * - If it's a negative number, a {@link RangeException} will be thrown.\n *\n * @returns A function that can be used to unsubscribe from the event.\n */\n public onTick(callback: (remainingTime: number) => void, tickStep = 0): () => void\n {\n if (tickStep < 0) { throw new RangeException(\"The tick step must be a non-negative number.\"); }\n if (tickStep === 0) { return this._publisher.subscribe(\"tick\", callback); }\n\n let lastTick = this.remainingTime;\n\n return this._publisher.subscribe(\"tick\", (remainingTime: number) =>\n {\n if ((lastTick - remainingTime) < tickStep) { return; }\n\n callback(remainingTime);\n lastTick = remainingTime;\n });\n }\n\n public override readonly [Symbol.toStringTag]: string = \"Countdown\";\n}\n","import { SmartIterator, ValueException } from \"../models/index.js\";\n\n/**\n * An utility class that provides a set of methods to generate sequences of numbers following specific curves. \n * It can be used to generate sequences of values that can be\n * used in animations, transitions and other different scenarios.\n *\n * It cannot be instantiated directly.\n */\nexport default class Curve\n{\n /**\n * Generates a given number of values following a linear curve. \n * The values are equally spaced and normalized between 0 and 1.\n *\n * ---\n *\n * @example\n * ```ts\n * for (const value of Curve.Linear(5))\n * {\n * console.log(value); // 0, 0.25, 0.5, 0.75, 1\n * }\n * ```\n *\n * ---\n *\n * @param values The number of values to generate.\n *\n * @returns A {@link SmartIterator} object that generates the values following a linear curve.\n */\n public static Linear(values: number): SmartIterator<number>\n {\n const steps = (values - 1);\n\n return new SmartIterator<number>(function* ()\n {\n for (let index = 0; index < values; index += 1) { yield index / steps; }\n });\n }\n\n /**\n * Generates a given number of values following an exponential curve. \n * The values are equally spaced and normalized between 0 and 1.\n *\n * ---\n *\n * @example\n * ```ts\n * for (const value of Curve.Exponential(6))\n * {\n * console.log(value); // 0, 0.04, 0.16, 0.36, 0.64, 1\n * }\n * ```\n *\n * ---\n *\n * @param values The number of values to generate.\n * @param base\n * The base of the exponential curve. Default is `2`.\n *\n * Also note that:\n * - If it's equal to `1`, the curve will be linear.\n * - If it's included between `0` and `1`, the curve will be logarithmic.\n *\n * The base cannot be negative. If so, a {@link ValueException} will be thrown.\n *\n * @returns A {@link SmartIterator} object that generates the values following an exponential curve.\n */\n public static Exponential(values: number, base = 2): SmartIterator<number>\n {\n if (base < 0) { throw new ValueException(\"The base of the exponential curve cannot be negative.\"); }\n\n const steps = (values - 1);\n\n return new SmartIterator<number>(function* ()\n {\n for (let index = 0; index < values; index += 1) { yield Math.pow(index / steps, base); }\n });\n }\n\n private constructor() { /* ... */ }\n\n public readonly [Symbol.toStringTag]: string = \"Curve\";\n}\n","import { ValueException } from \"../models/index.js\";\n\n/**\n * A wrapper class around the native {@link Math.random} function that\n * provides a set of methods to generate random values more easily. \n * It can be used to generate random numbers, booleans and other different values.\n *\n * It cannot be instantiated directly.\n */\nexport default class Random\n{\n /**\n * Generates a random boolean value.\n *\n * ---\n *\n * @example\n * ```ts\n * if (Random.Boolean())\n * {\n * // Do something...\n * }\n * ```\n *\n * ---\n *\n * @param ratio\n * The probability of generating `true`.\n *\n * It must be included between `0` and `1`. Default is `0.5`.\n *\n * @returns A random boolean value.\n */\n public static Boolean(ratio = 0.5): boolean\n {\n return (Math.random() < ratio);\n }\n\n /**\n * Generates a random integer value between `0` (included) and `max` (excluded).\n *\n * ---\n *\n * @example\n * ```ts\n * Random.Integer(5); // 0, 1, 2, 3, 4\n * ```\n *\n * ---\n *\n * @param max The maximum value (excluded).\n *\n * @returns A random integer value.\n */\n public static Integer(max: number): number;\n\n /**\n * Generates a random integer value between `min` (included) and `max` (excluded).\n *\n * ---\n *\n * @example\n * ```ts\n * Random.Integer(2, 7); // 2, 3, 4, 5, 6\n * ```\n *\n * ---\n *\n * @param min The minimum value (included).\n * @param max The maximum value (excluded).\n *\n * @returns A random integer value.\n */\n public static Integer(min: number, max: number): number;\n public static Integer(min: number, max?: number): number\n {\n if (max === undefined) { return Math.floor(Math.random() * min); }\n\n return Math.floor(Math.random() * (max - min) + min);\n }\n\n /**\n * Generates a random decimal value between `0` (included) and `1` (excluded).\n *\n * ---\n *\n * @example\n * ```ts\n * Random.Decimal(); // 0.123456789\n * ```\n *\n * ---\n *\n * @returns A random decimal value.\n */\n public static Decimal(): number;\n\n /**\n * Generates a random decimal value between `0` (included) and `max` (excluded).\n *\n * ---\n *\n * @example\n * ```ts\n * Random.Decimal(5); // 2.3456789\n * ```\n *\n * ---\n *\n * @param max The maximum value (excluded).\n *\n * @returns A random decimal value.\n */\n public static Decimal(max: number): number;\n\n /**\n * Generates a random decimal value between `min` (included) and `max` (excluded).\n *\n * ---\n *\n * @example\n * ```ts\n * Random.Decimal(2, 7); // 4.56789\n * ```\n *\n * ---\n *\n * @param min The minimum value (included).\n * @param max The maximum value (excluded).\n *\n * @returns A random decimal value\n */\n public static Decimal(min: number, max: number): number;\n public static Decimal(min?: number, max?: number): number\n {\n if (min === undefined) { return Math.random(); }\n if (max === undefined) { return (Math.random() * min); }\n\n return (Math.random() * (max - min) + min);\n }\n\n /**\n * Picks a random valid index from a given array of elements.\n *\n * ---\n *\n * @template T The type of the elements in the array.\n *\n * @param elements\n * The array of elements to pick from.\n *\n * It must contain at least one element. Otherwise, a {@link ValueException} will be thrown.\n *\n * @returns A valid random index from the given array.\n */\n public static Index<T>(elements: readonly T[]): number\n {\n if (elements.length === 0) { throw new ValueException(\"You must provide at least one element.\"); }\n\n return this.Integer(elements.length);\n }\n\n /**\n * Picks a random element from a given array of elements.\n *\n * ---\n *\n * @template T The type of the elements in the array.\n *\n * @param elements\n * The array of elements to pick from.\n *\n * It must contain at least one element. Otherwise, a {@link ValueException} will be thrown.\n *\n * @returns A random element from the given array.\n */\n public static Choice<T>(elements: readonly T[]): T\n {\n return elements[Random.Index(elements)];\n }\n\n private constructor() { /* ... */ }\n\n public readonly [Symbol.toStringTag]: string = \"Random\";\n}\n","/**\n * Returns a promise that resolves after a certain number of milliseconds. \n * It can be used to pause or delay the execution of an asynchronous function.\n *\n * ---\n *\n * @example\n * ```ts\n * doSomething();\n * await delay(1_000);\n * doSomethingElse();\n * ```\n *\n * ---\n *\n * @param milliseconds The number of milliseconds to wait before resolving the promise.\n *\n * @returns A {@link Promise} that resolves after the specified number of milliseconds.\n */\nexport function delay(milliseconds: number): Promise<void>\n{\n return new Promise((resolve) => setTimeout(resolve, milliseconds));\n}\n\n/**\n * Returns a promise that resolves on the next animation frame. \n * It can be used to synchronize operations with the browser's rendering cycle.\n *\n * ---\n *\n * @example\n * ```ts\n * const $el = document.querySelector(\".element\");\n *\n * $el.classList.add(\"animate\");\n * await nextAnimationFrame();\n * $el.style.opacity = \"1\";\n * ```\n *\n * ---\n *\n * @returns A {@link Promise} that resolves on the next animation frame.\n */\nexport function nextAnimationFrame(): Promise<void>\n{\n return new Promise((resolve) => requestAnimationFrame(() => resolve()));\n}\n\n/**\n * Returns a promise that resolves on the next microtask. \n * It can be used to yield to the event loop in long-running operations to prevent blocking the main thread.\n *\n * ---\n *\n * @example\n * ```ts\n * for (let i = 0; i < 100_000_000; i += 1)\n * {\n * doSomething(i);\n *\n * if (i % 100 === 0) await yieldToEventLoop();\n * }\n * ```\n *\n * ---\n *\n * @returns A {@link Promise} that resolves on the next microtask.\n */\nexport function yieldToEventLoop(): Promise<void>\n{\n return new Promise((resolve) => setTimeout(resolve));\n}\n","/**\n * Appends a script element to the document body. \n * It can be used to load external scripts dynamically.\n *\n * ---\n *\n * @example\n * ```ts\n * await loadScript(\"https://analytics.service/script.js?id=0123456789\");\n * ```\n *\n * ---\n *\n * @param scriptUrl The URL of the script to load.\n * @param scriptType The type of the script to load. Default is `\"text/javascript\"`.\n *\n * @returns\n * A {@link Promise} that resolves when the script has been loaded successfully or rejects if an error occurs.\n */\nexport function loadScript(scriptUrl: string, scriptType = \"text/javascript\"): Promise<void>\n{\n return new Promise<void>((resolve, reject) =>\n {\n const script = document.createElement(\"script\");\n\n script.async = true;\n script.defer = true;\n script.src = scriptUrl;\n script.type = scriptType;\n\n script.onload = (evt) => resolve();\n script.onerror = (reason) => reject(reason);\n\n document.body.appendChild(script);\n });\n}\n","import { RangeException, SmartIterator } from \"../models/index.js\";\n\n/**\n * An utility function that chains multiple iterables into a single one.\n *\n * Since the iterator is lazy, the chaining process will be\n * executed only once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * for (const value of chain([1, 2, 3], [4, 5, 6], [7, 8, 9]))\n * {\n * console.log(value); // 1, 2, 3, 4, 5, 6, 7, 8, 9\n * }\n * ```\n *\n * ---\n *\n * @template T The type of elements in the iterables.\n *\n * @param iterables The list of iterables to chain.\n *\n * @returns A new {@link SmartIterator} object that chains the iterables into a single one.\n */\nexport function chain<T>(...iterables: readonly Iterable<T>[]): SmartIterator<T>\n{\n return new SmartIterator<T>(function* ()\n {\n for (const iterable of iterables)\n {\n for (const element of iterable) { yield element; }\n }\n });\n}\n\n/**\n * An utility function that counts the number of elements in an iterable.\n *\n * Also note that:\n * - If the iterable isn't an {@link Array}, it will be consumed entirely in the process.\n * - If the iterable is an infinite generator, the function will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * count([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); // 10\n * ```\n *\n * ---\n *\n * @template T The type of elements in the iterable.\n *\n * @param elements The iterable to count.\n *\n * @returns The number of elements in the iterable.\n */\nexport function count<T>(elements: Iterable<T>): number\n{\n if (elements instanceof Array) { return elements.length; }\n\n let _count = 0;\n for (const _ of elements) { _count += 1; }\n\n return _count;\n}\n\n/**\n * An utility function that enumerates the elements of an iterable. \n * Each element is paired with its index in a new iterator.\n *\n * Since the iterator is lazy, the enumeration process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * for (const [index, value] of enumerate([\"A\", \"M\", \"N\", \"Z\"]))\n * {\n * console.log(`${index}: ${value}`); // \"0: A\", \"1: M\", \"2: N\", \"3: Z\"\n * }\n * ```\n *\n * ---\n *\n * @template T The type of elements in the iterable.\n *\n * @param elements The iterable to enumerate.\n *\n * @returns A new {@link SmartIterator} object containing the enumerated elements.\n */\nexport function enumerate<T>(elements: Iterable<T>): SmartIterator<[number, T]>\n{\n return new SmartIterator<[number, T]>(function* ()\n {\n let index = 0;\n for (const element of elements)\n {\n yield [index, element];\n\n index += 1;\n }\n });\n}\n\n/**\n * An utility function that generates an iterator over a range of numbers. \n * The values are included between `0` (included) and `end` (excluded).\n *\n * The default step between the numbers is `1`.\n *\n * ---\n *\n * @example\n * ```ts\n * for (const number of range(5))\n * {\n * console.log(number); // 0, 1, 2, 3, 4\n * }\n * ```\n *\n * ---\n *\n * @param end\n * The end value (excluded).\n *\n * If the `end` value is negative, the step will be `-1` leading to generate the numbers in reverse order.\n *\n * @returns A {@link SmartIterator} object that generates the numbers in the range.\n */\nexport function range(end: number): SmartIterator<number>;\n\n/**\n * An utility function that generates an iterator over a range of numbers. \n * The values are included between `start` (included) and `end` (excluded).\n *\n * The step between the numbers can be specified with a custom value. Default is `1`.\n *\n * ---\n *\n * @example\n * ```ts\n * for (const number of range(2, 7))\n * {\n * console.log(number); // 2, 3, 4, 5, 6\n * }\n * ```\n *\n * ---\n *\n * @param start\n * The start value (included).\n *\n * If the `start` value is greater than the `end` value, the iterator will generate the numbers in reverse order.\n *\n * @param end\n * The end value (excluded).\n *\n * If the `end` value is less than the `start` value, the iterator will generate the numbers in reverse order.\n *\n * @param step\n * The step between the numbers. Default is `1`.\n *\n * Must be a positive number. Otherwise, a {@link RangeError} will be thrown.\n *\n * @returns A {@link SmartIterator} object that generates the numbers in the range.\n */\nexport function range(start: number, end: number, step?: number): SmartIterator<number>;\nexport function range(start: number, end?: number, step = 1): SmartIterator<number>\n{\n if (step <= 0)\n {\n throw new RangeException(\n \"Step must be always a positive number, even when generating numbers in reverse order.\"\n );\n }\n\n if (end === undefined)\n {\n end = start;\n start = 0;\n }\n\n if (start > end)\n {\n return new SmartIterator<number>(function* ()\n {\n for (let index = start; index > end; index -= step) { yield index; }\n });\n }\n\n return new SmartIterator<number>(function* ()\n {\n for (let index = start; index < end; index += step) { yield index; }\n });\n}\n\n/**\n * An utility function shuffles the elements of a given iterable.\n *\n * The function uses the {@link https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle|Fisher-Yates}\n * algorithm to shuffle the elements.\n *\n * Also note that:\n * - If the iterable is an {@link Array}, it won't be modified since the shuffling isn't done in-place.\n * - If the iterable isn't an {@link Array}, it will be consumed entirely in the process.\n * - If the iterable is an infinite generator, the function will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * shuffle([1, 2, 3, 4, 5]); // [3, 1, 5, 2, 4]\n * ```\n *\n * ---\n *\n * @template T The type of elements in the iterable.\n *\n * @param iterable The iterable to shuffle.\n *\n * @returns A new `Array` containing the shuffled elements of the given iterable.\n */\nexport function shuffle<T>(iterable: Iterable<T>): T[]\n{\n const array = Array.from(iterable);\n\n for (let index = array.length - 1; index > 0; index -= 1)\n {\n const jndex = Math.floor(Math.random() * (index + 1));\n\n [array[index], array[jndex]] = [array[jndex], array[index]];\n }\n\n return array;\n}\n\n/**\n * An utility function that filters the elements of an iterable ensuring that they are all unique.\n *\n * ---\n *\n * @example\n * ```ts\n * for (const value of unique([1, 1, 2, 3, 2, 3, 4, 5, 5, 4]))\n * {\n * console.log(value); // 1, 2, 3, 4, 5\n * }\n * ```\n *\n * ---\n *\n * @template T The type of elements in the iterable.\n *\n * @param elements The iterable to filter.\n *\n * @returns A {@link SmartIterator} object that iterates over the unique elements of the given iterable.\n */\nexport function unique<T>(elements: Iterable<T>): SmartIterator<T>\n{\n return new SmartIterator<T>(function* ()\n {\n const values = new Set<T>();\n for (const element of elements)\n {\n if (values.has(element)) { continue; }\n\n values.add(element);\n\n yield element;\n }\n });\n}\n\n/**\n * An utility function that zips two iterables into a single one. \n * The resulting iterable will contain the elements of the two iterables paired together.\n *\n * The function will stop when one of the two iterables is exhausted.\n *\n * ---\n *\n * @example\n * ```ts\n * for (const [number, char] of zip([1, 2, 3, 4], [\"A\", \"M\", \"N\" \"Z\"]))\n * {\n * console.log(`${number} - ${char}`); // \"1 - A\", \"2 - M\", \"3 - N\", \"4 - Z\"\n * }\n * ```\n *\n * ---\n *\n * @template T The type of elements in the first iterable.\n * @template U The type of elements in the second iterable.\n *\n * @param first The first iterable to zip.\n * @param second The second iterable to zip.\n *\n * @returns A {@link SmartIterator} object that iterates over the zipped elements of the two given iterables.\n */\nexport function zip<T, U>(first: Iterable<T>, second: Iterable<U>): SmartIterator<[T, U]>\n{\n const firstIterator = first[Symbol.iterator]();\n const secondIterator = second[Symbol.iterator]();\n\n return new SmartIterator<[T, U]>(function* ()\n {\n while (true)\n {\n const firstResult = firstIterator.next();\n const secondResult = secondIterator.next();\n\n if ((firstResult.done) || (secondResult.done)) { break; }\n\n yield [firstResult.value, secondResult.value];\n }\n });\n}\n","import { ValueException } from \"../models/exceptions/index.js\";\nimport { zip } from \"./iterator.js\";\n\n/**\n * Computes the average of a given list of values. \n * The values can be weighted using an additional list of weights.\n *\n * ---\n *\n * @example\n * ```ts\n * average([1, 2, 3, 4, 5]); // 3\n * average([6, 8.5, 4], [3, 2, 1]); // 6.5\n * ```\n *\n * ---\n *\n * @template T The type of the values in the list. It must be or extend a `number` object.\n *\n * @param values\n * The list of values to compute the average.\n *\n * It must contain at least one element. Otherwise, a {@link ValueException} will be thrown.\n *\n * @param weights\n * The list of weights to apply to the values. \n * It should contain the same number of elements as the values list or\n * the smaller number of elements between the two lists will be considered.\n *\n * The sum of the weights must be greater than zero. Otherwise, a {@link ValueException} will be thrown.\n *\n * @returns The average of the specified values.\n */\nexport function average<T extends number>(values: Iterable<T>, weights?: Iterable<number>): number\n{\n if (weights === undefined)\n {\n let _sum = 0;\n let _index = 0;\n\n for (const value of values)\n {\n _sum += value;\n _index += 1;\n }\n\n if (_index === 0) { throw new ValueException(\"You must provide at least one value.\"); }\n\n return _sum / _index;\n }\n\n let _sum = 0;\n let _count = 0;\n let _index = 0;\n\n for (const [value, weight] of zip(values, weights))\n {\n if (weight <= 0)\n {\n throw new ValueException(`The weight for the value #${_index} must be greater than zero.`);\n }\n\n _sum += value * weight;\n _count += weight;\n _index += 1;\n }\n\n if (_index === 0) { throw new ValueException(\"You must provide at least one value and weight.\"); }\n if (_count <= 0) { throw new ValueException(\"The sum of weights must be greater than zero.\"); }\n\n return _sum / _count;\n}\n\n/**\n * An utility function to compute the hash of a given string.\n *\n * The hash is computed using a simple variation of the\n * {@link http://www.cse.yorku.ca/~oz/hash.html#djb2|djb2} algorithm. \n * However, the hash is garanteed to be a 32-bit signed integer.\n *\n * ---\n *\n * @example\n * ```ts\n * hash(\"Hello, world!\"); // -1880044555\n * hash(\"How are you?\"); // 1761539132\n * ```\n *\n * ---\n *\n * @param value The string to hash.\n *\n * @returns The hash of the specified string.\n */\nexport function hash(value: string): number\n{\n let hashedValue = 0;\n for (let index = 0; index < value.length; index += 1)\n {\n const char = value.charCodeAt(index);\n\n hashedValue = ((hashedValue << 5) - hashedValue) + char;\n hashedValue |= 0;\n }\n\n return hashedValue;\n}\n\n/**\n * Sums all the values of a given list.\n *\n * ---\n *\n * @example\n * ```ts\n * sum([1, 2, 3, 4, 5]); // 15\n * ```\n *\n * ---\n *\n * @template T The type of the values in the list. It must be or extend a `number` object.\n *\n * @param values The list of values to sum.\n *\n * @returns The sum of the specified values.\n */\nexport function sum<T extends number>(values: Iterable<T>): number\n{\n let _sum = 0;\n for (const value of values) { _sum += value; }\n\n return _sum;\n}\n","/**\n * Capitalize the first letter of a string.\n *\n * ---\n *\n * @example\n * ```ts\n * capitalize('hello'); // 'Hello'\n * ```\n *\n * ---\n *\n * @param value The string to capitalize.\n *\n * @returns The capitalized string.\n */\nexport function capitalize(value: string): string\n{\n return `${value.charAt(0).toUpperCase()}${value.slice(1)}`;\n}\n","export const VERSION = \"2.1.2\";\n\nexport type { Constructor, Interval, Timeout, ValueOf } from \"./core/types.js\";\n\nexport { isBrowser, isNode, isWorker } from \"./helpers.js\";\n\nexport {\n AggregatedIterator,\n AggregatedAsyncIterator,\n CallableObject,\n Clock,\n Countdown,\n DeferredPromise,\n EnvironmentException,\n Exception,\n FatalErrorException,\n FileException,\n FileExistsException,\n FileNotFoundException,\n GameLoop,\n JSONStorage,\n KeyException,\n MapView,\n NotImplementedException,\n NetworkException,\n PermissionException,\n Publisher,\n RangeException,\n ReducedIterator,\n ReferenceException,\n RuntimeException,\n SetView,\n SmartIterator,\n SmartAsyncIterator,\n SmartPromise,\n SwitchableCallback,\n TimeoutException,\n TimedPromise,\n TypeException,\n ValueException\n\n} from \"./models/index.js\";\n\nexport type {\n AsyncGeneratorFunction,\n AsyncIteratee,\n AsyncIteratorLike,\n AsyncKeyedIteratee,\n AsyncKeyedReducer,\n AsyncReducer,\n Callback,\n CallbackMap,\n FulfilledHandler,\n GeneratorFunction,\n Iteratee,\n IteratorLike,\n JSONArray,\n JSONObject,\n JSONValue,\n KeyedIteratee,\n KeyedReducer,\n KeyedTypeGuardPredicate,\n MapViewEventsMap,\n MaybeAsyncKeyedIteratee,\n MaybeAsyncKeyedReducer,\n MaybeAsyncGeneratorFunction,\n MaybeAsyncIteratee,\n MaybeAsyncIteratorLike,\n MaybeAsyncReducer,\n MaybePromise,\n PromiseExecutor,\n PromiseRejecter,\n PromiseResolver,\n Publishable,\n ReadonlyMapView,\n ReadonlySetView,\n Reducer,\n RejectedHandler,\n SetViewEventsMap,\n Subscribable,\n TypeGuardPredicate\n\n} from \"./models/types.js\";\n\nexport {\n average,\n capitalize,\n chain,\n count,\n Curve,\n delay,\n dateDifference,\n dateRange,\n dateRound,\n TimeUnit,\n enumerate,\n getWeek,\n hash,\n loadScript,\n nextAnimationFrame,\n Random,\n range,\n shuffle,\n sum,\n unique,\n WeekDay,\n yieldToEventLoop,\n zip\n\n} from \"./utils/index.js\";\n"],"names":["isBrowser","isNode","_a","isWorker","_b","Exception","_d","_c","message","cause","name","__publicField","error","exc","FatalErrorException","_f","_e","NotImplementedException","_h","_g","FileException","_j","_i","FileExistsException","_l","_k","FileNotFoundException","_n","_m","KeyException","_p","_o","NetworkException","_r","_q","PermissionException","_t","_s","ReferenceException","_v","_u","RuntimeException","_x","_w","EnvironmentException","_z","_y","TimeoutException","_B","_A","TypeException","_D","_C","ValueException","_F","_E","RangeException","_H","_G","SmartIterator","argument","_I","predicate","index","result","iterator","iteratee","reducer","initialValue","accumulator","elements","value","count","limit","values","AggregatedIterator","element","_J","_ReducedIterator","key","_","ReducedIterator","_K","_AggregatedAsyncIterator","SmartAsyncIterator","indexes","finding","keys","counters","map","groups","AggregatedAsyncIterator","_L","generator","next","_value","_M","_AggregatedIterator","SmartFunction","CallableObject","_O","_N","self","_P","Publisher","event","args","subscribers","subscriber","Disabler","SwitchableCallback","_R","_Q","callback","MapView","_T","_S","iterable","size","SetView","_V","_U","_W","JSONStorage","preferPersistence","storage","defaultValue","newValue","encodedValue","persistent","_X","_SmartPromise","executor","_onFulfilled","_onRejected","reason","promise","resolve","reject","onFulfilled","onRejected","onFinally","SmartPromise","DeferredPromise","_Z","_Y","_resolve","_reject","otherPromise","TimedPromise","_$","__","timeout","_timeoutId","TimeUnit","WeekDay","dateDifference","start","end","unit","_round","dateRange","step","endTime","unixTime","dateRound","date","getWeek","firstDay","startCorrector","weekDayIndex","firstDayTime","_aa","GameLoop","msIfNotBrowser","elapsedTime","Clock","_ca","_ba","tickStep","lastTick","Countdown","_ea","_da","duration","remainingTime","_fa","Curve","steps","base","_ga","_Random","ratio","min","max","Random","delay","milliseconds","nextAnimationFrame","yieldToEventLoop","loadScript","scriptUrl","scriptType","script","evt","chain","iterables","_count","enumerate","range","shuffle","array","jndex","unique","zip","first","second","firstIterator","secondIterator","firstResult","secondResult","average","weights","_sum","_index","weight","hash","hashedValue","char","sum","capitalize","VERSION"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"core.global.js","sources":["../src/helpers.ts","../src/models/exceptions/core.ts","../src/models/exceptions/index.ts","../src/models/iterators/smart-iterator.ts","../src/models/aggregators/reduced-iterator.ts","../src/models/aggregators/aggregated-async-iterator.ts","../src/models/iterators/smart-async-iterator.ts","../src/models/aggregators/aggregated-iterator.ts","../src/models/callbacks/callable-object.ts","../src/models/callbacks/publisher.ts","../src/models/callbacks/switchable-callback.ts","../src/models/collections/map-view.ts","../src/models/collections/set-view.ts","../src/models/json/json-storage.ts","../src/models/promises/smart-promise.ts","../src/models/promises/deferred-promise.ts","../src/models/promises/timed-promise.ts","../src/utils/date.ts","../src/models/timers/game-loop.ts","../src/models/timers/clock.ts","../src/models/timers/countdown.ts","../src/utils/curve.ts","../src/utils/random.ts","../src/utils/async.ts","../src/utils/dom.ts","../src/utils/iterator.ts","../src/utils/math.ts","../src/utils/string.ts","../src/index.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/ban-ts-comment */\n\n/**\n * An utility constant that indicates whether the current environment is a browser.\n */\n// @ts-ignore\nexport const isBrowser = ((typeof window !== \"undefined\") && (typeof window.document !== \"undefined\"));\n\n/**\n * An utility constant that indicates whether the current environment is a Node.js runtime.\n */\n// @ts-ignore\nexport const isNode = ((typeof process !== \"undefined\") && !!(process.versions?.node));\n\n/**\n * An utility constant that indicates whether the current environment is a Web Worker.\n */\n// @ts-ignore\nexport const isWorker = ((typeof self === \"object\") && (self.constructor?.name === \"DedicatedWorkerGlobalScope\"));\n","/**\n * A class representing an exception, subclass of the native {@link Error} class. \n * It's the base class for any other further exception.\n *\n * It allows to chain exceptions together, tracking the initial cause of an error and\n * storing its stack trace while providing a clear and friendly message to the user.\n *\n * ---\n *\n * @example\n * ```ts\n * try { loadGameSaves(); }\n * catch (error)\n * {\n * throw new Exception(\"The game saves may be corrupted. Try to restart the game.\", error);\n * // Uncaught Exception: The game saves may be corrupted. Try to restart the game.\n * // at /src/game/index.ts:37:15\n * // at /src/main.ts:23:17\n * //\n * // Caused by SyntaxError: Unexpected end of JSON input\n * // at /src/models/saves.ts:47:17\n * // at /src/game/index.ts:12:9\n * // at /src/main.ts:23:17\n * }\n * ```\n */\nexport default class Exception extends Error\n{\n /**\n * A static method to convert a generic caught error, ensuring it's an instance of the {@link Exception} class.\n *\n * ---\n *\n * @example\n * ```ts\n * try { [...] }\n * catch (error)\n * {\n * const exc = Exception.FromUnknown(error);\n *\n * [...]\n * }\n * ```\n *\n * ---\n *\n * @param error The caught error to convert.\n *\n * @returns An instance of the {@link Exception} class.\n */\n public static FromUnknown(error: unknown): Exception\n {\n if (error instanceof Exception)\n {\n return error;\n }\n if (error instanceof Error)\n {\n const exc = new Exception(error.message);\n\n exc.stack = error.stack;\n exc.name = error.name;\n\n return exc;\n }\n\n return new Exception(`${error}`);\n }\n\n /**\n * Initializes a new instance of the {@link Exception} class.\n *\n * ---\n *\n * @example\n * ```ts\n * throw new Exception(\"An error occurred while processing the request.\");\n * ```\n *\n * ---\n *\n * @param message The message that describes the error.\n * @param cause The previous caught error that caused this one, if any.\n * @param name The name of the exception. Default is `\"Exception\"`.\n */\n public constructor(message: string, cause?: unknown, name = \"Exception\")\n {\n super(message);\n\n this.cause = cause;\n this.name = name;\n\n if (cause)\n {\n if (cause instanceof Error)\n {\n this.stack += `\\n\\nCaused by ${cause.stack}`;\n }\n else\n {\n this.stack += `\\n\\nCaused by ${cause}`;\n }\n }\n }\n\n public readonly [Symbol.toStringTag]: string = \"Exception\";\n}\n\n/**\n * An utility class representing that kind of situation where the program should never reach. \n * Also commonly used to satisfy the type-system, but not part of a real feasible scenario.\n *\n * It provides a clear and friendly message by default.\n *\n * ---\n *\n * @example\n * ```ts\n * function checkCase(value: \"A\" | \"B\" | \"C\"): 1 | 2 | 3\n * {\n * switch (value)\n * {\n * case \"A\": return 1;\n * case \"B\": return 2;\n * case \"C\": return 3;\n * default: throw new FatalErrorException();\n * }\n * }\n * ```\n */\nexport class FatalErrorException extends Exception\n{\n /**\n * Initializes a new instance of the {@link FatalErrorException} class.\n *\n * ---\n *\n * @example\n * ```ts\n * throw new FatalErrorException(\"This error should never happen. Please, contact the support team.\");\n * ```\n *\n * ---\n *\n * @param message The message that describes the error.\n * @param cause The previous caught error that caused this one, if any.\n * @param name The name of the exception. Default is `\"FatalErrorException\"`.\n */\n public constructor(message?: string, cause?: unknown, name = \"FatalErrorException\")\n {\n if (message === undefined)\n {\n message = \"The program has encountered an unrecoverable error and cannot continue as expected. \" +\n \"Please, try again later. If the problem persists, contact the support team.\";\n }\n\n super(message, cause, name);\n }\n\n public override readonly [Symbol.toStringTag]: string = \"FatalErrorException\";\n}\n\n/**\n * An utility class representing a situation where a feature isn't implemented yet. \n * It's commonly used as a placeholder for future implementations.\n *\n * It provides a clear and friendly message by default.\n *\n * ---\n *\n * @example\n * ```ts\n * class Database\n * {\n * public async connect(): Promise<void>\n * {\n * throw new NotImplementedException();\n * }\n * }\n * ```\n */\nexport class NotImplementedException extends FatalErrorException\n{\n /**\n * Initializes a new instance of the {@link NotImplementedException} class.\n *\n * ---\n *\n * @example\n * ```ts\n * throw new NotImplementedException(\"This method hasn't been implemented yet. Check back later.\");\n * ```\n *\n * ---\n *\n * @param message The message that describes the error.\n * @param cause The previous caught error that caused this one, if any.\n * @param name The name of the exception. Default is `\"NotImplementedException\"`.\n */\n public constructor(message?: string, cause?: unknown, name = \"NotImplementedException\")\n {\n if (message === undefined)\n {\n message = \"This feature isn't implemented yet. Please, try again later.\";\n }\n\n super(message, cause, name);\n }\n\n public override readonly [Symbol.toStringTag]: string = \"NotImplementedException\";\n}\n","import Exception from \"./core.js\";\n\n/**\n * A class representing a generic exception that can be thrown when a file\n * operation fails, such as reading, writing, copying, moving, deleting, etc...\n *\n * It can also be used to catch all file-related exceptions at once.\n *\n * ---\n *\n * @example\n * ```ts\n * try { [...] }\n * catch (error)\n * {\n * if (error instanceof FileException)\n * {\n * // A file-related exception occurred. Handle it...\n * }\n * }\n * ```\n */\nexport class FileException extends Exception\n{\n /**\n * Initializes a new instance of the {@link FileException} class.\n *\n * ---\n *\n * @example\n * ```ts\n * throw new FileException(\"An error occurred while trying to read the file.\");\n * ```\n *\n * ---\n *\n * @param message The message that describes the error.\n * @param cause The previous caught error that caused this one, if any.\n * @param name The name of the exception. Default is `\"FileException\"`.\n */\n public constructor(message: string, cause?: unknown, name = \"FileException\")\n {\n super(message, cause, name);\n }\n\n public override readonly [Symbol.toStringTag]: string = \"FileException\";\n}\n\n/**\n * A class representing an exception that can be thrown when a file already exists.\n *\n * ---\n *\n * @example\n * ```ts\n * import { existsSync } from \"node:fs\";\n *\n * if (existsSync(\"file.txt\"))\n * {\n * throw new FileExistsException(\"The file named 'file.txt' already exists.\");\n * }\n * ```\n */\nexport class FileExistsException extends FileException\n{\n /**\n * Initializes a new instance of the {@link FileExistsException} class.\n *\n * ---\n *\n * @example\n * ```ts\n * throw new FileExistsException(\"The file named 'data.json' already exists on the server.\");\n * ```\n *\n * ---\n *\n * @param message The message that describes the error.\n * @param cause The previous caught error that caused this one, if any.\n * @param name The name of the exception. Default is `\"FileExistsException\"`.\n */\n public constructor(message: string, cause?: unknown, name = \"FileExistsException\")\n {\n super(message, cause, name);\n }\n\n public override readonly [Symbol.toStringTag]: string = \"FileExistsException\";\n}\n\n/**\n * A class representing an exception that can be thrown when a file isn't found.\n *\n * ---\n *\n * @example\n * ```ts\n * import { existsSync } from \"node:fs\";\n *\n * if (!existsSync(\"file.txt\"))\n * {\n * throw new FileNotFoundException(\"The file named 'file.txt' wasn't found.\");\n * }\n * ```\n */\nexport class FileNotFoundException extends FileException\n{\n /**\n * Initializes a new instance of the {@link FileNotFoundException} class.\n *\n * ---\n *\n * @example\n * ```ts\n * throw new FileNotFoundException(\"The file named 'data.json' wasn't found on the server.\");\n * ```\n *\n * ---\n *\n * @param message The message that describes the error.\n * @param cause The previous caught error that caused this one, if any.\n * @param name The name of the exception. Default is `\"FileNotFoundException\"`.\n */\n public constructor(message: string, cause?: unknown, name = \"FileNotFoundException\")\n {\n super(message, cause, name);\n }\n\n public override readonly [Symbol.toStringTag]: string = \"FileNotFoundException\";\n}\n\n/**\n * A class representing an exception that can be thrown when a key is invalid or not found. \n * It's commonly used when working with dictionaries, maps, objects, sets, etc...\n *\n * ---\n *\n * @example\n * ```ts\n * const map = new Map<string, number>();\n * if (!map.has(\"hash\"))\n * {\n * throw new KeyException(\"The key 'hash' wasn't found in the collection.\");\n * }\n * ```\n */\nexport class KeyException extends Exception\n{\n /**\n * Initializes a new instance of the {@link KeyException} class.\n *\n * ---\n *\n * @example\n * ```ts\n * throw new KeyException(\"The 'id' key wasn't found in the dictionary.\");\n * ```\n *\n * ---\n *\n * @param message The message that describes the error.\n * @param cause The previous caught error that caused this one, if any.\n * @param name The name of the exception. Default is `\"KeyException\"`.\n */\n public constructor(message: string, cause?: unknown, name = \"KeyException\")\n {\n super(message, cause, name);\n }\n\n public override readonly [Symbol.toStringTag]: string = \"KeyException\";\n}\n\n/**\n * A class representing an exception that can be thrown when a network operation fails. \n * It's commonly used when it's unable to connect to a server or when a request times out.\n *\n * ---\n *\n * @example\n * ```ts\n * import axios, { isAxiosError } from \"axios\";\n *\n * try { await axios.get(\"https://api.example.com/data\"); }\n * catch (error)\n * {\n * if (isAxiosError(error) && !error.response)\n * {\n * throw new NetworkException(\n * \"Unable to establish a connection to the server. \" +\n * \"Please, check your internet connection and try again.\"\n * );\n * }\n * }\n * ```\n */\nexport class NetworkException extends Exception\n{\n /**\n * Initializes a new instance of the {@link NetworkException} class.\n *\n * ---\n *\n * @example\n * ```ts\n * throw new NetworkException(\"Couldn't connect to the server. Please, try again later.\");\n * ```\n *\n * ---\n *\n * @param message The message that describes the error.\n * @param cause The previous caught error that caused this one, if any.\n * @param name The name of the exception. Default is `\"NetworkException\"`.\n */\n public constructor(message: string, cause?: unknown, name = \"NetworkException\")\n {\n super(message, cause, name);\n }\n\n public override readonly [Symbol.toStringTag]: string = \"NetworkException\";\n}\n\n/**\n * A class representing an exception that can be thrown when a permission is denied. \n * It's commonly used when an user tries to access a restricted resource or perform a forbidden action.\n *\n * ---\n *\n * @example\n * ```ts\n * const $user = useUserStore();\n * if (!$user.isAdmin)\n * {\n * throw new PermissionException(\"You don't have permission to perform this action.\");\n * }\n * ```\n */\nexport class PermissionException extends Exception\n{\n /**\n * Initializes a new instance of the {@link PermissionException} class.\n *\n * ---\n *\n * @example\n * ```ts\n * throw new PermissionException(\"You don't have permission to access this resource.\");\n * ```\n *\n * ---\n *\n * @param message The message that describes the error.\n * @param cause The previous caught error that caused this one, if any.\n * @param name The name of the exception. Default is `\"PermissionException\"`.\n */\n public constructor(message: string, cause?: unknown, name = \"PermissionException\")\n {\n super(message, cause, name);\n }\n\n public override readonly [Symbol.toStringTag]: string = \"PermissionException\";\n}\n\n/**\n * A class representing an exception that can be thrown when a reference is invalid or not found. \n * It's commonly used when a variable is `null`, `undefined` or when an object doesn't exist.\n *\n * ---\n *\n * @example\n * ```ts\n * const $el = document.getElementById(\"app\");\n * if ($el === null)\n * {\n * throw new ReferenceException(\"The element with the ID 'app' wasn't found in the document.\");\n * }\n * ```\n */\nexport class ReferenceException extends Exception\n{\n /**\n * Initializes a new instance of the {@link ReferenceException} class.\n *\n * ---\n *\n * @example\n * ```ts\n * throw new ReferenceException(\"The 'canvas' element wasn't found in the document.\");\n * ```\n *\n * ---\n *\n * @param message The message that describes the error.\n * @param cause The previous caught error that caused this one, if any.\n * @param name The name of the exception. Default is `\"ReferenceException\"`.\n */\n public constructor(message: string, cause?: unknown, name = \"ReferenceException\")\n {\n super(message, cause, name);\n }\n\n public override readonly [Symbol.toStringTag]: string = \"ReferenceException\";\n}\n\n/**\n * A class representing an exception that can be thrown when a runtime error occurs. \n * It's commonly used when an unexpected condition is encountered during the execution of a program.\n *\n * ---\n *\n * @example\n * ```ts\n * let status: \"enabled\" | \"disabled\" = \"enabled\";\n *\n * function enable(): void\n * {\n * if (status === \"enabled\") { throw new RuntimeException(\"The feature is already enabled.\"); }\n * status = \"enabled\";\n * }\n * ```\n */\nexport class RuntimeException extends Exception\n{\n /**\n * Initializes a new instance of the {@link RuntimeException} class.\n *\n * ---\n *\n * @example\n * ```ts\n * throw new RuntimeException(\"The received input seems to be malformed or corrupted.\");\n * ```\n *\n * ---\n *\n * @param message The message that describes the error.\n * @param cause The previous caught error that caused this one, if any.\n * @param name The name of the exception. Default is `\"RuntimeException\"`.\n */\n public constructor(message: string, cause?: unknown, name = \"RuntimeException\")\n {\n super(message, cause, name);\n }\n\n public override readonly [Symbol.toStringTag]: string = \"RuntimeException\";\n}\n\n/**\n * A class representing an exception that can be thrown when an environment\n * isn't properly configured or when a required variable isn't set. \n * It can also be used when the environment on which the program is running is unsupported.\n *\n * ---\n *\n * @example\n * ```ts\n * if (!navigator.geolocation)\n * {\n * throw new EnvironmentException(\"The Geolocation API isn't supported in this environment.\");\n * }\n * ```\n */\nexport class EnvironmentException extends RuntimeException\n{\n /**\n * Initializes a new instance of the {@link EnvironmentException} class.\n *\n * ---\n *\n * @example\n * ```ts\n * throw new EnvironmentException(\"The required environment variable 'API_KEY' isn't set.\");\n * ```\n *\n * ---\n *\n * @param message The message that describes the error.\n * @param cause The previous caught error that caused this one, if any.\n * @param name The name of the exception. Default is `\"EnvironmentException\"`.\n */\n public constructor(message: string, cause?: unknown, name = \"EnvironmentException\")\n {\n super(message, cause, name);\n }\n\n public override readonly [Symbol.toStringTag]: string = \"EnvironmentException\";\n}\n\n/**\n * A class representing an exception that can be thrown when a timeout occurs. \n * It's commonly used when a task takes too long to complete or when a request times out.\n *\n * ---\n *\n * @example\n * ```ts\n * const timeoutId = setTimeout(() => { throw new TimeoutException(\"The request timed out.\"); }, 5_000);\n * const response = await fetch(\"https://api.example.com/data\");\n *\n * clearTimeout(timeoutId);\n * ```\n */\nexport class TimeoutException extends Exception\n{\n /**\n * Initializes a new instance of the {@link TimeoutException} class.\n *\n * ---\n *\n * @example\n * ```ts\n * throw new TimeoutException(\"The task took too long to complete.\");\n * ```\n *\n * ---\n *\n * @param message The message that describes the error.\n * @param cause The previous caught error that caused this one, if any.\n * @param name The name of the exception. Default is `\"TimeoutException\"`.\n */\n public constructor(message: string, cause?: unknown, name = \"TimeoutException\")\n {\n super(message, cause, name);\n }\n\n public override readonly [Symbol.toStringTag]: string = \"TimeoutException\";\n}\n\n/**\n * A class representing an exception that can be thrown when a type is invalid or not supported. \n * It's commonly used when a function receives an unexpected type of argument.\n *\n * ---\n *\n * @example\n * ```ts\n * function greet(name: string): void\n * {\n * if (typeof name !== \"string\")\n * {\n * throw new TypeException(\"The 'name' argument must be a valid string.\");\n * }\n * }\n * ```\n */\nexport class TypeException extends Exception\n{\n /**\n * Initializes a new instance of the {@link TypeException} class.\n *\n * ---\n *\n * @example\n * ```ts\n * throw new TypeException(\"The 'username' argument must be a valid string.\");\n * ```\n *\n * ---\n *\n * @param message The message that describes the error.\n * @param cause The previous caught error that caused this one, if any.\n * @param name The name of the exception. Default is `\"TypeException\"`.\n */\n public constructor(message: string, cause?: unknown, name = \"TypeException\")\n {\n super(message, cause, name);\n }\n\n public override readonly [Symbol.toStringTag]: string = \"TypeException\";\n}\n\n/**\n * A class representing an exception that can be thrown when a value is invalid. \n * It's commonly used when a function receives an unexpected value as an argument.\n *\n * ---\n *\n * @example\n * ```ts\n * function setVolume(value: number): void\n * {\n * if (value < 0)\n * {\n * throw new ValueException(\"The 'value' argument must be greater than or equal to 0.\");\n * }\n * }\n * ```\n */\nexport class ValueException extends Exception\n{\n /**\n * Initializes a new instance of the {@link ValueException} class.\n *\n * ---\n *\n * @example\n * ```ts\n * throw new ValueException(\"The 'grade' argument cannot be negative.\");\n * ```\n *\n * ---\n *\n * @param message The message that describes the error.\n * @param cause The previous caught error that caused this one, if any.\n * @param name The name of the exception. Default is `\"ValueException\"`.\n */\n public constructor(message: string, cause?: unknown, name = \"ValueException\")\n {\n super(message, cause, name);\n }\n\n public override readonly [Symbol.toStringTag]: string = \"ValueException\";\n}\n\n/**\n * A class representing an exception that can be thrown when a value is out of range. \n * It's commonly used when a function receives an unexpected value as an argument.\n *\n * ---\n *\n * @example\n * ```ts\n * function setVolume(value: number): void\n * {\n * if ((value < 0) || (value > 100))\n * {\n * throw new RangeException(\"The 'value' argument must be between 0 and 100.\");\n * }\n * }\n * ```\n */\nexport class RangeException extends ValueException\n{\n /**\n * Initializes a new instance of the {@link RangeException} class.\n *\n * ---\n *\n * @example\n * ```ts\n * throw new RangeException(\"The 'percentage' argument must be between 0 and 100.\");\n * ```\n *\n * ---\n *\n * @param message The message that describes the error.\n * @param cause The previous caught error that caused this one, if any.\n * @param name The name of the exception. Default is `\"RangeException\"`.\n */\n public constructor(message: string, cause?: unknown, name = \"RangeException\")\n {\n super(message, cause, name);\n }\n\n public override readonly [Symbol.toStringTag]: string = \"RangeException\";\n}\n\nexport { Exception };\nexport { FatalErrorException, NotImplementedException } from \"./core.js\";\n","import AggregatedIterator from \"../aggregators/aggregated-iterator.js\";\nimport { ValueException } from \"../exceptions/index.js\";\n\nimport type { GeneratorFunction, Iteratee, TypeGuardPredicate, Reducer, IteratorLike } from \"./types.js\";\n\n/**\n * A wrapper class representing an enhanced and instantiable version\n * of the native {@link Iterable} & {@link Iterator} interfaces.\n *\n * It provides a set of utility methods to better manipulate and\n * transform iterators in a functional and highly performant way. \n * It takes inspiration from the native {@link Array} methods like\n * {@link Array.map}, {@link Array.filter}, {@link Array.reduce}, etc...\n *\n * The class is lazy, meaning that the transformations are applied\n * only when the resulting iterator is materialized, not before. \n * This allows to chain multiple transformations without\n * the need to iterate over the elements multiple times.\n *\n * ---\n *\n * @example\n * ```ts\n * const result = new SmartIterator<number>([\"-5\", \"-4\", \"-3\", \"-2\", \"-1\", \"0\", \"1\", \"2\", \"3\", \"4\", \"5\"])\n * .map(Number)\n * .map((value) => value + Math.ceil(Math.abs(value / 2)))\n * .filter((value) => value >= 0)\n * .map((value) => value + 1)\n * .reduce((acc, value) => acc + value);\n *\n * console.log(result); // 31\n * ```\n *\n * ---\n *\n * @template T The type of elements in the iterator.\n * @template R The type of the final result of the iterator. Default is `void`.\n * @template N The type of the argument required by the `next` method. Default is `undefined`.\n */\nexport default class SmartIterator<T, R = void, N = undefined> implements Iterator<T, R, N>\n{\n /**\n * The native {@link Iterator} object that is being wrapped by this instance.\n */\n protected readonly _iterator: Iterator<T, R, N>;\n\n /**\n * Initializes a new instance of the {@link SmartIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<string>([\"A\", \"B\", \"C\"]);\n * ```\n *\n * ---\n *\n * @param iterable The iterable object to wrap.\n */\n public constructor(iterable: Iterable<T, R, N>);\n\n /**\n * Initializes a new instance of the {@link SmartIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number, void, number>({\n * _sum: 0, _count: 0,\n *\n * next: function(value: number)\n * {\n * this._sum += value;\n * this._count += 1;\n *\n * return { done: false, value: this._sum / this._count };\n * }\n * })\n * ```\n *\n * ---\n *\n * @param iterator The iterator object to wrap.\n */\n public constructor(iterator: Iterator<T, R, N>);\n\n /**\n * Initializes a new instance of the {@link SmartIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number>(function* ()\n * {\n * for (let i = 2; i < 65_536; i *= 2) { yield (i - 1); }\n * });\n * ```\n *\n * ---\n *\n * @param generatorFn The generator function to wrap.\n */\n public constructor(generatorFn: GeneratorFunction<T, R, N>);\n\n /**\n * Initializes a new instance of the {@link SmartIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator(values);\n * ```\n *\n * ---\n *\n * @param argument The iterable, iterator or generator function to wrap.\n */\n public constructor(argument: IteratorLike<T, R, N> | GeneratorFunction<T, R, N>);\n public constructor(argument: IteratorLike<T, R, N> | GeneratorFunction<T, R, N>)\n {\n if (argument instanceof Function)\n {\n this._iterator = argument();\n }\n else if (Symbol.iterator in argument)\n {\n this._iterator = argument[Symbol.iterator]() as Iterator<T, R, N>;\n }\n else\n {\n this._iterator = argument;\n }\n }\n\n /**\n * Determines whether all elements of the iterator satisfy a given condition.\n * See also {@link SmartIterator.some}.\n *\n * This method will iterate over all elements of the iterator checking if they satisfy the condition. \n * Once a single element doesn't satisfy the condition, the method will return `false` immediately.\n *\n * This may lead to an unknown final state of the iterator, which may be entirely or partially consumed. \n * For this reason, it's recommended to consider it as consumed in any case and to not use it anymore. \n * Consider using {@link SmartIterator.find} instead.\n *\n * If the iterator is infinite and every element satisfies the condition, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number>([-2, -1, 0, 1, 2]);\n * const result = iterator.every((value) => value < 0);\n *\n * console.log(result); // false\n * ```\n *\n * ---\n *\n * @param predicate The condition to check for each element of the iterator.\n *\n * @returns `true` if all elements satisfy the condition, `false` otherwise.\n */\n public every(predicate: Iteratee<T, boolean>): boolean\n {\n let index = 0;\n\n while (true)\n {\n const result = this._iterator.next();\n\n if (result.done) { return true; }\n if (!(predicate(result.value, index))) { return false; }\n\n index += 1;\n }\n }\n\n /**\n * Determines whether any element of the iterator satisfies a given condition.\n * See also {@link SmartIterator.every}.\n *\n * This method will iterate over all elements of the iterator checking if they satisfy the condition. \n * Once a single element satisfies the condition, the method will return `true` immediately.\n *\n * This may lead to an unknown final state of the iterator, which may be entirely or partially consumed. \n * For this reason, it's recommended to consider it as consumed in any case and to not use it anymore. \n * Consider using {@link SmartIterator.find} instead.\n *\n * If the iterator is infinite and no element satisfies the condition, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number>([-2, -1, 0, 1, 2]);\n * const result = iterator.some((value) => value < 0);\n *\n * console.log(result); // true\n * ```\n *\n * ---\n *\n * @param predicate The condition to check for each element of the iterator.\n *\n * @returns `true` if any element satisfies the condition, `false` otherwise.\n */\n public some(predicate: Iteratee<T, boolean>): boolean\n {\n let index = 0;\n\n while (true)\n {\n const result = this._iterator.next();\n\n if (result.done) { return false; }\n if (predicate(result.value, index)) { return true; }\n\n index += 1;\n }\n }\n\n /**\n * Filters the elements of the iterator using a given condition.\n *\n * This method will iterate over all elements of the iterator checking if they satisfy the condition. \n * If the condition is met, the element will be included in the new iterator.\n *\n * Since the iterator is lazy, the filtering process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number>([-2, -1, 0, 1, 2]);\n * const result = iterator.filter((value) => value < 0);\n *\n * console.log(result.toArray()); // [-2, -1]\n * ```\n *\n * ---\n *\n * @param predicate The condition to check for each element of the iterator.\n *\n * @returns A new {@link SmartIterator} containing only the elements that satisfy the condition.\n */\n public filter(predicate: Iteratee<T, boolean>): SmartIterator<T, R>;\n\n /**\n * Filters the elements of the iterator using a given condition.\n *\n * This method will iterate over all elements of the iterator checking if they satisfy the condition. \n * If the condition is met, the element will be included in the new iterator.\n *\n * Since the iterator is lazy, the filtering process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number | string>([-2, \"-1\", \"0\", 1, \"2\"]);\n * const result = iterator.filter<number>((value) => typeof value === \"number\");\n *\n * console.log(result.toArray()); // [-2, 1]\n * ```\n *\n * ---\n *\n * @template S\n * The type of the elements that satisfy the condition. \n * This allows the type-system to infer the correct type of the new iterator.\n *\n * It must be a subtype of the original type of the elements.\n *\n * @param predicate The type guard condition to check for each element of the iterator.\n *\n * @returns A new {@link SmartIterator} containing only the elements that satisfy the condition.\n */\n public filter<S extends T>(predicate: TypeGuardPredicate<T, S>): SmartIterator<S, R>;\n public filter(predicate: Iteratee<T, boolean>): SmartIterator<T, R>\n {\n const iterator = this._iterator;\n\n return new SmartIterator<T, R>(function* ()\n {\n let index = 0;\n while (true)\n {\n const result = iterator.next();\n if (result.done) { return result.value; }\n if (predicate(result.value, index)) { yield result.value; }\n\n index += 1;\n }\n });\n }\n\n /**\n * Maps the elements of the iterator using a given transformation function.\n *\n * This method will iterate over all elements of the iterator applying the transformation function. \n * The result of each transformation will be included in the new iterator.\n *\n * Since the iterator is lazy, the mapping process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number>([-2, -1, 0, 1, 2]);\n * const result = iterator.map((value) => Math.abs(value));\n *\n * console.log(result.toArray()); // [2, 1, 0, 1, 2]\n * ```\n *\n * ---\n *\n * @template V The type of the elements after the transformation.\n *\n * @param iteratee The transformation function to apply to each element of the iterator.\n *\n * @returns A new {@link SmartIterator} containing the transformed elements.\n */\n public map<V>(iteratee: Iteratee<T, V>): SmartIterator<V, R>\n {\n const iterator = this._iterator;\n\n return new SmartIterator<V, R>(function* ()\n {\n let index = 0;\n while (true)\n {\n const result = iterator.next();\n if (result.done) { return result.value; }\n\n yield iteratee(result.value, index);\n\n index += 1;\n }\n });\n }\n\n /**\n * Reduces the elements of the iterator using a given reducer function. \n * This method will consume the entire iterator in the process.\n *\n * It will iterate over all elements of the iterator applying the reducer function. \n * The result of each iteration will be passed as the accumulator to the next one.\n *\n * The first accumulator value will be the first element of the iterator. \n * The last accumulator value will be the final result of the reduction.\n *\n * Also note that:\n * - If an empty iterator is provided, a {@link ValueException} will be thrown.\n * - If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number>([1, 2, 3, 4, 5]);\n * const result = iterator.reduce((acc, value) => acc + value);\n *\n * console.log(result); // 15\n * ```\n *\n * ---\n *\n * @param reducer The reducer function to apply to each element of the iterator.\n *\n * @returns The final result of the reduction.\n */\n public reduce(reducer: Reducer<T, T>): T;\n\n /**\n * Reduces the elements of the iterator using a given reducer function. \n * This method will consume the entire iterator in the process.\n *\n * It will iterate over all elements of the iterator applying the reducer function. \n * The result of each iteration will be passed as the accumulator to the next one.\n *\n * The first accumulator value will be the provided initial value. \n * The last accumulator value will be the final result of the reduction.\n *\n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number>([1, 2, 3, 4, 5]);\n * const result = iterator.reduce((acc, value) => acc + value, 10);\n *\n * console.log(result); // 25\n * ```\n *\n * ---\n *\n * @template A The type of the accumulator value which will also be the type of the final result of the reduction.\n *\n * @param reducer The reducer function to apply to each element of the iterator.\n * @param initialValue The initial value of the accumulator.\n *\n * @returns The final result of the reduction.\n */\n public reduce<A>(reducer: Reducer<T, A>, initialValue: A): A;\n public reduce<A>(reducer: Reducer<T, A>, initialValue?: A): A\n {\n let index = 0;\n let accumulator = initialValue;\n if (accumulator === undefined)\n {\n const result = this._iterator.next();\n if (result.done) { throw new ValueException(\"Cannot reduce an empty iterator without an initial value.\"); }\n\n accumulator = (result.value as unknown) as A;\n index += 1;\n }\n\n while (true)\n {\n const result = this._iterator.next();\n if (result.done) { return accumulator; }\n\n accumulator = reducer(accumulator, result.value, index);\n\n index += 1;\n }\n }\n\n /**\n * Flattens the elements of the iterator using a given transformation function.\n *\n * This method will iterate over all elements of the iterator applying the transformation function. \n * The result of each transformation will be flattened into the new iterator.\n *\n * Since the iterator is lazy, the flattening process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number[]>([[-2, -1], 0, 1, 2, [3, 4, 5]]);\n * const result = iterator.flatMap((value) => value);\n *\n * console.log(result.toArray()); // [-2, -1, 0, 1, 2, 3, 4, 5]\n * ```\n *\n * ---\n *\n * @template V The type of the elements after the transformation.\n *\n * @param iteratee The transformation function to apply to each element of the iterator.\n *\n * @returns A new {@link SmartIterator} containing the flattened elements.\n */\n public flatMap<V>(iteratee: Iteratee<T, V | readonly V[]>): SmartIterator<V, R>\n {\n const iterator = this._iterator;\n\n return new SmartIterator<V, R>(function* ()\n {\n let index = 0;\n while (true)\n {\n const result = iterator.next();\n if (result.done) { return result.value; }\n\n const elements = iteratee(result.value, index);\n if (elements instanceof Array)\n {\n for (const value of elements) { yield value; }\n }\n else { yield elements; }\n\n index += 1;\n }\n });\n }\n\n /**\n * Drops a given number of elements at the beginning of the iterator. \n * The remaining elements will be included in a new iterator.\n * See also {@link SmartIterator.take}.\n *\n * Since the iterator is lazy, the dropping process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * Only the dropped elements will be consumed in the process. \n * The rest of the iterator will be consumed only once the new one is.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number>([-2, -1, 0, 1, 2]);\n * const result = iterator.drop(3);\n *\n * console.log(result.toArray()); // [1, 2]\n * ```\n *\n * ---\n *\n * @param count The number of elements to drop.\n *\n * @returns A new {@link SmartIterator} containing the remaining elements.\n */\n public drop(count: number): SmartIterator<T, R | undefined>\n {\n const iterator = this._iterator;\n\n return new SmartIterator<T, R | undefined>(function* ()\n {\n let index = 0;\n while (index < count)\n {\n const result = iterator.next();\n if (result.done) { return; }\n\n index += 1;\n }\n\n while (true)\n {\n const result = iterator.next();\n if (result.done) { return result.value; }\n\n yield result.value;\n }\n });\n }\n\n /**\n * Takes a given number of elements at the beginning of the iterator. \n * These elements will be included in a new iterator.\n * See also {@link SmartIterator.drop}.\n *\n * Since the iterator is lazy, the taking process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * Only the taken elements will be consumed from the original iterator. \n * The rest of the original iterator will be available for further consumption.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number>([-2, -1, 0, 1, 2]);\n * const result = iterator.take(3);\n *\n * console.log(result.toArray()); // [-2, -1, 0]\n * console.log(iterator.toArray()); // [1, 2]\n * ```\n *\n * ---\n *\n * @param limit The number of elements to take.\n *\n * @returns A new {@link SmartIterator} containing the taken elements.\n */\n public take(limit: number): SmartIterator<T, R | undefined>\n {\n const iterator = this._iterator;\n\n return new SmartIterator<T, R | undefined>(function* ()\n {\n let index = 0;\n while (index < limit)\n {\n const result = iterator.next();\n if (result.done) { return result.value; }\n\n yield result.value;\n\n index += 1;\n }\n\n return;\n });\n }\n\n /**\n * Finds the first element of the iterator that satisfies a given condition.\n *\n * This method will iterate over all elements of the iterator checking if they satisfy the condition. \n * The first element that satisfies the condition will be returned immediately.\n *\n * Only the elements that are necessary to find the first\n * satisfying one will be consumed from the original iterator. \n * The rest of the original iterator will be available for further consumption.\n *\n * Also note that:\n * - If no element satisfies the condition, `undefined` will be returned once the entire iterator is consumed.\n * - If the iterator is infinite and no element satisfies the condition, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number>([-2, -1, 0, 1, 2]);\n * const result = iterator.find((value) => value > 0);\n *\n * console.log(result); // 1\n * ```\n *\n * ---\n *\n * @param predicate The condition to check for each element of the iterator.\n *\n * @returns The first element that satisfies the condition, `undefined` otherwise.\n */\n public find(predicate: Iteratee<T, boolean>): T | undefined;\n\n /**\n * Finds the first element of the iterator that satisfies a given condition.\n *\n * This method will iterate over all elements of the iterator checking if they satisfy the condition. \n * The first element that satisfies the condition will be returned immediately.\n *\n * Only the elements that are necessary to find the first\n * satisfying one will be consumed from the original iterator. \n * The rest of the original iterator will be available for further consumption.\n *\n * Also note that:\n * - If no element satisfies the condition, `undefined` will be returned once the entire iterator is consumed.\n * - If the iterator is infinite and no element satisfies the condition, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number | string>([-2, \"-1\", \"0\", 1, \"2\"]);\n * const result = iterator.find<number>((value) => typeof value === \"number\");\n *\n * console.log(result); // -2\n * ```\n *\n * ---\n *\n * @template S\n * The type of the element that satisfies the condition. \n * This allows the type-system to infer the correct type of the result.\n *\n * It must be a subtype of the original type of the elements.\n *\n * @param predicate The type guard condition to check for each element of the iterator.\n *\n * @returns The first element that satisfies the condition, `undefined` otherwise.\n */\n public find<S extends T>(predicate: TypeGuardPredicate<T, S>): S | undefined;\n public find(predicate: Iteratee<T, boolean>): T | undefined\n {\n let index = 0;\n\n while (true)\n {\n const result = this._iterator.next();\n\n if (result.done) { return; }\n if (predicate(result.value, index)) { return result.value; }\n\n index += 1;\n }\n }\n\n /**\n * Enumerates the elements of the iterator. \n * Each element is be paired with its index in a new iterator.\n *\n * Since the iterator is lazy, the enumeration process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<string>([\"A\", \"M\", \"N\", \"Z\"]);\n * const result = iterator.enumerate();\n *\n * console.log(result.toArray()); // [[0, \"A\"], [1, \"M\"], [2, \"N\"], [3, \"Z\"]]\n * ```\n *\n * ---\n *\n * @returns A new {@link SmartIterator} containing the enumerated elements.\n */\n public enumerate(): SmartIterator<[number, T], R>\n {\n return this.map((value, index) => [index, value]);\n }\n\n /**\n * Removes all duplicate elements from the iterator. \n * The first occurrence of each element will be kept.\n *\n * Since the iterator is lazy, the deduplication process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number>([1, 1, 2, 3, 2, 3, 4, 5, 5, 4]);\n * const result = iterator.unique();\n *\n * console.log(result.toArray()); // [1, 2, 3, 4, 5]\n * ```\n *\n * ---\n *\n * @returns A new {@link SmartIterator} containing only the unique elements.\n */\n public unique(): SmartIterator<T, R>\n {\n const iterator = this._iterator;\n\n return new SmartIterator<T, R>(function* ()\n {\n const values = new Set<T>();\n while (true)\n {\n const result = iterator.next();\n if (result.done) { return result.value; }\n if (values.has(result.value)) { continue; }\n values.add(result.value);\n\n yield result.value;\n }\n });\n }\n\n /**\n * Counts the number of elements in the iterator. \n * This method will consume the entire iterator in the process.\n *\n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number>([1, 2, 3, 4, 5]);\n * const result = iterator.count();\n *\n * console.log(result); // 5\n * ```\n *\n * ---\n *\n * @returns The number of elements in the iterator.\n */\n public count(): number\n {\n let index = 0;\n\n while (true)\n {\n const result = this._iterator.next();\n if (result.done) { return index; }\n\n index += 1;\n }\n }\n\n /**\n * Iterates over all elements of the iterator. \n * The elements are passed to the function along with their index.\n *\n * This method will consume the entire iterator in the process. \n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number>([\"A\", \"M\", \"N\", \"Z\"]);\n * iterator.forEach((value, index) =>\n * {\n * console.log(`${index}: ${value}`); // \"0: A\", \"1: M\", \"2: N\", \"3: Z\"\n * }\n * ```\n *\n * ---\n *\n * @param iteratee The function to apply to each element of the iterator.\n */\n public forEach(iteratee: Iteratee<T>): void\n {\n let index = 0;\n\n while (true)\n {\n const result = this._iterator.next();\n if (result.done) { return; }\n\n iteratee(result.value, index);\n\n index += 1;\n }\n }\n\n /**\n * Advances the iterator to the next element and returns the result. \n * If the iterator requires it, a value must be provided to be passed to the next element.\n *\n * Once the iterator is done, the method will return an object with the `done` property set to `true`.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number>([1, 2, 3, 4, 5]);\n *\n * let result = iterator.next();\n * while (!result.done)\n * {\n * console.log(result.value); // 1, 2, 3, 4, 5\n *\n * result = iterator.next();\n * }\n *\n * console.log(result); // { done: true, value: undefined }\n * ```\n *\n * ---\n *\n * @param values The value to pass to the next element, if required.\n *\n * @returns The result of the iteration, containing the value of the operation.\n */\n public next(...values: N extends undefined ? [] : [N]): IteratorResult<T, R>\n {\n return this._iterator.next(...values);\n }\n\n /**\n * An utility method that may be used to close the iterator gracefully,\n * free the resources and perform any cleanup operation. \n * It may also be used to signal the end or to compute a specific final result of the iteration process.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number>({\n * _index: 0,\n * next: function()\n * {\n * return { done: false, value: this._index += 1 };\n * },\n * return: function() { console.log(\"Closing the iterator...\"); }\n * });\n *\n * for (const value of iterator)\n * {\n * if (value > 5) { break; } // Closing the iterator...\n *\n * console.log(value); // 1, 2, 3, 4, 5\n * }\n * ```\n *\n * ---\n *\n * @param value The final value of the iterator.\n *\n * @returns The result of the iterator.\n */\n public return(value?: R): IteratorResult<T, R>\n {\n if (this._iterator.return) { return this._iterator.return(value); }\n\n return { done: true, value: value as R };\n }\n\n /**\n * An utility method that may be used to close the iterator due to an error,\n * free the resources and perform any cleanup operation. \n * It may also be used to signal that an error occurred during the iteration process or to handle it.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number>({\n * _index: 0,\n * next: function()\n * {\n * return { done: this._index > 10, value: this._index += 1 };\n * },\n * throw: function(error)\n * {\n * console.warn(error.message);\n *\n * this._index = 0;\n * }\n * });\n *\n * for (const value of iterator) // 1, 2, 3, 4, 5, \"The index is too high.\", 1, 2, 3, 4, 5, ...\n * {\n * try\n * {\n * if (value > 5) { throw new Error(\"The index is too high.\"); }\n *\n * console.log(value); // 1, 2, 3, 4, 5\n * }\n * catch (error) { iterator.throw(error); }\n * }\n * ```\n *\n * ---\n *\n * @param error The error to throw into the iterator.\n *\n * @returns The final result of the iterator.\n */\n public throw(error: unknown): IteratorResult<T, R>\n {\n if (this._iterator.throw) { return this._iterator.throw(error); }\n\n throw error;\n }\n\n /**\n * An utility method that aggregates the elements of the iterator using a given key function. \n * The elements will be grouped by the resulting keys in a new specialized iterator.\n * See {@link AggregatedIterator}.\n *\n * Since the iterator is lazy, the grouping process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * the new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator<number>([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);\n * const result = iterator.groupBy<string>((value) => value % 2 === 0 ? \"even\" : \"odd\");\n *\n * console.log(result.toObject()); // { odd: [1, 3, 5, 7, 9], even: [2, 4, 6, 8, 10] }\n * ```\n *\n * ---\n *\n * @template K The type of the keys used to group the elements.\n *\n * @param iteratee The key function to apply to each element of the iterator.\n *\n * @returns A new instance of the {@link AggregatedIterator} class containing the grouped elements.\n */\n public groupBy<K extends PropertyKey>(iteratee: Iteratee<T, K>): AggregatedIterator<K, T>\n {\n return new AggregatedIterator(this.map((element, index) =>\n {\n const key = iteratee(element, index);\n\n return [key, element] as [K, T];\n }));\n }\n\n /**\n * Materializes the iterator into an array. \n * This method will consume the entire iterator in the process.\n *\n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartIterator(function* ()\n * {\n * for (let i = 0; i < 5; i += 1) { yield i; }\n * });\n * const result = iterator.toArray();\n *\n * console.log(result); // [0, 1, 2, 3, 4]\n * ```\n *\n * ---\n *\n * @returns The {@link Array} containing all elements of the iterator.\n */\n public toArray(): T[]\n {\n return Array.from(this as Iterable<T>);\n }\n\n public readonly [Symbol.toStringTag]: string = \"SmartIterator\";\n\n public [Symbol.iterator](): SmartIterator<T, R, N> { return this; }\n}\n","import { ValueException } from \"../exceptions/index.js\";\nimport { SmartIterator } from \"../iterators/index.js\";\nimport type { GeneratorFunction } from \"../iterators/types.js\";\n\nimport AggregatedIterator from \"./aggregated-iterator.js\";\nimport type { KeyedIteratee, KeyedReducer, KeyedTypeGuardPredicate } from \"./types.js\";\n\n/**\n * A class representing an aggregated iterator that has been reduced in a lazy and optimized way.\n *\n * It's part of the {@link AggregatedIterator} and {@link AggregatedAsyncIterator} implementations,\n * providing a way to reduce them into a single value or another aggregated iterable. \n * For this reason, it isn't recommended to instantiate this class directly\n * (although it's still possible), but rather use the reducing methods provided by the aggregated iterators.\n *\n * It isn't directly iterable, just like its parent class, and needs to specify on what you want to iterate. \n * See the {@link ReducedIterator.keys}, {@link ReducedIterator.entries}\n * & {@link ReducedIterator.values} methods. \n * It does, however, provide the same set of methods to perform\n * operations and transformation on the elements of the iterator, \n * having also the knowledge and context of the groups to which\n * they belong, allowing to handle them in a grouped manner.\n *\n * This is particularly useful when you have group elements and\n * need perform specific operations on the reduced elements.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .count();\n *\n * console.log(results.toObject()); // { odd: 4, even: 4 }\n * ```\n *\n * ---\n *\n * @template K The type of the key used to group the elements.\n * @template T The type of the elements in the iterator.\n */\nexport default class ReducedIterator<K extends PropertyKey, T>\n{\n /**\n * The internal {@link SmartIterator} object that holds the reduced elements.\n */\n protected readonly _elements: SmartIterator<[K, T]>;\n\n /**\n * Initializes a new instance of the {@link ReducedIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new ReducedIterator<string, number>([[\"A\", 1], [\"B\", 2], [\"C\", 4]]);\n * ```\n *\n * ---\n *\n * @param iterable A reduced iterable object.\n */\n public constructor(iterable: Iterable<[K, T]>);\n\n /**\n * Initializes a new instance of the {@link ReducedIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new ReducedIterator<string, number>({\n * _index: 0,\n * next: () =>\n * {\n * if (this._index >= 3) { return { done: true, value: undefined }; }\n * this._index += 1;\n *\n * return { done: false, value: [[\"A\", \"B\", \"C\"][this._index], (this._index + 1)] };\n * }\n * });\n * ```\n *\n * ---\n *\n * @param iterator An reduced iterator object.\n */\n public constructor(iterator: Iterator<[K, T]>);\n\n /**\n * Initializes a new instance of the {@link ReducedIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * import { range, Random } from \"@byloth/core\";\n *\n * const results = new ReducedIterator<string, number>(function* ()\n * {\n * for (const index of range(3))\n * {\n * yield [[\"A\", \"B\", \"C\"][index], (index + 1)];\n * }\n * });\n * ```\n *\n * ---\n *\n * @param generatorFn A generator function that produces the reduced elements.\n */\n public constructor(generatorFn: GeneratorFunction<[K, T]>);\n\n /**\n * Initializes a new instance of the {@link ReducedIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new ReducedIterator(reducedValues);\n * ```\n *\n * ---\n *\n * @param argument An iterable, iterator or generator function that produces the reduced elements.\n */\n public constructor(argument: Iterable<[K, T]> | Iterator<[K, T]> | GeneratorFunction<[K, T]>);\n public constructor(argument: Iterable<[K, T]> | Iterator<[K, T]> | GeneratorFunction<[K, T]>)\n {\n this._elements = new SmartIterator(argument);\n }\n\n /**\n * Determines whether all elements of the reduced iterator satisfy the given condition.\n * See also {@link ReducedIterator.some}.\n *\n * This method will iterate over all the elements of the iterator checking if they satisfy the condition. \n * Once a single element doesn't satisfy the condition, the method will return `false` immediately.\n *\n * This may lead to an unknown final state of the iterator, which may be entirely or partially consumed. \n * For this reason, it's recommended to consider it as consumed in any case and to not use it anymore. \n * Consider using {@link ReducedIterator.find} instead.\n *\n * If the iterator is infinite and every element satisfies the condition, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value)\n * .every((key, value) => value > 0);\n *\n * console.log(results); // true\n * ```\n *\n * ---\n *\n * @param predicate The condition to check for each element of the iterator.\n *\n * @returns `true` if all elements satisfy the condition, `false` otherwise.\n */\n public every(predicate: KeyedIteratee<K, T, boolean>): boolean\n {\n for (const [index, [key, element]] of this._elements.enumerate())\n {\n if (!(predicate(key, element, index))) { return false; }\n }\n\n return true;\n }\n\n /**\n * Determines whether any element of the reduced iterator satisfies the given condition.\n * See also {@link ReducedIterator.every}.\n *\n * This method will iterate over all the elements of the iterator checking if they satisfy the condition. \n * Once a single element satisfies the condition, the method will return `true` immediately.\n *\n * This may lead to an unknown final state of the iterator, which may be entirely or partially consumed. \n * For this reason, it's recommended to consider it as consumed in any case and to not use it anymore. \n * Consider using {@link ReducedIterator.find} instead.\n *\n * If the iterator is infinite and no element satisfies the condition, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value)\n * .some((key, value) => value > 0);\n *\n * console.log(results); // true\n * ```\n *\n * ---\n *\n * @param predicate The condition to check for each element of the iterator.\n *\n * @returns `true` if any element satisfies the condition, `false` otherwise.\n */\n public some(predicate: KeyedIteratee<K, T, boolean>): boolean\n {\n for (const [index, [key, element]] of this._elements.enumerate())\n {\n if (predicate(key, element, index)) { return true; }\n }\n\n return false;\n }\n\n /**\n * Filters the elements of the reduced iterator using a given condition.\n *\n * This method will iterate over all the elements of the iterator checking if they satisfy the condition. \n * If the condition is met, the element will be included in the new iterator.\n *\n * Since the iterator is lazy, the filtering process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value)\n * .filter((key, value) => value > 0);\n *\n * console.log(results.toObject()); // { odd: 4, even: 16 }\n * ```\n *\n * ---\n *\n * @param predicate The condition to check for each element of the iterator.\n *\n * @returns A new {@link ReducedIterator} containing only the elements that satisfy the condition.\n */\n public filter(predicate: KeyedIteratee<K, T, boolean>): ReducedIterator<K, T>;\n\n /**\n * Filters the elements of the reduced iterator using a given type guard predicate.\n *\n * This method will iterate over all the elements of the iterator checking if they satisfy the condition. \n * If the condition is met, the element will be included in the new iterator.\n *\n * Since the iterator is lazy, the filtering process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number | string>([-3, -1, \"0\", \"2\", 3, 5, \"6\", \"8\"])\n * .groupBy((value) => Number(value) % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value)\n * .filter<number>((key, value) => typeof value === \"number\");\n *\n * console.log(results.toObject()); // { odd: 4 }\n * ```\n *\n * ---\n *\n * @template S\n * The type of the elements that satisfy the condition. \n * This allows the type-system to infer the correct type of the iterator.\n *\n * It must be a subtype of the original type of the elements.\n *\n * @param predicate The type guard condition to check for each element of the iterator.\n *\n * @returns A new {@link ReducedIterator} containing only the elements that satisfy the condition.\n */\n public filter<S extends T>(predicate: KeyedTypeGuardPredicate<K, T, S>): ReducedIterator<K, S>;\n public filter(predicate: KeyedIteratee<K, T, boolean>): ReducedIterator<K, T>\n {\n const elements = this._elements.enumerate();\n\n return new ReducedIterator(function* ()\n {\n for (const [index, [key, element]] of elements)\n {\n if (predicate(key, element, index)) { yield [key, element]; }\n }\n });\n }\n\n /**\n * Maps the elements of the reduced iterator using a given transformation function.\n *\n * This method will iterate over all the elements of the iterator applying the transformation function. \n * The result of the transformation will be included in the new iterator.\n *\n * Since the iterator is lazy, the mapping process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value)\n * .map((key, value) => value * 2);\n *\n * console.log(results.toObject()); // { odd: 8, even: 32 }\n * ```\n *\n * ---\n *\n * @template V The type of the elements after the transformation.\n *\n * @param iteratee The transformation function to apply to each element of the iterator.\n *\n * @returns A new {@link ReducedIterator} containing the transformed elements.\n */\n public map<V>(iteratee: KeyedIteratee<K, T, V>): ReducedIterator<K, V>\n {\n const elements = this._elements.enumerate();\n\n return new ReducedIterator(function* ()\n {\n for (const [index, [key, element]] of elements)\n {\n yield [key, iteratee(key, element, index)];\n }\n });\n }\n\n /**\n * Reduces the elements of the reduced iterator using a given reducer function. \n * This method will consume the entire iterator in the process.\n *\n * It will iterate over all the elements of the iterator applying the reducer function. \n * The result of each iteration will be passed as the accumulator to the next one.\n *\n * The first accumulator value will be the first element of the iterator. \n * The last accumulator value will be the final result of the reduction.\n *\n * Also note that:\n * - If an empty iterator is provided, a {@link ValueException} will be thrown.\n * - If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const result = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value)\n * .reduce((key, accumulator, value) => accumulator + value);\n *\n * console.log(result); // 20\n * ```\n *\n * ---\n *\n * @param reducer The reducer function to apply to the elements of the iterator.\n *\n * @returns The final value after reducing all the elements of the iterator.\n */\n public reduce(reducer: KeyedReducer<K, T, T>): T;\n\n /**\n * Reduces the elements of the reduced iterator using a given reducer function. \n * This method will consume the entire iterator in the process.\n *\n * It will iterate over all the elements of the iterator applying the reducer function. \n * The result of each iteration will be passed as the accumulator to the next one.\n *\n * The first accumulator value will be the provided initial value. \n * The last accumulator value will be the final result of the reduction.\n *\n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const result = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value)\n * .reduce((key, { value }, currentValue) => ({ value: value + currentValue }), { value: 0 });\n *\n * console.log(result); // { value: 20 }\n * ```\n *\n * ---\n *\n * @template A The type of the accumulator value which will also be the type of the final result of the reduction.\n *\n * @param reducer The reducer function to apply to the elements of the iterator.\n * @param initialValue The initial value of the accumulator.\n *\n * @returns The final result of the reduction.\n */\n public reduce<A>(reducer: KeyedReducer<K, T, A>, initialValue: A): A;\n public reduce<A>(reducer: KeyedReducer<K, T, A>, initialValue?: A): A\n {\n let index = 0;\n let accumulator = initialValue;\n if (accumulator === undefined)\n {\n const result = this._elements.next();\n if (result.done) { throw new ValueException(\"Cannot reduce an empty iterator without an initial value.\"); }\n\n accumulator = (result.value[1] as unknown) as A;\n index += 1;\n }\n\n for (const [key, element] of this._elements)\n {\n accumulator = reducer(key, accumulator, element, index);\n\n index += 1;\n }\n\n return accumulator;\n }\n\n /**\n * Flattens the elements of the reduced iterator using a given transformation function.\n *\n * This method will iterate over all the elements of the iterator applying the transformation function. \n * The result of each transformation will be flattened into the new iterator.\n *\n * Since the iterator is lazy, the flattening process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator.concat([value]), () => [])\n * .flatMap((key, value) => value);\n *\n * console.log(results.toObject()); // { odd: [-3, -1, 3, 5], even: [0, 2, 6, 8] }\n * ```\n *\n * ---\n *\n * @template V The type of the elements after the transformation.\n *\n * @param iteratee The transformation function to apply to each element of the iterator.\n *\n * @returns A new {@link AggregatedIterator} containing the flattened elements.\n */\n public flatMap<V>(iteratee: KeyedIteratee<K, T, V | readonly V[]>): AggregatedIterator<K, V>\n {\n const elements = this._elements.enumerate();\n\n return new AggregatedIterator(function* ()\n {\n for (const [index, [key, element]] of elements)\n {\n const values = iteratee(key, element, index);\n\n if (values instanceof Array)\n {\n for (const value of values) { yield [key, value]; }\n }\n else { yield [key, values]; }\n }\n });\n }\n\n /**\n * Drops a given number of elements at the beginning of the reduced iterator. \n * The remaining elements will be included in the new iterator.\n * See also {@link ReducedIterator.take}.\n *\n * Since the iterator is lazy, the dropping process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * Only the dropped elements will be consumed in the process. \n * The rest of the iterator will be consumed once the new iterator is.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator.concat(value), () => [])\n * .drop(1);\n *\n * console.log(results.toObject()); // { even: [0, 2, 6, 8] }\n * ```\n *\n * ---\n *\n * @param count The number of elements to drop.\n *\n * @returns A new {@link ReducedIterator} containing the remaining elements.\n */\n public drop(count: number): ReducedIterator<K, T>\n {\n const elements = this._elements.enumerate();\n\n return new ReducedIterator(function* ()\n {\n for (const [index, [key, element]] of elements)\n {\n if (index >= count) { yield [key, element]; }\n }\n });\n }\n\n /**\n * Takes a given number of elements at the beginning of the reduced iterator. \n * The elements will be included in the new iterator.\n * See also {@link ReducedIterator.drop}.\n *\n * Since the iterator is lazy, the taking process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * Only the taken elements will be consumed from the original reduced iterator. \n * The rest of the original reduced iterator will be available for further consumption.\n *\n * ---\n *\n * @example\n * ```ts\n * const reduced = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator.concat(value), () => []);\n *\n * const results = iterator.take(1);\n *\n * console.log(results.toObject()); // { odd: [-3, -1, 3, 5] }\n * console.log(reduced.toObject()); // { even: [0, 2, 6, 8] }\n * ```\n *\n * ---\n *\n * @param limit The number of elements to take.\n *\n * @returns A new {@link ReducedIterator} containing the taken elements.\n */\n public take(limit: number): ReducedIterator<K, T>\n {\n const elements = this._elements.enumerate();\n\n return new ReducedIterator(function* ()\n {\n for (const [index, [key, element]] of elements)\n {\n if (index >= limit) { break; }\n yield [key, element];\n }\n });\n }\n\n /**\n * Finds the first element of the reduced iterator that satisfies the given condition.\n *\n * This method will iterate over all the elements of the iterator checking if they satisfy the condition. \n * The first element that satisfies the condition will be returned immediately.\n *\n * Only the elements that are necessary to find the first\n * satisfying one will be consumed from the original iterator. \n * The rest of the iterator will be available for further consumption.\n *\n * Also note that:\n * - If no element satisfies the condition, `undefined` will be returned once the entire iterator is consumed.\n * - If the iterator is infinite and no element satisfies the condition, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -3, -1, 0, 1, 2, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value)\n * .find((key, value) => value > 0);\n *\n * console.log(results); // 16\n * ```\n *\n * ---\n *\n * @param predicate The condition to check for each element of the iterator.\n *\n * @returns The first element that satisfies the condition, `undefined` otherwise.\n */\n public find(predicate: KeyedIteratee<K, T, boolean>): T | undefined;\n\n /**\n * Finds the first element of the reduced iterator that satisfies the given type guard predicate.\n *\n * This method will iterate over all the elements of the iterator checking if they satisfy the condition. \n * The first element that satisfies the condition will be returned immediately.\n *\n * Only the elements that are necessary to find the first\n * satisfying one will be consumed from the original iterator. \n * The rest of the iterator will be available for further consumption.\n *\n * Also note that:\n * - If no element satisfies the condition, `undefined` will be returned once the entire iterator is consumed.\n * - If the iterator is infinite and no element satisfies the condition, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number | string>([\"-3\", -3, \"-1\", 0, 1, 2, \"5\", 6, 8])\n * .groupBy((value) => Number(value) % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value)\n * .find<number>((key, value) => typeof value === \"number\");\n *\n * console.log(results); // 16\n * ```\n *\n * ---\n *\n * @template S\n * The type of the elements that satisfy the condition. \n * This allows the type-system to infer the correct type of the result.\n *\n * It must be a subtype of the original type of the elements.\n *\n * @param predicate The type guard condition to check for each element of the iterator.\n *\n * @returns The first element that satisfies the condition, `undefined` otherwise.\n */\n public find<S extends T>(predicate: KeyedTypeGuardPredicate<K, T, S>): S | undefined;\n public find(predicate: KeyedIteratee<K, T, boolean>): T | undefined\n {\n for (const [index, [key, element]] of this._elements.enumerate())\n {\n if (predicate(key, element, index)) { return element; }\n }\n\n return undefined;\n }\n\n /**\n * Enumerates the elements of the reduced iterator. \n * Each element is paired with its index in a new iterator.\n *\n * Since the iterator is lazy, the enumeration process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new ReducedIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value)\n * .enumerate();\n *\n * console.log(results.toObject()); // [[0, 4], [1, 16]]\n * ```\n *\n * ---\n *\n * @returns A new {@link ReducedIterator} object containing the enumerated elements.\n */\n public enumerate(): ReducedIterator<K, [number, T]>\n {\n return this.map((_, element, index) => [index, element]);\n }\n\n /**\n * Removes all duplicate elements from the reduced iterator. \n * The first occurrence of each element will be kept.\n *\n * Since the iterator is lazy, the deduplication process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new ReducedIterator<number>([-3, -1, 0, 2, 3, 6, -3, -1, 1, 5, 6, 8, 7, 2])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .map((key, value) => Math.abs(value))\n * .reduce((key, accumulator, value) => accumulator + value)\n * .unique();\n *\n * console.log(results.toObject()); // { odd: 24 }\n *\n * @returns A new {@link ReducedIterator} containing only the unique elements.\n */\n public unique(): ReducedIterator<K, T>\n {\n const elements = this._elements;\n\n return new ReducedIterator(function* ()\n {\n const values = new Set<T>();\n for (const [key, element] of elements)\n {\n if (values.has(element)) { continue; }\n values.add(element);\n\n yield [key, element];\n }\n });\n }\n\n /**\n * Counts the number of elements in the reduced iterator. \n * This method will consume the entire iterator in the process.\n *\n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value)\n * .count();\n *\n * console.log(results); // 2\n * ```\n *\n * ---\n *\n * @returns The number of elements in the iterator.\n */\n public count(): number\n {\n let index = 0;\n\n for (const _ of this._elements) { index += 1; }\n\n return index;\n }\n\n /**\n * Iterates over all elements of the reduced iterator. \n * The elements are passed to the function along with their key and index.\n *\n * This method will consume the entire iterator in the process. \n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const reduced = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value);\n *\n * reduced.forEach((key, value, index) =>\n * {\n * console.log(`#${index} - ${key}: ${value}`); // \"#0 - odd: 4\", \"#1 - even: 16\"\n * });\n * ```\n *\n * ---\n *\n * @param iteratee The function to apply to each element of the reduced iterator.\n */\n public forEach(iteratee: KeyedIteratee<K, T>): void\n {\n for (const [index, [key, element]] of this._elements.enumerate())\n {\n iteratee(key, element, index);\n }\n }\n\n /**\n * Reaggregates the elements of the reduced iterator. \n * The elements are grouped by a new key computed by the given iteratee function.\n *\n * Since the iterator is lazy, the reorganizing process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, -6, -8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value)\n * .reorganizeBy((key, value) => value > 0 ? \"positive\" : \"negative\");\n *\n * console.log(results.toObject()); // { positive: 4, negative: -12 }\n * ```\n *\n * ---\n *\n * @template J The type of the new keys used to group the elements.\n *\n * @param iteratee The function to determine the new key of each element of the iterator.\n *\n * @returns A new {@link AggregatedIterator} containing the elements reorganized by the new keys.\n */\n public reorganizeBy<J extends PropertyKey>(iteratee: KeyedIteratee<K, T, J>): AggregatedIterator<J, T>\n {\n const elements = this._elements.enumerate();\n\n return new AggregatedIterator(function* ()\n {\n for (const [index, [key, element]] of elements)\n {\n yield [iteratee(key, element, index), element];\n }\n });\n }\n\n /**\n * An utility method that returns a new {@link SmartIterator}\n * object containing all the keys of the iterator.\n *\n * Since the iterator is lazy, the keys will be extracted\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const keys = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value)\n * .keys();\n *\n * console.log(keys.toArray()); // [\"odd\", \"even\"]\n * ```\n *\n * ---\n *\n * @returns A new {@link SmartIterator} containing all the keys of the iterator.\n */\n public keys(): SmartIterator<K>\n {\n const elements = this._elements;\n\n return new SmartIterator<K>(function* ()\n {\n for (const [key] of elements)\n {\n yield key;\n }\n });\n }\n\n /**\n * An utility method that returns a new {@link SmartIterator}\n * object containing all the entries of the iterator. \n * Each entry is a tuple containing the key and the element.\n *\n * Since the iterator is lazy, the entries will be extracted\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const entries = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value)\n * .entries();\n *\n * console.log(entries.toArray()); // [[\"odd\", 4], [\"even\", 16]]\n * ```\n *\n * ---\n *\n * @returns A new {@link SmartIterator} containing all the entries of the iterator.\n */\n public entries(): SmartIterator<[K, T]>\n {\n return this._elements;\n }\n\n /**\n * An utility method that returns a new {@link SmartIterator}\n * object containing all the values of the iterator.\n *\n * Since the iterator is lazy, the values will be extracted\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const values = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value)\n * .values();\n *\n * console.log(values.toArray()); // [4, 16]\n * ```\n *\n * ---\n *\n * @returns A new {@link SmartIterator} containing all the values of the iterator.\n */\n public values(): SmartIterator<T>\n {\n const elements = this._elements;\n\n return new SmartIterator<T>(function* ()\n {\n for (const [_, element] of elements)\n {\n yield element;\n }\n });\n }\n\n /**\n * Materializes the iterator into an array. \n * This method will consume the entire iterator in the process.\n *\n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const reduced = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value);\n *\n * console.log(reduced.toArray()); // [4, 16]\n * ```\n *\n * ---\n *\n * @returns The {@link Array} containing all elements of the iterator.\n */\n public toArray(): T[]\n {\n return Array.from(this.values());\n }\n\n /**\n * Materializes the iterator into a map. \n * This method will consume the entire iterator in the process.\n *\n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const reduced = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value);\n *\n * console.log(reduced.toMap()); // Map(2) { \"odd\" => 4, \"even\" => 16 }\n * ```\n *\n * ---\n *\n * @returns The {@link Map} containing all elements of the iterator.\n */\n public toMap(): Map<K, T>\n {\n return new Map(this.entries());\n }\n\n /**\n * Materializes the iterator into an object. \n * This method will consume the entire iterator in the process.\n *\n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const reduced = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value);\n *\n * console.log(reduced.toObject()); // { odd: 4, even: 16 }\n * ```\n *\n * ---\n *\n * @returns The {@link Object} containing all elements of the iterator.\n */\n public toObject(): Record<K, T>\n {\n return Object.fromEntries(this.entries()) as Record<K, T>;\n }\n\n public readonly [Symbol.toStringTag]: string = \"ReducedIterator\";\n}\n","import { SmartAsyncIterator } from \"../iterators/index.js\";\nimport type {\n GeneratorFunction,\n AsyncGeneratorFunction,\n MaybeAsyncGeneratorFunction,\n MaybeAsyncIteratorLike\n\n} from \"../iterators/types.js\";\nimport type { MaybePromise } from \"../types.js\";\n\nimport ReducedIterator from \"./reduced-iterator.js\";\nimport type { MaybeAsyncKeyedIteratee, MaybeAsyncKeyedReducer } from \"./types.js\";\n\n/**\n * A class representing an iterator that aggregates elements in a lazy and optimized way.\n *\n * It's part of the {@link SmartAsyncIterator} implementation,\n * providing a way to group elements of an iterable by key. \n * For this reason, it isn't recommended to instantiate this class directly\n * (although it's still possible), but rather use the {@link SmartAsyncIterator.groupBy} method.\n *\n * It isn't directly iterable like its parent class but rather needs to specify on what you want to iterate. \n * See the {@link AggregatedAsyncIterator.keys}, {@link AggregatedAsyncIterator.entries}\n * & {@link AggregatedAsyncIterator.values} methods. \n * It does, however, provide the same set of methods to perform\n * operations and transformations on the elements of the iterator,\n * having also the knowledge and context of the groups to which\n * they belong, allowing to handle them in a grouped manner.\n *\n * This is particularly useful when you need to group elements and\n * then perform specific operations on the groups themselves.\n *\n * ---\n *\n * @example\n * ```ts\n * const elements = fetch([...]); // Promise<[-3, -1, 0, 2, 3, 5, 6, 8]>;\n * const results = new SmartAsyncIterator(elements)\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .count();\n *\n * console.log(await results.toObject()); // { odd: 4, even: 4 }\n * ```\n *\n * ---\n *\n * @template K The type of the keys used to group the elements.\n * @template T The type of the elements to aggregate.\n */\nexport default class AggregatedAsyncIterator<K extends PropertyKey, T>\n{\n /**\n * The internal {@link SmartAsyncIterator} object that holds the elements to aggregate.\n */\n protected readonly _elements: SmartAsyncIterator<[K, T]>;\n\n /**\n * Initializes a new instance of the {@link AggregatedAsyncIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new AggregatedAsyncIterator<string, number>([[\"A\", 1], [\"B\", 2], [\"A\", 3], [\"C\", 4], [\"B\", 5]]);\n * ```\n *\n * ---\n *\n * @param iterable The iterable to aggregate.\n */\n public constructor(iterable: Iterable<[K, T]>);\n\n /**\n * Initializes a new instance of the {@link AggregatedAsyncIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const elements = fetch([...]); // Promise<[[\"A\", 1], [\"B\", 2], [\"A\", 3], [\"C\", 4], [\"B\", 5]]>\n * const iterator = new AggregatedAsyncIterator<string, number>(elements);\n * ```\n *\n * ---\n *\n * @param iterable The iterable to aggregate.\n */\n public constructor(iterable: AsyncIterable<[K, T]>);\n\n /**\n * Initializes a new instance of the {@link AggregatedAsyncIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * import { Random } from \"@byloth/core\";\n *\n * const iterator = new AggregatedAsyncIterator<string, number>({\n * _index: 0,\n * next: () =>\n * {\n * if (this._index >= 5) { return { done: true, value: undefined }; }\n * this._index += 1;\n *\n * return { done: false, value: [Random.Choice([\"A\", \"B\", \"C\"]), (this._index + 1)] };\n * }\n * });\n * ```\n *\n * ---\n *\n * @param iterator The iterator to aggregate.\n */\n public constructor(iterator: Iterator<[K, T]>);\n\n /**\n * Initializes a new instance of the {@link AggregatedAsyncIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * import { Random } from \"@byloth/core\";\n *\n * const iterator = new AggregatedAsyncIterator<string, number>({\n * _index: 0,\n * next: async () =>\n * {\n * if (this._index >= 5) { return { done: true, value: undefined }; }\n * this._index += 1;\n *\n * return { done: false, value: [Random.Choice([\"A\", \"B\", \"C\"]), (this._index + 1)] };\n * }\n * });\n * ```\n *\n * ---\n *\n * @param iterator The iterator to aggregate.\n */\n public constructor(iterator: AsyncIterator<[K, T]>);\n\n /**\n * Initializes a new instance of the {@link AggregatedAsyncIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * import { range, Random } from \"@byloth/core\";\n *\n * const iterator = new AggregatedAsyncIterator<string, number>(function* ()\n * {\n * for (const index of range(5))\n * {\n * yield [Random.Choice([\"A\", \"B\", \"C\"]), (index + 1)];\n * }\n * });\n * ```\n *\n * ---\n *\n * @param generatorFn The generator function to aggregate.\n */\n public constructor(generatorFn: GeneratorFunction<[K, T]>);\n\n /**\n * Initializes a new instance of the {@link AggregatedAsyncIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * import { range, Random } from \"@byloth/core\";\n *\n * const iterator = new AggregatedAsyncIterator<string, number>(async function* ()\n * {\n * for await (const index of range(5))\n * {\n * yield [Random.Choice([\"A\", \"B\", \"C\"]), (index + 1)];\n * }\n * });\n * ```\n *\n * ---\n *\n * @param generatorFn The generator function to aggregate.\n */\n public constructor(generatorFn: AsyncGeneratorFunction<[K, T]>);\n\n /**\n * Initializes a new instance of the {@link AggregatedAsyncIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new AggregatedAsyncIterator(asyncKeyedValues);\n * ```\n *\n * ---\n *\n * @param argument The iterable, iterator or generator function to aggregate.\n */\n public constructor(argument: MaybeAsyncIteratorLike<[K, T]> | MaybeAsyncGeneratorFunction<[K, T]>);\n public constructor(argument: MaybeAsyncIteratorLike<[K, T]> | MaybeAsyncGeneratorFunction<[K, T]>)\n {\n this._elements = new SmartAsyncIterator(argument);\n }\n\n /**\n * Determines whether all elements of each group of the iterator satisfy a given condition.\n * See also {@link AggregatedAsyncIterator.some}. \n * This method will consume the entire iterator in the process.\n *\n * It will iterate over all elements of the iterator checjing if they satisfy the condition. \n * Once a single element of one group doesn't satisfy the condition,\n * the result for the respective group will be `false`.\n *\n * Eventually, it will return a new {@link ReducedIterator}\n * object that will contain all the boolean results for each group. \n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .every(async (key, value) => value >= 0);\n *\n * console.log(await results.toObject()); // { odd: false, even: true }\n * ```\n *\n * ---\n *\n * @param predicate The condition to check for each element of the iterator.\n *\n * @returns\n * A {@link Promise} resolving to a new {@link ReducedIterator} containing the boolean results for each group.\n */\n public async every(predicate: MaybeAsyncKeyedIteratee<K, T, boolean>): Promise<ReducedIterator<K, boolean>>\n {\n const values = new Map<K, [number, boolean]>();\n\n for await (const [key, element] of this._elements)\n {\n const [index, result] = values.get(key) ?? [0, true];\n\n if (!(result)) { continue; }\n\n values.set(key, [index + 1, await predicate(key, element, index)]);\n }\n\n return new ReducedIterator(function* ()\n {\n for (const [key, [_, result]] of values) { yield [key, result]; }\n });\n }\n\n /**\n * Determines whether any element of each group of the iterator satisfies a given condition.\n * See also {@link AggregatedAsyncIterator.every}. \n * This method will consume the entire iterator in the process.\n *\n * It will iterate over all elements of the iterator checjing if they satisfy the condition. \n * Once a single element of one group satisfies the condition,\n * the result for the respective group will be `true`.\n *\n * Eventually, it will return a new {@link ReducedIterator}\n * object that will contain all the boolean results for each group. \n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartAsyncIterator<number>([-5, -4, -3, -2, -1, 0])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .some(async (key, value) => value >= 0);\n *\n * console.log(await results.toObject()); // { odd: false, even: true }\n * ```\n *\n * ---\n *\n * @param predicate The condition to check for each element of the iterator.\n *\n * @returns\n * A {@link Promise} resolving to a new {@link ReducedIterator} containing the boolean results for each group.\n */\n public async some(predicate: MaybeAsyncKeyedIteratee<K, T, boolean>): Promise<ReducedIterator<K, boolean>>\n {\n const values = new Map<K, [number, boolean]>();\n\n for await (const [key, element] of this._elements)\n {\n const [index, result] = values.get(key) ?? [0, false];\n\n if (result) { continue; }\n\n values.set(key, [index + 1, await predicate(key, element, index)]);\n }\n\n return new ReducedIterator(function* ()\n {\n for (const [key, [_, result]] of values) { yield [key, result]; }\n });\n }\n\n /**\n * Filters the elements of the iterator based on a given condition.\n *\n * This method will iterate over all elements of the iterator checking if they satisfy the condition. \n * If the condition is met, the element will be included in the new iterator.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .filter(async (key, value) => value >= 0);\n *\n * console.log(await results.toObject()); // { odd: [3, 5], even: [0, 2, 6, 8] }\n * ```\n *\n * ---\n *\n * @param predicate The condition to check for each element of the iterator.\n *\n * @returns A new {@link AggregatedAsyncIterator} containing the elements that satisfy the condition.\n */\n public filter(predicate: MaybeAsyncKeyedIteratee<K, T, boolean>): AggregatedAsyncIterator<K, T>;\n\n /**\n * Filters the elements of the iterator based on a given condition.\n *\n * This method will iterate over all elements of the iterator checking if they satisfy the condition. \n * If the condition is met, the element will be included in the new iterator.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartAsyncIterator<number>([-3, \"-1\", 0, \"2\", \"3\", 5, 6, \"8\"])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .filter<number>(async (key, value) => typeof value === \"number\");\n *\n * console.log(await results.toObject()); // { odd: [-3, 5], even: [0, 6] }\n * ```\n *\n * ---\n *\n * @template S\n * The type of the elements that satisfy the condition. \n * This allows the type-system to infer the correct type of the new iterator.\n *\n * It must be a subtype of the original type of the elements.\n *\n * @param predicate The type guard condition to check for each element of the iterator.\n *\n * @returns A new {@link AggregatedAsyncIterator} containing the elements that satisfy the condition.\n */\n public filter<S extends T>(predicate: MaybeAsyncKeyedIteratee<K, T, boolean>): AggregatedAsyncIterator<K, S>;\n public filter(predicate: MaybeAsyncKeyedIteratee<K, T, boolean>): AggregatedAsyncIterator<K, T>\n {\n const elements = this._elements;\n\n return new AggregatedAsyncIterator(async function* (): AsyncGenerator<[K, T]>\n {\n const indexes = new Map<K, number>();\n for await (const [key, element] of elements)\n {\n const index = indexes.get(key) ?? 0;\n if (await predicate(key, element, index)) { yield [key, element]; }\n\n indexes.set(key, index + 1);\n }\n });\n }\n\n /**\n * Maps the elements of the iterator using a given transformation function.\n *\n * This method will iterate over all elements of the iterator applying the condition. \n * The result of each transformation will be included in the new iterator.\n *\n * Since the iterator is lazy, the mapping process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .map(async (key, value) => Math.abs(value));\n *\n * console.log(await results.toObject()); // { odd: [3, 1, 3, 5], even: [0, 2, 6, 8] }\n * ```\n *\n * ---\n *\n * @template V The type of the elements after the transformation.\n *\n * @param iteratee The transformation function to apply to each element of the iterator.\n *\n * @returns A new {@link AggregatedAsyncIterator} containing the transformed elements.\n */\n public map<V>(iteratee: MaybeAsyncKeyedIteratee<K, T, V>): AggregatedAsyncIterator<K, V>\n {\n const elements = this._elements;\n\n return new AggregatedAsyncIterator(async function* (): AsyncGenerator<[K, V]>\n {\n const indexes = new Map<K, number>();\n for await (const [key, element] of elements)\n {\n const index = indexes.get(key) ?? 0;\n yield [key, await iteratee(key, element, index)];\n\n indexes.set(key, index + 1);\n }\n });\n }\n\n /**\n * Reduces the elements of the iterator using a given reducer function. \n * This method will consume the entire iterator in the process.\n *\n * It will iterate over all elements of the iterator applying the reducer function. \n * The result of each iteration will be passed as the accumulator to the next one.\n *\n * The first accoumulator value will be the first element of the iterator. \n * The last accumulator value will be the final result of the reduction.\n *\n * Eventually, it will return a new {@link ReducedIterator}\n * object that will contain all the reduced results for each group. \n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce(async (key, accumulator, value) => accumulator + value);\n *\n * console.log(await results.toObject()); // { odd: 4, even: 16 }\n * ```\n *\n * ---\n *\n * @param reducer The reducer function to apply to each element of the iterator.\n *\n * @returns\n * A {@link Promise} resolving to a new {@link ReducedIterator} containing the reduced results for each group.\n */\n public async reduce(reducer: MaybeAsyncKeyedReducer<K, T, T>): Promise<ReducedIterator<K, T>>;\n\n /**\n * Reduces the elements of the iterator using a given reducer function. \n * This method will consume the entire iterator in the process.\n *\n * It will iterate over all elements of the iterator applying the reducer function. \n * The result of each iteration will be passed as the accumulator to the next one.\n *\n * The first accoumulator value will be the provided initial value. \n * The last accumulator value will be the final result of the reduction.\n *\n * Eventually, it will return a new {@link ReducedIterator}\n * object that will contain all the reduced results for each group. \n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce(async (key, accumulator, value) => accumulator + value, 0);\n *\n * console.log(await results.toObject()); // { odd: 4, even: 16 }\n * ```\n *\n * ---\n *\n * @template A The type of the accumulator value which will also be the final result of the reduction.\n *\n * @param reducer The reducer function to apply to each element of the iterator.\n * @param initialValue The initial value for the accumulator.\n *\n * @returns\n * A {@link Promise} resolving to a new {@link ReducedIterator} containing the reduced results for each group.\n */\n public async reduce<A extends PropertyKey>(reducer: MaybeAsyncKeyedReducer<K, T, A>, initialValue: MaybePromise<A>)\n : Promise<ReducedIterator<K, A>>;\n\n /**\n * Reduces the elements of the iterator using a given reducer function. \n * This method will consume the entire iterator in the process.\n *\n * It will iterate over all elements of the iterator applying the reducer function. \n * The result of each iteration will be passed as the accumulator to the next one.\n *\n * The first accoumulator value will be the provided initial value by the given function. \n * The last accumulator value will be the final result of the reduction.\n *\n * Eventually, it will return a new {@link ReducedIterator}\n * object that will contain all the reduced results for each group. \n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce(async (key, { value }, currentValue) => ({ value: value + currentValue }), (key) => ({ value: 0 }));\n *\n * console.log(await results.toObject()); // { odd: { value: 4 }, even: { value: 16 } }\n * ```\n *\n * ---\n *\n * @template A The type of the accumulator value which will also be the final result of the reduction.\n *\n * @param reducer The reducer function to apply to each element of the iterator.\n * @param initialValue The function that provides the initial value for the accumulator.\n *\n * @returns\n * A {@link Promise} resolving to a new {@link ReducedIterator} containing the reduced results for each group.\n */\n public async reduce<A>(reducer: MaybeAsyncKeyedReducer<K, T, A>, initialValue: (key: K) => MaybePromise<A>)\n : Promise<ReducedIterator<K, A>>;\n public async reduce<A>(\n reducer: MaybeAsyncKeyedReducer<K, T, A>, initialValue?: MaybePromise<A> | ((key: K) => MaybePromise<A>)\n ): Promise<ReducedIterator<K, A>>\n {\n const values = new Map<K, [number, A]>();\n\n for await (const [key, element] of this._elements)\n {\n let index: number;\n let accumulator: A;\n\n if (values.has(key)) { [index, accumulator] = values.get(key)!; }\n else if (initialValue !== undefined)\n {\n index = 0;\n\n if (initialValue instanceof Function) { accumulator = await initialValue(key); }\n else { accumulator = await initialValue; }\n }\n else\n {\n values.set(key, [0, (element as unknown) as A]);\n\n continue;\n }\n\n values.set(key, [index + 1, await reducer(key, accumulator, element, index)]);\n }\n\n return new ReducedIterator(function* ()\n {\n for (const [key, [_, accumulator]] of values) { yield [key, accumulator]; }\n });\n }\n\n /**\n * Flattens the elements of the iterator using a given transformation function.\n *\n * This method will iterate over all elements of the iterator applying the transformation function. \n * The result of each transformation will be included in the new iterator.\n *\n * Since the iterator is lazy, the mapping process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartAsyncIterator<number>([[-3, -1], 0, 2, 3, 5, [6, 8]])\n * .groupBy(async (values) =>\n * {\n * const value = values instanceof Array ? values[0] : values;\n * return value % 2 === 0 ? \"even\" : \"odd\";\n * })\n * .flatMap(async (key, values) => values);\n *\n * console.log(await results.toObject()); // { odd: [-3, -1, 3, 5], even: [0, 2, 6, 8] }\n * ```\n *\n * ---\n *\n * @template V The type of the elements after the transformation.\n *\n * @param iteratee The transformation function to apply to each element of the iterator.\n *\n * @returns A new {@link AggregatedAsyncIterator} containing the transformed elements.\n */\n public flatMap<V>(iteratee: MaybeAsyncKeyedIteratee<K, T, V | readonly V[]>): AggregatedAsyncIterator<K, V>\n {\n const elements = this._elements;\n\n return new AggregatedAsyncIterator(async function* (): AsyncGenerator<[K, V]>\n {\n const indexes = new Map<K, number>();\n for await (const [key, element] of elements)\n {\n const index = indexes.get(key) ?? 0;\n const values = await iteratee(key, element, index);\n\n if (values instanceof Array)\n {\n for (const value of values) { yield [key, value]; }\n }\n else { yield [key, values]; }\n\n indexes.set(key, index + 1);\n }\n });\n }\n\n /**\n * Drops a given number of elements from the beginning of each group of the iterator. \n * The remaining elements will be included in the new iterator.\n * See also {@link AggregatedAsyncIterator.take}.\n *\n * Since the iterator is lazy, the dropping process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .drop(2);\n *\n * console.log(await results.toObject()); // { odd: [3, 5], even: [6, 8] }\n * ```\n *\n * ---\n *\n * @param count The number of elements to drop from the beginning of each group.\n *\n * @returns A new {@link AggregatedAsyncIterator} containing the remaining elements.\n */\n public drop(count: number): AggregatedAsyncIterator<K, T>\n {\n const elements = this._elements;\n\n return new AggregatedAsyncIterator(async function* (): AsyncGenerator<[K, T]>\n {\n const indexes = new Map<K, number>();\n for await (const [key, element] of elements)\n {\n const index = indexes.get(key) ?? 0;\n if (index < count)\n {\n indexes.set(key, index + 1);\n\n continue;\n }\n\n yield [key, element];\n }\n });\n }\n\n /**\n * Takes a given number of elements from the beginning of each group of the iterator. \n * The elements will be included in the new iterator.\n * See also {@link AggregatedAsyncIterator.drop}.\n *\n * Since the iterator is lazy, the taking process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .take(2);\n *\n * console.log(await results.toObject()); // { odd: [-3, -1], even: [0, 2] }\n * ```\n *\n * ---\n *\n * @param limit The number of elements to take from the beginning of each group.\n *\n * @returns A new {@link AggregatedAsyncIterator} containing the taken elements.\n */\n public take(limit: number): AggregatedAsyncIterator<K, T>\n {\n const elements = this._elements;\n\n return new AggregatedAsyncIterator(async function* (): AsyncGenerator<[K, T]>\n {\n const indexes = new Map<K, number>();\n for await (const [key, element] of elements)\n {\n const index = indexes.get(key) ?? 0;\n if (index >= limit) { continue; }\n\n yield [key, element];\n\n indexes.set(key, index + 1);\n }\n });\n }\n\n /**\n * Finds the first element of each group of the iterator that satisfies a given condition. \n * This method will consume the entire iterator in the process.\n *\n * It will iterate over all elements of the iterator checking if they satisfy the condition. \n * Once the first element of one group satisfies the condition,\n * the result for the respective group will be the element itself.\n *\n * Eventually, it will return a new {@link ReducedIterator}\n * object that will contain the first element that satisfies the condition for each group. \n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .find(async (key, value) => value > 0);\n *\n * console.log(await results.toObject()); // { odd: 3, even: 2 }\n * ```\n *\n * ---\n *\n * @param predicate The condition to check for each element of the iterator.\n *\n * @returns\n * A {@link Promise} resolving to a new {@link ReducedIterator} containing\n * the first element that satisfies the condition for each group.\n */\n public async find(predicate: MaybeAsyncKeyedIteratee<K, T, boolean>): Promise<ReducedIterator<K, T | undefined>>;\n\n /**\n * Finds the first element of each group of the iterator that satisfies a given condition. \n * This method will consume the entire iterator in the process.\n *\n * It will iterate over all elements of the iterator checking if they satisfy the condition. \n * Once the first element of one group satisfies the condition,\n * the result for the respective group will be the element itself.\n *\n * Eventually, it will return a new {@link ReducedIterator}\n * object that will contain the first element that satisfies the condition for each group. \n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartAsyncIterator<number | string>([-3, \"-1\", 0, \"2\", \"3\", 5, 6, \"8\"])\n * .groupBy(async (value) => Number(value) % 2 === 0 ? \"even\" : \"odd\")\n * .find<number>(async (key, value) => typeof value === \"number\");\n *\n * console.log(await results.toObject()); // { odd: -3, even: 0 }\n * ```\n *\n * ---\n *\n * @template S\n * The type of the elements that satisfy the condition. \n * This allows the type-system to infer the correct type of the new iterator.\n *\n * It must be a subtype of the original type of the elements.\n *\n * @param predicate The type guard condition to check for each element of the iterator.\n *\n * @returns\n * A {@link Promise} resolving to a new {@link ReducedIterator} containing\n * the first element that satisfies the condition for each group.\n */\n public async find<S extends T>(predicate: MaybeAsyncKeyedIteratee<K, T, boolean>)\n : Promise<ReducedIterator<K, S | undefined>>;\n\n public async find(predicate: MaybeAsyncKeyedIteratee<K, T, boolean>): Promise<ReducedIterator<K, T | undefined>>\n {\n const values = new Map<K, [number, T | undefined]>();\n\n for await (const [key, element] of this._elements)\n {\n let [index, finding] = values.get(key) ?? [0, undefined];\n\n if (finding !== undefined) { continue; }\n if (await predicate(key, element, index)) { finding = element; }\n\n values.set(key, [index + 1, finding]);\n }\n\n return new ReducedIterator(function* ()\n {\n for (const [key, [_, finding]] of values) { yield [key, finding]; }\n });\n }\n\n /**\n * Enumerates the elements of the iterator. \n * Each element is paired with its index within the group in the new iterator.\n *\n * Since the iterator is lazy, the enumeration process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartAsyncIterator<number>([-3, 0, 2, -1, 3])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .enumerate();\n *\n * console.log(results.toObject()); // { odd: [[0, -3], [1, -1], [2, 3]], even: [[0, 0], [1, 2]] }\n * ```\n *\n * ---\n *\n * @returns A new {@link AggregatedAsyncIterator} containing the enumerated elements.\n */\n public enumerate(): AggregatedAsyncIterator<K, [number, T]>\n {\n return this.map((key, value, index) => [index, value]);\n }\n\n /**\n * Removes all duplicate elements from within each group of the iterator. \n * The first occurrence of each element will be included in the new iterator.\n *\n * Since the iterator is lazy, the deduplication process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 6, -3, -1, 0, 5, 6, 8, 0, 2])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .unique();\n *\n * console.log(await results.toObject()); // { odd: [-3, -1, 3, 5], even: [0, 2, 6, 8] }\n * ```\n *\n * ---\n *\n * @returns A new {@link AggregatedAsyncIterator} containing only the unique elements.\n */\n public unique(): AggregatedAsyncIterator<K, T>\n {\n const elements = this._elements;\n\n return new AggregatedAsyncIterator(async function* (): AsyncGenerator<[K, T]>\n {\n const keys = new Map<K, Set<T>>();\n for await (const [key, element] of elements)\n {\n const values = keys.get(key) ?? new Set<T>();\n if (values.has(element)) { continue; }\n\n values.add(element);\n keys.set(key, values);\n\n yield [key, element];\n }\n });\n }\n\n /**\n * Counts the number of elements within each group of the iterator. \n * This method will consume the entire iterator in the process.\n *\n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .count();\n *\n * console.log(await results.toObject()); // { odd: 4, even: 4 }\n * ```\n *\n * ---\n *\n * @returns\n * A {@link Promise} resolving to a new {@link ReducedIterator} containing the number of elements for each group.\n */\n public async count(): Promise<ReducedIterator<K, number>>\n {\n const counters = new Map<K, number>();\n\n for await (const [key] of this._elements)\n {\n const count = counters.get(key) ?? 0;\n\n counters.set(key, count + 1);\n }\n\n return new ReducedIterator(function* ()\n {\n for (const [key, count] of counters) { yield [key, count]; }\n });\n }\n\n /**\n * Iterates over the elements of the iterator. \n * The elements are passed to the given iteratee function along with their key and index within the group.\n *\n * This method will consume the entire iterator in the process. \n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const aggregator = new SmartAsyncIterator<number>([-3, 0, 2, -1, 3])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\");\n *\n * await aggregator.forEach(async (key, value, index) =>\n * {\n * console.log(`${index}: ${value}`); // \"0: -3\", \"0: 0\", \"1: 2\", \"1: -1\", \"2: 3\"\n * };\n * ```\n *\n * ---\n *\n * @param iteratee The function to execute for each element of the iterator.\n *\n * @returns A {@link Promise} that will resolve once the iteration is complete.\n */\n public async forEach(iteratee: MaybeAsyncKeyedIteratee<K, T>): Promise<void>\n {\n const indexes = new Map<K, number>();\n\n for await (const [key, element] of this._elements)\n {\n const index = indexes.get(key) ?? 0;\n\n await iteratee(key, element, index);\n\n indexes.set(key, index + 1);\n }\n }\n\n /**\n * Changes the key of each element on which the iterator is aggregated. \n * The new key is determined by the given iteratee function.\n *\n * Since the iterator is lazy, the reorganization process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .map(async (key, value, index) => index % 2 === 0 ? value : -value)\n * .reorganizeBy(async (key, value) => value >= 0 ? \"+\" : \"-\");\n *\n * console.log(await results.toObject()); // { \"+\": [1, 0, 3, 6], \"-\": [-3, -2, -5, -8] }\n * ```\n *\n * ---\n *\n * @template J The type of the new key.\n *\n * @param iteratee The function to determine the new key for each element of the iterator.\n *\n * @returns A new {@link AggregatedAsyncIterator} containing the elements reorganized by the new keys.\n */\n public reorganizeBy<J extends PropertyKey>(iteratee: MaybeAsyncKeyedIteratee<K, T, J>)\n : AggregatedAsyncIterator<J, T>\n {\n const elements = this._elements;\n\n return new AggregatedAsyncIterator(async function* (): AsyncGenerator<[J, T]>\n {\n const indexes = new Map<K, number>();\n for await (const [key, element] of elements)\n {\n const index = indexes.get(key) ?? 0;\n yield [await iteratee(key, element, index), element];\n\n indexes.set(key, index + 1);\n }\n });\n }\n\n /**\n * An utility method that returns a new {@link SmartAsyncIterator}\n * object containing all the keys of the iterator.\n *\n * Since the iterator is lazy, the keys will be extracted\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const keys = new SmartAsyncIterator([-3, Symbol(), \"A\", { }, null, [1 , 2, 3], false])\n * .groupBy(async (value) => typeof value)\n * .keys();\n *\n * console.log(await keys.toArray()); // [\"number\", \"symbol\", \"string\", \"object\", \"boolean\"]\n * ```\n *\n * ---\n *\n * @returns A new {@link SmartAsyncIterator} containing all the keys of the iterator.\n */\n public keys(): SmartAsyncIterator<K>\n {\n const elements = this._elements;\n\n return new SmartAsyncIterator<K>(async function* ()\n {\n const keys = new Set<K>();\n for await (const [key] of elements)\n {\n if (keys.has(key)) { continue; }\n keys.add(key);\n\n yield key;\n }\n });\n }\n\n /**\n * An utility method that returns a new {@link SmartAsyncIterator}\n * object containing all the entries of the iterator. \n * Each entry is a tuple containing the key and the element.\n *\n * Since the iterator is lazy, the entries will be extracted\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const entries = new SmartAsyncIterator<number>([-3, 0, 2, -1, 3])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .entries();\n *\n * console.log(await entries.toArray()); // [[\"odd\", -3], [\"even\", 0], [\"even\", 2], [\"odd\", -1], [\"odd\", 3]]\n * ```\n *\n * ---\n *\n * @returns A new {@link SmartAsyncIterator} containing all the entries of the iterator.\n */\n public entries(): SmartAsyncIterator<[K, T]>\n {\n return this._elements;\n }\n\n /**\n * An utility method that returns a new {@link SmartAsyncIterator}\n * object containing all the values of the iterator.\n *\n * Since the iterator is lazy, the values will be extracted\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const values = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .values();\n *\n * console.log(await values.toArray()); // [-3, -1, 0, 2, 3, 5, 6, 8]\n * ```\n *\n * ---\n *\n * @returns A new {@link SmartAsyncIterator} containing all the values of the iterator.\n */\n public values(): SmartAsyncIterator<T>\n {\n const elements = this._elements;\n\n return new SmartAsyncIterator<T>(async function* ()\n {\n for await (const [_, element] of elements) { yield element; }\n });\n }\n\n /**\n * Materializes the iterator into an array of arrays. \n * This method will consume the entire iterator in the process.\n *\n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const aggregator = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\");\n *\n * console.log(await aggregator.toArray()); // [[-3, -1, 3, 5], [0, 2, 6, 8]]\n * ```\n *\n * ---\n *\n * @returns A {@link Promise} resolving to an {@link Array} containing all the values of the iterator.\n */\n public async toArray(): Promise<T[][]>\n {\n const map = await this.toMap();\n\n return Array.from(map.values());\n }\n\n /**\n * Materializes the iterator into a map. \n * This method will consume the entire iterator in the process.\n *\n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const aggregator = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\");\n *\n * console.log(await aggregator.toMap()); // Map(2) { \"odd\" => [-3, -1, 3, 5], \"even\" => [0, 2, 6, 8] }\n * ```\n *\n * ---\n *\n * @returns A {@link Promise} resolving to a {@link Map} containing all the entries of the iterator.\n */\n public async toMap(): Promise<Map<K, T[]>>\n {\n const groups = new Map<K, T[]>();\n\n for await (const [key, element] of this._elements)\n {\n const value = groups.get(key) ?? [];\n\n value.push(element);\n groups.set(key, value);\n }\n\n return groups;\n }\n\n /**\n * Materializes the iterator into an object. \n * This method will consume the entire iterator in the process.\n *\n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const aggregator = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy(async (value) => value % 2 === 0 ? \"even\" : \"odd\");\n *\n * console.log(await aggregator.toObject()); // { odd: [-3, -1, 3, 5], even: [0, 2, 6, 8] }\n * ```\n *\n * ---\n *\n * @returns A {@link Promise} resolving to an object containing all the entries of the iterator.\n */\n public async toObject(): Promise<Record<K, T[]>>\n {\n const groups = { } as Record<K, T[]>;\n\n for await (const [key, element] of this._elements)\n {\n const value = groups[key] ?? [];\n\n value.push(element);\n groups[key] = value;\n }\n\n return groups;\n }\n\n public readonly [Symbol.toStringTag]: string = \"AggregatedAsyncIterator\";\n}\n","import AggregatedAsyncIterator from \"../aggregators/aggregated-async-iterator.js\";\nimport { ValueException } from \"../exceptions/index.js\";\nimport type { MaybePromise } from \"../types.js\";\n\nimport type {\n GeneratorFunction,\n AsyncGeneratorFunction,\n MaybeAsyncGeneratorFunction,\n MaybeAsyncIteratee,\n MaybeAsyncReducer,\n MaybeAsyncIteratorLike\n\n} from \"./types.js\";\n\n/**\n * A wrapper class representing an enhanced and instantiable version\n * of the native {@link AsyncIterable} & {@link AsyncIterator} interfaces.\n *\n * It provides a set of utility methods to better manipulate and transform\n * asynchronous iterators in a functional and highly performant way. \n * It takes inspiration from the native {@link Array} methods like\n * {@link Array.map}, {@link Array.filter}, {@link Array.reduce}, etc...\n *\n * The class is lazy, meaning that the transformations are applied\n * only when the resulting iterator is materialized, not before. \n * This allows to chain multiple transformations without\n * the need to iterate over the elements multiple times.\n *\n * ---\n *\n * @example\n * ```ts\n * const result = new SmartAsyncIterator<number>([\"-5\", \"-4\", \"-3\", \"-2\", \"-1\", \"0\", \"1\", \"2\", \"3\", \"4\", \"5\"])\n * .map((value) => Number(value))\n * .map((value) => value + Math.ceil(Math.abs(value / 2)))\n * .filter((value) => value >= 0)\n * .map((value) => value + 1)\n * .reduce((acc, value) => acc + value);\n *\n * console.log(await result); // 31\n * ```\n *\n * ---\n *\n * @template T The type of elements in the iterator.\n * @template R The type of the final result of the iterator. Default is `void`.\n * @template N The type of the argument passed to the `next` method. Default is `undefined`.\n */\nexport default class SmartAsyncIterator<T, R = void, N = undefined> implements AsyncIterator<T, R, N>\n{\n /**\n * The native {@link AsyncIterator} object that is being wrapped by this instance.\n */\n protected readonly _iterator: AsyncIterator<T, R, N>;\n\n /**\n * Initializes a new instance of the {@link SmartAsyncIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<string>([\"A\", \"B\", \"C\"]);\n * ```\n *\n * ---\n *\n * @param iterable The iterable object to wrap.\n */\n public constructor(iterable: Iterable<T>);\n\n /**\n * Initializes a new instance of the {@link SmartAsyncIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number>([1, 2, 3, 4, 5]);\n * ```\n *\n * ---\n *\n * @param iterable The asynchronous iterable object to wrap.\n */\n public constructor(iterable: AsyncIterable<T>);\n\n /**\n * Initializes a new instance of the {@link SmartAsyncIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number, void, number>({\n * _sum: 0, _count: 0,\n *\n * next: function(value: number)\n * {\n * this._sum += value;\n * this._count += 1;\n *\n * return { done: false, value: this._sum / this._count };\n * }\n * })\n * ```\n *\n * ---\n *\n * @param iterator The iterator object to wrap.\n */\n public constructor(iterator: Iterator<T, R, N>);\n\n /**\n * Initializes a new instance of the {@link SmartAsyncIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number, void, number>({\n * _sum: 0, _count: 0,\n *\n * next: async function(value: number)\n * {\n * this._sum += value;\n * this._count += 1;\n *\n * return { done: false, value: this._sum / this._count };\n * }\n * })\n * ```\n *\n * ---\n *\n * @param iterator The asynchronous iterator object to wrap.\n */\n public constructor(iterator: AsyncIterator<T, R, N>);\n\n /**\n * Initializes a new instance of the {@link SmartAsyncIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number>(function* ()\n * {\n * for (let i = 2; i < 65_536; i *= 2) { yield (i - 1); }\n * });\n * ```\n *\n * ---\n *\n * @param generatorFn The generator function to wrap.\n */\n public constructor(generatorFn: GeneratorFunction<T, R, N>);\n\n /**\n * Initializes a new instance of the {@link SmartAsyncIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number>(async function* ()\n * {\n * for await (let i = 2; i < 65_536; i *= 2) { yield (i - 1); }\n * });\n * ```\n *\n * ---\n *\n * @param generatorFn The asynchronous generator function to wrap.\n */\n public constructor(generatorFn: AsyncGeneratorFunction<T, R, N>);\n\n /**\n * Initializes a new instance of the {@link SmartAsyncIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator(values);\n * ```\n *\n * ---\n *\n * @param argument The synchronous or asynchronous iterable, iterator or generator function to wrap.\n */\n public constructor(argument: MaybeAsyncIteratorLike<T, R, N> | MaybeAsyncGeneratorFunction<T, R, N>);\n public constructor(argument: MaybeAsyncIteratorLike<T, R, N> | MaybeAsyncGeneratorFunction<T, R, N>)\n {\n if (argument instanceof Function)\n {\n const generator = argument();\n if (Symbol.asyncIterator in generator)\n {\n this._iterator = generator;\n }\n else\n {\n this._iterator = (async function* ()\n {\n let next: [] | [N] = [];\n\n while (true)\n {\n const result = generator.next(...next);\n if (result.done) { return result.value; }\n\n next = [yield result.value];\n }\n\n })();\n }\n }\n else if (Symbol.asyncIterator in argument)\n {\n this._iterator = argument[Symbol.asyncIterator]() as AsyncIterator<T, R, N>;\n }\n else if (Symbol.iterator in argument)\n {\n const iterator = argument[Symbol.iterator]();\n this._iterator = (async function* ()\n {\n while (true)\n {\n const result = iterator.next();\n if (result.done) { return result.value; }\n\n yield result.value;\n }\n\n })();\n }\n else\n {\n this._iterator = (async function* ()\n {\n let next: [] | [N] = [];\n\n while (true)\n {\n const result: IteratorResult<T, R> = await argument.next(...next);\n if (result.done) { return result.value; }\n\n next = [yield result.value];\n }\n\n })();\n }\n }\n\n /**\n * Determines whether all elements of the iterator satisfy a given condition.\n * See also {@link SmartAsyncIterator.some}.\n *\n * This method will iterate over all elements of the iterator checking if they satisfy the condition. \n * Once a single element doesn't satisfy the condition, the method will return `false` immediately.\n *\n * This may lead to an unknown final state of the iterator, which may be entirely or partially consumed. \n * For this reason, it's recommended to consider it as consumed in any case and to not use it anymore. \n * Consider using {@link SmartAsyncIterator.find} instead.\n *\n * If the iterator is infinite and every element satisfies the condition, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number>([-2, -1, 0, 1, 2]);\n * const result = await iterator.every(async (value) => value < 0);\n *\n * console.log(result); // false\n * ```\n *\n * ---\n *\n * @param predicate The condition to check for each element of the iterator.\n *\n * @returns\n * A {@link Promise} that will resolve to `true` if all elements satisfy the condition, `false` otherwise.\n */\n public async every(predicate: MaybeAsyncIteratee<T, boolean>): Promise<boolean>\n {\n let index = 0;\n\n while (true)\n {\n const result = await this._iterator.next();\n\n if (result.done) { return true; }\n if (!(await predicate(result.value, index))) { return false; }\n\n index += 1;\n }\n }\n\n /**\n * Determines whether any element of the iterator satisfies a given condition.\n * See also {@link SmartAsyncIterator.every}.\n *\n * This method will iterate over all elements of the iterator checking if they satisfy the condition. \n * Once a single element satisfies the condition, the method will return `true` immediately.\n *\n * This may lead to an unknown final state of the iterator, which may be entirely or partially consumed. \n * For this reason, it's recommended to consider it as consumed in any case and to not use it anymore. \n * Consider using {@link SmartAsyncIterator.find} instead.\n *\n * If the iterator is infinite and no element satisfies the condition, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number>([-2, -1, 0, 1, 2]);\n * const result = await iterator.some(async (value) => value > 0);\n *\n * console.log(result); // true\n * ```\n *\n * ---\n *\n * @param predicate The condition to check for each element of the iterator.\n *\n * @returns\n * A {@link Promise} that will resolve to `true` if any element satisfies the condition, `false` otherwise.\n */\n public async some(predicate: MaybeAsyncIteratee<T, boolean>): Promise<boolean>\n {\n let index = 0;\n\n while (true)\n {\n const result = await this._iterator.next();\n\n if (result.done) { return false; }\n if (await predicate(result.value, index)) { return true; }\n\n index += 1;\n }\n }\n\n /**\n * Filters the elements of the iterator using a given condition.\n *\n * This method will iterate over all elements of the iterator checking if they satisfy the condition. \n * If the condition is met, the element will be included in the new iterator.\n *\n * Since the iterator is lazy, the filtering process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number>([-2, -1, 0, 1, 2]);\n * const result = iterator.filter(async (value) => value < 0);\n *\n * console.log(await result.toArray()); // [-2, -1]\n * ```\n *\n * ---\n *\n * @param predicate The condition to check for each element of the iterator.\n *\n * @returns A new {@link SmartAsyncIterator} containing only the elements that satisfy the condition.\n */\n public filter(predicate: MaybeAsyncIteratee<T, boolean>): SmartAsyncIterator<T, R>;\n\n /**\n * Filters the elements of the iterator using a given condition.\n *\n * This method will iterate over all elements of the iterator checking if they satisfy the condition. \n * If the condition is met, the element will be included in the new iterator.\n *\n * Since the iterator is lazy, the filtering process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number | string>([-2, \"-1\", \"0\", 1, \"2\"]);\n * const result = iterator.filter<number>(async (value) => typeof value === \"number\");\n *\n * console.log(await result.toArray()); // [-2, 1]\n * ```\n *\n * ---\n *\n * @template S\n * The type of the elements that satisfy the condition. \n * This allows the type-system to infer the correct type of the new iterator.\n *\n * It must be a subtype of the original type of the elements.\n *\n * @param predicate The type guard condition to check for each element of the iterator.\n *\n * @returns A new {@link SmartAsyncIterator} containing only the elements that satisfy the condition.\n */\n public filter<S extends T>(predicate: MaybeAsyncIteratee<T, boolean>): SmartAsyncIterator<S, R>;\n public filter(predicate: MaybeAsyncIteratee<T, boolean>): SmartAsyncIterator<T, R>\n {\n const iterator = this._iterator;\n\n return new SmartAsyncIterator<T, R>(async function* ()\n {\n let index = 0;\n while (true)\n {\n const result = await iterator.next();\n if (result.done) { return result.value; }\n if (await predicate(result.value, index)) { yield result.value; }\n\n index += 1;\n }\n });\n }\n\n /**\n * Maps the elements of the iterator using a given transformation function.\n *\n * This method will iterate over all elements of the iterator applying the transformation function. \n * The result of each transformation will be included in the new iterator.\n *\n * Since the iterator is lazy, the mapping process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number>([-2, -1, 0, 1, 2]);\n * const result = iterator.map(async (value) => Math.abs(value));\n *\n * console.log(await result.toArray()); // [2, 1, 0, 1, 2]\n * ```\n *\n * ---\n *\n * @template V The type of the elements after the transformation.\n *\n * @param iteratee The transformation function to apply to each element of the iterator.\n *\n * @returns A new {@link SmartAsyncIterator} containing the transformed elements.\n */\n public map<V>(iteratee: MaybeAsyncIteratee<T, V>): SmartAsyncIterator<V, R>\n {\n const iterator = this._iterator;\n\n return new SmartAsyncIterator<V, R>(async function* ()\n {\n let index = 0;\n while (true)\n {\n const result = await iterator.next();\n if (result.done) { return result.value; }\n\n yield await iteratee(result.value, index);\n\n index += 1;\n }\n });\n }\n\n /**\n * Reduces the elements of the iterator using a given reducer function. \n * This method will consume the entire iterator in the process.\n *\n * It will iterate over all elements of the iterator applying the reducer function. \n * The result of each iteration will be passed as the accumulator to the next one.\n *\n * The first accumulator value will be the first element of the iterator. \n * The last accumulator value will be the final result of the reduction.\n *\n * Also note that:\n * - If an empty iterator is provided, a {@link ValueException} will be thrown.\n * - If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number>([1, 2, 3, 4, 5]);\n * const result = await iterator.reduce(async (acc, value) => acc + value);\n *\n * console.log(result); // 15\n * ```\n *\n * ---\n *\n * @param reducer The reducer function to apply to each element of the iterator.\n *\n * @returns A {@link Promise} that will resolve to the final result of the reduction.\n */\n public async reduce(reducer: MaybeAsyncReducer<T, T>): Promise<T>;\n\n /**\n * Reduces the elements of the iterator using a given reducer function. \n * This method will consume the entire iterator in the process.\n *\n * It will iterate over all elements of the iterator applying the reducer function. \n * The result of each iteration will be passed as the accumulator to the next one.\n *\n * The first accumulator value will be the provided initial value. \n * The last accumulator value will be the final result of the reduction.\n *\n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number>([1, 2, 3, 4, 5]);\n * const result = await iterator.reduce(async (acc, value) => acc + value, 10);\n *\n * console.log(result); // 25\n * ```\n *\n * ---\n *\n * @template A The type of the accumulator value which will also be the type of the final result of the reduction.\n *\n * @param reducer The reducer function to apply to each element of the iterator.\n * @param initialValue The initial value of the accumulator.\n *\n * @returns A {@link Promise} that will resolve to the final result of the reduction.\n */\n public async reduce<A>(reducer: MaybeAsyncReducer<T, A>, initialValue: A): Promise<A>;\n public async reduce<A>(reducer: MaybeAsyncReducer<T, A>, initialValue?: A): Promise<A>\n {\n let index = 0;\n let accumulator = initialValue;\n if (accumulator === undefined)\n {\n const result = await this._iterator.next();\n if (result.done) { throw new ValueException(\"Cannot reduce an empty iterator without an initial value.\"); }\n\n accumulator = (result.value as unknown) as A;\n index += 1;\n }\n\n while (true)\n {\n const result = await this._iterator.next();\n if (result.done) { return accumulator; }\n\n accumulator = await reducer(accumulator, result.value, index);\n\n index += 1;\n }\n }\n\n /**\n * Flattens the elements of the iterator using a given transformation function.\n *\n * This method will iterate over all elements of the iterator applying the transformation function. \n * The result of each transformation will be flattened and included in the new iterator.\n *\n * Since the iterator is lazy, the flattening process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number[]>([[-2, -1], 0, 1, 2, [3, 4, 5]]);\n * const result = iterator.flatMap(async (value) => value);\n *\n * console.log(await result.toArray()); // [-2, -1, 0, 1, 2, 3, 4, 5]\n * ```\n *\n * ---\n *\n * @template V The type of the elements after the transformation.\n *\n * @param iteratee The transformation function to apply to each element of the iterator.\n *\n * @returns A new {@link SmartAsyncIterator} containing the flattened elements.\n */\n public flatMap<V>(iteratee: MaybeAsyncIteratee<T, V | readonly V[]>): SmartAsyncIterator<V, R>\n {\n const iterator = this._iterator;\n\n return new SmartAsyncIterator<V, R>(async function* ()\n {\n let index = 0;\n while (true)\n {\n const result = await iterator.next();\n if (result.done) { return result.value; }\n\n const elements = await iteratee(result.value, index);\n if (elements instanceof Array)\n {\n for (const value of elements) { yield value; }\n }\n else { yield elements; }\n\n index += 1;\n }\n });\n }\n\n /**\n * Drops a given number of elements at the beginning of the iterator. \n * The remaining elements will be included in a new iterator.\n * See also {@link SmartAsyncIterator.take}.\n *\n * Since the iterator is lazy, the dropping process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * Only the dropped elements will be consumed in the process. \n * The rest of the iterator will be consumed only once the new one is.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number>([-2, -1, 0, 1, 2]);\n * const result = iterator.drop(3);\n *\n * console.log(await result.toArray()); // [1, 2]\n * ```\n *\n * ---\n *\n * @param count The number of elements to drop.\n *\n * @returns A new {@link SmartAsyncIterator} containing the remaining elements.\n */\n public drop(count: number): SmartAsyncIterator<T, R | undefined>\n {\n const iterator = this._iterator;\n\n return new SmartAsyncIterator<T, R | undefined>(async function* ()\n {\n let index = 0;\n while (index < count)\n {\n const result = await iterator.next();\n if (result.done) { return; }\n\n index += 1;\n }\n\n while (true)\n {\n const result = await iterator.next();\n if (result.done) { return result.value; }\n\n yield result.value;\n }\n });\n }\n\n /**\n * Takes a given number of elements at the beginning of the iterator. \n * These elements will be included in a new iterator.\n * See also {@link SmartAsyncIterator.drop}.\n *\n * Since the iterator is lazy, the taking process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * Only the taken elements will be consumed from the original iterator. \n * The rest of the original iterator will be available for further consumption.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number>([-2, -1, 0, 1, 2]);\n * const result = iterator.take(3);\n *\n * console.log(await result.toArray()); // [-2, -1, 0]\n * console.log(await iterator.toArray()); // [1, 2]\n * ```\n *\n * ---\n *\n * @param limit The number of elements to take.\n *\n * @returns A new {@link SmartAsyncIterator} containing the taken elements.\n */\n public take(limit: number): SmartAsyncIterator<T, R | undefined>\n {\n const iterator = this._iterator;\n\n return new SmartAsyncIterator<T, R | undefined>(async function* ()\n {\n let index = 0;\n while (index < limit)\n {\n const result = await iterator.next();\n if (result.done) { return result.value; }\n\n yield result.value;\n\n index += 1;\n }\n\n return;\n });\n }\n\n /**\n * Finds the first element of the iterator that satisfies a given condition.\n *\n * This method will iterate over all elements of the iterator checking if they satisfy the condition. \n * The first element that satisfies the condition will be returned immediately.\n *\n * Only the elements that are necessary to find the first\n * satisfying one will be consumed from the original iterator. \n * The rest of the original iterator will be available for further consumption.\n *\n * Also note that:\n * - If no element satisfies the condition, `undefined` will be returned once the entire iterator is consumed.\n * - If the iterator is infinite and no element satisfies the condition, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number>([-2, -1, 0, 1, 2]);\n * const result = await iterator.find(async (value) => value > 0);\n *\n * console.log(result); // 1\n * ```\n *\n * ---\n *\n * @param predicate The condition to check for each element of the iterator.\n *\n * @returns\n * A {@link Promise} that will resolve to the first element that satisfies the condition, `undefined` otherwise.\n */\n public async find(predicate: MaybeAsyncIteratee<T, boolean>): Promise<T | undefined>;\n\n /**\n * Finds the first element of the iterator that satisfies a given condition.\n *\n * This method will iterate over all elements of the iterator checking if they satisfy the condition. \n * The first element that satisfies the condition will be returned immediately.\n *\n * Only the elements that are necessary to find the first\n * satisfying one will be consumed from the original iterator. \n * The rest of the original iterator will be available for further consumption.\n *\n * Also note that:\n * - If no element satisfies the condition, `undefined` will be returned once the entire iterator is consumed.\n * - If the iterator is infinite and no element satisfies the condition, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number | string>([-2, \"-1\", \"0\", 1, \"2\"]);\n * const result = await iterator.find<number>(async (value) => typeof value === \"number\");\n *\n * console.log(result); // -2\n * ```\n *\n * ---\n *\n * @template S\n * The type of the element that satisfies the condition. \n * This allows the type-system to infer the correct type of the result.\n *\n * It must be a subtype of the original type of the elements.\n *\n * @param predicate The type guard condition to check for each element of the iterator.\n *\n * @returns\n * A {@link Promise} that will resolve to the first element that satisfies the condition, `undefined` otherwise. \n */\n public async find<S extends T>(predicate: MaybeAsyncIteratee<T, boolean>): Promise<S | undefined>;\n public async find(predicate: MaybeAsyncIteratee<T, boolean>): Promise<T | undefined>\n {\n let index = 0;\n\n while (true)\n {\n const result = await this._iterator.next();\n\n if (result.done) { return; }\n if (await predicate(result.value, index)) { return result.value; }\n\n index += 1;\n }\n }\n\n /**\n * Enumerates the elements of the iterator. \n * Each element is be paired with its index in a new iterator.\n *\n * Since the iterator is lazy, the enumeration process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<string>([\"A\", \"M\", \"N\", \"Z\"]);\n * const result = iterator.enumerate();\n *\n * for await (const [index, value] of result)\n * {\n * console.log(`${index}: ${value}`); // \"0: A\", \"1: M\", \"2: N\", \"3: Z\"\n * }\n * ```\n *\n * ---\n *\n * @returns A new {@link SmartAsyncIterator} containing the enumerated elements.\n */\n public enumerate(): SmartAsyncIterator<[number, T], R>\n {\n return this.map((value, index) => [index, value]);\n }\n\n /**\n * Removes all duplicate elements from the iterator. \n * The first occurrence of each element will be kept.\n *\n * Since the iterator is lazy, the deduplication process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number>([1, 1, 2, 3, 2, 3, 4, 5, 5, 4]);\n * const result = iterator.unique();\n *\n * console.log(await result.toArray()); // [1, 2, 3, 4, 5]\n * ```\n *\n * ---\n *\n * @returns A new {@link SmartAsyncIterator} containing only the unique elements.\n */\n public unique(): SmartAsyncIterator<T, R>\n {\n const iterator = this._iterator;\n\n return new SmartAsyncIterator<T, R>(async function* ()\n {\n const values = new Set<T>();\n while (true)\n {\n const result = await iterator.next();\n if (result.done) { return result.value; }\n if (values.has(result.value)) { continue; }\n\n values.add(result.value);\n\n yield result.value;\n }\n });\n }\n\n /**\n * Counts the number of elements in the iterator. \n * This method will consume the entire iterator in the process.\n *\n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number>([1, 2, 3, 4, 5]);\n * const result = await iterator.count();\n *\n * console.log(result); // 5\n * ```\n *\n * ---\n *\n * @returns A {@link Promise} that will resolve to the number of elements in the iterator.\n */\n public async count(): Promise<number>\n {\n let index = 0;\n\n while (true)\n {\n const result = await this._iterator.next();\n if (result.done) { return index; }\n\n index += 1;\n }\n }\n\n /**\n * Iterates over all elements of the iterator. \n * The elements are passed to the function along with their index.\n *\n * This method will consume the entire iterator in the process. \n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number>([\"A\", \"M\", \"N\", \"Z\"]);\n * await iterator.forEach(async (value, index) =>\n * {\n * console.log(`${index}: ${value}`); // \"0: A\", \"1: M\", \"2: N\", \"3: Z\"\n * }\n * ```\n *\n * ---\n *\n * @param iteratee The function to apply to each element of the iterator.\n *\n * @returns A {@link Promise} that will resolve once the iteration is complete.\n */\n public async forEach(iteratee: MaybeAsyncIteratee<T>): Promise<void>\n {\n let index = 0;\n\n while (true)\n {\n const result = await this._iterator.next();\n if (result.done) { return; }\n\n await iteratee(result.value, index);\n\n index += 1;\n }\n }\n\n /**\n * Advances the iterator to the next element and returns the result. \n * If the iterator requires it, a value must be provided to be passed to the next element.\n *\n * Once the iterator is done, the method will return an object with the `done` property set to `true`.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number>([1, 2, 3, 4, 5]);\n *\n * let result = await iterator.next();\n * while (!result.done)\n * {\n * console.log(result.value); // 1, 2, 3, 4, 5\n *\n * result = await iterator.next();\n * }\n *\n * console.log(result); // { done: true, value: undefined }\n * ```\n *\n * ---\n *\n * @param values The value to pass to the next element, if required.\n *\n * @returns\n * A {@link Promise} that will resolve to the result of the iteration, containing the value of the operation.\n */\n public next(...values: N extends undefined ? [] : [N]): Promise<IteratorResult<T, R>>\n {\n return this._iterator.next(...values);\n }\n\n /**\n * An utility method that may be used to close the iterator gracefully,\n * free the resources and perform any cleanup operation. \n * It may also be used to signal the end or to compute a specific final result of the iteration process.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number>({\n * _index: 0,\n * next: async function()\n * {\n * return { done: false, value: this._index += 1 };\n * },\n * return: async function() { console.log(\"Closing the iterator...\"); }\n * });\n *\n * for await (const value of iterator)\n * {\n * if (value > 5) { break; } // Closing the iterator...\n *\n * console.log(value); // 1, 2, 3, 4, 5\n * }\n * ```\n *\n * ---\n *\n * @param value The final value of the iterator.\n *\n * @returns A {@link Promise} that will resolve to the final result of the iterator.\n */\n public async return(value?: MaybePromise<R>): Promise<IteratorResult<T, R>>\n {\n const _value = (await value) as R;\n\n if (this._iterator.return) { return await this._iterator.return(_value); }\n\n return { done: true, value: _value };\n }\n\n /**\n * An utility method that may be used to close the iterator due to an error,\n * free the resources and perform any cleanup operation. \n * It may also be used to signal that an error occurred during the iteration process or to handle it.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number>({\n * _index: 0,\n * next: async function()\n * {\n * return { done: this._index > 10, value: this._index += 1 };\n * },\n * throw: async function(error)\n * {\n * console.warn(error.message);\n *\n * this._index = 0;\n * }\n * });\n *\n * for await (const value of iterator) // 1, 2, 3, 4, 5, \"The index is too high.\", 1, 2, 3, 4, 5, ...\n * {\n * try\n * {\n * if (value > 5) { throw new Error(\"The index is too high.\"); }\n *\n * console.log(value); // 1, 2, 3, 4, 5\n * }\n * catch (error) { await iterator.throw(error); }\n * }\n * ```\n *\n * ---\n *\n * @param error The error to throw into the iterator.\n *\n * @returns A {@link Promise} that will resolve to the final result of the iterator.\n */\n public throw(error: unknown): Promise<IteratorResult<T, R>>\n {\n if (this._iterator.throw) { return this._iterator.throw(error); }\n\n throw error;\n }\n\n /**\n * An utility method that aggregates the elements of the iterator using a given key function. \n * The elements will be grouped by the resulting keys in a new specialized iterator.\n * See {@link AggregatedAsyncIterator}.\n *\n * Since the iterator is lazy, the grouping process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * the new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator<number>([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);\n * const result = iterator.groupBy<string>(async (value) => value % 2 === 0 ? \"even\" : \"odd\");\n *\n * console.log(await result.toObject()); // { odd: [1, 3, 5, 7, 9], even: [2, 4, 6, 8, 10] }\n * ```\n *\n * ---\n *\n * @template K The type of the keys used to group the elements.\n *\n * @param iteratee The key function to apply to each element of the iterator.\n *\n * @returns A new instance of the {@link AggregatedAsyncIterator} class containing the grouped elements.\n */\n public groupBy<K extends PropertyKey>(iteratee: MaybeAsyncIteratee<T, K>): AggregatedAsyncIterator<K, T>\n {\n return new AggregatedAsyncIterator(this.map(async (element, index) =>\n {\n const key = await iteratee(element, index);\n\n return [key, element] as [K, T];\n }));\n }\n\n /**\n * Materializes the iterator into an array. \n * This method will consume the entire iterator in the process.\n *\n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new SmartAsyncIterator(async function* ()\n * {\n * for (let i = 0; i < 5; i += 1) { yield i; }\n * });\n * const result = await iterator.toArray();\n *\n * console.log(result); // [0, 1, 2, 3, 4]\n * ```\n *\n * ---\n *\n * @returns A {@link Promise} that will resolve to an array containing all elements of the iterator.\n */\n public toArray(): Promise<T[]>\n {\n return Array.fromAsync(this as AsyncIterable<T>);\n }\n\n public readonly [Symbol.toStringTag]: string = \"SmartAsyncIterator\";\n\n public [Symbol.asyncIterator](): SmartAsyncIterator<T, R, N> { return this; }\n}\n","import { SmartIterator } from \"../iterators/index.js\";\nimport type { GeneratorFunction, IteratorLike } from \"../iterators/types.js\";\n\nimport ReducedIterator from \"./reduced-iterator.js\";\nimport type { KeyedIteratee, KeyedTypeGuardPredicate, KeyedReducer } from \"./types.js\";\n\n/**\n * A class representing an iterator that aggregates elements in a lazy and optimized way.\n *\n * It's part of the {@link SmartIterator} implementation, providing a way to group elements of an iterable by key. \n * For this reason, it isn't recommended to instantiate this class directly\n * (although it's still possible), but rather use the {@link SmartIterator.groupBy} method.\n *\n * It isn't directly iterable like its parent class but rather needs to specify on what you want to iterate. \n * See the {@link AggregatedIterator.keys}, {@link AggregatedIterator.entries}\n * & {@link AggregatedIterator.values} methods. \n * It does, however, provide the same set of methods to perform\n * operations and transformation on the elements of the iterator, \n * having also the knowledge and context of the groups to which\n * they belong, allowing to handle them in a grouped manner.\n *\n * This is particularly useful when you need to group elements and\n * then perform specific operations on the groups themselves.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .count();\n *\n * console.log(results.toObject()); // { odd: 4, even: 4 }\n * ```\n *\n * ---\n *\n * @template K The type of the keys used to group the elements.\n * @template T The type of the elements to aggregate.\n */\nexport default class AggregatedIterator<K extends PropertyKey, T>\n{\n /**\n * The internal {@link SmartIterator} object that holds the elements to aggregate.\n */\n protected readonly _elements: SmartIterator<[K, T]>;\n\n /**\n * Initializes a new instance of the {@link AggregatedIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new AggregatedIterator<string, number>([[\"A\", 1], [\"B\", 2], [\"A\", 3], [\"C\", 4], [\"B\", 5]]);\n * ```\n *\n * ---\n *\n * @param iterable The iterable to aggregate.\n */\n public constructor(iterable: Iterable<[K, T]>);\n\n /**\n * Initializes a new instance of the {@link AggregatedIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * import { Random } from \"@byloth/core\";\n *\n * const iterator = new AggregatedIterator<string, number>({\n * _index: 0,\n * next: () =>\n * {\n * if (this._index >= 5) { return { done: true, value: undefined }; }\n * this._index += 1;\n *\n * return { done: false, value: [Random.Choice([\"A\", \"B\", \"C\"]), (this._index + 1)] };\n * }\n * });\n * ```\n *\n * ---\n *\n * @param iterator The iterator to aggregate.\n */\n public constructor(iterator: Iterator<[K, T]>);\n\n /**\n * Initializes a new instance of the {@link AggregatedIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * import { range, Random } from \"@byloth/core\";\n *\n * const iterator = new AggregatedIterator<string, number>(function* ()\n * {\n * for (const index of range(5))\n * {\n * yield [Random.Choice([\"A\", \"B\", \"C\"]), (index + 1)];\n * }\n * });\n * ```\n *\n * ---\n *\n * @param generatorFn The generator function to aggregate.\n */\n public constructor(generatorFn: GeneratorFunction<[K, T]>);\n\n /**\n * Initializes a new instance of the {@link AggregatedIterator} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const iterator = new AggregatedIterator(keyedValues);\n * ```\n *\n * ---\n *\n * @param argument The iterable, iterator or generator function to aggregate.\n */\n public constructor(argument: IteratorLike<[K, T]> | GeneratorFunction<[K, T]>);\n public constructor(argument: IteratorLike<[K, T]> | GeneratorFunction<[K, T]>)\n {\n this._elements = new SmartIterator(argument);\n }\n\n /**\n * Determines whether all elements of each group of the iterator satisfy a given condition.\n * See also {@link AggregatedIterator.some}. \n * This method will consume the entire iterator in the process.\n *\n * It will iterate over all elements of the iterator checking if they satisfy the condition. \n * Once a single element of one group doesn't satisfy the condition,\n * the result for the respective group will be `false`.\n *\n * Eventually, it will return a new {@link ReducedIterator}\n * object that will contain all the boolean results for each group. \n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .every((key, value) => value >= 0);\n *\n * console.log(results.toObject()); // { odd: false, even: true }\n * ```\n *\n * ---\n *\n * @param predicate The condition to check for each element of the iterator.\n *\n * @returns A new {@link ReducedIterator} containing the boolean results for each group.\n */\n public every(predicate: KeyedIteratee<K, T, boolean>): ReducedIterator<K, boolean>\n {\n const values = new Map<K, [number, boolean]>();\n\n for (const [key, element] of this._elements)\n {\n const [index, result] = values.get(key) ?? [0, true];\n\n if (!(result)) { continue; }\n\n values.set(key, [index + 1, predicate(key, element, index)]);\n }\n\n return new ReducedIterator(function* ()\n {\n for (const [key, [_, result]] of values) { yield [key, result]; }\n });\n }\n\n /**\n * Determines whether any elements of each group of the iterator satisfy a given condition.\n * See also {@link AggregatedIterator.every}. \n * This method will consume the entire iterator in the process.\n *\n * It will iterate over all elements of the iterator checking if they satisfy the condition. \n * Once a single element of one group satisfies the condition,\n * the result for the respective group will be `true`.\n *\n * Eventually, it will return a new {@link ReducedIterator}\n * object that will contain all the boolean results for each group. \n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-5, -4, -3, -2, -1, 0])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .some((key, value) => value >= 0);\n *\n * console.log(results.toObject()); // { odd: false, even: true }\n * ```\n *\n * ---\n *\n * @param predicate The condition to check for each element of the iterator.\n *\n * @returns A {@link ReducedIterator} containing the boolean results for each group.\n */\n public some(predicate: KeyedIteratee<K, T, boolean>): ReducedIterator<K, boolean>\n {\n const values = new Map<K, [number, boolean]>();\n\n for (const [key, element] of this._elements)\n {\n const [index, result] = values.get(key) ?? [0, false];\n\n if (result) { continue; }\n\n values.set(key, [index + 1, predicate(key, element, index)]);\n }\n\n return new ReducedIterator(function* ()\n {\n for (const [key, [_, result]] of values) { yield [key, result]; }\n });\n }\n\n /**\n * Filters the elements of the iterator using a given condition.\n *\n * This method will iterate over all elements of the iterator checking if they satisfy the condition. \n * If the condition is met, the element will be included in the new iterator.\n *\n * Since the iterator is lazy, the filtering process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .filter((key, value) => value >= 0);\n *\n * console.log(results.toObject()); // { odd: [3, 5], even: [0, 2, 6, 8] }\n * ```\n *\n * ---\n *\n * @param predicate The condition to check for each element of the iterator.\n *\n * @returns A new {@link AggregatedIterator} containing only the elements that satisfy the condition.\n */\n public filter(predicate: KeyedIteratee<K, T, boolean>): AggregatedIterator<K, T>;\n\n /**\n * Filters the elements of the iterator using a given condition.\n *\n * This method will iterate over all elements of the iterator checking if they satisfy the condition. \n * If the condition is met, the element will be included in the new iterator.\n *\n * Since the iterator is lazy, the filtering process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number | string>([-3, \"-1\", 0, \"2\", \"3\", 5, 6, \"8\"])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .filter<number>((key, value) => typeof value === \"number\");\n *\n * console.log(results.toObject()); // { odd: [-3, 5], even: [0, 6] }\n * ```\n *\n * ---\n *\n * @template S\n * The type of the elements that satisfy the condition. \n * This allows the type-system to infer the correct type of the new iterator.\n *\n * It must be a subtype of the original type of the elements.\n *\n * @param predicate The type guard condition to check for each element of the iterator.\n *\n * @returns A new {@link AggregatedIterator} containing only the elements that satisfy the condition.\n */\n public filter<S extends T>(predicate: KeyedTypeGuardPredicate<K, T, S>): AggregatedIterator<K, S>;\n public filter(predicate: KeyedIteratee<K, T, boolean>): AggregatedIterator<K, T>\n {\n const elements = this._elements;\n\n return new AggregatedIterator(function* ()\n {\n const indexes = new Map<K, number>();\n for (const [key, element] of elements)\n {\n const index = indexes.get(key) ?? 0;\n if (predicate(key, element, index)) { yield [key, element]; }\n\n indexes.set(key, index + 1);\n }\n });\n }\n\n /**\n * Maps the elements of the iterator using a given transformation function.\n *\n * This method will iterate over all elements of the iterator applying the transformation function. \n * The result of each transformation will be included in the new iterator.\n *\n * Since the iterator is lazy, the mapping process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .map((key, value) => Math.abs(value));\n *\n * console.log(results.toObject()); // { odd: [3, 1, 3, 5], even: [0, 2, 6, 8] }\n * ```\n *\n * ---\n *\n * @template V The type of the elements after the transformation.\n *\n * @param iteratee The transformation function to apply to each element of the iterator.\n *\n * @returns A new {@link AggregatedIterator} containing the transformed elements.\n */\n public map<V>(iteratee: KeyedIteratee<K, T, V>): AggregatedIterator<K, V>\n {\n const elements = this._elements;\n\n return new AggregatedIterator(function* ()\n {\n const indexes = new Map<K, number>();\n for (const [key, element] of elements)\n {\n const index = indexes.get(key) ?? 0;\n yield [key, iteratee(key, element, index)];\n\n indexes.set(key, index + 1);\n }\n });\n }\n\n /**\n * Reduces the elements of the iterator using a given reducer function. \n * This method will consume the entire iterator in the process.\n *\n * It will iterate over all elements of the iterator applying the reducer function. \n * The result of each iteration will be passed as the accumulator to the next one.\n *\n * The first accumulator value will be the first element of the iterator. \n * The last accumulator value will be the final result of the reduction.\n *\n * Eventually, it will return a new {@link ReducedIterator}\n * object that will contain all the reduced results for each group. \n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value);\n *\n * console.log(results.toObject()); // { odd: 4, even: 16 }\n * ```\n *\n * ---\n *\n * @param reducer The reducer function to apply to each element of the iterator.\n *\n * @returns A new {@link ReducedIterator} containing the reduced results for each group.\n */\n public reduce(reducer: KeyedReducer<K, T, T>): ReducedIterator<K, T>;\n\n /**\n * Reduces the elements of the iterator using a given reducer function. \n * This method will consume the entire iterator in the process.\n *\n * It will iterate over all elements of the iterator applying the reducer function. \n * The result of each iteration will be passed as the accumulator to the next one.\n *\n * The first accumulator value will be the provided initial value. \n * The last accumulator value will be the final result of the reduction.\n *\n * Eventually, it will return a new {@link ReducedIterator}\n * object that will contain all the reduced results for each group. \n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, accumulator, value) => accumulator + value, 0);\n *\n * console.log(results.toObject()); // { odd: 4, even: 16 }\n * ```\n *\n * ---\n *\n * @template A The type of the accumulator value which will also be the type of the final result of the reduction.\n *\n * @param reducer The reducer function to apply to each element of the iterator.\n * @param initialValue The initial value of the accumulator.\n *\n * @returns A new {@link ReducedIterator} containing the reduced results for each group.\n */\n public reduce<A extends PropertyKey>(reducer: KeyedReducer<K, T, A>, initialValue: A): ReducedIterator<K, A>;\n\n /**\n * Reduces the elements of the iterator using a given reducer function. \n * This method will consume the entire iterator in the process.\n *\n * It will iterate over all elements of the iterator applying the reducer function. \n * The result of each iteration will be passed as the accumulator to the next one.\n *\n * The first accumulator value will be the provided initial value by the given function. \n * The last accumulator value will be the final result of the reduction.\n *\n * Eventually, it will return a new {@link ReducedIterator}\n * object that will contain all the reduced results for each group. \n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .reduce((key, { value }, currentValue) => ({ value: value + currentValue }), (key) => ({ value: 0 }));\n *\n * console.log(results.toObject()); // { odd: { value: 4 }, even: { value: 16 } }\n * ```\n *\n * ---\n *\n * @template A The type of the accumulator value which will also be the type of the final result of the reduction.\n *\n * @param reducer The reducer function to apply to each element of the iterator.\n * @param initialValue The function that provides the initial value for the accumulator.\n *\n * @returns A new {@link ReducedIterator} containing the reduced results for each group.\n */\n public reduce<A>(reducer: KeyedReducer<K, T, A>, initialValue: (key: K) => A): ReducedIterator<K, A>;\n public reduce<A>(reducer: KeyedReducer<K, T, A>, initialValue?: A | ((key: K) => A)): ReducedIterator<K, A>\n {\n const values = new Map<K, [number, A]>();\n\n for (const [key, element] of this._elements)\n {\n let index: number;\n let accumulator: A;\n\n if (values.has(key)) { [index, accumulator] = values.get(key)!; }\n else if (initialValue !== undefined)\n {\n index = 0;\n\n if (initialValue instanceof Function) { accumulator = initialValue(key); }\n else { accumulator = initialValue; }\n }\n else\n {\n values.set(key, [0, (element as unknown) as A]);\n\n continue;\n }\n\n values.set(key, [index + 1, reducer(key, accumulator, element, index)]);\n }\n\n return new ReducedIterator(function* ()\n {\n for (const [key, [_, accumulator]] of values) { yield [key, accumulator]; }\n });\n }\n\n /**\n * Flattens the elements of the iterator using a given transformation function.\n *\n * This method will iterate over all elements of the iterator applying the transformation function. \n * The result of each transformation will be included in the new iterator.\n *\n * Since the iterator is lazy, the flattening process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number[]>([[-3, -1], 0, 2, 3, 5, [6, 8]])\n * .groupBy((values) =>\n * {\n * const value = values instanceof Array ? values[0] : values;\n * return value % 2 === 0 ? \"even\" : \"odd\";\n * })\n * .flatMap((key, values) => values);\n *\n * console.log(results.toObject()); // { odd: [-3, -1, 3, 5], even: [0, 2, 6, 8] }\n * ```\n *\n * ---\n *\n * @template V The type of the elements after the transformation.\n *\n * @param iteratee The transformation function to apply to each element of the iterator.\n *\n * @returns A new {@link AggregatedIterator} containing the transformed elements.\n */\n public flatMap<V>(iteratee: KeyedIteratee<K, T, V | readonly V[]>): AggregatedIterator<K, V>\n {\n const elements = this._elements;\n\n return new AggregatedIterator(function* ()\n {\n const indexes = new Map<K, number>();\n for (const [key, element] of elements)\n {\n const index = indexes.get(key) ?? 0;\n const values = iteratee(key, element, index);\n\n if (values instanceof Array)\n {\n for (const value of values) { yield [key, value]; }\n }\n else { yield [key, values]; }\n\n indexes.set(key, index + 1);\n }\n });\n }\n\n /**\n * Drops a given number of elements from the beginning of each group of the iterator. \n * The remaining elements will be included in the new iterator.\n * See also {@link AggregatedIterator.take}.\n *\n * Since the iterator is lazy, the dropping process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .drop(2);\n *\n * console.log(results.toObject()); // { odd: [3, 5], even: [6, 8] }\n * ```\n *\n * ---\n *\n * @param count The number of elements to drop from the beginning of each group.\n *\n * @returns A new {@link AggregatedIterator} containing the remaining elements.\n */\n public drop(count: number): AggregatedIterator<K, T>\n {\n const elements = this._elements;\n\n return new AggregatedIterator(function* ()\n {\n const indexes = new Map<K, number>();\n for (const [key, element] of elements)\n {\n const index = indexes.get(key) ?? 0;\n if (index < count)\n {\n indexes.set(key, index + 1);\n\n continue;\n }\n\n yield [key, element];\n }\n });\n }\n\n /**\n * Takes a given number of elements from the beginning of each group of the iterator. \n * The elements will be included in the new iterator.\n * See also {@link AggregatedIterator.drop}.\n *\n * Since the iterator is lazy, the taking process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .take(2);\n *\n * console.log(results.toObject()); // { odd: [-3, -1], even: [0, 2] }\n * ```\n *\n * ---\n *\n * @param limit The number of elements to take from the beginning of each group.\n *\n * @returns A new {@link AggregatedIterator} containing the taken elements.\n */\n public take(limit: number): AggregatedIterator<K, T>\n {\n const elements = this._elements;\n\n return new AggregatedIterator(function* ()\n {\n const indexes = new Map<K, number>();\n for (const [key, element] of elements)\n {\n const index = indexes.get(key) ?? 0;\n if (index >= limit) { continue; }\n yield [key, element];\n\n indexes.set(key, index + 1);\n }\n });\n }\n\n /**\n * Finds the first element of each group of the iterator that satisfies a given condition. \n * This method will consume the entire iterator in the process.\n *\n * It will iterate over all elements of the iterator checking if they satisfy the condition. \n * Once the first element of one group satisfies the condition,\n * the result for the respective group will be the element itself.\n *\n * Eventually, it will return a new {@link ReducedIterator}\n * object that will contain the first element that satisfies the condition for each group. \n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .find((key, value) => value > 0);\n *\n * console.log(results.toObject()); // { odd: 3, even: 2 }\n * ```\n *\n * ---\n *\n * @param predicate The condition to check for each element of the iterator.\n *\n * @returns A new {@link ReducedIterator} containing the first element that satisfies the condition for each group.\n */\n public find(predicate: KeyedIteratee<K, T, boolean>): ReducedIterator<K, T | undefined>;\n\n /**\n * Finds the first element of each group of the iterator that satisfies a given condition. \n * This method will consume the entire iterator in the process.\n *\n * It will iterate over all elements of the iterator checking if they satisfy the condition. \n * Once the first element of one group satisfies the condition,\n * the result for the respective group will be the element itself.\n *\n * Eventually, it will return a new {@link ReducedIterator}\n * object that will contain the first element that satisfies the condition for each group. \n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number | string>([-3, \"-1\", 0, \"2\", \"3\", 5, 6, \"8\"])\n * .groupBy((value) => Number(value) % 2 === 0 ? \"even\" : \"odd\")\n * .find<number>((key, value) => typeof value === \"number\");\n *\n * console.log(results.toObject()); // { odd: -3, even: 0 }\n * ```\n *\n * ---\n *\n * @template S\n * The type of the elements that satisfy the condition. \n * This allows the type-system to infer the correct type of the new iterator.\n *\n * It must be a subtype of the original type of the elements.\n *\n * @param predicate The type guard condition to check for each element of the iterator.\n *\n * @returns A new {@link ReducedIterator} containing the first element that satisfies the condition for each group.\n */\n public find<S extends T>(predicate: KeyedTypeGuardPredicate<K, T, S>): ReducedIterator<K, S | undefined>;\n public find(predicate: KeyedIteratee<K, T, boolean>): ReducedIterator<K, T | undefined>\n {\n const values = new Map<K, [number, T | undefined]>();\n\n for (const [key, element] of this._elements)\n {\n let [index, finding] = values.get(key) ?? [0, undefined];\n\n if (finding !== undefined) { continue; }\n if (predicate(key, element, index)) { finding = element; }\n\n values.set(key, [index + 1, finding]);\n }\n\n return new ReducedIterator(function* ()\n {\n for (const [key, [_, finding]] of values) { yield [key, finding]; }\n });\n }\n\n /**\n * Enumerates the elements of the iterator. \n * Each element is paired with its index within the group in a new iterator.\n *\n * Since the iterator is lazy, the enumeration process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, 0, 2, -1, 3])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .enumerate();\n *\n * console.log(results.toObject()); // { odd: [[0, -3], [1, -1], [2, 3]], even: [[0, 0], [1, 2]] }\n * ```\n *\n * ---\n *\n * @returns A new {@link AggregatedIterator} containing the enumerated elements.\n */\n public enumerate(): AggregatedIterator<K, [number, T]>\n {\n return this.map((_, value, index) => [index, value]);\n }\n\n /**\n * Removes all duplicate elements from within each group of the iterator. \n * The first occurrence of each element will be included in the new iterator.\n *\n * Since the iterator is lazy, the deduplication process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 6, -3, -1, 0, 5, 6, 8, 0, 2])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .unique();\n *\n * console.log(results.toObject()); // { odd: [-3, -1, 3, 5], even: [0, 2, 6, 8] }\n * ```\n *\n * ---\n *\n * @returns A new {@link AggregatedIterator} containing only the unique elements.\n */\n public unique(): AggregatedIterator<K, T>\n {\n const elements = this._elements;\n\n return new AggregatedIterator(function* ()\n {\n const keys = new Map<K, Set<T>>();\n for (const [key, element] of elements)\n {\n const values = keys.get(key) ?? new Set<T>();\n if (values.has(element)) { continue; }\n\n values.add(element);\n keys.set(key, values);\n\n yield [key, element];\n }\n });\n }\n\n /**\n * Counts the number of elements within each group of the iterator. \n * This method will consume the entire iterator in the process.\n *\n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .count();\n *\n * console.log(results.toObject()); // { odd: 4, even: 4 }\n * ```\n *\n * ---\n *\n * @returns A new {@link ReducedIterator} containing the number of elements for each group.\n */\n public count(): ReducedIterator<K, number>\n {\n const counters = new Map<K, number>();\n\n for (const [key] of this._elements)\n {\n const count = counters.get(key) ?? 0;\n\n counters.set(key, count + 1);\n }\n\n return new ReducedIterator(function* ()\n {\n for (const [key, count] of counters) { yield [key, count]; }\n });\n }\n\n /**\n * Iterates over the elements of the iterator. \n * The elements are passed to the given iteratee function along with their key and index within the group.\n *\n * This method will consume the entire iterator in the process. \n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const aggregator = new SmartIterator<number>([-3, 0, 2, -1, 3])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\");\n *\n * aggregator.forEach((key, value, index) =>\n * {\n * console.log(`${index}: ${value}`); // \"0: -3\", \"0: 0\", \"1: 2\", \"1: -1\", \"2: 3\"\n * };\n * ```\n *\n * ---\n *\n * @param iteratee The function to execute for each element of the iterator.\n */\n public forEach(iteratee: KeyedIteratee<K, T>): void\n {\n const indexes = new Map<K, number>();\n for (const [key, element] of this._elements)\n {\n const index = indexes.get(key) ?? 0;\n iteratee(key, element, index);\n\n indexes.set(key, index + 1);\n }\n }\n\n /**\n * Changes the key of each element on which the iterator is aggregated. \n * The new key is determined by the given iteratee function.\n *\n * Since the iterator is lazy, the reorganization process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .map((key, value, index) => index % 2 === 0 ? value : -value)\n * .reorganizeBy((key, value) => value >= 0 ? \"+\" : \"-\");\n *\n * console.log(results.toObject()); // { \"+\": [1, 0, 3, 6], \"-\": [-3, -2, -5, -8] }\n * ```\n *\n * ---\n *\n * @template J The type of the new key.\n *\n * @param iteratee The function to determine the new key for each element of the iterator.\n *\n * @returns A new {@link AggregatedIterator} containing the elements reorganized by the new keys.\n */\n public reorganizeBy<J extends PropertyKey>(iteratee: KeyedIteratee<K, T, J>): AggregatedIterator<J, T>\n {\n const elements = this._elements;\n\n return new AggregatedIterator(function* ()\n {\n const indexes = new Map<K, number>();\n for (const [key, element] of elements)\n {\n const index = indexes.get(key) ?? 0;\n yield [iteratee(key, element, index), element];\n\n indexes.set(key, index + 1);\n }\n });\n }\n\n /**\n * An utility method that returns a new {@link SmartIterator}\n * object containing all the keys of the iterator.\n *\n * Since the iterator is lazy, the keys will be extracted\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const keys = new SmartIterator([-3, Symbol(), \"A\", { }, null, [1 , 2, 3], false])\n * .groupBy((value) => typeof value)\n * .keys();\n *\n * console.log(keys.toArray()); // [\"number\", \"symbol\", \"string\", \"object\", \"boolean\"]\n * ```\n *\n * ---\n *\n * @returns A new {@link SmartIterator} containing all the keys of the iterator.\n */\n public keys(): SmartIterator<K>\n {\n const elements = this._elements;\n\n return new SmartIterator<K>(function* ()\n {\n const keys = new Set<K>();\n for (const [key] of elements)\n {\n if (keys.has(key)) { continue; }\n keys.add(key);\n\n yield key;\n }\n });\n }\n\n /**\n * An utility method that returns a new {@link SmartIterator}\n * object containing all the entries of the iterator. \n * Each entry is a tuple containing the key and the element.\n *\n * Since the iterator is lazy, the entries will be extracted\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const entries = new SmartIterator<number>([-3, 0, 2, -1, 3])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .entries();\n *\n * console.log(entries.toArray()); // [[\"odd\", -3], [\"even\", 0], [\"even\", 2], [\"odd\", -1], [\"odd\", 3]]\n * ```\n *\n * ---\n *\n * @returns A new {@link SmartIterator} containing all the entries of the iterator.\n */\n public entries(): SmartIterator<[K, T]>\n {\n return this._elements;\n }\n\n /**\n * An utility method that returns a new {@link SmartIterator}\n * object containing all the values of the iterator.\n *\n * Since the iterator is lazy, the values will be extracted\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * const values = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\")\n * .values();\n *\n * console.log(values.toArray()); // [-3, -1, 0, 2, 3, 5, 6, 8]\n * ```\n *\n * ---\n *\n * @returns A new {@link SmartIterator} containing all the values of the iterator.\n */\n public values(): SmartIterator<T>\n {\n const elements = this._elements;\n\n return new SmartIterator<T>(function* ()\n {\n for (const [_, element] of elements) { yield element; }\n });\n }\n\n /**\n * Materializes the iterator into an array of arrays. \n * This method will consume the entire iterator in the process.\n *\n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const aggregator = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\");\n *\n * console.log(aggregator.toArray()); // [[-3, -1, 3, 5], [0, 2, 6, 8]]\n * ```\n *\n * ---\n *\n * @returns An {@link Array} of arrays containing the elements of the iterator.\n */\n public toArray(): T[][]\n {\n const map = this.toMap();\n\n return Array.from(map.values());\n }\n\n /**\n * Materializes the iterator into a map. \n * This method will consume the entire iterator in the process.\n *\n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const aggregator = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\");\n *\n * console.log(aggregator.toMap()); // Map(2) { \"odd\" => [-3, -1, 3, 5], \"even\" => [0, 2, 6, 8] }\n * ```\n *\n * ---\n *\n * @returns A {@link Map} containing the elements of the iterator.\n */\n public toMap(): Map<K, T[]>\n {\n const groups = new Map<K, T[]>();\n\n for (const [key, element] of this._elements)\n {\n const value = groups.get(key) ?? [];\n\n value.push(element);\n groups.set(key, value);\n }\n\n return groups;\n }\n\n /**\n * Materializes the iterator into an object. \n * This method will consume the entire iterator in the process.\n *\n * If the iterator is infinite, the method will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * const aggregator = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])\n * .groupBy((value) => value % 2 === 0 ? \"even\" : \"odd\");\n *\n * console.log(aggregator.toObject()); // { odd: [-3, -1, 3, 5], even: [0, 2, 6, 8] }\n * ```\n *\n * ---\n *\n * @returns An {@link Object} containing the elements of the iterator.\n */\n public toObject(): Record<K, T[]>\n {\n const groups = { } as Record<K, T[]>;\n\n for (const [key, element] of this._elements)\n {\n const value = groups[key] ?? [];\n\n value.push(element);\n groups[key] = value;\n }\n\n return groups;\n }\n\n public readonly [Symbol.toStringTag]: string = \"AggregatedIterator\";\n}\n","import type { Callback } from \"./types.js\";\n\nconst SmartFunction = (Function as unknown) as new<A extends unknown[] = [], R = void>(...args: string[])\n => (...args: A) => R;\n\n/**\n * An abstract class that can be used to implement callable objects.\n *\n * ---\n *\n * @example\n * ```ts\n * class ActivableCallback extends CallableObject<(evt: PointerEvent) => void>\n * {\n * public enabled = false;\n * protected _invoke(): void\n * {\n * if (this.enabled) { [...] }\n * }\n * }\n *\n * const callback = new ActivableCallback();\n *\n * window.addEventListener(\"pointerdown\", () => { callback.enabled = true; });\n * window.addEventListener(\"pointermove\", callback);\n * window.addEventListener(\"pointerup\", () => { callback.enabled = false; });\n * ```\n *\n * ---\n *\n * @template T\n * The type signature of the callback function. \n * It must be a function. Default is `(...args: any[]) => any`.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport default abstract class CallableObject<T extends Callback<any[], any> = () => void>\n extends SmartFunction<Parameters<T>, ReturnType<T>>\n{\n /**\n * Initializes a new instance of the {@link CallableObject} class.\n */\n public constructor()\n {\n super(`return this._invoke(...arguments);`);\n\n const self = this.bind(this);\n Object.setPrototypeOf(this, self);\n\n return self as this;\n }\n\n /**\n * The method that will be called when the object is invoked. \n * It must be implemented by the derived classes.\n *\n * ---\n *\n * @param args The arguments that have been passed to the object.\n *\n * @returns The return value of the method.\n */\n protected abstract _invoke(...args: Parameters<T>): ReturnType<T>;\n\n public readonly [Symbol.toStringTag]: string = \"CallableObject\";\n}\n","import { ReferenceException } from \"../exceptions/index.js\";\n\nimport type { Callback, CallbackMap, WithWildcard } from \"./types.js\";\n\n/**\n * A class implementing the\n * {@link https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern|Publish-subscribe} pattern.\n *\n * It can be used to create a simple event system where objects can subscribe\n * to events and receive notifications when the events are published. \n * It's a simple and efficient way to decouple the objects and make them communicate with each other.\n *\n * Using generics, it's also possible to define the type of the events and the callbacks that can be subscribed to them.\n *\n * ---\n *\n * @example\n * ```ts\n * interface EventsMap\n * {\n * \"player:spawn\": (evt: SpawnEvent) => void;\n * \"player:move\": ({ x, y }: Point) => void;\n * \"player:death\": () => void;\n * }\n *\n * const publisher = new Publisher<EventsMap>();\n *\n * let unsubscribe: () => void;\n * publisher.subscribe(\"player:death\", unsubscribe);\n * publisher.subscribe(\"player:spawn\", (evt) =>\n * {\n * unsubscribe = publisher.subscribe(\"player:move\", ({ x, y }) => { [...] });\n * });\n * ```\n *\n * ---\n *\n * @template T\n * A map containing the names of the emittable events and the\n * related callback signatures that can be subscribed to them. \n * Default is `Record<string, (...args: unknown[]) => unknown>`.\n *\n * @template E An utility type that extends the `T` map with a wildcard event.\n */\nexport default class Publisher<T extends CallbackMap<T> = CallbackMap, W extends WithWildcard<T> = WithWildcard<T>>\n{\n /**\n * A map containing all the subscribers for each event.\n *\n * The keys are the names of the events they are subscribed to. \n * The values are the arrays of the subscribers themselves.\n */\n protected readonly _subscribers: Map<string, Callback<unknown[], unknown>[]>;\n\n /**\n * Initializes a new instance of the {@link Publisher} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const publisher = new Publisher();\n * ```\n */\n public constructor()\n {\n this._subscribers = new Map();\n }\n\n /**\n * Unsubscribes all the subscribers from all the events.\n *\n * ---\n *\n * @example\n * ```ts\n * publisher.subscribe(\"player:spawn\", (evt) => { [...] });\n * publisher.subscribe(\"player:move\", (coords) => { [...] });\n * publisher.subscribe(\"player:move\", () => { [...] });\n * publisher.subscribe(\"player:move\", ({ x, y }) => { [...] });\n * publisher.subscribe(\"player:death\", () => { [...] });\n *\n * // All these subscribers are working fine...\n *\n * publisher.clear();\n *\n * // ... but now they're all gone!\n * ```\n */\n public clear(): void\n {\n // @ts-expect-error It's an internal event, not part of the public API.\n this.publish(\"__internals__:clear\");\n\n this._subscribers.clear();\n }\n\n /**\n * Creates a new scoped instance of the {@link Publisher} class,\n * which can be used to publish and subscribe events within a specific context.\n *\n * It can receive all events published to the parent publisher while also allowing\n * the scoped publisher to handle its own events independently. \n * In fact, events published to the scoped publisher won't be propagated back to the parent publisher.\n *\n * ---\n *\n * @example\n * ```ts\n * const publisher = new Publisher();\n * const context = publisher.createScope();\n *\n * publisher.subscribe(\"player:death\", () => { console.log(`Player has died.`); });\n * context.subscribe(\"player:spawn\", () => { console.log(`Player has spawned.`); });\n *\n * publisher.publish(\"player:spawn\"); // Player has spawned.\n * context.publish(\"player:death\"); // * no output *\n * ```\n *\n * ---\n *\n * @template U\n * A map containing the names of the emittable events and the\n * related callback signatures that can be subscribed to them.\n * Default is `T`.\n *\n * @template X An utility type that extends the `U` map with a wildcard event.\n */\n public createScope<U extends T = T, X extends WithWildcard<U> = WithWildcard<U>>(): Publisher<U, X>\n {\n const scope = new Publisher<U, X>();\n\n const propagator = (event: (keyof T) & string, ...args: Parameters<T[keyof T]>): void =>\n {\n scope.publish(event, ...args);\n };\n\n // @ts-expect-error It's an internal event, not part of the public API.\n this.subscribe(\"__internals__:clear\", () => scope.clear());\n this.subscribe(\"*\", propagator as W[\"*\"]);\n\n return scope;\n }\n\n /**\n * Publishes an event to all the subscribers.\n *\n * ---\n *\n * @example\n * ```ts\n * publisher.subscribe(\"player:move\", (coords) => { [...] });\n * publisher.subscribe(\"player:move\", ({ x, y }) => { [...] });\n * publisher.subscribe(\"player:move\", (evt) => { [...] });\n *\n * publisher.publish(\"player:move\", { x: 10, y: 20 });\n * ```\n *\n * ---\n *\n * @template K The key of the map containing the callback signature to publish.\n *\n * @param event The name of the event to publish.\n * @param args The arguments to pass to the subscribers.\n *\n * @returns An array containing the return values of all the subscribers.\n */\n public publish<K extends keyof T>(event: K & string, ...args: Parameters<T[K]>): ReturnType<T[K]>[]\n {\n let results: ReturnType<T[K]>[];\n let subscribers = this._subscribers.get(event);\n if (subscribers)\n {\n results = subscribers.slice()\n .map((subscriber) => subscriber(...args)) as ReturnType<T[K]>[];\n }\n else { results = []; }\n\n if (!(event.startsWith(\"__\")))\n {\n subscribers = this._subscribers.get(\"*\");\n if (subscribers)\n {\n subscribers.slice()\n .forEach((subscriber) => subscriber(event, ...args));\n }\n }\n\n return results;\n }\n\n /**\n * Subscribes to an event and adds a subscriber to be executed when the event is published.\n *\n * ---\n *\n * @example\n * ```ts\n * let unsubscribe: () => void;\n * publisher.subscribe(\"player:death\", unsubscribe);\n * publisher.subscribe(\"player:spawn\", (evt) =>\n * {\n * unsubscribe = publisher.subscribe(\"player:move\", ({ x, y }) => { [...] });\n * });\n * ```\n *\n * ---\n *\n * @template K The key of the map containing the callback signature to subscribe.\n *\n * @param event The name of the event to subscribe to.\n * @param subscriber The subscriber to execute when the event is published.\n *\n * @returns A function that can be used to unsubscribe the subscriber from the event.\n */\n public subscribe<K extends keyof W>(event: K & string, subscriber: W[K]): () => void\n {\n const subscribers = this._subscribers.get(event) ?? [];\n subscribers.push(subscriber);\n\n this._subscribers.set(event, subscribers);\n\n return () =>\n {\n const index = subscribers.indexOf(subscriber);\n if (index < 0)\n {\n throw new ReferenceException(\"Unable to unsubscribe the required subscriber. \" +\n \"The subscription was already unsubscribed.\");\n }\n\n subscribers.splice(index, 1);\n };\n }\n\n /**\n * Unsubscribes from an event and removes a subscriber from being executed when the event is published.\n *\n * ---\n *\n * @example\n * ```ts\n * const onPlayerMove = ({ x, y }: Point) => { [...] };\n *\n * publisher.subscribe(\"player:spawn\", (evt) => publisher.subscribe(\"player:move\", onPlayerMove));\n * publisher.subscribe(\"player:death\", () => publisher.unsubscribe(\"player:move\", onPlayerMove));\n * ```\n *\n * ---\n *\n * @template K The key of the map containing the callback signature to unsubscribe.\n *\n * @param event The name of the event to unsubscribe from.\n * @param subscriber The subscriber to remove from the event.\n */\n public unsubscribe<K extends keyof W>(event: K & string, subscriber: W[K]): void\n {\n const subscribers = this._subscribers.get(event);\n if (!(subscribers))\n {\n throw new ReferenceException(\"Unable to unsubscribe the required subscriber. \" +\n \"The subscription was already unsubscribed or was never subscribed.\");\n }\n\n const index = subscribers.indexOf(subscriber);\n if (index < 0)\n {\n throw new ReferenceException(\"Unable to unsubscribe the required subscriber. \" +\n \"The subscription was already unsubscribed or was never subscribed.\");\n }\n\n subscribers.splice(index, 1);\n if (subscribers.length === 0) { this._subscribers.delete(event); }\n }\n\n public readonly [Symbol.toStringTag]: string = \"Publisher\";\n}\n","import { KeyException, NotImplementedException, RuntimeException } from \"../exceptions/index.js\";\n\nimport CallableObject from \"./callable-object.js\";\nimport type { Callback } from \"./types.js\";\n\nconst Disabler = () => { /* ... */ };\n\n/**\n * A class representing a callback that can be switched between multiple implementations.\n *\n * It can be used to implement different behaviors for the same event handler, allowing\n * it to respond to different states without incurring any overhead during execution.\n *\n * ---\n *\n * @example\n * ```ts\n * const onPointerMove = new SwitchableCallback<(evt: PointerEvent) => void>();\n *\n * onPointerMove.register(\"released\", () => { [...] });\n * onPointerMove.register(\"pressed\", () => { [...] });\n *\n * window.addEventListener(\"pointerdown\", () => { onPointerMove.switch(\"pressed\"); });\n * window.addEventListener(\"pointermove\", onPointerMove);\n * window.addEventListener(\"pointerup\", () => { onPointerMove.switch(\"released\"); });\n * ```\n *\n * ---\n *\n * @template T The type signature of the callback. Default is `(...args: any[]) => any`.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport default class SwitchableCallback<T extends Callback<any[], any> = Callback> extends CallableObject<T>\n{\n /**\n * The currently selected implementation of the callback.\n */\n protected _callback: T;\n\n /**\n * All the implementations that have been registered for the callback.\n *\n * The keys are the names of the implementations they were registered with. \n * The values are the implementations themselves.\n */\n protected readonly _callbacks: Map<string, T>;\n\n /**\n * A flag indicating whether the callback is enabled or not.\n *\n * This protected property is the only one that can be modified directly by the derived classes. \n * If you're looking for the public and readonly property, use\n * the {@link SwitchableCallback.isEnabled} getter instead.\n */\n protected _isEnabled: boolean;\n\n /**\n * A flag indicating whether the callback is enabled or not.\n *\n * It indicates whether the callback is currently able to execute the currently selected implementation. \n * If it's disabled, the callback will be invoked without executing anything.\n */\n public get isEnabled(): boolean { return this._isEnabled; }\n\n /**\n * The key that is associated with the currently selected implementation.\n *\n * This protected property is the only one that can be modified directly by the derived classes. \n * If you're looking for the public and readonly property, use the {@link SwitchableCallback.key} getter instead.\n */\n protected _key: string;\n\n /**\n * The key that is associated with the currently selected implementation.\n */\n public get key(): string { return this._key; }\n\n /**\n * The function that will be called by the extended class when the object is invoked as a function.\n */\n protected readonly _invoke: (...args: Parameters<T>) => ReturnType<T>;\n\n /**\n * Initializes a new instance of the {@link SwitchableCallback} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const onPointerMove = new SwitchableCallback<(evt: PointerEvent) => void>();\n * ```\n */\n public constructor();\n\n /**\n * Initializes a new instance of the {@link SwitchableCallback}\n * class with the specified callback enabled by default.\n *\n * ---\n *\n * @example\n * ```ts\n * const onPointerMove = new SwitchableCallback<(evt: PointerEvent) => void>((evt) => { [...] });\n * ```\n *\n * ---\n *\n * @param callback The callback that will be executed when the object is invoked as a function by default.\n * @param key The key that is associated by default to the given callback. Default is `default`.\n */\n public constructor(callback: T, key?: string);\n public constructor(callback?: T, key = \"default\")\n {\n super();\n\n this._callbacks = new Map<string, T>();\n this._isEnabled = true;\n\n if (callback)\n {\n this._callbacks.set(key, callback);\n }\n else\n {\n key = \"\";\n\n callback = ((() =>\n {\n throw new NotImplementedException(\n \"The `SwitchableCallback` has no callback defined yet. \" +\n \"Did you forget to call the `register` method?\"\n );\n\n }) as unknown) as T;\n }\n\n this._key = key;\n\n this._callback = callback;\n this._invoke = (...args: Parameters<T>): ReturnType<T> => this._callback(...args);\n }\n\n /**\n * Enables the callback, allowing it to execute the currently selected implementation.\n *\n * Also note that:\n * - If any implementation has been registered yet, a {@link KeyException} will be thrown. \n * - If any key is given and it doesn't have any associated\n * implementation yet, a {@link KeyException} will be thrown.\n * - If the callback is already enabled, a {@link RuntimeException} will be thrown.\n *\n * ---\n *\n * @example\n * ```ts\n * window.addEventListener(\"pointerdown\", () => { onPointerMove.enable(); });\n * window.addEventListener(\"pointermove\", onPointerMove);\n * ```\n *\n * ---\n *\n * @param key\n * The key that is associated with the implementation to enable. Default is the currently selected implementation.\n */\n public enable(key?: string): void\n {\n if (key === undefined)\n {\n if (!(this._key))\n {\n throw new KeyException(\n \"The `SwitchableCallback` has no callback defined yet. \" +\n \"Did you forget to call the `register` method?\"\n );\n }\n\n key = this._key;\n }\n else if (!(key))\n {\n throw new KeyException(\"The key must be a non-empty string.\");\n }\n else if (!(this._callbacks.has(key)))\n {\n throw new KeyException(`The key '${key}' doesn't yet have any associated callback.`);\n }\n\n if (this._isEnabled)\n {\n throw new RuntimeException(\"The `SwitchableCallback` is already enabled.\");\n }\n\n this._callback = this._callbacks.get(key)!;\n this._isEnabled = true;\n }\n\n /**\n * Disables the callback, allowing it to be invoked without executing any implementation.\n *\n * If the callback is already disabled, a {@link RuntimeException} will be thrown.\n *\n * ---\n *\n * @example\n * ```ts\n * window.addEventListener(\"pointermove\", onPointerMove);\n * window.addEventListener(\"pointerup\", () => { onPointerMove.disable(); });\n * ```\n */\n public disable(): void\n {\n if (!(this._isEnabled))\n {\n throw new RuntimeException(\"The `SwitchableCallback` is already disabled.\");\n }\n\n this._callback = Disabler as T;\n this._isEnabled = false;\n }\n\n /**\n * Registers a new implementation for the callback.\n *\n * Also note that:\n * - If the callback has no other implementation registered yet, this one will be selected as default.\n * - If the key has already been used for another implementation, a {@link KeyException} will be thrown.\n *\n * ---\n *\n * @example\n * ```ts\n * onPointerMove.register(\"pressed\", () => { [...] });\n * onPointerMove.register(\"released\", () => { [...] });\n * ```\n *\n * ---\n *\n * @param key The key that will be associated with the implementation.\n * @param callback The implementation to register.\n */\n public register(key: string, callback: T): void\n {\n if (this._callbacks.size === 0)\n {\n this._key = key;\n this._callback = callback;\n }\n else if (this._callbacks.has(key))\n {\n throw new KeyException(`The key '${key}' has already been used for another callback.`);\n }\n\n this._callbacks.set(key, callback);\n }\n\n /**\n * Unregisters an implementation for the callback.\n *\n * Also note that:\n * - If the key is the currently selected implementation, a {@link KeyException} will be thrown.\n * - If the key has no associated implementation yet, a {@link KeyException} will be thrown.\n *\n * ---\n *\n * @example\n * ```ts\n * onPointerMove.unregister(\"released\");\n * ```\n *\n * ---\n *\n * @param key The key that is associated with the implementation to unregister.\n */\n public unregister(key: string): void\n {\n if (this._key === key)\n {\n throw new KeyException(\"Unable to unregister the currently selected callback.\");\n }\n if (!(this._callbacks.has(key)))\n {\n throw new KeyException(`The key '${key}' doesn't yet have any associated callback.`);\n }\n\n this._callbacks.delete(key);\n }\n\n /**\n * Switches the callback to the implementation associated with the given key.\n *\n * If the key has no associated implementation yet, a {@link KeyException} will be thrown.\n *\n * ---\n *\n * @example\n * ```ts\n * window.addEventListener(\"pointerdown\", () => { onPointerMove.switch(\"pressed\"); });\n * window.addEventListener(\"pointermove\", onPointerMove);\n * window.addEventListener(\"pointerup\", () => { onPointerMove.switch(\"released\"); });\n * ```\n *\n * ---\n *\n * @param key The key that is associated with the implementation to switch to.\n */\n public switch(key: string): void\n {\n if (!(this._callbacks.has(key)))\n {\n throw new KeyException(`The key '${key}' doesn't yet have any associated callback.`);\n }\n\n if (this._key === key) { return; }\n this._key = key;\n\n if (this._isEnabled)\n {\n this._callback = this._callbacks.get(key)!;\n }\n }\n\n public override readonly [Symbol.toStringTag]: string = \"SwitchableCallback\";\n}\n","import Publisher from \"../callbacks/publisher.js\";\nimport type { WithWildcard } from \"../callbacks/types.js\";\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport type SetView from \"./set-view.js\";\nimport type { MapViewEventsMap } from \"./types.js\";\n\n/**\n * A wrapper class around the native {@link Map} class that provides additional functionality\n * for publishing events when entries are added, removed or the collection is cleared. \n * There's also a complementary class that works with the native `Set` class.\n * See also {@link SetView}.\n *\n * ---\n *\n * @example\n * ```ts\n * const map = new MapView<string, number>();\n *\n * map.subscribe(\"entry:add\", (key: string, value: number) => console.log(`Added ${key}: ${value}`));\n * map.set(\"answer\", 42); // Added answer: 42\n * ```\n *\n * ---\n *\n * @template K The type of the keys in the map.\n * @template V The type of the values in the map.\n */\nexport default class MapView<K, V> extends Map<K, V>\n{\n /**\n * The internal {@link Publisher} instance used to publish events.\n */\n protected readonly _publisher: Publisher<MapViewEventsMap<K, V>>;\n\n /**\n * Initializes a new instance of the {@link MapView} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const map = new MapView<string, number>([[\"key1\", 2], [\"key2\", 4], [\"key3\", 8]]);\n * ```\n *\n * ---\n *\n * @param iterable An optional iterable of key-value pairs to initialize the {@link Map} with.\n */\n public constructor(iterable?: Iterable<[K, V]> | null)\n {\n super();\n\n this._publisher = new Publisher();\n\n if (iterable)\n {\n for (const [key, value] of iterable) { this.set(key, value); }\n }\n }\n\n /**\n * Adds a new entry with a specified key and value to the {@link Map}. \n * If an entry with the same key already exists, the entry will be overwritten with the new value.\n *\n * ---\n *\n * @example\n * ```ts\n * const map = new MapView<string, number>();\n * map.set(\"key1\", 2)\n * .set(\"key2\", 4)\n * .set(\"key3\", 8);\n *\n * console.log(map); // MapView { \"key1\" => 2, \"key2\" => 4, \"key3\" => 8 }\n * ```\n *\n * ---\n *\n * @param key The key of the entry to add.\n * @param value The value of the entry to add.\n *\n * @returns The current instance of the {@link MapView} class.\n */\n public override set(key: K, value: V): this\n {\n super.set(key, value);\n\n this._publisher.publish(\"entry:add\", key, value);\n\n return this;\n }\n\n /**\n * Removes an entry with a specified key from the {@link Map}.\n *\n * ---\n *\n * @example\n * ```ts\n * const map = new MapView<string, number>([[\"key1\", 2], [\"key2\", 4], [\"key3\", 8]]);\n * map.delete(\"key2\"); // true\n * map.delete(\"key4\"); // false\n *\n * console.log(map); // MapView { \"key1\" => 2, \"key3\" => 8 }\n * ```\n *\n * ---\n *\n * @param key The key of the entry to remove.\n *\n * @returns `true` if the entry existed and has been removed; otherwise `false` if the entry doesn't exist.\n */\n public override delete(key: K): boolean\n {\n const value = this.get(key);\n if (value === undefined) { return false; }\n\n super.delete(key);\n\n this._publisher.publish(\"entry:remove\", key, value);\n\n return true;\n }\n\n /**\n * Removes all entries from the {@link Map}.\n *\n * ---\n *\n * @example\n * ```ts\n * const map = new MapView<string, number>([[\"key1\", 2], [\"key2\", 4], [\"key3\", 8]]);\n * map.clear();\n *\n * console.log(map); // MapView { }\n * ```\n */\n public override clear(): void\n {\n const size = this.size;\n\n super.clear();\n if (size > 0) { this._publisher.publish(\"collection:clear\"); }\n }\n\n /**\n * Subscribes to an event and adds a callback to be executed when the event is published.\n *\n * ---\n *\n * @example\n * ```ts\n * const map = new MapView<string, number>();\n * const unsubscribe = map.subscribe(\"entry:add\", (key: string, value: number) =>\n * {\n * if (key === \"answer\") { unsubscribe(); }\n * console.log(`Added ${key}: ${value}`);\n * });\n *\n * map.set(\"key1\", 2); // Added key1: 2\n * map.set(\"answer\", 42); // Added answer: 42\n * map.set(\"key2\", 4);\n * map.set(\"key3\", 8);\n * ```\n *\n * ---\n *\n * @template T The key of the map containing the callback signature to subscribe.\n *\n * @param event The name of the event to subscribe to.\n * @param callback The callback to execute when the event is published.\n *\n * @returns A function that can be used to unsubscribe the callback from the event.\n */\n public subscribe<T extends keyof WithWildcard<MapViewEventsMap<K, V>>>(\n event: T & string, callback: WithWildcard<MapViewEventsMap<K, V>>[T]\n ): () => void\n {\n return this._publisher.subscribe(event, callback);\n }\n\n /**\n * Unsubscribes from an event and removes a callback from being executed when the event is published.\n *\n * ---\n *\n * @example\n * ```ts\n * const callback = (key: string, value: number) => console.log(`Added ${key}: ${value}`);\n * const map = new MapView<string, number>();\n *\n * map.subscribe(\"entry:add\", callback);\n * map.set(\"key1\", 2); // Added key1: 2\n *\n * map.unsubscribe(\"entry:add\", callback);\n * map.set(\"key2\", 4);\n * ```\n *\n * ---\n *\n * @template T The key of the map containing the callback signature to unsubscribe.\n *\n * @param event The name of the event to unsubscribe from.\n * @param callback The callback to remove from the event.\n */\n public unsubscribe<T extends keyof WithWildcard<MapViewEventsMap<K, V>>>(\n event: T & string, callback: WithWildcard<MapViewEventsMap<K, V>>[T]): void\n {\n this._publisher.unsubscribe(event, callback);\n }\n\n public override readonly [Symbol.toStringTag]: string = \"MapView\";\n}\n","import Publisher from \"../callbacks/publisher.js\";\nimport type { WithWildcard } from \"../callbacks/types.js\";\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport type MapView from \"./map-view.js\";\nimport type { SetViewEventsMap } from \"./types.js\";\n\n/**\n * A wrapper class around the native {@link Set} class that provides additional functionality\n * for publishing events when entries are added, removed or the collection is cleared. \n * There's also a complementary class that works with the native `Map` class.\n * See also {@link MapView}.\n *\n * ---\n *\n * @example\n * ```ts\n * const set = new SetView<number>();\n *\n * set.subscribe(\"entry:add\", (value: number) => console.log(`Added ${value}`));\n * set.add(42); // Added 42\n * ```\n *\n * ---\n *\n * @template T The type of the values in the set.\n */\nexport default class SetView<T> extends Set<T>\n{\n /**\n * The internal {@link Publisher} instance used to publish events.\n */\n protected readonly _publisher: Publisher<SetViewEventsMap<T>>;\n\n /**\n * Initializes a new instance of the {@link SetView} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const set = new SetView<number>([2, 4, 8]);\n * ```\n *\n * ---\n *\n * @param iterable An optional iterable of values to initialize the {@link Set} with.\n */\n public constructor(iterable?: Iterable<T> | null)\n {\n super();\n\n this._publisher = new Publisher();\n\n if (iterable)\n {\n for (const value of iterable) { this.add(value); }\n }\n }\n\n /**\n * Appends a new element with a specified value to the end of the {@link Set}. \n * If the value already exists, it will not be added again.\n *\n * ---\n *\n * @example\n * ```ts\n * const set = new SetView<number>();\n * set.add(2)\n * .add(4)\n * .add(8);\n *\n * console.log(set); // SetView(4) { 2, 4, 8 }\n * ```\n *\n * ---\n *\n * @param value The value to add.\n *\n * @returns The current instance of the {@link SetView} class.\n */\n public override add(value: T): this\n {\n super.add(value);\n\n this._publisher.publish(\"entry:add\", value);\n\n return this;\n }\n\n /**\n * Removes the specified value from the {@link Set}.\n *\n * ---\n *\n * @example\n * ```ts\n * const set = new SetView<number>([2, 4, 8]);\n * set.delete(4); // true\n * set.delete(16); // false\n *\n * console.log(set); // SetView(2) { 2, 8 }\n * ```\n *\n * ---\n *\n * @param value The value to remove.\n *\n * @returns `true` if the entry existed and has been removed; otherwise `false` if the entry doesn't exist.\n */\n public override delete(value: T): boolean\n {\n const result = super.delete(value);\n if (result) { this._publisher.publish(\"entry:remove\", value); }\n\n return result;\n }\n\n /**\n * Removes all entries from the {@link Set}.\n *\n * ---\n *\n * @example\n * ```ts\n * const set = new SetView<number>([2, 4, 8]);\n * set.clear();\n *\n * console.log(set); // SetView(0) { }\n * ```\n */\n public override clear(): void\n {\n const size = this.size;\n\n super.clear();\n if (size > 0) { this._publisher.publish(\"collection:clear\"); }\n }\n\n /**\n * Subscribes to an event and adds a callback to be executed when the event is published.\n *\n * ---\n *\n * @example\n * ```ts\n * const set = new SetView<number>();\n * const unsubscribe = set.subscribe(\"entry:add\", (value: number) =>\n * {\n * if (value === 42) { unsubscribe(); }\n * console.log(`Added ${value}`);\n * });\n *\n * set.add(2); // Added 2\n * set.add(42); // Added 42\n * set.add(4);\n * set.add(8);\n * ```\n *\n * ---\n *\n * @template K The key of the map containing the callback signature to subscribe.\n *\n * @param event The name of the event to subscribe to.\n * @param callback The callback to execute when the event is published.\n *\n * @returns A function that can be used to unsubscribe the callback from the event.\n */\n public subscribe<K extends keyof WithWildcard<SetViewEventsMap<T>>>(\n event: K & string, callback: WithWildcard<SetViewEventsMap<T>>[K]\n ): () => void\n {\n return this._publisher.subscribe(event, callback);\n }\n\n /**\n * Unsubscribes from an event and removes a callback from being executed when the event is published.\n *\n * ---\n *\n * @example\n * ```ts\n * const callback = (value: number) => console.log(`Added ${value}`);\n * const set = new SetView<number>();\n *\n * set.subscribe(\"entry:add\", callback);\n * set.add(2); // Added 2\n *\n * set.unsubscribe(\"entry:add\", callback);\n * set.add(4);\n * ```\n *\n * ---\n *\n * @template K The key of the map containing the callback signature to unsubscribe.\n *\n * @param event The name of the event to unsubscribe from.\n * @param callback The callback to remove from the event.\n */\n public unsubscribe<K extends keyof WithWildcard<SetViewEventsMap<T>>>(\n event: K & string, callback: WithWildcard<SetViewEventsMap<T>>[K]\n ): void\n {\n this._publisher.unsubscribe(event, callback);\n }\n\n public override readonly [Symbol.toStringTag]: string = \"SetView\";\n}\n","import { isBrowser } from \"../../helpers.js\";\nimport { EnvironmentException } from \"../exceptions/index.js\";\n\nimport type { JSONValue } from \"./types.js\";\n\n/**\n * A wrapper around the {@link Storage} API to better store and easily retrieve\n * typed JSON values using the classical key-value pair storage system.\n *\n * It allows to handle either the volatile {@link sessionStorage} or the persistent\n * {@link localStorage} at the same time, depending on what's your required use case.\n *\n * ---\n *\n * @example\n * ```ts\n * const jsonStorage = new JSONStorage();\n *\n * jsonStorage.write(\"user:cookieAck\", { value: true, version: \"2023-02-15\" });\n * // ... between sessions ...\n * const cookieAck = jsonStorage.read<{ value: boolean; version: string; }>(\"user:cookieAck\");\n * ```\n */\nexport default class JSONStorage\n{\n /**\n * Whether to prefer the {@link localStorage} over the {@link sessionStorage} when calling an ambivalent method.\n *\n * If `true`, the persistent storage is preferred. If `false`, the volatile storage is preferred. \n * Default is `true`.\n */\n protected readonly _preferPersistence: boolean;\n\n /**\n * A reference to the volatile {@link sessionStorage} storage.\n */\n protected readonly _volatile: Storage;\n\n /**\n * A reference to the persistent {@link localStorage} storage.\n */\n protected readonly _persistent: Storage;\n\n /**\n * Initializes a new instance of the {@link JSONStorage} class. \n * It cannot be instantiated outside of a browser environment or an {@link EnvironmentException} is thrown.\n *\n * ---\n *\n * @example\n * ```ts\n * const jsonStorage = new JSONStorage();\n * ```\n *\n * ---\n *\n * @param preferPersistence\n * Whether to prefer the {@link localStorage} over the {@link sessionStorage} when calling an ambivalent method. \n * If omitted, it defaults to `true` to prefer the persistent storage.\n */\n public constructor(preferPersistence = true)\n {\n if (!(isBrowser))\n {\n throw new EnvironmentException(\n \"The `JSONStorage` class can only be instantiated within a browser environment.\"\n );\n }\n\n this._preferPersistence = preferPersistence;\n\n this._volatile = window.sessionStorage;\n this._persistent = window.localStorage;\n }\n\n protected _get<T extends JSONValue>(storage: Storage, key: string): T | undefined;\n protected _get<T extends JSONValue>(storage: Storage, key: string, defaultValue: T): T;\n protected _get<T extends JSONValue>(storage: Storage, key: string, defaultValue?: T): T | undefined;\n protected _get<T extends JSONValue>(storage: Storage, key: string, defaultValue?: T): T | undefined\n {\n const value = storage.getItem(key);\n if (value)\n {\n try\n {\n return JSON.parse(value);\n }\n catch\n {\n // eslint-disable-next-line no-console\n console.warn(\n `The \"${value}\" value for \"${key}\"` +\n \" property cannot be parsed. Clearing the storage...\");\n\n storage.removeItem(key);\n }\n }\n\n return defaultValue;\n }\n protected _set<T extends JSONValue>(storage: Storage, key: string, newValue?: T): void\n {\n const encodedValue = JSON.stringify(newValue);\n if (encodedValue)\n {\n storage.setItem(key, encodedValue);\n }\n else\n {\n storage.removeItem(key);\n }\n }\n\n /**\n * Retrieves the value with the specified key from the default storage.\n *\n * ---\n *\n * @example\n * ```ts\n * const value: TValue = jsonStorage.get<TValue>(\"key\");\n * ```\n *\n * ---\n *\n * @template T The type of the value to retrieve.\n *\n * @param key The key of the value to retrieve.\n *\n * @returns The value with the specified key or `undefined` if the key doesn't exist.\n */\n public get<T extends JSONValue>(key: string): T | undefined;\n\n /**\n * Retrieves the value with the specified key from the default storage.\n *\n * ---\n *\n * @example\n * ```ts\n * const value: TValue = jsonStorage.get<TValue>(\"key\", defaultValue);\n * ```\n *\n * ---\n *\n * @template T The type of the value to retrieve.\n *\n * @param key The key of the value to retrieve.\n * @param defaultValue The default value to return if the key doesn't exist.\n * @param persistent\n * Whether to prefer the persistent {@link localStorage} over the volatile {@link sessionStorage}. \n * If omitted, it defaults to the `preferPersistence` value set in the constructor.\n *\n * @returns The value with the specified key or the provided default value if the key doesn't exist.\n */\n public get<T extends JSONValue>(key: string, defaultValue: T, persistent?: boolean): T;\n\n /**\n * Retrieves the value with the specified key from the default storage.\n *\n * ---\n *\n * @example\n * ```ts\n * const value: TValue = jsonStorage.get<TValue>(\"key\", obj?.value);\n * ```\n *\n * ---\n *\n * @template T The type of the value to retrieve.\n *\n * @param key The key of the value to retrieve.\n * @param defaultValue The default value to return (which may be `undefined`) if the key doesn't exist.\n * @param persistent\n * Whether to prefer the persistent {@link localStorage} over the volatile {@link sessionStorage}. \n * If omitted, it defaults to the `preferPersistence` value set in the constructor.\n *\n * @returns The value with the specified key or the default value if the key doesn't exist.\n */\n public get<T extends JSONValue>(key: string, defaultValue?: T, persistent?: boolean): T | undefined;\n public get<T extends JSONValue>(key: string, defaultValue?: T, persistent = this._preferPersistence)\n : T | undefined\n {\n const storage = persistent ? this._persistent : this._volatile;\n\n return this._get<T>(storage, key, defaultValue);\n }\n\n /**\n * Retrieves the value with the specified key from the volatile {@link sessionStorage}.\n *\n * ---\n *\n * @example\n * ```ts\n * const value: TValue = jsonStorage.recall<TValue>(\"key\");\n * ```\n *\n * ---\n *\n * @template T The type of the value to retrieve.\n *\n * @param key The key of the value to retrieve.\n *\n * @returns The value with the specified key or `undefined` if the key doesn't exist.\n */\n public recall<T extends JSONValue>(key: string): T | undefined;\n\n /**\n * Retrieves the value with the specified key from the volatile {@link sessionStorage}.\n *\n * ---\n *\n * @example\n * ```ts\n * const value: TValue = jsonStorage.recall<TValue>(\"key\", defaultValue);\n * ```\n *\n * ---\n *\n * @template T The type of the value to retrieve.\n *\n * @param key The key of the value to retrieve.\n * @param defaultValue The default value to return if the key doesn't exist.\n *\n * @returns The value with the specified key or the default value if the key doesn't exist.\n */\n public recall<T extends JSONValue>(key: string, defaultValue: T): T;\n\n /**\n * Retrieves the value with the specified key from the volatile {@link sessionStorage}.\n *\n * ---\n *\n * @example\n * ```ts\n * const value: TValue = jsonStorage.recall<TValue>(\"key\", obj?.value);\n * ```\n *\n * ---\n *\n * @template T The type of the value to retrieve.\n *\n * @param key The key of the value to retrieve.\n * @param defaultValue The default value to return (which may be `undefined`) if the key doesn't exist.\n *\n * @returns The value with the specified key or the default value if the key doesn't exist.\n */\n public recall<T extends JSONValue>(key: string, defaultValue?: T): T | undefined;\n public recall<T extends JSONValue>(key: string, defaultValue?: T): T | undefined\n {\n return this._get<T>(this._volatile, key, defaultValue);\n }\n\n /**\n * Retrieves the value with the specified key looking first in the volatile\n * {@link sessionStorage} and then, if not found, in the persistent {@link localStorage}.\n *\n * ---\n *\n * @example\n * ```ts\n * const value: TValue = jsonStorage.retrieve<TValue>(\"key\");\n * ```\n *\n * ---\n *\n * @template T The type of the value to retrieve.\n *\n * @param key The key of the value to retrieve.\n *\n * @returns The value with the specified key or `undefined` if the key doesn't exist.\n */\n public retrieve<T extends JSONValue>(key: string): T | undefined;\n\n /**\n * Retrieves the value with the specified key looking first in the volatile\n * {@link sessionStorage} and then, if not found, in the persistent {@link localStorage}.\n *\n * ---\n *\n * @example\n * ```ts\n * const value: TValue = jsonStorage.retrieve<TValue>(\"key\", defaultValue);\n * ```\n *\n * ---\n *\n * @template T The type of the value to retrieve.\n *\n * @param key The key of the value to retrieve.\n * @param defaultValue The default value to return if the key doesn't exist.\n *\n * @returns The value with the specified key or the default value if the key doesn't exist.\n */\n public retrieve<T extends JSONValue>(key: string, defaultValue: T): T;\n\n /**\n * Retrieves the value with the specified key looking first in the volatile\n * {@link sessionStorage} and then, if not found, in the persistent {@link localStorage}.\n *\n * ---\n *\n * @example\n * ```ts\n * const value: TValue = jsonStorage.retrieve<TValue>(\"key\", obj?.value);\n * ```\n *\n * ---\n *\n * @template T The type of the value to retrieve.\n *\n * @param key The key of the value to retrieve.\n * @param defaultValue The default value to return (which may be `undefined`) if the key doesn't exist.\n *\n * @returns The value with the specified key or the default value if the key doesn't exist.\n */\n public retrieve<T extends JSONValue>(key: string, defaultValue?: T): T | undefined;\n public retrieve<T extends JSONValue>(key: string, defaultValue?: T): T | undefined\n {\n return this.recall<T>(key) ?? this.read<T>(key, defaultValue);\n }\n\n /**\n * Retrieves the value with the specified key from the persistent {@link localStorage}.\n *\n * ---\n *\n * @example\n * ```ts\n * const value: TValue = jsonStorage.read<TValue>(\"key\");\n * ```\n *\n * ---\n *\n * @template T The type of the value to retrieve.\n *\n * @param key The key of the value to retrieve.\n *\n * @returns The value with the specified key or `undefined` if the key doesn't exist.\n */\n public read<T extends JSONValue>(key: string): T | undefined;\n\n /**\n * Retrieves the value with the specified key from the persistent {@link localStorage}.\n *\n * ---\n *\n * @example\n * ```ts\n * const value: TValue = jsonStorage.read<TValue>(\"key\", defaultValue);\n * ```\n *\n * ---\n *\n * @template T The type of the value to retrieve.\n *\n * @param key The key of the value to retrieve.\n * @param defaultValue The default value to return if the key doesn't exist.\n *\n * @returns The value with the specified key or the default value if the key doesn't exist.\n */\n public read<T extends JSONValue>(key: string, defaultValue: T): T;\n\n /**\n * Retrieves the value with the specified key from the persistent {@link localStorage}.\n *\n * ---\n *\n * @example\n * ```ts\n * const value: TValue = jsonStorage.read<TValue>(\"key\", obj?.value);\n * ```\n *\n * ---\n *\n * @template T The type of the value to retrieve.\n *\n * @param key The key of the value to retrieve.\n * @param defaultValue The default value to return (which may be `undefined`) if the key doesn't exist.\n *\n * @returns The value with the specified key or the default value if the key doesn't exist.\n */\n public read<T extends JSONValue>(key: string, defaultValue?: T): T | undefined;\n public read<T extends JSONValue>(key: string, defaultValue?: T): T | undefined\n {\n return this._get<T>(this._persistent, key, defaultValue);\n }\n\n /**\n * Checks whether the value with the specified key exists within the default storage.\n *\n * ---\n *\n * @example\n * ```ts\n * if (jsonStorage.has(\"key\"))\n * {\n * // The key exists. Do something...\n * }\n * ```\n *\n * ---\n *\n * @param key The key of the value to check.\n * @param persistent\n * Whether to prefer the persistent {@link localStorage} over the volatile {@link sessionStorage}. \n * If omitted, it defaults to the `preferPersistence` value set in the constructor.\n *\n * @returns `true` if the key exists, `false` otherwise.\n */\n public has(key: string, persistent?: boolean): boolean\n {\n const storage = persistent ? this._persistent : this._volatile;\n\n return storage.getItem(key) !== null;\n }\n\n /**\n * Checks whether the value with the specified key exists within the volatile {@link sessionStorage}.\n *\n * ---\n *\n * @example\n * ```ts\n * if (jsonStorage.knows(\"key\"))\n * {\n * // The key exists. Do something...\n * }\n * ```\n *\n * ---\n *\n * @param key The key of the value to check.\n *\n * @returns `true` if the key exists, `false` otherwise.\n */\n public knows(key: string): boolean\n {\n return this._volatile.getItem(key) !== null;\n }\n\n /**\n * Checks whether the value with the specified key exists looking first in the\n * volatile {@link sessionStorage} and then, if not found, in the persistent {@link localStorage}.\n *\n * ---\n *\n * @example\n * ```ts\n * if (jsonStorage.find(\"key\"))\n * {\n * // The key exists. Do something...\n * }\n * ```\n *\n * ---\n *\n * @param key The key of the value to check.\n *\n * @returns `true` if the key exists, `false` otherwise.\n */\n public find(key: string): boolean\n {\n return this.knows(key) ?? this.exists(key);\n }\n\n /**\n * Checks whether the value with the specified key exists within the persistent {@link localStorage}.\n *\n * ---\n *\n * @example\n * ```ts\n * if (jsonStorage.exists(\"key\"))\n * {\n * // The key exists. Do something...\n * }\n * ```\n *\n * ---\n *\n * @param key The key of the value to check.\n *\n * @returns `true` if the key exists, `false` otherwise.\n */\n public exists(key: string): boolean\n {\n return this._persistent.getItem(key) !== null;\n }\n\n /**\n * Sets the value with the specified key in the default storage. \n * If the value is `undefined` or omitted, the key is removed from the storage.\n *\n * ---\n *\n * @example\n * ```ts\n * jsonStorage.set(\"key\");\n * jsonStorage.set(\"key\", value);\n * jsonStorage.set(\"key\", obj?.value);\n * ```\n *\n * ---\n *\n * @template T The type of the value to set.\n *\n * @param key The key of the value to set.\n * @param newValue The new value to set. If it's `undefined` or omitted, the key is removed instead.\n * @param persistent\n * Whether to prefer the persistent {@link localStorage} over the volatile {@link sessionStorage}. \n * If omitted, it defaults to the `preferPersistence` value set in the constructor.\n */\n public set<T extends JSONValue>(key: string, newValue?: T, persistent = this._preferPersistence): void\n {\n const storage = persistent ? this._persistent : this._volatile;\n\n this._set<T>(storage, key, newValue);\n }\n\n /**\n * Sets the value with the specified key in the volatile {@link sessionStorage}. \n * If the value is `undefined` or omitted, the key is removed from the storage.\n *\n * ---\n *\n * @example\n * ```ts\n * jsonStorage.remember(\"key\");\n * jsonStorage.remember(\"key\", value);\n * jsonStorage.remember(\"key\", obj?.value);\n * ```\n *\n * ---\n *\n * @template T The type of the value to set.\n *\n * @param key The key of the value to set.\n * @param newValue The new value to set. If it's `undefined` or omitted, the key is removed instead.\n */\n public remember<T extends JSONValue>(key: string, newValue?: T): void\n {\n this._set<T>(this._volatile, key, newValue);\n }\n\n /**\n * Sets the value with the specified key in the persistent {@link localStorage}. \n * If the value is `undefined` or omitted, the key is removed from the storage.\n *\n * ---\n *\n * @example\n * ```ts\n * jsonStorage.write(\"key\");\n * jsonStorage.write(\"key\", value);\n * jsonStorage.write(\"key\", obj?.value);\n * ```\n *\n * ---\n *\n * @template T The type of the value to set.\n *\n * @param key The key of the value to set.\n * @param newValue The new value to set. If it's `undefined` or omitted, the key is removed instead.\n */\n public write<T extends JSONValue>(key: string, newValue?: T): void\n {\n this._set<T>(this._persistent, key, newValue);\n }\n\n /**\n * Removes the value with the specified key from the default storage.\n *\n * ---\n *\n * @example\n * ```ts\n * jsonStorage.delete(\"key\");\n * ```\n *\n * ---\n *\n * @param key The key of the value to remove.\n * @param persistent\n * Whether to prefer the persistent {@link localStorage} over the volatile {@link sessionStorage}. \n * If omitted, it defaults to the `preferPersistence` value set in the constructor.\n */\n public delete(key: string, persistent?: boolean): void\n {\n const storage = persistent ? this._persistent : this._volatile;\n\n storage.removeItem(key);\n }\n\n /**\n * Removes the value with the specified key from the volatile {@link sessionStorage}.\n *\n * ---\n *\n * @example\n * ```ts\n * jsonStorage.forget(\"key\");\n * ```\n *\n * ---\n *\n * @param key The key of the value to remove.\n */\n public forget(key: string): void\n {\n this._volatile.removeItem(key);\n }\n\n /**\n * Removes the value with the specified key from the persistent {@link localStorage}.\n *\n * ---\n *\n * @example\n * ```ts\n * jsonStorage.erase(\"key\");\n * ```\n *\n * ---\n *\n * @param key The key of the value to remove.\n */\n public erase(key: string): void\n {\n this._persistent.removeItem(key);\n }\n\n /**\n * Removes the value with the specified key from both the\n * volatile {@link sessionStorage} and the persistent {@link localStorage}.\n *\n * ---\n *\n * @example\n * ```ts\n * jsonStorage.clear(\"key\");\n * ```\n *\n * ---\n *\n * @param key The key of the value to remove.\n */\n public clear(key: string): void\n {\n this._volatile.removeItem(key);\n this._persistent.removeItem(key);\n }\n\n public readonly [Symbol.toStringTag]: string = \"JSONStorage\";\n}\n","import type { FulfilledHandler, PromiseExecutor, RejectedHandler } from \"./types.js\";\n\n/**\n * A wrapper class representing an enhanced version of the native {@link Promise} object.\n *\n * It provides additional properties to check the state of the promise itself. \n * The state can be either `pending`, `fulfilled` or `rejected` and is accessible through\n * the {@link SmartPromise.isPending}, {@link SmartPromise.isFulfilled} & {@link SmartPromise.isRejected} properties.\n *\n * ---\n *\n * @example\n * ```ts\n * const promise = new SmartPromise<string>((resolve, reject) =>\n * {\n * setTimeout(() => resolve(\"Hello, World!\"), 1_000);\n * });\n *\n * console.log(promise.isPending); // true\n * console.log(promise.isFulfilled); // false\n *\n * console.log(await promise); // \"Hello, World!\"\n *\n * console.log(promise.isPending); // false\n * console.log(promise.isFulfilled); // true\n * ```\n *\n * ---\n *\n * @template T The type of value the promise will eventually resolve to. Default is `void`.\n */\nexport default class SmartPromise<T = void> implements Promise<T>\n{\n /**\n * Wraps a new {@link SmartPromise} object around an existing native {@link Promise} object.\n *\n * ---\n *\n * @example\n * ```ts\n * const request = fetch(\"https://api.example.com/data\");\n * const smartRequest = SmartPromise.FromPromise(request);\n *\n * console.log(request.isPending); // Throws an error: `isPending` is not a property of `Promise`.\n * console.log(smartRequest.isPending); // true\n *\n * const response = await request;\n * console.log(smartRequest.isFulfilled); // true\n * ```\n *\n * ---\n *\n * @param promise The promise to wrap.\n *\n * @returns A new {@link SmartPromise} object that wraps the provided promise.\n */\n public static FromPromise<T>(promise: Promise<T>): SmartPromise<T>\n {\n return new SmartPromise((resolve, reject) => promise.then(resolve, reject));\n }\n\n /**\n * A flag indicating whether the promise is still pending or not.\n *\n * The protected property is the only one that can be modified directly by the derived classes. \n * If you're looking for the public and readonly property, use the {@link SmartPromise.isPending} getter instead.\n */\n protected _isPending: boolean;\n\n /**\n * A flag indicating whether the promise is still pending or not.\n */\n public get isPending(): boolean\n {\n return this._isPending;\n }\n\n /**\n * A flag indicating whether the promise has been fulfilled or not.\n *\n * The protected property is the only one that can be modified directly by the derived classes. \n * If you're looking for the public and readonly property, use the {@link SmartPromise.isFulfilled} getter instead.\n */\n protected _isFulfilled: boolean;\n\n /**\n * A flag indicating whether the promise has been fulfilled or not.\n */\n public get isFulfilled(): boolean\n {\n return this._isFulfilled;\n }\n\n /**\n * A flag indicating whether the promise has been rejected or not.\n *\n * The protected property is the only one that can be modified directly by the derived classes. \n * If you're looking for the public and readonly property, use the {@link SmartPromise.isRejected} getter instead.\n */\n protected _isRejected: boolean;\n\n /**\n * A flag indicating whether the promise has been rejected or not.\n */\n public get isRejected(): boolean\n {\n return this._isRejected;\n }\n\n /**\n * The native {@link Promise} object wrapped by this instance.\n */\n protected readonly _promise: Promise<T>;\n\n /**\n * Initializes a new instance of the {@link SmartPromise} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const promise = new SmartPromise<string>((resolve, reject) =>\n * {\n * setTimeout(() => resolve(\"Hello, World!\"), 1_000);\n * });\n * ```\n *\n * ---\n *\n * @param executor\n * The function responsible for eventually resolving or rejecting the promise. \n * Similarly to the native {@link Promise} object, it's immediately executed after the promise is created.\n */\n public constructor(executor: PromiseExecutor<T>)\n {\n this._isPending = true;\n this._isFulfilled = false;\n this._isRejected = false;\n\n const _onFulfilled = (result: T): T =>\n {\n this._isPending = false;\n this._isFulfilled = true;\n\n return result;\n };\n const _onRejected = (reason: unknown): never =>\n {\n this._isPending = false;\n this._isRejected = true;\n\n throw reason;\n };\n\n this._promise = new Promise<T>(executor)\n .then(_onFulfilled, _onRejected);\n }\n\n /**\n * Creates a new {@link Promise} identical to the one wrapped by this instance, with a different reference.\n *\n * ---\n *\n * @example\n * ```ts\n * const promise = new SmartPromise<string>((resolve, reject) =>\n * {\n * setTimeout(() => resolve(\"Hello, World!\"), 1_000);\n * });\n *\n * console.log(await promise.then()); // \"Hello, World!\"\n * ```\n *\n * ---\n *\n * @returns A new {@link Promise} identical to the original one.\n */\n public then(onFulfilled?: null): Promise<T>;\n\n /**\n * Attaches a callback that executes right after the promise is fulfilled.\n *\n * The previous result of the promise is passed as the argument to the callback. \n * The callback's return value is considered the new promise's result instead.\n *\n * ---\n *\n * @example\n * ```ts\n * const promise = new SmartPromise<string>((resolve, reject) =>\n * {\n * setTimeout(() => resolve(\"Hello, World!\"), 1_000);\n * });\n *\n * promise.then((result) => console.log(result)); // \"Hello, World!\"\n * ```\n *\n * ---\n *\n * @template F The type of value the new promise will eventually resolve to. Default is `T`.\n *\n * @param onFulfilled The callback to execute once the promise is fulfilled.\n *\n * @returns A new {@link Promise} resolved with the return value of the callback.\n */\n public then<F = T>(onFulfilled: FulfilledHandler<T, F>, onRejected?: null): Promise<F>;\n\n /**\n * Attaches callbacks that executes right after the promise is fulfilled or rejected.\n *\n * The previous result of the promise is passed as the argument to the fulfillment callback. \n * The fulfillment callback's return value is considered the new promise's result instead.\n *\n * If an error is thrown during execution, the rejection callback is then executed instead.\n *\n * Also note that:\n * - If the rejection callback runs properly, the error is considered handled. \n * The rejection callback's return value is considered the new promise's result.\n * - If the rejection callback throws an error, the new promise is rejected with that error.\n *\n * ---\n *\n * @example\n * ```ts\n * const promise = new SmartPromise((resolve, reject) =>\n * {\n * setTimeout(resolve, Math.random() * 1_000);\n * setTimeout(reject, Math.random() * 1_000);\n * });\n *\n * promise.then(() => console.log(\"OK!\"), () => console.log(\"KO!\")); // \"OK!\" or \"KO!\"\n * ```\n *\n * ---\n *\n * @template F The type of value the new promise will eventually resolve to. Default is `T`.\n * @template R The type of value the new promise will eventually resolve to. Default is `never`.\n *\n * @param onFulfilled The callback to execute once the promise is fulfilled.\n * @param onRejected The callback to execute once the promise is rejected.\n *\n * @returns A new {@link Promise} resolved or rejected based on the callbacks.\n */\n public then<F = T, R = never>(onFulfilled: FulfilledHandler<T, F>, onRejected: RejectedHandler<unknown, R>)\n : Promise<F | R>;\n public then<F = T, R = never>(\n onFulfilled?: FulfilledHandler<T, F> | null,\n onRejected?: RejectedHandler<unknown, R> | null): Promise<F | R>\n {\n return this._promise.then(onFulfilled, onRejected);\n }\n\n /**\n * Creates a new {@link Promise} identical to the one wrapped by this instance, with a different reference.\n *\n * ---\n *\n * @example\n * ```ts\n * const promise = new SmartPromise((resolve, reject) =>\n * {\n * setTimeout(() => reject(new Error(\"An unknown error occurred.\")), 1_000);\n * });\n *\n * promise.catch(); // Uncaught Error: An unknown error occurred.\n * ```\n *\n * ---\n *\n * @returns A new {@link Promise} identical to the original one.\n */\n public catch(onRejected?: null): Promise<T>;\n\n /**\n * Attaches a callback to handle the potential rejection of the promise. \n * If it happens, the callback is then executed.\n *\n * Also note that:\n * - If the callback runs properly, the error is considered handled. \n * The callback's return value is considered the new promise's result.\n * - If the callback throws an error, the new promise is rejected with that error.\n *\n * ---\n *\n * @example\n * ```ts\n * const promise = new SmartPromise((resolve, reject) =>\n * {\n * setTimeout(() => reject(new Error(\"An unknown error occurred.\")), 1_000);\n * });\n *\n * promise.catch((reason) => console.error(reason)); // \"Error: An unknown error occurred.\"\n * ```\n *\n * ---\n *\n * @template R The type of value the new promise will eventually resolve to. Default is `T`.\n *\n * @param onRejected The callback to execute once the promise is rejected.\n *\n * @returns A new {@link Promise} able to catch and handle the potential error.\n */\n public catch<R = never>(onRejected: RejectedHandler<unknown, R>): Promise<T | R>;\n public catch<R = never>(onRejected?: RejectedHandler<unknown, R> | null): Promise<T | R>\n {\n return this._promise.catch(onRejected);\n }\n\n /**\n * Attaches a callback that executes right after the promise is settled, regardless of the outcome.\n *\n * ---\n *\n * @example\n * ```ts\n * const promise = new SmartPromise((resolve, reject) =>\n * {\n * setTimeout(resolve, Math.random() * 1_000);\n * setTimeout(reject, Math.random() * 1_000);\n * });\n *\n *\n * promise\n * .then(() => console.log(\"OK!\")) // Logs \"OK!\" if the promise is fulfilled.\n * .catch(() => console.log(\"KO!\")) // Logs \"KO!\" if the promise is rejected.\n * .finally(() => console.log(\"Done!\")); // Always logs \"Done!\".\n * ```\n *\n * ---\n *\n * @param onFinally The callback to execute when once promise is settled.\n *\n * @returns A new {@link Promise} that executes the callback once the promise is settled.\n */\n public finally(onFinally?: (() => void) | null): Promise<T>\n {\n return this._promise.finally(onFinally);\n }\n\n public readonly [Symbol.toStringTag]: string = \"SmartPromise\";\n}\n","import type { PromiseResolver, PromiseRejecter, FulfilledHandler, RejectedHandler } from \"./types.js\";\n\nimport SmartPromise from \"./smart-promise.js\";\n\n/**\n * A class representing a {@link SmartPromise} that can be resolved or rejected from the \"outside\". \n * The `resolve` and `reject` methods are exposed to allow the promise to be settled from another context.\n *\n * It's particularly useful in scenarios where the promise is created and needs to be awaited in one place, \n * while being resolved or rejected in another (e.g. an event handler for an user interaction).\n *\n * This is a change in the approach to promises: instead of defining how the promise will be resolved (or rejected), \n * you define how to handle the resolution (or rejection) when it occurs.\n *\n * ---\n *\n * @example\n * ```ts\n * const promise = new DeferredPromise<string, string[]>((value: string) => value.split(\" \"));\n *\n * promise.then((result) => console.log(result)); // [\"Hello,\", \"World!\"]\n * promise.resolve(\"Hello, World!\");\n * ```\n *\n * ---\n *\n * @template T The type of value the promise expects to initially be resolved with. Default is `void`.\n * @template F\n * The type of value returned by the `onFulfilled` callback. \n * This will be the actual type of value the promise will eventually resolve to. Default is `T`.\n * @template R\n * The type of value possibly returned by the `onRejected` callback. \n * This will be coupled with the type of value the promise will eventually resolve to, if provided. Default is `never`.\n */\nexport default class DeferredPromise<T = void, F = T, R = never> extends SmartPromise<F | R>\n{\n /**\n * The exposed function that allows to resolve the promise.\n *\n * This protected property is the only one that can be modified directly by the derived classes. \n * If you're looking for the public and readonly property, use the {@link DeferredPromise.resolve} getter instead.\n */\n protected readonly _resolve: PromiseResolver<T>;\n\n /**\n * The exposed function that allows to reject the promise.\n */\n public get resolve(): PromiseResolver<T> { return this._resolve; }\n\n /**\n * The exposed function that allows to reject the promise.\n *\n * This protected property is the only one that can be modified directly by the derived classes. \n * If you're looking for the public and readonly property, use the {@link DeferredPromise.reject} getter instead.\n */\n protected readonly _reject: PromiseRejecter;\n\n /**\n * The exposed function that allows to reject the promise.\n */\n public get reject(): PromiseRejecter { return this._reject; }\n\n /**\n * The native {@link Promise} object wrapped by this instance.\n */\n declare protected readonly _promise: Promise<F | R>;\n\n /**\n * Initializes a new instance of the {@link DeferredPromise} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const promise = new DeferredPromise<string, string[]>((value: string) => value.split(\" \"));\n * ```\n *\n * ---\n *\n * @param onFulfilled The callback to execute once the promise is fulfilled.\n * @param onRejected The callback to execute once the promise is rejected.\n */\n public constructor(onFulfilled?: FulfilledHandler<T, F> | null, onRejected?: RejectedHandler<unknown, R> | null)\n {\n let _resolve: PromiseResolver<T>;\n let _reject: PromiseRejecter;\n\n super((resolve, reject) =>\n {\n // ReferenceError: Must call super constructor in derived class before accessing\n // 'this' or returning from derived constructor.\n //\n _resolve = resolve as PromiseResolver<T>;\n _reject = reject;\n });\n\n this._promise = this._promise.then(onFulfilled as FulfilledHandler<F | R>, onRejected);\n\n this._resolve = _resolve!;\n this._reject = _reject!;\n }\n\n /**\n * Watches another promise and resolves or rejects this promise when the other one is settled.\n *\n * ---\n *\n * @example\n * ```ts\n * const promise = new Promise<string>((resolve) => setTimeout(() => resolve(\"Hello, World!\"), 1_000));\n * const deferred = new DeferredPromise<string, string[]>((value: string) => value.split(\" \"));\n *\n * deferred.then((result) => console.log(result)); // [\"Hello,\", \"World!\"]\n * deferred.watch(promise);\n * ```\n *\n * ---\n *\n * @param otherPromise The promise to watch.\n *\n * @returns The current instance of the {@link DeferredPromise} class.\n */\n public watch(otherPromise: PromiseLike<T>): this\n {\n otherPromise.then(this.resolve, this.reject);\n\n return this;\n }\n\n public override readonly [Symbol.toStringTag]: string = \"DeferredPromise\";\n}\n","import { TimeoutException } from \"../exceptions/index.js\";\n\nimport SmartPromise from \"./smart-promise.js\";\nimport type { MaybePromise, PromiseExecutor } from \"./types.js\";\n\n/**\n * A class representing a {@link SmartPromise} that rejects automatically after a given time. \n * It's useful for operations that must be completed within a certain time frame.\n *\n * If the operation takes longer than the specified time, the promise is rejected with a {@link TimeoutException}.\n *\n * ---\n *\n * @example\n * ```ts\n * const promise = new TimedPromise<string>((resolve, reject) =>\n * {\n * setTimeout(() => resolve(\"Hello, World!\"), Math.random() * 10_000);\n *\n * }, 5_000);\n *\n * promise\n * .then((result) => console.log(result)) // \"Hello, World!\"\n * .catch((error) => console.error(error)); // TimeoutException: The operation has timed out.\n * ```\n *\n * ---\n *\n * @template T The type of value the promise will eventually resolve to. Default is `void`.\n */\nexport default class TimedPromise<T = void> extends SmartPromise<T>\n{\n /**\n * Initializes a new instance of the {@link TimedPromise} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const promise = new TimedPromise<string>((resolve, reject) =>\n * {\n * setTimeout(() => resolve(\"Hello, World!\"), Math.random() * 10_000);\n *\n * }, 5_000);\n * ```\n *\n * ---\n *\n * @param executor\n * The function responsible for eventually resolving or rejecting the promise. \n * Similarly to the native {@link Promise} object, it's immediately executed after the promise is created.\n *\n * @param timeout The maximum time in milliseconds that the operation can take before timing out.\n */\n public constructor(executor: PromiseExecutor<T>, timeout?: number)\n {\n super((resolve, reject) =>\n {\n const _resolve = (result: MaybePromise<T>) =>\n {\n clearTimeout(_timeoutId);\n resolve(result);\n };\n const _reject = (reason: unknown) =>\n {\n clearTimeout(_timeoutId);\n reject(reason);\n };\n\n const _timeout = () => _reject(new TimeoutException(\"The operation has timed out.\"));\n const _timeoutId = setTimeout(_timeout, timeout);\n\n executor(_resolve, _reject);\n });\n }\n\n public override readonly [Symbol.toStringTag]: string = \"TimedPromise\";\n}\n","/* eslint-disable @typescript-eslint/prefer-literal-enum-member */\n\nimport { RangeException, SmartIterator } from \"../models/index.js\";\n\n/**\n * An enumeration that represents the time units and their conversion factors. \n * It can be used as utility to express time values in a more\n * readable way or to convert time values between different units.\n *\n * ---\n *\n * @example\n * ```ts\n * setTimeout(() => { [...] }, 5 * TimeUnit.Minute);\n * ```\n */\nexport enum TimeUnit\n{\n /**\n * A millisecond: the base time unit.\n */\n Millisecond = 1,\n\n /**\n * A second: 1000 milliseconds.\n */\n Second = 1_000,\n\n /**\n * A minute: 60 seconds.\n */\n Minute = 60 * Second,\n\n /**\n * An hour: 60 minutes.\n */\n Hour = 60 * Minute,\n\n /**\n * A day: 24 hours.\n */\n Day = 24 * Hour,\n\n /**\n * A week: 7 days.\n */\n Week = 7 * Day,\n\n /**\n * A month: 30 days.\n */\n Month = 30 * Day,\n\n /**\n * A year: 365 days.\n */\n Year = 365 * Day\n}\n\n/**\n * An enumeration that represents the days of the week. \n * It can be used as utility to identify the days of the week when working with dates.\n *\n * ---\n *\n * @example\n * ```ts\n * const today = new Date();\n * if (today.getUTCDay() === WeekDay.Sunday)\n * {\n * // Today is Sunday. Do something...\n * }\n * ```\n */\nexport enum WeekDay\n{\n /**\n * Sunday\n */\n Sunday = 0,\n\n /**\n * Monday\n */\n Monday = 1,\n\n /**\n * Tuesday\n */\n Tuesday = 2,\n\n /**\n * Wednesday\n */\n Wednesday = 3,\n\n /**\n * Thursday\n */\n Thursday = 4,\n\n /**\n * Friday\n */\n Friday = 5,\n\n /**\n * Saturday\n */\n Saturday = 6\n}\n\n/**\n * An utility function that calculates the difference between two dates. \n * The difference can be expressed in different time units.\n *\n * ---\n *\n * @example\n * ```ts\n * const start = new Date(\"2025-01-01\");\n * const end = new Date(\"2025-01-31\");\n *\n * dateDifference(start, end, TimeUnit.Minute); // 43200\n * ```\n *\n * ---\n *\n * @param start The start date.\n * @param end The end date.\n * @param unit The time unit to express the difference. `TimeUnit.Day` by default.\n *\n * @returns The difference between the two dates in the specified time unit.\n */\nexport function dateDifference(start: number | string | Date, end: number | string | Date, unit = TimeUnit.Day): number\n{\n let _round: (value: number) => number;\n\n start = new Date(start);\n end = new Date(end);\n\n if (start < end) { _round = Math.floor; }\n else { _round = Math.ceil; }\n\n return _round((end.getTime() - start.getTime()) / unit);\n}\n\n/**\n * An utility function that generates an iterator over a range of dates. \n * The step between the dates can be expressed in different time units.\n *\n * ---\n *\n * @example\n * ```ts\n * const start = new Date(\"2025-01-01\");\n * const end = new Date(\"2025-01-31\");\n *\n * for (const date of dateRange(start, end, TimeUnit.Week))\n * {\n * date.toISOString().slice(8, 10); // \"01\", \"08\", \"15\", \"22\", \"29\"\n * }\n * ```\n *\n * ---\n *\n * @param start The start date (included).\n * @param end\n * The end date (excluded).\n *\n * Must be greater than the start date. Otherwise, a {@link RangeException} will be thrown.\n *\n * @param step The time unit to express the step between the dates. `TimeUnit.Day` by default.\n *\n * @returns A {@link SmartIterator} object that generates the dates in the range.\n */\nexport function dateRange(start: number | string | Date, end: number | string | Date, step = TimeUnit.Day)\n : SmartIterator<Date>\n{\n start = new Date(start);\n end = new Date(end);\n\n if (start >= end) { throw new RangeException(\"The end date must be greater than the start date.\"); }\n\n return new SmartIterator<Date>(function* ()\n {\n const endTime = end.getTime();\n\n let unixTime: number = start.getTime();\n while (unixTime < endTime)\n {\n yield new Date(unixTime);\n\n unixTime += step;\n }\n });\n}\n\n/**\n * An utility function that rounds a date to the nearest time unit. \n * The rounding can be expressed in different time units.\n *\n * ---\n *\n * @example\n * ```ts\n * const date = new Date(\"2025-01-01T12:34:56.789Z\");\n *\n * dateRound(date, TimeUnit.Hour); // 2025-01-01T12:00:00.000Z\n * ```\n *\n * ---\n *\n * @param date The date to round.\n * @param unit\n * The time unit to express the rounding. `TimeUnit.Day` by default.\n *\n * Must be greater than a millisecond and less than or equal to a day. \n * Otherwise, a {@link RangeException} will be thrown.\n *\n * @returns The rounded date.\n */\nexport function dateRound(date: number | string | Date, unit = TimeUnit.Day): Date\n{\n if (unit <= TimeUnit.Millisecond)\n {\n throw new RangeException(\n \"Rounding a timestamp by milliseconds or less makes no sense.\" +\n \"Use the timestamp value directly instead.\"\n );\n }\n if (unit > TimeUnit.Day)\n {\n throw new RangeException(\n \"Rounding by more than a day leads to unexpected results. \" +\n \"Consider using other methods to round dates by weeks, months or years.\"\n );\n }\n\n date = new Date(date);\n return new Date(Math.floor(date.getTime() / unit) * unit);\n}\n\n/**\n * An utility function that gets the week of a date. \n * The first day of the week can be optionally specified.\n *\n * ---\n *\n * @example\n * ```ts\n * const date = new Date(\"2025-01-01\");\n *\n * getWeek(date, WeekDay.Monday); // 2024-12-30\n * ```\n *\n * ---\n *\n * @param date The date to get the week of.\n * @param firstDay The first day of the week. `WeekDay.Sunday` by default.\n *\n * @returns The first day of the week of the specified date.\n */\nexport function getWeek(date: number | string | Date, firstDay = WeekDay.Sunday): Date\n{\n date = new Date(date);\n\n const startCorrector = 7 - firstDay;\n const weekDayIndex = (date.getUTCDay() + startCorrector) % 7;\n const firstDayTime = date.getTime() - (TimeUnit.Day * weekDayIndex);\n\n return dateRound(new Date(firstDayTime));\n}\n","import type { Interval } from \"../../core/types.js\";\nimport { isBrowser } from \"../../helpers.js\";\n\nimport Publisher from \"../callbacks/publisher.js\";\nimport { FatalErrorException, RuntimeException } from \"../exceptions/index.js\";\n\ninterface GameLoopEventsMap\n{\n start: () => void;\n stop: () => void;\n}\n\n/**\n * A class representing a {@link https://en.wikipedia.org/wiki/Video_game_programming#Game_structure|game loop} pattern\n * that allows to run a function at a specific frame rate.\n *\n * In a browser environment, it uses the native {@link requestAnimationFrame}\n * function to run the callback at the refresh rate of the screen. \n * In a non-browser environment, however, it uses the {@link setInterval}\n * function to run the callback at the specified fixed interval of time.\n *\n * Every time the callback is executed, it receives the\n * elapsed time since the start of the game loop. \n * It's also possible to subscribe to the `start` & `stop` events to receive notifications when they occur.\n *\n * ---\n *\n * @example\n * ```ts\n * const loop = new GameLoop((elapsedTime: number) =>\n * {\n * console.log(`The game loop has been running for ${elapsedTime}ms.`);\n * });\n *\n * loop.onStart(() => { console.log(\"The game loop has started.\"); });\n * loop.onStop(() => { console.log(\"The game loop has stopped.\"); });\n *\n * loop.start();\n * ```\n */\nexport default class GameLoop\n{\n /**\n * The handle of the interval or the animation frame, depending on the environment. \n * It's used to stop the game loop when the {@link GameLoop._stop} method is called.\n */\n protected _handle?: number | Interval;\n\n /**\n * The time when the game loop has started. \n * In addition to indicating the {@link https://en.wikipedia.org/wiki/Unix_time|Unix timestamp}\n * of the start of the game loop, it's also used to calculate the elapsed time.\n *\n * This protected property is the only one that can be modified directly by the derived classes. \n * If you're looking for the public and readonly property, use the {@link GameLoop.startTime} getter instead.\n */\n protected _startTime: number;\n\n /**\n * The time when the game loop has started. \n * In addition to indicating the {@link https://en.wikipedia.org/wiki/Unix_time|Unix timestamp}\n * of the start of the game loop, it's also used to calculate the elapsed time.\n */\n public get startTime(): number\n {\n return this._startTime;\n }\n\n /**\n * A flag indicating whether the game loop is currently running or not.\n *\n * This protected property is the only one that can be modified directly by the derived classes. \n * If you're looking for the public and readonly property, use the {@link GameLoop.isRunning} getter instead.\n */\n protected _isRunning: boolean;\n\n /**\n * A flag indicating whether the game loop is currently running or not.\n */\n public get isRunning(): boolean\n {\n return this._isRunning;\n }\n\n /**\n * The elapsed time since the start of the game loop. \n * It's calculated as the difference between the current time and the {@link GameLoop.startTime}.\n */\n public get elapsedTime(): number\n {\n return performance.now() - this._startTime;\n }\n\n /**\n * The {@link Publisher} object that will be used to publish the events of the game loop.\n */\n protected readonly _publisher: Publisher<GameLoopEventsMap>;\n\n /**\n * The internal method actually responsible for starting the game loop.\n *\n * Depending on the current environment, it could use the\n * {@link requestAnimationFrame} or the {@link setInterval} function.\n */\n protected readonly _start: () => void;\n\n /**\n * The internal method actually responsible for stopping the game loop.\n *\n * Depending on the current environment, it could use the\n * {@link cancelAnimationFrame} or the {@link clearInterval} function.\n */\n protected readonly _stop: () => void;\n\n /**\n * Initializes a new instance of the {@link GameLoop} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const loop = new GameLoop((elapsedTime: number) => { [...] });\n * ```\n *\n * ---\n *\n * @param callback The function that will be executed at each iteration of the game loop.\n * @param msIfNotBrowser\n * The interval in milliseconds that will be used if the current environment isn't a browser. Default is `40`.\n */\n public constructor(callback: FrameRequestCallback, msIfNotBrowser = 40)\n {\n this._startTime = 0;\n this._isRunning = false;\n\n if (isBrowser)\n {\n this._start = () =>\n {\n callback(this.elapsedTime);\n\n this._handle = window.requestAnimationFrame(this._start);\n };\n\n this._stop = () => window.cancelAnimationFrame(this._handle as number);\n }\n else\n {\n // eslint-disable-next-line no-console\n console.warn(\n \"Not a browser environment detected. \" +\n `Using setInterval@${msIfNotBrowser}ms instead of requestAnimationFrame...`\n );\n\n this._start = () =>\n {\n this._handle = setInterval(() => callback(this.elapsedTime), msIfNotBrowser);\n };\n\n this._stop = () => clearInterval(this._handle as Interval);\n }\n\n this._publisher = new Publisher();\n }\n\n /**\n * Starts the execution of the game loop.\n *\n * If the game loop is already running, a {@link RuntimeException} will be thrown.\n *\n * ---\n *\n * @example\n * ```ts\n * loop.onStart(() => { [...] }); // This callback will be executed.\n * loop.start();\n * ```\n *\n * ---\n *\n * @param elapsedTime The elapsed time to set as default when the game loop starts. Default is `0`.\n */\n public start(elapsedTime = 0): void\n {\n if (this._isRunning) { throw new RuntimeException(\"The game loop has already been started.\"); }\n\n this._startTime = performance.now() - elapsedTime;\n this._start();\n this._isRunning = true;\n\n this._publisher.publish(\"start\");\n }\n\n /**\n * Stops the execution of the game loop.\n *\n * If the game loop hasn't yet started, a {@link RuntimeException} will be thrown.\n *\n * ---\n *\n * @example\n * ```ts\n * loop.onStop(() => { [...] }); // This callback will be executed.\n * loop.stop();\n * ```\n */\n public stop(): void\n {\n if (!(this._isRunning))\n {\n throw new RuntimeException(\"The game loop had already stopped or hadn't yet started.\");\n }\n if (!(this._handle)) { throw new FatalErrorException(); }\n\n this._stop();\n this._handle = undefined;\n this._isRunning = false;\n\n this._publisher.publish(\"stop\");\n }\n\n /**\n * Subscribes to the `start` event of the game loop.\n *\n * ---\n *\n * @example\n * ```ts\n * loop.onStart(() => { console.log(\"The game loop has started.\"); });\n * ```\n *\n * ---\n *\n * @param callback The function that will be executed when the game loop starts.\n *\n * @returns A function that can be used to unsubscribe from the event.\n */\n public onStart(callback: () => void): () => void\n {\n return this._publisher.subscribe(\"start\", callback);\n }\n\n /**\n * Subscribes to the `stop` event of the game loop.\n *\n * ---\n *\n * @example\n * ```ts\n * loop.onStop(() => { console.log(\"The game loop has stopped.\"); });\n * ```\n *\n * ---\n *\n * @param callback The function that will be executed when the game loop stops.\n *\n * @returns A function that can be used to unsubscribe from the event.\n */\n public onStop(callback: () => void): () => void\n {\n return this._publisher.subscribe(\"stop\", callback);\n }\n\n public readonly [Symbol.toStringTag]: string = \"GameLoop\";\n}\n","import { TimeUnit } from \"../../utils/date.js\";\n\nimport Publisher from \"../callbacks/publisher.js\";\nimport { FatalErrorException, RangeException, RuntimeException } from \"../exceptions/index.js\";\n\nimport GameLoop from \"./game-loop.js\";\n\ninterface ClockEventsMap\n{\n start: () => void;\n stop: () => void;\n tick: (elapsedTime: number) => void;\n}\n\n/**\n * A class representing a clock.\n *\n * It can be started, stopped and, when running, it ticks at a specific frame rate. \n * It's possible to subscribe to these events to receive notifications when they occur.\n *\n * ---\n *\n * @example\n * ```ts\n * const clock = new Clock();\n *\n * clock.onStart(() => { console.log(\"The clock has started.\"); });\n * clock.onTick((elapsedTime) => { console.log(`The clock has ticked at ${elapsedTime}ms.`); });\n * clock.onStop(() => { console.log(\"The clock has stopped.\"); });\n *\n * clock.start();\n * ```\n */\nexport default class Clock extends GameLoop\n{\n /**\n * The {@link Publisher} object that will be used to publish the events of the clock.\n */\n declare protected readonly _publisher: Publisher<ClockEventsMap>;\n\n /**\n * Initializes a new instance of the {@link Clock} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const clock = new Clock();\n * ```\n *\n * ---\n *\n * @param msIfNotBrowser\n * The interval in milliseconds at which the clock will tick if the environment is not a browser. \n * `TimeUnit.Second` by default.\n */\n public constructor(msIfNotBrowser: number = TimeUnit.Second)\n {\n super((elapsedTime) => this._publisher.publish(\"tick\", elapsedTime), msIfNotBrowser);\n }\n\n /**\n * Starts the execution of the clock.\n *\n * If the clock is already running, a {@link RuntimeException} will be thrown.\n *\n * ---\n *\n * @example\n * ```ts\n * clock.onStart(() => { [...] }); // This callback will be executed.\n * clock.start();\n * ```\n *\n * ---\n *\n * @param elapsedTime The elapsed time to set as default when the clock starts. Default is `0`.\n */\n public override start(elapsedTime = 0): void\n {\n if (this._isRunning) { throw new RuntimeException(\"The clock has already been started.\"); }\n\n this._startTime = performance.now() - elapsedTime;\n this._start();\n this._isRunning = true;\n\n this._publisher.publish(\"start\");\n }\n\n /**\n * Stops the execution of the clock.\n *\n * If the clock hasn't yet started, a {@link RuntimeException} will be thrown.\n *\n * ---\n *\n * @example\n * ```ts\n * clock.onStop(() => { [...] }); // This callback will be executed.\n * clock.stop();\n * ```\n */\n public override stop(): void\n {\n if (!(this._isRunning)) { throw new RuntimeException(\"The clock had already stopped or hadn't yet started.\"); }\n if (!(this._handle)) { throw new FatalErrorException(); }\n\n this._stop();\n this._handle = undefined;\n this._isRunning = false;\n\n this._publisher.publish(\"stop\");\n }\n\n /**\n * Subscribes to the `tick` event of the clock.\n *\n * ---\n *\n * @example\n * ```ts\n * clock.onTick((elapsedTime) => { [...] }); // This callback will be executed.\n * clock.start();\n * ```\n *\n * ---\n *\n * @param callback The callback that will be executed when the clock ticks.\n * @param tickStep\n * The minimum time in milliseconds that must pass from the previous execution of the callback to the next one.\n *\n * - If it's a positive number, the callback will be executed only if the\n * time passed from the previous execution is greater than this number.\n * - If it's `0`, the callback will be executed every tick without even checking for the time.\n * - If it's a negative number, a {@link RangeException} will be thrown.\n *\n * @returns A function that can be used to unsubscribe from the event.\n */\n public onTick(callback: (elapsedTime: number) => void, tickStep = 0): () => void\n {\n if (tickStep < 0) { throw new RangeException(\"The tick step must be a non-negative number.\"); }\n if (tickStep === 0) { return this._publisher.subscribe(\"tick\", callback); }\n\n let lastTick = 0;\n\n return this._publisher.subscribe(\"tick\", (elapsedTime: number) =>\n {\n if ((elapsedTime - lastTick) < tickStep) { return; }\n\n callback(elapsedTime);\n lastTick = elapsedTime;\n });\n }\n\n public override readonly [Symbol.toStringTag]: string = \"Clock\";\n}\n","import { TimeUnit } from \"../../utils/date.js\";\n\nimport Publisher from \"../callbacks/publisher.js\";\nimport { FatalErrorException, RangeException, RuntimeException } from \"../exceptions/index.js\";\nimport { DeferredPromise, SmartPromise } from \"../promises/index.js\";\nimport type { Callback } from \"../types.js\";\n\nimport GameLoop from \"./game-loop.js\";\n\ninterface CountdownEventsMap\n{\n start: () => void;\n stop: (reason: unknown) => void;\n tick: (remainingTime: number) => void;\n expire: () => void;\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [key: string]: Callback<any[], any>;\n}\n\n/**\n * A class representing a countdown.\n *\n * It can be started, stopped, when running it ticks at a specific frame rate and it expires when the time's up. \n * It's possible to subscribe to these events to receive notifications when they occur.\n *\n * ---\n *\n * @example\n * ```ts\n * const countdown = new Countdown(10_000);\n *\n * countdown.onStart(() => { console.log(\"The countdown has started.\"); });\n * countdown.onTick((remainingTime) => { console.log(`The countdown has ${remainingTime}ms remaining.`); });\n * countdown.onStop((reason) => { console.log(`The countdown has stopped because of ${reason}.`); });\n * countdown.onExpire(() => { console.log(\"The countdown has expired.\"); });\n *\n * countdown.start();\n * ```\n */\nexport default class Countdown extends GameLoop\n{\n /**\n * The {@link Publisher} object that will be used to publish the events of the countdown.\n */\n declare protected readonly _publisher: Publisher<CountdownEventsMap>;\n\n /**\n * The total duration of the countdown in milliseconds.\n *\n * This protected property is the only one that can be modified directly by the derived classes. \n * If you're looking for the public and readonly property, use the {@link Countdown.duration} getter instead.\n */\n protected _duration: number;\n\n /**\n * The total duration of the countdown in milliseconds.\n */\n public get duration(): number\n {\n return this._duration;\n }\n\n /**\n * The remaining time of the countdown in milliseconds. \n * It's calculated as the difference between the total duration and the elapsed time.\n */\n public get remainingTime(): number\n {\n return this._duration - this.elapsedTime;\n }\n\n /**\n * The {@link DeferredPromise} that will be resolved or rejected when the countdown expires or stops.\n */\n protected _deferrer?: DeferredPromise<void>;\n\n /**\n * Initializes a new instance of the {@link Countdown} class.\n *\n * ---\n *\n * @example\n * ```ts\n * const countdown = new Countdown(10_000);\n * ```\n *\n * ---\n *\n * @param duration\n * The total duration of the countdown in milliseconds.\n *\n * @param msIfNotBrowser\n * The interval in milliseconds at which the countdown will tick if the environment is not a browser. \n * `TimeUnit.Second` by default.\n */\n public constructor(duration: number, msIfNotBrowser: number = TimeUnit.Second)\n {\n const callback = () =>\n {\n const remainingTime = this.remainingTime;\n if (remainingTime <= 0)\n {\n this._deferrerStop();\n\n this._publisher.publish(\"tick\", 0);\n this._publisher.publish(\"expire\");\n }\n else\n {\n this._publisher.publish(\"tick\", remainingTime);\n }\n };\n\n super(callback, msIfNotBrowser);\n\n this._duration = duration;\n }\n\n /**\n * The internal method actually responsible for stopping the\n * countdown and resolving or rejecting the {@link Countdown._deferrer} promise.\n *\n * ---\n *\n * @param reason\n * The reason why the countdown has stopped.\n *\n * - If it's `undefined`, the promise will be resolved.\n * - If it's a value, the promise will be rejected with that value.\n */\n protected _deferrerStop(reason?: unknown): void\n {\n if (!(this._isRunning)) { throw new RuntimeException(\"The countdown hadn't yet started.\"); }\n if (!(this._deferrer)) { throw new FatalErrorException(); }\n\n this._stop();\n this._handle = undefined;\n this._isRunning = false;\n\n if (reason !== undefined) { this._deferrer.reject(reason); }\n else { this._deferrer.resolve(); }\n\n this._deferrer = undefined;\n }\n\n /**\n * Starts the execution of the countdown.\n *\n * If the countdown is already running, a {@link RuntimeException} will be thrown.\n *\n * ---\n *\n * @example\n * ```ts\n * countdown.onStart(() => { [...] }); // This callback will be executed.\n * countdown.start();\n * ```\n *\n * ---\n *\n * @param remainingTime\n * The remaining time to set as default when the countdown starts. \n * Default is the {@link Countdown.duration} itself.\n *\n * @returns A {@link SmartPromise} that will be resolved or rejected when the countdown expires or stops.\n */\n public override start(remainingTime: number = this.duration): SmartPromise<void>\n {\n if (this._isRunning) { throw new RuntimeException(\"The countdown had already stopped or hadn't yet started.\"); }\n if (this._deferrer) { throw new FatalErrorException(); }\n\n this._deferrer = new DeferredPromise();\n super.start(this.duration - remainingTime);\n\n this._publisher.publish(\"start\");\n\n return this._deferrer;\n }\n\n /**\n * Stops the execution of the countdown.\n *\n * If the countdown hasn't yet started, a {@link RuntimeException} will be thrown.\n *\n * ---\n *\n * @example\n * ```ts\n * countdown.onStop(() => { [...] }); // This callback will be executed.\n * countdown.stop();\n * ```\n *\n * ---\n *\n * @param reason\n * The reason why the countdown has stopped.\n *\n * - If it's `undefined`, the promise will be resolved.\n * - If it's a value, the promise will be rejected with that value.\n */\n public override stop(reason?: unknown): void\n {\n // TODO: Once solved Issues #6 & #10, make the `reason` parameter required.\n // - https://github.com/Byloth/core/issues/6\n // - https://github.com/Byloth/core/issues/10\n //\n this._deferrerStop(reason);\n\n this._publisher.publish(\"stop\", reason);\n }\n\n /**\n * Subscribes to the `expire` event of the countdown.\n *\n * ---\n *\n * @example\n * ```ts\n * countdown.onExpire(() => { [...] }); // This callback will be executed once the countdown has expired.\n * countdown.start();\n * ```\n *\n * ---\n *\n * @param callback The callback that will be executed when the countdown expires.\n *\n * @returns A function that can be used to unsubscribe from the event.\n */\n public onExpire(callback: () => void): () => void\n {\n return this._publisher.subscribe(\"expire\", callback);\n }\n\n /**\n * Subscribes to the `tick` event of the countdown.\n *\n * ---\n *\n * @example\n * ```ts\n * countdown.onTick((remainingTime) => { [...] }); // This callback will be executed.\n * countdown.start();\n * ```\n *\n * ---\n *\n * @param callback The callback that will be executed when the countdown ticks.\n * @param tickStep\n * The minimum time in milliseconds that must pass from the previous execution of the callback to the next one.\n *\n * - If it's a positive number, the callback will be executed only if the\n * time passed from the previous execution is greater than this number.\n * - If it's `0`, the callback will be executed every tick without even checking for the time.\n * - If it's a negative number, a {@link RangeException} will be thrown.\n *\n * @returns A function that can be used to unsubscribe from the event.\n */\n public onTick(callback: (remainingTime: number) => void, tickStep = 0): () => void\n {\n if (tickStep < 0) { throw new RangeException(\"The tick step must be a non-negative number.\"); }\n if (tickStep === 0) { return this._publisher.subscribe(\"tick\", callback); }\n\n let lastTick = this.remainingTime;\n\n return this._publisher.subscribe(\"tick\", (remainingTime: number) =>\n {\n if ((lastTick - remainingTime) < tickStep) { return; }\n\n callback(remainingTime);\n lastTick = remainingTime;\n });\n }\n\n public override readonly [Symbol.toStringTag]: string = \"Countdown\";\n}\n","import { SmartIterator, ValueException } from \"../models/index.js\";\n\n/**\n * An utility class that provides a set of methods to generate sequences of numbers following specific curves. \n * It can be used to generate sequences of values that can be\n * used in animations, transitions and other different scenarios.\n *\n * It cannot be instantiated directly.\n */\nexport default class Curve\n{\n /**\n * Generates a given number of values following a linear curve. \n * The values are equally spaced and normalized between 0 and 1.\n *\n * ---\n *\n * @example\n * ```ts\n * for (const value of Curve.Linear(5))\n * {\n * console.log(value); // 0, 0.25, 0.5, 0.75, 1\n * }\n * ```\n *\n * ---\n *\n * @param values The number of values to generate.\n *\n * @returns A {@link SmartIterator} object that generates the values following a linear curve.\n */\n public static Linear(values: number): SmartIterator<number>\n {\n const steps = (values - 1);\n\n return new SmartIterator<number>(function* ()\n {\n for (let index = 0; index < values; index += 1) { yield index / steps; }\n });\n }\n\n /**\n * Generates a given number of values following an exponential curve. \n * The values are equally spaced and normalized between 0 and 1.\n *\n * ---\n *\n * @example\n * ```ts\n * for (const value of Curve.Exponential(6))\n * {\n * console.log(value); // 0, 0.04, 0.16, 0.36, 0.64, 1\n * }\n * ```\n *\n * ---\n *\n * @param values The number of values to generate.\n * @param base\n * The base of the exponential curve. Default is `2`.\n *\n * Also note that:\n * - If it's equal to `1`, the curve will be linear.\n * - If it's included between `0` and `1`, the curve will be logarithmic.\n *\n * The base cannot be negative. If so, a {@link ValueException} will be thrown.\n *\n * @returns A {@link SmartIterator} object that generates the values following an exponential curve.\n */\n public static Exponential(values: number, base = 2): SmartIterator<number>\n {\n if (base < 0) { throw new ValueException(\"The base of the exponential curve cannot be negative.\"); }\n\n const steps = (values - 1);\n\n return new SmartIterator<number>(function* ()\n {\n for (let index = 0; index < values; index += 1) { yield Math.pow(index / steps, base); }\n });\n }\n\n private constructor() { /* ... */ }\n\n public readonly [Symbol.toStringTag]: string = \"Curve\";\n}\n","import { ValueException } from \"../models/index.js\";\n\n/**\n * A wrapper class around the native {@link Math.random} function that\n * provides a set of methods to generate random values more easily. \n * It can be used to generate random numbers, booleans and other different values.\n *\n * It cannot be instantiated directly.\n */\nexport default class Random\n{\n /**\n * Generates a random boolean value.\n *\n * ---\n *\n * @example\n * ```ts\n * if (Random.Boolean())\n * {\n * // Do something...\n * }\n * ```\n *\n * ---\n *\n * @param ratio\n * The probability of generating `true`.\n *\n * It must be included between `0` and `1`. Default is `0.5`.\n *\n * @returns A random boolean value.\n */\n public static Boolean(ratio = 0.5): boolean\n {\n return (Math.random() < ratio);\n }\n\n /**\n * Generates a random integer value between `0` (included) and `max` (excluded).\n *\n * ---\n *\n * @example\n * ```ts\n * Random.Integer(5); // 0, 1, 2, 3, 4\n * ```\n *\n * ---\n *\n * @param max The maximum value (excluded).\n *\n * @returns A random integer value.\n */\n public static Integer(max: number): number;\n\n /**\n * Generates a random integer value between `min` (included) and `max` (excluded).\n *\n * ---\n *\n * @example\n * ```ts\n * Random.Integer(2, 7); // 2, 3, 4, 5, 6\n * ```\n *\n * ---\n *\n * @param min The minimum value (included).\n * @param max The maximum value (excluded).\n *\n * @returns A random integer value.\n */\n public static Integer(min: number, max: number): number;\n public static Integer(min: number, max?: number): number\n {\n if (max === undefined) { return Math.floor(Math.random() * min); }\n\n return Math.floor(Math.random() * (max - min) + min);\n }\n\n /**\n * Generates a random decimal value between `0` (included) and `1` (excluded).\n *\n * ---\n *\n * @example\n * ```ts\n * Random.Decimal(); // 0.123456789\n * ```\n *\n * ---\n *\n * @returns A random decimal value.\n */\n public static Decimal(): number;\n\n /**\n * Generates a random decimal value between `0` (included) and `max` (excluded).\n *\n * ---\n *\n * @example\n * ```ts\n * Random.Decimal(5); // 2.3456789\n * ```\n *\n * ---\n *\n * @param max The maximum value (excluded).\n *\n * @returns A random decimal value.\n */\n public static Decimal(max: number): number;\n\n /**\n * Generates a random decimal value between `min` (included) and `max` (excluded).\n *\n * ---\n *\n * @example\n * ```ts\n * Random.Decimal(2, 7); // 4.56789\n * ```\n *\n * ---\n *\n * @param min The minimum value (included).\n * @param max The maximum value (excluded).\n *\n * @returns A random decimal value\n */\n public static Decimal(min: number, max: number): number;\n public static Decimal(min?: number, max?: number): number\n {\n if (min === undefined) { return Math.random(); }\n if (max === undefined) { return (Math.random() * min); }\n\n return (Math.random() * (max - min) + min);\n }\n\n /**\n * Picks a random valid index from a given array of elements.\n *\n * ---\n *\n * @template T The type of the elements in the array.\n *\n * @param elements\n * The array of elements to pick from.\n *\n * It must contain at least one element. Otherwise, a {@link ValueException} will be thrown.\n *\n * @returns A valid random index from the given array.\n */\n public static Index<T>(elements: readonly T[]): number\n {\n if (elements.length === 0) { throw new ValueException(\"You must provide at least one element.\"); }\n\n return this.Integer(elements.length);\n }\n\n /**\n * Picks a random element from a given array of elements.\n *\n * ---\n *\n * @template T The type of the elements in the array.\n *\n * @param elements\n * The array of elements to pick from.\n *\n * It must contain at least one element. Otherwise, a {@link ValueException} will be thrown.\n *\n * @returns A random element from the given array.\n */\n public static Choice<T>(elements: readonly T[]): T\n {\n return elements[Random.Index(elements)];\n }\n\n private constructor() { /* ... */ }\n\n public readonly [Symbol.toStringTag]: string = \"Random\";\n}\n","/**\n * Returns a promise that resolves after a certain number of milliseconds. \n * It can be used to pause or delay the execution of an asynchronous function.\n *\n * ---\n *\n * @example\n * ```ts\n * doSomething();\n * await delay(1_000);\n * doSomethingElse();\n * ```\n *\n * ---\n *\n * @param milliseconds The number of milliseconds to wait before resolving the promise.\n *\n * @returns A {@link Promise} that resolves after the specified number of milliseconds.\n */\nexport function delay(milliseconds: number): Promise<void>\n{\n return new Promise((resolve) => setTimeout(resolve, milliseconds));\n}\n\n/**\n * Returns a promise that resolves on the next animation frame. \n * It can be used to synchronize operations with the browser's rendering cycle.\n *\n * ---\n *\n * @example\n * ```ts\n * const $el = document.querySelector(\".element\");\n *\n * $el.classList.add(\"animate\");\n * await nextAnimationFrame();\n * $el.style.opacity = \"1\";\n * ```\n *\n * ---\n *\n * @returns A {@link Promise} that resolves on the next animation frame.\n */\nexport function nextAnimationFrame(): Promise<void>\n{\n return new Promise((resolve) => requestAnimationFrame(() => resolve()));\n}\n\n/**\n * Returns a promise that resolves on the next microtask. \n * It can be used to yield to the event loop in long-running operations to prevent blocking the main thread.\n *\n * ---\n *\n * @example\n * ```ts\n * for (let i = 0; i < 100_000_000; i += 1)\n * {\n * doSomething(i);\n *\n * if (i % 100 === 0) await yieldToEventLoop();\n * }\n * ```\n *\n * ---\n *\n * @returns A {@link Promise} that resolves on the next microtask.\n */\nexport function yieldToEventLoop(): Promise<void>\n{\n return new Promise((resolve) => setTimeout(resolve));\n}\n","/**\n * Appends a script element to the document body. \n * It can be used to load external scripts dynamically.\n *\n * ---\n *\n * @example\n * ```ts\n * await loadScript(\"https://analytics.service/script.js?id=0123456789\");\n * ```\n *\n * ---\n *\n * @param scriptUrl The URL of the script to load.\n * @param scriptType The type of the script to load. Default is `\"text/javascript\"`.\n *\n * @returns\n * A {@link Promise} that resolves when the script has been loaded successfully or rejects if an error occurs.\n */\nexport function loadScript(scriptUrl: string, scriptType = \"text/javascript\"): Promise<void>\n{\n return new Promise<void>((resolve, reject) =>\n {\n const script = document.createElement(\"script\");\n\n script.async = true;\n script.defer = true;\n script.src = scriptUrl;\n script.type = scriptType;\n\n script.onload = (evt) => resolve();\n script.onerror = (reason) => reject(reason);\n\n document.body.appendChild(script);\n });\n}\n","import { RangeException, SmartIterator } from \"../models/index.js\";\n\n/**\n * An utility function that chains multiple iterables into a single one.\n *\n * Since the iterator is lazy, the chaining process will be\n * executed only once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * for (const value of chain([1, 2, 3], [4, 5, 6], [7, 8, 9]))\n * {\n * console.log(value); // 1, 2, 3, 4, 5, 6, 7, 8, 9\n * }\n * ```\n *\n * ---\n *\n * @template T The type of elements in the iterables.\n *\n * @param iterables The list of iterables to chain.\n *\n * @returns A new {@link SmartIterator} object that chains the iterables into a single one.\n */\nexport function chain<T>(...iterables: readonly Iterable<T>[]): SmartIterator<T>\n{\n return new SmartIterator<T>(function* ()\n {\n for (const iterable of iterables)\n {\n for (const element of iterable) { yield element; }\n }\n });\n}\n\n/**\n * An utility function that counts the number of elements in an iterable.\n *\n * Also note that:\n * - If the iterable isn't an {@link Array}, it will be consumed entirely in the process.\n * - If the iterable is an infinite generator, the function will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * count([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); // 10\n * ```\n *\n * ---\n *\n * @template T The type of elements in the iterable.\n *\n * @param elements The iterable to count.\n *\n * @returns The number of elements in the iterable.\n */\nexport function count<T>(elements: Iterable<T>): number\n{\n if (elements instanceof Array) { return elements.length; }\n\n let _count = 0;\n for (const _ of elements) { _count += 1; }\n\n return _count;\n}\n\n/**\n * An utility function that enumerates the elements of an iterable. \n * Each element is paired with its index in a new iterator.\n *\n * Since the iterator is lazy, the enumeration process will\n * be executed once the resulting iterator is materialized.\n *\n * A new iterator will be created, holding the reference to the original one. \n * This means that the original iterator won't be consumed until the\n * new one is and that consuming one of them will consume the other as well.\n *\n * ---\n *\n * @example\n * ```ts\n * for (const [index, value] of enumerate([\"A\", \"M\", \"N\", \"Z\"]))\n * {\n * console.log(`${index}: ${value}`); // \"0: A\", \"1: M\", \"2: N\", \"3: Z\"\n * }\n * ```\n *\n * ---\n *\n * @template T The type of elements in the iterable.\n *\n * @param elements The iterable to enumerate.\n *\n * @returns A new {@link SmartIterator} object containing the enumerated elements.\n */\nexport function enumerate<T>(elements: Iterable<T>): SmartIterator<[number, T]>\n{\n return new SmartIterator<[number, T]>(function* ()\n {\n let index = 0;\n for (const element of elements)\n {\n yield [index, element];\n\n index += 1;\n }\n });\n}\n\n/**\n * An utility function that generates an iterator over a range of numbers. \n * The values are included between `0` (included) and `end` (excluded).\n *\n * The default step between the numbers is `1`.\n *\n * ---\n *\n * @example\n * ```ts\n * for (const number of range(5))\n * {\n * console.log(number); // 0, 1, 2, 3, 4\n * }\n * ```\n *\n * ---\n *\n * @param end\n * The end value (excluded).\n *\n * If the `end` value is negative, the step will be `-1` leading to generate the numbers in reverse order.\n *\n * @returns A {@link SmartIterator} object that generates the numbers in the range.\n */\nexport function range(end: number): SmartIterator<number>;\n\n/**\n * An utility function that generates an iterator over a range of numbers. \n * The values are included between `start` (included) and `end` (excluded).\n *\n * The step between the numbers can be specified with a custom value. Default is `1`.\n *\n * ---\n *\n * @example\n * ```ts\n * for (const number of range(2, 7))\n * {\n * console.log(number); // 2, 3, 4, 5, 6\n * }\n * ```\n *\n * ---\n *\n * @param start\n * The start value (included).\n *\n * If the `start` value is greater than the `end` value, the iterator will generate the numbers in reverse order.\n *\n * @param end\n * The end value (excluded).\n *\n * If the `end` value is less than the `start` value, the iterator will generate the numbers in reverse order.\n *\n * @param step\n * The step between the numbers. Default is `1`.\n *\n * Must be a positive number. Otherwise, a {@link RangeError} will be thrown.\n *\n * @returns A {@link SmartIterator} object that generates the numbers in the range.\n */\nexport function range(start: number, end: number, step?: number): SmartIterator<number>;\nexport function range(start: number, end?: number, step = 1): SmartIterator<number>\n{\n if (step <= 0)\n {\n throw new RangeException(\n \"Step must be always a positive number, even when generating numbers in reverse order.\"\n );\n }\n\n if (end === undefined)\n {\n end = start;\n start = 0;\n }\n\n if (start > end)\n {\n return new SmartIterator<number>(function* ()\n {\n for (let index = start; index > end; index -= step) { yield index; }\n });\n }\n\n return new SmartIterator<number>(function* ()\n {\n for (let index = start; index < end; index += step) { yield index; }\n });\n}\n\n/**\n * An utility function shuffles the elements of a given iterable.\n *\n * The function uses the {@link https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle|Fisher-Yates}\n * algorithm to shuffle the elements.\n *\n * Also note that:\n * - If the iterable is an {@link Array}, it won't be modified since the shuffling isn't done in-place.\n * - If the iterable isn't an {@link Array}, it will be consumed entirely in the process.\n * - If the iterable is an infinite generator, the function will never return.\n *\n * ---\n *\n * @example\n * ```ts\n * shuffle([1, 2, 3, 4, 5]); // [3, 1, 5, 2, 4]\n * ```\n *\n * ---\n *\n * @template T The type of elements in the iterable.\n *\n * @param iterable The iterable to shuffle.\n *\n * @returns A new `Array` containing the shuffled elements of the given iterable.\n */\nexport function shuffle<T>(iterable: Iterable<T>): T[]\n{\n const array = Array.from(iterable);\n\n for (let index = array.length - 1; index > 0; index -= 1)\n {\n const jndex = Math.floor(Math.random() * (index + 1));\n\n [array[index], array[jndex]] = [array[jndex], array[index]];\n }\n\n return array;\n}\n\n/**\n * An utility function that filters the elements of an iterable ensuring that they are all unique.\n *\n * ---\n *\n * @example\n * ```ts\n * for (const value of unique([1, 1, 2, 3, 2, 3, 4, 5, 5, 4]))\n * {\n * console.log(value); // 1, 2, 3, 4, 5\n * }\n * ```\n *\n * ---\n *\n * @template T The type of elements in the iterable.\n *\n * @param elements The iterable to filter.\n *\n * @returns A {@link SmartIterator} object that iterates over the unique elements of the given iterable.\n */\nexport function unique<T>(elements: Iterable<T>): SmartIterator<T>\n{\n return new SmartIterator<T>(function* ()\n {\n const values = new Set<T>();\n for (const element of elements)\n {\n if (values.has(element)) { continue; }\n\n values.add(element);\n\n yield element;\n }\n });\n}\n\n/**\n * An utility function that zips two iterables into a single one. \n * The resulting iterable will contain the elements of the two iterables paired together.\n *\n * The function will stop when one of the two iterables is exhausted.\n *\n * ---\n *\n * @example\n * ```ts\n * for (const [number, char] of zip([1, 2, 3, 4], [\"A\", \"M\", \"N\" \"Z\"]))\n * {\n * console.log(`${number} - ${char}`); // \"1 - A\", \"2 - M\", \"3 - N\", \"4 - Z\"\n * }\n * ```\n *\n * ---\n *\n * @template T The type of elements in the first iterable.\n * @template U The type of elements in the second iterable.\n *\n * @param first The first iterable to zip.\n * @param second The second iterable to zip.\n *\n * @returns A {@link SmartIterator} object that iterates over the zipped elements of the two given iterables.\n */\nexport function zip<T, U>(first: Iterable<T>, second: Iterable<U>): SmartIterator<[T, U]>\n{\n const firstIterator = first[Symbol.iterator]();\n const secondIterator = second[Symbol.iterator]();\n\n return new SmartIterator<[T, U]>(function* ()\n {\n while (true)\n {\n const firstResult = firstIterator.next();\n const secondResult = secondIterator.next();\n\n if ((firstResult.done) || (secondResult.done)) { break; }\n\n yield [firstResult.value, secondResult.value];\n }\n });\n}\n","import { ValueException } from \"../models/exceptions/index.js\";\nimport { zip } from \"./iterator.js\";\n\n/**\n * Computes the average of a given list of values. \n * The values can be weighted using an additional list of weights.\n *\n * ---\n *\n * @example\n * ```ts\n * average([1, 2, 3, 4, 5]); // 3\n * average([6, 8.5, 4], [3, 2, 1]); // 6.5\n * ```\n *\n * ---\n *\n * @template T The type of the values in the list. It must be or extend a `number` object.\n *\n * @param values\n * The list of values to compute the average.\n *\n * It must contain at least one element. Otherwise, a {@link ValueException} will be thrown.\n *\n * @param weights\n * The list of weights to apply to the values. \n * It should contain the same number of elements as the values list or\n * the smaller number of elements between the two lists will be considered.\n *\n * The sum of the weights must be greater than zero. Otherwise, a {@link ValueException} will be thrown.\n *\n * @returns The average of the specified values.\n */\nexport function average<T extends number>(values: Iterable<T>, weights?: Iterable<number>): number\n{\n if (weights === undefined)\n {\n let _sum = 0;\n let _index = 0;\n\n for (const value of values)\n {\n _sum += value;\n _index += 1;\n }\n\n if (_index === 0) { throw new ValueException(\"You must provide at least one value.\"); }\n\n return _sum / _index;\n }\n\n let _sum = 0;\n let _count = 0;\n let _index = 0;\n\n for (const [value, weight] of zip(values, weights))\n {\n if (weight <= 0)\n {\n throw new ValueException(`The weight for the value #${_index} must be greater than zero.`);\n }\n\n _sum += value * weight;\n _count += weight;\n _index += 1;\n }\n\n if (_index === 0) { throw new ValueException(\"You must provide at least one value and weight.\"); }\n if (_count <= 0) { throw new ValueException(\"The sum of weights must be greater than zero.\"); }\n\n return _sum / _count;\n}\n\n/**\n * An utility function to compute the hash of a given string.\n *\n * The hash is computed using a simple variation of the\n * {@link http://www.cse.yorku.ca/~oz/hash.html#djb2|djb2} algorithm. \n * However, the hash is garanteed to be a 32-bit signed integer.\n *\n * ---\n *\n * @example\n * ```ts\n * hash(\"Hello, world!\"); // -1880044555\n * hash(\"How are you?\"); // 1761539132\n * ```\n *\n * ---\n *\n * @param value The string to hash.\n *\n * @returns The hash of the specified string.\n */\nexport function hash(value: string): number\n{\n let hashedValue = 0;\n for (let index = 0; index < value.length; index += 1)\n {\n const char = value.charCodeAt(index);\n\n hashedValue = ((hashedValue << 5) - hashedValue) + char;\n hashedValue |= 0;\n }\n\n return hashedValue;\n}\n\n/**\n * Sums all the values of a given list.\n *\n * ---\n *\n * @example\n * ```ts\n * sum([1, 2, 3, 4, 5]); // 15\n * ```\n *\n * ---\n *\n * @template T The type of the values in the list. It must be or extend a `number` object.\n *\n * @param values The list of values to sum.\n *\n * @returns The sum of the specified values.\n */\nexport function sum<T extends number>(values: Iterable<T>): number\n{\n let _sum = 0;\n for (const value of values) { _sum += value; }\n\n return _sum;\n}\n","/**\n * Capitalize the first letter of a string.\n *\n * ---\n *\n * @example\n * ```ts\n * capitalize('hello'); // 'Hello'\n * ```\n *\n * ---\n *\n * @param value The string to capitalize.\n *\n * @returns The capitalized string.\n */\nexport function capitalize(value: string): string\n{\n return `${value.charAt(0).toUpperCase()}${value.slice(1)}`;\n}\n","export const VERSION = \"2.1.4\";\n\nexport type { Constructor, Interval, Timeout, ValueOf } from \"./core/types.js\";\n\nexport { isBrowser, isNode, isWorker } from \"./helpers.js\";\n\nexport {\n AggregatedIterator,\n AggregatedAsyncIterator,\n CallableObject,\n Clock,\n Countdown,\n DeferredPromise,\n EnvironmentException,\n Exception,\n FatalErrorException,\n FileException,\n FileExistsException,\n FileNotFoundException,\n GameLoop,\n JSONStorage,\n KeyException,\n MapView,\n NotImplementedException,\n NetworkException,\n PermissionException,\n Publisher,\n RangeException,\n ReducedIterator,\n ReferenceException,\n RuntimeException,\n SetView,\n SmartIterator,\n SmartAsyncIterator,\n SmartPromise,\n SwitchableCallback,\n TimeoutException,\n TimedPromise,\n TypeException,\n ValueException\n\n} from \"./models/index.js\";\n\nexport type {\n AsyncGeneratorFunction,\n AsyncIteratee,\n AsyncIteratorLike,\n AsyncKeyedIteratee,\n AsyncKeyedReducer,\n AsyncReducer,\n Callback,\n CallbackMap,\n FulfilledHandler,\n GeneratorFunction,\n Iteratee,\n IteratorLike,\n JSONArray,\n JSONObject,\n JSONValue,\n KeyedIteratee,\n KeyedReducer,\n KeyedTypeGuardPredicate,\n MapViewEventsMap,\n MaybeAsyncKeyedIteratee,\n MaybeAsyncKeyedReducer,\n MaybeAsyncGeneratorFunction,\n MaybeAsyncIteratee,\n MaybeAsyncIteratorLike,\n MaybeAsyncReducer,\n MaybePromise,\n PromiseExecutor,\n PromiseRejecter,\n PromiseResolver,\n Publishable,\n ReadonlyMapView,\n ReadonlySetView,\n Reducer,\n RejectedHandler,\n SetViewEventsMap,\n Subscribable,\n TypeGuardPredicate\n\n} from \"./models/types.js\";\n\nexport {\n average,\n capitalize,\n chain,\n count,\n Curve,\n delay,\n dateDifference,\n dateRange,\n dateRound,\n TimeUnit,\n enumerate,\n getWeek,\n hash,\n loadScript,\n nextAnimationFrame,\n Random,\n range,\n shuffle,\n sum,\n unique,\n WeekDay,\n yieldToEventLoop,\n zip\n\n} from \"./utils/index.js\";\n"],"names":["isBrowser","isNode","_a","isWorker","_b","Exception","_d","_c","message","cause","name","__publicField","error","exc","FatalErrorException","_f","_e","NotImplementedException","_h","_g","FileException","_j","_i","FileExistsException","_l","_k","FileNotFoundException","_n","_m","KeyException","_p","_o","NetworkException","_r","_q","PermissionException","_t","_s","ReferenceException","_v","_u","RuntimeException","_x","_w","EnvironmentException","_z","_y","TimeoutException","_B","_A","TypeException","_D","_C","ValueException","_F","_E","RangeException","_H","_G","SmartIterator","argument","_I","predicate","index","result","iterator","iteratee","reducer","initialValue","accumulator","elements","value","count","limit","values","AggregatedIterator","element","_J","_ReducedIterator","key","_","ReducedIterator","_K","_AggregatedAsyncIterator","SmartAsyncIterator","indexes","finding","keys","counters","map","groups","AggregatedAsyncIterator","_L","generator","next","_value","_M","_AggregatedIterator","SmartFunction","CallableObject","_O","_N","self","_P","_Publisher","scope","propagator","event","args","results","subscribers","subscriber","Publisher","Disabler","SwitchableCallback","_R","_Q","callback","MapView","_T","_S","iterable","size","SetView","_V","_U","_W","JSONStorage","preferPersistence","storage","defaultValue","newValue","encodedValue","persistent","_X","_SmartPromise","executor","_onFulfilled","_onRejected","reason","promise","resolve","reject","onFulfilled","onRejected","onFinally","SmartPromise","DeferredPromise","_Z","_Y","_resolve","_reject","otherPromise","TimedPromise","_$","__","timeout","_timeoutId","TimeUnit","WeekDay","dateDifference","start","end","unit","_round","dateRange","step","endTime","unixTime","dateRound","date","getWeek","firstDay","startCorrector","weekDayIndex","firstDayTime","_aa","GameLoop","msIfNotBrowser","elapsedTime","Clock","_ca","_ba","tickStep","lastTick","Countdown","_ea","_da","duration","remainingTime","_fa","Curve","steps","base","_ga","_Random","ratio","min","max","Random","delay","milliseconds","nextAnimationFrame","yieldToEventLoop","loadScript","scriptUrl","scriptType","script","evt","chain","iterables","_count","enumerate","range","shuffle","array","jndex","unique","zip","first","second","firstIterator","secondIterator","firstResult","secondResult","average","weights","_sum","_index","weight","hash","hashedValue","char","sum","capitalize","VERSION"],"mappings":"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"}
|