UNPKG

@rickosborne/rebound

Version:

Rick Osborne's utilities for working with bounded numbers

138 lines (137 loc) 5.21 kB
var __defProp = Object.defineProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); import { computeIfAbsent, lowerFirst } from "@rickosborne/foundation"; import { scrubStackTrace } from "@rickosborne/guard"; import { assertForBounds } from "./assert-bounded.mjs"; import { fromNumberForBounds } from "./from-number-bounded.mjs"; import { guardForBounds } from "./guard-bounded.mjs"; import { CEIL, FLOOR, integerFrom, ROUND, TRUNC } from "./integer-from.mjs"; import { integerGenerator } from "./integer-generator.mjs"; import { randomBounded } from "./random-bounded.mjs"; import { ReboundBuilder } from "./rebound-builder.mjs"; import { BOUNDS } from "./spec.mjs"; import { ifIfPresent } from "./util.mjs"; const _Rebound = class _Rebound { static buildType(typeName) { return new ReboundBuilder( {}, (_config, range) => new _Rebound(typeName, range) ); } fnCache = /* @__PURE__ */ new Map(); isInt; isLowerInc; isUpperInc; label; lower; numberType = NaN; outOfBoundsErrorProvider; range; typeName; upper; constructor(typeName, range) { this.range = range; this.typeName = typeName; this.isInt = range.isInt; this.isUpperInc = range.isUpperInc; this.isLowerInc = range.isLowerInc; this.lower = range.lower; this.upper = range.upper; this.label = range.label; this.outOfBoundsErrorProvider = (v, n) => this.outOfRangeError(v, n); } get assert() { return this.assertWith(); } assertWith(options) { const config = this.withOptions(options, "assert"); const guard = ifIfPresent(config.ifPresent, this.guardWith({ ifPresent: true }), this.guard); return this.cacheFn(config, () => assertForBounds(guard, config.errorProvider, config.ifPresent)); } cacheFn(options, compute) { const key = options.defaultName.concat(":", options.fnName, ":", options.errorProvider.name); return computeIfAbsent(key, this.fnCache, compute); } get ceil() { return this.toIntWith({ strategy: CEIL }); } get floor() { return this.toIntWith({ strategy: FLOOR }); } get fromNumber() { return this.fromNumberWith({ ifPresent: false }); } fromNumberWith(options) { const config = this.withOptions(options, "", "FromNumber"); return this.cacheFn(config, () => fromNumberForBounds(this.guard, config.errorProvider, config.ifPresent, config.fnName)); } get guard() { return this.guardWith({ ifPresent: false }); } guardWith(options) { const config = this.withOptions(options, "is"); return this.cacheFn( config, () => guardForBounds(this.range, this.typeName, config.fnName, config.ifPresent) ); } get integers() { return this.integersWith(); } integersWith(options = {}) { return integerGenerator(this.range, options); } outOfRangeError(value, name) { const type = value === null ? "null" : value === void 0 ? "undefined" : typeof value; return scrubStackTrace(new RangeError(`Expected ${name == null ? "" : name.concat(":")} ${this.typeName} ${this.range.toString()}, actual: ${type === "number" ? value : type}`), /at ((?:Rebound[.])?outOfRangeError|buildError)/); } get random() { return this.randomWith(); } randomWith(options = {}) { const defaultName = `random${this.typeName}`; const { fnName = defaultName, rng } = options; return this.cacheFn({ defaultName, errorProvider: this.outOfBoundsErrorProvider, fnName: (options == null ? void 0 : options.fnName) ?? defaultName, ifPresent: false }, () => randomBounded(this.typeName, this.range.label, this.range.isLowerInc, this.range.lower, this.range.isInt, this.range.upper, this.range.isUpperInc, rng, fnName)); } get round() { return this.toIntWith({ strategy: ROUND }); } toIntWith(options) { const config = this.withIntStrategy(options); const { errorProvider, fnName, ifPresent, strategy } = config; return this.cacheFn(config, () => integerFrom(this.typeName, this.range, errorProvider, ifPresent, strategy, fnName)); } get trunc() { return this.toIntWith({ strategy: TRUNC }); } withIntStrategy(options) { const prefix = typeof (options == null ? void 0 : options.strategy) === "function" ? "toInt" : (options == null ? void 0 : options.strategy) ?? ROUND; const config = this.withOptions(options, prefix); const strategy = (options == null ? void 0 : options.strategy) ?? ROUND; return { ...config, strategy }; } withOptions(options, prefix, suffix = "") { const ifPresent = (options == null ? void 0 : options.ifPresent) ?? false; const errorProvider = (options == null ? void 0 : options.errorProvider) ?? this.outOfBoundsErrorProvider; const defaultName = `${prefix}${prefix === "" ? lowerFirst(this.typeName) : this.typeName}${suffix}${ifPresent ? "IfPresent" : ""}`; const fnName = (options == null ? void 0 : options.fnName) ?? defaultName; return { defaultName, errorProvider, fnName, ifPresent }; } get [BOUNDS]() { return this; } }; __name(_Rebound, "Rebound"); let Rebound = _Rebound; export { Rebound }; //# sourceMappingURL=rebound.mjs.map