232 lines
6.4 KiB
JavaScript
232 lines
6.4 KiB
JavaScript
"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 = [];
|
|
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;
|
|
}
|
|
|
|
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;
|
|
return processed || quote ? "\"" + object + "\"" : object;
|
|
}
|
|
|
|
if (typeof object === "symbol") {
|
|
return object.toString();
|
|
}
|
|
|
|
if (typeof object === "function" && !(object instanceof RegExp)) {
|
|
return ascii.func(object);
|
|
}
|
|
|
|
processed = processed || [];
|
|
|
|
if (isCircular(object, processed)) { return "[Circular]"; }
|
|
|
|
if (typeOf(object) === "array") {
|
|
return ascii.array.call(f, object, processed);
|
|
}
|
|
|
|
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, processed);
|
|
}
|
|
|
|
return ascii.object.call(f, object, processed, indent);
|
|
}
|
|
|
|
ascii.func = function (func) {
|
|
var funcName = functionName(func) || "";
|
|
return "function " + funcName + "() {}";
|
|
};
|
|
|
|
function delimit(str, delimiters) {
|
|
delimiters = delimiters || ["[", "]"];
|
|
return delimiters[0] + str + delimiters[1];
|
|
}
|
|
|
|
ascii.array = function (array, processed, delimiters) {
|
|
processed = processed || [];
|
|
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.object = function (object, processed, indent) {
|
|
processed = processed || [];
|
|
processed.push(object);
|
|
indent = indent || 0;
|
|
var pieces = [];
|
|
var symbols = typeof Object.getOwnPropertySymbols === "function"
|
|
? Object.getOwnPropertySymbols(object)
|
|
: [];
|
|
var properties = Object.keys(object).sort().concat(symbols);
|
|
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, indent + 2);
|
|
}
|
|
|
|
str = (
|
|
typeof prop === "string" && /\s/.test(prop) ?
|
|
"\"" + 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 = indent; i < k; ++i) { is += " "; }
|
|
|
|
if (l < properties.length)
|
|
{pieces.push("[... " + (properties.length - l) + " more elements]");}
|
|
|
|
if (length + indent > 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) { 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 +
|
|
"</" + tagName + ">";
|
|
|
|
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;
|