{"version":3,"file":"data-builder.mjs","sources":["../../src/data-builder.ts"],"sourcesContent":["import { deepClone } from './deep-clone'\n\n/**\n * Data builder is an abstract class builders can inherit to make working with the {@linkplain dossierProxy} easier.\n *\n * ```typescript\n * export class ShapeBuilder extends DataBuilder<Shape> {\n *   constructor() {\n *     super({\n *       name: randomString(10, 20),\n *       sides: randomNumberBetween(1, 4),\n *       colour: randomElement(['Blue', 'Red', 'Yellow', 'Green']),\n *     })\n *   }\n *\n *   public withName(name: string) {\n *     return this.with('name', name + ' Intercepted')\n *   }\n * }\n *\n * export const shapeBuilder = dossierProxy<ShapeBuilder, Shape>(ShapeBuilder)\n * ```\n */\nexport abstract class DataBuilder<T> {\n  protected constructor(protected thing: T) {\n    this.thing = thing\n  }\n\n  public with<K extends keyof T>(key: K, value: T[K]): this {\n    this.thing[key] = value\n    return this\n  }\n\n  public build(): T {\n    return deepClone(this.thing)\n  }\n\n  public clone(): this {\n    return new Proxy(deepClone(this), proxyHandler)\n  }\n}\n\ntype WithMethods<T extends object, TBuilder> = CoerceIntellisense<\n  {\n    [K in keyof T as K extends string ? `with${Capitalize<K>}` : never]-?: (d: T[K]) => WithMethods<T, TBuilder> & TBuilder\n  } & TBuilder\n>\n\nexport type CoerceIntellisense<T> = T extends infer O ? { [K in keyof O]: O[K] } : never\n\nconst proxyHandler = {\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  get: function (target: any, prop: string, receiver: any) {\n    if (!target[prop] && prop.startsWith('with')) {\n      const propertyName = prop[4].toLocaleLowerCase() + prop.substring(5)\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n      return (value: any) => {\n        // eslint-disable-next-line @typescript-eslint/no-explicit-any\n        target.with(propertyName as any, value)\n        return receiver\n      }\n    }\n    return Reflect.get(target, prop, receiver)\n  },\n}\n\ntype DynamicDataBuilder<TDataBuilder, TData extends object> = TDataBuilder & WithMethods<TData, TDataBuilder>\n\n/**\n * The proxy builder allows one to easily create a builder and have a [proxy]{@link https://developer.mozilla.org/en-US/docs/web/javascript/reference/global_objects/proxy/proxy}\n * instance handle any with* methods not specifically declared by the builder itself.\n *\n * ```typescript\n * class ShapeBuilder extends DataBuilder<Shape> {\n *   constructor() {\n *     super({\n *       name: randomString(10, 20),\n *       sides: randomNumberBetween(1, 4),\n *       colour: randomElement(['Blue', 'Red', 'Yellow', 'Green']),\n *     })\n *   }\n *\n *   public withName(name: string) {\n *     return this.with('name', name + ' Intercepted')\n *   }\n * }\n *\n * const shapeBuilder = dossierProxy<ShapeBuilder, Shape>(ShapeBuilder)\n *\n * const shape = shapeBuilder().withName('Square').withSides(4).withColour('Red').build()\n *\n * console.log(shape) // Outputs { name: 'Square Intercepted', sides: 4, colour: 'Red' }\n * ```\n * @param builder The constructor to call to create a new instance of the builder.\n */\nexport function dossierProxy<TDataBuilder, TData extends object>(\n  builder: new () => TDataBuilder,\n): () => DynamicDataBuilder<TDataBuilder, TData> {\n  return () => new Proxy(new builder(), proxyHandler)\n}\n"],"names":[],"mappings":";;AAEA;;;;;;;;;;;;;;;;;;;;AAoBG;MACmB,WAAW,CAAA;AACC,IAAA,KAAA;AAAhC,IAAA,WAAA,CAAgC,KAAQ,EAAA;QAAR,IAAK,CAAA,KAAA,GAAL,KAAK;AACnC,QAAA,IAAI,CAAC,KAAK,GAAG,KAAK;;IAGb,IAAI,CAAoB,GAAM,EAAE,KAAW,EAAA;AAChD,QAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,KAAK;AACvB,QAAA,OAAO,IAAI;;IAGN,KAAK,GAAA;AACV,QAAA,OAAO,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC;;IAGvB,KAAK,GAAA;QACV,OAAO,IAAI,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,YAAY,CAAC;;AAElD;AAUD,MAAM,YAAY,GAAG;;AAEnB,IAAA,GAAG,EAAE,UAAU,MAAW,EAAE,IAAY,EAAE,QAAa,EAAA;AACrD,QAAA,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE;AAC5C,YAAA,MAAM,YAAY,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,iBAAiB,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;;YAEpE,OAAO,CAAC,KAAU,KAAI;;AAEpB,gBAAA,MAAM,CAAC,IAAI,CAAC,YAAmB,EAAE,KAAK,CAAC;AACvC,gBAAA,OAAO,QAAQ;AACjB,aAAC;;QAEH,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC;KAC3C;CACF;AAID;;;;;;;;;;;;;;;;;;;;;;;;;;AA0BG;AACG,SAAU,YAAY,CAC1B,OAA+B,EAAA;AAE/B,IAAA,OAAO,MAAM,IAAI,KAAK,CAAC,IAAI,OAAO,EAAE,EAAE,YAAY,CAAC;AACrD;;;;"}