1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192 |
- {
- "manifest": {
- "name": "bfj",
- "version": "6.1.2",
- "description": "Big-friendly JSON. Asynchronous streaming functions for large JSON data sets.",
- "homepage": "https://gitlab.com/philbooth/bfj",
- "bugs": {
- "url": "https://gitlab.com/philbooth/bfj/issues"
- },
- "license": "MIT",
- "author": {
- "name": "Phil Booth",
- "url": "https://gitlab.com/philbooth"
- },
- "main": "./src",
- "keywords": [
- "json",
- "streamify",
- "stringify",
- "walk",
- "parse",
- "parser",
- "serialise",
- "serialize",
- "read",
- "write",
- "async",
- "asynchronous"
- ],
- "repository": {
- "type": "git",
- "url": "https://gitlab.com/philbooth/bfj.git"
- },
- "engines": {
- "node": ">= 6.0.0"
- },
- "dependencies": {
- "bluebird": "^3.5.5",
- "check-types": "^8.0.3",
- "hoopy": "^0.1.4",
- "tryer": "^1.0.1"
- },
- "devDependencies": {
- "chai": "^4.2.0",
- "eslint": "^6.0.1",
- "mocha": "^6.1.4",
- "please-release-me": "^2.1.2",
- "proxyquire": "^2.1.0",
- "request": "^2.88.0",
- "spooks": "^2.0.0"
- },
- "scripts": {
- "lint": "eslint src",
- "test": "npm run unit && npm run integration",
- "unit": "mocha --ui tdd --reporter spec --recursive --colors --slow 120 test/unit",
- "integration": "mocha --ui tdd --reporter spec --colors test/integration",
- "perf": "wget -O test/mtg.json http://mtgjson.com/json/AllSets-x.json && node test/performance mtg"
- },
- "_registry": "npm",
- "_loc": "/home/jovyan/.cache/yarn/v6/npm-bfj-6.1.2-325c861a822bcb358a41c78a33b8e6e2086dde7f-integrity/node_modules/bfj/package.json",
- "contributors": [
- {
- "name": "Phil Booth",
- "email": "pmbooth@gmail.com",
- "url": "https://philbooth.me/"
- },
- {
- "name": "Rowan Manning",
- "url": "https://github.com/rowanmanning"
- },
- {
- "name": "Benedikt Rötsch",
- "url": "https://github.com/axe312ger"
- }
- ],
- "readmeFilename": "README.md",
- "readme": "# BFJ\n\n[![Build status](https://gitlab.com/philbooth/bfj/badges/master/pipeline.svg)](https://gitlab.com/philbooth/bfj/pipelines)\n[![Package status](https://img.shields.io/npm/v/bfj.svg)](https://www.npmjs.com/package/bfj)\n[![Downloads](https://img.shields.io/npm/dm/bfj.svg)](https://www.npmjs.com/package/bfj)\n[![License](https://img.shields.io/npm/l/bfj.svg)](https://opensource.org/licenses/MIT)\n\nBig-Friendly JSON. Asynchronous streaming functions for large JSON data sets.\n\n* [Why would I want those?](#why-would-i-want-those)\n* [Is it fast?](#is-it-fast)\n* [What functions does it implement?](#what-functions-does-it-implement)\n* [How do I install it?](#how-do-i-install-it)\n* [How do I read a JSON file?](#how-do-i-read-a-json-file)\n* [How do I parse a stream of JSON?](#how-do-i-parse-a-stream-of-json)\n* [How do I selectively parse individual items from a JSON stream?](#how-do-i-selectively-parse-individual-items-from-a-json-stream)\n* [How do I write a JSON file?](#how-do-i-write-a-json-file)\n* [How do I create a stream of JSON?](#how-do-i-create-a-stream-of-json)\n* [How do I create a JSON string?](#how-do-i-create-a-json-string)\n* [What other methods are there?](#what-other-methods-are-there)\n * [bfj.walk (stream, options)](#bfjwalk-stream-options)\n * [bfj.eventify (data, options)](#bfjeventify-data-options)\n* [What options can I specify?](#what-options-can-i-specify)\n * [Options for parsing functions](#options-for-parsing-functions)\n * [Options for serialisation functions](#options-for-serialisation-functions)\n* [Is it possible to pause parsing or serialisation from calling code?](#is-it-possible-to-pause-parsing-or-serialisation-from-calling-code)\n* [Can it handle newline-delimited JSON (NDJSON)?](#can-it-handle-newline-delimited-json-ndjson)\n* [Why does it default to bluebird promises?](#why-does-it-default-to-bluebird-promises)\n* [Can I specify a different promise implementation?](#can-i-specify-a-different-promise-implementation)\n* [Is there a change log?](#is-there-a-change-log)\n* [How do I set up the dev environment?](#how-do-i-set-up-the-dev-environment)\n* [What versions of Node.js does it support?](#what-versions-of-nodejs-does-it-support)\n* [What license is it released under?](#what-license-is-it-released-under)\n\n## Why would I want those?\n\nIf you need\nto parse huge JSON strings\nor stringify huge JavaScript data sets,\nit monopolises the event loop\nand can lead to out-of-memory exceptions.\nBFJ implements asynchronous functions\nand uses pre-allocated fixed-length arrays\nto try and alleviate those issues.\n\n## Is it fast?\n\nNo.\n\nBFJ yields frequently\nto avoid monopolising the event loop,\ninterrupting its own execution\nto let other event handlers run.\nThe frequency of those yields\ncan be controlled with the [`yieldRate` option](#what-options-can-i-specify),\nbut fundamentally it is not designed for speed.\n\nFurthermore,\nwhen serialising data to a stream,\nBFJ uses a fixed-length buffer\nto avoid exhausting available memory.\nWhenever that buffer is full,\nserialisation is paused\nuntil the receiving stream processes some more data,\nregardless of the value of `yieldRate`.\nYou can control the size of the buffer\nusing the [`bufferLength` option](#options-for-serialisation-functions)\nbut really,\nif you need quick results,\nBFJ is not for you.\n\n## What functions does it implement?\n\nNine functions\nare exported.\n\nFive are\nconcerned with\nparsing, or\nturning JSON strings\ninto JavaScript data:\n\n* [`read`](#how-do-i-read-a-json-file)\n asynchronously parses\n a JSON file from disk.\n\n* [`parse` and `unpipe`](#how-do-i-parse-a-stream-of-json)\n are for asynchronously parsing\n streams of JSON.\n\n* [`match`](#how-do-i-selectively-parse-individual-items-from-a-json-stream)\n selectively parses individual items\n from a JSON stream.\n\n* [`walk`](#bfjwalk-stream-options)\n asynchronously walks\n a stream,\n emitting events\n as it encounters\n JSON tokens.\n Analagous to a\n [SAX parser][sax].\n\nThe other four functions\nhandle the reverse transformations,\nserialising\nJavaScript data\nto JSON:\n\n* [`write`](#how-do-i-write-a-json-file)\n asynchronously serialises data\n to a JSON file on disk.\n\n* [`streamify`](#how-do-i-create-a-stream-of-json)\n asynchronously serialises data\n to a stream of JSON.\n\n* [`stringify`](#how-do-i-create-a-json-string)\n asynchronously serialises data\n to a JSON string.\n\n* [`eventify`](#bfjeventify-data-options)\n asynchronously traverses\n a data structure\n depth-first,\n emitting events\n as it encounters items.\n By default\n it coerces\n promises, buffers and iterables\n to JSON-friendly values.\n\n## How do I install it?\n\nIf you're using npm:\n\n```\nnpm i bfj --save\n```\n\nOr if you just want\nthe git repo:\n\n```\ngit clone git@gitlab.com:philbooth/bfj.git\n```\n\n## How do I read a JSON file?\n\n```js\nconst bfj = require('bfj');\n\nbfj.read(path, options)\n .then(data => {\n // :)\n })\n .catch(error => {\n // :(\n });\n```\n\n`read` returns a [bluebird promise][promise] and\nasynchronously parses\na JSON file\nfrom disk.\n\nIt takes two arguments;\nthe path to the JSON file\nand an [options](#options-for-parsing-functions) object.\n\nIf there are\nno syntax errors,\nthe returned promise is resolved\nwith the parsed data.\nIf syntax errors occur,\nthe promise is rejected\nwith the first error.\n\n## How do I parse a stream of JSON?\n\n```js\nconst bfj = require('bfj');\n\n// By passing a readable stream to bfj.parse():\nbfj.parse(fs.createReadStream(path), options)\n .then(data => {\n // :)\n })\n .catch(error => {\n // :(\n });\n\n// ...or by passing the result from bfj.unpipe() to stream.pipe():\nrequest({ url }).pipe(bfj.unpipe((error, data) => {\n if (error) {\n // :(\n } else {\n // :)\n }\n}))\n```\n\n* `parse` returns a [bluebird promise][promise]\n and asynchronously parses\n a stream of JSON data.\n\n It takes two arguments;\n a [readable stream][readable]\n from which\n the JSON\n will be parsed\n and an [options](#options-for-parsing-functions) object.\n\n If there are\n no syntax errors,\n the returned promise is resolved\n with the parsed data.\n If syntax errors occur,\n the promise is rejected\n with the first error.\n\n* `unpipe` returns a [writable stream][writable]\n that can be passed to [`stream.pipe`][pipe],\n then parses JSON data\n read from the stream.\n\n It takes two arguments;\n a callback function\n that will be called\n after parsing is complete\n and an [options](#options-for-parsing-functions) object.\n\n If there are no errors,\n the callback is invoked\n with the result as the second argument.\n If errors occur,\n the first error is passed\n the callback\n as the first argument.\n\n## How do I selectively parse individual items from a JSON stream?\n\n```js\nconst bfj = require('bfj');\n\n// Call match with your stream and a selector predicate/regex/string\nconst dataStream = bfj.match(jsonStream, selector, options);\n\n// Get data out of the returned stream with event handlers\ndataStream.on('data', item => { /* ... */ });\ndataStream.on('end', () => { /* ... */);\ndataStream.on('error', () => { /* ... */);\ndataStream.on('dataError', () => { /* ... */);\n\n// ...or you can pipe it to another stream\ndataStream.pipe(someOtherStream);\n```\n\n`match` returns a readable, object-mode stream\nand asynchronously parses individual matching items\nfrom an input JSON stream.\n\nIt takes three arguments:\na [readable stream][readable]\nfrom which the JSON will be parsed;\na selector argument for determining matches,\nwhich may be a string, a regular expression or a predicate function;\nand an [options](#options-for-parsing-functions) object.\n\nIf the selector is a string,\nit will be compared to property keys\nto determine whether\neach item in the data is a match.\nIf it is a regular expression,\nthe comparison will be made\nby calling the [RegExp `test` method][regexp-test]\nwith the property key.\nPredicate functions will be called with three arguments:\n`key`, `value` and `depth`.\nIf the result of the predicate is a truthy value\nthen the item will be deemed a match.\n\nIf there are any syntax errors in the JSON,\na `dataError` event will be emitted.\nIf any other errors occur,\nan `error` event will be emitted.\n\n## How do I write a JSON file?\n\n```js\nconst bfj = require('bfj');\n\nbfj.write(path, data, options)\n .then(() => {\n // :)\n })\n .catch(error => {\n // :(\n });\n```\n\n`write` returns a [bluebird promise][promise]\nand asynchronously serialises a data structure\nto a JSON file on disk.\nThe promise is resolved\nwhen the file has been written,\nor rejected with the error\nif writing failed.\n\nIt takes three arguments;\nthe path to the JSON file,\nthe data structure to serialise\nand an [options](#options-for-serialisation-functions) object.\n\n## How do I create a stream of JSON?\n\n```js\nconst bfj = require('bfj');\n\nconst stream = bfj.streamify(data, options);\n\n// Get data out of the stream with event handlers\nstream.on('data', chunk => { /* ... */ });\nstream.on('end', () => { /* ... */);\nstream.on('error', () => { /* ... */);\nstream.on('dataError', () => { /* ... */);\n\n// ...or you can pipe it to another stream\nstream.pipe(someOtherStream);\n```\n\n`streamify` returns a [readable stream][readable]\nand asynchronously serialises\na data structure to JSON,\npushing the result\nto the returned stream.\n\nIt takes two arguments;\nthe data structure to serialise\nand an [options](#options-for-serialisation-functions) object.\n\nIf there a circular reference is encountered in the data\nand `options.circular` is not set to `'ignore'`,\na `dataError` event will be emitted.\nIf any other errors occur,\nan `error` event will be emitted.\n\n## How do I create a JSON string?\n\n```js\nconst bfj = require('bfj');\n\nbfj.stringify(data, options)\n .then(json => {\n // :)\n })\n .catch(error => {\n // :(\n });\n```\n\n`stringify` returns a [bluebird promise][promise] and\nasynchronously serialises a data structure\nto a JSON string.\nThe promise is resolved\nto the JSON string\nwhen serialisation is complete.\n\nIt takes two arguments;\nthe data structure to serialise\nand an [options](#options-for-serialisation-functions) object.\n\n## What other methods are there?\n\n### bfj.walk (stream, options)\n\n```js\nconst bfj = require('bfj');\n\nconst emitter = bfj.walk(fs.createReadStream(path), options);\n\nemitter.on(bfj.events.array, () => { /* ... */ });\nemitter.on(bfj.events.object, () => { /* ... */ });\nemitter.on(bfj.events.property, name => { /* ... */ });\nemitter.on(bfj.events.string, value => { /* ... */ });\nemitter.on(bfj.events.number, value => { /* ... */ });\nemitter.on(bfj.events.literal, value => { /* ... */ });\nemitter.on(bfj.events.endArray, () => { /* ... */ });\nemitter.on(bfj.events.endObject, () => { /* ... */ });\nemitter.on(bfj.events.error, error => { /* ... */ });\nemitter.on(bfj.events.dataError, error => { /* ... */ });\nemitter.on(bfj.events.end, () => { /* ... */ });\n```\n\n`walk` returns an [event emitter][eventemitter]\nand asynchronously walks\na stream of JSON data,\nemitting events\nas it encounters\ntokens.\n\nIt takes two arguments;\na [readable stream][readable]\nfrom which\nthe JSON\nwill be read\nand an [options](#options-for-parsing-functions) object.\n\nThe emitted events\nare defined\nas public properties\nof an object,\n`bfj.events`:\n\n* `bfj.events.array`\n indicates that\n an array context\n has been entered\n by encountering\n the `[` character.\n\n* `bfj.events.endArray`\n indicates that\n an array context\n has been left\n by encountering\n the `]` character.\n\n* `bfj.events.object`\n indicates that\n an object context\n has been entered\n by encountering\n the `{` character.\n\n* `bfj.events.endObject`\n indicates that\n an object context\n has been left\n by encountering\n the `}` character.\n\n* `bfj.events.property`\n indicates that\n a property\n has been encountered\n in an object.\n The listener\n will be passed\n the name of the property\n as its argument\n and the next event\n to be emitted\n will represent\n the property's value.\n\n* `bfj.events.string`\n indicates that\n a string\n has been encountered.\n The listener\n will be passed\n the value\n as its argument.\n\n* `bfj.events.number`\n indicates that\n a number\n has been encountered.\n The listener\n will be passed\n the value\n as its argument.\n\n* `bfj.events.literal`\n indicates that\n a JSON literal\n (either `true`, `false` or `null`)\n has been encountered.\n The listener\n will be passed\n the value\n as its argument.\n\n* `bfj.events.error`\n indicates that\n an error was caught\n from one of the event handlers\n in user code.\n The listener\n will be passed\n the `Error` instance\n as its argument.\n\n* `bfj.events.dataError`\n indicates that\n a syntax error was encountered\n in the incoming JSON stream.\n The listener\n will be passed\n an `Error` instance\n decorated with `actual`, `expected`, `lineNumber` and `columnNumber` properties\n as its argument.\n\n* `bfj.events.end`\n indicates that\n the end of the input\n has been reached\n and the stream is closed.\n\n* `bfj.events.endLine`\n indicates that a root-level newline character\n has been encountered in an [NDJSON](#can-it-handle-newline-delimited-json-ndjson) stream.\n Only emitted if the `ndjson` [option](#options-for-parsing-functions) is set.\n\nIf you are using `bfj.walk`\nto sequentially parse items in an array,\nyou might also be interested in\nthe [bfj-collections] module.\n\n### bfj.eventify (data, options)\n\n```js\nconst bfj = require('bfj');\n\nconst emitter = bfj.eventify(data, options);\n\nemitter.on(bfj.events.array, () => { /* ... */ });\nemitter.on(bfj.events.object, () => { /* ... */ });\nemitter.on(bfj.events.property, name => { /* ... */ });\nemitter.on(bfj.events.string, value => { /* ... */ });\nemitter.on(bfj.events.number, value => { /* ... */ });\nemitter.on(bfj.events.literal, value => { /* ... */ });\nemitter.on(bfj.events.endArray, () => { /* ... */ });\nemitter.on(bfj.events.endObject, () => { /* ... */ });\nemitter.on(bfj.events.error, error => { /* ... */ });\nemitter.on(bfj.events.dataError, error => { /* ... */ });\nemitter.on(bfj.events.end, () => { /* ... */ });\n```\n\n`eventify` returns an [event emitter][eventemitter]\nand asynchronously traverses\na data structure depth-first,\nemitting events as it\nencounters items.\nBy default it coerces\npromises, buffers and iterables\nto JSON-friendly values.\n\nIt takes two arguments;\nthe data structure to traverse\nand an [options](#options-for-serialisation-functions) object.\n\nThe emitted events\nare defined\nas public properties\nof an object,\n`bfj.events`:\n\n* `bfj.events.array`\n indicates that\n an array\n has been encountered.\n\n* `bfj.events.endArray`\n indicates that\n the end of an array\n has been encountered.\n\n* `bfj.events.object`\n indicates that\n an object\n has been encountered.\n\n* `bfj.events.endObject`\n indicates that\n the end of an object\n has been encountered.\n\n* `bfj.events.property`\n indicates that\n a property\n has been encountered\n in an object.\n The listener\n will be passed\n the name of the property\n as its argument\n and the next event\n to be emitted\n will represent\n the property's value.\n\n* `bfj.events.string`\n indicates that\n a string\n has been encountered.\n The listener\n will be passed\n the value\n as its argument.\n\n* `bfj.events.number`\n indicates that\n a number\n has been encountered.\n The listener\n will be passed\n the value\n as its argument.\n\n* `bfj.events.literal`\n indicates that\n a JSON literal\n (either `true`, `false` or `null`)\n has been encountered.\n The listener\n will be passed\n the value\n as its argument.\n\n* `bfj.events.error`\n indicates that\n an error was caught\n from one of the event handlers\n in user code.\n The listener\n will be passed\n the `Error` instance\n as its argument.\n\n* `bfj.events.dataError`\n indicates that\n a circular reference was encountered in the data\n and the `circular` option was not set to `'ignore'`.\n The listener\n will be passed\n an `Error` instance\n as its argument.\n\n* `bfj.events.end`\n indicates that\n the end of the data\n has been reached and\n no further events\n will be emitted.\n\n## What options can I specify?\n\n### Options for parsing functions\n\n* `options.reviver`:\n Transformation function,\n invoked depth-first\n against the parsed\n data structure.\n This option\n is analagous to the\n [reviver parameter for JSON.parse][reviver].\n\n* `options.yieldRate`:\n The number of data items to process\n before yielding to the event loop.\n Smaller values yield to the event loop more frequently,\n meaning less time will be consumed by bfj per tick\n but the overall parsing time will be slower.\n Larger values yield to the event loop less often,\n meaning slower tick times but faster overall parsing time.\n The default value is `16384`.\n\n* `options.Promise`:\n Promise constructor that will be used\n for promises returned by all methods.\n If you set this option,\n please be aware that some promise implementations\n (including native promises)\n may cause your process to die\n with out-of-memory exceptions.\n Defaults to [bluebird's implementation][promise],\n which does not have that problem.\n\n* `options.ndjson`:\n If set to `true`,\n newline characters at the root level\n will be treated as delimiters between\n discrete chunks of JSON.\n See [NDJSON](#can-it-handle-newline-delimited-json-ndjson) for more information.\n\n* `options.numbers`:\n For `bfj.match` only,\n set this to `true`\n if you wish to match against numbers\n with a string or regular expression\n `selector` argument.\n\n* `options.bufferLength`:\n For `bfj.match` only,\n the length of the match buffer.\n Smaller values use less memory\n but may result in a slower parse time.\n The default value is `1024`.\n\n* `options.highWaterMark`:\n For `bfj.match` only,\n set this if you would like to\n pass a value for the `highWaterMark` option\n to the readable stream constructor.\n\n### Options for serialisation functions\n\n* `options.space`:\n Indentation string\n or the number of spaces\n to indent\n each nested level by.\n This option\n is analagous to the\n [space parameter for JSON.stringify][space].\n\n* `options.promises`:\n By default,\n promises are coerced\n to their resolved value.\n Set this property\n to `'ignore'`\n for improved performance\n if you don't need\n to coerce promises.\n\n* `options.buffers`:\n By default,\n buffers are coerced\n using their `toString` method.\n Set this property\n to `'ignore'`\n for improved performance\n if you don't need\n to coerce buffers.\n\n* `options.maps`:\n By default,\n maps are coerced\n to plain objects.\n Set this property\n to `'ignore'`\n for improved performance\n if you don't need\n to coerce maps.\n\n* `options.iterables`:\n By default,\n other iterables\n (i.e. not arrays, strings or maps)\n are coerced\n to arrays.\n Set this property\n to `'ignore'`\n for improved performance\n if you don't need\n to coerce iterables.\n\n* `options.circular`:\n By default,\n circular references\n will cause the write\n to fail.\n Set this property\n to `'ignore'`\n if you'd prefer\n to silently skip past\n circular references\n in the data.\n\n* `options.bufferLength`:\n The length of the write buffer.\n Smaller values use less memory\n but may result in a slower serialisation time.\n The default value is `1024`.\n\n* `options.highWaterMark`:\n Set this if you would like to\n pass a value for the `highWaterMark` option\n to the readable stream constructor.\n\n* `options.yieldRate`:\n The number of data items to process\n before yielding to the event loop.\n Smaller values yield to the event loop more frequently,\n meaning less time will be consumed by bfj per tick\n but the overall serialisation time will be slower.\n Larger values yield to the event loop less often,\n meaning slower tick times but faster overall serialisation time.\n The default value is `16384`.\n\n* `options.Promise`:\n Promise constructor that will be used\n for promises returned by all methods.\n If you set this option,\n please be aware that some promise implementations\n (including native promises)\n may cause your process to die\n with out-of-memory exceptions.\n Defaults to [bluebird's implementation][promise],\n which does not have that problem.\n\n## Is it possible to pause parsing or serialisation from calling code?\n\nYes it is!\nBoth [`walk`](#bfjwalk-stream-options)\nand [`eventify`](#bfjeventify-data-options)\ndecorate their returned event emitters\nwith a `pause` method\nthat will prevent any further events being emitted.\nThe `pause` method itself\nreturns a `resume` function\nthat you can call to indicate\nthat processing should continue.\n\nFor example:\n\n```js\nconst bfj = require('bfj');\nconst emitter = bfj.walk(fs.createReadStream(path), options);\n\n// Later, when you want to pause parsing:\n\nconst resume = emitter.pause();\n\n// Then when you want to resume:\n\nresume();\n```\n\n## Can it handle [newline-delimited JSON (NDJSON)](http://ndjson.org/)?\n\nYes.\nIf you pass the `ndjson` [option](#options-for-parsing-functions)\nto `bfj.walk`, `bfj.match` or `bfj.parse`,\nnewline characters at the root level\nwill act as delimiters between\ndiscrete JSON values:\n\n* `bfj.walk` will emit a `bfj.events.endLine` event\n each time it encounters a newline character.\n\n* `bfj.match` will just ignore the newlines\n while it continues looking for matching items.\n\n* `bfj.parse` will resolve with the first value\n and pause the underlying stream.\n If it's called again with the same stream,\n it will resume processing\n and resolve with the second value.\n To parse the entire stream,\n calls should be made sequentially one-at-a-time\n until the returned promise\n resolves to `undefined`\n (`undefined` is not a valid JSON token).\n\n`bfj.unpipe` and `bfj.read` will not parse NDJSON.\n\n## Why does it default to bluebird promises?\n\nUntil version `4.2.4`,\nnative promises were used.\nBut they were found\nto cause out-of-memory errors\nwhen serialising large amounts of data to JSON,\ndue to [well-documented problems\nwith the native promise implementation](https://alexn.org/blog/2017/10/11/javascript-promise-leaks-memory.html).\nSo in version `5.0.0`,\nbluebird promises were used instead.\nIn version `5.1.0`,\nan option was added\nthat enables callers to specify\nthe promise constructor to use.\nUse it at your own risk.\n\n## Can I specify a different promise implementation?\n\nYes.\nJust pass the `Promise` option\nto any method.\nIf you get out-of-memory errors\nwhen using that option,\nconsider changing your promise implementation.\n\n## Is there a change log?\n\n[Yes][history].\n\n## How do I set up the dev environment?\n\nThe development environment\nrelies on [Node.js][node],\n[ESLint],\n[Mocha],\n[Chai],\n[Proxyquire] and\n[Spooks].\nAssuming that\nyou already have\nnode and NPM\nset up,\nyou just need\nto run\n`npm install`\nto install\nall of the dependencies\nas listed in `package.json`.\n\nYou can\nlint the code\nwith the command\n`npm run lint`.\n\nYou can\nrun the tests\nwith the command\n`npm test`.\n\n## What versions of Node.js does it support?\n\nAs of [version `3.0.0`](HISTORY.md#300),\nonly Node.js versions 6 or greater\nare supported\nbecause of the dependency\non [Hoopy](https://gitlab.com/philbooth/hoopy).\nPrevious versions supported\nnode 4 and later.\n\nA separate `node-4` branch was maintained\nuntil version `5.4.1`,\nwhich had feature parity version-for-version\nwith releases from `master`.\nReleases from the `node-4` branch\nare available in npm\nunder the package name [`bfj-node4`](https://www.npmjs.com/package/bfj-node4).\n\n## What license is it released under?\n\n[MIT][license].\n\n[ci-image]: https://secure.travis-ci.org/philbooth/bfj.png?branch=master\n[ci-status]: http://travis-ci.org/#!/philbooth/bfj\n[sax]: http://en.wikipedia.org/wiki/Simple_API_for_XML\n[promise]: http://bluebirdjs.com/docs/api-reference.html\n[bfj-collections]: https://github.com/hash-bang/bfj-collections\n[eventemitter]: https://nodejs.org/api/events.html#events_class_eventemitter\n[readable]: https://nodejs.org/api/stream.html#stream_readable_streams\n[writable]: https://nodejs.org/api/stream.html#stream_writable_streams\n[pipe]: https://nodejs.org/api/stream.html#stream_readable_pipe_destination_options\n[regexp-test]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/test\n[reviver]: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#Using_the_reviver_parameter\n[space]: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#The_space_argument\n[history]: HISTORY.md\n[node]: https://nodejs.org/en/\n[eslint]: http://eslint.org/\n[mocha]: https://mochajs.org/\n[chai]: http://chaijs.com/\n[proxyquire]: https://github.com/thlorenz/proxyquire\n[spooks]: https://gitlab.com/philbooth/spooks.js\n[license]: COPYING\n"
- },
- "artifacts": [],
- "remote": {
- "resolved": "https://registry.yarnpkg.com/bfj/-/bfj-6.1.2.tgz#325c861a822bcb358a41c78a33b8e6e2086dde7f",
- "type": "tarball",
- "reference": "https://registry.yarnpkg.com/bfj/-/bfj-6.1.2.tgz",
- "hash": "325c861a822bcb358a41c78a33b8e6e2086dde7f",
- "integrity": "sha512-BmBJa4Lip6BPRINSZ0BPEIfB1wUY/9rwbwvIHQA1KjX9om29B6id0wnWXq7m3bn5JrUVjeOTnVuhPT1FiHwPGw==",
- "registry": "npm",
- "packageName": "bfj",
- "cacheIntegrity": "sha512-BmBJa4Lip6BPRINSZ0BPEIfB1wUY/9rwbwvIHQA1KjX9om29B6id0wnWXq7m3bn5JrUVjeOTnVuhPT1FiHwPGw== sha1-MlyGGoIryzWKQceKM7jm4ght3n8="
- },
- "registry": "npm",
- "hash": "325c861a822bcb358a41c78a33b8e6e2086dde7f"
- }
|