diff --git a/editor/js/ui/utils.js b/editor/js/ui/utils.js index 6d5884cdd..4f84da8ba 100644 --- a/editor/js/ui/utils.js +++ b/editor/js/ui/utils.js @@ -34,6 +34,8 @@ RED.utils = (function() { result = $('').text('buffer['+value.length+']'); } else if (value.hasOwnProperty('type') && value.type === 'array' && value.hasOwnProperty('data')) { result = $('').text('array['+value.length+']'); + } else if (value.hasOwnProperty('type') && value.type === 'function') { + result = $('').text('function'); } else { result = $('object'); } @@ -125,7 +127,7 @@ RED.utils = (function() { e.stopPropagation(); RED.clipboard.copyText(msg,copyPayload,"clipboard.copyMessageValue"); }) - if (strippedKey !== '') { + if (strippedKey !== undefined && strippedKey !== '') { var isPinned = pinnedPaths[sourceId].hasOwnProperty(strippedKey); var pinPath = $('').appendTo(tools).click(function(e) { @@ -296,9 +298,12 @@ RED.utils = (function() { isArray = true; isArrayObject = true; } - if (obj === null || obj === undefined) { $(''+obj+'').appendTo(entryObj); + } else if (typeHint === "function" || (obj.__encoded__ && obj.type === 'function')) { + e = $('').text("function").appendTo(entryObj); + } else if (typeHint === "internal" || (obj.__encoded__ && obj.type === 'internal')) { + e = $('').text("[internal]").appendTo(entryObj); } else if (typeof obj === 'string') { if (/[\t\n\r]/.test(obj)) { element.addClass('collapsed'); @@ -791,6 +796,29 @@ RED.utils = (function() { return spinner; } + function decodeObject(payload,format) { + if ((format === 'number') && (payload === "NaN")) { + payload = Number.NaN; + } else if (format === 'Object' || /^array/.test(format) || format === 'boolean' || format === 'number' ) { + payload = JSON.parse(payload); + } else if (/error/i.test(format)) { + payload = JSON.parse(payload); + payload = (payload.name?payload.name+": ":"")+payload.message; + } else if (format === 'null') { + payload = null; + } else if (format === 'undefined') { + payload = undefined; + } else if (/^buffer/.test(format)) { + var buffer = payload; + payload = []; + for (var c = 0; c < buffer.length; c += 2) { + payload.push(parseInt(buffer.substr(c, 2), 16)); + } + } + return payload; + } + + return { createObjectElement: buildMessageElement, getMessageProperty: getMessageProperty, @@ -800,6 +828,7 @@ RED.utils = (function() { getDefaultNodeIcon: getDefaultNodeIcon, getNodeIcon: getNodeIcon, getNodeLabel: getNodeLabel, - addSpinnerOverlay: addSpinnerOverlay + addSpinnerOverlay: addSpinnerOverlay, + decodeObject: decodeObject } })(); diff --git a/editor/sass/debug.scss b/editor/sass/debug.scss index aded6d718..a3acd18ff 100644 --- a/editor/sass/debug.scss +++ b/editor/sass/debug.scss @@ -64,22 +64,22 @@ display: inline-block; } } - .debug-message-row { - .debug-message-tools-pin { - display: none; - } - &.debug-message-row-pinned .debug-message-tools-pin { - display: inline-block; - } - &:hover { - background: #f3f3f3; - &>.debug-message-tools { - .debug-message-tools-copy { - display: inline-block; - } - .debug-message-tools-pin { - display: inline-block; - } +} +.debug-message-row { + .debug-message-tools-pin { + display: none; + } + &.debug-message-row-pinned .debug-message-tools-pin { + display: inline-block; + } + &:hover { + background: #f3f3f3; + &>.debug-message-tools { + .debug-message-tools-copy { + display: inline-block; + } + .debug-message-tools-pin { + display: inline-block; } } } diff --git a/nodes/core/core/58-debug.js b/nodes/core/core/58-debug.js index 3e4290554..fe84d487d 100644 --- a/nodes/core/core/58-debug.js +++ b/nodes/core/core/58-debug.js @@ -4,7 +4,6 @@ module.exports = function(RED) { var util = require("util"); var events = require("events"); var path = require("path"); - var safeJSONStringify = require("json-stringify-safe"); var debuglength = RED.settings.debugMaxLength || 1000; var useColors = RED.settings.debugUseColors || false; util.inspect.styles.boolean = "red"; @@ -104,111 +103,7 @@ module.exports = function(RED) { function sendDebug(msg) { // don't put blank errors in sidebar (but do add to logs) //if ((msg.msg === "") && (msg.hasOwnProperty("level")) && (msg.level === 20)) { return; } - if (msg.msg instanceof Error) { - msg.format = "error"; - var errorMsg = {}; - if (msg.msg.name) { - errorMsg.name = msg.msg.name; - } - if (msg.msg.hasOwnProperty('message')) { - errorMsg.message = msg.msg.message; - } else { - errorMsg.message = msg.msg.toString(); - } - msg.msg = JSON.stringify(errorMsg); - } else if (msg.msg instanceof Buffer) { - msg.format = "buffer["+msg.msg.length+"]"; - msg.msg = msg.msg.toString('hex'); - if (msg.msg.length > debuglength) { - msg.msg = msg.msg.substring(0,debuglength); - } - } else if (msg.msg && typeof msg.msg === 'object') { - try { - msg.format = msg.msg.constructor.name || "Object"; - // Handle special case of msg.req/res objects from HTTP In node - if (msg.format === "IncomingMessage" || msg.format === "ServerResponse") { - msg.format = "Object"; - } - } catch(err) { - msg.format = "Object"; - } - if (/error/i.test(msg.format)) { - msg.msg = JSON.stringify({ - name: msg.msg.name, - message: msg.msg.message - }); - } else { - var isArray = util.isArray(msg.msg); - if (isArray) { - msg.format = "array["+msg.msg.length+"]"; - if (msg.msg.length > debuglength) { - // msg.msg = msg.msg.slice(0,debuglength); - msg.msg = { - __encoded__: true, - type: "array", - data: msg.msg.slice(0,debuglength), - length: msg.msg.length - } - } - } - if (isArray || (msg.format === "Object")) { - msg.msg = safeJSONStringify(msg.msg, function(key, value) { - if (key === '_req' || key === '_res') { - value = "[internal]" - } else if (value instanceof Error) { - value = value.toString() - } else if (util.isArray(value) && value.length > debuglength) { - value = { - __encoded__: true, - type: "array", - data: value.slice(0,debuglength), - length: value.length - } - } else if (typeof value === 'string') { - if (value.length > debuglength) { - value = value.substring(0,debuglength)+"..."; - } - } else if (value && value.constructor) { - if (value.type === "Buffer") { - value.__encoded__ = true; - value.length = value.data.length; - if (value.length > debuglength) { - value.data = value.data.slice(0,debuglength); - } - } else if (value.constructor.name === "ServerResponse") { - value = "[internal]" - } else if (value.constructor.name === "Socket") { - value = "[internal]" - } - } - return value; - }," "); - } else { - try { msg.msg = msg.msg.toString(); } - catch(e) { msg.msg = "[Type not printable]"; } - } - } - } else if (typeof msg.msg === "boolean") { - msg.format = "boolean"; - msg.msg = msg.msg.toString(); - } else if (typeof msg.msg === "number") { - msg.format = "number"; - msg.msg = msg.msg.toString(); - } else if (msg.msg === 0) { - msg.format = "number"; - msg.msg = "0"; - } else if (msg.msg === null || typeof msg.msg === "undefined") { - msg.format = (msg.msg === null)?"null":"undefined"; - msg.msg = "(undefined)"; - } else { - msg.format = "string["+msg.msg.length+"]"; - if (msg.msg.length > debuglength) { - msg.msg = msg.msg.substring(0,debuglength)+"..."; - } - } - // if (msg.msg.length > debuglength) { - // msg.msg = msg.msg.substr(0,debuglength) +" ...."; - // } + msg = RED.util.encodeObject(msg,{maxLength:debuglength}); RED.comms.publish("debug",msg); } diff --git a/nodes/core/core/lib/debug/debug-utils.js b/nodes/core/core/lib/debug/debug-utils.js index 17b850327..2d47155ba 100644 --- a/nodes/core/core/lib/debug/debug-utils.js +++ b/nodes/core/core/lib/debug/debug-utils.js @@ -455,24 +455,8 @@ RED.debug = (function() { $(''+name+'').appendTo(metaRow); } - if ((format === 'number') && (payload === "NaN")) { - payload = Number.NaN; - } else if (format === 'Object' || /^array/.test(format) || format === 'boolean' || format === 'number' ) { - payload = JSON.parse(payload); - } else if (/error/i.test(format)) { - payload = JSON.parse(payload); - payload = (payload.name?payload.name+": ":"")+payload.message; - } else if (format === 'null') { - payload = null; - } else if (format === 'undefined') { - payload = undefined; - } else if (/^buffer/.test(format)) { - var buffer = payload; - payload = []; - for (var c = 0; c < buffer.length; c += 2) { - payload.push(parseInt(buffer.substr(c, 2), 16)); - } - } + payload = RED.utils.decodeObject(payload,format); + var el = $('').appendTo(msg); var path = o.property||''; var debugMessage = RED.utils.createObjectElement(payload, { diff --git a/red/runtime/util.js b/red/runtime/util.js index 257e87777..022faa65d 100644 --- a/red/runtime/util.js +++ b/red/runtime/util.js @@ -16,6 +16,8 @@ var clone = require("clone"); var jsonata = require("jsonata"); +var safeJSONStringify = require("json-stringify-safe"); +var util = require("util"); function generateId() { return (1+Math.random()*4294967295).toString(16); @@ -389,7 +391,130 @@ function normaliseNodeTypeName(name) { return result; } +function encodeObject(msg,opts) { + var debuglength = 1000; + if (opts && opts.hasOwnProperty('maxLength')) { + debuglength = opts.maxLength; + } + var msgType = typeof msg.msg; + if (msg.msg instanceof Error) { + msg.format = "error"; + var errorMsg = {}; + if (msg.msg.name) { + errorMsg.name = msg.msg.name; + } + if (msg.msg.hasOwnProperty('message')) { + errorMsg.message = msg.msg.message; + } else { + errorMsg.message = msg.msg.toString(); + } + msg.msg = JSON.stringify(errorMsg); + } else if (msg.msg instanceof Buffer) { + msg.format = "buffer["+msg.msg.length+"]"; + msg.msg = msg.msg.toString('hex'); + if (msg.msg.length > debuglength) { + msg.msg = msg.msg.substring(0,debuglength); + } + } else if (msg.msg && msgType === 'object') { + try { + msg.format = msg.msg.constructor.name || "Object"; + // Handle special case of msg.req/res objects from HTTP In node + if (msg.format === "IncomingMessage" || msg.format === "ServerResponse") { + msg.format = "Object"; + } + } catch(err) { + msg.format = "Object"; + } + if (/error/i.test(msg.format)) { + msg.msg = JSON.stringify({ + name: msg.msg.name, + message: msg.msg.message + }); + } else { + var isArray = util.isArray(msg.msg); + if (isArray) { + msg.format = "array["+msg.msg.length+"]"; + if (msg.msg.length > debuglength) { + // msg.msg = msg.msg.slice(0,debuglength); + msg.msg = { + __encoded__: true, + type: "array", + data: msg.msg.slice(0,debuglength), + length: msg.msg.length + } + } + } + if (isArray || (msg.format === "Object")) { + msg.msg = safeJSONStringify(msg.msg, function(key, value) { + if (key === '_req' || key === '_res') { + value = { + __encoded__: true, + type: "internal" + } + } else if (value instanceof Error) { + value = value.toString() + } else if (util.isArray(value) && value.length > debuglength) { + value = { + __encoded__: true, + type: "array", + data: value.slice(0,debuglength), + length: value.length + } + } else if (typeof value === 'string') { + if (value.length > debuglength) { + value = value.substring(0,debuglength)+"..."; + } + } else if (typeof value === 'function') { + value = { + __encoded__: true, + type: "function" + } + } else if (value && value.constructor) { + if (value.type === "Buffer") { + value.__encoded__ = true; + value.length = value.data.length; + if (value.length > debuglength) { + value.data = value.data.slice(0,debuglength); + } + } else if (value.constructor.name === "ServerResponse") { + value = "[internal]" + } else if (value.constructor.name === "Socket") { + value = "[internal]" + } + } + return value; + }," "); + } else { + try { msg.msg = msg.msg.toString(); } + catch(e) { msg.msg = "[Type not printable]"; } + } + } + } else if (msgType === "function") { + msg.format = "function"; + msg.msg = "[function]" + } else if (msgType === "boolean") { + msg.format = "boolean"; + msg.msg = msg.msg.toString(); + } else if (msgType === "number") { + msg.format = "number"; + msg.msg = msg.msg.toString(); + } else if (msg.msg === 0) { + msg.format = "number"; + msg.msg = "0"; + } else if (msg.msg === null || msgType === "undefined") { + msg.format = (msg.msg === null)?"null":"undefined"; + msg.msg = "(undefined)"; + } else { + msg.format = "string["+msg.msg.length+"]"; + if (msg.msg.length > debuglength) { + msg.msg = msg.msg.substring(0,debuglength)+"..."; + } + } + return msg; +} + module.exports = { + encodeObject: encodeObject, ensureString: ensureString, ensureBuffer: ensureBuffer, cloneMessage: cloneMessage,