"use strict"; var samsam = require("@sinonjs/samsam"); var functionName = require("@sinonjs/commons").functionName; var typeOf = require("@sinonjs/commons").typeOf; var formatio = { excludeConstructors: ["Object", /^.$/], quoteStrings: true, limitChildrenCount: 0 }; var specialObjects = []; /* istanbul ignore else */ if (typeof global !== "undefined") { specialObjects.push({ object: global, value: "[object global]" }); } if (typeof document !== "undefined") { specialObjects.push({ object: document, value: "[object HTMLDocument]" }); } if (typeof window !== "undefined") { specialObjects.push({ object: window, value: "[object Window]" }); } function constructorName(f, object) { var name = functionName(object && object.constructor); var excludes = f.excludeConstructors || formatio.excludeConstructors; var i, l; for (i = 0, l = excludes.length; i < l; ++i) { if (typeof excludes[i] === "string" && excludes[i] === name) { return ""; } else if (excludes[i].test && excludes[i].test(name)) { return ""; } } return name; } function isCircular(object, objects) { if (typeof object !== "object") { return false; } var i, l; for (i = 0, l = objects.length; i < l; ++i) { if (objects[i] === object) { return true; } } return false; } // eslint-disable-next-line complexity function ascii(f, object, processed, indent) { if (typeof object === "string") { if (object.length === 0) { return "(empty string)"; } var qs = f.quoteStrings; var quote = typeof qs !== "boolean" || qs; // eslint-disable-next-line quotes return processed || quote ? '"' + object + '"' : object; } if (typeof object === "symbol") { return object.toString(); } if (typeof object === "function" && !(object instanceof RegExp)) { return ascii.func(object); } // eslint supports bigint as of version 6.0.0 // https://github.com/eslint/eslint/commit/e4ab0531c4e44c23494c6a802aa2329d15ac90e5 // eslint-disable-next-line if (typeOf(object) === "bigint") { return object.toString(); } var internalProcessed = processed || []; if (isCircular(object, internalProcessed)) { return "[Circular]"; } if (typeOf(object) === "array") { return ascii.array.call(f, object, internalProcessed); } if (!object) { return String(1 / object === -Infinity ? "-0" : object); } if (samsam.isElement(object)) { return ascii.element(object); } if ( typeof object.toString === "function" && object.toString !== Object.prototype.toString ) { return object.toString(); } var i, l; for (i = 0, l = specialObjects.length; i < l; i++) { if (object === specialObjects[i].object) { return specialObjects[i].value; } } if (samsam.isSet(object)) { return ascii.set.call(f, object, internalProcessed); } if (object instanceof Map) { return ascii.map.call(f, object, internalProcessed); } return ascii.object.call(f, object, internalProcessed, indent); } ascii.func = function(func) { var funcName = functionName(func) || ""; return "function " + funcName + "() {}"; }; function delimit(str, delimiters) { var delims = delimiters || ["[", "]"]; return delims[0] + str + delims[1]; } ascii.array = function(array, processed, delimiters) { processed.push(array); var pieces = []; var i, l; l = this.limitChildrenCount > 0 ? Math.min(this.limitChildrenCount, array.length) : array.length; for (i = 0; i < l; ++i) { pieces.push(ascii(this, array[i], processed)); } if (l < array.length) { pieces.push("[... " + (array.length - l) + " more elements]"); } return delimit(pieces.join(", "), delimiters); }; ascii.set = function(set, processed) { return ascii.array.call(this, Array.from(set), processed, ["Set {", "}"]); }; ascii.map = function(map, processed) { return ascii.array.call(this, Array.from(map), processed, ["Map [", "]"]); }; function getSymbols(object) { if (samsam.isArguments(object)) { return []; } /* istanbul ignore else */ if (typeof Object.getOwnPropertySymbols === "function") { return Object.getOwnPropertySymbols(object); } /* istanbul ignore next: This is only for IE, since getOwnPropertySymbols * does not exist on Object there */ return []; } ascii.object = function(object, processed, indent) { processed.push(object); var internalIndent = indent || 0; var pieces = []; var properties = Object.keys(object) .sort() .concat(getSymbols(object)); var length = 3; var prop, str, obj, i, k, l; l = this.limitChildrenCount > 0 ? Math.min(this.limitChildrenCount, properties.length) : properties.length; for (i = 0; i < l; ++i) { prop = properties[i]; obj = object[prop]; if (isCircular(obj, processed)) { str = "[Circular]"; } else { str = ascii(this, obj, processed, internalIndent + 2); } str = (typeof prop === "string" && /\s/.test(prop) ? // eslint-disable-next-line quotes '"' + prop + '"' : prop.toString()) + ": " + str; length += str.length; pieces.push(str); } var cons = constructorName(this, object); var prefix = cons ? "[" + cons + "] " : ""; var is = ""; for (i = 0, k = internalIndent; i < k; ++i) { is += " "; } if (l < properties.length) { pieces.push("[... " + (properties.length - l) + " more elements]"); } if (length + internalIndent > 80) { return ( prefix + "{\n " + is + pieces.join(",\n " + is) + "\n" + is + "}" ); } return prefix + "{ " + pieces.join(", ") + " }"; }; ascii.element = function(element) { var tagName = element.tagName.toLowerCase(); var attrs = element.attributes; var pairs = []; var attr, attrName, i, l, val; for (i = 0, l = attrs.length; i < l; ++i) { attr = attrs.item(i); attrName = attr.nodeName.toLowerCase().replace("html:", ""); val = attr.nodeValue; if (attrName !== "contenteditable" || val !== "inherit") { if (val) { // eslint-disable-next-line quotes pairs.push(attrName + '="' + val + '"'); } } } var formatted = "<" + tagName + (pairs.length > 0 ? " " : ""); // SVG elements have undefined innerHTML var content = element.innerHTML || ""; if (content.length > 20) { content = content.substr(0, 20) + "[...]"; } var res = formatted + pairs.join(" ") + ">" + content + ""; return res.replace(/ contentEditable="inherit"/, ""); }; function Formatio(options) { // eslint-disable-next-line guard-for-in for (var opt in options) { this[opt] = options[opt]; } } Formatio.prototype = { functionName: functionName, configure: function(options) { return new Formatio(options); }, constructorName: function(object) { return constructorName(this, object); }, ascii: function(object, processed, indent) { return ascii(this, object, processed, indent); } }; module.exports = Formatio.prototype;