Created
January 13, 2021 23:02
-
-
Save Akryum/4834d93626042a31b032d2df51855d8f to your computer and use it in GitHub Desktop.
Format a JS object or array to JavaScript source code string
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const KEY_ESCAPE_REG = /[\s-.:|#@$£*%]/ | |
const MAX_SINGLE_LINE_ARRAY_LENGTH = 3 | |
export function formatObjectToSource (obj) { | |
return printLines(Array.isArray(obj) ? arrayToSourceLines(obj) : objectToSourceLines(obj)) | |
} | |
function objectToSourceLines (object, indentCount = 0) { | |
return createLines(indentCount, lines => { | |
lines.push('{') | |
lines.push(...createLines(1, lines => { | |
for (const key in object) { | |
const value = object[key] | |
let printedKey = key | |
if (KEY_ESCAPE_REG.test(key)) { | |
printedKey = `'${printedKey}'` | |
} | |
addLinesFromValue(lines, value, `${printedKey}: `, ',') | |
} | |
})) | |
lines.push('}') | |
}) | |
} | |
/** | |
* @param {any[]} array | |
* @param {number} indentCount | |
*/ | |
function arrayToSourceLines (array, indentCount = 0) { | |
return createLines(indentCount, lines => { | |
const contentLines = createLines(1, lines => { | |
for (const value of array) { | |
addLinesFromValue(lines, value, '', ',') | |
} | |
}) | |
if (contentLines.length === 0) { | |
lines.push('[]') | |
} else if (contentLines.length <= MAX_SINGLE_LINE_ARRAY_LENGTH) { | |
const [first] = contentLines | |
first.line = contentLines.map(({ line }) => line.substr(0, line.length - 1)).join(', ') | |
first.line = `[${first.line}]` | |
first.spaces-- | |
lines.push(first) | |
} else { | |
lines.push('[', ...contentLines, ']') | |
} | |
}) | |
} | |
/** | |
* @param {number} count | |
*/ | |
function indent (count) { | |
return ' '.repeat(count * 2) | |
} | |
/** | |
* @param {number} indentCount | |
* @param {(lines: any[]) => unknown} handler | |
*/ | |
function createLines (indentCount, handler) { | |
const lines = [] | |
handler(lines) | |
return lines.map(line => { | |
if (line.spaces != null) { | |
line.spaces += indentCount | |
return line | |
} | |
return { spaces: indentCount, line } | |
}) | |
} | |
function printLines (lines) { | |
return lines.map(({ spaces, line }) => indent(spaces) + line).join('\n') | |
} | |
function addLinesFromValue (lines, value, before, after) { | |
let result | |
if (Array.isArray(value)) { | |
lines.push(...wrap(arrayToSourceLines(value), before, after)) | |
return | |
} else if (value && typeof value === 'object') { | |
lines.push(...wrap(objectToSourceLines(value), before, after)) | |
return | |
} else if (typeof value === 'string') { | |
result = value.includes('\'') ? `\`${value}\`` : `'${value}'` | |
} else if (typeof value === 'undefined') { | |
return | |
} else { | |
result = value | |
} | |
lines.push(before + result + after) | |
} | |
function wrap (lines, before, after) { | |
lines[0].line = before + lines[0].line | |
lines[lines.length - 1].line += after | |
return lines | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment