{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/serialization.ts"],"sourcesContent":["import { stack, stackwrap, TransformationError } from \"./errors\"\nimport { DefaultSerializationConfig } from \"./serialization\"\nimport { Bound, Stack, Literal, PrimitiveRecord, SerializationConfig, Unwrap } from \"./types\"\n\nexport * from \"./serialization\"\nexport * from \"./types\"\n\n/** represents any type. use with care. */\nexport function any(): Bound<any, any> {\n  return {\n    transform: (object: any) => object,\n    restore: (json: any) => json\n  }\n}\n\n/** validate a value with given functions upon transformation/restoration */\nexport function validated<T extends Literal>(\n  validator: (v: any) => boolean,\n  reason: (v: any) => string = () => 'Failed validation'\n): Bound<T, Literal> {\n  return {\n    transform: (object: T, s: Stack) => {\n      if (!validator(object)) {\n        throw new TransformationError(reason(object), s, object)\n      }\n\n      return object as Literal\n    },\n    restore: (json: Literal, s: Stack) => {\n      if (!validator(json)) {\n        throw new TransformationError(reason(object), s, object)\n      }\n\n      return json as T\n    }\n  }\n}\n\n/** Make a provided type expression optional */\nexport function optional<T, L>(schema: Bound<T, L>): Bound<T|undefined, L|undefined> {\n  return {\n    transform: (object: T|undefined, s: Stack) => {\n      return object === undefined ? undefined : schema.transform(object, s)\n    },\n    restore: (json: L, s: Stack) => {\n      return json === undefined ? undefined : schema.restore(json, s)\n    },\n    attributes: {\n      optional: true\n    }\n  }\n}\n\n/** Make a provided type expression nullable */\nexport function nullable<T, L>(schema: Bound<T, L>): Bound<T|null, L|null> {\n  return {\n    transform: (object: T|null, s: Stack) => {\n      return object === null ? null : schema.transform(object, s)\n    },\n    restore: (json: L, s: Stack) => {\n      return json === null ? null : schema.restore(json, s)\n    },\n    attributes: {\n      nullable: true\n    }\n  }\n}\n\n/** Extend an existing object schema with another */\nexport function extendObject<BS extends {}, BD, WS extends {}, WD>(baseSchema: Bound<BS, BD>, withSchema: Bound<WS, WD>): Bound<BS&WS, BD&WD> {\n  return {\n    transform: (object: BS&WS, s: Stack) => {\n      return {\n        ...baseSchema.transform(object, s),\n        ...withSchema.transform(object, s)\n      }\n    },\n    restore: (json: BD&WD, s: Stack) => {\n      return {\n        ...baseSchema.restore(json, s),\n        ...withSchema.restore(json, s)\n      }\n    }\n  }\n}\n\n/** expresses a literal value of any type */\nexport function literal<T extends Literal>(value: T): Bound<T, T> {\n  return stackwrap(validated<T>((v: any) => v === value) as unknown as Bound<T, T>, 'literal')\n}\n\n/** expresses a string value */\nexport const string = () => stackwrap(\n  validated<string>((v: any) => typeof v === 'string', v => `expected 'string', received '${typeof v}'`),\n  'string'\n) as Bound<string, string>\n\n/** expresses a numeric value */\nexport const number = () => stackwrap(\n  validated<number>((v: any) => typeof v === 'number', v => `expected 'number', received '${typeof v}'`),\n  'number'\n) as Bound<number, number>\n\n/** expresses a boolean value */\nexport const boolean = () => stackwrap(\n  validated<boolean>((v: any) => typeof v === 'boolean', v => `expected 'boolean', received '${typeof v}'`),\n  'boolean'\n) as Bound<boolean, boolean>\n\n/** expresses a null value (called nil, because null is a reserved keyword) */\nexport const nil = () => stackwrap(\n  validated<null>((v: any) => v === null, v => `expected 'null', received '${typeof v}'`),\n  'nil'\n) as Bound<null, null>\n\n/**\n * Express an object with unknown key values and associated values\n * @param keySchema expression of key type\n * @param valueSchema expression of value type\n */\nexport function record<\n  K extends string,\n  V,\n  R extends Record<K, V>\n>(\n  keySchema: Bound<K>,\n  valueSchema: Bound<V>\n): Bound<R, Literal> {\n  return {\n    transform: (object: R, s: Stack = stack()) => {\n      return Object.fromEntries(\n        Object.entries(object).map(\n          ([key, value]) => [\n            keySchema.transform(key as K, s.with(`record:transform['key of ${key}']`)),\n            valueSchema.transform(value as V, s.with(`record:transform[value of '${key}']`))\n          ]\n        )\n      ) as PrimitiveRecord\n    },\n    restore: (json: Literal, s: Stack = stack()) => {\n      return Object.fromEntries(\n        Object.entries(json as PrimitiveRecord).map(\n          ([key, value]) => [\n            keySchema.restore(key, s.with(`record:restore['key of ${key}']`)),\n            valueSchema.restore(value, s.with(`record:restore[value of '${key}']`))\n          ]\n        )\n      ) as R\n    }\n  }\n}\n\n/**\n * Expresses an array of items all typed-alike.\n * For arrays containing multiple types, you'll want to use `union` within this.\n * @param itemSchema expression of array element\n */\nexport function array<T>(itemSchema: Bound<T>): Bound<Array<T>, Literal> {\n  return {\n    transform: (array: T[], s: Stack = stack()) => {\n      return array.map((e, i) => itemSchema.transform(e, s.with(`array:transform[${i}]`)))\n    },\n    restore: (array: Literal, s: Stack = stack()) => {\n      if (!Array.isArray(array)) {\n        throw new TransformationError('Not an array', s.with('array:restore'))\n      }\n\n      return array.map((e, i) => itemSchema.restore(e, s.with(`array:restore[${i}]`)))\n    }\n  }\n}\n\n/**\n * Expresses an object with a known structure.\n * If you're looking for an object with unknown keys, use `record`.\n * @param schemaObject Object prototype expressing the structure and expressed types therewithin\n */\nexport function object<\n  O extends { [key: string]: any }\n>(\n  schemaObject: { [K in keyof O]: Bound<O[K], Literal> }\n): Bound<O, Literal> {\n  return {\n    transform: (object: { [K in keyof O]: Unwrap<O[K]> }, s: Stack = stack()) => {\n      return Object.fromEntries(\n        Object.entries(schemaObject).map(\n          ([key, value]) => [key, value.transform((object as any)[key], s.with(`object:transform['${key}']`))]\n        )\n      )\n    },\n    restore: (json: Literal, s: Stack = stack()) => {\n      if (typeof json !== 'object' || Array.isArray(json) || json === null) {\n        const t = Array.isArray(json) ? 'array' : typeof json\n        throw new TransformationError(`Not an object. Expected 'object', got '${t}'`, s.with('object:transform'))\n      }\n\n      for (const key of Object.keys(schemaObject)) {\n        if (!(key in json) && (schemaObject as any)[key]?.attributes?.optional !== true) {\n          throw new TransformationError(`Missing required object key '${key}'`, s.with('object:transform'))\n        }\n      }\n\n      return Object.fromEntries(\n        Object.entries(schemaObject).map(\n          ([key, value]) => [key, value.restore((json as any)[key], s.with(`object:restore['${key}']`))]\n        )\n      ) as { [K in keyof O]: Unwrap<O[K]> }\n    }\n  }\n}\n\ntype UnionDiscriminator<T, R> = (v: T) => Bound<R, any> | false\n\n/**\n * Expresses a discriminated union.\n * @param discriminators validation functions that either return the selected type expression or false\n */\nexport function union<\n  TUnion,\n  TDiscriminators extends readonly UnionDiscriminator<TUnion, any>[] = readonly UnionDiscriminator<TUnion, any>[]\n>(\n  ...discriminators: TDiscriminators\n): Bound<TUnion, Literal> {\n  return {\n    transform: (object: TUnion, s: Stack = stack()) => {\n      for (let i = 0; i < discriminators.length; i++) {\n        const discriminator = discriminators[i]\n        const discriminated = discriminator(object as TUnion)\n        if (discriminated === false) {\n          continue\n        }\n\n        return discriminated.transform(object as any, s.with(`union:transform[${i}]`))\n      }\n\n      throw new TransformationError('No matching union discriminator', s.with('union:transform'))\n    },\n    restore: (json: Literal, s: Stack = stack()) => {\n      for (let i = 0; i < discriminators.length; i++) {\n        const discriminator = discriminators[i]\n        const discriminated = discriminator(json as TUnion)\n        if (discriminated === false) {\n          continue\n        }\n\n        return discriminated.restore(json, s.with(`union:restore[${i}]`))\n      }\n\n      throw new TransformationError('No matching union discriminator', s.with('union:restore'))\n    }\n  }\n}\n\n/**\n * Express a serialized string that matches a specific schema.\n * Unpacked into an object of matching type during transformation,\n * and re-packed into a serialized string during restoration.\n * @param schema expression of serialized type\n */\nexport function document<T, S = string>(\n  schema: Bound<T>,\n  { serializer, deserializer  }: SerializationConfig<Literal, S>\n    = (DefaultSerializationConfig as unknown as SerializationConfig<Literal, S>)\n): Bound<T, S> {\n  return {\n    transform: (object: T, s: Stack = stack()) => {\n      const literal = schema.transform(object, s.with('document:transform'))\n      const transformed = serializer(literal)\n      return transformed\n    },\n    restore: (str: S, s: Stack = stack()) => {\n      const literal = deserializer(str)\n      const restored = schema.restore(literal, s.with('document:restore'))\n      return restored\n    }\n  }\n}","import { Bound, DefaultStackType, Stack, ToStringable } from \"./types\"\n\nexport class TransformationError<T extends ToStringable> {\n  constructor(public message: string, customStack: Stack<T> = stack(), public offender?: any) {\n    this.location = customStack.stack.map(e => e.toString()).join(' -> ') + \"(!!)\"\n  }\n\n  location: string\n\n  toString(): string {\n    return \"hi\"\n  }\n}\n\nexport function stack<T extends ToStringable = DefaultStackType>(existing: T[] = []): Stack<T> {\n  return {\n    with: (message: T) => stack(existing.concat(message)),\n    stack: existing\n  }\n}\n\n/** convenience wrapper to push a stack message on simple alias types */\nexport function stackwrap<T, U>(upstream: Bound<T, U>, thisMessage: string): Bound<T, U> {\n  return {\n    transform: (object: T, s: Stack = stack()) => {\n      s = s.with(thisMessage)\n      return upstream.transform(object, s)\n    },\n    restore: (json: U, s: Stack = stack()) => {\n      s = s.with(thisMessage)\n      return upstream.restore(json, s)\n    }\n  }\n}\n","import { Literal, SerializationConfig } from \"./types\"\n\nexport const JsonPrettySerializationConfig: SerializationConfig<Literal, string> = {\n  serializer: (lit: Literal) => JSON.stringify(lit, null, 2),\n  deserializer: JSON.parse\n}\n\nexport const JsonSerializationConfig: SerializationConfig<Literal, string> = {\n  serializer: (lit: Literal) => JSON.stringify(lit),\n  deserializer: JSON.parse\n}\n\nexport let DefaultSerializationConfig: SerializationConfig = JsonPrettySerializationConfig\nexport function SetDefaultSerializationConfig(config: SerializationConfig) {\n  DefaultSerializationConfig = config\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACEO,IAAM,sBAAN,MAAkD;AAAA,EACvD,YAAmB,SAAiB,cAAwB,MAAM,GAAU,UAAgB;AAAzE;AAAyD;AAC1E,SAAK,WAAW,YAAY,MAAM,IAAI,OAAK,EAAE,SAAS,CAAC,EAAE,KAAK,MAAM,IAAI;AAAA,EAC1E;AAAA,EAIA,WAAmB;AACjB,WAAO;AAAA,EACT;AACF;AAEO,SAAS,MAAiD,WAAgB,CAAC,GAAa;AAC7F,SAAO;AAAA,IACL,MAAM,CAAC,YAAe,MAAM,SAAS,OAAO,OAAO,CAAC;AAAA,IACpD,OAAO;AAAA,EACT;AACF;AAGO,SAAS,UAAgB,UAAuB,aAAkC;AACvF,SAAO;AAAA,IACL,WAAW,CAACA,SAAW,IAAW,MAAM,MAAM;AAC5C,UAAI,EAAE,KAAK,WAAW;AACtB,aAAO,SAAS,UAAUA,SAAQ,CAAC;AAAA,IACrC;AAAA,IACA,SAAS,CAAC,MAAS,IAAW,MAAM,MAAM;AACxC,UAAI,EAAE,KAAK,WAAW;AACtB,aAAO,SAAS,QAAQ,MAAM,CAAC;AAAA,IACjC;AAAA,EACF;AACF;;;AC/BO,IAAM,gCAAsE;AAAA,EACjF,YAAY,CAAC,QAAiB,KAAK,UAAU,KAAK,MAAM,CAAC;AAAA,EACzD,cAAc,KAAK;AACrB;AAEO,IAAM,0BAAgE;AAAA,EAC3E,YAAY,CAAC,QAAiB,KAAK,UAAU,GAAG;AAAA,EAChD,cAAc,KAAK;AACrB;AAEO,IAAI,6BAAkD;AACtD,SAAS,8BAA8B,QAA6B;AACzE,+BAA6B;AAC/B;;;AFPO,SAAS,MAAuB;AACrC,SAAO;AAAA,IACL,WAAW,CAACC,YAAgBA;AAAA,IAC5B,SAAS,CAAC,SAAc;AAAA,EAC1B;AACF;AAGO,SAAS,UACd,WACA,SAA6B,MAAM,qBAChB;AACnB,SAAO;AAAA,IACL,WAAW,CAACA,SAAW,MAAa;AAClC,UAAI,CAAC,UAAUA,OAAM,GAAG;AACtB,cAAM,IAAI,oBAAoB,OAAOA,OAAM,GAAG,GAAGA,OAAM;AAAA,MACzD;AAEA,aAAOA;AAAA,IACT;AAAA,IACA,SAAS,CAAC,MAAe,MAAa;AACpC,UAAI,CAAC,UAAU,IAAI,GAAG;AACpB,cAAM,IAAI,oBAAoB,OAAO,MAAM,GAAG,GAAG,MAAM;AAAA,MACzD;AAEA,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAGO,SAAS,SAAe,QAAsD;AACnF,SAAO;AAAA,IACL,WAAW,CAACA,SAAqB,MAAa;AAC5C,aAAOA,YAAW,SAAY,SAAY,OAAO,UAAUA,SAAQ,CAAC;AAAA,IACtE;AAAA,IACA,SAAS,CAAC,MAAS,MAAa;AAC9B,aAAO,SAAS,SAAY,SAAY,OAAO,QAAQ,MAAM,CAAC;AAAA,IAChE;AAAA,IACA,YAAY;AAAA,MACV,UAAU;AAAA,IACZ;AAAA,EACF;AACF;AAGO,SAAS,SAAe,QAA4C;AACzE,SAAO;AAAA,IACL,WAAW,CAACA,SAAgB,MAAa;AACvC,aAAOA,YAAW,OAAO,OAAO,OAAO,UAAUA,SAAQ,CAAC;AAAA,IAC5D;AAAA,IACA,SAAS,CAAC,MAAS,MAAa;AAC9B,aAAO,SAAS,OAAO,OAAO,OAAO,QAAQ,MAAM,CAAC;AAAA,IACtD;AAAA,IACA,YAAY;AAAA,MACV,UAAU;AAAA,IACZ;AAAA,EACF;AACF;AAGO,SAAS,aAAmD,YAA2B,YAAgD;AAC5I,SAAO;AAAA,IACL,WAAW,CAACA,SAAe,MAAa;AACtC,aAAO;AAAA,QACL,GAAG,WAAW,UAAUA,SAAQ,CAAC;AAAA,QACjC,GAAG,WAAW,UAAUA,SAAQ,CAAC;AAAA,MACnC;AAAA,IACF;AAAA,IACA,SAAS,CAAC,MAAa,MAAa;AAClC,aAAO;AAAA,QACL,GAAG,WAAW,QAAQ,MAAM,CAAC;AAAA,QAC7B,GAAG,WAAW,QAAQ,MAAM,CAAC;AAAA,MAC/B;AAAA,IACF;AAAA,EACF;AACF;AAGO,SAAS,QAA2B,OAAuB;AAChE,SAAO,UAAU,UAAa,CAAC,MAAW,MAAM,KAAK,GAA6B,SAAS;AAC7F;AAGO,IAAM,SAAS,MAAM;AAAA,EAC1B,UAAkB,CAAC,MAAW,OAAO,MAAM,UAAU,OAAK,gCAAgC,OAAO,CAAC,GAAG;AAAA,EACrG;AACF;AAGO,IAAM,SAAS,MAAM;AAAA,EAC1B,UAAkB,CAAC,MAAW,OAAO,MAAM,UAAU,OAAK,gCAAgC,OAAO,CAAC,GAAG;AAAA,EACrG;AACF;AAGO,IAAM,UAAU,MAAM;AAAA,EAC3B,UAAmB,CAAC,MAAW,OAAO,MAAM,WAAW,OAAK,iCAAiC,OAAO,CAAC,GAAG;AAAA,EACxG;AACF;AAGO,IAAM,MAAM,MAAM;AAAA,EACvB,UAAgB,CAAC,MAAW,MAAM,MAAM,OAAK,8BAA8B,OAAO,CAAC,GAAG;AAAA,EACtF;AACF;AAOO,SAAS,OAKd,WACA,aACmB;AACnB,SAAO;AAAA,IACL,WAAW,CAACA,SAAW,IAAW,MAAM,MAAM;AAC5C,aAAO,OAAO;AAAA,QACZ,OAAO,QAAQA,OAAM,EAAE;AAAA,UACrB,CAAC,CAAC,KAAK,KAAK,MAAM;AAAA,YAChB,UAAU,UAAU,KAAU,EAAE,KAAK,4BAA4B,GAAG,IAAI,CAAC;AAAA,YACzE,YAAY,UAAU,OAAY,EAAE,KAAK,8BAA8B,GAAG,IAAI,CAAC;AAAA,UACjF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IACA,SAAS,CAAC,MAAe,IAAW,MAAM,MAAM;AAC9C,aAAO,OAAO;AAAA,QACZ,OAAO,QAAQ,IAAuB,EAAE;AAAA,UACtC,CAAC,CAAC,KAAK,KAAK,MAAM;AAAA,YAChB,UAAU,QAAQ,KAAK,EAAE,KAAK,0BAA0B,GAAG,IAAI,CAAC;AAAA,YAChE,YAAY,QAAQ,OAAO,EAAE,KAAK,4BAA4B,GAAG,IAAI,CAAC;AAAA,UACxE;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAOO,SAAS,MAAS,YAAgD;AACvE,SAAO;AAAA,IACL,WAAW,CAACC,QAAY,IAAW,MAAM,MAAM;AAC7C,aAAOA,OAAM,IAAI,CAAC,GAAG,MAAM,WAAW,UAAU,GAAG,EAAE,KAAK,mBAAmB,CAAC,GAAG,CAAC,CAAC;AAAA,IACrF;AAAA,IACA,SAAS,CAACA,QAAgB,IAAW,MAAM,MAAM;AAC/C,UAAI,CAAC,MAAM,QAAQA,MAAK,GAAG;AACzB,cAAM,IAAI,oBAAoB,gBAAgB,EAAE,KAAK,eAAe,CAAC;AAAA,MACvE;AAEA,aAAOA,OAAM,IAAI,CAAC,GAAG,MAAM,WAAW,QAAQ,GAAG,EAAE,KAAK,iBAAiB,CAAC,GAAG,CAAC,CAAC;AAAA,IACjF;AAAA,EACF;AACF;AAOO,SAAS,OAGd,cACmB;AACnB,SAAO;AAAA,IACL,WAAW,CAACD,SAA0C,IAAW,MAAM,MAAM;AAC3E,aAAO,OAAO;AAAA,QACZ,OAAO,QAAQ,YAAY,EAAE;AAAA,UAC3B,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,KAAK,MAAM,UAAWA,QAAe,GAAG,GAAG,EAAE,KAAK,qBAAqB,GAAG,IAAI,CAAC,CAAC;AAAA,QACrG;AAAA,MACF;AAAA,IACF;AAAA,IACA,SAAS,CAAC,MAAe,IAAW,MAAM,MAAM;AAC9C,UAAI,OAAO,SAAS,YAAY,MAAM,QAAQ,IAAI,KAAK,SAAS,MAAM;AACpE,cAAM,IAAI,MAAM,QAAQ,IAAI,IAAI,UAAU,OAAO;AACjD,cAAM,IAAI,oBAAoB,0CAA0C,CAAC,KAAK,EAAE,KAAK,kBAAkB,CAAC;AAAA,MAC1G;AAEA,iBAAW,OAAO,OAAO,KAAK,YAAY,GAAG;AAC3C,YAAI,EAAE,OAAO,SAAU,aAAqB,GAAG,GAAG,YAAY,aAAa,MAAM;AAC/E,gBAAM,IAAI,oBAAoB,gCAAgC,GAAG,KAAK,EAAE,KAAK,kBAAkB,CAAC;AAAA,QAClG;AAAA,MACF;AAEA,aAAO,OAAO;AAAA,QACZ,OAAO,QAAQ,YAAY,EAAE;AAAA,UAC3B,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,KAAK,MAAM,QAAS,KAAa,GAAG,GAAG,EAAE,KAAK,mBAAmB,GAAG,IAAI,CAAC,CAAC;AAAA,QAC/F;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAQO,SAAS,SAIX,gBACqB;AACxB,SAAO;AAAA,IACL,WAAW,CAACA,SAAgB,IAAW,MAAM,MAAM;AACjD,eAAS,IAAI,GAAG,IAAI,eAAe,QAAQ,KAAK;AAC9C,cAAM,gBAAgB,eAAe,CAAC;AACtC,cAAM,gBAAgB,cAAcA,OAAgB;AACpD,YAAI,kBAAkB,OAAO;AAC3B;AAAA,QACF;AAEA,eAAO,cAAc,UAAUA,SAAe,EAAE,KAAK,mBAAmB,CAAC,GAAG,CAAC;AAAA,MAC/E;AAEA,YAAM,IAAI,oBAAoB,mCAAmC,EAAE,KAAK,iBAAiB,CAAC;AAAA,IAC5F;AAAA,IACA,SAAS,CAAC,MAAe,IAAW,MAAM,MAAM;AAC9C,eAAS,IAAI,GAAG,IAAI,eAAe,QAAQ,KAAK;AAC9C,cAAM,gBAAgB,eAAe,CAAC;AACtC,cAAM,gBAAgB,cAAc,IAAc;AAClD,YAAI,kBAAkB,OAAO;AAC3B;AAAA,QACF;AAEA,eAAO,cAAc,QAAQ,MAAM,EAAE,KAAK,iBAAiB,CAAC,GAAG,CAAC;AAAA,MAClE;AAEA,YAAM,IAAI,oBAAoB,mCAAmC,EAAE,KAAK,eAAe,CAAC;AAAA,IAC1F;AAAA,EACF;AACF;AAQO,SAAS,SACd,QACA,EAAE,YAAY,aAAc,IACvB,4BACQ;AACb,SAAO;AAAA,IACL,WAAW,CAACA,SAAW,IAAW,MAAM,MAAM;AAC5C,YAAME,WAAU,OAAO,UAAUF,SAAQ,EAAE,KAAK,oBAAoB,CAAC;AACrE,YAAM,cAAc,WAAWE,QAAO;AACtC,aAAO;AAAA,IACT;AAAA,IACA,SAAS,CAAC,KAAQ,IAAW,MAAM,MAAM;AACvC,YAAMA,WAAU,aAAa,GAAG;AAChC,YAAM,WAAW,OAAO,QAAQA,UAAS,EAAE,KAAK,kBAAkB,CAAC;AACnE,aAAO;AAAA,IACT;AAAA,EACF;AACF;","names":["object","object","array","literal"]}