
export interface ExtendableLike {
  extensions?: Record<string, unknown> | null | undefined;
}

export function getExtensions ( extendable: ExtendableLike ) {
  return (extendable.extensions ??= { });
}

export function hasExtension (
  extendable: ExtendableLike, key: string | symbol
) {
  return key in getExtensions(extendable);
}

export function getExtension<T = unknown> (
  extendable: ExtendableLike, key: string | symbol
): T | undefined;
export function getExtension<T = unknown> (
  extendable: ExtendableLike, key: string | symbol, fallback: T
): T;
export function getExtension<T = unknown> (
  extendable: ExtendableLike, key: string | symbol, fallback?: T
) {
  const extensions = getExtensions(extendable);

  return (extensions[key as string] ??= fallback) as T;
}

export function setExtension (
  extendable: ExtendableLike, key: string | symbol, value: unknown
) {
  getExtensions(extendable)[key as string] = value;
}
