@dra2020/baseclient 1.0.13 → 1.0.14

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 (185) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +37 -0
  3. package/dist/all/all.d.ts +36 -0
  4. package/dist/all/allclient.d.ts +18 -0
  5. package/dist/base.js +33010 -0
  6. package/dist/base.js.map +1 -0
  7. package/dist/baseclient.js +8991 -0
  8. package/dist/baseclient.js.map +1 -0
  9. package/dist/context/all.d.ts +1 -0
  10. package/dist/context/context.d.ts +13 -0
  11. package/dist/dbabstract/all.d.ts +1 -0
  12. package/dist/dbabstract/db.d.ts +83 -0
  13. package/dist/dbdynamo/all.d.ts +1 -0
  14. package/dist/dbdynamo/dbdynamo.d.ts +190 -0
  15. package/dist/filterexpr/all.d.ts +1 -0
  16. package/dist/filterexpr/filterexpr.d.ts +64 -0
  17. package/dist/fsm/all.d.ts +1 -0
  18. package/dist/fsm/fsm.d.ts +118 -0
  19. package/dist/fsmfile/all.d.ts +1 -0
  20. package/dist/fsmfile/fsmfile.d.ts +47 -0
  21. package/dist/jsonstream/all.d.ts +1 -0
  22. package/dist/jsonstream/jsonstream.d.ts +130 -0
  23. package/dist/lambda/all.d.ts +1 -0
  24. package/dist/lambda/env.d.ts +10 -0
  25. package/dist/lambda/lambda.d.ts +18 -0
  26. package/dist/logabstract/all.d.ts +1 -0
  27. package/dist/logabstract/log.d.ts +26 -0
  28. package/dist/logclient/all.d.ts +1 -0
  29. package/dist/logclient/log.d.ts +6 -0
  30. package/dist/logserver/all.d.ts +5 -0
  31. package/dist/logserver/log.d.ts +11 -0
  32. package/dist/logserver/logaccum.d.ts +154 -0
  33. package/dist/logserver/logblob.d.ts +24 -0
  34. package/dist/logserver/logconcat.d.ts +55 -0
  35. package/dist/logserver/logkey.d.ts +28 -0
  36. package/dist/memsqs/all.d.ts +4 -0
  37. package/dist/memsqs/client.d.ts +13 -0
  38. package/dist/memsqs/loopback.d.ts +11 -0
  39. package/dist/memsqs/orderedlist.d.ts +19 -0
  40. package/dist/memsqs/queue.d.ts +84 -0
  41. package/dist/memsqs/server.d.ts +37 -0
  42. package/dist/ot-editutil/all.d.ts +2 -0
  43. package/dist/ot-editutil/oteditutil.d.ts +14 -0
  44. package/dist/ot-editutil/otmaputil.d.ts +21 -0
  45. package/dist/ot-js/all.d.ts +9 -0
  46. package/dist/ot-js/otarray.d.ts +111 -0
  47. package/dist/ot-js/otclientengine.d.ts +38 -0
  48. package/dist/ot-js/otcomposite.d.ts +37 -0
  49. package/dist/ot-js/otcounter.d.ts +17 -0
  50. package/dist/ot-js/otengine.d.ts +22 -0
  51. package/dist/ot-js/otmap.d.ts +19 -0
  52. package/dist/ot-js/otserverengine.d.ts +38 -0
  53. package/dist/ot-js/otsession.d.ts +111 -0
  54. package/dist/ot-js/ottypes.d.ts +29 -0
  55. package/dist/poly/all.d.ts +15 -0
  56. package/dist/poly/blend.d.ts +1 -0
  57. package/dist/poly/boundbox.d.ts +16 -0
  58. package/dist/poly/cartesian.d.ts +5 -0
  59. package/dist/poly/graham-scan.d.ts +8 -0
  60. package/dist/poly/hash.d.ts +1 -0
  61. package/dist/poly/matrix.d.ts +24 -0
  62. package/dist/poly/minbound.d.ts +1 -0
  63. package/dist/poly/poly.d.ts +52 -0
  64. package/dist/poly/polybin.d.ts +5 -0
  65. package/dist/poly/polylabel.d.ts +7 -0
  66. package/dist/poly/polypack.d.ts +30 -0
  67. package/dist/poly/polyround.d.ts +1 -0
  68. package/dist/poly/polysimplify.d.ts +1 -0
  69. package/dist/poly/quad.d.ts +48 -0
  70. package/dist/poly/selfintersect.d.ts +1 -0
  71. package/dist/poly/shamos.d.ts +1 -0
  72. package/dist/poly/simplify.d.ts +2 -0
  73. package/dist/poly/topo.d.ts +46 -0
  74. package/dist/poly/union.d.ts +48 -0
  75. package/dist/storage/all.d.ts +4 -0
  76. package/dist/storage/datablob.d.ts +9 -0
  77. package/dist/storage/env.d.ts +10 -0
  78. package/dist/storage/splitsblob.d.ts +13 -0
  79. package/dist/storage/storage.d.ts +166 -0
  80. package/dist/storages3/all.d.ts +1 -0
  81. package/dist/storages3/s3.d.ts +62 -0
  82. package/dist/util/all.d.ts +5 -0
  83. package/dist/util/bintrie.d.ts +93 -0
  84. package/dist/util/countedhash.d.ts +19 -0
  85. package/dist/util/gradient.d.ts +15 -0
  86. package/dist/util/indexedarray.d.ts +15 -0
  87. package/dist/util/util.d.ts +68 -0
  88. package/docs/context.md +2 -0
  89. package/docs/dbabstract.md +2 -0
  90. package/docs/dbdynamo.md +2 -0
  91. package/docs/fsm.md +243 -0
  92. package/docs/fsmfile.md +2 -0
  93. package/docs/jsonstream.md +44 -0
  94. package/docs/lambda.md +2 -0
  95. package/docs/logabstract.md +2 -0
  96. package/docs/logclient.md +2 -0
  97. package/docs/logserver.md +2 -0
  98. package/docs/ot-editutil.md +2 -0
  99. package/docs/ot-js.md +95 -0
  100. package/docs/poly.md +103 -0
  101. package/docs/storage.md +2 -0
  102. package/docs/storages3.md +2 -0
  103. package/docs/util.md +2 -0
  104. package/lib/all/all.ts +41 -0
  105. package/lib/all/allclient.ts +19 -0
  106. package/lib/context/all.ts +1 -0
  107. package/lib/context/context.ts +82 -0
  108. package/lib/dbabstract/all.ts +1 -0
  109. package/lib/dbabstract/db.ts +246 -0
  110. package/lib/dbdynamo/all.ts +1 -0
  111. package/lib/dbdynamo/dbdynamo.ts +1551 -0
  112. package/lib/filterexpr/all.ts +1 -0
  113. package/lib/filterexpr/filterexpr.ts +625 -0
  114. package/lib/fsm/all.ts +1 -0
  115. package/lib/fsm/fsm.ts +549 -0
  116. package/lib/fsmfile/all.ts +1 -0
  117. package/lib/fsmfile/fsmfile.ts +236 -0
  118. package/lib/jsonstream/all.ts +1 -0
  119. package/lib/jsonstream/jsonstream.ts +940 -0
  120. package/lib/lambda/all.ts +1 -0
  121. package/lib/lambda/env.ts +13 -0
  122. package/lib/lambda/lambda.ts +120 -0
  123. package/lib/logabstract/all.ts +1 -0
  124. package/lib/logabstract/log.ts +55 -0
  125. package/lib/logclient/all.ts +1 -0
  126. package/lib/logclient/log.ts +105 -0
  127. package/lib/logserver/all.ts +5 -0
  128. package/lib/logserver/log.ts +565 -0
  129. package/lib/logserver/logaccum.ts +1445 -0
  130. package/lib/logserver/logblob.ts +84 -0
  131. package/lib/logserver/logconcat.ts +313 -0
  132. package/lib/logserver/logkey.ts +125 -0
  133. package/lib/memsqs/all.ts +4 -0
  134. package/lib/memsqs/client.ts +268 -0
  135. package/lib/memsqs/loopback.ts +64 -0
  136. package/lib/memsqs/orderedlist.ts +74 -0
  137. package/lib/memsqs/queue.ts +395 -0
  138. package/lib/memsqs/server.ts +262 -0
  139. package/lib/ot-editutil/all.ts +2 -0
  140. package/lib/ot-editutil/oteditutil.ts +180 -0
  141. package/lib/ot-editutil/otmaputil.ts +209 -0
  142. package/lib/ot-js/all.ts +9 -0
  143. package/lib/ot-js/otarray.ts +1168 -0
  144. package/lib/ot-js/otclientengine.ts +327 -0
  145. package/lib/ot-js/otcomposite.ts +247 -0
  146. package/lib/ot-js/otcounter.ts +145 -0
  147. package/lib/ot-js/otengine.ts +71 -0
  148. package/lib/ot-js/otmap.ts +144 -0
  149. package/lib/ot-js/otserverengine.ts +329 -0
  150. package/lib/ot-js/otsession.ts +199 -0
  151. package/lib/ot-js/ottypes.ts +98 -0
  152. package/lib/poly/all.ts +15 -0
  153. package/lib/poly/blend.ts +27 -0
  154. package/lib/poly/boundbox.ts +102 -0
  155. package/lib/poly/cartesian.ts +130 -0
  156. package/lib/poly/graham-scan.ts +401 -0
  157. package/lib/poly/hash.ts +15 -0
  158. package/lib/poly/matrix.ts +309 -0
  159. package/lib/poly/minbound.ts +211 -0
  160. package/lib/poly/poly.ts +767 -0
  161. package/lib/poly/polybin.ts +218 -0
  162. package/lib/poly/polylabel.ts +204 -0
  163. package/lib/poly/polypack.ts +458 -0
  164. package/lib/poly/polyround.ts +30 -0
  165. package/lib/poly/polysimplify.ts +24 -0
  166. package/lib/poly/quad.ts +272 -0
  167. package/lib/poly/selfintersect.ts +87 -0
  168. package/lib/poly/shamos.ts +297 -0
  169. package/lib/poly/simplify.ts +119 -0
  170. package/lib/poly/topo.ts +525 -0
  171. package/lib/poly/union.ts +371 -0
  172. package/lib/storage/all.ts +4 -0
  173. package/lib/storage/datablob.ts +36 -0
  174. package/lib/storage/env.ts +14 -0
  175. package/lib/storage/splitsblob.ts +63 -0
  176. package/lib/storage/storage.ts +604 -0
  177. package/lib/storages3/all.ts +1 -0
  178. package/lib/storages3/s3.ts +576 -0
  179. package/lib/util/all.ts +5 -0
  180. package/lib/util/bintrie.ts +603 -0
  181. package/lib/util/countedhash.ts +83 -0
  182. package/lib/util/gradient.ts +108 -0
  183. package/lib/util/indexedarray.ts +80 -0
  184. package/lib/util/util.ts +695 -0
  185. package/package.json +8 -8
