{
  "name": "fs-jetpack",
  "description": "Better file system API",
  "version": "0.9.2",
  "author": {
    "name": "Jakub Szwacz",
    "email": "jakub@szwacz.com"
  },
  "dependencies": {
    "minimatch": "^3.0.2",
    "mkdirp": "^0.5.1",
    "q": "^1.0.1",
    "rimraf": "^2.2.8"
  },
  "devDependencies": {
    "eslint": "^2.13.1",
    "eslint-config-airbnb-base": "^3.0.1",
    "eslint-plugin-import": "^1.9.2",
    "fs-extra": "^0.16.3",
    "jasmine": "^2.2.1",
    "pre-commit": "^1.1.2"
  },
  "scripts": {
    "test": "jasmine",
    "lint": "eslint ."
  },
  "main": "main.js",
  "homepage": "https://github.com/szwacz/fs-jetpack",
  "repository": {
    "type": "git",
    "url": "https://github.com/szwacz/fs-jetpack.git"
  },
  "license": "MIT",
  "keywords": [
    "fs",
    "file system"
  ],
  "pre-commit": [
    "lint",
    "test"
  ],
  "readme": "fs-jetpack [![Build Status](https://travis-ci.org/szwacz/fs-jetpack.svg?branch=master)](https://travis-ci.org/szwacz/fs-jetpack) [![Build status](https://ci.appveyor.com/api/projects/status/er206e91fpuuqf58?svg=true)](https://ci.appveyor.com/project/szwacz/fs-jetpack)\n==========\n\nNode's [fs library](http://nodejs.org/api/fs.html) is very low level and because of that often painful to use. *fs-jetpack* wants to fix that by giving you completely rethought, much more convenient API to work with file system.\n\n#### [Jump to API Docs](#api)\n\n## Installation\n```\nnpm install fs-jetpack\n```\n\n## Usage\n```javascript\nvar jetpack = require('fs-jetpack');\n```\n\n\n# What's cool about jetpack?\n\n## Promises instead of callbacks\nAPI has the same set of synchronous and asynchronous methods. All async methods are promise based.\n\nCommonly used naming convention in Node world is reversed in this library (no 'method' and 'methodSync' naming). Asynchronous methods are those with 'Async' suffix, all methods without 'Async' in the name are synchronous. Reason behind this is that it gives very nice look to blocking API, and promise based non-blocking code is verbose anyway, so one more word is not much of a difference.\n\nThanks to that the API is also coherent...\n```js\n// If method has no 'Async' suffix it gives you answer right away.\nvar data = jetpack.read('file.txt');\nconsole.log(data);\n\n// Want to make that call asynchronous? Just add the word \"Async\"\n// and it will give you promise instead of ready value.\njetpack.readAsync('file.txt')\n.then(function (data) {\n    console.log(data);\n});\n```\n\n## Every jetpack instance has its internal CWD\nYou can create many jetpack objects with different internal working directories (which are independent of `process.cwd()`) and work on directories in a little more object-oriented manner.\n```js\nvar src = jetpack.cwd('path/to/source');\nvar dest = jetpack.cwd('path/to/destination');\nsrc.copy('foo.txt', dest.path('bar.txt'));\n```\n\n## JSON is a first class citizen\nYou can write JavaScript object directly to disk and it will be transformed to JSON automatically.\n```js\nvar obj = { greet: \"Hello World!\" };\njetpack.write('file.json', obj);\n```\nThen you can get your object back just by telling read method that it's a JSON.\n```js\nvar obj = jetpack.read('file.json', 'json');\n```\n\n## Throws errors at you as the last resort\nEveryone who did something with files for sure seen (and probably hates) *\"ENOENT, no such file or directory\"* error. Jetpack tries to recover from that error if possible.  \n1. For write/creation operations, if any of parent directories doesn't exist jetpack will just create lacking directories.  \n2. For read/inspect operations, if file or directory doesn't exist `undefined` is returned instead of throwing.\n\n## All methods play nicely with each other (examples)\n**Note:** All examples are synchronous. Unfortunately asynchronous equivalents won't be that pretty.\n\n#### Great for build scripts\n```js\nvar src = jetpack.cwd('path/to/source');\nvar dest = jetpack.dir('path/to/destination', { empty: true });\n\nsrc.copy('.', dest.path(), {\n    matching: ['./vendor/**', '*.html', '*.png', '*.jpg']\n});\n\nvar config = src.read('config.json', 'json');\nconfig.env = 'production';\ndest.write('config.json', config);\n```\n\n#### Files creation in declarative style\nLet's say you want to create folder structure:\n```\n.\n|- greets\n   |- greet.txt\n   |- greet.json\n|- greets-i18n\n   |- polish.txt\n```\nPeace of cake with jetpack!\n```js\njetpack\n.dir('greets')\n    .file('greet.txt', { content: 'Hello world!' })\n    .file('greet.json', { content: { greet: 'Hello world!' } })\n    .cwd('..')\n.dir('greets-i18n')\n    .file('polish.txt', { content: 'Witaj świecie!' });\n```\n\n#### Delete all tmp files inside directory tree\n```js\njetpack.find('my-dir', {\n    matching: '*.tmp'\n})\n.forEach(jetpack.remove);\n```\n\n#### Check if two files have the same content\n```js\nvar file1 = jetpack.inspect('file1', { checksum: 'md5' });\nvar file2 = jetpack.inspect('file2', { checksum: 'md5' });\nvar areTheSame = (file1.md5 === file2.md5);\n```\n\n\n# <a name=\"api\"></a> API Docs\n\nAPI methods have blocking and non-blocking equivalents:\n```js\n// Synchronous call\nvar data = jetpack.read('file.txt');\nconsole.log(data);\n\n// Asynchronous call\njetpack.readAsync('file.txt')\n.then(function (data) {\n    console.log(data);\n});\n```\n\n**Methods:**\n- [append](#appendpath-data-options)\n- [copy](#copyfrom-to-options)\n- [createReadStream](#createreadstreampath-options)\n- [createWriteStream](#createwritestreampath-options)\n- [cwd](#cwdpath)\n- [dir](#dirpath-criteria)\n- [exists](#existspath)\n- [file](#filepath-criteria)\n- [find](#findpath-searchoptions)\n- [inspect](#inspectpath-options)\n- [inspectTree](#inspecttreepath-options)\n- [list](#listpath)\n- [move](#movefrom-to)\n- [path](#pathparts)\n- [read](#readpath-returnas)\n- [remove](#removepath)\n- [rename](#renamepath-newname)\n- [symlink](#symlinksymlinkvalue-path)\n- [write](#writepath-data-options)\n\n## append(path, data, [options])\nasynchronous: **appendAsync(path, data, [options])**\n\nAppends given data to the end of file. If file (or any parent directory) doesn't exist, creates it (or them).\n\n**parameters:**  \n`path` the path to file.  \n`data` data to append (could be `String` or `Buffer`).  \n`options` (optional) `Object` with possible fields:\n* `mode` if the file doesn't exist yet, will be created with given mode. Value could be number (eg. `0700`) or string (eg. `'700'`).\n\n**returns:**  \nNothing.\n\n\n## copy(from, to, [options])\nasynchronous: **copyAsync(from, to, [options])**  \n\nCopies given file or directory (with everything inside).\n\n**parameters:**  \n`from` path to location you want to copy.  \n`to` path to destination location, where the copy should be placed.  \n`options` (optional) additional options for customization. Is an `Object` with possible fields:  \n* `overwrite` (default: `false`) Whether to overwrite destination path if it exists. For directories, source directory is merged with destination directory, so files in destination which are not present in the source, will remain intact.\n* `matching` if defined will actually copy **only** items matching any of specified glob patterns and omit everything else (see examples below).\n\n**returns:**  \nNothing.\n\n**examples:**\n```javascript\n// Copies a file (and replaces it if one already exists in 'copied' directory)\njetpack.copy('file.txt', 'copied/file.txt', { overwrite: true });\n\n// Copies only .md files inside 'dir' to 'copied-dir'\njetpack.copy('dir', 'copied-dir', { matching: '*.md' });\n\n// Can add many globs as an array\njetpack.copy('dir', 'copied-dir', { matching: ['*.md', '*.txt'] });\n\n// Supports negation patterns as well\njetpack.copy('dir', 'copied-dir', { matching: ['*.md', '!top-secret.md'] });\n\n// All patterns are anchored to dir you want to copy, not to CWD.\n// So in this example directory 'dir1/dir2/images' will be copied\n// to 'copied-dir2/images'\njetpack.copy('dir1/dir2', 'copied-dir2', {\n    matching: 'images/**'\n});\n```\n\n\n## createReadStream(path, [options])\n\nJust an alias to vanilla [fs.createReadStream](http://nodejs.org/api/fs.html#fs_fs_createreadstream_path_options).\n\n\n## createWriteStream(path, [options])\n\nJust an alias to vanilla [fs.createWriteStream](http://nodejs.org/api/fs.html#fs_fs_createwritestream_path_options).\n\n\n\n## cwd([path...])\nReturns Current Working Directory (CWD) for this instance of jetpack, or creates new jetpack object with given path as its internal CWD.  \n**Note:** fs-jetpack never changes value of `process.cwd()`, the CWD we are talking about here is internal value inside every jetpack instance.\n\n**parameters:**  \n`path...` (optional) path (or many path parts) to become new CWD. Could be absolute, or relative. If relative path given new CWD will be resolved basing on current CWD of this jetpack instance.\n\n**returns:**  \nIf `path` not specified, returns CWD path of this jetpack object. For main instance of fs-jetpack it is always `process.cwd()`.  \nIf `path` specified, returns new jetpack object (totally the same thing as main jetpack). The new object resolves paths according to its internal CWD, not the global one (`process.cwd()`).\n\n**examples:**\n```javascript\n// Let's assume that process.cwd() outputs...\nconsole.log(process.cwd()); // '/one/two/three'\n// jetpack.cwd() will always return the same value as process.cwd()\nconsole.log(jetpack.cwd()); // '/one/two/three'\n\n// Now let's create new CWD context...\nvar jetParent = jetpack.cwd('..');\nconsole.log(jetParent.cwd()); // '/one/two'\n// ...and use this new context.\njetParent.dir('four'); // we just created directory '/one/two/four'\n\n// One CWD context can be used to create next CWD context.\nvar jetParentParent = jetParent.cwd('..');\nconsole.log(jetParentParent.cwd()); // '/one'\n\n// When many parameters specified they are treated as parts of path to resolve\nvar sillyCwd = jetpack.cwd('a', 'b', 'c');\nconsole.log(sillyCwd.cwd()); // '/one/two/three/a/b/c'\n```\n\n\n## dir(path, [criteria])\nasynchronous: **dirAsync(path, [criteria])**  \n\nEnsures that directory on given path exists and meets given criteria. If any criterium is not met it will be after this call.\n\n**parameters:**  \n`path` path to directory to examine.  \n`criteria` (optional) criteria to be met by the directory. Is an `Object` with possible fields:\n* `empty` (default: `false`) whether directory should be empty (no other files or directories inside). If set to `true` and directory contains any files or subdirectories all of them will be deleted.\n* `mode` ensures directory has specified mode. If not set and directory already exists, current mode will be preserved. Value could be number (eg. `0700`) or string (eg. `'700'`).\n\n**returns:**  \nNew CWD context with directory specified in `path` as CWD.  \n\n**examples:**\n```javascript\n// Creates directory if doesn't exist\njetpack.dir('new-dir');\n\n// Makes sure directory mode is 0700 and that it's empty\njetpack.dir('empty-dir', { empty: true, mode: '700' });\n\n// Because dir returns new CWD context pointing to just\n// created directory you can create dir chains.\njetpack\n.dir('main-dir') // creates 'main-dir'\n.dir('sub-dir'); // creates 'main-dir/sub-dir'\n```\n\n\n## exists(path)\nasynchronous: **existsAsync(path)**  \n\nChecks whether something exists on given `path`. This method returns values more specific than `true/false` to protect from errors like \"I was expecting directory, but it was a file\".\n\n**returns:**  \n* `false` if path doesn't exist.\n* `\"dir\"` if path is a directory.\n* `\"file\"` if path is a file.\n* `\"other\"` if none of the above.\n\n\n## file(path, [criteria])\nasynchronous: **fileAsync(path, [criteria])**  \n\nEnsures that file exists and meets given criteria. If any criterium is not met it will be after this call.\n\n**parameters:**  \n`path` path to file to examine.  \n`criteria` (optional) criteria to be met by the file. Is an `Object` with possible fields:\n* `content` sets file content. Could be `String`, `Buffer`, `Object` or `Array`. If `Object` or `Array` given to this parameter data will be written as JSON.\n* `jsonIndent` (defaults to 2) if writing JSON data this tells how many spaces should one indentation have.\n* `mode` ensures file has specified mode. If not set and file already exists, current mode will be preserved. Value could be number (eg. `0700`) or string (eg. `'700'`).\n\n**returns:**  \nJetpack object you called this method on (self).\n\n**examples:**\n```javascript\n// Creates file if doesn't exist\njetpack.file('something.txt');\n\n// Creates file with mode '777' and content 'Hello World!'\njetpack.file('hello.txt', { mode: '777', content: 'Hello World!' });\n```\n\n\n## find([path], searchOptions)\nasynchronous: **findAsync([path], searchOptions)**\n\nFinds in directory specified by `path` all files fulfilling `searchOptions`. Returned paths are relative to current CWD of jetpack instance.\n\n**parameters:**  \n`path` (optional, defaults to `'.'`) path to start search in (all subdirectories will be searched).  \n`searchOptions` is an `Object` with possible fields:\n* `matching` glob patterns of files you would like to find.\n* `files` (default `true`) whether or not should search for files.\n* `directories` (default `false`) whether or not should search for directories.\n\n**returns:**  \n`Array` of found files.\n\n**examples:**\n```javascript\n// Finds all files which has 2015 in the name\njetpack.find('my-work', { matching: '*2015*' });\n\n// Finds all .js files inside 'my-project' but excluding those in 'vendor' subtree.\njetpack.find('my-project', { matching: ['*.js', '!vendor/**/*'] });\n\n// Looks for all directories named 'foo' (and will omit all files named 'foo').\njetpack.find('my-work', { matching: ['foo'], files: false, directories: true });\n\n// Path parameter might be omitted and CWD is used as path in that case.\nvar myStuffDir = jetpack.cwd('my-stuff');\nmyStuffDir.find({ matching: ['*.md'] });\n```\n\n## inspect(path, [options])\nasynchronous: **inspectAsync(path, [options])**  \n\nInspects given path (replacement for `fs.stat`). Returned object by default contains only very basic, not platform-dependent properties (so you have something e.g. your unit tests can rely on), you can enable more properties through options object.\n\n**parameters:**  \n`path` path to inspect.  \n`options` (optional). Possible values:\n* `checksum` if specified will return checksum of inspected file. Possible values are strings `'md5'`, `'sha1'` or `'sha256'`. If given path is directory this field is ignored.\n* `mode` (default `false`) if set to `true` will add file mode (unix file permissions) value.\n* `times` (default `false`) if set to `true` will add atime, mtime and ctime fields (here called `accessTime`, `modifyTime` and `changeTime`).\n* `absolutePath` (default `false`) if set to `true` will add absolute path to this resource.\n* `symlinks` (default `false`) if set to `true` will just inspect symlink itself and not follow it.\n\n**returns:**\n`undefined` if given path doens't exist.  \nOtherwise `Object` of structure:\n```javascript\n{\n    name: \"my_dir\",\n    type: \"file\", // possible values: \"file\", \"dir\"\n    size: 123, // size in bytes, this is returned only for files\n    // if checksum option was specified:\n    md5: '900150983cd24fb0d6963f7d28e17f72',\n    // if mode option was set to true:\n    mode: 33204,\n    // if times option was set to true:\n    accessTime: [object Date],\n    modifyTime: [object Date],\n    changeTime: [object Date]\n}\n```\n\n\n## inspectTree(path, [options])\nasynchronous: **inspectTreeAsync(path, [options])**  \n\nCalls [inspect](#inspect) recursively on given path so it creates tree of all directories and sub-directories inside it.\n\n**parameters:**  \n`path` the path to inspect.  \n`options` (optional). Possible values:\n* `checksum` if specified will also calculate checksum of every item in the tree. Possible values are strings `'md5'`, `'sha1'` or `'sha256'`. Checksums for directories are calculated as checksum of all children' checksums plus their filenames (see example below).\n* `relativePath` if set to `true` every tree node will have relative path anchored to root inspected folder.\n\n**returns:**  \n`undefined` if given path doesn't exist.\nOtherwise tree of inspect objects like:\n```javascript\n{\n    name: 'my_dir',\n    type: 'dir',\n    size: 123, // this is combined size of all items in this directory\n    relativePath: '.',\n    md5: '11c68d9ad988ff4d98768193ab66a646',\n    // checksum of this directory was calculated as:\n    // md5(child[0].name + child[0].md5 + child[1].name + child[1].md5)\n    children: [\n        {\n            name: 'empty',\n            type: 'dir',\n            size: 0,\n            relativePath: './dir',\n            md5: 'd41d8cd98f00b204e9800998ecf8427e',\n            children: []\n        },{\n            name: 'file.txt',\n            type: 'file',\n            size: 123,\n            relativePath: './file.txt',\n            md5: '900150983cd24fb0d6963f7d28e17f72'\n        }\n    ]\n}\n```\n\n\n## list([path])\nasynchronous: **listAsync(path)**  \n\nLists the contents of directory. Equivalent of `fs.readdir`.\n\n**parameters:**  \n`path` (optional) path to directory you would like to list. If not specified defaults to CWD.\n\n**returns:**  \nArray of file names inside given path, or `undefined` if given path doesn't exist.\n\n\n## move(from, to)\nasynchronous: **moveAsync(from, to)**  \n\nMoves given path to new location.\n\n**parameters:**  \n`from` path to directory or file you want to move.  \n`to` path where the thing should be moved.\n\n**returns:**  \nNothing.\n\n\n## path(parts...)\nReturns path resolved to internal CWD of this jetpack object.\n\n**parameters:**  \n`parts` strings to join and resolve as path (as many as you like).\n\n**returns:**  \nResolved path as string.\n\n**examples:**\n```javascript\njetpack.cwd(); // if it returns '/one/two'\njetpack.path(); // this will return the same '/one/two'\njetpack.path('three'); // this will return '/one/two/three'\njetpack.path('..', 'four'); // this will return '/one/four'\n```\n\n\n## read(path, [returnAs])\nasynchronous: **readAsync(path, [returnAs])**  \n\nReads content of file.\n\n**parameters:**  \n`path` path to file.  \n`returnAs` (optional) how the content of file should be returned. Is a string with possible values:\n* `'utf8'` (default) content will be returned as UTF-8 String.\n* `'buffer'` content will be returned as a Buffer.\n* `'buf'` **deprecated** use `'buffer'` instead.\n* `'json'` content will be returned as parsed JSON object.\n* `'jsonWithDates'` content will be returned as parsed JSON object, and date strings in [ISO format](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) will be automatically turned into Date objects.\n\n**returns:**  \nFile content in specified format, or `undefined` if file doesn't exist.\n\n\n## remove([path])\nasynchronous: **removeAsync([path])**  \n\nDeletes given path, no matter what it is (file or directory). If path already doesn't exist ends without throwing, so you can use it as 'ensure path doesn't exist'.\n\n**parameters:**  \n`path` (optional) path to file or directory you want to remove. If not specified the remove action will be performed on current working directory (CWD).\n\n**returns:**  \nNothing.\n\n**examples:**\n```javascript\n// Deletes file\njetpack.remove('my_work/notes.txt');\n\n// Deletes directory \"important_stuff\" and everything inside\njetpack.remove('my_work/important_stuff');\n\n// Remove can be called with no parameters and will default to CWD then.\n// In this example folder 'my_work' will cease to exist.\nvar myStuffDir = jetpack.cwd('my_stuff');\nmyStuffDir.remove();\n```\n\n\n## rename(path, newName)\nasynchronous: **renameAsync(path, newName)**  \n\nRenames given file or directory.\n\n**parameters:**  \n`path` path to thing you want to change name.  \n`newName` new name for this thing (not full path, just a name).\n\n**returns:**  \nNothing.\n\n\n## symlink(symlinkValue, path)\nasynchronous: **symlinkAsync(symlinkValue, path)**  \n\nCreates symbolic link.\n\n**parameters:**  \n`symlinkValue` path where symbolic link should point.  \n`path` path where symbolic link should be put.  \n\n**returns:**  \nNothing.\n\n\n## write(path, data, [options])\nasynchronous: **writeAsync(path, data, [options])**  \n\nWrites data to file.\n\n**parameters:**  \n`path` path to file.  \n`data` data to be written. This could be `String`, `Buffer`, `Object` or `Array` (if last two used, the data will be outputted into file as JSON).  \n`options` (optional) `Object` with possible fields:\n* `atomic` (default `false`) if set to `true` the file will be written using strategy which is much more resistant to data loss. The trick is very simple, [read this to get the concept](http://stackoverflow.com/questions/17047994/transactionally-writing-files-in-node-js).\n* `jsonIndent` (defaults to 2) if writing JSON data this tells how many spaces should one indentation have.\n\n**returns:**  \nNothing.\n",
  "readmeFilename": "README.md",
  "bugs": {
    "url": "https://github.com/szwacz/fs-jetpack/issues"
  },
  "_id": "fs-jetpack@0.9.2",
  "_shasum": "93b414dbd07801863d64c81a76adc03d850c9b56",
  "_from": "fs-jetpack@^0.9.2",
  "_resolved": "https://registry.npmjs.org/fs-jetpack/-/fs-jetpack-0.9.2.tgz"
}
