1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 var EXPORTED_SYMBOLS = ["pprint", "truncate"];
9 const { Log } = ChromeUtils.import("chrome://remote/content/Log.jsm");
11 const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
12 const { XPCOMUtils } = ChromeUtils.import(
13 "resource://gre/modules/XPCOMUtils.jsm"
16 XPCOMUtils.defineLazyGetter(this, "log", Log.get);
18 const ELEMENT_NODE = 1;
19 const MAX_STRING_LENGTH = 250;
20 const PREF_TRUNCATE = "remote.log.truncate";
23 * Pretty-print values passed to template strings.
27 * let bool = {value: true};
28 * pprint`Expected boolean, got ${bool}`;
29 * => 'Expected boolean, got [object Object] {"value": true}'
31 * let htmlElement = document.querySelector("input#foo");
32 * pprint`Expected element ${htmlElement}`;
33 * => 'Expected element <input id="foo" class="bar baz" type="input">'
35 * pprint`Current window: ${window}`;
36 * => '[object Window https://www.mozilla.org/]'
38 function pprint(ss, ...values) {
39 function pretty(val) {
40 let proto = Object.prototype.toString.call(val);
42 typeof val == "object" &&
45 val.nodeType === ELEMENT_NODE
47 return prettyElement(val);
48 } else if (["[object Window]", "[object ChromeWindow]"].includes(proto)) {
49 return prettyWindowGlobal(val);
50 } else if (proto == "[object Attr]") {
51 return prettyAttr(val);
53 return prettyObject(val);
56 function prettyElement(el) {
57 let attrs = ["id", "class", "href", "name", "src", "type"];
60 for (let attr of attrs) {
61 if (el.hasAttribute(attr)) {
62 idents += ` ${attr}="${el.getAttribute(attr)}"`;
66 return `<${el.localName}${idents}>`;
69 function prettyWindowGlobal(win) {
70 let proto = Object.prototype.toString.call(win);
71 return `[${proto.substring(1, proto.length - 1)} ${win.location}]`;
74 function prettyAttr(obj) {
75 return `[object Attr ${obj.name}="${obj.value}"]`;
78 function prettyObject(obj) {
79 let proto = Object.prototype.toString.call(obj);
82 s = JSON.stringify(obj);
84 if (e instanceof TypeError) {
90 return `${proto} ${s}`;
94 for (let i = 0; i < ss.length; i++) {
96 if (i < values.length) {
99 s = pretty(values[i]);
101 log.warn("Problem pretty printing:", e);
102 s = typeof values[i];
111 * Template literal that truncates string values in arbitrary objects.
113 * Given any object, the template will walk the object and truncate
114 * any strings it comes across to a reasonable limit. This is suitable
115 * when you have arbitrary data and data integrity is not important.
117 * The strings are truncated in the middle so that the beginning and
118 * the end is preserved. This will make a long, truncated string look
119 * like "X <...> Y", where X and Y are half the number of characters
120 * of the maximum string length from either side of the string.
125 * truncate`Hello ${"x".repeat(260)}!`;
126 * // Hello xxx ... xxx!
128 * Functions named `toJSON` or `toString` on objects will be called.
130 function truncate(strings, ...values) {
131 const truncateLog = Services.prefs.getBoolPref(PREF_TRUNCATE, false);
133 const typ = Object.prototype.toString.call(obj);
136 case "[object Undefined]":
137 case "[object Null]":
138 case "[object Boolean]":
139 case "[object Number]":
142 case "[object String]":
143 if (truncateLog && obj.length > MAX_STRING_LENGTH) {
144 let s1 = obj.substring(0, MAX_STRING_LENGTH / 2);
145 let s2 = obj.substring(obj.length - MAX_STRING_LENGTH / 2);
146 return `${s1} ... ${s2}`;
150 case "[object Array]":
151 return obj.map(walk);
156 Object.getOwnPropertyNames(obj).includes("toString") &&
157 typeof obj.toString == "function"
159 return walk(obj.toString());
163 for (let prop in obj) {
164 rv[prop] = walk(obj[prop]);
171 for (let i = 0; i < strings.length; ++i) {
172 res.push(strings[i]);
173 if (i < values.length) {
174 let obj = walk(values[i]);
175 let t = Object.prototype.toString.call(obj);
176 if (t == "[object Array]" || t == "[object Object]") {
177 res.push(JSON.stringify(obj));