@@ -0,0 +1,940 @@
1
+ // Node libraries
2
+ import * as Stream from 'stream';
3
+ import * as Events from 'events';
4
+
5
+ // Shared libraries
6
+ import * as Util from '../util/all';
7
+
8
+ // Acts like Stream.Readable, emits 'error', 'close', 'data', 'end'
9
+ export class Readable extends Events.EventEmitter
10
+ {
11
+ constructor()
12
+ {
13
+ super();
14
+ }
15
+ }
16
+
17
+ // Acts like Stream.Writable, emits 'error', 'close', 'drain', 'finish''
18
+ export class Writable extends Events.EventEmitter
19
+ {
20
+ constructor()
21
+ {
22
+ super();
23
+ }
24
+
25
+ // override
26
+ write(b: any, encoding?: BufferEncoding, cb?: () => void): boolean
27
+ {
28
+ return true;
29
+ }
30
+
31
+ // override
32
+ end(): void
33
+ {
34
+ this.emit('finish');
35
+ }
36
+ }
37
+
38
+ // Useful class for having JSONStreamWriter generate a Buffer
39
+ export class BufferWritable extends Writable
40
+ {
41
+ _bufs: Buffer[];
42
+ _buf: Buffer;
43
+
44
+ constructor()
45
+ {
46
+ super();
47
+ this._bufs = [];
48
+ this._buf = null;
49
+ }
50
+
51
+ write(b: any, encoding?: BufferEncoding, cb?: () => void): boolean
52
+ {
53
+ if (typeof b === 'string')
54
+ b = Buffer.from(b as string, encoding);
55
+ this._bufs.push(b as Buffer);
56
+ if (this._bufs.length > 100) this._bufs = [ Buffer.concat(this._bufs) ];
57
+ return true;
58
+ }
59
+
60
+ end(): void
61
+ {
62
+ this._buf = Buffer.concat(this._bufs);
63
+ this.emit('finish', this._buf);
64
+ }
65
+ }
66
+
67
+ // Useful class for having JSONStreamReader read from an existing Buffer
68
+ export class BufferReadable extends Stream.Readable
69
+ {
70
+ _b: Buffer;
71
+
72
+ constructor(b: Buffer)
73
+ {
74
+ super({});
75
+ this._b = b;
76
+ }
77
+
78
+ _read(): void
79
+ {
80
+ if (this._b)
81
+ {
82
+ this.push(this._b);
83
+ this.push(null);
84
+ this._b = null;
85
+ }
86
+ }
87
+ }
88
+
89
+ export class MultiBufferReadable extends Stream.Readable
90
+ {
91
+ constructor()
92
+ {
93
+ super({});
94
+ }
95
+
96
+ _read(): void
97
+ {
98
+ }
99
+
100
+ more(buf: Buffer): void
101
+ {
102
+ this.push(buf);
103
+ }
104
+
105
+ end(): void
106
+ {
107
+ this.push(null);
108
+ }
109
+ }
110
+
111
+ enum ReadState {
112
+ Start,
113
+ ObjectPropertyStart,
114
+ ObjectPropertyEnd,
115
+ ValueStart,
116
+ ValueEnd,
117
+ InName,
118
+ InNameBackslash,
119
+ NeedColon,
120
+ InNumber,
121
+ InString,
122
+ InStringBackslash,
123
+ InTrue,
124
+ InFalse,
125
+ InNull,
126
+ InUndefined,
127
+ Error,
128
+ Ended
129
+ };
130
+
131
+ const CurlyOpen = 123;
132
+ const CurlyClose = 125;
133
+ const SquareOpen = 91;
134
+ const SquareClose = 93;
135
+ const Comma = 44;
136
+ const Colon = 58;
137
+ const Quote = 34;
138
+ const Backslash = 92;
139
+ const Forwardslash = 47
140
+ const Zero = 48;
141
+ const Nine = 57;
142
+ const Minus = 45;
143
+ const Plus = 43;
144
+ const Period = 46;
145
+ const UpperA = 65;
146
+ const LowerA = 97;
147
+ const UpperB = 66;
148
+ const LowerB = 98;
149
+ const UpperE = 69;
150
+ const LowerE = 101;
151
+ const UpperF = 70;
152
+ const LowerF = 102;
153
+ const UpperN = 78;
154
+ const LowerN = 110;
155
+ const UpperR = 82;
156
+ const LowerR = 114;
157
+ const UpperT = 84;
158
+ const LowerT = 116;
159
+ const UpperU = 85;
160
+ const LowerU = 117;
161
+ const UpperZ = 90;
162
+ const LowerZ = 122;
163
+ const Space = 32;
164
+ const Backspace = 8;
165
+ const Tab = 9;
166
+ const Newline = 10;
167
+ const CR = 13;
168
+
169
+
170
+ function isWhite(c: number): boolean
171
+ {
172
+ return c == Space || c == Newline || c == Tab || c == CR;
173
+ }
174
+
175
+ function isEscapable(c: number): number
176
+ {
177
+ switch (c)
178
+ {
179
+ case Quote: return Quote;
180
+ case Backslash: return Backslash;
181
+ case Forwardslash: return Forwardslash;
182
+ case UpperB:
183
+ case LowerB: return Backspace;
184
+ case UpperT:
185
+ case LowerT: return Tab;
186
+ case UpperN:
187
+ case LowerN: return Newline;
188
+ case UpperR:
189
+ case LowerR: return CR;
190
+
191
+ // TODO: Really should support unicode \uHHHH
192
+ default:
193
+ return -1;
194
+ }
195
+ }
196
+
197
+ function isNumeric(c: number): boolean
198
+ {
199
+ return (c >= Zero && c <= Nine) || c == Minus || c == Plus || c == UpperE || c == LowerE || c == Period;
200
+ }
201
+
202
+ function isAlpha(c: number): boolean
203
+ {
204
+ return (c >= UpperA && c <= UpperZ) || (c >= LowerA && c <= LowerZ);
205
+ }
206
+
207
+ enum TokType { TTNone, TTArray, TTObject, TTName, TTString, TTNumber, TTTrue, TTFalse, TTNull, TTUndefined };
208
+
209
+ interface Token
210
+ {
211
+ tt: TokType;
212
+ v: any;
213
+ emit?: string;
214
+ }
215
+
216
+ export interface JSONStreamOptions
217
+ {
218
+ maxTokenSize?: number;
219
+ outBufferSize?: number;
220
+ encoding?: BufferEncoding;
221
+ syncChunkSize?: number;
222
+ }
223
+
224
+ const DefaultStreamOptions: JSONStreamOptions =
225
+ {
226
+ maxTokenSize: 10000,
227
+ outBufferSize: 10000,
228
+ encoding: 'utf8',
229
+ syncChunkSize: 10000,
230
+ }
231
+
232
+ export class JSONStreamReader extends Events.EventEmitter
233
+ {
234
+ _s: Readable;
235
+ _charCount: number;
236
+ _lineCount: number;
237
+ _state: ReadState;
238
+ _tok: Buffer;
239
+ _tokLen: number;
240
+ _stack: Token[];
241
+ _result: any;
242
+ _incr: any;
243
+ _options: JSONStreamOptions;
244
+ _chunks: Buffer[];
245
+ _chunkCur: number;
246
+ _chunkIndex: number;
247
+ _chunkScheduled: boolean;
248
+ _ended: boolean;
249
+ _closed: boolean;
250
+
251
+ constructor(options?: JSONStreamOptions)
252
+ {
253
+ super();
254
+ this.onData = this.onData.bind(this);
255
+ this.onClose = this.onClose.bind(this);
256
+ this.onEnd = this.onEnd.bind(this);
257
+ this.onError = this.onError.bind(this);
258
+ this.nextChunk = this.nextChunk.bind(this);
259
+ this._state = ReadState.Start;
260
+ this._charCount = 1;
261
+ this._lineCount = 1;
262
+ this._stack = [];
263
+ this._result = undefined;
264
+ this._incr = {};
265
+ this._options = Util.shallowAssignImmutable(DefaultStreamOptions, options);
266
+ this._tok = Buffer.alloc(this._options.maxTokenSize);
267
+ this._tokLen = 0;
268
+ this._s = undefined;
269
+ this._chunks = [];
270
+ this._chunkCur = 0;
271
+ this._chunkIndex = 0;
272
+ this._chunkScheduled = false;
273
+ this._ended = false;
274
+ this._closed = false;
275
+ }
276
+
277
+ start(s: Readable): void
278
+ {
279
+ this._s = s;
280
+ this._s.on('close', this.onClose);
281
+ this._s.on('end', this.onEnd);
282
+ this._s.on('error', this.onError);
283
+ this._s.on('data', this.onData);
284
+ }
285
+
286
+ finish(): void
287
+ {
288
+ this._s.off('close', this.onClose);
289
+ this._s.off('end', this.onEnd);
290
+ this._s.off('error', this.onError);
291
+ this._s.off('data', this.onData);
292
+ this._s = undefined;
293
+ }
294
+
295
+ emitIncremental(name: string): void
296
+ {
297
+ this._incr[name] = true;
298
+ }
299
+
300
+ pushToken(tok: Token): void
301
+ {
302
+ this._stack.push(tok);
303
+ if (tok.tt == TokType.TTArray || tok.tt == TokType.TTObject)
304
+ {
305
+ let prevTok: Token = this._stack.length > 1 ? this._stack[this._stack.length - 2] : null;
306
+ if (prevTok && prevTok.tt == TokType.TTName && this._incr[prevTok.v] == true)
307
+ tok.emit = prevTok.v;
308
+ else if (prevTok == null && this._incr[''] == true) // special-case top-level object
309
+ tok.emit = '';
310
+ }
311
+ }
312
+
313
+ private badJSON(detail?: string): void
314
+ {
315
+ this._state = ReadState.Error;
316
+ if (detail !== undefined)
317
+ this.emit('error', `Invalid JSON (${detail}) at line ${this._lineCount}, character ${this._charCount}`);
318
+ else
319
+ this.emit('error', `Invalid JSON at line ${this._lineCount}, character ${this._charCount}`);
320
+ this.finish();
321
+ }
322
+
323
+ private startTok(s: ReadState, c?: number): void
324
+ {
325
+ this._state = s;
326
+ if (c !== undefined)
327
+ this.addToTok(c);
328
+ }
329
+
330
+ private addToTok(c: number): void
331
+ {
332
+ if (this._tokLen == this._options.maxTokenSize)
333
+ this.badJSON('token too long');
334
+ else
335
+ {
336
+ this._tok.writeUInt8(c, this._tokLen);
337
+ this._tokLen++;
338
+ }
339
+ }
340
+
341
+ private consumeTok(): string
342
+ {
343
+ let s: string = this._tok.toString(this._options.encoding, 0, this._tokLen);
344
+ this._tokLen = 0;
345
+ return s;
346
+ }
347
+
348
+ private produceValue(tok: Token): void
349
+ {
350
+ if (this._stack.length == 0)
351
+ {
352
+ this._state = ReadState.Ended;
353
+ this._result = tok.v;
354
+ }
355
+ else
356
+ {
357
+ this._state = ReadState.ValueEnd;
358
+ let topTok: Token = this._stack[this._stack.length - 1];
359
+ if (topTok.tt == TokType.TTArray)
360
+ {
361
+ if (topTok.emit !== undefined)
362
+ this.emit('array', topTok.emit, tok.v);
363
+ else
364
+ topTok.v.push(tok.v);
365
+ }
366
+ else if (topTok.tt == TokType.TTName)
367
+ {
368
+ let p: string = topTok.v;
369
+ this._stack.pop();
370
+ topTok = this._stack[this._stack.length - 1];
371
+ if (topTok.tt != TokType.TTObject)
372
+ this.badJSON();
373
+ else
374
+ {
375
+ if (topTok.emit !== undefined)
376
+ this.emit('object', topTok.emit, p, tok.v);
377
+ else
378
+ topTok.v[p] = tok.v;
379
+ }
380
+ }
381
+ }
382
+ }
383
+
384
+ private produceValidatedValue(tok: Token): void
385
+ {
386
+ let s: string = tok.v;
387
+ switch (tok.tt)
388
+ {
389
+ case TokType.TTNumber:
390
+ // TODO: Constrained parsing: [-]{0 | [1-9][0-9]*}[.[0-9]+][{e|E}[+-][0-9]+]
391
+ // Optional leading minus, either zero or set of digits not starting with zero.
392
+ // Optional decimal point with required digit sequence
393
+ // Optional exponent, e or E, optional sign, required digit sequence
394
+ tok.v = parseFloat(s);
395
+ break;
396
+
397
+ case TokType.TTNull:
398
+ if (s != 'null')
399
+ this.badJSON('bad value');
400
+ else
401
+ tok.v = null;
402
+ break;
403
+
404
+ case TokType.TTUndefined:
405
+ if (s != 'undefined')
406
+ this.badJSON('bad value');
407
+ else
408
+ tok.v = undefined;
409
+ break;
410
+
411
+ case TokType.TTTrue:
412
+ if (s != 'true')
413
+ this.badJSON('bad value');
414
+ else
415
+ tok.v = true;
416
+ break;
417
+
418
+ case TokType.TTFalse:
419
+ if (s != 'false')
420
+ this.badJSON('bad value');
421
+ else
422
+ tok.v = false;
423
+ break;
424
+ }
425
+
426
+ if (this._state != ReadState.Error)
427
+ this.produceValue(tok);
428
+ }
429
+
430
+ private onData(chunk: Buffer): void
431
+ {
432
+ this._chunks.push(chunk);
433
+ this.nextChunk();
434
+ }
435
+
436
+ private scheduleNext(): void
437
+ {
438
+ if (this._state != ReadState.Error && this._chunkCur < this._chunks.length)
439
+ {
440
+ if (! this._chunkScheduled)
441
+ {
442
+ this._chunkScheduled = true;
443
+ setImmediate(this.nextChunk);
444
+ }
445
+ }
446
+ else if (this._closed)
447
+ this.doClose();
448
+ else if (this._ended)
449
+ this.doEnd();
450
+ }
451
+
452
+ private nextChunk(): void
453
+ {
454
+ this._chunkScheduled = false;
455
+ if (this._chunkCur >= this._chunks.length)
456
+ {
457
+ this.scheduleNext();
458
+ return;
459
+ }
460
+
461
+ let chunk = this._chunks[this._chunkCur];
462
+ let i = this._chunkIndex;
463
+ let e = i + this._options.syncChunkSize;
464
+ if (e > chunk.length) e = chunk.length;
465
+
466
+ for (; this._state != ReadState.Error && i < e; i++)
467
+ {
468
+ let c: number = chunk[i];
469
+ this._charCount++;
470
+ if (c == 10) { this._lineCount++; this._charCount = 1; }
471
+
472
+ switch (this._state)
473
+ {
474
+ case ReadState.Start:
475
+ if (! isWhite(c))
476
+ if (c === CurlyOpen)
477
+ {
478
+ this.pushToken({ tt: TokType.TTObject, v: {} });
479
+ this._state = ReadState.ObjectPropertyStart;
480
+ }
481
+ else
482
+ this.badJSON(`Unexpected character: ${String.fromCharCode(c)} in chunk ${chunk.toString('utf8')}`);
483
+ break;
484
+
485
+ case ReadState.ObjectPropertyStart:
486
+ if (! isWhite(c))
487
+ switch (c)
488
+ {
489
+ case Quote:
490
+ this.startTok(ReadState.InName);
491
+ break;
492
+ case CurlyClose:
493
+ this.produceValue(this._stack.pop());
494
+ break;
495
+ default:
496
+ this.badJSON();
497
+ }
498
+ break;
499
+
500
+ case ReadState.ValueEnd:
501
+ if (! isWhite(c))
502
+ {
503
+ let topTok: Token = this._stack[this._stack.length - 1];
504
+ if (c == Comma)
505
+ this._state = topTok.tt == TokType.TTArray ? ReadState.ValueStart : ReadState.ObjectPropertyStart;
506
+ else if ((c == SquareClose && topTok.tt == TokType.TTArray) || (c == CurlyClose && topTok.tt == TokType.TTObject))
507
+ this.produceValue(this._stack.pop());
508
+ else
509
+ this.badJSON(`missing comma or ending ${topTok.tt == TokType.TTArray ? 'square' : 'curly'} bracket`);
510
+ }
511
+ break;
512
+
513
+ case ReadState.ValueStart:
514
+ if (! isWhite(c))
515
+ {
516
+ if (c == CurlyOpen)
517
+ {
518
+ this.pushToken({ tt: TokType.TTObject, v: {} });
519
+ this._state = ReadState.ObjectPropertyStart;
520
+ }
521
+ else if (c == SquareOpen)
522
+ {
523
+ this.pushToken({ tt: TokType.TTArray, v: [] });
524
+ this._state = ReadState.ValueStart;
525
+ }
526
+ else if (c == SquareClose)
527
+ {
528
+ // Could be in array (good) or expecting value of object property (bad)
529
+ let topTok: Token = this._stack[this._stack.length - 1];
530
+ if (topTok.tt == TokType.TTArray)
531
+ this.produceValue(this._stack.pop());
532
+ else
533
+ this.badJSON(`Unexpected character: ${String.fromCharCode(c)} in chunk ${chunk.toString('utf8')}`);
534
+ }
535
+ else if (c == Quote)
536
+ this.startTok(ReadState.InString);
537
+ else if (c == UpperT || c == LowerT)
538
+ this.startTok(ReadState.InTrue, c);
539
+ else if (c == UpperF || c == LowerF)
540
+ this.startTok(ReadState.InFalse, c);
541
+ else if (c == UpperN || c == LowerN)
542
+ this.startTok(ReadState.InNull, c);
543
+ else if (c == UpperU || c == LowerU)
544
+ this.startTok(ReadState.InUndefined, c);
545
+ else if (isNumeric(c))
546
+ this.startTok(ReadState.InNumber, c);
547
+ else
548
+ this.badJSON();
549
+ }
550
+ break;
551
+
552
+ case ReadState.InName:
553
+ if (c == Backslash)
554
+ this._state = ReadState.InNameBackslash;
555
+ else if (c != Quote)
556
+ this.addToTok(c);
557
+ else
558
+ {
559
+ this.pushToken({ tt: TokType.TTName, v: this.consumeTok() });
560
+ this._state = ReadState.NeedColon;
561
+ }
562
+ break;
563
+
564
+ case ReadState.InNameBackslash:
565
+ {
566
+ // TODO: add hex encoding support
567
+ let escC = isEscapable(c);
568
+ if (escC < 0)
569
+ this.badJSON(`Illegal escaped character: ${String.fromCharCode(c)}`);
570
+ this.addToTok(escC);
571
+ this._state = ReadState.InName;
572
+ }
573
+ break;
574
+
575
+ case ReadState.NeedColon:
576
+ if (! isWhite(c))
577
+ if (c !== Colon)
578
+ this.badJSON('expected colon');
579
+ else
580
+ this._state = ReadState.ValueStart;
581
+ break;
582
+
583
+ case ReadState.InNumber:
584
+ if (isNumeric(c))
585
+ this.addToTok(c);
586
+ else
587
+ {
588
+ this.produceValidatedValue({ tt: TokType.TTNumber, v: this.consumeTok() });
589
+ i--;
590
+ }
591
+ break;
592
+
593
+ case ReadState.InString:
594
+ if (c == Backslash)
595
+ this._state = ReadState.InStringBackslash;
596
+ else if (c != Quote)
597
+ this.addToTok(c);
598
+ else
599
+ this.produceValue({ tt: TokType.TTString, v: this.consumeTok() });
600
+ break;
601
+
602
+ case ReadState.InStringBackslash:
603
+ {
604
+ // TODO: add hex encoding support
605
+ let escC = isEscapable(c);
606
+ if (escC < 0)
607
+ this.badJSON(`Illegal escaped character: ${String.fromCharCode(c)}`);
608
+ this.addToTok(escC);
609
+ this._state = ReadState.InString;
610
+ }
611
+ break;
612
+
613
+ case ReadState.InTrue:
614
+ if (isAlpha(c))
615
+ this.addToTok(c);
616
+ else
617
+ {
618
+ this.produceValidatedValue({ tt: TokType.TTTrue, v: this.consumeTok() });
619
+ i--;
620
+ }
621
+ break;
622
+
623
+ case ReadState.InFalse:
624
+ if (isAlpha(c))
625
+ this.addToTok(c);
626
+ else
627
+ {
628
+ this.produceValidatedValue({ tt: TokType.TTFalse, v: this.consumeTok() });
629
+ i--;
630
+ }
631
+ break;
632
+
633
+ case ReadState.InNull:
634
+ if (isAlpha(c))
635
+ this.addToTok(c);
636
+ else
637
+ {
638
+ this.produceValidatedValue({ tt: TokType.TTNull, v: this.consumeTok() });
639
+ i--;
640
+ }
641
+ break;
642
+
643
+ case ReadState.InUndefined:
644
+ if (isAlpha(c))
645
+ this.addToTok(c);
646
+ else
647
+ {
648
+ this.produceValidatedValue({ tt: TokType.TTUndefined, v: this.consumeTok() });
649
+ i--;
650
+ }
651
+ break;
652
+
653
+ case ReadState.Ended:
654
+ if (! isWhite(c))
655
+ this.badJSON('unexpected character after end of object');
656
+ break;
657
+ }
658
+ }
659
+
660
+ // Potentially advance to next chunk and schedule next processing slice
661
+ if (this._state === ReadState.Error)
662
+ {
663
+ this._chunks = [];
664
+ this._chunkCur = 0;
665
+ this._chunkIndex = 0;
666
+ }
667
+ else
668
+ {
669
+ if (e === chunk.length)
670
+ {
671
+ this._chunkIndex = 0;
672
+ if (this._chunkCur === this._chunks.length - 1)
673
+ {
674
+ this._chunks = [];
675
+ this._chunkCur = 0;
676
+ }
677
+ else
678
+ {
679
+ this._chunkCur++;
680
+ if (this._chunkCur >= 100)
681
+ {
682
+ this._chunks.splice(0, this._chunkCur);
683
+ this._chunkCur = 0;
684
+ }
685
+ }
686
+ }
687
+ else
688
+ this._chunkIndex = e;
689
+ }
690
+ this.scheduleNext();
691
+ }
692
+
693
+ private onClose(): void
694
+ {
695
+ this._closed = true;
696
+ this.scheduleNext();
697
+ }
698
+
699
+ private doClose(): void
700
+ {
701
+ this._closed = undefined;
702
+ this.doEnd();
703
+ this.emit('close');
704
+ }
705
+
706
+ private onError(e: Error): void
707
+ {
708
+ this._state = ReadState.Error;
709
+ let s: string = 'stream error';
710
+ if (e && typeof e.message === 'string')
711
+ s = e.message;
712
+ console.log(`jsonreader: emitting error: ${s}`);
713
+ this.emit('error', s);
714
+ this.finish();
715
+ }
716
+
717
+ private onEnd(): void
718
+ {
719
+ this._ended = true;
720
+ this.scheduleNext();
721
+ }
722
+
723
+ private doEnd(): void
724
+ {
725
+ this._ended = undefined;
726
+ if (this._state == ReadState.Ended)
727
+ {
728
+ // Only emit once
729
+ if (this._result !== undefined)
730
+ {
731
+ this.emit('end', this._result);
732
+ this._result = undefined;
733
+ this.finish();
734
+ }
735
+ }
736
+ else if (this._state !== ReadState.Error)
737
+ this.badJSON('Unexpected end of input');
738
+ }
739
+ }
740
+
741
+ interface ObjectWriteState
742
+ {
743
+ o: any;
744
+ keys: string[];
745
+ index: number;
746
+ }
747
+
748
+ export class JSONStreamWriter extends Events.EventEmitter
749
+ {
750
+ _s: Writable;
751
+ _stack: ObjectWriteState[];
752
+ _chunk: Buffer;
753
+ _chunkLen: number;
754
+ _options: JSONStreamOptions;
755
+ _bDone: boolean;
756
+
757
+ constructor(options?: JSONStreamOptions)
758
+ {
759
+ super();
760
+ this._bDone = false;
761
+ this._s = null;
762
+ this._stack = [];
763
+ this.onDrain = this.onDrain.bind(this);
764
+ this.onError = this.onError.bind(this);
765
+ this.onFinish = this.onFinish.bind(this);
766
+ this.onClose = this.onClose.bind(this);
767
+ this._options = Util.shallowAssignImmutable(DefaultStreamOptions, options);
768
+ this._chunk = Buffer.alloc(this._options.outBufferSize);
769
+ this._chunkLen = 0;
770
+ }
771
+
772
+ start(o: any, s: Writable): void
773
+ {
774
+ this._s = s;
775
+ this._s.on('drain', this.onDrain);
776
+ this._stack.push({ o: o, keys: Array.isArray(o) ? null : Object.keys(o), index: 0 });
777
+ this.onDrain();
778
+ }
779
+
780
+ addToChunk(s: string): boolean
781
+ {
782
+ let b = Buffer.from(s as string, this._options.encoding);
783
+ let bContinue: boolean = true;
784
+
785
+ if (b.length + this._chunkLen > this._options.outBufferSize)
786
+ bContinue = this.drainChunk();
787
+
788
+ if (b.length > this._options.outBufferSize)
789
+ throw 'Internal error: atom larger than buffer size';
790
+
791
+ b.copy(this._chunk, this._chunkLen);
792
+ this._chunkLen += b.length;
793
+ return bContinue;
794
+ }
795
+
796
+ drainChunk(): boolean
797
+ {
798
+ if (this._chunkLen > 0)
799
+ {
800
+ let b: Buffer = this._chunk.slice(0, this._chunkLen);
801
+
802
+ // false just indicates backpressure - write still succeeded.
803
+ let bDraining: boolean = this._s.write(b);
804
+
805
+ // Allocate new write buffer to prevent overwriting output buffer before output stream
806
+ // gets chance to copy out the data.
807
+ this._chunk = Buffer.alloc(this._options.outBufferSize);
808
+ this._chunkLen = 0;
809
+
810
+ return bDraining;
811
+ }
812
+ return true;
813
+ }
814
+
815
+ onDrain(): void
816
+ {
817
+ let bContinue: boolean;
818
+
819
+ while (! this._bDone && this._stack.length > 0)
820
+ {
821
+ let top: ObjectWriteState = this._stack[this._stack.length - 1];
822
+
823
+ // Object
824
+ if (top.keys)
825
+ {
826
+ if (top.keys.length == 0)
827
+ bContinue = this.addToChunk('{');
828
+ let bRecurse = false;
829
+ // Even index means propname not written
830
+ while (! this._bDone && top.index < top.keys.length * 2)
831
+ {
832
+ let ii: number = Math.floor(top.index / 2);
833
+ if ((top.index % 2) == 0)
834
+ {
835
+ let s: string = `${top.index == 0 ? '{' : ','}"${top.keys[ii]}":`;
836
+ bContinue = this.addToChunk(s);
837
+ top.index++;
838
+ if (! bContinue)
839
+ return;
840
+ }
841
+ let oo: any = top.o[top.keys[ii]];
842
+ if (oo && typeof oo === 'object')
843
+ {
844
+ bRecurse = true;
845
+ top.index++;
846
+ this._stack.push({ o: oo, keys: Array.isArray(oo) ? null : Object.keys(oo), index: 0 });
847
+ break;
848
+ }
849
+ else
850
+ {
851
+ let s: string = JSON.stringify(oo === undefined ? null : oo);
852
+ bContinue = this.addToChunk(s);
853
+ top.index++;
854
+ if (! bContinue)
855
+ return;
856
+ }
857
+ }
858
+
859
+ if (! bRecurse)
860
+ {
861
+ bContinue = this.addToChunk('}');
862
+ this._stack.pop();
863
+ if (! bContinue)
864
+ return;
865
+ }
866
+ }
867
+
868
+ // Array
869
+ else
870
+ {
871
+ if (top.o.length == 0)
872
+ bContinue = this.addToChunk('[');
873
+ let bRecurse = false;
874
+
875
+ // Even index means separator not written
876
+ while (! this._bDone && top.index < top.o.length * 2)
877
+ {
878
+ let ii: number = Math.floor(top.index / 2);
879
+ if ((top.index % 2) == 0)
880
+ {
881
+ let s: string = top.index == 0 ? '[' : ',';
882
+ bContinue = this.addToChunk(s);
883
+ top.index++;
884
+ if (! bContinue)
885
+ return;
886
+ }
887
+ let oo: any = top.o[ii];
888
+ if (oo && typeof oo === 'object')
889
+ {
890
+ bRecurse = true;
891
+ top.index++;
892
+ this._stack.push({ o: oo, keys: Array.isArray(oo) ? null : Object.keys(oo), index: 0 });
893
+ break;
894
+ }
895
+ else
896
+ {
897
+ let s: string = JSON.stringify(oo === undefined ? null : oo);
898
+ bContinue = this.addToChunk(s);
899
+ top.index++;
900
+ if (! bContinue)
901
+ return;
902
+ }
903
+ }
904
+
905
+ if (! bRecurse)
906
+ {
907
+ bContinue = this.addToChunk(']');
908
+ this._stack.pop();
909
+ if (! bContinue)
910
+ return;
911
+ }
912
+ }
913
+ }
914
+
915
+ this.drainChunk();
916
+ this._s.end();
917
+ }
918
+
919
+ onError(e: Error): void
920
+ {
921
+ this._bDone = true;
922
+ let s: string = 'stream error';
923
+ if (e && typeof e.message === 'string')
924
+ s = e.message;
925
+ console.log(`jsonwriter: emitting error: ${s}`);
926
+ this.emit('error', s);
927
+ }
928
+
929
+ onClose(): void
930
+ {
931
+ this._bDone = true;
932
+ this.emit('close');
933
+ }
934
+
935
+ onFinish(): void
936
+ {
937
+ this._bDone = true;
938
+ this.emit('finish');
939
+ }
940
+ }