Skip to content

Instantly share code, notes, and snippets.

@cyyynthia
Created May 6, 2023 21:59
Show Gist options
  • Save cyyynthia/e77c744cb6494dabe37d0182506526b9 to your computer and use it in GitHub Desktop.
Save cyyynthia/e77c744cb6494dabe37d0182506526b9 to your computer and use it in GitHub Desktop.
An utility to generate a large random TOML file. Used to benchmark https://github.com/squirrelchat/smol-toml
/*!
* BSD Zero Clause License
* Copyright (c) Cynthia Rey
* SPDX-License-Identifier: 0BSD
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
const TABLES_COUNT = 1000
const MAX_KEYS_PER_TABLE = 50
const MAX_TABLE_ARRAY = 10
const MAX_ELEMENTS_PER_INLINE_STRUCT = 10
const STRING_LENGTH = [ 10, 50 ]
const ML_STRING_MAX_WORDS = 10
const ML_STRING_MAX_LINES = 10
const KEY_PART_LENGTH = [ 5, 10 ]
const MAX_KEY_DEPTH = 3
const ALPHABET = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
function generateKey (maxDepth = 1) {
let key = ''
const depth = ((Math.random() * maxDepth) | 0) + 1
for (let i = 0; i < depth; i++) {
if (i !== 0) key += '.'
const targetLength = ((Math.random() * (KEY_PART_LENGTH[1] - KEY_PART_LENGTH[0])) | 0) + KEY_PART_LENGTH[0]
for (let j = 0; j < targetLength; j++) {
key += ALPHABET[(Math.random() * ALPHABET.length) | 0]
}
}
return key
}
function generateWord () {
let word = ''
const targetLength = ((Math.random() * (STRING_LENGTH[1] - STRING_LENGTH[0])) | 0) + STRING_LENGTH[0]
for (let j = 0; j < targetLength; j++) {
word += ALPHABET[(Math.random() * ALPHABET.length) | 0]
}
return word
}
const ESCAPES = [ '\\b', '\\t', '\\n', '\\f', '\\r', '\\"', '\\\\', '\\u2764', '\\U0001F43F' ]
function generateString (isInline) {
let str = ''
const isLiteral = Math.random() < .2
const isMl = isInline ? false : Math.random() < .1
const lines = (isMl && (Math.random() * ML_STRING_MAX_LINES)) + 1
const escapeEol = Math.random() < .1
for (let i = 0; i < lines; i++) {
if (i !== 0) {
if (escapeEol) str += ' \\'
str += '\n'
}
const words = (isMl && (Math.random() * ML_STRING_MAX_WORDS)) + 1
for (let j = 0; j < words; j++) {
if (j !== 0) str += ' '
str += generateWord()
if (!isLiteral && Math.random() < .1) {
str += ESCAPES[(Math.random() * ESCAPES.length) | 0]
}
}
}
let strMark = isLiteral ? "'" : '"'
if (isMl) strMark = strMark.repeat(3)
return isLiteral
? strMark + str + strMark
: strMark + str + strMark
}
function generateInteger () {
const isLarge = Math.random() < .1
const number = Math.floor(Math.random() * (isLarge ? Number.MAX_SAFE_INTEGER - 1 : 10000))
if (Math.random() < .4) {
if (Math.random() < .2) {
return '0b' + number.toString(2)
}
if (Math.random() < .2) {
return '0o' + number.toString(8)
}
const hex = Math.random() < .5 ? number.toString(16) : number.toString(16).toUpperCase()
return '0x' + (isLarge ? hex.replace(/(\d)(?=(\d{4})+(?!\d))/g, "$1_") : hex)
}
const sign = Math.random() < .5 ? '-' : (Math.random() < .05 ? '+' : '')
return sign + (isLarge ? number.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1_") : number)
}
const FLOAT_SPECIAL = [ 'inf', '+inf', '-inf', 'nan', '+nan', '-nan' ]
function generateFloat () {
if (Math.random() < .05) {
return FLOAT_SPECIAL[(Math.random() * FLOAT_SPECIAL.length) | 0]
}
const sign = Math.random() < .5 ? '-' : (Math.random() < .05 ? '+' : '')
const intPart = ((Math.random() * 10000) | 0).toString()
const decPart = ((Math.random() * 10000) | 0).toString()
let exponent = ''
if (Math.random() < .2) {
exponent += Math.random() < .5 ? 'e' : 'E'
exponent += Math.random() < .5 ? '-' : (Math.random() < .05 ? '+' : '')
exponent += ((Math.random() * 100) | 0).toString()
}
return sign + intPart + '.' + decPart + exponent
}
function generateBoolean () {
return (Math.random() < .5).toString()
}
function generateDate () {
const date = new Date(Math.round(Math.random() * Date.now())).toISOString().split(/T|Z/)
date.splice(1, 0, Math.random() < .5 ? ' ' : 'T')
if (Math.random() < .6) {
date[2] = date[2].slice(0, 8)
}
if (Math.random() < .6) {
if (Math.random() < .2) {
const sign = Math.random() < .5 ? '-' : '+'
const hours = ((Math.random() * 12) | 0).toString().padStart(2, '0')
const mins = Math.random() < .5 ? '30' : '00'
date[3] = sign + hours + ':' + mins
} else {
date[3] = 'Z'
}
}
if (Math.random() < .3) {
return date[0]
}
if (Math.random() < .3) {
return date[2]
}
return date.join('')
}
function generateArray () {
let str = '[ '
const targetCount = ((Math.random() * MAX_ELEMENTS_PER_INLINE_STRUCT) | 0) + 1
for (let i = 0; i < targetCount; i++) {
if (i !== 0) str += ', '
str += generateValue(.05)
}
return str + ' ]'
}
function generateInlineTable () {
let str = '{ '
const targetCount = ((Math.random() * MAX_ELEMENTS_PER_INLINE_STRUCT) | 0) + 1
for (let i = 0; i < targetCount; i++) {
if (i !== 0) str += ', '
str += generateKey()
str += ' = '
str += generateValue(.1)
}
return str + ' }'
}
function generateValue (isInline) {
if (Math.random() < (isInline ? .05 : .2)) {
return Math.random() < .5
? generateInlineTable()
: generateArray()
}
const kind = (Math.random() * 4) | 0
switch (kind) {
case 0: return generateString()
case 1: return generateInteger()
case 2: return generateFloat()
case 3: return generateDate()
}
}
let document = ''
let table = ''
let currentDepth = 0
let arrayDepthToGo = 0
for (let i = 0; i < TABLES_COUNT; i++) {
if (arrayDepthToGo) {
i--
arrayDepthToGo--
document += `[[${table}]]\n`
} else {
if (currentDepth && currentDepth < MAX_KEY_DEPTH && Math.random() < .6) {
table += '.' + generateKey(1)
currentDepth++
} else {
currentDepth = 1
table = generateKey(1)
}
if (Math.random() < .05) {
i--
arrayDepthToGo = ((Math.random() * MAX_TABLE_ARRAY) | 0) + 1
continue
}
document += `[${table}]\n`
}
const keyCount = ((Math.random() * MAX_KEYS_PER_TABLE) | 0) + 1
for (let j = 0; j < keyCount; j++) {
const key = generateKey(MAX_KEY_DEPTH)
document += `${key} = ${generateValue()}\n`
}
document += `\n`
}
console.log(document)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment