import seedrandom from 'seedrandom'; import type { PickAlgorithm } from './types'; type Opts = { /** Randomization seed. */ seed: string, /** * Start/end index of the slot by which one item will be randomly picked per page. * * Eg. `[2, 6]` will cause one item to be picked among the third through seventh indexes. * * `end` must be larger than `start`. */ range: [start: number, end: number], /** Number of items in the page. */ pageSize: number, }; /** * Algorithm to display items per-page. * One item is randomly inserted into each page within the index range. */ const abovefoldAlgorithm: PickAlgorithm = (items, iteration, rawOpts) => { const opts = normalizeOpts(rawOpts); /** Current page of the index. */ const page = Math.floor(iteration / opts.pageSize); /** Current index within the page. */ const pageIndex = (iteration % opts.pageSize); /** RNG for the page. */ const rng = seedrandom(`${opts.seed}-page-${page}`); /** Index to insert the item. */ const insertIndex = Math.floor(rng() * (opts.range[1] - opts.range[0])) + opts.range[0]; if (pageIndex === insertIndex) { return items[page % items.length]; } }; const normalizeOpts = (opts: unknown): Opts => { const { seed, range, pageSize } = (opts && typeof opts === 'object' ? opts : {}) as Record; return { seed: typeof seed === 'string' ? seed : '', range: Array.isArray(range) ? [Number(range[0]), Number(range[1])] : [2, 6], pageSize: typeof pageSize === 'number' ? pageSize : 20, }; }; export { abovefoldAlgorithm, };