@grandom/pick
Version:
A configurable, flexible, seedable, and overall great random picker.
136 lines (132 loc) • 5.44 kB
JavaScript
;
var core = require('@grandom/core');
// TODO: remove istanbul ignore and write tests for it
// TODO: implement unique
// TODO: include / exclude / filter function
// TODO: implement edge cases (including infinite loops)
const DEFAULT_FALLBACK = undefined;
class RandomPick extends core.RandomGenerator {
// -----------------------------------------------------------------------------------------------
pick(arg1, arg2, arg3) {
if (typeof arg1 !== 'undefined') {
let count;
let options = {};
// process count and options
if (typeof arg2 !== 'undefined') {
if (typeof arg2 === 'number') {
count = arg2;
}
else if (typeof arg2 === 'object' && arg2 !== null) {
options = arg2;
}
else {
throw new TypeError('2nd argument must be a number (count), or an object (options), ' +
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
`got: ${arg2} (typeof === '${typeof arg2}').`);
}
if (typeof arg3 !== 'undefined') {
/* istanbul ignore next */
if (typeof arg3 === 'object' && arg3 !== null) {
options = arg3;
}
else {
throw new TypeError('3rd argument must be an object (options), ' +
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
`got: ${arg3} (typeof === '${typeof arg3}').`);
}
}
}
// process strings
if (typeof arg1 === 'string') {
return this._pickString(arg1, count, options);
// process arrays
}
else if (Array.isArray(arg1)) {
return this._pickArray(arg1, count, options);
// process objects
}
else if (typeof arg1 === 'object' && arg1 !== null) {
return this._pickObject(arg1, count, options);
}
}
// type guard ----------------------------------------------------------------------------------
throw new TypeError(
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
`Must be called with a string, array, or object, got: ${arg1} (typeof === '${typeof arg1}').`);
}
_pickString(string, count, options) {
if (typeof count !== 'undefined') {
// NaN check and bound checks
// eslint-disable-next-line no-self-compare
if (count !== count || count < 1 || count > Number.MAX_SAFE_INTEGER) {
throw new RangeError(`Count must be 1 >= count <= Number.MAX_SAFE_INTEGER, got: ${count}.`);
}
}
// return the fallback if the string is empty ('')
if (string.length === 0) {
return 'fallback' in options
? options.fallback
: DEFAULT_FALLBACK;
}
if (count > 1) {
let str = '';
for (let i = 0; i < count; i++) {
str += this._engine.pickArray(string);
}
return str;
}
return this._engine.pickArray(string);
}
_pickArray(array, count, options) {
if (typeof count !== 'undefined') {
// NaN check and bound checks
// eslint-disable-next-line no-self-compare
if (count !== count || count < 1 || count > Number.MAX_SAFE_INTEGER) {
throw new RangeError(`Count must be 1 >= count <= Number.MAX_SAFE_INTEGER, got: ${count}.`);
}
}
// return the fallback if the array is empty ([])
if (array.length === 0) {
return 'fallback' in options
? options.fallback
: DEFAULT_FALLBACK;
}
if (count > 1) {
const result = [];
for (let i = 0; i < count; i++) {
result.push(this._engine.pickArray(array));
}
return result;
}
return this._engine.pickArray(array);
}
_pickObject(object, count, options) {
if (typeof count !== 'undefined') {
// NaN check and bound checks
// eslint-disable-next-line no-self-compare
if (count !== count || count < 1 || count > Number.MAX_SAFE_INTEGER) {
throw new RangeError(`Count must be 1 >= count <= Number.MAX_SAFE_INTEGER, got: ${count}.`);
}
}
const keys = Object.keys(object);
// return the fallback if the keys array is empty (object === {})
if (keys.length === 0) {
return 'fallback' in options
? options.fallback
: DEFAULT_FALLBACK;
}
if (count > 1) {
const result = [];
let key;
for (let i = 0; i < count; i++) {
key = this._engine.pickArray(keys);
result.push([key, object[key]]);
}
return result;
}
const key = this._engine.pickArray(keys);
return [key, object[key]];
}
}
module.exports = RandomPick;
//# sourceMappingURL=index.js.map