{"version":3,"file":"bounded-length-array.mjs","sources":["../../src/array/bounded-length-array.mts"],"sourcesContent":["import { Arr, asUint32, memoizeFunction, Result } from 'ts-data-forge';\nimport {\n  type BoundedLengthArray,\n  type MaxLengthArray,\n  type MinLengthArray,\n  type SupportedLength,\n} from 'ts-type-forge';\nimport { type Type } from '../type.mjs';\nimport {\n  createPrimitiveValidationError,\n  type ValidationError,\n} from '../utils/index.mjs';\nimport { buildType, validateElements } from './build-type.mjs';\n\nexport type { BoundedLengthArray } from 'ts-type-forge';\n\n/**\n * Creates a `Type` for a readonly array whose length is within the inclusive\n * range `[min, max]`, typed as the branded {@link BoundedLengthArray} instead\n * of the union of tuple types produced by `boundedLengthTuple`.\n *\n * Because the length constraint lives only in the brand, no union of tuples\n * of the element type is ever constructed, which keeps type-checking cheap\n * even when `A` is a large type.\n */\nexport function boundedLengthArray<\n  A,\n  Min extends SupportedLength,\n  Max extends SupportedLength,\n>(\n  min: Min,\n  max: Max,\n  elementType: Type<A>,\n  options?: Partial<\n    Readonly<{\n      typeName: string;\n      defaultValue: BoundedLengthArray<Min, Max, A>;\n    }>\n  >,\n): Type<BoundedLengthArray<Min, Max, A>>;\n\n// Only the lower bound is in `SupportedLength`, so the upper bound is dropped from\n// the result type and only the \"at least `min`\" guarantee is kept.\nexport function boundedLengthArray<A, Min extends SupportedLength>(\n  min: Min,\n  max: number,\n  elementType: Type<A>,\n  options?: Partial<\n    Readonly<{\n      typeName: string;\n      defaultValue: MinLengthArray<Min, A>;\n    }>\n  >,\n): Type<MinLengthArray<Min, A>>;\n\n// Only the upper bound is in `SupportedLength`, so the lower bound is dropped from\n// the result type and only the \"at most `max`\" guarantee is kept.\nexport function boundedLengthArray<A, Max extends SupportedLength>(\n  min: number,\n  max: Max,\n  elementType: Type<A>,\n  options?: Partial<\n    Readonly<{\n      typeName: string;\n      defaultValue: MaxLengthArray<Max, A>;\n    }>\n  >,\n): Type<MaxLengthArray<Max, A>>;\n\n// Neither bound is in `SupportedLength`, so the result length is left unconstrained.\nexport function boundedLengthArray<A>(\n  min: number,\n  max: number,\n  elementType: Type<A>,\n  options?: Partial<\n    Readonly<{\n      typeName: string;\n      defaultValue: readonly A[];\n    }>\n  >,\n): Type<readonly A[]>;\n\nexport function boundedLengthArray<A>(\n  min: number,\n  max: number,\n  elementType: Type<A>,\n  options?: Partial<\n    Readonly<{\n      typeName: string;\n      defaultValue: readonly A[];\n    }>\n  >,\n): Type<readonly A[]> {\n  type T = readonly A[];\n\n  const typeName =\n    options?.typeName ??\n    `BoundedLengthArray<${min}, ${max}, ${elementType.typeName}>`;\n\n  const getDefaultValue = memoizeFunction(\n    (): T =>\n      options?.defaultValue ??\n      // An array of the minimum length is the shortest value within the range.\n      Arr.create(asUint32(min), elementType.defaultValue),\n  );\n\n  const validate: Type<T>['validate'] = (a) => {\n    if (!Arr.isArray(a)) {\n      return Result.err([\n        createPrimitiveValidationError({\n          actualValue: a,\n          expectedType: 'array',\n          typeName,\n          details: undefined,\n        }),\n      ]);\n    }\n\n    if (a.length < min || max < a.length) {\n      return Result.err([\n        {\n          path: [],\n          actualValue: a,\n          expectedType: typeName,\n          typeName,\n          details: {\n            kind: 'array-range-length',\n            minLength: min,\n            maxLength: max,\n            actualLength: a.length,\n          },\n        } satisfies ValidationError,\n      ]);\n    }\n\n    return validateElements(a, elementType);\n  };\n\n  const fill: Type<T>['fill'] = (a) => {\n    if (!Arr.isArray(a)) {\n      return getDefaultValue();\n    }\n\n    // Trim down to at most `max`, then pad up to at least `min`.\n    const capped = Arr.take(a, asUint32(max));\n\n    return capped.length >= min\n      ? Arr.map(capped, (el) => elementType.fill(el) satisfies A)\n      : Arr.map(\n          Arr.seq(asUint32(min)),\n          (i) => elementType.fill(capped[i]) satisfies A,\n        );\n  };\n\n  return buildType({ typeName, getDefaultValue, validate, fill, elementType });\n}\n"],"names":[],"mappings":";;;;AAkFO,SAAS,kBAAA,CACd,GAAA,EACA,GAAA,EACA,WAAA,EACA,OAAA,EAMoB;AAGpB,EAAA,MAAM,QAAA,GACJ,SAAS,QAAA,IACT,CAAA,mBAAA,EAAsB,GAAG,CAAA,EAAA,EAAK,GAAG,CAAA,EAAA,EAAK,WAAA,CAAY,QAAQ,CAAA,CAAA,CAAA;AAE5D,EAAA,MAAM,eAAA,GAAkB,eAAA;AAAA,IACtB,MACE,OAAA,EAAS,YAAA;AAAA,IAET,IAAI,MAAA,CAAO,QAAA,CAAS,GAAG,CAAA,EAAG,YAAY,YAAY;AAAA,GACtD;AAEA,EAAA,MAAM,QAAA,GAAgC,CAAC,CAAA,KAAM;AAC3C,IAAA,IAAI,CAAC,GAAA,CAAI,OAAA,CAAQ,CAAC,CAAA,EAAG;AACnB,MAAA,OAAO,OAAO,GAAA,CAAI;AAAA,QAChB,8BAAA,CAA+B;AAAA,UAC7B,WAAA,EAAa,CAAA;AAAA,UACb,YAAA,EAAc,OAAA;AAAA,UACd,QAAA;AAAA,UACA,OAAA,EAAS;AAAA,SACV;AAAA,OACF,CAAA;AAAA,IACH;AAEA,IAAA,IAAI,CAAA,CAAE,MAAA,GAAS,GAAA,IAAO,GAAA,GAAM,EAAE,MAAA,EAAQ;AACpC,MAAA,OAAO,OAAO,GAAA,CAAI;AAAA,QAChB;AAAA,UACE,MAAM,EAAC;AAAA,UACP,WAAA,EAAa,CAAA;AAAA,UACb,YAAA,EAAc,QAAA;AAAA,UACd,QAAA;AAAA,UACA,OAAA,EAAS;AAAA,YACP,IAAA,EAAM,oBAAA;AAAA,YACN,SAAA,EAAW,GAAA;AAAA,YACX,SAAA,EAAW,GAAA;AAAA,YACX,cAAc,CAAA,CAAE;AAAA;AAClB;AACF,OACD,CAAA;AAAA,IACH;AAEA,IAAA,OAAO,gBAAA,CAAiB,GAAG,WAAW,CAAA;AAAA,EACxC,CAAA;AAEA,EAAA,MAAM,IAAA,GAAwB,CAAC,CAAA,KAAM;AACnC,IAAA,IAAI,CAAC,GAAA,CAAI,OAAA,CAAQ,CAAC,CAAA,EAAG;AACnB,MAAA,OAAO,eAAA,EAAgB;AAAA,IACzB;AAGA,IAAA,MAAM,SAAS,GAAA,CAAI,IAAA,CAAK,CAAA,EAAG,QAAA,CAAS,GAAG,CAAC,CAAA;AAExC,IAAA,OAAO,MAAA,CAAO,MAAA,IAAU,GAAA,GACpB,GAAA,CAAI,GAAA,CAAI,MAAA,EAAQ,CAAC,EAAA,KAAO,WAAA,CAAY,IAAA,CAAK,EAAE,CAAa,IACxD,GAAA,CAAI,GAAA;AAAA,MACF,GAAA,CAAI,GAAA,CAAI,QAAA,CAAS,GAAG,CAAC,CAAA;AAAA,MACrB,CAAC,CAAA,KAAM,WAAA,CAAY,IAAA,CAAK,MAAA,CAAO,CAAC,CAAC;AAAA,KACnC;AAAA,EACN,CAAA;AAEA,EAAA,OAAO,UAAU,EAAE,QAAA,EAAU,iBAAiB,QAAA,EAAU,IAAA,EAAM,aAAa,CAAA;AAC7E;;;;"}