bfj 4.2.0 → 4.2.4

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/HISTORY.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # History
2
2
 
3
+ ## 4.2.4
4
+
5
+ * chore: update deps (c3eeeb4)
6
+
7
+ ## 4.2.3
8
+
9
+ * fix: eliminate costly string concatenation (42998d7)
10
+ * fix: micro-optimise eventify::proceed::after (98a2519)
11
+ * fix: micro-optimise walk::character (8d1c4cf)
12
+
13
+ ## 4.2.2
14
+
15
+ * fix: silence obnoxious unhandled rejection warnings (1d4a902)
16
+
17
+ ## 4.2.1
18
+
19
+ * refactor: discard chunks more aggressively (970a964)
20
+
3
21
  ## 4.2.0
4
22
 
5
23
  * chore: add a unit test for parallel object references (e8f3895)
package/README.md CHANGED
@@ -548,14 +548,6 @@ of an object,
548
548
  is analagous to the
549
549
  [reviver parameter for JSON.parse][reviver].
550
550
 
551
- * `options.discard`:
552
- The number of characters
553
- to process before
554
- discarding them
555
- to save memory.
556
- The default value
557
- is `1048576`.
558
-
559
551
  * `options.yieldRate`:
560
552
  The number of data items to process
561
553
  before yielding to the event loop.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bfj",
3
- "version": "4.2.0",
3
+ "version": "4.2.4",
4
4
  "description": "Big-friendly JSON. Asynchronous streaming functions for large JSON data sets.",
5
5
  "homepage": "https://github.com/philbooth/bfj",
6
6
  "bugs": "https://github.com/philbooth/bfj/issues",
@@ -30,14 +30,14 @@
30
30
  },
31
31
  "dependencies": {
32
32
  "check-types": "^7.3.0",
33
- "hoopy": "^0.1.1",
34
- "trier": "^0.3.6"
33
+ "hoopy": "^0.1.2",
34
+ "tryer": "^1.0.0"
35
35
  },
36
36
  "devDependencies": {
37
- "eslint": "3.19.x",
38
- "mocha": "3.2.x",
39
- "chai": "3.5.x",
40
- "mockery": "2.0.x",
37
+ "eslint": "4.6.x",
38
+ "mocha": "3.5.x",
39
+ "chai": "4.1.x",
40
+ "mockery": "2.1.x",
41
41
  "spooks": "2.0.x",
42
42
  "please-release-me": "1.0.x",
43
43
  "request": "2.81.x"
package/src/eventify.js CHANGED
@@ -114,21 +114,20 @@ function eventify (data, options) {
114
114
  return literal(coerced)
115
115
  }
116
116
 
117
- const type = typeof coerced
118
-
119
- if (type === 'number') {
120
- return value(coerced, type)
121
- }
122
-
123
- if (type === 'string') {
124
- return value(escapeString(coerced), type)
125
- }
126
-
127
117
  if (Array.isArray(coerced)) {
128
118
  return array(coerced)
129
119
  }
130
120
 
131
- return object(coerced)
121
+ const type = typeof coerced
122
+
123
+ switch (type) {
124
+ case 'number':
125
+ return value(coerced, type)
126
+ case 'string':
127
+ return value(escapeString(coerced), type)
128
+ default:
129
+ return object(coerced)
130
+ }
132
131
  }
133
132
  }
134
133
 
package/src/parse.js CHANGED
@@ -17,9 +17,6 @@ module.exports = parse
17
17
  *
18
18
  * @option reviver: Transformation function, invoked depth-first.
19
19
  *
20
- * @option discard: The number of characters to process before discarding
21
- * them to save memory. The default value is `1048576`.
22
- *
23
20
  * @option yieldRate: The number of data items to process per timeslice,
24
21
  * default is 16384.
25
22
  **/
package/src/read.js CHANGED
@@ -16,9 +16,6 @@ module.exports = read
16
16
  *
