ipld-garbage
Version:
Garbage data generator for the IPLD Data Model
188 lines • 3.72 kB
JavaScript
import { CID } from 'multiformats/cid';
import { create as createDigest } from 'multiformats/hashes/digest';
const kinds = [
'list',
'map',
'string',
'bytes',
'boolean',
'integer',
'float',
'null',
'CID'
];
const codecs = [
85,
112,
113,
297
];
const hashes = [
[
18,
256
],
[
22,
256
],
[
27,
256
],
[
45600,
256
],
[
19,
512
],
[
21,
384
],
[
20,
512
]
];
const charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789`~!@#$%^&*()-_=+[]{}|\\:;\'",.<>?/ \t\n\u263A';
const baseOptions = {
initialWeights: {
map: 10,
list: 10
}
};
export function garbage(count = 200, options) {
options = Object.assign({}, baseOptions, options);
return generate(count, options)[1];
}
function generate(count, options) {
let totWeight = 0;
const weights = Object.assign({}, options.initialWeights, options.weights || {});
if (options.initialWeights) {
options = Object.assign(options, { initialWeights: null });
}
const types = kinds.map(t => {
const weight = weights && typeof weights[t] === 'number' ? weights[t] : 1;
if (weight < 0) {
throw new TypeError('Cannot have a negative weight');
}
totWeight += weight;
return [
t,
weight
];
});
if (totWeight === 0) {
throw new Error('Cannot have a total weight of zero');
}
const rnd = Math.random() * totWeight;
let wacc = 0;
for (const [type, weight] of types) {
wacc += weight;
if (wacc >= rnd) {
return generators[type](count, options);
}
}
throw new Error('Internal error');
}
function rndSize(bias = 5) {
return Math.abs(Math.floor(5 / (1 - Math.random() ** 2) - 5 + Math.random() * bias));
}
function rndChar() {
return charset.charAt(Math.floor(Math.random() * charset.length));
}
function rndByte() {
return Math.floor(Math.random() * 256);
}
const generators = {
list(count, options) {
const res = [];
const len = rndSize();
let size = 0;
for (let i = 0; i < len && size < count; i++) {
const x = generate(count - size, options);
res.push(x[1]);
size += x[0];
}
return [
size,
res
];
},
map(count, options) {
const res = {};
const len = rndSize();
let size = 0;
for (let i = 0; i < len && size < count; i++) {
const key = generators.string(5)[1];
const x = generate(count - size, options);
res[key] = x[1];
size += x[0] + key.length;
}
return [
size,
res
];
},
string(bias = 50) {
const len = rndSize(bias);
const res = [];
for (let i = 0; i < len; i++) {
res.push(rndChar());
}
return [
len,
res.join('')
];
},
bytes(bias = 50) {
const len = rndSize(bias);
const res = new Uint8Array(len);
for (let i = 0; i < len; i++) {
res[i] = rndByte();
}
return [
len,
res
];
},
boolean() {
return [
1,
Math.random() > 0.5
];
},
integer() {
return [
1,
Math.floor(Number.MAX_SAFE_INTEGER * Math.random()) * (Math.random() < 0.5 ? -1 : 1)
];
},
float() {
return [
1,
Math.tan((Math.random() - 0.5) * Math.PI)
];
},
null() {
return [
1,
null
];
},
CID() {
const hasher = hashes[Math.floor(Math.random() * hashes.length)];
const codec = codecs[Math.floor(Math.random() * codecs.length)];
const bytes = new Uint8Array(hasher[1] / 8);
for (let i = 0; i < bytes.length; i++) {
bytes[i] = rndByte();
}
return [
bytes.length,
CID.create(1, codec, createDigest(hasher[0], bytes))
];
}
};