Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | 2x 2x 2x 2x 2x 2x 127x 127x 127x 127x 127x 127x 127x 3213x 3213x 3213x 3213x 3213x 247x 942x 10x 514x 3x 1360x 10x 29x 19x 10x 11x 21x 37x 267x 80x 80x 80x 247x 247x 247x 247x 1338x 247x 247x 942x 942x 942x 1710x 1710x 76x 63x 1675x 1675x 1675x 942x 10x 10x 10x 10x 10x 23x 23x 23x 10x 514x 3x 3x 1360x 1360x 10x 10x 32x 32x 32x 32x 19x 19x 10x 10x 10x 10x 120x 10x 21x 37x 37x 37x | import {int, int64} from '../number';
import {randomString} from '../string';
import {clone} from '../util';
import * as templates from './templates';
import type {
ArrayTemplate,
BinTemplate,
BooleanTemplate,
FloatTemplate,
IntegerTemplate,
Int64Template,
LiteralTemplate,
MapTemplate,
NumberTemplate,
ObjectTemplate,
OrTemplate,
StringTemplate,
Template,
TemplateNode,
} from './types';
export interface TemplateJsonOpts {
/**
* Sets the limit of maximum number of JSON nodes to generate. This is a soft
* limit: once this limit is reached, no further optional values are generate
* (optional object and map keys are not generated, arrays are generated with
* their minimum required size).
*/
maxNodes?: number;
}
export class TemplateJson {
public static readonly gen = (template?: Template, opts?: TemplateJsonOpts): unknown => {
const generator = new TemplateJson(template, opts);
return generator.gen();
};
protected nodes: number = 0;
protected maxNodes: number;
constructor(
public readonly template: Template = templates.nil,
public readonly opts: TemplateJsonOpts = {},
) {
this.maxNodes = opts.maxNodes ?? 100;
}
public gen(): unknown {
return this.generate(this.template);
}
protected generate(tpl: Template): unknown {
this.nodes++;
while (typeof tpl === 'function') tpl = tpl();
const template: TemplateNode = typeof tpl === 'string' ? [tpl] : tpl;
const type = template[0];
switch (type) {
case 'arr':
return this.generateArray(template as ArrayTemplate);
case 'obj':
return this.generateObject(template as ObjectTemplate);
case 'map':
return this.generateMap(template as MapTemplate);
case 'str':
return this.generateString(template as StringTemplate);
case 'num':
return this.generateNumber(template as NumberTemplate);
case 'int':
return this.generateInteger(template as IntegerTemplate);
case 'int64':
return this.generateInt64(template as Int64Template);
case 'float':
return this.generateFloat(template as FloatTemplate);
case 'bool':
return this.generateBoolean(template as BooleanTemplate);
case 'bin':
return this.generateBin(template as BinTemplate);
case 'nil':
return null;
case 'lit':
return this.generateLiteral(template as any);
case 'or':
return this.generateOr(template as any);
default:
throw new Error(`Unknown template type: ${type}`);
}
}
protected minmax(min: number, max: number): number {
if (this.nodes > this.maxNodes) return min;
if (this.nodes + max > this.maxNodes) max = this.maxNodes - this.nodes;
if (max < min) max = min;
return int(min, max);
}
protected generateArray(template: ArrayTemplate): unknown[] {
const [, min = 0, max = 5, itemTemplate = 'nil', head = [], tail = []] = template;
const length = this.minmax(min, max);
const result: unknown[] = [];
for (const tpl of head) result.push(this.generate(tpl));
for (let i = 0; i < length; i++) result.push(this.generate(itemTemplate));
for (const tpl of tail) result.push(this.generate(tpl));
return result;
}
protected generateObject(template: ObjectTemplate): Record<string, unknown> {
const [, fields = []] = template;
const result: Record<string, unknown> = {};
for (const field of fields) {
const [keyToken, valueTemplate = 'nil', optionality = 0] = field;
if (optionality) {
if (this.nodes > this.maxNodes) continue;
if (Math.random() < optionality) continue;
}
const key = randomString(keyToken ?? templates.tokensObjectKey);
const value = this.generate(valueTemplate);
result[key] = value;
}
return result;
}
protected generateMap(template: MapTemplate): Record<string, unknown> {
const [, keyToken, valueTemplate = 'nil', min = 0, max = 5] = template;
const length = this.minmax(min, max);
const result: Record<string, unknown> = {};
const token = keyToken ?? templates.tokensObjectKey;
for (let i = 0; i < length; i++) {
const key = randomString(token);
const value = this.generate(valueTemplate);
result[key] = value;
}
return result;
}
protected generateString(template: StringTemplate): string {
return randomString(template[1] ?? templates.tokensHelloWorld);
}
protected generateNumber([, min, max]: NumberTemplate): number {
Iif (Math.random() > 0.5) return this.generateInteger(['int', min, max]);
else return this.generateFloat(['float', min, max]);
}
protected generateInteger(template: IntegerTemplate): number {
const [, min = Number.MIN_SAFE_INTEGER, max = Number.MAX_SAFE_INTEGER] = template;
return int(min, max);
}
protected generateInt64(template: Int64Template): bigint {
const [, min = BigInt('-9223372036854775808'), max = BigInt('9223372036854775807')] = template;
return int64(min, max);
}
protected generateFloat(template: FloatTemplate): number {
const [, min = -Number.MAX_VALUE, max = Number.MAX_VALUE] = template;
let float = Math.random() * (max - min) + min;
float = Math.max(min, Math.min(max, float));
return float;
}
protected generateBoolean(template: BooleanTemplate): boolean {
const value = template[1];
return value !== undefined ? value : Math.random() < 0.5;
}
protected generateBin(template: BinTemplate): Uint8Array {
const [, min = 0, max = 5, omin = 0, omax = 255] = template;
const length = this.minmax(min, max);
const result = new Uint8Array(length);
for (let i = 0; i < length; i++) {
result[i] = int(omin, omax);
}
return result;
}
protected generateLiteral(template: LiteralTemplate): unknown {
return clone(template[1]);
}
protected generateOr(template: OrTemplate): unknown {
const [, ...options] = template;
const index = int(0, options.length - 1);
return this.generate(options[index]);
}
}
|