903b6d1a61054f237389b4febfc4a36b24bced72aa0978de29577623cf4d5404554e6a42e239edc566dce72032eb4fe9538d0adb03ecf7351f0f24f05bcf58 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963
  1. # BFJ
  2. [![Build status](https://gitlab.com/philbooth/bfj/badges/master/pipeline.svg)](https://gitlab.com/philbooth/bfj/pipelines)
  3. [![Package status](https://img.shields.io/npm/v/bfj.svg)](https://www.npmjs.com/package/bfj)
  4. [![Downloads](https://img.shields.io/npm/dm/bfj.svg)](https://www.npmjs.com/package/bfj)
  5. [![License](https://img.shields.io/npm/l/bfj.svg)](https://opensource.org/licenses/MIT)
  6. Big-Friendly JSON. Asynchronous streaming functions for large JSON data sets.
  7. * [Why would I want those?](#why-would-i-want-those)
  8. * [Is it fast?](#is-it-fast)
  9. * [What functions does it implement?](#what-functions-does-it-implement)
  10. * [How do I install it?](#how-do-i-install-it)
  11. * [How do I read a JSON file?](#how-do-i-read-a-json-file)
  12. * [How do I parse a stream of JSON?](#how-do-i-parse-a-stream-of-json)
  13. * [How do I selectively parse individual items from a JSON stream?](#how-do-i-selectively-parse-individual-items-from-a-json-stream)
  14. * [How do I write a JSON file?](#how-do-i-write-a-json-file)
  15. * [How do I create a stream of JSON?](#how-do-i-create-a-stream-of-json)
  16. * [How do I create a JSON string?](#how-do-i-create-a-json-string)
  17. * [What other methods are there?](#what-other-methods-are-there)
  18. * [bfj.walk (stream, options)](#bfjwalk-stream-options)
  19. * [bfj.eventify (data, options)](#bfjeventify-data-options)
  20. * [What options can I specify?](#what-options-can-i-specify)
  21. * [Options for parsing functions](#options-for-parsing-functions)
  22. * [Options for serialisation functions](#options-for-serialisation-functions)
  23. * [Is it possible to pause parsing or serialisation from calling code?](#is-it-possible-to-pause-parsing-or-serialisation-from-calling-code)
  24. * [Can it handle newline-delimited JSON (NDJSON)?](#can-it-handle-newline-delimited-json-ndjson)
  25. * [Why does it default to bluebird promises?](#why-does-it-default-to-bluebird-promises)
  26. * [Can I specify a different promise implementation?](#can-i-specify-a-different-promise-implementation)
  27. * [Is there a change log?](#is-there-a-change-log)
  28. * [How do I set up the dev environment?](#how-do-i-set-up-the-dev-environment)
  29. * [What versions of Node.js does it support?](#what-versions-of-nodejs-does-it-support)
  30. * [What license is it released under?](#what-license-is-it-released-under)
  31. ## Why would I want those?
  32. If you need
  33. to parse huge JSON strings
  34. or stringify huge JavaScript data sets,
  35. it monopolises the event loop
  36. and can lead to out-of-memory exceptions.
  37. BFJ implements asynchronous functions
  38. and uses pre-allocated fixed-length arrays
  39. to try and alleviate those issues.
  40. ## Is it fast?
  41. No.
  42. BFJ yields frequently
  43. to avoid monopolising the event loop,
  44. interrupting its own execution
  45. to let other event handlers run.
  46. The frequency of those yields
  47. can be controlled with the [`yieldRate` option](#what-options-can-i-specify),
  48. but fundamentally it is not designed for speed.
  49. Furthermore,
  50. when serialising data to a stream,
  51. BFJ uses a fixed-length buffer
  52. to avoid exhausting available memory.
  53. Whenever that buffer is full,
  54. serialisation is paused
  55. until the receiving stream processes some more data,
  56. regardless of the value of `yieldRate`.
  57. You can control the size of the buffer
  58. using the [`bufferLength` option](#options-for-serialisation-functions)
  59. but really,
  60. if you need quick results,
  61. BFJ is not for you.
  62. ## What functions does it implement?
  63. Nine functions
  64. are exported.
  65. Five are
  66. concerned with
  67. parsing, or
  68. turning JSON strings
  69. into JavaScript data:
  70. * [`read`](#how-do-i-read-a-json-file)
  71. asynchronously parses
  72. a JSON file from disk.
  73. * [`parse` and `unpipe`](#how-do-i-parse-a-stream-of-json)
  74. are for asynchronously parsing
  75. streams of JSON.
  76. * [`match`](#how-do-i-selectively-parse-individual-items-from-a-json-stream)
  77. selectively parses individual items
  78. from a JSON stream.
  79. * [`walk`](#bfjwalk-stream-options)
  80. asynchronously walks
  81. a stream,
  82. emitting events
  83. as it encounters
  84. JSON tokens.
  85. Analagous to a
  86. [SAX parser][sax].
  87. The other four functions
  88. handle the reverse transformations,
  89. serialising
  90. JavaScript data
  91. to JSON:
  92. * [`write`](#how-do-i-write-a-json-file)
  93. asynchronously serialises data
  94. to a JSON file on disk.
  95. * [`streamify`](#how-do-i-create-a-stream-of-json)
  96. asynchronously serialises data
  97. to a stream of JSON.
  98. * [`stringify`](#how-do-i-create-a-json-string)
  99. asynchronously serialises data
  100. to a JSON string.
  101. * [`eventify`](#bfjeventify-data-options)
  102. asynchronously traverses
  103. a data structure
  104. depth-first,
  105. emitting events
  106. as it encounters items.
  107. By default
  108. it coerces
  109. promises, buffers and iterables
  110. to JSON-friendly values.
  111. ## How do I install it?
  112. If you're using npm:
  113. ```
  114. npm i bfj --save
  115. ```
  116. Or if you just want
  117. the git repo:
  118. ```
  119. git clone git@gitlab.com:philbooth/bfj.git
  120. ```
  121. ## How do I read a JSON file?
  122. ```js
  123. const bfj = require('bfj');
  124. bfj.read(path, options)
  125. .then(data => {
  126. // :)
  127. })
  128. .catch(error => {
  129. // :(
  130. });
  131. ```
  132. `read` returns a [bluebird promise][promise] and
  133. asynchronously parses
  134. a JSON file
  135. from disk.
  136. It takes two arguments;
  137. the path to the JSON file
  138. and an [options](#options-for-parsing-functions) object.
  139. If there are
  140. no syntax errors,
  141. the returned promise is resolved
  142. with the parsed data.
  143. If syntax errors occur,
  144. the promise is rejected
  145. with the first error.
  146. ## How do I parse a stream of JSON?
  147. ```js
  148. const bfj = require('bfj');
  149. // By passing a readable stream to bfj.parse():
  150. bfj.parse(fs.createReadStream(path), options)
  151. .then(data => {
  152. // :)
  153. })
  154. .catch(error => {
  155. // :(
  156. });
  157. // ...or by passing the result from bfj.unpipe() to stream.pipe():
  158. request({ url }).pipe(bfj.unpipe((error, data) => {
  159. if (error) {
  160. // :(
  161. } else {
  162. // :)
  163. }
  164. }))
  165. ```
  166. * `parse` returns a [bluebird promise][promise]
  167. and asynchronously parses
  168. a stream of JSON data.
  169. It takes two arguments;
  170. a [readable stream][readable]
  171. from which
  172. the JSON
  173. will be parsed
  174. and an [options](#options-for-parsing-functions) object.
  175. If there are
  176. no syntax errors,
  177. the returned promise is resolved
  178. with the parsed data.
  179. If syntax errors occur,
  180. the promise is rejected
  181. with the first error.
  182. * `unpipe` returns a [writable stream][writable]
  183. that can be passed to [`stream.pipe`][pipe],
  184. then parses JSON data
  185. read from the stream.
  186. It takes two arguments;
  187. a callback function
  188. that will be called
  189. after parsing is complete
  190. and an [options](#options-for-parsing-functions) object.
  191. If there are no errors,
  192. the callback is invoked
  193. with the result as the second argument.
  194. If errors occur,
  195. the first error is passed
  196. the callback
  197. as the first argument.
  198. ## How do I selectively parse individual items from a JSON stream?
  199. ```js
  200. const bfj = require('bfj');
  201. // Call match with your stream and a selector predicate/regex/string
  202. const dataStream = bfj.match(jsonStream, selector, options);
  203. // Get data out of the returned stream with event handlers
  204. dataStream.on('data', item => { /* ... */ });
  205. dataStream.on('end', () => { /* ... */);
  206. dataStream.on('error', () => { /* ... */);
  207. dataStream.on('dataError', () => { /* ... */);
  208. // ...or you can pipe it to another stream
  209. dataStream.pipe(someOtherStream);
  210. ```
  211. `match` returns a readable, object-mode stream
  212. and asynchronously parses individual matching items
  213. from an input JSON stream.
  214. It takes three arguments:
  215. a [readable stream][readable]
  216. from which the JSON will be parsed;
  217. a selector argument for determining matches,
  218. which may be a string, a regular expression or a predicate function;
  219. and an [options](#options-for-parsing-functions) object.
  220. If the selector is a string,
  221. it will be compared to property keys
  222. to determine whether
  223. each item in the data is a match.
  224. If it is a regular expression,
  225. the comparison will be made
  226. by calling the [RegExp `test` method][regexp-test]
  227. with the property key.
  228. Predicate functions will be called with three arguments:
  229. `key`, `value` and `depth`.
  230. If the result of the predicate is a truthy value
  231. then the item will be deemed a match.
  232. If there are any syntax errors in the JSON,
  233. a `dataError` event will be emitted.
  234. If any other errors occur,
  235. an `error` event will be emitted.
  236. ## How do I write a JSON file?
  237. ```js
  238. const bfj = require('bfj');
  239. bfj.write(path, data, options)
  240. .then(() => {
  241. // :)
  242. })
  243. .catch(error => {
  244. // :(
  245. });
  246. ```
  247. `write` returns a [bluebird promise][promise]
  248. and asynchronously serialises a data structure
  249. to a JSON file on disk.
  250. The promise is resolved
  251. when the file has been written,
  252. or rejected with the error
  253. if writing failed.
  254. It takes three arguments;
  255. the path to the JSON file,
  256. the data structure to serialise
  257. and an [options](#options-for-serialisation-functions) object.
  258. ## How do I create a stream of JSON?
  259. ```js
  260. const bfj = require('bfj');
  261. const stream = bfj.streamify(data, options);
  262. // Get data out of the stream with event handlers
  263. stream.on('data', chunk => { /* ... */ });
  264. stream.on('end', () => { /* ... */);
  265. stream.on('error', () => { /* ... */);
  266. stream.on('dataError', () => { /* ... */);
  267. // ...or you can pipe it to another stream
  268. stream.pipe(someOtherStream);
  269. ```
  270. `streamify` returns a [readable stream][readable]
  271. and asynchronously serialises
  272. a data structure to JSON,
  273. pushing the result
  274. to the returned stream.
  275. It takes two arguments;
  276. the data structure to serialise
  277. and an [options](#options-for-serialisation-functions) object.
  278. If there a circular reference is encountered in the data
  279. and `options.circular` is not set to `'ignore'`,
  280. a `dataError` event will be emitted.
  281. If any other errors occur,
  282. an `error` event will be emitted.
  283. ## How do I create a JSON string?
  284. ```js
  285. const bfj = require('bfj');
  286. bfj.stringify(data, options)
  287. .then(json => {
  288. // :)
  289. })
  290. .catch(error => {
  291. // :(
  292. });
  293. ```
  294. `stringify` returns a [bluebird promise][promise] and
  295. asynchronously serialises a data structure
  296. to a JSON string.
  297. The promise is resolved
  298. to the JSON string
  299. when serialisation is complete.
  300. It takes two arguments;
  301. the data structure to serialise
  302. and an [options](#options-for-serialisation-functions) object.
  303. ## What other methods are there?
  304. ### bfj.walk (stream, options)
  305. ```js
  306. const bfj = require('bfj');
  307. const emitter = bfj.walk(fs.createReadStream(path), options);
  308. emitter.on(bfj.events.array, () => { /* ... */ });
  309. emitter.on(bfj.events.object, () => { /* ... */ });
  310. emitter.on(bfj.events.property, name => { /* ... */ });
  311. emitter.on(bfj.events.string, value => { /* ... */ });
  312. emitter.on(bfj.events.number, value => { /* ... */ });
  313. emitter.on(bfj.events.literal, value => { /* ... */ });
  314. emitter.on(bfj.events.endArray, () => { /* ... */ });
  315. emitter.on(bfj.events.endObject, () => { /* ... */ });
  316. emitter.on(bfj.events.error, error => { /* ... */ });
  317. emitter.on(bfj.events.dataError, error => { /* ... */ });
  318. emitter.on(bfj.events.end, () => { /* ... */ });
  319. ```
  320. `walk` returns an [event emitter][eventemitter]
  321. and asynchronously walks
  322. a stream of JSON data,
  323. emitting events
  324. as it encounters
  325. tokens.
  326. It takes two arguments;
  327. a [readable stream][readable]
  328. from which
  329. the JSON
  330. will be read
  331. and an [options](#options-for-parsing-functions) object.
  332. The emitted events
  333. are defined
  334. as public properties
  335. of an object,
  336. `bfj.events`:
  337. * `bfj.events.array`
  338. indicates that
  339. an array context
  340. has been entered
  341. by encountering
  342. the `[` character.
  343. * `bfj.events.endArray`
  344. indicates that
  345. an array context
  346. has been left
  347. by encountering
  348. the `]` character.
  349. * `bfj.events.object`
  350. indicates that
  351. an object context
  352. has been entered
  353. by encountering
  354. the `{` character.
  355. * `bfj.events.endObject`
  356. indicates that
  357. an object context
  358. has been left
  359. by encountering
  360. the `}` character.
  361. * `bfj.events.property`
  362. indicates that
  363. a property
  364. has been encountered
  365. in an object.
  366. The listener
  367. will be passed
  368. the name of the property
  369. as its argument
  370. and the next event
  371. to be emitted
  372. will represent
  373. the property's value.
  374. * `bfj.events.string`
  375. indicates that
  376. a string
  377. has been encountered.
  378. The listener
  379. will be passed
  380. the value
  381. as its argument.
  382. * `bfj.events.number`
  383. indicates that
  384. a number
  385. has been encountered.
  386. The listener
  387. will be passed
  388. the value
  389. as its argument.
  390. * `bfj.events.literal`
  391. indicates that
  392. a JSON literal
  393. (either `true`, `false` or `null`)
  394. has been encountered.
  395. The listener
  396. will be passed
  397. the value
  398. as its argument.
  399. * `bfj.events.error`
  400. indicates that
  401. an error was caught
  402. from one of the event handlers
  403. in user code.
  404. The listener
  405. will be passed
  406. the `Error` instance
  407. as its argument.
  408. * `bfj.events.dataError`
  409. indicates that
  410. a syntax error was encountered
  411. in the incoming JSON stream.
  412. The listener
  413. will be passed
  414. an `Error` instance
  415. decorated with `actual`, `expected`, `lineNumber` and `columnNumber` properties
  416. as its argument.
  417. * `bfj.events.end`
  418. indicates that
  419. the end of the input
  420. has been reached
  421. and the stream is closed.
  422. * `bfj.events.endLine`
  423. indicates that a root-level newline character
  424. has been encountered in an [NDJSON](#can-it-handle-newline-delimited-json-ndjson) stream.
  425. Only emitted if the `ndjson` [option](#options-for-parsing-functions) is set.
  426. If you are using `bfj.walk`
  427. to sequentially parse items in an array,
  428. you might also be interested in
  429. the [bfj-collections] module.
  430. ### bfj.eventify (data, options)
  431. ```js
  432. const bfj = require('bfj');
  433. const emitter = bfj.eventify(data, options);
  434. emitter.on(bfj.events.array, () => { /* ... */ });
  435. emitter.on(bfj.events.object, () => { /* ... */ });
  436. emitter.on(bfj.events.property, name => { /* ... */ });
  437. emitter.on(bfj.events.string, value => { /* ... */ });
  438. emitter.on(bfj.events.number, value => { /* ... */ });
  439. emitter.on(bfj.events.literal, value => { /* ... */ });
  440. emitter.on(bfj.events.endArray, () => { /* ... */ });
  441. emitter.on(bfj.events.endObject, () => { /* ... */ });
  442. emitter.on(bfj.events.error, error => { /* ... */ });
  443. emitter.on(bfj.events.dataError, error => { /* ... */ });
  444. emitter.on(bfj.events.end, () => { /* ... */ });
  445. ```
  446. `eventify` returns an [event emitter][eventemitter]
  447. and asynchronously traverses
  448. a data structure depth-first,
  449. emitting events as it
  450. encounters items.
  451. By default it coerces
  452. promises, buffers and iterables
  453. to JSON-friendly values.
  454. It takes two arguments;
  455. the data structure to traverse
  456. and an [options](#options-for-serialisation-functions) object.
  457. The emitted events
  458. are defined
  459. as public properties
  460. of an object,
  461. `bfj.events`:
  462. * `bfj.events.array`
  463. indicates that
  464. an array
  465. has been encountered.
  466. * `bfj.events.endArray`
  467. indicates that
  468. the end of an array
  469. has been encountered.
  470. * `bfj.events.object`
  471. indicates that
  472. an object
  473. has been encountered.
  474. * `bfj.events.endObject`
  475. indicates that
  476. the end of an object
  477. has been encountered.
  478. * `bfj.events.property`
  479. indicates that
  480. a property
  481. has been encountered
  482. in an object.
  483. The listener
  484. will be passed
  485. the name of the property
  486. as its argument
  487. and the next event
  488. to be emitted
  489. will represent
  490. the property's value.
  491. * `bfj.events.string`
  492. indicates that
  493. a string
  494. has been encountered.
  495. The listener
  496. will be passed
  497. the value
  498. as its argument.
  499. * `bfj.events.number`
  500. indicates that
  501. a number
  502. has been encountered.
  503. The listener
  504. will be passed
  505. the value
  506. as its argument.
  507. * `bfj.events.literal`
  508. indicates that
  509. a JSON literal
  510. (either `true`, `false` or `null`)
  511. has been encountered.
  512. The listener
  513. will be passed
  514. the value
  515. as its argument.
  516. * `bfj.events.error`
  517. indicates that
  518. an error was caught
  519. from one of the event handlers
  520. in user code.
  521. The listener
  522. will be passed
  523. the `Error` instance
  524. as its argument.
  525. * `bfj.events.dataError`
  526. indicates that
  527. a circular reference was encountered in the data
  528. and the `circular` option was not set to `'ignore'`.
  529. The listener
  530. will be passed
  531. an `Error` instance
  532. as its argument.
  533. * `bfj.events.end`
  534. indicates that
  535. the end of the data
  536. has been reached and
  537. no further events
  538. will be emitted.
  539. ## What options can I specify?
  540. ### Options for parsing functions
  541. * `options.reviver`:
  542. Transformation function,
  543. invoked depth-first
  544. against the parsed
  545. data structure.
  546. This option
  547. is analagous to the
  548. [reviver parameter for JSON.parse][reviver].
  549. * `options.yieldRate`:
  550. The number of data items to process
  551. before yielding to the event loop.
  552. Smaller values yield to the event loop more frequently,
  553. meaning less time will be consumed by bfj per tick
  554. but the overall parsing time will be slower.
  555. Larger values yield to the event loop less often,
  556. meaning slower tick times but faster overall parsing time.
  557. The default value is `16384`.
  558. * `options.Promise`:
  559. Promise constructor that will be used
  560. for promises returned by all methods.
  561. If you set this option,
  562. please be aware that some promise implementations
  563. (including native promises)
  564. may cause your process to die
  565. with out-of-memory exceptions.
  566. Defaults to [bluebird's implementation][promise],
  567. which does not have that problem.
  568. * `options.ndjson`:
  569. If set to `true`,
  570. newline characters at the root level
  571. will be treated as delimiters between
  572. discrete chunks of JSON.
  573. See [NDJSON](#can-it-handle-newline-delimited-json-ndjson) for more information.
  574. * `options.numbers`:
  575. For `bfj.match` only,
  576. set this to `true`
  577. if you wish to match against numbers
  578. with a string or regular expression
  579. `selector` argument.
  580. * `options.bufferLength`:
  581. For `bfj.match` only,
  582. the length of the match buffer.
  583. Smaller values use less memory
  584. but may result in a slower parse time.
  585. The default value is `1024`.
  586. * `options.highWaterMark`:
  587. For `bfj.match` only,
  588. set this if you would like to
  589. pass a value for the `highWaterMark` option
  590. to the readable stream constructor.
  591. ### Options for serialisation functions
  592. * `options.space`:
  593. Indentation string
  594. or the number of spaces
  595. to indent
  596. each nested level by.
  597. This option
  598. is analagous to the
  599. [space parameter for JSON.stringify][space].
  600. * `options.promises`:
  601. By default,
  602. promises are coerced
  603. to their resolved value.
  604. Set this property
  605. to `'ignore'`
  606. for improved performance
  607. if you don't need
  608. to coerce promises.
  609. * `options.buffers`:
  610. By default,
  611. buffers are coerced
  612. using their `toString` method.
  613. Set this property
  614. to `'ignore'`
  615. for improved performance
  616. if you don't need
  617. to coerce buffers.
  618. * `options.maps`:
  619. By default,
  620. maps are coerced
  621. to plain objects.
  622. Set this property
  623. to `'ignore'`
  624. for improved performance
  625. if you don't need
  626. to coerce maps.
  627. * `options.iterables`:
  628. By default,
  629. other iterables
  630. (i.e. not arrays, strings or maps)
  631. are coerced
  632. to arrays.
  633. Set this property
  634. to `'ignore'`
  635. for improved performance
  636. if you don't need
  637. to coerce iterables.
  638. * `options.circular`:
  639. By default,
  640. circular references
  641. will cause the write
  642. to fail.
  643. Set this property
  644. to `'ignore'`
  645. if you'd prefer
  646. to silently skip past
  647. circular references
  648. in the data.
  649. * `options.bufferLength`:
  650. The length of the write buffer.
  651. Smaller values use less memory
  652. but may result in a slower serialisation time.
  653. The default value is `1024`.
  654. * `options.highWaterMark`:
  655. Set this if you would like to
  656. pass a value for the `highWaterMark` option
  657. to the readable stream constructor.
  658. * `options.yieldRate`:
  659. The number of data items to process
  660. before yielding to the event loop.
  661. Smaller values yield to the event loop more frequently,
  662. meaning less time will be consumed by bfj per tick
  663. but the overall serialisation time will be slower.
  664. Larger values yield to the event loop less often,
  665. meaning slower tick times but faster overall serialisation time.
  666. The default value is `16384`.
  667. * `options.Promise`:
  668. Promise constructor that will be used
  669. for promises returned by all methods.
  670. If you set this option,
  671. please be aware that some promise implementations
  672. (including native promises)
  673. may cause your process to die
  674. with out-of-memory exceptions.
  675. Defaults to [bluebird's implementation][promise],
  676. which does not have that problem.
  677. ## Is it possible to pause parsing or serialisation from calling code?
  678. Yes it is!
  679. Both [`walk`](#bfjwalk-stream-options)
  680. and [`eventify`](#bfjeventify-data-options)
  681. decorate their returned event emitters
  682. with a `pause` method
  683. that will prevent any further events being emitted.
  684. The `pause` method itself
  685. returns a `resume` function
  686. that you can call to indicate
  687. that processing should continue.
  688. For example:
  689. ```js
  690. const bfj = require('bfj');
  691. const emitter = bfj.walk(fs.createReadStream(path), options);
  692. // Later, when you want to pause parsing:
  693. const resume = emitter.pause();
  694. // Then when you want to resume:
  695. resume();
  696. ```
  697. ## Can it handle [newline-delimited JSON (NDJSON)](http://ndjson.org/)?
  698. Yes.
  699. If you pass the `ndjson` [option](#options-for-parsing-functions)
  700. to `bfj.walk`, `bfj.match` or `bfj.parse`,
  701. newline characters at the root level
  702. will act as delimiters between
  703. discrete JSON values:
  704. * `bfj.walk` will emit a `bfj.events.endLine` event
  705. each time it encounters a newline character.
  706. * `bfj.match` will just ignore the newlines
  707. while it continues looking for matching items.
  708. * `bfj.parse` will resolve with the first value
  709. and pause the underlying stream.
  710. If it's called again with the same stream,
  711. it will resume processing
  712. and resolve with the second value.
  713. To parse the entire stream,
  714. calls should be made sequentially one-at-a-time
  715. until the returned promise
  716. resolves to `undefined`
  717. (`undefined` is not a valid JSON token).
  718. `bfj.unpipe` and `bfj.read` will not parse NDJSON.
  719. ## Why does it default to bluebird promises?
  720. Until version `4.2.4`,
  721. native promises were used.
  722. But they were found
  723. to cause out-of-memory errors
  724. when serialising large amounts of data to JSON,
  725. due to [well-documented problems
  726. with the native promise implementation](https://alexn.org/blog/2017/10/11/javascript-promise-leaks-memory.html).
  727. So in version `5.0.0`,
  728. bluebird promises were used instead.
  729. In version `5.1.0`,
  730. an option was added
  731. that enables callers to specify
  732. the promise constructor to use.
  733. Use it at your own risk.
  734. ## Can I specify a different promise implementation?
  735. Yes.
  736. Just pass the `Promise` option
  737. to any method.
  738. If you get out-of-memory errors
  739. when using that option,
  740. consider changing your promise implementation.
  741. ## Is there a change log?
  742. [Yes][history].
  743. ## How do I set up the dev environment?
  744. The development environment
  745. relies on [Node.js][node],
  746. [ESLint],
  747. [Mocha],
  748. [Chai],
  749. [Proxyquire] and
  750. [Spooks].
  751. Assuming that
  752. you already have
  753. node and NPM
  754. set up,
  755. you just need
  756. to run
  757. `npm install`
  758. to install
  759. all of the dependencies
  760. as listed in `package.json`.
  761. You can
  762. lint the code
  763. with the command
  764. `npm run lint`.
  765. You can
  766. run the tests
  767. with the command
  768. `npm test`.
  769. ## What versions of Node.js does it support?
  770. As of [version `3.0.0`](HISTORY.md#300),
  771. only Node.js versions 6 or greater
  772. are supported
  773. because of the dependency
  774. on [Hoopy](https://gitlab.com/philbooth/hoopy).
  775. Previous versions supported
  776. node 4 and later.
  777. A separate `node-4` branch was maintained
  778. until version `5.4.1`,
  779. which had feature parity version-for-version
  780. with releases from `master`.
  781. Releases from the `node-4` branch
  782. are available in npm
  783. under the package name [`bfj-node4`](https://www.npmjs.com/package/bfj-node4).
  784. ## What license is it released under?
  785. [MIT][license].
  786. [ci-image]: https://secure.travis-ci.org/philbooth/bfj.png?branch=master
  787. [ci-status]: http://travis-ci.org/#!/philbooth/bfj
  788. [sax]: http://en.wikipedia.org/wiki/Simple_API_for_XML
  789. [promise]: http://bluebirdjs.com/docs/api-reference.html
  790. [bfj-collections]: https://github.com/hash-bang/bfj-collections
  791. [eventemitter]: https://nodejs.org/api/events.html#events_class_eventemitter
  792. [readable]: https://nodejs.org/api/stream.html#stream_readable_streams
  793. [writable]: https://nodejs.org/api/stream.html#stream_writable_streams
  794. [pipe]: https://nodejs.org/api/stream.html#stream_readable_pipe_destination_options
  795. [regexp-test]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/test
  796. [reviver]: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#Using_the_reviver_parameter
  797. [space]: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#The_space_argument
  798. [history]: HISTORY.md
  799. [node]: https://nodejs.org/en/
  800. [eslint]: http://eslint.org/
  801. [mocha]: https://mochajs.org/
  802. [chai]: http://chaijs.com/
  803. [proxyquire]: https://github.com/thlorenz/proxyquire
  804. [spooks]: https://gitlab.com/philbooth/spooks.js
  805. [license]: COPYING