@node-red/util 4.0.9 → 4.1.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/i18n.js CHANGED
@@ -80,6 +80,21 @@ function mergeCatalog(fallback,catalog) {
80
80
  }
81
81
  }
82
82
 
83
+ function migrateMessageCatalogV3toV4(catalog) {
84
+ const keys = Object.keys(catalog)
85
+ keys.forEach(key => {
86
+ if (typeof catalog[key] === 'object') {
87
+ catalog[key] = migrateMessageCatalogV3toV4(catalog[key])
88
+ } else if (key.endsWith('_plural')) {
89
+ const otherKey = key.replace('_plural', '_other')
90
+ if (!catalog[otherKey]) {
91
+ catalog[otherKey] = catalog[key]
92
+ }
93
+ delete catalog[key]
94
+ }
95
+ })
96
+ return catalog
97
+ }
83
98
 
84
99
  async function readFile(lng, ns) {
85
100
  if (/[^a-z\-]/i.test(lng)) {
@@ -92,6 +107,12 @@ async function readFile(lng, ns) {
92
107
  const content = await fs.promises.readFile(file, "utf8");
93
108
  resourceCache[ns] = resourceCache[ns] || {};
94
109
  resourceCache[ns][lng] = JSON.parse(content.replace(/^\uFEFF/, ''));
110
+
111
+ // Message catalogues are in i18next v3 format. That is no longer supported
112
+ // by i18next so we need to migrate any catalog to the v4 format.
113
+ // This primarily means mapping `FOO_plural` to `FOO_other`
114
+ resourceCache[ns][lng] = migrateMessageCatalogV3toV4(resourceCache[ns][lng])
115
+
95
116
  var baseLng = lng.split('-')[0];
96
117
  if (baseLng !== lng && resourceCache[ns][baseLng]) {
97
118
  mergeCatalog(resourceCache[ns][baseLng], resourceCache[ns][lng]);
@@ -139,7 +160,6 @@ function init(settings) {
139
160
  initPromise = new Promise((resolve,reject) => {
140
161
  i18n.use(MessageFileLoader);
141
162
  var opt = {
142
- compatibilityJSON: 'v3',
143
163
  // debug: true,
144
164
  defaultNS: "runtime",
145
165
  ns: [],
package/lib/log.js CHANGED
@@ -23,6 +23,7 @@ var util = require("util");
23
23
  var EventEmitter = require("events").EventEmitter;
24
24
 
25
25
  var i18n = require("./i18n");
26
+ const chalk = require("chalk");
26
27
 
27
28
  var levels = {
28
29
  off: 1,
@@ -47,6 +48,17 @@ var levelNames = {
47
48
  99: "metric"
48
49
  };
49
50
 
51
+ var levelColours = {
52
+ 10: 'red',
53
+ 20: 'red',
54
+ 30: 'yellow',
55
+ 40: '',
56
+ 50: 'cyan',
57
+ 60: 'gray',
58
+ 98: '',
59
+ 99: ''
60
+ };
61
+
50
62
  var logHandlers = [];
51
63
 
52
64
  var verbose;
@@ -75,28 +87,32 @@ LogHandler.prototype.shouldReportMessage = function(msglevel) {
75
87
  msglevel <= this.logLevel;
76
88
  }
77
89
 
78
-
79
90
  // Older versions of Node-RED used the deprecated util.log function.
80
91
  // With Node.js 22, use of that function causes warnings. So here we
81
92
  // are replicating the same format output to ensure we don't break any
82
93
  // log parsing that happens in the real world.
83
94
  const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
84
- const utilLog = function (msg) {
95
+ const utilLog = function (msg, level) {
85
96
  const d = new Date();
86
97
  const time = [
87
98
  d.getHours().toString().padStart(2, '0'),
88
99
  d.getMinutes().toString().padStart(2, '0'),
89
100
  d.getSeconds().toString().padStart(2, '0')
90
101
  ].join(':');
91
- console.log(`${d.getDate()} ${months[d.getMonth()]} ${time} - ${msg}`)
102
+ const logLine = `${d.getDate()} ${months[d.getMonth()]} ${time} - ${msg}`
103
+ if (levelColours[level]) {
104
+ console.log(chalk[levelColours[level]](logLine))
105
+ } else {
106
+ console.log(logLine)
107
+ }
92
108
  }
93
109
 
94
110
  var consoleLogger = function(msg) {
95
111
  if (msg.level == log.METRIC || msg.level == log.AUDIT) {
96
- utilLog("["+levelNames[msg.level]+"] "+JSON.stringify(msg));
112
+ utilLog("["+levelNames[msg.level]+"] "+JSON.stringify(msg), msg.level);
97
113
  } else {
98
114
  if (verbose && msg.msg && msg.msg.stack) {
99
- utilLog("["+levelNames[msg.level]+"] "+(msg.type?"["+msg.type+":"+(msg.name||msg.id)+"] ":"")+msg.msg.stack);
115
+ utilLog("["+levelNames[msg.level]+"] "+(msg.type?"["+msg.type+":"+(msg.name||msg.id)+"] ":"")+msg.msg.stack, msg.level);
100
116
  } else {
101
117
  var message = msg.msg;
102
118
  try {
@@ -107,7 +123,7 @@ var consoleLogger = function(msg) {
107
123
  message = 'Exception trying to log: '+util.inspect(message);
108
124
  }
109
125
 
110
- utilLog("["+levelNames[msg.level]+"] "+(msg.type?"["+msg.type+":"+(msg.name||msg.id)+"] ":"")+message);
126
+ utilLog("["+levelNames[msg.level]+"] "+(msg.type?"["+msg.type+":"+(msg.name||msg.id)+"] ":"")+message, msg.level);
111
127
  }
112
128
  }
113
129
  }
package/lib/util.js CHANGED
@@ -828,18 +828,31 @@ function encodeObject(msg,opts) {
828
828
  debuglength = opts.maxLength;
829
829
  }
830
830
  var msgType = typeof msg.msg;
831
- if (msg.msg instanceof Error) {
831
+ if (msg.msg instanceof Error || /Error/.test(msg.msg?.__proto__?.name)) {
832
832
  msg.format = "error";
833
- var errorMsg = {};
834
- if (msg.msg.name) {
835
- errorMsg.name = msg.msg.name;
833
+
834
+ const cause = msg.msg.cause
835
+ const value = {
836
+ __enc__: true,
837
+ type: 'error',
838
+ data: {
839
+ name: msg.msg.name,
840
+ message: hasOwnProperty.call(msg.msg, 'message') ? msg.msg.message : msg.msg.toString(),
841
+ code: msg.msg.code,
842
+ cause: cause + "",
843
+ stack: msg.msg.stack,
844
+ }
836
845
  }
837
- if (hasOwnProperty.call(msg.msg, 'message')) {
838
- errorMsg.message = msg.msg.message;
839
- } else {
840
- errorMsg.message = msg.msg.toString();
846
+ // We optimistically added these properties to the object
847
+ // to ensure they are shown above 'stack'. But we don't want
848
+ // to include them if they are undefined
849
+ if (cause === undefined) {
850
+ delete value.data.cause
841
851
  }
842
- msg.msg = JSON.stringify(errorMsg);
852
+ if (msg.msg.code === undefined) {
853
+ delete value.data.code
854
+ }
855
+ msg.msg = JSON.stringify(value);
843
856
  } else if (msg.msg instanceof Buffer) {
844
857
  msg.format = "buffer["+msg.msg.length+"]";
845
858
  msg.msg = msg.msg.toString('hex');
@@ -857,6 +870,7 @@ function encodeObject(msg,opts) {
857
870
  msg.format = "Object";
858
871
  }
859
872
  if (/error/i.test(msg.format)) {
873
+ // TODO: check if this is needed
860
874
  msg.msg = JSON.stringify({
861
875
  name: msg.msg.name,
862
876
  message: msg.msg.message
@@ -904,8 +918,29 @@ function encodeObject(msg,opts) {
904
918
  __enc__: true,
905
919
  type: "internal"
906
920
  }
907
- } else if (value instanceof Error) {
908
- value = value.toString()
921
+ } else if (value instanceof Error || /Error/.test(value?.__proto__?.name)) {
922
+ const cause = value.cause
923
+ const code = value.code
924
+ value = {
925
+ __enc__: true,
926
+ type: 'error',
927
+ data: {
928
+ name: value.name,
929
+ message: hasOwnProperty.call(value, 'message') ? value.message : value.toString(),
930
+ code,
931
+ cause: cause + "",
932
+ stack: value.stack,
933
+ }
934
+ }
935
+ // We optimistically added these properties to the object
936
+ // to ensure they are shown above 'stack'. But we don't want
937
+ // to include them if they are undefined
938
+ if (cause === undefined) {
939
+ delete value.data.cause
940
+ }
941
+ if (code === undefined) {
942
+ delete value.data.code
943
+ }
909
944
  } else if (Array.isArray(value) && value.length > debuglength) {
910
945
  value = {
911
946
  __enc__: true,
@@ -977,8 +1012,19 @@ function encodeObject(msg,opts) {
977
1012
  return value;
978
1013
  });
979
1014
  } else {
980
- try { msg.msg = msg.msg.toString(); }
981
- catch(e) { msg.msg = "[Type not printable]" + util.inspect(msg.msg); }
1015
+ try {
1016
+ msg.msg = msg.msg.toString();
1017
+ } catch(e) {
1018
+ msg.msg.format = 'error'
1019
+ msg.msg = JSON.stringify({
1020
+ __enc__: true,
1021
+ type: 'error',
1022
+ data: {
1023
+ message: "[Type not serializable]",
1024
+ stack: e.stack
1025
+ }
1026
+ })
1027
+ }
982
1028
  }
983
1029
  }
984
1030
  } else if (msgType === "function") {
@@ -1009,17 +1055,14 @@ function encodeObject(msg,opts) {
1009
1055
  return msg;
1010
1056
  } catch(e) {
1011
1057
  msg.format = "error";
1012
- var errorMsg = {};
1013
- if (e.name) {
1014
- errorMsg.name = e.name;
1015
- }
1016
- if (hasOwnProperty.call(e, 'message')) {
1017
- errorMsg.message = 'encodeObject Error: ['+e.message + '] Value: '+util.inspect(msg.msg);
1018
- } else {
1019
- errorMsg.message = 'encodeObject Error: ['+e.toString() + '] Value: '+util.inspect(msg.msg);
1020
- }
1021
- if (errorMsg.message.length > debuglength) {
1022
- errorMsg.message = errorMsg.message.substring(0,debuglength);
1058
+ const errorMsg = {
1059
+ __enc__: true,
1060
+ type: 'error',
1061
+ data: {
1062
+ name: e.name,
1063
+ message: 'encodeObject Error: ' + (hasOwnProperty.call(e, 'message') ? e.message : e.toString()),
1064
+ stack: e.stack,
1065
+ }
1023
1066
  }
1024
1067
  msg.msg = JSON.stringify(errorMsg);
1025
1068
  return msg;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@node-red/util",
3
- "version": "4.0.9",
3
+ "version": "4.1.0-beta.1",
4
4
  "license": "Apache-2.0",
5
5
  "repository": {
6
6
  "type": "git",
@@ -15,12 +15,13 @@
15
15
  }
16
16
  ],
17
17
  "dependencies": {
18
- "fs-extra": "11.2.0",
19
- "i18next": "21.10.0",
18
+ "chalk": "^4.1.2",
19
+ "fs-extra": "11.3.0",
20
+ "i18next": "24.2.3",
20
21
  "json-stringify-safe": "5.0.1",
21
- "jsonata": "2.0.5",
22
+ "jsonata": "2.0.6",
22
23
  "lodash.clonedeep": "^4.5.0",
23
24
  "moment": "2.30.1",
24
- "moment-timezone": "0.5.46"
25
+ "moment-timezone": "0.5.48"
25
26
  }
26
27
  }