import { primitive, PropSchema } from "serializr"; function invariant(cond: boolean, message?: string) { if (!cond) { throw new Error("[serializr] " + (message || "Illegal State")); } } function isPropSchema(thing: any) { return thing && thing.serializer && thing.deserializer; } function isAliasedPropSchema(propSchema: any) { return typeof propSchema === "object" && !!propSchema.jsonname; } function parallel(ar: any[], processor: (item: any, done: any) => void, cb: any) { if (ar.length === 0) { return void cb(null, []); } let left = ar.length; const resultArray: any[] = []; let failed = false; const processorCb = (idx: number, err: any, result: any) => { if (err) { if (!failed) { failed = true; cb(err); } } else if (!failed) { resultArray[idx] = result; if (--left === 0) { cb(null, resultArray); } } }; ar.forEach((value, idx) => processor(value, processorCb.bind(null, idx))); } export default function list(propSchema: PropSchema): PropSchema { propSchema = propSchema || primitive(); invariant(isPropSchema(propSchema), "expected prop schema as first argument"); invariant(!isAliasedPropSchema(propSchema), "provided prop is aliased, please put aliases first"); return { serializer(ar) { invariant(ar && typeof ar.length === "number" && typeof ar.map === "function", "expected array (like) object"); return ar.map(propSchema.serializer); }, deserializer(jsonArray, done, context) { if (jsonArray === null) { // sometimes go will return null in place of empty array return void done(null, []); } if (!Array.isArray(jsonArray)) { return void done("[serializr] expected JSON array", null); } parallel( jsonArray, (item: any, itemDone: (err: any, targetPropertyValue: any) => void) => propSchema.deserializer(item, itemDone, context, undefined), done, ); }, }; }