1 | "use strict";
|
2 |
|
3 | var samsam = require("@sinonjs/samsam");
|
4 | var formatio = {
|
5 | excludeConstructors: ["Object", /^.$/],
|
6 | quoteStrings: true,
|
7 | limitChildrenCount: 0
|
8 | };
|
9 |
|
10 | var specialObjects = [];
|
11 | if (typeof global !== "undefined") {
|
12 | specialObjects.push({ object: global, value: "[object global]" });
|
13 | }
|
14 | if (typeof document !== "undefined") {
|
15 | specialObjects.push({
|
16 | object: document,
|
17 | value: "[object HTMLDocument]"
|
18 | });
|
19 | }
|
20 | if (typeof window !== "undefined") {
|
21 | specialObjects.push({ object: window, value: "[object Window]" });
|
22 | }
|
23 |
|
24 | function functionName(func) {
|
25 | if (!func) { return ""; }
|
26 | if (func.displayName) { return func.displayName; }
|
27 | if (func.name) { return func.name; }
|
28 | var matches = func.toString().match(/function\s+([^\(]+)/m);
|
29 | return (matches && matches[1]) || "";
|
30 | }
|
31 |
|
32 | function constructorName(f, object) {
|
33 | var name = functionName(object && object.constructor);
|
34 | var excludes = f.excludeConstructors ||
|
35 | formatio.excludeConstructors || [];
|
36 |
|
37 | var i, l;
|
38 | for (i = 0, l = excludes.length; i < l; ++i) {
|
39 | if (typeof excludes[i] === "string" && excludes[i] === name) {
|
40 | return "";
|
41 | } else if (excludes[i].test && excludes[i].test(name)) {
|
42 | return "";
|
43 | }
|
44 | }
|
45 |
|
46 | return name;
|
47 | }
|
48 |
|
49 | function isCircular(object, objects) {
|
50 | if (typeof object !== "object") { return false; }
|
51 | var i, l;
|
52 | for (i = 0, l = objects.length; i < l; ++i) {
|
53 | if (objects[i] === object) { return true; }
|
54 | }
|
55 | return false;
|
56 | }
|
57 |
|
58 | function ascii(f, object, processed, indent) {
|
59 | if (typeof object === "string") {
|
60 | if (object.length === 0) { return "(empty string)"; }
|
61 | var qs = f.quoteStrings;
|
62 | var quote = typeof qs !== "boolean" || qs;
|
63 | return processed || quote ? "\"" + object + "\"" : object;
|
64 | }
|
65 |
|
66 | if (typeof object === "function" && !(object instanceof RegExp)) {
|
67 | return ascii.func(object);
|
68 | }
|
69 |
|
70 | processed = processed || [];
|
71 |
|
72 | if (isCircular(object, processed)) { return "[Circular]"; }
|
73 |
|
74 | if (Object.prototype.toString.call(object) === "[object Array]") {
|
75 | return ascii.array.call(f, object, processed);
|
76 | }
|
77 |
|
78 | if (!object) { return String((1 / object) === -Infinity ? "-0" : object); }
|
79 | if (samsam.isElement(object)) { return ascii.element(object); }
|
80 |
|
81 | if (typeof object.toString === "function" &&
|
82 | object.toString !== Object.prototype.toString) {
|
83 | return object.toString();
|
84 | }
|
85 |
|
86 | var i, l;
|
87 | for (i = 0, l = specialObjects.length; i < l; i++) {
|
88 | if (object === specialObjects[i].object) {
|
89 | return specialObjects[i].value;
|
90 | }
|
91 | }
|
92 |
|
93 | if (typeof Set !== "undefined" && object instanceof Set) {
|
94 | return ascii.set.call(f, object, processed);
|
95 | }
|
96 |
|
97 | return ascii.object.call(f, object, processed, indent);
|
98 | }
|
99 |
|
100 | ascii.func = function (func) {
|
101 | return "function " + functionName(func) + "() {}";
|
102 | };
|
103 |
|
104 | function delimit(str, delimiters) {
|
105 | delimiters = delimiters || ["[", "]"];
|
106 | return delimiters[0] + str + delimiters[1];
|
107 | }
|
108 |
|
109 | ascii.array = function (array, processed, delimiters) {
|
110 | processed = processed || [];
|
111 | processed.push(array);
|
112 | var pieces = [];
|
113 | var i, l;
|
114 | l = (this.limitChildrenCount > 0) ?
|
115 | Math.min(this.limitChildrenCount, array.length) : array.length;
|
116 |
|
117 | for (i = 0; i < l; ++i) {
|
118 | pieces.push(ascii(this, array[i], processed));
|
119 | }
|
120 |
|
121 | if (l < array.length) {
|
122 | pieces.push("[... " + (array.length - l) + " more elements]");
|
123 | }
|
124 |
|
125 | return delimit(pieces.join(", "), delimiters);
|
126 | };
|
127 |
|
128 | ascii.set = function (set, processed) {
|
129 | return ascii.array.call(this, Array.from(set), processed, ["Set {", "}"]);
|
130 | };
|
131 |
|
132 | ascii.object = function (object, processed, indent) {
|
133 | processed = processed || [];
|
134 | processed.push(object);
|
135 | indent = indent || 0;
|
136 | var pieces = [];
|
137 | var properties = Object.keys(object).sort();
|
138 | var length = 3;
|
139 | var prop, str, obj, i, k, l;
|
140 | l = (this.limitChildrenCount > 0) ?
|
141 | Math.min(this.limitChildrenCount, properties.length) : properties.length;
|
142 |
|
143 | for (i = 0; i < l; ++i) {
|
144 | prop = properties[i];
|
145 | obj = object[prop];
|
146 |
|
147 | if (isCircular(obj, processed)) {
|
148 | str = "[Circular]";
|
149 | } else {
|
150 | str = ascii(this, obj, processed, indent + 2);
|
151 | }
|
152 |
|
153 | str = (/\s/.test(prop) ? "\"" + prop + "\"" : prop) + ": " + str;
|
154 | length += str.length;
|
155 | pieces.push(str);
|
156 | }
|
157 |
|
158 | var cons = constructorName(this, object);
|
159 | var prefix = cons ? "[" + cons + "] " : "";
|
160 | var is = "";
|
161 | for (i = 0, k = indent; i < k; ++i) { is += " "; }
|
162 |
|
163 | if (l < properties.length)
|
164 | {pieces.push("[... " + (properties.length - l) + " more elements]");}
|
165 |
|
166 | if (length + indent > 80) {
|
167 | return prefix + "{\n " + is + pieces.join(",\n " + is) + "\n" +
|
168 | is + "}";
|
169 | }
|
170 | return prefix + "{ " + pieces.join(", ") + " }";
|
171 | };
|
172 |
|
173 | ascii.element = function (element) {
|
174 | var tagName = element.tagName.toLowerCase();
|
175 | var attrs = element.attributes;
|
176 | var pairs = [];
|
177 | var attr, attrName, i, l, val;
|
178 |
|
179 | for (i = 0, l = attrs.length; i < l; ++i) {
|
180 | attr = attrs.item(i);
|
181 | attrName = attr.nodeName.toLowerCase().replace("html:", "");
|
182 | val = attr.nodeValue;
|
183 | if (attrName !== "contenteditable" || val !== "inherit") {
|
184 | if (val) { pairs.push(attrName + "=\"" + val + "\""); }
|
185 | }
|
186 | }
|
187 |
|
188 | var formatted = "<" + tagName + (pairs.length > 0 ? " " : "");
|
189 |
|
190 | var content = element.innerHTML || "";
|
191 |
|
192 | if (content.length > 20) {
|
193 | content = content.substr(0, 20) + "[...]";
|
194 | }
|
195 |
|
196 | var res = formatted + pairs.join(" ") + ">" + content +
|
197 | "</" + tagName + ">";
|
198 |
|
199 | return res.replace(/ contentEditable="inherit"/, "");
|
200 | };
|
201 |
|
202 | function Formatio(options) {
|
203 |
|
204 | for (var opt in options) {
|
205 | this[opt] = options[opt];
|
206 | }
|
207 | }
|
208 |
|
209 | Formatio.prototype = {
|
210 | functionName: functionName,
|
211 |
|
212 | configure: function (options) {
|
213 | return new Formatio(options);
|
214 | },
|
215 |
|
216 | constructorName: function (object) {
|
217 | return constructorName(this, object);
|
218 | },
|
219 |
|
220 | ascii: function (object, processed, indent) {
|
221 | return ascii(this, object, processed, indent);
|
222 | }
|
223 | };
|
224 |
|
225 | module.exports = Formatio.prototype;
|