@aitodotai/json-stringify-pretty-compact
Version:
The best of both `JSON.stringify(obj)` and `JSON.stringify(obj, null, indent)`.
147 lines (123 loc) • 3.79 kB
JavaScript
function isObject (obj) {
return typeof obj === 'object' && obj !== null
}
function forEach (obj, cb) {
if (Array.isArray(obj)) {
obj.forEach(cb)
} else if (isObject(obj)) {
Object.keys(obj).forEach(function (key) {
var val = obj[key]
cb(val, key)
})
}
}
function getTreeDepth (obj) {
var depth = 0
if (Array.isArray(obj) || isObject(obj)) {
forEach(obj, function (val) {
if (Array.isArray(val) || isObject(val)) {
var tmpDepth = getTreeDepth(val)
if (tmpDepth > depth) {
depth = tmpDepth
}
}
})
return depth + 1
}
return depth
}
function stringify (obj, options) {
options = options || {}
var indent = JSON.stringify([1], null, get(options, 'indent', 2)).slice(2, -3)
var addMargin = get(options, 'margins', false)
var addArrayMargin = get(options, 'arrayMargins', false)
var addObjectMargin = get(options, 'objectMargins', false)
var maxLength = (indent === '' ? Infinity : get(options, 'maxLength', 80))
var maxNesting = get(options, 'maxNesting', Infinity)
return (function _stringify (obj, currentIndent, reserved) {
if (obj && typeof obj.toJSON === 'function') {
obj = obj.toJSON()
}
var string = JSON.stringify(obj)
if (string === undefined) {
return string
}
var length = maxLength - currentIndent.length - reserved
var treeDepth = getTreeDepth(obj)
if (treeDepth <= maxNesting && string.length <= length) {
var prettified = prettify(string, {
addMargin: addMargin,
addArrayMargin: addArrayMargin,
addObjectMargin: addObjectMargin
})
if (prettified.length <= length) {
return prettified
}
}
if (isObject(obj)) {
var nextIndent = currentIndent + indent
var items = []
var delimiters
var comma = function (array, index) {
return (index === array.length - 1 ? 0 : 1)
}
if (Array.isArray(obj)) {
for (var index = 0; index < obj.length; index++) {
items.push(
_stringify(obj[index], nextIndent, comma(obj, index)) || 'null'
)
}
delimiters = '[]'
} else {
Object.keys(obj).forEach(function (key, index, array) {
var keyPart = JSON.stringify(key) + ': '
var value = _stringify(obj[key], nextIndent,
keyPart.length + comma(array, index))
if (value !== undefined) {
items.push(keyPart + value)
}
})
delimiters = '{}'
}
if (items.length > 0) {
return [
delimiters[0],
indent + items.join(',\n' + nextIndent),
delimiters[1]
].join('\n' + currentIndent)
}
}
return string
}(obj, '', 0))
}
// Note: This regex matches even invalid JSON strings, but since we’re
// working on the output of `JSON.stringify` we know that only valid strings
// are present (unless the user supplied a weird `options.indent` but in
// that case we don’t care since the output would be invalid anyway).
var stringOrChar = /("(?:[^\\"]|\\.)*")|[:,\][}{]/g
function prettify (string, options) {
options = options || {}
var tokens = {
'{': '{',
'}': '}',
'[': '[',
']': ']',
',': ', ',
':': ': '
}
if (options.addMargin || options.addObjectMargin) {
tokens['{'] = '{ '
tokens['}'] = ' }'
}
if (options.addMargin || options.addArrayMargin) {
tokens['['] = '[ '
tokens[']'] = ' ]'
}
return string.replace(stringOrChar, function (match, string) {
return string ? match : tokens[match]
})
}
function get (options, name, defaultValue) {
return (name in options ? options[name] : defaultValue)
}
module.exports = stringify