Functional Weave
Code in Rust

money.allocate@1.0.1

impl/typescript.ts

1,414 bytes · the TypeScript implementation · view raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

import { type Money, money } from "./money_amount.ts";  ← from money.amount ^1.0.0 · built alongside by fune

/**
 * Split `amount` across `ratios` so the parts add back up to the whole.
 *
 * Splitting 10.00 three ways gives 3.34, 3.33, 3.33 - never 3.33 three times
 * with a penny quietly lost. The leftover goes to the largest remainders,
 * ties broken by position, so the split is stable and reproducible.
 */
export function allocate(amount: Money, ratios: readonly number[]): readonly Money[] {
  if (ratios.length === 0) {
    throw new RangeError("allocate needs at least one ratio");
  }
  if (!ratios.every((r) => Number.isInteger(r))) {
    throw new TypeError("ratios must be integers");
  }
  const total = ratios.reduce((sum, r) => sum + r, 0);
  if (total === 0) {
    throw new RangeError("ratios must not sum to zero");
  }

  const shares = ratios.map((ratio) => {
    const numerator = amount.minor * ratio;
    const base = Math.floor(numerator / total);
    return { base, remainder: numerator - base * total };
  });

  let leftover = amount.minor - shares.reduce((sum, s) => sum + s.base, 0);

  const order = shares
    .map((share, index) => ({ index, remainder: share.remainder }))
    .sort((a, b) => b.remainder - a.remainder || a.index - b.index);

  for (const { index } of order) {
    if (leftover <= 0) break;
    shares[index].base += 1;
    leftover -= 1;
  }

  return shares.map((share) => money(share.base, amount.currency));
}