17
17
  * @option reviver: Transformation function, invoked depth-first.
18
18
  *
19
- * @option discard: The number of characters to process before discarding them
20
- * to save memory. The default value is `1048576`.
21
- *
22
19
  * @option yieldRate: The number of data items to process per timeslice,
23
20
  * default is 16384.
24
21
  **/
package/src/streamify.js CHANGED
@@ -5,7 +5,7 @@ const eventify = require('./eventify')
5
5
  const events = require('./events')
6
6
  const JsonStream = require('./jsonstream')
7
7
  const Hoopy = require('hoopy')
8
- const trier = require('trier')
8
+ const tryer = require('tryer')
9
9
 
10
10
  const DEFAULT_BUFFER_LENGTH = 1048576
11
11
 
@@ -167,7 +167,7 @@ function streamify (data, options = {}) {
167
167
  isPaused = true
168
168
  return new Promise(resolve => {
169
169
  const unpause = emitter.pause()
170
- trier.attempt({
170
+ tryer({
171
171
  interval: -10,
172
172
  until () {
173
173
  return length + 1 <= json.length
package/src/stringify.js CHANGED
@@ -34,7 +34,7 @@ function stringify (data, options) {
34
34
  let resolve, reject
35
35
 
36
36
  const stream = streamify(data, options)
37
- let json = ''
37
+ const json = []
38
38
 
39
39
  stream.on('data', read)
40
40
  stream.on('end', end)
@@ -46,11 +46,11 @@ function stringify (data, options) {
46
46
  })
47
47
 
48
48
  function read (chunk) {
49
- json += chunk
49
+ json.push(chunk)
50
50
  }
51
51
 
52
52
  function end () {
53
- resolve(json)
53
+ resolve(json.join(''))
54
54
  }
55
55
 
56
56
  function error (e) {
package/src/walk.js CHANGED
@@ -33,9 +33,6 @@ module.exports = initialise
33
33
  *
34
34
  * @param stream: Readable instance representing the incoming JSON.
35
35
  *
36
- * @option discard: The number of characters to process before discarding
37
- * them to save memory. The default value is `1048576`.
38
- *
39
36
  * @option yieldRate: The number of data items to process per timeslice,
40
37
  * default is 16384.
41
38
  **/
@@ -44,7 +41,6 @@ function initialise (stream, options) {
44
41
 
45
42
  options = options || {}
46
43
 
47
- let json = ''
48
44
  let index = 0
49
45
  let isStreamEnded = false
50
46
  let isWalkBegun = false
@@ -52,7 +48,10 @@ function initialise (stream, options) {
52
48
  let isWalkingString = false
53
49
  let count = 0
54
50
  let resumeFn
51
+ let cachedCharacter
55
52
 
53
+ const json = []
54
+ const lengths = []
56
55
  const currentPosition = {
57
56
  line: 1,
58
57
  column: 1
@@ -64,7 +63,6 @@ function initialise (stream, options) {
64
63
  obj: property
65
64
  }
66
65
  const emitter = new EventEmitter()
67
- const discardThreshold = options.discard || 1048576
68
66
  const yieldRate = options.yieldRate || 16384
69
67
 
70
68
  stream.setEncoding('utf8')
@@ -74,7 +72,7 @@ function initialise (stream, options) {
74
72
  return emitter
75
73
 
76
74
  function readStream (chunk) {
77
- json += chunk
75
+ addChunk(chunk)
78
76
 
79
77
  if (!isWalkBegun) {
80
78
  isWalkBegun = true
@@ -84,6 +82,26 @@ function initialise (stream, options) {
84
82
  return resume()
85
83
  }
86
84
 
85
+ function addChunk (chunk) {
86
+ json.push(chunk)
87
+
88
+ const chunkLength = chunk.length
89
+ lengths.push({
90
+ item: chunkLength,
91
+ aggregate: length() + chunkLength
92
+ })
93
+ }
94
+
95
+ function length () {
96
+ const chunkCount = lengths.length
97
+
98
+ if (chunkCount === 0) {
99
+ return 0
100
+ }
101
+
102
+ return lengths[chunkCount - 1].aggregate
103
+ }
104
+
87
105
  function value () {
88
106
  /* eslint-disable no-underscore-dangle */
89
107
  if (++count % yieldRate !== 0) {
@@ -121,7 +139,7 @@ function initialise (stream, options) {
121
139
  function awaitCharacter () {
122
140
  let resolve, reject
123
141
 
124
- if (index < json.length) {
142
+ if (index < length()) {
125
143
  return Promise.resolve()
126
144
  }
127
145
 
@@ -138,7 +156,7 @@ function initialise (stream, options) {
138
156
  })
139
157
 
140
158
  function after () {
141
- if (index < json.length) {
159
+ if (index < length()) {
142
160
  return resolve()
143
161
  }
144
162
 
@@ -151,7 +169,21 @@ function initialise (stream, options) {
151
169
  }
152
170
 
153
171
  function character () {
154
- return json[index]
172
+ if (cachedCharacter) {
173
+ return cachedCharacter
174
+ }
175
+
176
+ if (lengths[0].item > index) {
177
+ return cachedCharacter = json[0][index]
178
+ }
179
+
180
+ const len = lengths.length
181
+ for (let i = 1; i < len; ++i) {
182
+ const { aggregate, item } = lengths[i]
183
+ if (aggregate > index) {
184
+ return cachedCharacter = json[i][index + item - aggregate]
185
+ }
186
+ }
155
187
  }
156
188
 
157
189
  function next () {
@@ -160,6 +192,7 @@ function initialise (stream, options) {
160
192
  function after () {
161
193
  const result = character()
162
194
 
195
+ cachedCharacter = null
163
196
  index += 1
164
197
  previousPosition.line = currentPosition.line
165
198
  previousPosition.column = currentPosition.column
@@ -171,9 +204,13 @@ function initialise (stream, options) {
171
204
  currentPosition.column += 1
172
205
  }
173
206
 
174
- if (index === discardThreshold) {
175
- json = json.substring(index)
176
- index = 0
207
+ if (index > lengths[0].aggregate) {
208
+ json.shift()
209
+
210
+ const difference = lengths.shift().item
211
+ index -= difference
212
+
213
+ lengths.forEach(len => len.aggregate -= difference)
177
214
  }
178
215
 
179
216
  return result
@@ -320,7 +357,7 @@ function initialise (stream, options) {
320
357
 
321
358
  function walkString (event) {
322
359
  let isEscaping = false
323
- let str = ''
360
+ const str = []
324
361
 
325
362
  isWalkingString = true
326
363
 
@@ -331,7 +368,7 @@ function initialise (stream, options) {
331
368
  isEscaping = false
332
369
 
333
370
  return escape(char).then(escaped => {
334
- str += escaped
371
+ str.push(escaped)
335
372
  return next().then(step)
336
373
  })
337
374
  }
@@ -342,12 +379,12 @@ function initialise (stream, options) {
342
379
  }
343
380
 
344
381
  if (char !== '"') {
345
- str += char
382
+ str.push(char)
346
383
  return next().then(step)
347
384
  }
348
385
 
349
386
  isWalkingString = false
350
- emitter.emit(event, str)
387
+ emitter.emit(event, str.join(''))
351
388
  }
352
389
  }
353
390
 
@@ -365,19 +402,21 @@ function initialise (stream, options) {
365
402
  }
366
403
 
367
404
  function escapeHex () {
368
- let hexits = ''
405
+ let hexits = []
369
406
 
370
407
  return next().then(step.bind(null, 0))
371
408
 
372
409
  function step (idx, char) {
373
410
  if (isHexit(char)) {
374
- hexits += char
411
+ hexits.push(char)
375
412
  }
376
413
 
377
414
  if (idx < 3) {
378
415
  return next().then(step.bind(null, idx + 1))
379
416
  }
380
417
 
418
+ hexits = hexits.join('')
419
+
381
420
  if (hexits.length === 4) {
382
421
  return String.fromCharCode(parseInt(hexits, 16))
383
422
  }
@@ -393,12 +432,12 @@ function initialise (stream, options) {
393
432
  }
394
433
 
395
434
  function number (firstCharacter) {
396
- let digits = firstCharacter
435
+ let digits = [ firstCharacter ]
397
436
 
398
437
  return walkDigits().then(addDigits.bind(null, checkDecimalPlace))
399
438
 
400
439
  function addDigits (step, result) {
401
- digits += result.digits
440
+ digits = digits.concat(result.digits)
402
441
 
403
442
  if (result.atEnd) {
404
443
  return endNumber()
@@ -410,7 +449,7 @@ function initialise (stream, options) {
410
449
  function checkDecimalPlace () {
411
450
  if (character() === '.') {
412
451
  return next().then(char => {
413
- digits += char
452
+ digits.push(char)
414
453
  walkDigits().then(addDigits.bind(null, checkExponent))
415
454
  })
416
455
  }
@@ -421,7 +460,7 @@ function initialise (stream, options) {
421
460
  function checkExponent () {
422
461
  if (character() === 'e' || character() === 'E') {
423
462
  return next().then(char => {
424
- digits += char
463
+ digits.push(char)
425
464
  awaitCharacter()
426
465
  .then(checkSign)
427
466
  .catch(fail.bind(null, 'EOF', 'exponent', currentPosition))
@@ -434,7 +473,7 @@ function initialise (stream, options) {
434
473
  function checkSign () {
435
474
  if (character() === '+' || character() === '-') {
436
475
  return next().then(char => {
437
- digits += char
476
+ digits.push(char)
438
477
  readExponent()
439
478
  })
440
479
  }
@@ -447,13 +486,13 @@ function initialise (stream, options) {
447
486
  }
448
487
 
449
488
  function endNumber () {
450
- emitter.emit(events.number, parseFloat(digits))
489
+ emitter.emit(events.number, parseFloat(digits.join('')))
451
490
  return endValue()
452
491
  }
453
492
  }
454
493
 
455
494
  function walkDigits () {
456
- let digits = ''
495
+ const digits = []
457
496
 
458
497
  return wait()
459
498
 
@@ -466,7 +505,7 @@ function initialise (stream, options) {
466
505
  function step () {
467
506
  if (isDigit(character())) {
468
507
  return next().then(char => {
469
- digits += char
508
+ digits.push(char)
470
509
  return wait()
471
510
  })
472
511
  }
package/test/unit/read.js CHANGED
@@ -148,7 +148,7 @@ suite('read with error thrown by fs.createReadStream:', () => {
148
148
 
149
149
  test('read does not throw', () => {
150
150
  assert.doesNotThrow(() => {
151
- read()
151
+ read().catch(() => {})
152
152
  })
153
153
  })
154
154
 
@@ -9,7 +9,7 @@ const modulePath = '../../src/streamify'
9
9
  mockery.registerAllowable(modulePath)
10
10
  mockery.registerAllowable('hoopy')
11
11
  mockery.registerAllowable('check-types')
12
- mockery.registerAllowable('trier')
12
+ mockery.registerAllowable('tryer')
13
13
  mockery.registerAllowable('./events')
14
14
 
15
15
  suite('streamify:', () => {
@@ -290,7 +290,7 @@ suite('write with error thrown by fs.createWriteStream:', () => {
290
290
 
291
291
  test('write does not throw', () => {
292
292
  assert.doesNotThrow(() => {
293
- write()
293
+ write().catch(() => {})
294
294
  })
295
295
  })
296
296