//·························································· // Copyright (c) 2023-2026. Jonathan Bédard ~ JóôòKiwi // // This project is free to use. // All the right is reserved to the author of this project. // My projects: // - https://github.com/joooKiwi/type // - https://github.com/joooKiwi/lazy // - https://github.com/joooKiwi/collection // - https://github.com/joooKiwi/enumeration //·························································· import type {BigIntOrObject, MutableArray, NullOr, NullOrUndefined, Nullable, NumericOrObject, StringOrNumericOrObject, StringOrObject, TemplateOrNumber, TemplateOrNumericOrObject} from "@joookiwi/type" import type {Enumerable} from "../Enumerable" import type {EnumerableConstructor} from "../EnumerableConstructor" import type {EnumerableWithNullableGrandParent} from "../EnumerableWithNullableGrandParent" import type {EnumerableWithNullableParent} from "../EnumerableWithNullableParent" import type {CompanionEnumerable} from "./CompanionEnumerable" import type {CompanionEnumerableWithGrandParent} from "./CompanionEnumerableWithGrandParent" import type {CompanionEnumerableWithParent} from "./CompanionEnumerableWithParent" import type {CompanionEnumerableType, CompanionEnumerableWithParentType} from "../type/companion" import type {ImpossibleNames} from "../type/name" import type {NameOf, SpecificNameOf} from "../type/nameOf" import type {OrdinalOf, SpecificOrdinalOf} from "../type/ordinalOf" import type {NameByOrdinal, OrdinalByName, ValueByName, ValueBySpecificName, ValueBySpecificOrdinal} from "../type/valueBy" import type {EnumerableWithNullableGrandParentGeneralType, EnumerableWithNullableParentGeneralType} from "../type/general" import {Enum} from "../Enum" import {EnumWithNullableGrandParent} from "../EnumWithNullableGrandParent" import {EnumWithNullableParent} from "../EnumWithNullableParent" import {EnumWithGrandParent} from "../EnumWithGrandParent" import {EnumWithParent} from "../EnumWithParent" import {CompanionEnumWithParent} from "./CompanionEnumWithParent" import {InvalidEnumerableException} from "../exception/InvalidEnumerableException" import {InvalidInstanceException} from "../exception/InvalidInstanceException" import {NullInstanceException} from "../exception/NullInstanceException" import {NullReferenceException} from "../exception/NullReferenceException" import {_hasPrototypeOf} from "../method/_hasPrototypeOf" import {_getSimplifiedPrototypeChains} from "../method/_getSimplifiedPrototypeChains" export class CompanionEnumWithGrandParent, const ENUM_CONSTRUCTOR extends EnumerableConstructor>, const PARENT_ENUM extends EnumerableWithNullableParent, const PARENT_ENUM_CONSTRUCTOR extends EnumerableConstructor>, const GRAND_PARENT_ENUM extends Enumerable, const GRAND_PARENT_ENUM_CONSTRUCTOR extends EnumerableConstructor>, > extends CompanionEnumWithParent implements CompanionEnumerableWithGrandParent { //#region -------------------- Fields -------------------- readonly #grandParentInstance: GRAND_PARENT_ENUM_CONSTRUCTOR //#endregion -------------------- Fields -------------------- //#region -------------------- Constructor -------------------- protected constructor(instance: ENUM_CONSTRUCTOR, parentInstance: PARENT_ENUM_CONSTRUCTOR, grandParentInstance: GRAND_PARENT_ENUM_CONSTRUCTOR,) { super(instance, parentInstance,) __validateInstance(instance,) __validateParentInstance(parentInstance,) if (grandParentInstance == null) throw new NullInstanceException() if (!(grandParentInstance instanceof Function)) throw new InvalidInstanceException(`Invalid instance exception. The grandparent instance received in “${this.constructor.name}” is not a function type.`, grandParentInstance,) this.#grandParentInstance = __validateGrandParentInstance(grandParentInstance,) } //#endregion -------------------- Constructor -------------------- //#region -------------------- Getter & setter methods -------------------- public get grandParentInstance(): GRAND_PARENT_ENUM_CONSTRUCTOR { return this.#grandParentInstance } public override get defaultValue(): ENUM { return super.defaultValue } public override set defaultValue(value: Nullable<| StringOrNumericOrObject | ENUM | PARENT_ENUM | GRAND_PARENT_ENUM>) { super.defaultValue = value == null ? null : this._getValue(value,) } public override setDefaultValue(value: NullOrUndefined,): this public override setDefaultValue(value: ImpossibleNames,): never public override setDefaultValue(ordinal: Nullable,): this public override setDefaultValue(name: Nullable,): this public override setDefaultValue(enumerable: Nullable,): this public override setDefaultValue(parentEnumerable: Nullable,): this public override setDefaultValue(grandParentEnumerable: Nullable,): this public override setDefaultValue(value: Nullable<| StringOrNumericOrObject | ENUM | PARENT_ENUM | GRAND_PARENT_ENUM>,): this public override setDefaultValue(value: Nullable<| StringOrNumericOrObject | ENUM | PARENT_ENUM | GRAND_PARENT_ENUM>): this { this.defaultValue = value return this } //#endregion -------------------- Getter & setter methods -------------------- //#region -------------------- Methods -------------------- //#region -------------------- Validation methods -------------------- //#region -------------------- Get value (validated) methods -------------------- /** * Get a valid value that is a valid {@link EnumerableWithNullableGrandParent} * for the current {@link instance}, {@link parentInstance} or {@link grandParentInstance} * * @param enumerable The instance to validate * @throws {InvalidEnumerableException} * @throws {NullReferenceException} */ protected override _getValidValueByEnumerable(enumerable: Enumerable,): ENUM { const instance = this.instance if (enumerable instanceof instance) return this._getValueFromValues(enumerable,) const parentInstance = this.parentInstance if (enumerable instanceof parentInstance) return this._getValueFromValuesByParent(enumerable,) const grandParentInstance = this.grandParentInstance if (enumerable instanceof grandParentInstance) return this._getValueFromValuesByGrandParent(enumerable,) throw new InvalidEnumerableException(`The enumerable “${instance.name}.${enumerable.name}” is not an instance of “${instance.name}”, “${parentInstance.name}” or “${grandParentInstance.name}”.`, enumerable, [instance, parentInstance, grandParentInstance,],) } //#endregion -------------------- Get value (validated) methods -------------------- //#region -------------------- Get value from … methods -------------------- /** * Get an {@link Enumerable} * by the {@link EnumerableWithNullableGrandParent.grandParent grandparent} * or throw a {@link NullReferenceException} if never found * * @param value The {@link Enumerable} to find * @throws {NullReferenceException} */ protected _getValueFromValuesByGrandParent(value: Enumerable,): ENUM { const valueFound = this.values.findFirstOrNull(it => it.grandParent === value) if (valueFound == null) throw new NullReferenceException(`No grandparent “${value}” could be found on the “${this.instance.name}”.`, value,) return valueFound } //#endregion -------------------- Get value from … methods -------------------- //#endregion -------------------- Validation methods -------------------- public override getValue (value: Nullable,): never public override getValue (ordinal: Nullable,): ValueBySpecificOrdinal public override getValue (ordinal: Nullable>,): ValueBySpecificOrdinal public override getValue (ordinal: Nullable,): ENUM public override getValue (name: Nullable,): ValueBySpecificName public override getValue (nameOrOrdinal: Nullable,): ENUM public override getValue (instance: Nullable,): INSTANCE public override getValue (parentInstance: Nullable,): ValueByName public override getValue (grandParentInstance: Nullable,): ValueByName public override getValue(value: Nullable<| TemplateOrNumber | NAME | String | Number | BigIntOrObject | INSTANCE | PARENT_INSTANCE | GRAND_PARENT_INSTANCE>,): | ValueBySpecificOrdinal | ValueBySpecificName | INSTANCE | ValueByName | ValueByName | ENUM public override getValue(value: Nullable<| StringOrNumericOrObject | ENUM | PARENT_ENUM | GRAND_PARENT_ENUM>,) { return this._getValue(value,) } public override getName (value: Nullable,): never public override getName (ordinal: Nullable,): NameByOrdinal public override getName (ordinal: Nullable>,): NameByOrdinal public override getName (ordinal: Nullable,): NameOf public override getName (name: Nullable,): SpecificNameOf public override getName (nameOrOrdinal: Nullable,): NameOf public override getName (instance: Nullable,): NameOf public override getName (parentInstance: Nullable,): NameOf public override getName (grandParentInstance: Nullable,): NameOf public override getName(value: Nullable<| TemplateOrNumber | NAME | String | Number | BigIntOrObject | INSTANCE | PARENT_INSTANCE | GRAND_PARENT_INSTANCE>,): | NameByOrdinal | SpecificNameOf | NameOf | NameOf | NameOf | NameOf public override getName(value: Nullable<| StringOrNumericOrObject | ENUM | PARENT_ENUM | GRAND_PARENT_ENUM>,) { return this._getName(value,) } public override getOrdinal (value: Nullable,): never public override getOrdinal (ordinal: Nullable,): SpecificOrdinalOf public override getOrdinal (ordinal: Nullable>,): SpecificOrdinalOf public override getOrdinal (ordinal: Nullable,): OrdinalOf public override getOrdinal (name: Nullable,): OrdinalByName public override getOrdinal (nameOrOrdinal: Nullable,): OrdinalOf public override getOrdinal (instance: Nullable,): OrdinalOf public override getOrdinal (parentInstance: Nullable,): OrdinalOf public override getOrdinal (grandParentInstance: Nullable,): OrdinalOf public override getOrdinal(value: Nullable<| TemplateOrNumber | NAME | String | Number | BigIntOrObject | INSTANCE | PARENT_INSTANCE | GRAND_PARENT_INSTANCE>,): | OrdinalByName | SpecificOrdinalOf | OrdinalOf | OrdinalOf | OrdinalOf | OrdinalOf public override getOrdinal(value: Nullable<| StringOrNumericOrObject | ENUM | PARENT_ENUM | GRAND_PARENT_ENUM>,) { return this._getOrdinal(value,) } //#endregion -------------------- Methods -------------------- } /** * Validate that the {@link grandParentInstance} is a relative to {@link Enum} or has the structure of an {@link Enumerable} * * @param grandParentInstance The {@link CompanionEnumerable} constructor to validate * @throws InvalidInstanceException It is not a relative to {@link Enum} or does not have the structure of an {@link Enumerable} */ function __validateGrandParentInstance>, >( grandParentInstance: GRAND_PARENT_ENUM_CONSTRUCTOR,): GRAND_PARENT_ENUM_CONSTRUCTOR { if (_hasPrototypeOf(grandParentInstance, Enum,)) // Is relative to the Enum class return grandParentInstance const parentInstancePrototype = grandParentInstance.prototype as NullOr if (parentInstancePrototype != null) if ("name" in parentInstancePrototype) if ("ordinal" in parentInstancePrototype) if (Symbol.toStringTag in parentInstancePrototype) if (Symbol.toPrimitive in parentInstancePrototype) // Is Enumerable by structure return grandParentInstance // We now know that it is invalid. // We will get its chain to display in a simplified manner toward the inheritance let prototype: NullOr = grandParentInstance const prototypeChain: MutableArray = [] while (prototype != null) { prototypeChain.push(prototype,) prototype = Reflect.getPrototypeOf(prototype,) } throw new InvalidInstanceException(`Invalid instance exception. The grandparent instance received in ${_getSimplifiedPrototypeChains(prototypeChain,)} does not have an inheritor of “Enum” or the structure of an “Enumerable”.`, grandParentInstance,) } /** * Validate that the {@link parentInstance} is a relative to {@link EnumWithNullableParent}, {@link EnumWithParent} or has the structure of an {@link EnumerableWithParent} * * @param parentInstance The {@link CompanionEnumerableWithParent} constructor to validate * @throws InvalidInstanceException It is not a relative to {@link EnumWithNullableParent}|{@link EnumWithParent} or does not have the structure of an {@link EnumerableWithParent} */ function __validateParentInstance>>>, >( parentInstance: PARENT_ENUM_CONSTRUCTOR,): void { if (_hasPrototypeOf(parentInstance, EnumWithNullableParent,)) // Is relative to the EnumWithNullableParent class return if (_hasPrototypeOf(parentInstance, EnumWithParent,)) // Is relative to the EnumWithParent class return if ("parent" in (parentInstance.prototype as object)) // Is EnumerableWithParent by structure return // We now know that it is invalid. // We will get its chain to display in a simplified manner toward the inheritance let prototype: NullOr = parentInstance const prototypeChain: MutableArray = [] while (prototype != null) { prototypeChain.push(prototype,) prototype = Reflect.getPrototypeOf(prototype,) } throw new InvalidInstanceException(`Invalid instance exception. The parent instance received in ${_getSimplifiedPrototypeChains(prototypeChain,)} does not have an inheritor of “EnumWithNullableParent”, “EnumWithParent” or the structure of an “EnumerableWithParent”.`, parentInstance,) } /** * Validate that the {@link instance} is a relative to {@link EnumWithNullableGrandParent}, {@link EnumWithGrandParent} or has the structure of an {@link EnumerableWithGrandParent} * * @param instance The {@link CompanionEnumerableWithGrandParent} constructor to validate * @throws InvalidInstanceException It is not a relative to {@link EnumWithNullableGrandParent}|{@link EnumWithGrandParent} or does not have the structure of an {@link EnumerableWithGrandParent} */ function __validateInstance>, Enumerable, EnumerableConstructor>>>, >( instance: ENUM_CONSTRUCTOR,): void { if (_hasPrototypeOf(instance, EnumWithNullableGrandParent,)) // Is relative to the EnumWithNullableGrandParent class return if (_hasPrototypeOf(instance, EnumWithGrandParent,)) // Is relative to the EnumWithGrandParent class return if ("grandParent" in (instance.prototype as object)) // Is EnumerableWithGrandParent by structure return // We now know that it is invalid. // We will get its chain to display in a simplified manner toward the inheritance let prototype: NullOr = instance const prototypeChain: MutableArray = [] while (prototype != null) { prototypeChain.push(prototype,) prototype = Reflect.getPrototypeOf(prototype,) } throw new InvalidInstanceException(`Invalid instance exception. The instance received in ${_getSimplifiedPrototypeChains(prototypeChain,)} does not have an inheritor of “EnumWithNullableGrandParent”, “EnumWithGrandParent” or the structure of an “EnumerableWithGrandParent”.`, instance,) }