node-red-contrib-prib-functions 0.22.0 → 0.23.2
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/README.md +87 -35
- package/lib/common.js +128 -0
- package/lib/objectExtensions.js +190 -80
- package/lib/typedInput.js +77 -0
- package/matrix/matrixNode.html +2 -1
- package/package.json +12 -11
- package/test/00-objectExtensions.js +192 -1
- package/test/data/.config.nodes.json +3 -3
- package/test/data/.config.nodes.json.backup +3 -3
- package/test/data/.config.users.json +3 -2
- package/test/data/.config.users.json.backup +3 -2
- package/test/data/.flow.json.backup +3208 -425
- package/test/data/flow.json +3187 -402
- package/test/data/package-lock.json +4 -4
- package/testing/test.js +59 -26
- package/transform/transform.html +163 -19
- package/transform/transform.js +106 -55
- package/visual/shapes/base..js +1 -0
- package/visual/visual.js +0 -0
- package/visual/visualNode.js +45 -0
package/README.md
CHANGED
|
@@ -111,53 +111,104 @@ Messages generates a message for each row or record.
|
|
|
111
111
|
|
|
112
112
|
Transformations:
|
|
113
113
|
|
|
114
|
-
* Array to
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
114
|
+
* Array to
|
|
115
|
+
* CSV
|
|
116
|
+
* HTML
|
|
117
|
+
* ISO8385
|
|
118
|
+
* Messages
|
|
119
|
+
* xlsx / xlsx object (excel uses [xlsx][7])
|
|
119
120
|
* AVRO to JSON (uses [avsc][6])
|
|
120
|
-
* Buffer to
|
|
121
|
+
* Buffer to compressed
|
|
121
122
|
* Confluence to JSON
|
|
122
|
-
* Compressed to
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
* CSV to
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
* CSVWithHeader to
|
|
123
|
+
* Compressed to
|
|
124
|
+
* Buffer
|
|
125
|
+
* String
|
|
126
|
+
* JSON
|
|
127
|
+
* CSV to
|
|
128
|
+
* Array
|
|
129
|
+
* HTML
|
|
130
|
+
* Messages
|
|
131
|
+
* CSVWithHeader to
|
|
132
|
+
* Array
|
|
133
|
+
* HTML
|
|
134
|
+
* JSON
|
|
135
|
+
* Date to
|
|
136
|
+
* is between
|
|
137
|
+
* ISO string
|
|
138
|
+
* locale string
|
|
139
|
+
* range limit
|
|
131
140
|
* ISO8385 to Array
|
|
132
141
|
* ISO8385 to JSON
|
|
133
|
-
* JSON to
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
* path
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
142
|
+
* JSON to
|
|
143
|
+
* Array
|
|
144
|
+
* Confluence
|
|
145
|
+
* CSV
|
|
146
|
+
* AVRO (uses [avsc][6])
|
|
147
|
+
* ISO8385
|
|
148
|
+
* Messages
|
|
149
|
+
* String
|
|
150
|
+
* xlsx / xlsx object (excel uses [xlsx][7])
|
|
151
|
+
* XML (uses [fast-xml-parser][4])
|
|
152
|
+
* Number
|
|
153
|
+
* is between
|
|
154
|
+
* range limit
|
|
155
|
+
* path
|
|
156
|
+
* Basename
|
|
157
|
+
* Dirname
|
|
158
|
+
* Extname
|
|
159
|
+
* Format
|
|
160
|
+
* Is Absolute
|
|
161
|
+
* Join
|
|
162
|
+
* Parse
|
|
163
|
+
* Normalize
|
|
164
|
+
* Resolve
|
|
152
165
|
* snappy compress (uses [snappy][5], must install separately)
|
|
153
166
|
* snappy uncompress (uses [snappy][5], must install separately)
|
|
167
|
+
* String to
|
|
168
|
+
* Append
|
|
169
|
+
* Array By Delimiter
|
|
170
|
+
* At
|
|
171
|
+
* Camelize
|
|
172
|
+
* Capitalize
|
|
173
|
+
* Compressed
|
|
174
|
+
* Char At
|
|
175
|
+
* Char Code At"
|
|
176
|
+
* Code Point At
|
|
177
|
+
* Concat
|
|
178
|
+
* Date
|
|
179
|
+
* Delimiter On Case
|
|
180
|
+
* _ to space
|
|
181
|
+
* _ to space Capitilize
|
|
182
|
+
* Drop square bracket prefix
|
|
183
|
+
* Ends With
|
|
184
|
+
* Float
|
|
185
|
+
* Get Word
|
|
186
|
+
* Integer
|
|
187
|
+
* is Between
|
|
188
|
+
* Lower Case
|
|
189
|
+
* Number
|
|
190
|
+
* Prepend
|
|
191
|
+
* JSON
|
|
192
|
+
* Range Limit
|
|
193
|
+
* Split
|
|
194
|
+
* Starts With
|
|
195
|
+
* Timestamp
|
|
196
|
+
* Title
|
|
197
|
+
* Title Grammatical
|
|
198
|
+
* Trim
|
|
199
|
+
* Trim End
|
|
200
|
+
* Trim Start
|
|
201
|
+
* Upper Case
|
|
202
|
+
* Xml String Encode
|
|
203
|
+
|
|
204
|
+
|
|
154
205
|
* xlsx / xlsx object to array/JSON (excel uses [xlsx][7])
|
|
155
206
|
* XML to JSON (uses [fast-xml-parser][4])
|
|
156
207
|
|
|
157
208
|
Note, snappy needs to be installed separately as can have issues with auto install as build binaries.
|
|
158
209
|
|
|
159
210
|
With xlsx object one can use the function in [xlsx][7] against the object in functions node.
|
|
160
|
-
|
|
211
|
+
"
|
|
161
212
|
Example AVRO with schema
|
|
162
213
|
|
|
163
214
|

