diff --git a/README.md b/README.md index 3dccff957..84ff50fda 100644 --- a/README.md +++ b/README.md @@ -14,11 +14,13 @@ In-memory file-system with [Node's `fs` API](https://nodejs.org/api/fs.html). - Permissions may* be implemented in the future - Can be used in browser, see [`memfs-webpack`](https://github.com/streamich/memfs-webpack) -Install: +### Install - npm install --save memfs +```shell +npm install --save memfs +``` -Usage: +## Usage ```js import {fs} from 'memfs'; @@ -46,27 +48,17 @@ vol.readFileSync('/app/src/index.js', 'utf8'); // 2 Export to JSON: ```js -vol.writeFileSync('/script.sh', '#! /bin/bash'); -vol.toJSON(); // {"/script.sh": "#! /bin/bash"} +vol.writeFileSync('/script.sh', 'sudo rm -rf *'); +vol.toJSON(); // {"/script.sh": "sudo rm -rf *"} ``` Use it for testing: ```js vol.writeFileSync('/foo', 'bar'); -expect(vol.toJSON()).to.eql({"/foo": "bar"}); +expect(vol.toJSON()).toEqual({"/foo": "bar"}); ``` -#### See also - -Other filesystem goodies: - - - [`spyfs`][spyfs] - spies on filesystem actions - - [`unionfs`][unionfs] - creates a union of multiple filesystem volumes - - [`linkfs`][linkfs] - redirects filesystem paths - - [`fs-monkey`][fs-monkey] - monkey-patches Node's `fs` module and `require` function - - [`libfs`](https://github.com/streamich/full-js/blob/master/src/lib/fs.ts) - real filesystem (that executes UNIX system calls) implemented in JavaScript - Create as many filesystem volumes as you need: ```js @@ -103,263 +95,29 @@ patchRequire(vol); require('/index'); // hi world ``` -## Dependencies - -This package depends on the following Node modules: `buffer`, `events`, -`streams`, `path`. - -It also uses `process` and `setImmediate` globals, but mocks them, if not -available. - -## Reference - -#### `vol` vs `fs` - -This package exports `vol` and `fs` objects which both can be used for -filesystem operations but are slightly different. - -```js -import {vol, fs} from 'memfs'; -``` - -`vol` is an instance of `Volume` constructor, it is the default volume created -for your convenience. `fs` is an *fs-like* object created from `vol` using -`createFsFromVolume(vol)`, see reference below. - -All contents of the `fs` object are also exported individually, so you can use -`memfs` just like you would use the `fs` module: - -```js -import {readFileSync, F_OK, ReadStream} from 'memfs'; -``` - -#### `Volume` Constructor - -`Volume` is a constructor function for creating new volumes: - -```js -import {Volume} from 'memfs'; -const vol = new Volume; -``` - -`Volume` implements all [Node's filesystem methods](https://nodejs.org/api/fs.html): - -```js -vol.writeFileSync('/foo', 'bar'); -``` - -But it does not hold constants and its methods are not bound to `vol`: +## Docs -```js -vol.F_OK; // undefined -``` - -A new volume can be create using the `Volume.fromJSON` convenience method: - -```js -const vol = Volume.fromJSON({ - '/app/index.js': '...', - '/app/package.json': '...', -}); -``` - -It is just a shorthand for `vol.fromJSON`, see below. + - [Reference](./docs/reference.md) + - [Relative paths](./docs/relative-paths.md) + - [API status](./docs/api-status.md) -#### `Volume` instance `vol` - -###### `vol.fromJSON(json[, cwd])` - -Adds files from a flat `json` object to the volume `vol`. The `cwd` argument -is optional and is used to compute absolute file paths, if a file path is -given in a relative form. - -**Note:** To remove all existing files, use `vol.reset()` method. - -```js -vol.fromJSON({ - './index.js': '...', - './package.json': '...', -}, '/app'); -``` -###### `vol.mountSync(cwd, json)` +## See also -Legacy method, which is just an alias for `vol.fromJSON`. - -###### `vol.toJSON([paths[, json[, isRelative]]])` - -Exports the whole contents of the volume recursively to a flat JSON object. - -`paths` is an optional argument that specifies one or more paths to be exported. -If this argument is omitted, the whole volume is exported. `paths` can be -an array of paths. A path can be a string, `Buffer` or an `URL` object. - -`json` is an optional object parameter which will be populated with the exported files. - -`isRelative` is boolean that specifies if returned paths should be relative. - -**Note:** JSON contains only files, empty folders will be absent. - -###### `vol.reset()` - -Removes all files from the volume. - -```js -vol.fromJSON({'/index.js': '...'}); -vol.toJSON(); // {'/index.js': '...' } -vol.reset(); -vol.toJSON(); // {} -``` - -###### `vol.mkdirp(path, callback)` - -Creates a directory tree recursively. `path` specifies a directory to -create and can be a string, `Buffer`, or an `URL` object. `callback` is -called on completion and may receive only one argument - an `Error` object. - -###### `vol.mkdirpSync(path)` - -A synchronous version of `vol.mkdirp()`. This method throws. - -#### `createFsFromVolume(vol)` - -Returns an *fs-like* object created from a `Volume` instance `vol`. - -```js -import {createFsFromVolume, Volume} from 'memfs'; - -const vol = new Volume; -const fs = createFsFromVolume(vol); -``` - -The idea behind the *fs-like* object is to make it identical to the one -you get from `require('fs')`. Here are some things this function does: - - - Binds all methods, so you can do: - - ```js - const {createFileSync, readFileSync} = fs; - ``` - - - Adds constants `fs.constants`, `fs.F_OK`, etc. - -# Relative paths - -If you work with *absolute* paths, you should get what you expect from `memfs`. - -You can also use *relative* paths but the gotcha is that then `memfs` needs -to somehow resolve those relative paths to absolute paths. `memfs` will use -the value of `process.cwd()` to resolve the absolute paths. The problem is -that `process.cwd()` specifies the *current working directory* of your -on-disk filesystem and you will probably not have that directory available in -`memfs`. - -The best solution is to always use absolute paths. Alternatively, you can use -`mkdirp` method to recursively create the current working directory in your -volume: - -```js -vol.mkdirpSync(process.cwd()); -``` + - [`spyfs`][spyfs] - spies on filesystem actions + - [`unionfs`][unionfs] - creates a union of multiple filesystem volumes + - [`linkfs`][linkfs] - redirects filesystem paths + - [`fs-monkey`][fs-monkey] - monkey-patches Node's `fs` module and `require` function + - [`libfs`](https://github.com/streamich/full-js/blob/master/src/lib/fs.ts) - real filesystem (that executes UNIX system calls) implemented in JavaScript -Or, you can set the current working directory to `/`, which -is one folder that exists in all your `memfs` volumes: - -```js -process.chdir('/'); -``` +## Dependencies -# API Status - -All of the [Node's `fs` API](https://nodejs.org/api/fs.html) is implemented. -Some error messages may be inaccurate. File permissions are currently not -implemented (you have access to any file), basically `fs.access()` is a no-op. - - - [x] Constants - - [x] `FSWatcher` - - [x] `ReadStream` - - [x] `WriteStream` - - [x] `Stats` - - [x] `access(path[, mode], callback)` - - Does not check permissions - - [x] `accessSync(path[, mode])` - - Does not check permissions - - [x] `appendFile(file, data[, options], callback)` - - [x] `appendFileSync(file, data[, options])` - - [x] `chmod(path, mode, callback)` - - [x] `chmodSync(path, mode)` - - [x] `chown(path, uid, gid, callback)` - - [x] `chownSync(path, uid, gid)` - - [x] `close(fd, callback)` - - [x] `closeSync(fd)` - - [x] `createReadStream(path[, options])` - - [x] `createWriteStream(path[, options])` - - [x] `exists(path, callback)` - - [x] `existsSync(path)` - - [x] `fchmod(fd, mode, callback)` - - [x] `fchmodSync(fd, mode)` - - [x] `fchown(fd, uid, gid, callback)` - - [x] `fchownSync(fd, uid, gid)` - - [x] `fdatasync(fd, callback)` - - [x] `fdatasyncSync(fd)` - - [x] `fstat(fd, callback)` - - [x] `fstatSync(fd)` - - [x] `fsync(fd, callback)` - - [x] `fsyncSync(fd)` - - [x] `ftruncate(fd[, len], callback)` - - [x] `ftruncateSync(fd[, len])` - - [x] `futimes(fd, atime, mtime, callback)` - - [x] `futimesSync(fd, atime, mtime)` - - [x] `lchmod(path, mode, callback)` - - [x] `lchmodSync(path, mode)` - - [x] `lchown(path, uid, gid, callback)` - - [x] `lchownSync(path, uid, gid)` - - [x] `link(existingPath, newPath, callback)` - - [x] `linkSync(existingPath, newPath)` - - [x] `lstat(path, callback)` - - [x] `lstatSync(path)` - - [x] `mkdir(path[, mode], callback)` - - [x] `mkdirSync(path[, mode])` - - [x] `mkdtemp(prefix[, options], callback)` - - [x] `mkdtempSync(prefix[, options])` - - [x] `open(path, flags[, mode], callback)` - - [x] `openSync(path, flags[, mode])` - - [x] `read(fd, buffer, offset, length, position, callback)` - - [x] `readSync(fd, buffer, offset, length, position)` - - [x] `readdir(path[, options], callback)` - - [x] `readdirSync(path[, options])` - - [x] `readFile(path[, options], callback)` - - [x] `readFileSync(path[, options])` - - [x] `readlink(path[, options], callback)` - - [x] `readlinkSync(path[, options])` - - [x] `realpath(path[, options], callback)` - - [x] `realpathSync(path[, options])` - - Caching not implemented - - [x] `rename(oldPath, newPath, callback)` - - [x] `renameSync(oldPath, newPath)` - - [x] `rmdir(path, callback)` - - [x] `rmdirSync(path)` - - [x] `stat(path, callback)` - - [x] `statSync(path)` - - [x] `symlink(target, path[, type], callback)` - - [x] `symlinkSync(target, path[, type])` - - [x] `truncate(path[, len], callback)` - - [x] `truncateSync(path[, len])` - - [x] `unlink(path, callback)` - - [x] `unlinkSync(path)` - - [x] `utimes(path, atime, mtime, callback)` - - [x] `utimesSync(path, atime, mtime)` - - [x] `watch(filename[, options][, listener])` - - [x] `watchFile(filename[, options], listener)` - - [x] `unwatchFile(filename[, listener])` - - [x] `write(fd, buffer[, offset[, length[, position]]], callback)` - - [x] `write(fd, string[, position[, encoding]], callback)` - - [x] `writeFile(file, data[, options], callback)` - - [x] `writeFileSync(file, data[, options])` - - [x] `writeSync(fd, buffer[, offset[, length[, position]]])` - - [x] `writeSync(fd, string[, position[, encoding]])` +This package depends on the following Node modules: `buffer`, `events`, +`streams`, `path`. +It also uses `process` and `setImmediate` globals, but mocks them, if not +available. [npm-url]: https://www.npmjs.com/package/memfs [npm-badge]: https://img.shields.io/npm/v/memfs.svg @@ -373,31 +131,6 @@ implemented (you have access to any file), basically `fs.access()` is a no-op. +## License - -# License - -This is free and unencumbered software released into the public domain. - -Anyone is free to copy, modify, publish, use, compile, sell, or -distribute this software, either in source code form or as a compiled -binary, for any purpose, commercial or non-commercial, and by any -means. - -In jurisdictions that recognize copyright laws, the author or authors -of this software dedicate any and all copyright interest in the -software to the public domain. We make this dedication for the benefit -of the public at large and to the detriment of our heirs and -successors. We intend this dedication to be an overt act of -relinquishment in perpetuity of all present and future rights to this -software under copyright law. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - -For more information, please refer to +[Unlicense](./LICENSE) - public domain. diff --git a/docs/api-status.md b/docs/api-status.md new file mode 100644 index 000000000..a5b1e1ef9 --- /dev/null +++ b/docs/api-status.md @@ -0,0 +1,89 @@ +# API Status + +All of the [Node's `fs` API](https://nodejs.org/api/fs.html) is implemented. +Some error messages may be inaccurate. File permissions are currently not +implemented (you have access to any file), basically `fs.access()` is a no-op. + + - [x] Constants + - [x] `FSWatcher` + - [x] `ReadStream` + - [x] `WriteStream` + - [x] `Stats` + - [x] `access(path[, mode], callback)` + - Does not check permissions + - [x] `accessSync(path[, mode])` + - Does not check permissions + - [x] `appendFile(file, data[, options], callback)` + - [x] `appendFileSync(file, data[, options])` + - [x] `chmod(path, mode, callback)` + - [x] `chmodSync(path, mode)` + - [x] `chown(path, uid, gid, callback)` + - [x] `chownSync(path, uid, gid)` + - [x] `close(fd, callback)` + - [x] `closeSync(fd)` + - [x] `createReadStream(path[, options])` + - [x] `createWriteStream(path[, options])` + - [x] `exists(path, callback)` + - [x] `existsSync(path)` + - [x] `fchmod(fd, mode, callback)` + - [x] `fchmodSync(fd, mode)` + - [x] `fchown(fd, uid, gid, callback)` + - [x] `fchownSync(fd, uid, gid)` + - [x] `fdatasync(fd, callback)` + - [x] `fdatasyncSync(fd)` + - [x] `fstat(fd, callback)` + - [x] `fstatSync(fd)` + - [x] `fsync(fd, callback)` + - [x] `fsyncSync(fd)` + - [x] `ftruncate(fd[, len], callback)` + - [x] `ftruncateSync(fd[, len])` + - [x] `futimes(fd, atime, mtime, callback)` + - [x] `futimesSync(fd, atime, mtime)` + - [x] `lchmod(path, mode, callback)` + - [x] `lchmodSync(path, mode)` + - [x] `lchown(path, uid, gid, callback)` + - [x] `lchownSync(path, uid, gid)` + - [x] `link(existingPath, newPath, callback)` + - [x] `linkSync(existingPath, newPath)` + - [x] `lstat(path, callback)` + - [x] `lstatSync(path)` + - [x] `mkdir(path[, mode], callback)` + - [x] `mkdirSync(path[, mode])` + - [x] `mkdtemp(prefix[, options], callback)` + - [x] `mkdtempSync(prefix[, options])` + - [x] `open(path, flags[, mode], callback)` + - [x] `openSync(path, flags[, mode])` + - [x] `read(fd, buffer, offset, length, position, callback)` + - [x] `readSync(fd, buffer, offset, length, position)` + - [x] `readdir(path[, options], callback)` + - [x] `readdirSync(path[, options])` + - [x] `readFile(path[, options], callback)` + - [x] `readFileSync(path[, options])` + - [x] `readlink(path[, options], callback)` + - [x] `readlinkSync(path[, options])` + - [x] `realpath(path[, options], callback)` + - [x] `realpathSync(path[, options])` + - Caching not implemented + - [x] `rename(oldPath, newPath, callback)` + - [x] `renameSync(oldPath, newPath)` + - [x] `rmdir(path, callback)` + - [x] `rmdirSync(path)` + - [x] `stat(path, callback)` + - [x] `statSync(path)` + - [x] `symlink(target, path[, type], callback)` + - [x] `symlinkSync(target, path[, type])` + - [x] `truncate(path[, len], callback)` + - [x] `truncateSync(path[, len])` + - [x] `unlink(path, callback)` + - [x] `unlinkSync(path)` + - [x] `utimes(path, atime, mtime, callback)` + - [x] `utimesSync(path, atime, mtime)` + - [x] `watch(filename[, options][, listener])` + - [x] `watchFile(filename[, options], listener)` + - [x] `unwatchFile(filename[, listener])` + - [x] `write(fd, buffer[, offset[, length[, position]]], callback)` + - [x] `write(fd, string[, position[, encoding]], callback)` + - [x] `writeFile(file, data[, options], callback)` + - [x] `writeFileSync(file, data[, options])` + - [x] `writeSync(fd, buffer[, offset[, length[, position]]])` + - [x] `writeSync(fd, string[, position[, encoding]])` diff --git a/docs/reference.md b/docs/reference.md new file mode 100644 index 000000000..31ca562ca --- /dev/null +++ b/docs/reference.md @@ -0,0 +1,131 @@ +# Reference + +## `vol` vs `fs` + +This package exports `vol` and `fs` objects which both can be used for +filesystem operations but are slightly different. + +```js +import {vol, fs} from 'memfs'; +``` + +`vol` is an instance of `Volume` constructor, it is the default volume created +for your convenience. `fs` is an *fs-like* object created from `vol` using +`createFsFromVolume(vol)`, see reference below. + +All contents of the `fs` object are also exported individually, so you can use +`memfs` just like you would use the `fs` module: + +```js +import {readFileSync, F_OK, ReadStream} from 'memfs'; +``` + +## `Volume` Constructor + +`Volume` is a constructor function for creating new volumes: + +```js +import {Volume} from 'memfs'; +const vol = new Volume; +``` + +`Volume` implements all [Node's filesystem methods](https://nodejs.org/api/fs.html): + +```js +vol.writeFileSync('/foo', 'bar'); +``` + +But it does not hold constants and its methods are not bound to `vol`: + +```js +vol.F_OK; // undefined +``` + +A new volume can be create using the `Volume.fromJSON` convenience method: + +```js +const vol = Volume.fromJSON({ + '/app/index.js': '...', + '/app/package.json': '...', +}); +``` + +It is just a shorthand for `vol.fromJSON`, see below. + +## `Volume` instance `vol` + +#### `vol.fromJSON(json[, cwd])` + +Adds files from a flat `json` object to the volume `vol`. The `cwd` argument +is optional and is used to compute absolute file paths, if a file path is +given in a relative form. + +**Note:** To remove all existing files, use `vol.reset()` method. + +```js +vol.fromJSON({ + './index.js': '...', + './package.json': '...', +}, '/app'); +``` + +#### `vol.mountSync(cwd, json)` + +Legacy method, which is just an alias for `vol.fromJSON`. + +#### `vol.toJSON([paths[, json[, isRelative]]])` + +Exports the whole contents of the volume recursively to a flat JSON object. + +`paths` is an optional argument that specifies one or more paths to be exported. +If this argument is omitted, the whole volume is exported. `paths` can be +an array of paths. A path can be a string, `Buffer` or an `URL` object. + +`json` is an optional object parameter which will be populated with the exported files. + +`isRelative` is boolean that specifies if returned paths should be relative. + +**Note:** JSON contains only files, empty folders will be absent. + +#### `vol.reset()` + +Removes all files from the volume. + +```js +vol.fromJSON({'/index.js': '...'}); +vol.toJSON(); // {'/index.js': '...' } +vol.reset(); +vol.toJSON(); // {} +``` + +#### `vol.mkdirp(path, callback)` + +Creates a directory tree recursively. `path` specifies a directory to +create and can be a string, `Buffer`, or an `URL` object. `callback` is +called on completion and may receive only one argument - an `Error` object. + +#### `vol.mkdirpSync(path)` + +A synchronous version of `vol.mkdirp()`. This method throws. + +## `createFsFromVolume(vol)` + +Returns an *fs-like* object created from a `Volume` instance `vol`. + +```js +import {createFsFromVolume, Volume} from 'memfs'; + +const vol = new Volume; +const fs = createFsFromVolume(vol); +``` + +The idea behind the *fs-like* object is to make it identical to the one +you get from `require('fs')`. Here are some things this function does: + + - Binds all methods, so you can do: + + ```js + const {createFileSync, readFileSync} = fs; + ``` + + - Adds constants `fs.constants`, `fs.F_OK`, etc. diff --git a/docs/relative-paths.md b/docs/relative-paths.md new file mode 100644 index 000000000..9e15857b0 --- /dev/null +++ b/docs/relative-paths.md @@ -0,0 +1,25 @@ +# Relative paths + +If you work with *absolute* paths, you should get what you expect from `memfs`. + +You can also use *relative* paths but the gotcha is that then `memfs` needs +to somehow resolve those relative paths into absolute paths. `memfs` will use +the value of `process.cwd()` to resolve the relative paths. The problem is +that `process.cwd()` specifies the *current working directory* of your +on-disk filesystem and you will probably not have that directory available in your +`memfs` volume. + +The best solution is to always use absolute paths. Alternatively, you can use +`mkdirp` method to recursively create the current working directory in your +volume: + +```js +vol.mkdirpSync(process.cwd()); +``` + +Or, you can set the current working directory to `/`, which +is one folder that exists in all your `memfs` volumes: + +```js +process.chdir('/'); +``` diff --git a/package.json b/package.json index 7896ea8b2..99d2e2719 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "memfs", - "version": "2.5.9", + "version": "2.5.10", "description": "In-memory file-system with Node's fs API.", "main": "lib/index.js", "keywords": [ @@ -29,6 +29,7 @@ }, "devDependencies": { "jest": "^21.1.0", + "jest-tap-reporter": "1.7.0", "ts-jest": "^21.0.1", "mocha": "3.4.2", "chai": "4.1.0",