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 { XPCOMUtils } = ChromeUtils.import(
10 "resource://gre/modules/XPCOMUtils.jsm"
13 XPCOMUtils.defineLazyModuleGetters(this, {
14 Services: "resource://gre/modules/Services.jsm",
16 Log: "chrome://remote/content/shared/Log.jsm",
19 XPCOMUtils.defineLazyGetter(this, "logger", () => Log.get());
21 const ELEMENT_NODE = 1;
22 const MAX_STRING_LENGTH = 250;
24 const PREF_TRUNCATE = "remote.log.truncate";
27 * Pretty-print values passed to template strings.
31 * let bool = {value: true};
32 * pprint`Expected boolean, got ${bool}`;
33 * => 'Expected boolean, got [object Object] {"value": true}'
35 * let htmlElement = document.querySelector("input#foo");
36 * pprint`Expected element ${htmlElement}`;
37 * => 'Expected element <input id="foo" class="bar baz" type="input">'
39 * pprint`Current window: ${window}`;
40 * => '[object Window https://www.mozilla.org/]'
42 function pprint(ss, ...values) {
43 function pretty(val) {
44 let proto = Object.prototype.toString.call(val);
46 typeof val == "object" &&
49 val.nodeType === ELEMENT_NODE
51 return prettyElement(val);
52 } else if (["[object Window]", "[object ChromeWindow]"].includes(proto)) {
53 return prettyWindowGlobal(val);
54 } else if (proto == "[object Attr]") {
55 return prettyAttr(val);
57 return prettyObject(val);
60 function prettyElement(el) {
61 let attrs = ["id", "class", "href", "name", "src", "type"];
64 for (let attr of attrs) {
65 if (el.hasAttribute(attr)) {
66 idents += ` ${attr}="${el.getAttribute(attr)}"`;
70 return `<${el.localName}${idents}>`;
73 function prettyWindowGlobal(win) {
74 let proto = Object.prototype.toString.call(win);
75 return `[${proto.substring(1, proto.length - 1)} ${win.location}]`;
78 function prettyAttr(obj) {
79 return `[object Attr ${obj.name}="${obj.value}"]`;
82 function prettyObject(obj) {
83 let proto = Object.prototype.toString.call(obj);
86 s = JSON.stringify(obj);
88 if (e instanceof TypeError) {
94 return `${proto} ${s}`;
98 for (let i = 0; i < ss.length; i++) {
100 if (i < values.length) {
103 s = pretty(values[i]);
105 logger.warn("Problem pretty printing:", e);
106 s = typeof values[i];
115 * Template literal that truncates string values in arbitrary objects.
117 * Given any object, the template will walk the object and truncate
118 * any strings it comes across to a reasonable limit. This is suitable
119 * when you have arbitrary data and data integrity is not important.
121 * The strings are truncated in the middle so that the beginning and
122 * the end is preserved. This will make a long, truncated string look
123 * like "X <...> Y", where X and Y are half the number of characters
124 * of the maximum string length from either side of the string.
129 * truncate`Hello ${"x".repeat(260)}!`;
130 * // Hello xxx ... xxx!
132 * Functions named `toJSON` or `toString` on objects will be called.
134 function truncate(strings, ...values) {
135 const truncateLog = Services.prefs.getBoolPref(PREF_TRUNCATE, false);
137 const typ = Object.prototype.toString.call(obj);
140 case "[object Undefined]":
141 case "[object Null]":
142 case "[object Boolean]":
143 case "[object Number]":
146 case "[object String]":
147 if (truncateLog && obj.length > MAX_STRING_LENGTH) {
148 let s1 = obj.substring(0, MAX_STRING_LENGTH / 2);
149 let s2 = obj.substring(obj.length - MAX_STRING_LENGTH / 2);
150 return `${s1} ... ${s2}`;
154 case "[object Array]":
155 return obj.map(walk);
160 Object.getOwnPropertyNames(obj).includes("toString") &&
161 typeof obj.toString == "function"
163 return walk(obj.toString());
167 for (let prop in obj) {
168 rv[prop] = walk(obj[prop]);
175 for (let i = 0; i < strings.length; ++i) {
176 res.push(strings[i]);
177 if (i < values.length) {
178 let obj = walk(values[i]);
179 let t = Object.prototype.toString.call(obj);
180 if (t == "[object Array]" || t == "[object Object]") {
181 res.push(JSON.stringify(obj));