|
|
@@ -302,6 +353,7 @@ Test/example flow in test/generalTest.json
|
|
|
302
353
|
------------------------------------------------------------
|
|
303
354
|
|
|
304
355
|
# Version
|
|
356
|
+
0.23.0 Removes bug in test, more translation
|
|
305
357
|
|
|
306
358
|
0.22.0 Add autocovariance + autocorealationship to real time data analystics, improves test
|
|
307
359
|
|
package/lib/common.js
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
const error=(node,message,shortMessage,logger)=>{
|
|
2
|
+
if(logger && logger.active) logger.send({label:"error",node:node.id,error:error,shortMessage});
|
|
3
|
+
node.error(message);
|
|
4
|
+
node.status({fill:"red",shape:"ring",text:shortMessage});
|
|
5
|
+
}
|
|
6
|
+
const evalFunction(id,mapping,logger)=>{
|
|
7
|
+
logger&&logger.sendInfo({label:"evalFunction",id:id,mapping:mapping})
|
|
8
|
+
try{
|
|
9
|
+
return eval(mapping);
|
|
10
|
+
} catch(ex) {
|
|
11
|
+
logger.sendError({label:"evalFunction error",id:id,mapping:mapping,error:ex.message})
|
|
12
|
+
throw Error(id+" "+ex.message);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
const evalInFunction=(node,propertyName)=>{
|
|
16
|
+
try{
|
|
17
|
+
const nodeContext = node.context();
|
|
18
|
+
const flow = nodeContext.flow;
|
|
19
|
+
const global = nodeContext.global;
|
|
20
|
+
const property=node[propertyName];
|
|
21
|
+
if(property==null) throw Error("no value for "+propertyName);
|
|
22
|
+
const propertyType=propertyName+"-type";
|
|
23
|
+
if(! (propertyType in node)) return evalFunction(propertyName,"()=>node."+property)
|
|
24
|
+
switch (node[propertyType]){
|
|
25
|
+
case "num":
|
|
26
|
+
case "json":
|
|
27
|
+
return evalFunction(propertyName,"()=>"+property);
|
|
28
|
+
case "node":
|
|
29
|
+
return evalFunction(propertyName,"()=>nodeContext.get("+property+")");
|
|
30
|
+
case "flow":
|
|
31
|
+
if(flow) throw Error("context store may be memoryonly so flow doesn't work")
|
|
32
|
+
return evalFunction(propertyName,"()=>flow.get("+property+")");
|
|
33
|
+
case "global":
|
|
34
|
+
return evalFunction(propertyName,"()=>global.get("+property+")");
|
|
35
|
+
case "env":
|
|
36
|
+
return evalFunction(propertyName,"()=>env.get("+property+")");
|
|
37
|
+
case "msg":
|
|
38
|
+
return evalFunction(propertyName,"(msg)=>msg."+property);
|
|
39
|
+
default:
|
|
40
|
+
logger.sendInfo({label:"setData unknown type",action:node.action,propertyType:propertyType,type:node[propertyType]});
|
|
41
|
+
throw Error("unknown type "+node[propertyType])
|
|
42
|
+
}
|
|
43
|
+
} catch(ex) {
|
|
44
|
+
logger.sendError({label:"setup",error:ex.message,stack:ex.stack});
|
|
45
|
+
throw Error(property+" "+ex.message);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const argsArray=(node,msg)=>{
|
|
50
|
+
const args=[];
|
|
51
|
+
node.argFunction.forEach(callFunction=> {
|
|
52
|
+
const result=callFunction(msg);
|
|
53
|
+
args.push(result);
|
|
54
|
+
});
|
|
55
|
+
return args;
|
|
56
|
+
}
|
|
57
|
+
const setArgsFunction=(node)=>{
|
|
58
|
+
node.argFunction=[];
|
|
59
|
+
node.args.forEach(property=>{
|
|
60
|
+
try{
|
|
61
|
+
node.argFunction.push(evalInFunction(node,property).bind(this));
|
|
62
|
+
} catch(ex) {
|
|
63
|
+
throw Error("args "+property+" "+ex.message)
|
|
64
|
+
}
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
const setTargetFunction=(node)=>{
|
|
70
|
+
if(node.target) throw Error("target is null")
|
|
71
|
+
if(node.hasOwnProperty("target-type")) {
|
|
72
|
+
node.setData=evalFunction("target","data=>data)")
|
|
73
|
+
return
|
|
74
|
+
}
|
|
75
|
+
const nodeContext = node.context()
|
|
76
|
+
const type=node["target-type"]
|
|
77
|
+
switch(type){
|
|
78
|
+
case "node":
|
|
79
|
+
node.setData=evalFunction("target","data=>nodeContext.set("+node.target+",data)")
|
|
80
|
+
break
|
|
81
|
+
case "flow":
|
|
82
|
+
if(nodeContext.flow) throw Error("context store may be memory only so flow doesn't work")
|
|
83
|
+
node.setData=evalFunction("target","data=>nodeContext.flow.set("+node.target+",data)")
|
|
84
|
+
break
|
|
85
|
+
case "global":
|
|
86
|
+
node.setData=evalFunction("target","data=>nodeContext.global.set("+node.target+",data)")
|
|
87
|
+
break
|
|
88
|
+
case "msg":
|
|
89
|
+
node.setData=evalFunction("target","(data,msg)=>{msg."+node.target+"=data;}")
|
|
90
|
+
break
|
|
91
|
+
default:
|
|
92
|
+
throw Error("setData unknown type "+type)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const baseProcess=(msg,call=sourceMatrix[node.action])=>{
|
|
97
|
+
const value=node.getSource(msg);
|
|
98
|
+
if(value==null) throw Error("source data not found");
|
|
99
|
+
const valueObject=(value instanceof Matrix?value:new Matrix(value));
|
|
100
|
+
return call.apply(valueObject,argsArray(node,msg));
|
|
101
|
+
}
|
|
102
|
+
const baseProcessAndSet=(msg)=>{
|
|
103
|
+
const result=baseProcess(msg);
|
|
104
|
+
node.setData.apply(node,[result,msg]);
|
|
105
|
+
}
|
|
106
|
+
function createProcess(msg){
|
|
107
|
+
const sourceMatrix=new Matrix({rowsMax:node.rows,columns:node.columns,dataType:node.dataType});
|
|
108
|
+
if(!(node.initialState in sourceMatrix)) throw Error("Invalid initial state "+node.initialState);
|
|
109
|
+
sourceMatrix[node.initialState]()
|
|
110
|
+
node.setData.apply(node,[sourceMatrix,msg]);
|
|
111
|
+
}
|
|
112
|
+
function defineProcess(msg){
|
|
113
|
+
const sourceMatrix=new Matrix({rows:node.rows,columns:node.columns,dataType:node.dataType});
|
|
114
|
+
node.setData.apply(node,[sourceMatrix,msg]);
|
|
115
|
+
}
|
|
116
|
+
function defineEmptyProcess(msg){
|
|
117
|
+
if(logger.active) logger.sendInfo({label:"define",arg:{rowsMax:node.row,columns:node.column}});
|
|
118
|
+
const sourceMatrix=new Matrix({rowsMax:node.rows,columns:node.columns});
|
|
119
|
+
node.setData.apply(node,[sourceMatrix,msg]);
|
|
120
|
+
}
|
|
121
|
+
function createSize(msg){
|
|
122
|
+
const sourceMatrix=new Matrix({rows:node.size,columns:node.size});
|
|
123
|
+
node.setData.apply(node,[sourceMatrix[node.action](),msg]);
|
|
124
|
+
}
|
|
125
|
+
function createDummy(msg){
|
|
126
|
+
const sourceMatrix=new Matrix(1,1);
|
|
127
|
+
node.setData.apply(node,[sourceMatrix[node.action].apply(sourceMatrix,argsArray(node,msg)),msg]);
|
|
128
|
+
}
|
package/lib/objectExtensions.js
CHANGED
|
@@ -1,71 +1,54 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
if(!String.prototype.in)
|
|
11
|
-
String.prototype.in = function (str) {
|
|
12
|
-
for (var i = 0; i < arguments.length; i++)
|
|
13
|
-
if(this==arguments[i]) return true;
|
|
14
|
-
return false;
|
|
15
|
-
};
|
|
16
|
-
if(!String.prototype.startsWith)
|
|
17
|
-
String.prototype.startsWith = function (str) {
|
|
18
|
-
return this.slice(0, str.length) == str;
|
|
19
|
-
};
|
|
20
|
-
if(!String.prototype.toTitle)
|
|
21
|
-
String.prototype.toTitle = function () {
|
|
22
|
-
var title=this.substr(0,1).toUpperCase()
|
|
23
|
-
,lastLowerCase=false;
|
|
24
|
-
for(var i=1 ; i<this.length; i++ ) {
|
|
25
|
-
char=this.substr(i,1);
|
|
26
|
-
if(char==char.toUpperCase()) {
|
|
27
|
-
if(lastLowerCase) title+=' ';
|
|
28
|
-
lastLowerCase=false;
|
|
29
|
-
if(char=='_') continue;
|
|
30
|
-
if(char==' ') continue;
|
|
31
|
-
} else lastLowerCase=true;
|
|
32
|
-
title+=char;
|
|
33
|
-
}
|
|
34
|
-
return title;
|
|
35
|
-
};
|
|
36
|
-
if(!String.prototype.to)
|
|
37
|
-
String.prototype.to = function (type) {
|
|
38
|
-
if (this==null) return null;
|
|
39
|
-
if (type==null) return value;
|
|
40
|
-
return this['to'+type.capitalize()];
|
|
1
|
+
const defineMethod=(object,name,call)=>{
|
|
2
|
+
if(name in object.prototype) return
|
|
3
|
+
try{
|
|
4
|
+
Object.defineProperty(object.prototype, name, {
|
|
5
|
+
enumerable: false,
|
|
6
|
+
value: call
|
|
7
|
+
})
|
|
8
|
+
} catch(ex){
|
|
9
|
+
console.error("defining "+name,ex.message)
|
|
41
10
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if(
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
11
|
+
}
|
|
12
|
+
const toDateType=aDate=>aDate instanceof Date? aDate : new Date(Date.parse(aDate))
|
|
13
|
+
const toDateTypeZulu=aDate=>aDate instanceof Date? aDate : new Date(aDate)
|
|
14
|
+
defineMethod(Array,'move',function(from, to) {
|
|
15
|
+
if(from<to) to--
|
|
16
|
+
this.splice(to, 0, this.splice(from, 1)[0])
|
|
17
|
+
})
|
|
18
|
+
defineMethod(String,"in",function (...str) {
|
|
19
|
+
for (var i = 0; i < arguments.length; i++)
|
|
20
|
+
if(this==arguments[i]) return true
|
|
21
|
+
return false
|
|
22
|
+
})
|
|
23
|
+
defineMethod(String,"capitalize",function() {return this.charAt(0).toUpperCase() + this.slice(1)})
|
|
24
|
+
defineMethod(String,"toCapitalized",function() {return this.charAt(0).toUpperCase() + this.slice(1)})
|
|
25
|
+
defineMethod(String,"to",function (type) {
|
|
26
|
+
if(type==null) return value
|
|
27
|
+
return this['to'+type.capitalize()]
|
|
28
|
+
})
|
|
29
|
+
defineMethod(String,"toReal",function (){return parseFloat(this)})
|
|
30
|
+
defineMethod(String,"toTitle", function (){return this.replace(/\w\S*/g, text => text.capitalize())})
|
|
31
|
+
|
|
32
|
+
defineMethod(String,"toTitleGrammatical", function (){
|
|
33
|
+
const lowerCaseList = ['a', 'an', 'the', 'and', 'but', 'or', 'for', 'nor', 'as', 'at',
|
|
34
|
+
'by', 'from', 'in', 'into', 'of', 'on', 'onto', 'to', 'with', 'yet', 'so','upon', 'like', 'over', 'plus', 'up', 'down', 'off', 'near'];
|
|
35
|
+
const title=this.replace(/\p{L}+/gu, (word)=>{
|
|
36
|
+
const wordLowerCase=word.toLowerCase()
|
|
37
|
+
return lowerCaseList.includes(wordLowerCase) ? wordLowerCase : word.capitalize()
|
|
38
|
+
})
|
|
39
|
+
return title.capitalize()
|
|
40
|
+
})
|
|
67
41
|
|
|
68
|
-
|
|
42
|
+
defineMethod(String,"toInt",function() {return parseInt(this)})
|
|
43
|
+
if(!String.prototype.toInt) String.prototype.toInteger=String.prototype.toInt
|
|
44
|
+
defineMethod(String,"toTimestamp",function () {
|
|
45
|
+
return Date.parse(this.substring(0,4)+'/'+this.substring(5,2)+'/'+this.substring(8,11))
|
|
46
|
+
+ parseInt(this.substring(21,3));
|
|
47
|
+
})
|
|
48
|
+
defineMethod(String,"toTime",function () {return Date.parse(this)})
|
|
49
|
+
defineMethod(String,"CRLF2BR", function(){return this.replace("\n\r","<br/>").replace("\n","<br/>")})
|
|
50
|
+
|
|
51
|
+
defineMethod(Array,"findSorted",function(searchElement,minIndex = 0,maxIndex = this.length - 1) {
|
|
69
52
|
let currentIndex, currentElement
|
|
70
53
|
while(minIndex <= maxIndex) {
|
|
71
54
|
currentIndex = (minIndex + maxIndex) / 2 | 0
|
|
@@ -77,8 +60,8 @@ Array.prototype.findSorted = function(searchElement,minIndex = 0,maxIndex = this
|
|
|
77
60
|
} else return currentIndex
|
|
78
61
|
}
|
|
79
62
|
return -minIndex
|
|
80
|
-
}
|
|
81
|
-
Array
|
|
63
|
+
})
|
|
64
|
+
defineMethod(Array,"addSorted",function(element) {
|
|
82
65
|
if(this.length){
|
|
83
66
|
const position = -this.findSorted(element)
|
|
84
67
|
if(position<0 ) return -position
|
|
@@ -87,15 +70,16 @@ Array.prototype.findSorted = function(searchElement,minIndex = 0,maxIndex = this
|
|
|
87
70
|
}
|
|
88
71
|
this.push(element)
|
|
89
72
|
return 0
|
|
90
|
-
}
|
|
91
|
-
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
defineMethod(Object,"addList",function(property,object) {
|
|
92
76
|
try{
|
|
93
77
|
this[property].push(object)
|
|
94
78
|
} catch(ex) {
|
|
95
79
|
this[property]=[object]
|
|
96
80
|
}
|
|
97
|
-
}
|
|
98
|
-
Object
|
|
81
|
+
})
|
|
82
|
+
defineMethod(Object,"addErrorFunctions",function(){
|
|
99
83
|
this.onError=function(call){
|
|
100
84
|
if(this.errorStack) this.errorStack.push(call)
|
|
101
85
|
else this.errorStack=[this.call]
|
|
@@ -113,8 +97,9 @@ Object.prototype.addErrorFunctions = function(){
|
|
|
113
97
|
if(typeof ex == "string") throw Error(ex)
|
|
114
98
|
throw ex
|
|
115
99
|
}
|
|
116
|
-
}
|
|
117
|
-
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
const colourSmallList={
|
|
118
103
|
"Red":'#FF0000',
|
|
119
104
|
"Turquoise":'#00FFFF',
|
|
120
105
|
"Grass Green":'#408080',
|
|
@@ -132,7 +117,7 @@ if(!colourSmallList) var colourSmallList={
|
|
|
132
117
|
"Light Purple":'#FF0080',
|
|
133
118
|
"Dark Grey":'#808080'
|
|
134
119
|
}
|
|
135
|
-
|
|
120
|
+
const colours ={
|
|
136
121
|
AliceBlue: '#F0F8FF',
|
|
137
122
|
AntiqueWhite: '#FAEBD7',
|
|
138
123
|
Aqua: '#00FFFF',
|
|
@@ -282,8 +267,7 @@ if(!colours) var colours ={
|
|
|
282
267
|
Yellow: '#FFFF00',
|
|
283
268
|
YellowGreen: '#9ACD32'
|
|
284
269
|
}
|
|
285
|
-
|
|
286
|
-
String.prototype.csvLine=function(delimiter=",",quote='"'){
|
|
270
|
+
defineMethod(String,"csvLine",function(delimiter=",",quote='"'){
|
|
287
271
|
let i=this.length,j=i,charInQuote,result=[]
|
|
288
272
|
if(i==0) return result
|
|
289
273
|
delimiter:while(i--){
|
|
@@ -317,9 +301,8 @@ String.prototype.csvLine=function(delimiter=",",quote='"'){
|
|
|
317
301
|
const v=this.substring(i+1,j)
|
|
318
302
|
result.unshift(v.length?isNaN(v)? v : Number(v):null)
|
|
319
303
|
return result
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
String.prototype.csvFile=function(delimiter=",",quote='"'){
|
|
304
|
+
})
|
|
305
|
+
defineMethod(String,"csvFile",function(delimiter=",",quote='"'){
|
|
323
306
|
let i=this.length,j=i,charInQuote,result=[],line=[]
|
|
324
307
|
if(i==0) return result
|
|
325
308
|
line:while(i--){
|
|
@@ -358,4 +341,131 @@ String.prototype.csvFile=function(delimiter=",",quote='"'){
|
|
|
358
341
|
result.unshift(line)
|
|
359
342
|
}
|
|
360
343
|
return result
|
|
344
|
+
})
|
|
345
|
+
|
|
346
|
+
defineMethod(Date,"isBetween",function(min, max) {return !(this < toDateType(min) || this > toDateType(max))})
|
|
347
|
+
defineMethod(Number,"isBetween",function(min, max) {return !(this < min || this > max)})
|
|
348
|
+
defineMethod(String,"isBetween",function(min, max) {return !(this < min || this > max)})
|
|
349
|
+
defineMethod(Object,"toSimpleArray",function(prefix) {
|
|
350
|
+
const returnValue=[]
|
|
351
|
+
for (let property in this) {
|
|
352
|
+
if(this[property]==null || this[property].enumerable==null || this[property].enumerable)
|
|
353
|
+
returnValue.push([(prefix?prefix:"")+property,this[property],typeof this[property]])
|
|
354
|
+
}
|
|
355
|
+
return returnValue
|
|
356
|
+
})
|
|
357
|
+
defineMethod(Object,"toSimpleArrayIgnoreNulls",function(prefix) {
|
|
358
|
+
const returnValue=[]
|
|
359
|
+
for (let property in this) {
|
|
360
|
+
if(this[property]==null ) continue
|
|
361
|
+
if(this[property].enumerable==null || this[property].enumerable)
|
|
362
|
+
returnValue.push([(prefix?prefix:"")+property,this[property],typeof this[property]])
|
|
363
|
+
}
|
|
364
|
+
return returnValue
|
|
365
|
+
})
|
|
366
|
+
|
|
367
|
+
defineMethod(String,"in",function () {
|
|
368
|
+
for (let i = 0; i < arguments.length; i++)
|
|
369
|
+
if(this.toString()===arguments[i]) return true;
|
|
370
|
+
return false
|
|
371
|
+
})
|
|
372
|
+
defineMethod(String,"startsWithList",function () {
|
|
373
|
+
for (var i = 0; i < arguments.length; i++)
|
|
374
|
+
if(this.slice(0, arguments[i].length)===arguments[i]) return true
|
|
375
|
+
return false
|
|
376
|
+
})
|
|
377
|
+
defineMethod(String,"startsWithListAnyCase",function (...list) {
|
|
378
|
+
for (var i = 0; i < list.length; i++){
|
|
379
|
+
const testString=list[i].toLowerCase()
|
|
380
|
+
if(this.slice(0, testString.length).toLowerCase()==testString) return true
|
|
381
|
+
}
|
|
382
|
+
return false
|
|
383
|
+
})
|
|
384
|
+
defineMethod(String,"xmlStringEncode",function() {
|
|
385
|
+
return this.toString().replace(/([\&"<>])/g, function(str, item) {
|
|
386
|
+
return {
|
|
387
|
+
'&': '&',
|
|
388
|
+
'"': '"',
|
|
389
|
+
'<': '<',
|
|
390
|
+
'>': '>'
|
|
391
|
+
}[item]
|
|
392
|
+
});
|
|
393
|
+
})
|
|
394
|
+
|
|
395
|
+
defineMethod(Number,"toAbbreviated",function() {
|
|
396
|
+
const digits=(v,e)=>{
|
|
397
|
+
const nv=v/Math.pow(10,e)
|
|
398
|
+
const anv=Math.abs(nv)
|
|
399
|
+
if(anv<10) return nv.toFixed(2).toString()
|
|
400
|
+
if(anv<100) return nv.toFixed(1).toString()
|
|
401
|
+
return nv.toFixed(0).toString()
|
|
402
|
+
}
|
|
403
|
+
const a=Math.abs(this)
|
|
404
|
+
if(a>Math.pow(10,15)) return digits(this,15)+'P'
|
|
405
|
+
if(a>Math.pow(10,12)) return digits(this,12)+'T'
|
|
406
|
+
if(a>Math.pow(10,9)) return digits(this,9)+'G'
|
|
407
|
+
if(a>Math.pow(10,6)) return digits(this,6)+'M'
|
|
408
|
+
if(a>Math.pow(10,3)) return digits(this,3)+'K'
|
|
409
|
+
return digits(this,0)
|
|
410
|
+
})
|
|
411
|
+
|
|
412
|
+
defineMethod(BigInt,"toAbbreviated",function() {
|
|
413
|
+
const digits=(v,e)=>{
|
|
414
|
+
const nv=v/Math.pow(10,e)
|
|
415
|
+
const anv=Math.abs(nv)
|
|
416
|
+
if(anv<10) return nv.toFixed(2).toString()
|
|
417
|
+
if(anv<100) return nv.toFixed(1).toString()
|
|
418
|
+
return nv.toFixed(0).toString()
|
|
419
|
+
}
|
|
420
|
+
const a=Math.abs(this)
|
|
421
|
+
if(a>Math.pow(10,15)) return digits(this,15)+'P'
|
|
422
|
+
if(a>Math.pow(10,12)) return digits(this,12)+'T'
|
|
423
|
+
if(a>Math.pow(10,9)) return digits(this,9)+'G'
|
|
424
|
+
if(a>Math.pow(10,6)) return digits(this,6)+'M'
|
|
425
|
+
if(a>Math.pow(10,3)) return digits(this,3)+'K'
|
|
426
|
+
return digits(this,0)
|
|
427
|
+
})
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
defineMethod(String,"getWord",function(wordPosition) {return this.split(/\s+/g,wordPosition+1)[wordPosition-1]??""})
|
|
431
|
+
|
|
432
|
+
const coalesce=(...args)=>{
|
|
433
|
+
for (var i=0; i<args.length; ++i)
|
|
434
|
+
if (args[i] != null) return args[i]
|
|
435
|
+
return null;
|
|
361
436
|
}
|
|
437
|
+
const nullif=(a,b)=>{return a==b?null:a}
|
|
438
|
+
//missing Float16Array,
|
|
439
|
+
[ArrayBuffer,Number,Boolean,BigInt,Date,String,Int8Array,Uint8Array,Uint8ClampedArray,Int16Array,Uint16Array,Int32Array,Uint32Array,BigInt64Array,BigUint64Array,Float32Array,Float64Array].forEach(type=>{
|
|
440
|
+
defineMethod(type,"deepClone",function(){ return new type(this)})
|
|
441
|
+
})
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
//defineMethod(TypedArray,"deepClone",function(){ return new type(this)})
|
|
445
|
+
defineMethod(Array,"deepClone",function(){
|
|
446
|
+
const clone=[]
|
|
447
|
+
for (let i in this)
|
|
448
|
+
clone[i]=this[i].deepClone()
|
|
449
|
+
return clone
|
|
450
|
+
})
|
|
451
|
+
defineMethod(Object,"deepClone",function(){
|
|
452
|
+
const clone={}
|
|
453
|
+
for (let i in this)
|
|
454
|
+
clone[i]=this[i].deepClone()
|
|
455
|
+
return clone
|
|
456
|
+
})
|
|
457
|
+
defineMethod(Number, "rangeLimit",function(min,max) {return (min!=null && this<min) ? min : ((max!=null && this>max) ? max : this)})
|
|
458
|
+
defineMethod(BigInt, "rangeLimit",function(min,max) {return (min!=null && this<min) ? min : ((max!=null && this>max) ? max : this)})
|
|
459
|
+
defineMethod(Date, "rangeLimit",function(min,max) {return (min!=null && this<min) ? min : ((max!=null && this>max) ? max : this)})
|
|
460
|
+
defineMethod(String, "rangeLimit",function(min,max) {return (min!=null && this<min) ? min : ((max!=null && this>max) ? max : this)})
|
|
461
|
+
defineMethod(String,"deunderscore",function(){return this.replace(/_/g," ")})
|
|
462
|
+
defineMethod(String,"deunderscoreCapitilize",function(){return this.replace(/_/g," ").toTitle()})
|
|
463
|
+
defineMethod(String,"dropSquareBracketPrefix",function(bracket="[",endBracket="]"){return (this.substr(0,1)==bracket)? this.split(endBracket+" ")[1] : this})
|
|
464
|
+
module.exports={
|
|
465
|
+
coalesce:coalesce,
|
|
466
|
+
colours:colours,
|
|
467
|
+
colourSmallList:colourSmallList,
|
|
468
|
+
nullif:nullif,
|
|
469
|
+
toDateType,
|
|
470
|
+
toDateTypeZulu,
|
|
471
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
|
|
2
|
+
const setGetFunction=(RED,node,propertyName)=>node["get"+propertyName[0].toUpperCase() + propertyName.slice(1)]=getFunction(RED,node,propertyName)
|
|
3
|
+
|
|
4
|
+
const getFunction=(RED,node,propertyName)=>{
|
|
5
|
+
try{
|
|
6
|
+
const property=node[propertyName];
|
|
7
|
+
if(property==null) throw Error("no value for "+propertyName);
|
|
8
|
+
const propertyType=propertyName+"Type";
|
|
9
|
+
if(! (propertyType in node)) return eval("()=>node."+property)
|
|
10
|
+
const type=node[propertyType]
|
|
11
|
+
switch (type){
|
|
12
|
+
case "bin": // a Node.js Buffer
|
|
13
|
+
case "re": // a Regular Expression
|
|
14
|
+
case "jsonata": // a Jsonata Expression
|
|
15
|
+
case "cred": // a secure credential
|
|
16
|
+
case "bool":
|
|
17
|
+
case "json":
|
|
18
|
+
case "num":
|
|
19
|
+
case "str":
|
|
20
|
+
case "date": // the current timestamp
|
|
21
|
+
case "env":
|
|
22
|
+
case "global":
|
|
23
|
+
const value=RED.util.evaluateNodeProperty(property, type, node)
|
|
24
|
+
return eval("()=>value")
|
|
25
|
+
case "flow":
|
|
26
|
+
const flow = node.context().flow;
|
|
27
|
+
if(flow) throw Error("context store may be memoryonly so flow doesn't work")
|
|
28
|
+
return eval("()=>flow.get("+property+")");
|
|
29
|
+
case "msg":
|
|
30
|
+
return eval("(msg)=>msg."+property);
|
|
31
|
+
case "node":
|
|
32
|
+
const nodeContext = node.context();
|
|
33
|
+
return eval("()=>nodeContext.get("+property+")");
|
|
34
|
+
default:
|
|
35
|
+
throw Error("unknown type "+node[propertyType])
|
|
36
|
+
}
|
|
37
|
+
} catch(ex) {
|
|
38
|
+
throw Error(propertyName+" "+ex.message);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
}
|
|
42
|
+
const setFunction=(RED,node,name)=>{
|
|
43
|
+
if(!name)
|
|
44
|
+
if(!node.hasOwnProperty(name)) throw Error("name is null")
|
|
45
|
+
if(!node.hasOwnProperty(name+"-type")) {
|
|
46
|
+
node.set[name]=eval("data=>msg.payload['"+name+"']=data)")
|
|
47
|
+
return
|
|
48
|
+
}
|
|
49
|
+
const type=node[name+"t-type"]
|
|
50
|
+
switch(type){
|
|
51
|
+
case "node":
|
|
52
|
+
node.set[name]=eval("data=>node.context().set("+node[name]+",data)")
|
|
53
|
+
break
|
|
54
|
+
case "flow":
|
|
55
|
+
const flow=node.context().flow
|
|
56
|
+
if(flow) throw Error("context store may be memory only so flow doesn't work")
|
|
57
|
+
node.set[name]=eval("data=>flow.set("+node[name]+",data)")
|
|
58
|
+
break
|
|
59
|
+
case "global":
|
|
60
|
+
node.set[name]=eval("data=>nodeContext.global.set("+node[name]+",data)")
|
|
61
|
+
break
|
|
62
|
+
case "msg":
|
|
63
|
+
node.set[name]=eval("(data,msg)=>{msg."+node[name]+"=data;}")
|
|
64
|
+
break
|
|
65
|
+
default:
|
|
66
|
+
throw Error("setData unknown type "+type)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const getValue=(RED,node,propertyName,defaultValue)=>propertyName in node?getFunction(RED,node,propertyName)():defaultValue
|
|
71
|
+
|
|
72
|
+
module.exports={
|
|
73
|
+
getFunction:getFunction,
|
|
74
|
+
setFunction:setFunction,
|
|
75
|
+
setGetFunction:setGetFunction,
|
|
76
|
+
getValue:getValue
|
|
77
|
+
}
|