{
  "_args": [
    [
      {
        "raw": "broccoli-persistent-filter@^1.4.0",
        "scope": null,
        "escapedName": "broccoli-persistent-filter",
        "name": "broccoli-persistent-filter",
        "rawSpec": "^1.4.0",
        "spec": ">=1.4.0 <2.0.0",
        "type": "range"
      },
      "/home/travis/build/lukesargeant/ember-sparkline/node_modules/broccoli-babel-transpiler"
    ]
  ],
  "_from": "broccoli-persistent-filter@>=1.4.0 <2.0.0",
  "_id": "broccoli-persistent-filter@1.4.3",
  "_inCache": true,
  "_location": "/broccoli-persistent-filter",
  "_nodeVersion": "8.1.3",
  "_npmOperationalInternal": {
    "host": "s3://npm-registry-packages",
    "tmp": "tmp/broccoli-persistent-filter-1.4.3.tgz_1502811837968_0.16976283374242485"
  },
  "_npmUser": {
    "name": "stefanpenner",
    "email": "stefan.penner@gmail.com"
  },
  "_npmVersion": "5.1.0",
  "_phantomChildren": {},
  "_requested": {
    "raw": "broccoli-persistent-filter@^1.4.0",
    "scope": null,
    "escapedName": "broccoli-persistent-filter",
    "name": "broccoli-persistent-filter",
    "rawSpec": "^1.4.0",
    "spec": ">=1.4.0 <2.0.0",
    "type": "range"
  },
  "_requiredBy": [
    "/broccoli-babel-transpiler",
    "/broccoli-clean-css",
    "/broccoli-lint-eslint",
    "/broccoli-stew",
    "/ember-cli-htmlbars"
  ],
  "_resolved": "https://registry.npmjs.org/broccoli-persistent-filter/-/broccoli-persistent-filter-1.4.3.tgz",
  "_shasum": "3511bc52fc53740cda51621f58a28152d9911bc1",
  "_shrinkwrap": null,
  "_spec": "broccoli-persistent-filter@^1.4.0",
  "_where": "/home/travis/build/lukesargeant/ember-sparkline/node_modules/broccoli-babel-transpiler",
  "author": {
    "name": "Stefan Penner",
    "email": "stefan.penner@gmail.com"
  },
  "bugs": {
    "url": "https://github.com/stefanpenner/broccoli-persistent-filter/issues"
  },
  "dependencies": {
    "async-disk-cache": "^1.2.1",
    "async-promise-queue": "^1.0.3",
    "broccoli-plugin": "^1.0.0",
    "fs-tree-diff": "^0.5.2",
    "hash-for-dep": "^1.0.2",
    "heimdalljs": "^0.2.1",
    "heimdalljs-logger": "^0.1.7",
    "mkdirp": "^0.5.1",
    "promise-map-series": "^0.2.1",
    "rimraf": "^2.6.1",
    "rsvp": "^3.0.18",
    "symlink-or-copy": "^1.0.1",
    "walk-sync": "^0.3.1"
  },
  "description": "broccoli filter but with a persistent cache",
  "devDependencies": {
    "babel-polyfill": "^6.23.0",
    "babel-preset-es2015": "^6.24.1",
    "babel-register": "^6.24.1",
    "broccoli-test-helper": "^1.1.0",
    "broccoli-test-helpers": "^0.0.9",
    "chai": "^3.5.0",
    "chai-as-promised": "^5.3.0",
    "chai-files": "^1.4.0",
    "co": "^4.6.0",
    "coveralls": "^2.11.10",
    "istanbul": "^0.4.2",
    "minimatch": "^3.0.2",
    "mocha": "^3.0.0",
    "mocha-jshint": "^2.3.1",
    "sinon": "^2.1.0",
    "sinon-chai": "^2.8.0"
  },
  "directories": {},
  "dist": {
    "integrity": "sha512-JwNLDvvXJlhUmr+CHcbVhCyp33NbCIAITjQZmJY9e8QzANXh3jpFWlhSFvkWghwKA8rTAKcXkW12agtiZjxr4g==",
    "shasum": "3511bc52fc53740cda51621f58a28152d9911bc1",
    "tarball": "https://registry.npmjs.org/broccoli-persistent-filter/-/broccoli-persistent-filter-1.4.3.tgz"
  },
  "files": [
    "index.js",
    "lib/"
  ],
  "gitHead": "d0bcc3fb45a038dd0dd600b847a60e1d2b0f8fc9",
  "homepage": "https://github.com/stefanpenner/broccoli-persistent-filter#readme",
  "keywords": [
    "broccoli",
    "broccoli-plugin",
    "broccoli-helper",
    "filter",
    "cache"
  ],
  "license": "MIT",
  "main": "index.js",
  "maintainers": [
    {
      "name": "hjdivad",
      "email": "npm@hjdivad.com"
    },
    {
      "name": "kellyselden",
      "email": "kellyselden@gmail.com"
    },
    {
      "name": "rwjblue",
      "email": "me@rwjblue.com"
    },
    {
      "name": "stefanpenner",
      "email": "stefan.penner@gmail.com"
    }
  ],
  "name": "broccoli-persistent-filter",
  "optionalDependencies": {},
  "readme": "# broccoli-persistent-filter\n\n[![Greenkeeper badge](https://badges.greenkeeper.io/stefanpenner/broccoli-persistent-filter.svg)](https://greenkeeper.io/)\n[![Build Status](https://travis-ci.org/stefanpenner/broccoli-persistent-filter.svg?branch=master)](https://travis-ci.org/stefanpenner/broccoli-persistent-filter)\n[![Build status](https://ci.appveyor.com/api/projects/status/gvt0rheb1c2c4jwd/branch/master?svg=true)](https://ci.appveyor.com/project/embercli/broccoli-persistent-filter/branch/master)\n\nHelper base class for Broccoli plugins that map input files into output files. Except with a persistent cache to fast restarts.\none-to-one.\n\n## API\n\n```js\nclass Filter {\n  /**\n   * Abstract base-class for filtering purposes.\n   *\n   * Enforces that it is invoked on an instance of a class which prototypically\n   * inherits from Filter, and which is not itself Filter.\n   */\n  constructor(inputNode: BroccoliNode, options: FilterOptions): Filter;\n\n  /**\n   * Abstract method `processString`: must be implemented on subclasses of\n   * Filter.\n   *\n   * The resolved return value can either be an object or a string.\n   *\n   * An object can be used to cache additional meta-data that is not part of the\n   * final output. When an object is returned, the `.output` property of that\n   * object is used as the resulting file contents.\n   *\n   * When a string is returned it is used as the file contents.\n   */\n  abstract processString(contents: string, relativePath: string): {string | object };\n\n  /**\n   * Virtual method `getDestFilePath`: determine whether the source file should\n   * be processed, and optionally rename the output file when processing occurs.\n   *\n   * Return `null` to pass the file through without processing. Return\n   * `relativePath` to process the file with `processString`. Return a\n   * different path to process the file with `processString` and rename it.\n   *\n   * By default, if the options passed into the `Filter` constructor contain a\n   * property `extensions`, and `targetExtension` is supplied, the first matching\n   * extension in the list is replaced with the `targetExtension` option's value.\n   */\n  virtual getDestFilePath(relativePath: string): string;\n\n  /**\n   * Method `postProcess`: may be implemented on subclasses of\n   * Filter.\n   *\n   * This method can be used in subclasses to do processing on the results of\n   * each files `processString` method.\n   *\n   * A common scenario for this is linting plugins, where on initial build users\n   * expect to get console warnings for lint errors, but we do not want to re-lint\n   * each file on every boot (since most of them will be able to be served from the\n   * cache).\n   *\n   * The `.output` property of the return value is used as the emitted file contents.\n   */\n  postProcess(results: object, relativePath: string): object\n\n}\n```\n\n### Options\n\n* `extensions`: An array of file extensions to process, e.g. `['md', 'markdown']`.\n* `targetExtension`: The file extension of the corresponding output files, e.g.\n  `'html'`.\n* `inputEncoding`: The character encoding used for reading input files to be\n  processed (default: `'utf8'`). For binary files, pass `null` to receive a\n  `Buffer` object in `processString`.\n* `outputEncoding`: The character encoding used for writing output files after\n  processing (default: `'utf8'`). For binary files, pass `null` and return a\n  `Buffer` object from `processString`.\n* `async`: Whether the `create` and `change` file operations are allowed to\n  complete asynchronously (true|false, default: false)\n* `name`, `annotation`: Same as\n  [broccoli-plugin](https://github.com/broccolijs/broccoli-plugin#new-plugininputnodes-options);\n  see there.\n* `concurrency`: Used with `async: true`. The number of operations that can be\n  run concurrently. This overrides the value set with `JOBS=n` environment variable.\n  (default: the number of detected CPU cores - 1, with a min of 1)\n\nAll options except `name` and `annotation` can also be set on the prototype\ninstead of being passed into the constructor.\n\n### Example Usage\n\n```js\nvar Filter = require('broccoli-filter');\n\nAwk.prototype = Object.create(Filter.prototype);\nAwk.prototype.constructor = Awk;\nfunction Awk(inputNode, search, replace, options) {\n  options = options || {};\n  Filter.call(this, inputNode, {\n    annotation: options.annotation\n  });\n  this.search = search;\n  this.replace = replace;\n}\n\nAwk.prototype.extensions = ['txt'];\nAwk.prototype.targetExtension = 'txt';\n\nAwk.prototype.processString = function(content, relativePath) {\n  return content.replace(this.search, this.replace);\n};\n```\n\nIn `Brocfile.js`, use your new `Awk` plugin like so:\n\n```\nvar node = new Awk('docs', 'ES6', 'ECMAScript 2015');\n\nmodule.exports = node;\n```\n\n## Persistent Cache\n\nAdding persist flag allows a subclass to persist state across restarts. This exists to mitigate the upfront cost of some more expensive transforms on warm boot. __It does not aim to improve incremental build performance, if it does, it should indicate something is wrong with the filter or input filter in question.__\n\n### How does it work?\n\nIt does so but establishing a 2 layer file cache. The first layer, is the entire bucket.\nThe second, `cacheKeyProcessString` is a per file cache key.\n\nTogether, these two layers should provide the right balance of speed and sensibility.\n\nThe bucket level cacheKey must be stable but also never become stale. If the key is not\nstable, state between restarts will be lost and performance will suffer. On the flip-side,\nif the cacheKey becomes stale changes may not be correctly reflected.\n\nIt is configured by subclassing and refining `cacheKey` method. A good key here, is\nlikely the name of the plugin, its version and the actual versions of its dependencies.\n\n```js\nSubclass.prototype.cacheKey = function() {\n return md5(Filter.prototype.call(this) + inputOptionsChecksum + dependencyVersionChecksum);\n}\n```\n\nThe second key, represents the contents of the file. Typically the base-class's functionality\nis sufficient, as it merely generates a checksum of the file contents. If for some reason this\nis not sufficient, it can be re-configured via subclassing.\n\n```js\nSubclass.prototype.cacheKeyProcessString = function(string, relativePath) {\n  return superAwesomeDigest(string);\n}\n```\n\nIt is recommended that persistent re-builds is opt-in by the consuming plugin author, as if no reasonable cache key can be created it should not be used.\n\n```js\nvar myTree = new SomePlugin('lib', { persist: true });\n```\n\n### Warning\n\nBy using the persistent cache, a lot of small files will be created on the disk without being deleted.\nThis might use all the inodes of your disk.\nYou need to make sure to clean regularly the old files or configure your system to do so.\n\nOn OSX, [files that aren't accessed in three days are deleted from `/tmp`](http://superuser.com/a/187105).  \nOn systems using systemd, [systemd-tmpfiles](https://www.freedesktop.org/software/systemd/man/systemd-tmpfiles.html) should already be present and regularly clean up the `/tmp` directory.  \nOn Debian-like systems, you can use [tmpreaper](https://packages.debian.org/stable/tmpreaper).  \nOn RedHad-like systems, you can use [tmpwatch](https://fedorahosted.org/tmpwatch/).\n\nBy default, the files are stored in the [operatin system's default directory for temporary files](https://nodejs.org/api/os.html#os_os_tmpdir),\nbut you can change this location by setting the `BROCCOLI_PERSISTENT_FILTER_CACHE_ROOT` environment variable to the path of another folder.\n\n## FAQ\n\n### Upgrading from 0.1.x to 1.x\n\nYou must now call the base class constructor. For example:\n\n```js\n// broccoli-filter 0.1.x:\nfunction MyPlugin(inputTree) {\n  this.inputTree = inputTree;\n}\n\n// broccoli-filter 1.x:\nfunction MyPlugin(inputNode) {\n  Filter.call(this, inputNode);\n}\n```\n\nNote that \"node\" is simply new terminology for \"tree\".\n\n### Source Maps\n\n**Can this help with compilers that are almost 1:1, like a minifier that takes\na `.js` and `.js.map` file and outputs a `.js` and `.js.map` file?**\n\nNot at the moment. I don't know yet how to implement this and still have the\nAPI look beautiful. We also have to make sure that caching works correctly, as\nwe have to invalidate if either the `.js` or the `.js.map` file changes. My\nplan is to write a source-map-aware uglifier plugin to understand this use\ncase better, and then extract common code back into this `Filter` base class.\n",
  "readmeFilename": "README.md",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/stefanpenner/broccoli-persistent-filter.git"
  },
  "scripts": {
    "test": "mocha",
    "test:ci": "mocha --compilers js:babel-register --require babel-polyfill",
    "test:coverage": "istanbul cover --config=test/istanbul.yml _mocha",
    "test:debug": "mocha debug",
    "test:debug:brk": "mocha --debug-brk",
    "test:watch": "mocha --watch"
  },
  "version": "1.4.3"
}
