import {mapDecoder} from '../../coder/map/map-decoder.js'; import {mapEncoder} from '../../coder/map/map-encoder.js'; import {IncompatibleLiteralError} from '../../error/incompatible-literal-error.js'; import type {Decoding} from '../../type/decoding.js'; import type {Encoding} from '../../type/encoding.js'; import {every} from '../../util/every.js'; import {isArray} from '../../util/guard/is-array.js'; import {isEntry} from '../../util/guard/is-entry.js'; import {isMap} from '../../util/guard/is-map.js'; import {map} from '../../util/map.js'; import {ValueTransformer} from '../value/value-transformer.js'; export class MapTransformer< KI, KO extends KI, VI, VO extends VI, > extends ValueTransformer, Map> { readonly #keyTransformer: ValueTransformer; readonly #valueTransformer: ValueTransformer; public constructor( keyTransformer: ValueTransformer, valueTransformer: ValueTransformer, ) { super(); this.#valueTransformer = valueTransformer; this.#keyTransformer = keyTransformer; } public compatibleWith(data: unknown): data is ReadonlyMap { return ( isMap(data) && every( data, ([key, value]) => this.#keyTransformer.compatibleWith(key) && this.#valueTransformer.compatibleWith(value), ) ); } public decoder(): Decoding> { return mapDecoder( () => this.#keyTransformer.decoder(), () => this.#valueTransformer.decoder(), ); } public encoder(data: ReadonlyMap): Encoding { console.assert(isMap(data)); return mapEncoder( data, (key) => this.#keyTransformer.encoder(key), (value) => this.#valueTransformer.encoder(value), ); } public fromLiteral(literal: unknown): Map { if (!isArray(literal)) { throw new IncompatibleLiteralError(); } return new Map( map(literal, (item) => { if (!isArray(item) || !isEntry(item)) { throw new IncompatibleLiteralError(); } const [key, value]: readonly [unknown, unknown] = item; return [ this.#keyTransformer.fromLiteral(key), this.#valueTransformer.fromLiteral(value), ]; }), ); } public toLiteral(data: ReadonlyMap, compact: boolean): unknown { console.assert(isMap(data)); return Array.from( data, ([key, value]) => [ this.#keyTransformer.toLiteral(key, compact), this.#valueTransformer.toLiteral(value, compact), ], ); } }