summaryrefslogtreecommitdiffstats
path: root/devtools/server/actors/object/stringifiers.js
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /devtools/server/actors/object/stringifiers.js
parentInitial commit. (diff)
downloadfirefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz
firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'devtools/server/actors/object/stringifiers.js')
-rw-r--r--devtools/server/actors/object/stringifiers.js198
1 files changed, 198 insertions, 0 deletions
diff --git a/devtools/server/actors/object/stringifiers.js b/devtools/server/actors/object/stringifiers.js
new file mode 100644
index 0000000000..2b0fab0fe6
--- /dev/null
+++ b/devtools/server/actors/object/stringifiers.js
@@ -0,0 +1,198 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const DevToolsUtils = require("devtools/shared/DevToolsUtils");
+
+loader.lazyRequireGetter(
+ this,
+ "ObjectUtils",
+ "devtools/server/actors/object/utils"
+);
+
+/**
+ * Stringify a Debugger.Object based on its class.
+ *
+ * @param Debugger.Object obj
+ * The object to stringify.
+ * @return String
+ * The stringification for the object.
+ */
+function stringify(obj) {
+ if (!DevToolsUtils.isSafeDebuggerObject(obj)) {
+ const unwrapped = DevToolsUtils.unwrap(obj);
+ if (unwrapped === undefined) {
+ return "<invisibleToDebugger>";
+ } else if (unwrapped.isProxy) {
+ return "<proxy>";
+ }
+ // The following line should not be reached. It's there just in case somebody
+ // modifies isSafeDebuggerObject to return false for additional kinds of objects.
+ return "[object " + obj.class + "]";
+ } else if (obj.class == "DeadObject") {
+ return "<dead object>";
+ }
+
+ const stringifier = stringifiers[obj.class] || stringifiers.Object;
+
+ try {
+ return stringifier(obj);
+ } catch (e) {
+ DevToolsUtils.reportException("stringify", e);
+ return "<failed to stringify object>";
+ }
+}
+
+/**
+ * Create a function that can safely stringify Debugger.Objects of a given
+ * builtin type.
+ *
+ * @param Function ctor
+ * The builtin class constructor.
+ * @return Function
+ * The stringifier for the class.
+ */
+function createBuiltinStringifier(ctor) {
+ return obj => {
+ try {
+ return ctor.prototype.toString.call(obj.unsafeDereference());
+ } catch (err) {
+ // The debuggee will see a "Function" class if the object is callable and
+ // its compartment is not subsumed. The above will throw if it's not really
+ // a function, e.g. if it's a callable proxy.
+ return "[object " + obj.class + "]";
+ }
+ };
+}
+
+/**
+ * Stringify a Debugger.Object-wrapped Error instance.
+ *
+ * @param Debugger.Object obj
+ * The object to stringify.
+ * @return String
+ * The stringification of the object.
+ */
+function errorStringify(obj) {
+ let name = DevToolsUtils.getProperty(obj, "name");
+ if (name === "" || name === undefined) {
+ name = obj.class;
+ } else if (isObject(name)) {
+ name = stringify(name);
+ }
+
+ let message = DevToolsUtils.getProperty(obj, "message");
+ if (isObject(message)) {
+ message = stringify(message);
+ }
+
+ if (message === "" || message === undefined) {
+ return name;
+ }
+ return name + ": " + message;
+}
+
+// Used to prevent infinite recursion when an array is found inside itself.
+var seen = null;
+
+var stringifiers = {
+ Error: errorStringify,
+ EvalError: errorStringify,
+ RangeError: errorStringify,
+ ReferenceError: errorStringify,
+ SyntaxError: errorStringify,
+ TypeError: errorStringify,
+ URIError: errorStringify,
+ Boolean: createBuiltinStringifier(Boolean),
+ Function: createBuiltinStringifier(Function),
+ Number: createBuiltinStringifier(Number),
+ RegExp: createBuiltinStringifier(RegExp),
+ String: createBuiltinStringifier(String),
+ Object: obj => "[object " + obj.class + "]",
+ Array: obj => {
+ // If we're at the top level then we need to create the Set for tracking
+ // previously stringified arrays.
+ const topLevel = !seen;
+ if (topLevel) {
+ seen = new Set();
+ } else if (seen.has(obj)) {
+ return "";
+ }
+
+ seen.add(obj);
+
+ const len = ObjectUtils.getArrayLength(obj);
+ let string = "";
+
+ // Array.length is always a non-negative safe integer.
+ for (let i = 0; i < len; i++) {
+ const desc = obj.getOwnPropertyDescriptor(i);
+ if (desc) {
+ const { value } = desc;
+ if (value != null) {
+ string += isObject(value) ? stringify(value) : value;
+ }
+ }
+
+ if (i < len - 1) {
+ string += ",";
+ }
+ }
+
+ if (topLevel) {
+ seen = null;
+ }
+
+ return string;
+ },
+ DOMException: obj => {
+ const message = DevToolsUtils.getProperty(obj, "message") || "<no message>";
+ const result = (+DevToolsUtils.getProperty(obj, "result")).toString(16);
+ const code = DevToolsUtils.getProperty(obj, "code");
+ const name = DevToolsUtils.getProperty(obj, "name") || "<unknown>";
+
+ return (
+ '[Exception... "' +
+ message +
+ '" ' +
+ 'code: "' +
+ code +
+ '" ' +
+ 'nsresult: "0x' +
+ result +
+ " (" +
+ name +
+ ')"]'
+ );
+ },
+ Promise: obj => {
+ const { state, value, reason } = ObjectUtils.getPromiseState(obj);
+ let statePreview = state;
+ if (state != "pending") {
+ const settledValue = state === "fulfilled" ? value : reason;
+ statePreview +=
+ ": " +
+ (typeof settledValue === "object" && settledValue !== null
+ ? stringify(settledValue)
+ : settledValue);
+ }
+ return "Promise (" + statePreview + ")";
+ },
+};
+
+/**
+ * Determine if a given value is non-primitive.
+ *
+ * @param Any value
+ * The value to test.
+ * @return Boolean
+ * Whether the value is non-primitive.
+ */
+function isObject(value) {
+ const type = typeof value;
+ return type == "object" ? value !== null : type == "function";
+}
+
+module.exports = stringify;