@gent-js/gent
Version:
template-based data generator.
67 lines (66 loc) • 1.98 kB
JavaScript
import { faker } from "@faker-js/faker";
const DEFAULT_WEIGHT = 1;
const MIN_WEIGHT = 0;
const MAX_WEIGHT = 2 ** 16;
export class WeightedItemFeeder {
totalWeight = -1;
normalizedWeightedItems;
constructor(...weightedItems) {
this.normalizedWeightedItems = weightedItems.map(normalizeWeightedItem);
this.updateTotalWeight();
}
get size() {
return this.normalizedWeightedItems.length;
}
addItem(item, weight = DEFAULT_WEIGHT) {
const weightedItem = {
content: item,
weight: weight,
};
this.addWeightedItem(weightedItem);
}
addWeightedItem(weightedItem) {
this.normalizedWeightedItems.push(normalizeWeightedItem(weightedItem));
this.updateTotalWeight();
}
getItem() {
const totalWeight = this.totalWeight;
if (totalWeight < MIN_WEIGHT) {
return undefined;
}
const targetAccumWeight = faker.number.float({
min: MIN_WEIGHT,
max: totalWeight,
});
let accumWeight = MIN_WEIGHT;
const weightedItem = this.normalizedWeightedItems.find(({ weight }) => {
accumWeight = accumWeight + weight;
if (targetAccumWeight <= accumWeight) {
return true;
}
return false;
});
return weightedItem?.content;
}
updateTotalWeight() {
this.totalWeight = this.normalizedWeightedItems.reduce((sum, { weight }) => {
return sum + weight;
}, 0);
}
}
function normalizeWeightedItem(weightedItem) {
let weight;
if (typeof weightedItem.weight === "number") {
weight = weightedItem.weight;
}
else {
weight = DEFAULT_WEIGHT;
}
return {
content: weightedItem.content,
weight: normalizeWeight(weight),
};
}
export function normalizeWeight(value) {
return Math.min(Math.max(value, MIN_WEIGHT), MAX_WEIGHT);
}