node-red-contrib-prib-functions 0.19.2 → 0.21.0

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.
Files changed (82) hide show
  1. package/.github/workflows/codeql-analysis.yml +3 -3
  2. package/.github/workflows/npmpublish.yml +6 -6
  3. package/.vs/VSWorkspaceState.json +7 -0
  4. package/.vs/node-red-contrib-prib-functions/v17/.wsuo +0 -0
  5. package/README.md +84 -70
  6. package/dataAnalysis/arrayAllRowsSwap.js +15 -0
  7. package/dataAnalysis/arrayCompareToPrecision.js +34 -0
  8. package/dataAnalysis/arrayDifference.js +14 -0
  9. package/dataAnalysis/arrayDifferenceSeasonal.js +15 -0
  10. package/dataAnalysis/arrayDifferenceSeasonalSecondOrder.js +20 -0
  11. package/dataAnalysis/arrayDifferenceSecondOrder.js +14 -0
  12. package/dataAnalysis/arrayForEachRange.js +38 -0
  13. package/dataAnalysis/arrayOverlay.js +13 -0
  14. package/dataAnalysis/arrayProduct.js +11 -0
  15. package/dataAnalysis/arrayRandom.js +14 -0
  16. package/dataAnalysis/arrayReduceRange.js +11 -0
  17. package/dataAnalysis/arrayScale.js +11 -0
  18. package/dataAnalysis/arraySum.js +11 -0
  19. package/dataAnalysis/arraySumSquared.js +11 -0
  20. package/dataAnalysis/arraySwap.js +11 -0
  21. package/dataAnalysis/dataAnalysis.html +52 -21
  22. package/dataAnalysis/dataAnalysis.js +73 -44
  23. package/dataAnalysis/generateMatrixFunction.js +89 -0
  24. package/dataAnalysis/generateVectorFunction.js +25 -0
  25. package/dataAnalysis/pca.js +472 -325
  26. package/dataAnalysis/svd.js +239 -0
  27. package/documentation/DataAnalysisRealtime.JPG +0 -0
  28. package/documentation/monitorSystem.JPG +0 -0
  29. package/documentation/monitorSystemTest.JPG +0 -0
  30. package/echart/echart.html +68 -0
  31. package/echart/echart.js +85 -0
  32. package/echart/icons/chart-671.png +0 -0
  33. package/echart/lib/echarts.js +95886 -0
  34. package/lib/Chart.js +177 -0
  35. package/lib/Column.js +99 -0
  36. package/lib/GraphDB.js +14 -0
  37. package/lib/Table.js +185 -0
  38. package/lib/objectExtensions.js +361 -0
  39. package/matrix/matrix.js +95 -56
  40. package/matrix/matrixNode.html +88 -55
  41. package/matrix/matrixNode.js +12 -5
  42. package/monitor/BarGauge.js +8 -0
  43. package/monitor/Dataset.js +29 -0
  44. package/monitor/DialGauge.js +109 -0
  45. package/monitor/DialNeedle.js +36 -0
  46. package/monitor/Format.js +74 -0
  47. package/monitor/centerElement.js +14 -0
  48. package/monitor/compareElements.js +95 -0
  49. package/monitor/defs.js +23 -0
  50. package/monitor/extensions.js +906 -0
  51. package/monitor/functions.js +36 -0
  52. package/monitor/json2xml.js +103 -0
  53. package/monitor/monitorSystem.html +199 -0
  54. package/monitor/monitorSystem.js +322 -0
  55. package/monitor/svgHTML.js +179 -0
  56. package/monitor/svgObjects.js +64 -0
  57. package/package.json +20 -6
  58. package/test/00-objectExtensions.js +94 -0
  59. package/test/04-tables.js +33 -0
  60. package/test/data/.config.nodes.json +608 -0
  61. package/test/data/.config.nodes.json.backup +608 -0
  62. package/test/data/.config.runtime.json +4 -0
  63. package/test/data/.config.runtime.json.backup +3 -0
  64. package/test/data/.config.users.json +21 -0
  65. package/test/data/.config.users.json.backup +21 -0
  66. package/test/data/.flow.json.backup +2820 -2003
  67. package/test/data/float32vector10.npy +0 -0
  68. package/test/data/flow.json +2830 -2033
  69. package/test/data/int2matrix2x3.npy +0 -0
  70. package/test/data/package-lock.json +158 -0
  71. package/test/data/package.json +11 -0
  72. package/test/dataAnalysisExtensions.js +471 -0
  73. package/test/dataAnalysisPCA.js +54 -0
  74. package/test/dataAnalysisSVD.js +31 -0
  75. package/test/euclideanDistance.js +2 -2
  76. package/test/transformConfluence.js +1 -1
  77. package/test/transformNumPy.js +132 -0
  78. package/testing/test.html +1 -1
  79. package/testing/test.js +78 -53
  80. package/transform/NumPy.js +303 -0
  81. package/transform/transform.html +12 -0
  82. package/transform/transform.js +34 -2
