import {primitive, PropSchema} from 'serializr'; function invariant(cond: boolean, message?: string) { if (!cond) { throw new Error('[serializr] ' + (message || 'Illegal ServerState')); } } 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); }, beforeDeserialize: () => {}, afterDeserialize: () => {}, }; }