@alexgyver/bson 2.0.1 → 2.1.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.
package/bson.js CHANGED
@@ -1,39 +1,52 @@
1
+ const BS_STRING = (0 << 5);
2
+ const BS_BOOLEAN = (1 << 5);
3
+ const BS_INTEGER = (2 << 5);
4
+ const BS_FLOAT = (3 << 5);
5
+ const BS_CODE = (4 << 5);
6
+ const BS_BINARY = (5 << 5);
7
+ const BS_CONTAINER = (6 << 5);
8
+ const BS_NULL = (7 << 5);
9
+
10
+ const BS_CONT_OBJ = (1 << 4);
11
+ const BS_CONT_OPEN = (1 << 3);
12
+ const BS_CONT_ARR = (1 << 2);
13
+ const BS_CONT_CLOSE = (1 << 1);
14
+
15
+ const BS_MAX_LEN = 0b0001111111111111;
16
+
17
+ const BS_TYPE_MASK = 0b11100000;
18
+ const BS_TYPE = x => x & BS_TYPE_MASK;
19
+ const BS_DATA_MASK = 0b00011111;
20
+ const BS_DATA = x => x & BS_DATA_MASK;
21
+
22
+ const BS_BOOLV_MASK = 0b1;
23
+ const BS_BOOLV = x => x & BS_BOOLV_MASK;
24
+
25
+ const BS_NEG_MASK = 0b10000;
26
+ const BS_NEGATIVE = x => x & BS_NEG_MASK;
27
+ const BS_SIZE_MASK = 0b01111;
28
+ const BS_SIZE = x => x & BS_SIZE_MASK;
29
+
30
+ const BS_FLOAT_SIZE = 4;
31
+ const BS_DEC_MASK = 0b1111;
32
+ const BS_DECIMAL = x => x & BS_DEC_MASK;
33
+
34
+ const BS_D16_MSB = x => (x >> 8) & BS_DATA_MASK;
35
+ const BS_D16_LSB = x => x & 0xff;
36
+ const BS_D16_MERGE = (msb5, lsb) => ((msb5 << 8) | lsb) >>> 0;
37
+
38
+ const BS_BIN_PREFIX = "__BSON_BIN_";
39
+ const BS_CODE_PREFIX = "__BSON_CODE_";
40
+
1
41
  /**
2
42
  * @param {Uint8Array} b
3
43
  * @param {Array} codes
4
44
  * @returns {Object}
5
45
  */
