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