// https://github.com/mightyiam/get-own-enumerable-property-symbols/blob/master/src/index.ts const getOwnEnumPropSymbols = (object: Object): symbol[] => Object.getOwnPropertySymbols(object).filter( (keySymbol): boolean => object.propertyIsEnumerable(keySymbol) ); // https://github.com/sindresorhus/is-regexp/blob/master/index.js const isRegexp = input => Object.prototype.toString.call(input) === "[object RegExp]"; // https://github.com/sindresorhus/is-obj/blob/master/index.js const isObj = function(x) { var type = typeof x; return x !== null && (type === "object" || type === "function"); }; module.exports = (val, opts, pad) => { const seen = []; return (function stringify(val, opts, pad) { opts = opts || {}; opts.indent = opts.indent || "\t"; pad = pad || ""; let tokens; if (opts.inlineCharacterLimit === undefined) { tokens = { newLine: "\n", newLineOrSpace: "\n", pad, indent: pad + opts.indent, }; } else { tokens = { newLine: "@@__STRINGIFY_OBJECT_NEW_LINE__@@", newLineOrSpace: "@@__STRINGIFY_OBJECT_NEW_LINE_OR_SPACE__@@", pad: "@@__STRINGIFY_OBJECT_PAD__@@", indent: "@@__STRINGIFY_OBJECT_INDENT__@@", }; } const expandWhiteSpace = string => { if (opts.inlineCharacterLimit === undefined) { return string; } const oneLined = string .replace(new RegExp(tokens.newLine, "g"), "") .replace(new RegExp(tokens.newLineOrSpace, "g"), " ") .replace(new RegExp(tokens.pad + "|" + tokens.indent, "g"), ""); if (oneLined.length <= opts.inlineCharacterLimit) { return oneLined; } return string .replace( new RegExp(tokens.newLine + "|" + tokens.newLineOrSpace, "g"), "\n" ) .replace(new RegExp(tokens.pad, "g"), pad) .replace(new RegExp(tokens.indent, "g"), pad + opts.indent); }; if (seen.indexOf(val) !== -1) { return '"[Circular]"'; } if ( val === null || val === undefined || typeof val === "number" || typeof val === "boolean" || typeof val === "function" || typeof val === "symbol" || isRegexp(val) ) { return String(val); } if (val instanceof Date) { return `new Date('${val.toISOString()}')`; } if (Array.isArray(val)) { if (val.length === 0) { return "[]"; } seen.push(val); const ret = "[" + tokens.newLine + val .map((el, i) => { const eol = val.length - 1 === i ? tokens.newLine : "," + tokens.newLineOrSpace; let value = stringify(el, opts, pad + opts.indent); if (opts.transform) { value = opts.transform(val, i, value); } return tokens.indent + value + eol; }) .join("") + tokens.pad + "]"; seen.pop(val); return expandWhiteSpace(ret); } if (isObj(val)) { const objKeys = Object.keys(val).concat(getOwnEnumPropSymbols(val)); if (objKeys.length === 0) { return "{}"; } seen.push(val); const ret = "{" + tokens.newLine + objKeys .map((el, i) => { if (opts.filter && !opts.filter(val, el)) { return ""; } const eol = objKeys.length - 1 === i ? tokens.newLine : "," + tokens.newLineOrSpace; const isSymbol = typeof el === "symbol"; const isClassic = !isSymbol && /^[a-z$_][a-z$_0-9]*$/i.test(el); const key = isSymbol || isClassic ? el : stringify(el, opts); let value = stringify(val[el], opts, pad + opts.indent); if (opts.transform) { value = opts.transform(val, el, value); } return tokens.indent + String(key) + ": " + value + eol; }) .join("") + tokens.pad + "}"; seen.pop(val); return expandWhiteSpace(ret); } val = String(val).replace(/[\r\n]/g, x => (x === "\n" ? "\\n" : "\\r")); if (opts.singleQuotes === false) { val = val.replace(/"/g, '\\"'); return `"${val}"`; } val = val.replace(/\\?'/g, "\\'"); return `'${val}'`; })(val, opts, pad); };