Source: config.ts

/**
 * Configuration utility functions
 * @module config
 */

/**
 * Tuple containing value, key, and label
 * @typedef {[string|number, string, string]} DataTuple
 */
type DataTuple = readonly [value: string | number, key: string, label: string];

/**
 * Array of data tuples
 * @typedef {readonly DataTuple[]} DataTupleDataSource
 */
export type DataTupleDataSource = readonly DataTuple[];

/**
 * Index types for data tuple
 * @typedef {0|1|2} DataTupleIndex
 */
type DataTupleIndex = 0 | 1 | 2;

/**
 * Extracts values from tuple based on key and value indices
 * @template T - Data tuple type
 * @template KeyIndex - Index for key
 * @template ValueIndex - Index for value
 */
export type ExtractFromTuple<T extends DataTuple, KeyIndex extends DataTupleIndex, ValueIndex extends DataTupleIndex>
    = {
    [K in T[KeyIndex]]: Extract<
        T,
        KeyIndex extends 0
            ? (readonly [K, any, any])
            : (
                KeyIndex extends 1
                    ? (readonly [any, K, any])
                    : (readonly [any, any, K])
            )
    >[ValueIndex];
};

type ValueMapByKey<T extends DataTuple> = ExtractFromTuple<T, 1, 0>;
type KeyMapByValue<T extends DataTuple> = ExtractFromTuple<T, 0, 1>;
type NameMapByValue<T extends DataTuple> = ExtractFromTuple<T, 0, 2>;
type NameMapByKey<T extends DataTuple> = ExtractFromTuple<T, 1, 2>;

type DataSource<T extends DataTupleDataSource> = {
    [K in keyof T]: {
        label: T[K][2];
        value: T[K][0];
        key: T[K][1];
    };
};

interface ResultBase<T extends DataTupleDataSource> {
    valueMapByKey: ValueMapByKey<T[number]>;
    keyMapByValue: KeyMapByValue<T[number]>;
    nameMapByValue: NameMapByValue<T[number]>;
    nameMapByKey: NameMapByKey<T[number]>;
}

type Result<T extends DataTupleDataSource> = {
    readonly [K in keyof ResultBase<T>]: Readonly<ResultBase<T>[K]>;
};

/**
 * Maps configuration data into various lookup objects
 * @param {DataTupleDataSource} dataSource - Source data array
 * @returns {Object} Object containing various mappings of the data
 * @example
 * ```ts
 * const data = [
 *   [1, 'A', '文案A'],
 *   [2, 'B', '文案B']
 * ] as const;
 * const result = getConfigFromDataSource(data);
 * // result = {
 * //   valueMapByKey: { A: 1, B: 2 },
 * //   keyMapByValue: { 1: 'A', 2: 'B' },
 * //   nameMapByValue: { 1: '文案A', 2: '文案B' },
 * //   nameMapByKey: { A: '文案A', B: '文案B' }
 * // }
 * ```
 */
export function getConfigFromDataSource<T extends DataTupleDataSource>(dataSource: T): Readonly<
    Result<T> & { dataSource: DataSource<T> }
> {
    const initialResult = {
        valueMapByKey: {},
        keyMapByValue: {},
        nameMapByValue: {},
        nameMapByKey: {},
        dataSource: [] as DataSource<T>,
    } as unknown as (ResultBase<T> & { dataSource: DataSource<T> });

    const ds: any[] = [];

    const result = dataSource.reduce((r, [value, key, name]) => {
        type Key = keyof typeof r.valueMapByKey;
        type Value = keyof typeof r.keyMapByValue;
        if (r.valueMapByKey[key as Key] !== undefined) {
            throw new Error(`Duplicate key "${key}" found in dataSource.`);
        }
        if (r.keyMapByValue[value as Value] !== undefined) {
            throw new Error(`Duplicate value "${value}" found in dataSource.`);
        }
        r.valueMapByKey[key as Key] = value;
        r.keyMapByValue[value as Value] = key;
        r.nameMapByValue[value as Value] = name;
        r.nameMapByKey[key as Key] = name;
        ds.push({
            label: name,
            value,
            key,
        });
        return r;
    }, initialResult);

    result.dataSource = ds as DataSource<T>;
    return result;
}