@@ -0,0 +1,31 @@
1
+ const assert=require('assert');
2
+ const should=require("should");
3
+ const svd=require("../dataAnalysis/svd.js");
4
+ require("../dataAnalysis/arrayCompareToPrecision.js");
5
+
6
+ const expected={
7
+ orthonormalizedColumns: [
8
+ [ -0.3913289321676804, 0.3487948014410755, 0.10448989927485411 ],
9
+ [ -0.4639397307294648, -0.34948424610207607, 0.7962721013609022 ],
10
+ [ -0.6197155556759748, -0.5188940242462491, -0.5888137410546312 ],
11
+ [ -0.4975683100363125, 0.6978194177691509, -0.0912742016622088 ]
12
+ ],
13
+ singularValues: [ 223.85445199527607, 13.695880509722402, 17.366841363876695 ],
14
+ orthogonalMatrix: [
15
+ [ -0.5061583666044986, -0.7405855572048029, -0.44196916224541927 ],
16
+ [ -0.5596333427471312, -0.10788454127728717, 0.8216881692217926 ],
17
+ [ -0.6562120309792694, 0.6632450212500965, -0.35984970777398323 ]
18
+ ]
19
+ }
20
+
21
+ describe('SVD', function(){
22
+ it("getEigenVectors", function(done){
23
+ const data = [[40,50,60],[50,70,60],[80,70,90],[50,60,80]];
24
+ const vectors = svd(data);
25
+ console.log(vectors)
26
+ vectors.orthonormalizedColumns.compareToPrecision(expected.orthonormalizedColumns)
27
+ vectors.singularValues.compareToPrecision(expected.singularValues)
28
+ vectors.orthogonalMatrix.compareToPrecision(expected.orthogonalMatrix)
29
+ done();
30
+ });
31
+ });
@@ -1,8 +1,8 @@
1
- const assert=require('assert');
1
+ onst assert=require('assert');
2
2
  const should=require("should");
3
3
  const ed=require("../dataAnalysis/euclideanDistance.js");
4
4
  require("../dataAnalysis/forNestedEach");
