Merge pull request #5290 from node-red/5283-fix-ui-lockup-for-typed-arrays

Fix UI lock-up when typed arrays are expanded in debug window
This commit is contained in:
Nick O'Leary
2025-10-09 11:24:43 +01:00
committed by GitHub
4 changed files with 201 additions and 7 deletions

View File

@@ -15,6 +15,7 @@
**/
RED.utils = (function() {
const listOfTypedArrays = ['Int8Array','Uint8Array','Uint8ClampedArray','Int16Array','Uint16Array','Int32Array','Uint32Array','Float32Array','Float64Array','BigInt64Array','BigUint64Array'];
window._marked = window.marked;
window.marked = function(txt) {
@@ -170,6 +171,8 @@ RED.utils = (function() {
result = $('<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-number"></span>').text(value.data);
} else if (value.hasOwnProperty('type') && value.type === 'regexp') {
result = $('<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-string"></span>').text(value.data);
} else if (value.hasOwnProperty('type') && value.hasOwnProperty('data') && listOfTypedArrays.includes(value.type)) {
result = $('<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-meta"></span>').text(value.type + '['+value.length+']');
} else {
result = $('<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-meta">object</span>');
}
@@ -475,7 +478,7 @@ RED.utils = (function() {
var isArray = Array.isArray(obj);
var isArrayObject = false;
if (obj && typeof obj === 'object' && obj.hasOwnProperty('type') && obj.hasOwnProperty('data') && ((obj.__enc__ && obj.type === 'set') || (obj.__enc__ && obj.type === 'array') || obj.type === 'Buffer')) {
if (obj && typeof obj === 'object' && obj.hasOwnProperty('type') && obj.hasOwnProperty('data') && ((obj.__enc__ && obj.type === 'set') || (obj.__enc__ && obj.type === 'array') || (obj.__enc__ && listOfTypedArrays.includes(obj.type)) || obj.type === 'Buffer')) {
isArray = true;
isArrayObject = true;
}
@@ -1299,7 +1302,7 @@ RED.utils = (function() {
payload = Infinity;
} else if ((format === 'number') && (payload === "-Infinity")) {
payload = -Infinity;
} else if (format === 'Object' || /^(array|set|map)/.test(format) || format === 'boolean' || format === 'number' ) {
} else if (format === 'Object' || /^(array|set|map)/.test(format) || format === 'boolean' || format === 'number' || listOfTypedArrays.includes(format)) {
payload = JSON.parse(payload);
} else if (/error/i.test(format)) {
payload = JSON.parse(payload);

View File

@@ -437,6 +437,11 @@ RED.debug = (function() {
var property = sanitize(o.property?o.property:'');
var payload = o.msg;
var format = sanitize((o.format||"").toString());
var baseFormat = format
// If format is "array[12]"/"Float32Array[12]" then strip off the size portion [12] for the decodeObject
if (/\w+\[\d+\]$/.test(baseFormat)) {
baseFormat = format.replace(/\[\d+\]$/,'');
}
msg.attr("class", 'red-ui-debug-msg'+(o.level?(' red-ui-debug-msg-level-'+o.level):'')+
(sourceNode?(
" red-ui-debug-msg-node-"+sourceNode.id.replace(/\./g,"_")+
@@ -502,7 +507,7 @@ RED.debug = (function() {
$('<span class="red-ui-debug-msg-name">'+name+'</span>').appendTo(metaRow);
}
payload = RED.utils.decodeObject(payload,format);
payload = RED.utils.decodeObject(payload, baseFormat);
var el = $('<span class="red-ui-debug-msg-payload"></span>').appendTo(msg);
var path = o.property||'';

View File

@@ -877,14 +877,16 @@ function encodeObject(msg,opts) {
});
} else {
var isArray = Array.isArray(msg.msg);
var needsStringify = isArray;
if (isArray) {
msg.format = "array["+msg.msg.length+"]";
const isTypedArray = ArrayBuffer.isView(msg.msg);
var needsStringify = isArray || isTypedArray;
var typeName = isArray ? 'array' : constructorName(msg.msg);
if (isArray || isTypedArray) {
msg.format = typeName + "["+msg.msg.length+"]";
if (msg.msg.length > debuglength) {
// msg.msg = msg.msg.slice(0,debuglength);
msg.msg = {
__enc__: true,
type: "array",
type: typeName,
data: msg.msg.slice(0,debuglength),
length: msg.msg.length
}
@@ -948,6 +950,16 @@ function encodeObject(msg,opts) {
data: value.slice(0,debuglength),
length: value.length
}
} else if (ArrayBuffer.isView(value) && value.length > debuglength && !Buffer.isBuffer(value)) { // include typed arrays, exclude Buffer
// Note: Buffer is a subclass of Uint8Array
const typeName = constructorName(value);
/** @type {ArrayBufferView} */
value = {
__enc__: true,
type: typeName,
data: Array.from(value).slice(0,debuglength),
length: value.length
}
} else if (typeof value === 'string') {
if (value.length > debuglength) {
value = value.substring(0,debuglength)+"...";
@@ -978,6 +990,13 @@ function encodeObject(msg,opts) {
if (value.length > debuglength) {
value.data = value.data.slice(0,debuglength);
}
} else if (ArrayBuffer.isView(value)) {
value = {
__enc__: true,
type: "array",
data: Array.from(value),
length: value.length
}
} else if (constructorName(value) === "ServerResponse") {
value = "[internal]"
} else if (constructorName(value) === "Socket") {