6
- export default function decodeBson(b, codes = []) {
46
+ export function decodeBson(b, codes = []) {
7
47
  if (!b || !(b instanceof Uint8Array)) return null;
8
48
  if (!b.length) return {};
9
49
 
10
- const BS_STRING = (0 << 5);
11
- const BS_BOOLEAN = (1 << 5);
12
- const BS_INTEGER = (2 << 5);
13
- const BS_FLOAT = (3 << 5);
14
- const BS_CODE = (4 << 5);
15
- const BS_BINARY = (5 << 5);
16
- const BS_CONTAINER = (6 << 5);
17
-
18
- const BS_CONT_OBJ = (1 << 4);
19
- const BS_CONT_OPEN = (1 << 3);
20
- const BS_NEGATIVE = (1 << 4);
21
- const BS_BIN_PREFIX = "__BSON_BINARY";
22
-
23
- function unpack5(msb5, lsb) {
24
- return ((msb5 << 8) | lsb) >>> 0;
25
- }
26
- function makeBins(obj, bins) {
27
- if (typeof obj !== 'object') return;
28
- for (let k in obj) {
29
- if (typeof obj[k] === "object" && obj[k] !== null) {
30
- makeBins(obj[k], bins);
31
- } else if (typeof obj[k] === "string" && obj[k].startsWith(BS_BIN_PREFIX)) {
32
- obj[k] = bins[obj[k].split('#')[1]];
33
- }
34
- }
35
- }
36
-
37
50
  let bins = [];
38
51
  let stack = [];
39
52
  let keyf = true;
@@ -41,8 +54,8 @@ export default function decodeBson(b, codes = []) {
41
54
 
42
55
  try {
43
56
  for (let i = 0; i < b.length; i++) {
44
- const type = b[i] & 0b11100000;
45
- const data = b[i] & 0b00011111;
57
+ const type = BS_TYPE(b[i]);
58
+ const data = BS_DATA(b[i]);
46
59
 
47
60
  switch (type) {
48
61
 
@@ -61,24 +74,18 @@ export default function decodeBson(b, codes = []) {
61
74
  continue;
62
75
 
63
76
  case BS_CODE:
64
- s += '"' + codes[unpack5(data, b[++i])] + '"';
77
+ s += '"' + codes[BS_D16_MERGE(data, b[++i])] + '"';
65
78
  break;
66
79
 
67
80
  case BS_STRING: {
68
- let len = unpack5(data, b[++i]);
69
- let txt = new TextDecoder().decode(b.slice(i + 1, i + 1 + len));
70
- txt = txt.replaceAll(/([^\\])\\([^\"\\nrt])/ig, "$1\\\\$2")
71
- .replaceAll(/\t/ig, "\\t")
72
- .replaceAll(/\n/ig, "\\n")
73
- .replaceAll(/\r/ig, "\\r")
74
- .replaceAll(/([^\\])(")/ig, '$1\\"');
75
- s += '"' + txt + '"';
81
+ let len = BS_D16_MERGE(data, b[++i]);
82
+ s += JSON.stringify(new TextDecoder().decode(b.slice(i + 1, i + 1 + len)));
76
83
  i += len;
77
84
  } break;
78
85
 
79
86
  case BS_INTEGER: {
80
- if (data & BS_NEGATIVE) s += '-';
81
- let len = data & 0b1111;
87
+ if (BS_NEGATIVE(data)) s += '-';
88
+ let len = BS_SIZE(data);
82
89
  let u8 = new Uint8Array(8);
83
90
  u8.set(b.slice(i + 1, i + 1 + len));
84
91
  s += new BigUint64Array(u8.buffer)[0];
@@ -86,19 +93,24 @@ export default function decodeBson(b, codes = []) {
86
93
  } break;
87
94
 
88
95
  case BS_BOOLEAN:
89
- s += (data & 0b1) ? 'true' : 'false';
96
+ s += BS_BOOLV(data) ? 'true' : 'false';
97
+ break;
98
+
99
+ case BS_NULL:
100
+ s += 'null';
90
101
  break;
91
102
 
92
103
  case BS_FLOAT: {
93
- let f = new Float32Array(b.slice(i + 1, i + 1 + 4).buffer)[0];
94
- s += (isNaN(f) || !isFinite(f)) ? 'null' : f.toFixed(data);
95
- i += 4;
104
+ let f = new DataView(b.buffer, b.byteOffset + i + 1, BS_FLOAT_SIZE).getFloat32(0, true);
105
+ s += (isNaN(f) || !isFinite(f)) ? 'null' : f.toFixed(BS_DECIMAL(data));
106
+ i += BS_FLOAT_SIZE;
107
+
96
108
  } break;
97
109
 
98
110
  case BS_BINARY: {
99
- let len = unpack5(data, b[++i]);
111
+ let len = BS_D16_MERGE(data, b[++i]);
100
112
  i++;
101
- s += '"' + BS_BIN_PREFIX + '#' + bins.length + '"';
113
+ s += '"' + BS_BIN_PREFIX + bins.length + '"';
102
114
  bins.push(b.slice(i, i + len));
103
115
  i += len - 1;
104
116
  } break;
@@ -113,7 +125,7 @@ export default function decodeBson(b, codes = []) {
113
125
  }
114
126
  }
115
127
  } catch (e) {
116
- console.log(e, s);
128
+ console.error(e, s);
117
129
  throw new Error("BSON decode error");
118
130
  }
119
131
 
@@ -121,10 +133,107 @@ export default function decodeBson(b, codes = []) {
121
133
 
122
134
  try {
123
135
  let obj = JSON.parse(s);
124
- if (bins.length) makeBins(obj, bins);
136
+ if (bins.length) _makeBins(obj, bins);
125
137
  return obj;
126
138
  } catch (e) {
127
- console.log(e, s);
139
+ console.error(e, s);
128
140
  throw new Error("JSON parse error");
129
141
  }
142
+ }
143
+
144
+ function _makeBins(obj, bins) {
145
+ if (typeof obj !== 'object') return;
146
+ for (let k in obj) {
147
+ if (typeof obj[k] === "object" && obj[k] !== null) {
148
+ _makeBins(obj[k], bins);
149
+ } else if (typeof obj[k] === "string" && obj[k].startsWith(BS_BIN_PREFIX)) {
150
+ obj[k] = bins[obj[k].slice(BS_BIN_PREFIX.length)];
151
+ }
152
+ }
153
+ }
154
+
155
+ /**
156
+ * @param {*} val
157
+ * @returns {Uint8Array}
158
+ */
159
+ export function encodeBson(val) {
160
+ let arr = [];
161
+ _encode(val, arr);
162
+ return Uint8Array.from(arr);
163
+ }
164
+
165
+ function _encode(val, arr) {
166
+ if (Array.isArray(val)) {
167
+ arr.push(BS_CONTAINER | BS_CONT_ARR | BS_CONT_OPEN);
168
+ val.forEach(v => _encode(v, arr));
169
+ arr.push(BS_CONTAINER | BS_CONT_ARR | BS_CONT_CLOSE);
170
+ return;
171
+ }
172
+
173
+ switch (typeof val) {
174
+ case 'object':
175
+ if (val === null) {
176
+ arr.push(BS_NULL);
177
+ } else if (val instanceof Uint8Array) {
178
+ const len = Math.min(val.length, BS_MAX_LEN);
179
+ arr.push(BS_BINARY | BS_D16_MSB(len));
180
+ arr.push(BS_D16_LSB(len));
181
+ arr.push(...val.slice(0, len));
182
+ } else {
183
+ arr.push(BS_CONTAINER | BS_CONT_OBJ | BS_CONT_OPEN);
184
+ for (const [key, value] of Object.entries(val)) {
185
+ _encode(key, arr);
186
+ _encode(value, arr);
187
+ }
188
+ arr.push(BS_CONTAINER | BS_CONT_OBJ | BS_CONT_CLOSE);
189
+ }
190
+ break;
191
+
192
+ case 'bigint':
193
+ case 'number':
194
+ if (Number.isInteger(val)) {
195
+ val = BigInt(val);
196
+ const neg = val < 0;
197
+ if (neg) val = -val;
198
+ let bytes = [];
199
+ while (val) {
200
+ bytes.push(Number(val & 0xFFn));
201
+ val >>= 8n;
202
+ }
203
+ arr.push(BS_INTEGER | (neg ? BS_NEG_MASK : 0) | bytes.length);
204
+ arr.push(...bytes);
205
+ } else {
206
+ const buffer = new ArrayBuffer(BS_FLOAT_SIZE);
207
+ new DataView(buffer).setFloat32(0, val, true);
208
+ arr.push(BS_FLOAT | 4);
209
+ arr.push(...new Uint8Array(buffer));
210
+ }
211
+ break;
212
+
213
+ case 'string':
214
+ if (val.startsWith(BS_CODE_PREFIX)) {
215
+ let code = Number(val.slice(BS_CODE_PREFIX.length));
216
+ arr.push(BS_CODE | BS_D16_MSB(code));
217
+ arr.push(BS_D16_LSB(code));
218
+ } else {
219
+ const bytes = new TextEncoder().encode(val);
220
+ const len = Math.min(bytes.length, BS_MAX_LEN);
221
+ arr.push(BS_STRING | BS_D16_MSB(len));
222
+ arr.push(BS_D16_LSB(len));
223
+ arr.push(...bytes.slice(0, len));
224
+ }
225
+ break;
226
+
227
+ case 'boolean':
228
+ arr.push(BS_BOOLEAN | (val ? 1 : 0));
229
+ break;
230
+
231
+ default:
232
+ arr.push(BS_NULL);
233
+ break;
234
+ }
235
+ }
236
+
237
+ export function getCode(name, codes) {
238
+ return BS_CODE_PREFIX + codes.indexOf(name);
130
239
  }
package/bson.min.js ADDED
@@ -0,0 +1 @@
1
+ var e={d:(t,r)=>{for(var n in r)e.o(r,n)&&!e.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:r[n]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)},t={};e.d(t,{$R:()=>U,QC:()=>C,lo:()=>F});const r=0,n=32,s=64,o=96,a=128,c=160,i=192,l=224,u=16,h=8,f=4,p=2,b=8191,g=e=>224&e,y=e=>31&e,d=e=>1&e,w=16,O=e=>e&w,N=e=>15&e,k=4,A=e=>15&e,B=e=>e>>8&31,m=e=>255&e,_=(e,t)=>(e<<8|t)>>>0,j="__BSON_BIN_",x="__BSON_CODE_";function F(e,t=[]){if(!(e&&e instanceof Uint8Array))return null;if(!e.length)return{};let f=[],p=[],b=!0,w="";try{for(let B=0;B<e.length;B++){const m=g(e[B]),x=y(e[B]);switch(m){case i:if(x&h){let e=x&u?"{":"[";w+=e,p.push(e)}else","==w[w.length-1]&&(w=w.slice(0,-1)),w+=(x&u?"}":"]")+",",p.pop();b=!0;continue;case a:w+='"'+t[_(x,e[++B])]+'"';break;case r:{let t=_(x,e[++B]);w+=JSON.stringify((new TextDecoder).decode(e.slice(B+1,B+1+t))),B+=t}break;case s:{O(x)&&(w+="-");let t=N(x),r=new Uint8Array(8);r.set(e.slice(B+1,B+1+t)),w+=new BigUint64Array(r.buffer)[0],B+=t}break;case n:w+=d(x)?"true":"false";break;case l:w+="null";break;case o:{let t=new DataView(e.buffer,e.byteOffset+B+1,k).getFloat32(0,!0);w+=isNaN(t)||!isFinite(t)?"null":t.toFixed(A(x)),B+=k}break;case c:{let t=_(x,e[++B]);B++,w+='"'+j+f.length+'"',f.push(e.slice(B,B+t)),B+=t-1}}"{"===p[p.length-1]?(w+=b?":":",",b=!b):w+=","}}catch(e){throw console.error(e,w),new Error("BSON decode error")}","==w[w.length-1]&&(w=w.slice(0,-1));try{let e=JSON.parse(w);return f.length&&S(e,f),e}catch(e){throw console.error(e,w),new Error("JSON parse error")}}function S(e,t){if("object"==typeof e)for(let r in e)"object"==typeof e[r]&&null!==e[r]?S(e[r],t):"string"==typeof e[r]&&e[r].startsWith(j)&&(e[r]=t[e[r].slice(j.length)])}function U(e){let t=[];return E(e,t),Uint8Array.from(t)}function E(e,t){if(Array.isArray(e))return t.push(i|f|h),e.forEach(e=>E(e,t)),void t.push(i|f|p);switch(typeof e){case"object":if(null===e)t.push(l);else if(e instanceof Uint8Array){const r=Math.min(e.length,b);t.push(c|B(r)),t.push(m(r)),t.push(...e.slice(0,r))}else{t.push(i|u|h);for(const[r,n]of Object.entries(e))E(r,t),E(n,t);t.push(i|u|p)}break;case"bigint":case"number":if(Number.isInteger(e)){const r=(e=BigInt(e))<0;r&&(e=-e);let n=[];for(;e;)n.push(Number(0xFFn&e)),e>>=8n;t.push(s|(r?w:0)|n.length),t.push(...n)}else{const r=new ArrayBuffer(k);new DataView(r).setFloat32(0,e,!0),t.push(4|o),t.push(...new Uint8Array(r))}break;case"string":if(e.startsWith(x)){let r=Number(e.slice(x.length));t.push(a|B(r)),t.push(m(r))}else{const n=(new TextEncoder).encode(e),s=Math.min(n.length,b);t.push(r|B(s)),t.push(m(s)),t.push(...n.slice(0,s))}break;case"boolean":t.push(n|(e?1:0));break;default:t.push(l)}}function C(e,t){return x+t.indexOf(e)}const D=t.lo,v=t.$R,I=t.QC;export{D as decodeBson,v as encodeBson,I as getCode};
package/package.json CHANGED
@@ -1,14 +1,21 @@
1
1
  {
2
2
  "name": "@alexgyver/bson",
3
- "version": "2.0.1",
3
+ "version": "2.1.0",
4
4
  "description": "Decode BSON from BSON Arduino library",
5
5
  "main": "./bson.js",
6
6
  "module": "./bson.js",
7
7
  "types": "./bson.js",
8
+ "scripts": {
9
+ "build": "webpack --config ./webpack.config.js"
10
+ },
8
11
  "repository": {
9
12
  "type": "git",
10
13
  "url": "git+https://github.com/GyverLibs/bson.js.git"
11
14
  },
15
+ "devDependencies": {
16
+ "webpack": "^5.98.0",
17
+ "webpack-cli": "^6.0.1"
18
+ },
12
19
  "author": "AlexGyver <alex@alexgyver.ru>",
13
20
  "license": "MIT"
14
21
  }
package/test.html CHANGED
@@ -5,7 +5,8 @@
5
5
  <p id="out" style="white-space: break-spaces;"></p>
6
6
 
7
7
  <script type="module">
8
- import decodeBson from '/bson.js';
8
+ import { decodeBson, encodeBson, getCode } from 'https://gyverlibs.github.io/bson.js/dist/bson.js';
9
+ // import { decodeBson, encodeBson, getCode } from '/bson.js';
9
10
 
10
11
  const url = 'http://192.168.1.54';
11
12
 
@@ -15,6 +16,34 @@
15
16
  'constants',
16
17
  ];
17
18
 
19
+ // =========== getCode ===========
20
+ console.log(getCode('constants', codes));
21
+
22
+ // =========== encode ===========
23
+ let test = {
24
+ int: 123,
25
+ float: 3.14,
26
+ arr: [
27
+ "str",
28
+ true,
29
+ 1234,
30
+ new Uint8Array([1, 2, 3]),
31
+ ],
32
+ obj: {
33
+ str2: "str2",
34
+ true: true,
35
+ },
36
+ str3: "str3",
37
+ nul: null,
38
+ [getCode('constants', codes)]: getCode('string', codes),
39
+ bins: new Uint8Array([1, 2, 3]),
40
+ };
41
+
42
+ let enc = encodeBson(test);
43
+ let json = decodeBson(enc, codes);
44
+ console.log(json);
45
+
46
+ // =========== request ===========
18
47
  req.onclick = async () => {
19
48
  let res = await fetch(url + '/bson');
20
49
  try {
@@ -0,0 +1,14 @@
1
+ module.exports = {
2
+ entry: './bson.js',
3
+ output: {
4
+ path: __dirname,
5
+ filename: 'bson.min.js',
6
+ library: {
7
+ type: 'module'
8
+ }
9
+ },
10
+ experiments: {
11
+ outputModule: true
12
+ },
13
+ mode: "production",
14
+ };