5
-
5
+ c
6
6
  describe('euclideanDistance', function() {
7
7
  it("array forNestedEach", function(done) {
8
8
  const atest=[1,2,3,4];
@@ -1,4 +1,4 @@
1
- const should = require("should");
1
+ //const should = require("should");
2
2
  const helper = require("node-red-node-test-helper");
3
3
  const transformNode = require("../transform/transform.js");
4
4
  const Buffer=require('buffer').Buffer;
@@ -0,0 +1,132 @@
1
+ const assert=require('assert')
2
+ const helper = require("node-red-node-test-helper")
3
+ const NumPy = require("../transform/NumPy.js")
4
+ const transformNode = require("../transform/transform.js");
5
+ const fs = require('fs')
6
+ const path = require('path')
7
+ const filePath = path.join(__dirname, "data/float32vector10.npy")
8
+ const npyFloat32V10 = fs.readFileSync(filePath)
9
+ const npyInt2matrix2x3 = fs.readFileSync(path.join(__dirname, "data/int2matrix2x3.npy"))
10
+ const int2matrix2x3={"dataType":"int64","fortran_order":false,"shape":[1,2,3],"version":1.0,"dataVector":new BigInt64Array([1n,2n,3n,4n,5n,6n])}
11
+ if(!Buffer.prototype.toBufferArray)
12
+ Buffer.prototype.toBufferArray = function() {return this.buffer.slice(this.byteOffset, this.byteOffset + this.byteLength)}
13
+
14
+ const float32V10 = new Float32Array([
15
+ 86, 46, 10, 148, 133,
16
+ 86, 103, 118, 62, 49
17
+ ])
18
+ const NumPyJSON={
19
+ "dataType":"float32",
20
+ "fortran_order":false,
21
+ version:1.0,
22
+ "shape":[10],
23
+ "dataVector":{"0":86,"1":46,"2":10,"3":148,"4":133,"5":86,"6":103,"7":118,"8":62,"9":49}
24
+ }
25
+ helper.init(require.resolve('node-red'));
26
+
27
+ const npy2JSONNode={
28
+ id : "npy2JSON",
29
+ type : "transform",
30
+ name : "npy to JSON",
31
+ actionSource: "npy",
32
+ actionTarget: "JSON",
33
+ sourceProperty:"msg.payload",
34
+ targetProperty:"msg.payload",
35
+ topicProperty:"'test topic'"
36
+ };
37
+ const JSON2npyNode={
38
+ id : "npy2JSON",
39
+ type : "transform",
40
+ name : "JSON to npy",
41
+ actionSource: "JSON",
42
+ actionTarget: "npy",
43
+ sourceProperty:"msg.payload",
44
+ targetProperty:"msg.payload",
45
+ topicProperty:"'test topic'"
46
+ };
47
+ function getAndTestNodeProperties(o) {
48
+ const n = helper.getNode(o.id);
49
+ for(let p in o) n.should.have.property(p, o[p]);
50
+ return n;
51
+ }
52
+ function testFlow(done,node,data,result) {
53
+ const flow = [
54
+ Object.assign(node,{wires : [ [ "outHelper" ],["errorHelper"] ]}),
55
+ {id :"outHelper", type : "helper"},
56
+ {id :"errorHelper", type : "helper"}
57
+ ];
58
+ helper.load(transformNode, flow, function() {
59
+ const n=getAndTestNodeProperties(node);
60
+ const outHelper = helper.getNode("outHelper");
61
+ const errorHelper = helper.getNode("errorHelper");
62
+ outHelper.on("input", function(msg) {
63
+ console.log("outHelper "+JSON.stringify(msg.payload));
64
+ if(JSON.stringify(msg.payload)==JSON.stringify(result)) {
65
+ done();
66
+ } else {
67
+ console.log("mismatch expected: "+JSON.stringify(result) +" returned: "+JSON.stringify(msg.payload));
68
+ done("mismatch");
69
+ }
70
+ });
71
+ errorHelper.on("input", function(msg) {
72
+ console.log("errorHelper "+JSON.stringify(msg));
73
+ done("error check log output");
74
+ });
75
+ n.receive({
76
+ topic:"test",
77
+ payload : data
78
+ });
79
+ });
80
+ }
81
+
82
+ describe('NumPy', function() {
83
+ it("parse npyFloat10",(done)=>{
84
+ const tensor=new NumPy(npyFloat32V10)
85
+ assert.deepStrictEqual(tensor.dataType,'float32')
86
+ assert.deepStrictEqual(tensor.shape,[10])
87
+ assert.deepStrictEqual(tensor.fortran_order,false)
88
+ assert.deepStrictEqual(tensor.dataVector,float32V10)
89
+ done()
90
+ });
91
+ it("parse npyInt2matrix2x3",(done)=>{
92
+ const tensor=new NumPy(npyInt2matrix2x3)
93
+ assert.deepStrictEqual(tensor.toSerializable(),int2matrix2x3)
94
+ done()
95
+ });
96
+ it("parse int2matrix2x3",(done)=>{
97
+ const tensor=new NumPy(int2matrix2x3)
98
+ assert.deepStrictEqual(tensor.toSerializable(),int2matrix2x3)
99
+ console.log({label:"toString",result:tensor.toString()})
100
+ const npy=tensor.toNpy()
101
+ done();
102
+ });
103
+ /*
104
+ it("toNpy float32V10",(done)=>{
105
+ const tensor=new NumPy(NumPyJSON)
106
+ assert.deepStrictEqual(tensor.toNpy(),npyFloat32V10.toBufferArray())
107
+ done();
108
+ });
109
+
110
+ it("toNpy int2matrix2x3",(done)=>{
111
+ const tensor=new NumPy(int2matrix2x3)
112
+ assert.deepStrictEqual(tensor.toNpy(),npyInt2matrix2x3.toBufferArray())
113
+ done();
114
+ });
115
+ */
116
+ });
117
+
118
+ describe('transform numpy', function() {
119
+ beforeEach(function(done) {
120
+ helper.startServer(done);
121
+ });
122
+ afterEach(function(done) {
123
+ helper.unload();
124
+ helper.stopServer(done);
125
+ });
126
+ it('npy to Array', function(done) {
127
+ testFlow(done,JSON2npyNode,int2matrix2x3,npyInt2matrix2x3);
128
+ });
129
+ it('npy to JSON', function(done) {
130
+ testFlow(done,npy2JSONNode,npyInt2matrix2x3,int2matrix2x3);
131
+ });
132
+ });
package/testing/test.html CHANGED
@@ -153,7 +153,7 @@
153
153
  this.payloadType=setType(this.payloadType);
154
154
  this.resultType=setType(this.resultType);
155
155
  function setInput(t) {
156
- let types=['flow','global','str','num','bool','json','bin','date','env'];
156
+ let types=['flow','global','str','num','bool','json','jsonata','bin','date','env'];
157
157
  if(t=="result") types.push('re');
158
158
  $("#node-input-"+t+"Type").val(this[t+"Type"]);
159
159
  $("#node-input-"+t).typedInput({
package/testing/test.js CHANGED
@@ -29,25 +29,35 @@ function setError(msg,node,err) {
29
29
  node.send([null,msg]);
30
30
  }
31
31
 
32
- function equalObjects(obj1,obj2,errorFactor) {
33
- if( obj1 === obj2 ) return true;
32
+ function equalObjects(obj1,obj2,errorFactor,callEquals=()=>true,callNotEquals=()=>false) {
33
+ if( obj1 === obj2 ) return callEquals();
34
34
  if(obj1 instanceof Buffer ) return Buffer.compare(obj1, obj2) === 0
35
- if( obj1 === Number.POSITIVE_INFINITY && obj2==="Infinity") return true;
36
- if( obj1 === Number.NEGATIVE_INFINITY && obj2==="-Infinity") return true;
37
- if( Number.isNaN(obj1) && obj2==="NaN") return true;
35
+ if( obj1 === Number.POSITIVE_INFINITY && obj2==="Infinity") return callEquals();
36
+ if( obj1 === Number.NEGATIVE_INFINITY && obj2==="-Infinity") return callEquals();
37
+ if( Number.isNaN(obj1) && obj2==="NaN") return callEquals();
38
38
  const obj1type=typeof obj1;
39
- if( obj1type != typeof obj2 ) return false;
39
+ if( obj1type != typeof obj2 ) return callNotEquals();
40
40
  if(errorFactor && obj1type=="number") return (Math.abs(obj2-obj1)/obj2)<errorFactor;
41
- if( !(obj1 instanceof Object) ) return false;
42
- if( Object.keys(obj1).length !== Object.keys(obj2).length ) return false;
41
+ if( !(obj1 instanceof Object) ) return callNotEquals();
42
+ if( Object.keys(obj1).length !== Object.keys(obj2).length ) return callNotEquals();
43
43
  try{
44
44
  for(let key in obj1) {
45
- if( !equalObjects(obj1[key],obj2[key],errorFactor) ) return false;
45
+ if( !equalObjects(obj1[key],obj2[key],errorFactor) ) return callNotEquals();
46
46
  }
47
47
  } catch(e) {
48
- return false;
48
+ return callNotEquals();
49
49
  }
50
- return true;
50
+ return callEquals();
51
+ }
52
+
53
+ const testedOK=(node,msg)=>{
54
+ node.status({fill:"green",shape:"ring",text:"Success"});
55
+ delete msg._test;
56
+ node.send([null,null,msg]);
57
+ }
58
+ const testedFailed=(node,msg)=>{
59
+ msg._test.testedValue=node.getData(msg,node);
60
+ setError(msg,node,"Test failed");
51
61
  }
52
62
 
53
63
  module.exports = function(RED) {
@@ -56,9 +66,17 @@ module.exports = function(RED) {
56
66
  RED.nodes.createNode(this,n);
57
67
  let node=Object.assign(this,n);
58
68
  try{
59
- node.getData=eval("((msg,node)=>"+(node.resultProperty||"msg.payload")+")");
69
+ node.isJSONata=node.resultType=="jsonata"
60
70
  if(node.escapeString && node.resultType=="str") {
61
71
  node.getData=eval("((msg,node)=>escapeSpecialChars("+(node.resultProperty||"msg.payload")+"))");
72
+ } else{
73
+ if(node.isJSONata) {
74
+ if(!node.result.startsWith("$boolean"))
75
+ throw Error("JSONata must have $boolean outcome, found: "+node.resultProperty.substr(0,8))
76
+ node.resultExpression=RED.util.prepareJSONataExpression(node.result, node)
77
+ node.resultExpression.assign('node', node);
78
+ }
79
+ node.getData=eval("((msg,node)=>"+(node.resultProperty||"msg.payload")+")");
62
80
  }
63
81
  node.status({fill:"green",shape:"ring",text:"Ready"});
64
82
  } catch(e) {
@@ -66,59 +84,66 @@ module.exports = function(RED) {
66
84
  node.status({fill:"red",shape:"ring",text:"Invalid setup "+e.toString()});
67
85
  }
68
86
  node.payloadEscape=(node.payloadType=="str"&&node.escapeString);
69
- node.equalObjects=node.resultType=="re"?(value,regex)=>RegExp(regex).test(value):equalObjects;
87
+ node.equalObjects=node.resultType=="re"?
88
+ (value,regex,callEquals,callNotEquals)=>(RegExp(regex).test(value)?callEquals():callNotEquals()):
89
+ (obj1,obj2,errorFactor,callEquals,callNotEquals)=>equalObjects(obj1,obj2,errorFactor,callEquals,callNotEquals);
70
90
  node.on("input",function(msg) {
71
91
  if(msg._test) {
72
92
  try{
73
- if(msg._test.id!==node.id) {
74
- setError(msg,node,"Sent by another test "+msg._test.id);
75
- } else if(!equalObjects(node.getData(msg,node),msg._test.result,node.errorFactor)) {
76
- msg._test.testedValue=node.getData(msg,node);
77
- setError(msg,node,"Test failed");
78
- } else {
79
- node.status({fill:"green",shape:"ring",text:"Success"});
80
- delete msg._test;
81
- node.send([null,null,msg]);
82
- }
93
+ if(msg._test.id!==node.id) return setError(msg,node,"Sent by another test "+msg._test.id);
94
+
95
+ if(node.isJSONata)
96
+ return RED.util.evaluateJSONataExpression(node.resultExpression,msg,(err,data)=>{
97
+ if(err) testedFailed(node,msg)
98
+ else return data?testedOK(node,msg):testedFailed(node,msg)
99
+ })
100
+
101
+ node.equalObjects(node.getData(msg,node),msg._test.result,node.errorFactor,
102
+ ()=>testedOK(node,msg),
103
+ ()=>testedFailed(node,msg)
104
+ );
105
+
83
106
  } catch(ex){
84
107
  setError(msg,node,"Test failed on get data "+ex.message);
85
108
  }
86
109
  return;
87
110
  }
88
111
  node.status({fill:"yellow",shape:"ring",text:"waiting on response"});
89
- const result=RED.util.evaluateNodeProperty(node.result,node.resultType,node,msg);
90
- msg._test={
91
- id:node.id,
92
- result:node.escapeString&&node.resultType=="str"?escapeSpecialChars(result):result
93
- };
94
- msg.topic=node.topic;
95
- if(["flow","global"].includes(node.payloadType)) {
96
- RED.util.evaluateNodeProperty(node.payload,node.payloadType,node,msg, function(err,res) {
97
- if (err) {
98
- node.error(err,msg);
99
- } else {
100
- msg.payload=res;
112
+ let result=RED.util.evaluateNodeProperty(node.result,node.resultType,node,msg,(err,data)=>{
113
+ if(err) node.error(err,msg)
114
+ msg._test={
115
+ id:node.id,
116
+ result:node.escapeString&&node.resultType=="str"?escapeSpecialChars(data):data
117
+ };
118
+ msg.topic=node.topic;
119
+ if(["flow","global"].includes(node.payloadType)) {
120
+ RED.util.evaluateNodeProperty(node.payload,node.payloadType,node,msg, (err,res)=>{
121
+ if (err) {
122
+ node.error(err,msg);
123
+ } else {
124
+ msg.payload=res;
125
+ node.send(msg);
126
+ }
127
+ });
128
+ } else {
129
+ try {
130
+ if ( (node.payloadType == null && node.payload === "") || node.payloadType === "date") {
131
+ msg.payload = Date.now();
132
+ } else if (node.payloadType == null) {
133
+ msg.payload = node.payload;
134
+ } else if (node.payloadType === 'none') {
135
+ msg.payload = "";
136
+ } else {
137
+ msg.payload=RED.util.evaluateNodeProperty(this.payload,node.payloadType,node,msg);
138
+ if(node.payloadEscape) msg.payload=msg.payload.escapeSpecialChars();
139
+ }
101
140
  node.send(msg);
141
+ msg = null;
142
+ } catch(err) {
143
+ node.error(err,msg);
102
144
  }
103
- });
104
- } else {
105
- try {
106
- if ( (node.payloadType == null && node.payload === "") || node.payloadType === "date") {
107
- msg.payload = Date.now();
108
- } else if (node.payloadType == null) {
109
- msg.payload = node.payload;
110
- } else if (node.payloadType === 'none') {
111
- msg.payload = "";
112
- } else {
113
- msg.payload=RED.util.evaluateNodeProperty(this.payload,node.payloadType,node,msg);
114
- if(node.payloadEscape) msg.payload=msg.payload.escapeSpecialChars();
115
- }
116
- node.send(msg);
117
- msg = null;
118
- } catch(err) {
119
- node.error(err,msg);
120
145
  }
121
- }
146
+ });
122
147
  });
123
148
  }
124
149
 
@@ -0,0 +1,303 @@
1
+ if(!BigInt.prototype.toJSON)
2
+ BigInt.prototype.toJSON = function(){return Number(this.toString())}
3
+ if(!Buffer.prototype.toBufferArray)
4
+ Buffer.prototype.toBufferArray = function() {return this.buffer.slice(this.byteOffset, this.byteOffset + this.byteLength)}
5
+ //const bufferToArrayBuffer = (b) => b.buffer.slice(b.byteOffset, b.byteOffset + b.byteLength);
6
+ const MAGIC_STRING = "\x93NUMPY"
7
+ const defaultVersionStr = "\x01\x00" // version 1.0
8
+ const defaultVersion = 1.0
9
+ const getTotalCells = (shape)=> shape.reduce((a, b) => a * b, 1);
10
+ const dataTypes = {
11
+ "|b1": {
12
+ bytes4DataType: 1,
13
+ name: "bool",
14
+ cellConstructor: Uint8Array,
15
+ setDataView: "setUint8"
16
+ },
17
+ "<u1": {
18
+ name: "uint8",
19
+ bytes4DataType: 8,
20
+ cellConstructor: Uint8Array,
21
+ setDataView: "setUint8"
22
+ },
23
+ "|u1": {
24
+ name: "uint8",
25
+ bytes4DataType: 8,
26
+ cellConstructor: Uint8Array,
27
+ setDataView: "setUint8"
28
+ },
29
+ "|i1": {
30
+ name: "int8",
31
+ bytes4DataType: 8,
32
+ cellConstructor: Int8Array,
33
+ setDataView: "setInt8"
34
+ },
35
+ "<u2": {
36
+ name: "uint16",
37
+ bytes4DataType: 16,
38
+ cellConstructor: Uint16Array,
39
+ setDataView: "setUint16"
40
+ },
41
+ "<i1": {
42
+ name: "int8",
43
+ bytes4DataType: 8,
44
+ cellConstructor: Int8Array,
45
+ setDataView: "setInt16"
46
+ },
47
+ "<i2": {
48
+ name: "int16",
49
+ bytes4DataType: 16,
50
+ cellConstructor: Int16Array,
51
+ setDataView: "setInt16"
52
+ },
53
+ "<u4": {
54
+ name: "uint32",
55
+ bytes4DataType: 32,
56
+ cellConstructor: Int32Array,
57
+ setDataView: "setInt32"
58
+ },
59
+ "<i4": {
60
+ name: "int32",
61
+ bytes4DataType: 32,
62
+ cellConstructor: Int32Array,
63
+ setDataView: "setInt32"
64
+ },
65
+ "<u8": {
66
+ name: "uint64",
67
+ bytes4DataType: 64,
68
+ cellConstructor: BigUint64Array,
69
+ setDataView: "setBigUint64"
70
+ },
71
+ "<i8": {
72
+ name: "int64",
73
+ bytes4DataType: 64,
74
+ cellConstructor: BigInt64Array,
75
+ setDataView: "setBigInt64"
76
+ },
77
+ "<f4": {
78
+ name: "float32",
79
+ bytes4DataType: 32,
80
+ cellConstructor: Float32Array,
81
+ setDataView: "setFloat32"
82
+ },
83
+ "<f8": {
84
+ name: "float64",
85
+ bytes4DataType: 64,
86
+ cellConstructor: Float64Array,
87
+ setDataView: "setFloat64"
88
+ },
89
+ };
90
+
91
+ /*
92
+ ‘S’ - swap dtype from current to opposite endian
93
+ {‘<’, ‘little’} - little endian
94
+ {‘>’, ‘big’} - big endian
95
+ {‘=’, ‘native’} - native order
96
+ {‘|’, ‘I’} - ignore (no change to byte order)
97
+
98
+ b boolean
99
+ i signed integer
100
+ u unsigned integer f floating-point
101
+ c complex floating-point
102
+ m timedelta
103
+ M datetime
104
+ O object
105
+ S (byte-)string
106
+ U Unicode
107
+ V void
108
+
109
+
110
+ * Float data
111
+ typestr == '>f4'
112
+ descr == [('','>f4')]
113
+
114
+ * Complex double
115
+ typestr == '>c8'
116
+ descr == [('real','>f4'), ('imag','>f4')]
117
+
118
+ * RGB Pixel data
119
+ typestr == '|V3'
120
+ descr == [('r','|u1'), ('g','|u1'), ('b','|u1')]
121
+
122
+ * Mixed endian (weird but could happen).
123
+ typestr == '|V8' (or '>u8')
124
+ descr == [('big','>i4'), ('little','<i4')]
125
+
126
+ * Nested structure
127
+ struct {
128
+ int ival;
129
+ struct {
130
+ unsigned short sval;
131
+ unsigned char bval;
132
+ unsigned char cval;
133
+ } sub;
134
+ }
135
+ typestr == '|V8' (or '<u8' if you want)
136
+ descr == [('ival','<i4'), ('sub', [('sval','<u2'), ('bval','|u1'), ('cval','|u1') ]) ]
137
+
138
+ * Nested array
139
+ struct {
140
+ int ival;
141
+ double data[16*4];
142
+ }
143
+ typestr == '|V516'
144
+ descr == [('ival','>i4'), ('data','>f8',(16,4))]
145
+
146
+ * Padded structure
147
+ struct {
148
+ int ival;
149
+ double dval;
150
+ }
151
+ typestr == '|V16'
152
+ descr == [('ival','>i4'),('','|V4'),('dval','>f8')]
153
+ */
154
+ const dataTypeToNumpyDescr = new Map([
155
+ ["float32", "<f4"],
156
+ ["float64", "<f8"],
157
+ ["int8", "<i1"],
158
+ ["int16", "<i2"],
159
+ ["int32", "<i4"],
160
+ ["int64", "<i8"],
161
+ ["uint8", "<u1"],
162
+ ["uint16", "<u2"],
163
+ ["uint32", "<u4"],
164
+ ["uint64", "<u8"],
165
+ ["bool", "|b1"],
166
+ ]);
167
+ /*
168
+ function array2Npy (tensor) {
169
+ const versionStr = "\x01\x00"; // version 1.0
170
+ const shapeStr = tensor.shape.join(",") + ","
171
+ const descr = dataTypeToNumpyDescr.get(tensor.dtype);
172
+ const header = "{'descr':"+descr+", 'fortran_order': false, 'shape': ("+shapeStr+"), }"
173
+ const unpaddedLength = MAGIC_STRING.length + versionStr.length + 2 + header.length;
174
+ // Spaces to 16-bit align.
175
+ const padding = " ".repeat((16 - (unpaddedLength % 16)) % 16)
176
+ header += padding;
177
+ // Number of bytes is in the Numpy descr
178
+ const bytesPerElement = Number.parseInt(descr[2], 10)
179
+ const dataLen = bytesPerElement * getTotalCells(tensor.shape)
180
+ const totalSize = unpaddedLength + padding.length + dataLen
181
+ const arrayBuffer = new ArrayBuffer(totalSize)
182
+ const view = new DataView(arrayBuffer)
183
+ let pos = writeStrToDataView(view, MAGIC_STRING + versionStr, 0)
184
+ view.setUint16(pos, header.length, true);
185
+ pos += 2 + writeStrToDataView(view, header, pos);
186
+ const setDataView = view.setDataView[dataTypes[descr].setDataView];
187
+ for (let i = 0; i < data.length; i++) {
188
+ view.setDataView(pos,data[i],true)
189
+ pos += bytesPerElement;
190
+ }
191
+ return arrayBuffer;
192
+ }
193
+ */
194
+ function writeStrToDataView(dataView, str, pos) {
195
+ const sl=str.length
196
+ for (let i = 0; i < sl; i++) {
197
+ dataView.setInt8(pos + i, str.charCodeAt(i));
198
+ }
199
+ return pos + sl;
200
+ }
201
+ function NumPy (tensor){
202
+ this.fortran_order=false
203
+ this.version=defaultVersion
204
+ return this.parse(tensor)
205
+ }
206
+ NumPy.prototype.getBytes4DataType = function(){
207
+ const descr = dataTypeToNumpyDescr.get(this.dtype);
208
+ return Number.parseInt(descr[2], 10)
209
+ }
210
+ NumPy.prototype.getDesc = function() {
211
+ return dataTypeToNumpyDescr.get(this.dtype);
212
+ }
213
+ NumPy.prototype.setDType = function(dataType) {
214
+ this.dataType=dataType
215
+ const descr=dataTypeToNumpyDescr.get(this.dataType);
216
+ if(descr==null) throw Error("data type not found for "+dataType)
217
+ this.setDescr(descr)
218
+ return this
219
+ }
220
+ NumPy.prototype.setDescr = function(descr) {
221
+ this.descr=descr
222
+ const dataTypeDetails = dataTypes[this.descr];
223
+ this.dataType=dataTypeDetails.name
224
+ this.setDataView = dataTypeDetails.setDataView;
225
+ this.cellConstructor = dataTypeDetails.cellConstructor
226
+ this.bytes4DataType = Number.parseInt(this.descr[2], 10)
227
+ return this
228
+ }
229
+ NumPy.prototype.toNpy = function () {
230
+ const versionStr = "\x01\x00"; // version 1.0
231
+ const shapeStr = this.shape.join(",") + ","
232
+ let header = "{'descr':"+this.descr+", 'fortran_order': false, 'shape': ("+shapeStr+"), }"
233
+ const unpaddedLength = MAGIC_STRING.length + versionStr.length + 2 + header.length;
234
+ // 16-bit align with spaces
235
+ header += " ".repeat((16 - (unpaddedLength % 16)) % 16);
236
+ // SIze of Npy
237
+ const totalSize = header.length + this.bytes4DataType * getTotalCells(this.shape)
238
+ // const totalSize = unpaddedLength + padding.length + this.bytes4DataType * getTotalCells(this.shape)
239
+ const arrayBuffer = new ArrayBuffer(totalSize)
240
+ const view = new DataView(arrayBuffer)
241
+ let pos = writeStrToDataView(view, MAGIC_STRING + defaultVersionStr, 0)
242
+ view.setUint16(pos, header.length, true);
243
+ pos += 2 + writeStrToDataView(view, header, pos);
244
+ const data=this.dataVector
245
+ // const setDataView = view[this.setDataView];
246
+ for (let i = 0; i < data.length; i++) {
247
+ // setDataView(pos,data[i],true)
248
+ view[pos]=data[i]
249
+ pos += this.bytes4DataType;
250
+ }
251
+ return arrayBuffer;
252
+ }
253
+ NumPy.prototype.toNpyBuffer = function () {
254
+ return Buffer.from(this.toNpy())
255
+ }
256
+ NumPy.prototype.parse = function(contentIn={dataType:"int8",
257
+ shape:[1],
258
+ dataVector:new int8Array(0)}) {
259
+ if(!contentIn instanceof Object) throw Error("not an object")
260
+ if(contentIn.hasOwnProperty("dataVector")) {
261
+ Object.assign(this,contentIn)
262
+ if(contentIn.dataType) this.setDType(contentIn.dataType)
263
+ else if(contentIn.descr) this.setDescr(contentIn.descr)
264
+ else throw Error("data type not defined")
265
+ if(this.shape==null) this.shape=[1];
266
+ return this
267
+ }
268
+ return this.parseNpy(contentIn)
269
+ }
270
+ NumPy.prototype.parseNpy = function(npyContentIn) {
271
+ // this.npyContent=npyContentIn instanceof ArrayBuffer ? npyContentIn : bufferToArrayBuffer(npyContentIn)
272
+ this.npyContent=npyContentIn instanceof ArrayBuffer ? npyContentIn : npyContentIn.toBufferArray()
273
+ const headerLength = new DataView(this.npyContent.slice(8, 10)).getUint8(0)
274
+ const offsetBytes = 10 + headerLength;
275
+ const headerContents = new TextDecoder("utf-8").decode(
276
+ new Uint8Array(this.npyContent.slice(10, 10 + headerLength))
277
+ );
278
+ const header = JSON.parse(
279
+ headerContents
280
+ .toLowerCase() // True -> true
281
+ .replace(/'/g, '"')
282
+ .replace("(", "[")
283
+ .replace(/,*\),*/g, "]")
284
+ );
285
+ this.setDescr(header.descr);
286
+ this.shape = header.shape
287
+ this.dataVector=new this.cellConstructor(this.npyContent, offsetBytes)
288
+ if(header.fortran_order) this.fortran_order=header.fortran_order
289
+ return this
290
+ }
291
+ NumPy.prototype.toSerializable = function() {
292
+ return {
293
+ dataType:this.dataType,
294
+ fortran_order: this.fortran_order,
295
+ shape:this.shape,
296
+ version:this.version,
297
+ dataVector:this.dataVector
298
+ }
299
+ }
300
+ NumPy.prototype.toString = function() {
301
+ return JSON.stringify(this.toSerializable())
302
+ }
303
+ module.exports=NumPy;