UNPKG

inventoresed

Version:

Z-Wave driver written entirely in JavaScript/TypeScript

87 lines (80 loc) 2.67 kB
import type { JSONObject } from "@zwave-js/shared"; import { composeObject } from "alcalzone-shared/objects"; import { isArray, isObject } from "alcalzone-shared/typeguards"; import { Duration } from "./Duration"; import type { ValueMetadata } from "./Metadata"; import type { ValueID } from "./_Types"; // export type SerializableValue = number | string | boolean | Map<string | number, any> | JSONObject; type SerializedValue = number | string | boolean | JSONObject | undefined; export interface CacheValue extends Pick<ValueID, "endpoint" | "property" | "propertyKey"> { value: SerializedValue; } export interface CacheMetadata extends Pick<ValueID, "endpoint" | "property" | "propertyKey"> { metadata: ValueMetadata; } const SPECIAL_TYPE_KEY = "$$type$$"; /** Serializes a value so it can be stored in a JSON object (and later on disk) */ export function serializeCacheValue(value: unknown): SerializedValue { if (value instanceof Map) { // We mark maps with a special key, so they can be detected by the deserialization routine return { ...composeObject( [...value.entries()].map(([k, v]) => [ k, serializeCacheValue(v), ]), ), [SPECIAL_TYPE_KEY]: "map", }; } else if (value instanceof Duration) { const valueAsJSON = value.toJSON(); return { ...(typeof valueAsJSON === "string" ? { unit: valueAsJSON } : valueAsJSON), [SPECIAL_TYPE_KEY]: "duration", }; } else if (Buffer.isBuffer(value)) { return { [SPECIAL_TYPE_KEY]: "buffer", data: value.toString("hex"), }; } else if ( typeof value === "number" || typeof value === "string" || typeof value === "boolean" || isObject(value) || isArray(value) ) { return value; } } /** Deserializes a value that was serialized by serializeCacheValue */ export function deserializeCacheValue(value: SerializedValue): unknown { if (isObject(value)) { const specialType = (value as Record<any, SerializedValue>)[ SPECIAL_TYPE_KEY ]; // Convert objects which used to be a map back to a Map if (specialType === "map") { const { [SPECIAL_TYPE_KEY]: _, ...rest } = value as Record< any, SerializedValue >; return new Map<unknown, unknown>( Object.entries(rest) // We assume that all keys that resemble a number should be a number .map(([k, v]) => [/^\d+$/.test(k) ? parseInt(k, 10) : k, v]) // recursively deserialize the value .map(([k, v]) => [k, deserializeCacheValue(v)]), ); } else if (specialType === "duration") { return new Duration(value.value ?? 1, value.unit); } else if (specialType === "buffer") { return Buffer.from(value.data, "hex"); } } return value; }