Socket
Socket
Sign inDemoInstall

fs-jetpack

Package Overview
Dependencies
Maintainers
1
Versions
61
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.4.1 to 0.5.0

lib/streams.js

7

CHANGELOG.md

@@ -0,1 +1,8 @@

0.5.0 (2014-08-31)
-------------------
* **(breaking change)** Method `tree()` renamed to `inspectTree()`.
* **(breaking change)** Parameters passed to `list()` has changed.
* Methods `inspect()` and `inspectTree()` can calculate md5 and sha1 checksums.
* Added aliases to `fs.createReadStream()` and `fs.createWriteStream()`.
0.4.1 (2014-07-16)

@@ -2,0 +9,0 @@ -------------------

29

lib/copy.js

@@ -45,2 +45,8 @@ "use strict";

if (!exists.sync(from)) {
var err = new Error("Path to copy '" + from + "' doesn't exist.");
err.code = 'ENOENT';
throw err;
}
if (exists.sync(to) && options.overwrite === false) {

@@ -122,10 +128,21 @@ var err = new Error('Destination path already exists.');

exists.async(to)
.then(function (exists) {
if (exists && options.overwrite === false) {
var err = new Error('Destination path already exists.');
err.code = 'EEXIST';
exists.async(from)
.then(function (ex) {
if (!ex) {
var err = new Error("Path to copy '" + from + "' doesn't exist.");
err.code = 'ENOENT';
deferred.reject(err);
} else {
startCopying();
exists.async(to)
.then(function (ex) {
if (ex && options.overwrite === false) {
var err = new Error('Destination path already exists.');
err.code = 'EEXIST';
deferred.reject(err);
} else {
startCopying();
}
});
}

@@ -132,0 +149,0 @@ });

"use strict";
var fs = require('fs');
var crypto = require('crypto');
var pathUtil = require('path');
var Q = require('q');
var parseStat = function (path, stat) {
var createInspectObj = function (path, stat, computedChecksum) {
var obj = {};

@@ -21,5 +22,21 @@

if (computedChecksum) {
obj[computedChecksum.type] = computedChecksum.value;
}
return obj;
}
};
var checksumOfDir = function (inspectList, algo) {
if (inspectList.length === 0) {
return null;
}
var hash = crypto.createHash(algo);
inspectList.forEach(function (inspectObj) {
hash.update(inspectObj.name + (inspectObj[algo] || ''));
});
return hash.digest('hex');
};
//---------------------------------------------------------

@@ -29,3 +46,15 @@ // Sync

var inspect = function (path) {
var fileChecksum = function (path, algo) {
var hash = crypto.createHash(algo);
var data = fs.readFileSync(path);
hash.update(data);
return {
type: algo,
value: hash.digest('hex')
};
};
var inspect = function (path, options) {
options = options || {};
try {

@@ -42,9 +71,11 @@ var stat = fs.statSync(path);

}
return parseStat(path, stat);
if (stat.isFile() && options.checksum) {
var computedChecksum = fileChecksum(path, options.checksum);
}
return createInspectObj(path, stat, computedChecksum);
};
var list = function (path, mode) {
mode = mode || 'simple';
var list = function (path, useInspect) {
try {

@@ -62,8 +93,13 @@ var simpleList = fs.readdirSync(path);

if (mode === 'simple') {
if (!useInspect) {
return simpleList;
}
var inspectConfig = {};
if (typeof useInspect === 'object') {
// useInspec contains config
inspectConfig = useInspect;
}
var inspectedList = simpleList.map(function (filename) {
return inspect(pathUtil.join(path, filename));
return inspect(pathUtil.join(path, filename), inspectConfig);
});

@@ -74,13 +110,18 @@

var tree = function (path) {
var treeBranch = inspect(path);
var tree = function (path, options) {
options = options || {};
var treeBranch = inspect(path, options);
if (treeBranch && treeBranch.type === 'dir') {
treeBranch.size = 0;
//treeBranch.blockSize =
treeBranch.children = list(path).map(function (filename) {
var treeSubBranch = tree(pathUtil.join(path, filename));
var treeSubBranch = tree(pathUtil.join(path, filename), options);
treeBranch.size += treeSubBranch.size;
return treeSubBranch;
});
if (options.checksum) {
treeBranch[options.checksum] = checksumOfDir(treeBranch.children, options.checksum);
}
}

@@ -98,8 +139,40 @@

var inspectAsync = function (path) {
var fileChecksumAsync = function (path, algo) {
var deferred = Q.defer();
var hash = crypto.createHash(algo);
var s = fs.createReadStream(path);
s.on('data', function(data) {
hash.update(data);
});
s.on('end', function() {
deferred.resolve({
type: algo,
value: hash.digest('hex')
});
});
s.on('error', deferred.reject);
return deferred.promise;
};
var inspectAsync = function (path, options) {
var deferred = Q.defer();
options = options || {};
qStat(path)
.then(function (stat) {
deferred.resolve(parseStat(path, stat));
if (stat.isFile() && options.checksum) {
// Have to count checksum
fileChecksumAsync(path, options.checksum)
.then(function (computedChecksum) {
deferred.resolve(createInspectObj(path, stat, computedChecksum));
}, deferred.reject);
} else {
// Finish now
deferred.resolve(createInspectObj(path, stat, null));
}
}, function (err) {

@@ -118,11 +191,9 @@ // Detection if path exists

var listAsync = function (path, mode) {
var listAsync = function (path, useInspect) {
var deferred = Q.defer();
mode = mode || 'simple';
qReaddir(path)
.then(function (simpleList) {
if (mode === 'simple') {
if (!useInspect) {
// we are done!

@@ -132,2 +203,8 @@ deferred.resolve(simpleList);

var inspectConfig = {};
if (typeof useInspect === 'object') {
// useInspec contains config
inspectConfig = useInspect;
}
// have to call inspect for every item in array

@@ -138,3 +215,3 @@ var inspectedList = simpleList.concat();

simpleList.forEach(function (filename) {
inspectAsync(pathUtil.join(path, filename))
inspectAsync(pathUtil.join(path, filename), inspectConfig)
.then(function (inspectObj) {

@@ -169,6 +246,8 @@

var treeAsync = function (path) {
var treeAsync = function (path, options) {
var deferred = Q.defer();
inspectAsync(path)
options = options || {};
inspectAsync(path, options)
.then(function (treeBranch) {

@@ -180,3 +259,2 @@

.then(function (children) {
// now children is just an array of filename strings

@@ -189,2 +267,8 @@ treeBranch.children = children;

if (countDone === children.length) {
if (options.checksum) {
// We are done, but still have to calculate checksum of whole directory.
treeBranch[options.checksum] = checksumOfDir(treeBranch.children, options.checksum);
}
deferred.resolve(treeBranch);

@@ -199,3 +283,3 @@ }

children.forEach(function (filename, index) {
treeAsync(pathUtil.join(path, filename))
treeAsync(pathUtil.join(path, filename), options)
.then(function (treeSubBranch) {

@@ -202,0 +286,0 @@ children[index] = treeSubBranch;

@@ -16,2 +16,3 @@ // The main thing. Here everything starts.

var remove = require('./remove');
var streams = require('./streams');

@@ -72,2 +73,9 @@ // This is Jetpack Context object.

createWriteStream: function (path, options) {
return streams.createWriteStream(resolvePath(path), options);
},
createReadStream: function (path, options) {
return streams.createReadStream(resolvePath(path), options);
},
dir: function (path, criteria) {

@@ -116,14 +124,20 @@ var normalizedPath = pathUtil.resolve(getCwdPath(), path);

inspect: function (path) {
return inspector.inspect(resolvePath(path));
inspect: function (path, fieldsToInclude) {
return inspector.inspect(resolvePath(path), fieldsToInclude);
},
inspectAsync: function (path) {
return inspector.inspectAsync(resolvePath(path));
inspectAsync: function (path, fieldsToInclude) {
return inspector.inspectAsync(resolvePath(path), fieldsToInclude);
},
inspectTree: function (path, options) {
return inspector.tree(resolvePath(path), options);
},
inspectTreeAsync: function (path, options) {
return inspector.treeAsync(resolvePath(path), options);
},
list: function (path, options) {
return inspector.list(resolvePath(path), options);
list: function (path, useInspect) {
return inspector.list(resolvePath(path), useInspect);
},
listAsync: function (path, options) {
return inspector.listAsync(resolvePath(path), options);
listAsync: function (path, useInspect) {
return inspector.listAsync(resolvePath(path), useInspect);
},

@@ -163,9 +177,2 @@

tree: function (path) {
return inspector.tree(resolvePath(path));
},
treeAsync: function (path) {
return inspector.treeAsync(resolvePath(path));
},
write: function (path, data, options) {

@@ -172,0 +179,0 @@ fileOps.write(resolvePath(path), data, options);

{
"name": "fs-jetpack",
"description": "Higher level API for 'fs' library",
"version": "0.4.1",
"version": "0.5.0",
"author": "Jakub Szwacz <jakub@szwacz.com>",

@@ -6,0 +6,0 @@ "dependencies": {

@@ -41,2 +41,4 @@ fs-jetpack

* [copy(from, to, [options])](#copy)
* [createReadStream(path, [options])](#create-read-stream)
* [createWriteStream(path, [options])](#create-write-stream)
* [cwd([path])](#cwd)

@@ -46,4 +48,5 @@ * [dir(path, [criteria])](#dir)

* [file(path, [criteria])](#file)
* [inspect(path)](#inspect)
* [list(path, [mode])](#list)
* [inspect(path, [options])](#inspect)
* [inspectTree(path, [options])](#inspect-tree)
* [list(path, [useInspect])](#list)
* [move(from, to)](#move)

@@ -54,3 +57,2 @@ * [path(parts...)](#path)

* [rename(path, newName)](#rename)
* [tree(path)](#tree)
* [write(path, data, [options])](#write)

@@ -84,4 +86,4 @@

* `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.
* `only` (`Array` of patterns) will copy **only** items matching any of specified pattern. Pattern is a `String` of .gitignore-like notation [(read more)](#matching-paths).
* `allBut` (`Array` of patterns) will copy **everything except** items matching any of specified pattern. Pattern is a `String` of .gitignore-like notation [(read more)](#matching-paths). If `only` was also specified this field is ignored.
* `only` (`Array` of globs) will copy **only** items matching any of specified glob patterns [(read more)](#matching-paths).
* `allBut` (`Array` of globs) will copy **everything except** items matching any of specified glob patterns [(read more)](#matching-paths). If `only` was also specified this field is ignored.

@@ -104,2 +106,13 @@ **returns:**

## <a name="create-read-stream"></a> createReadStream(path, [options])
Just an alias to vanilla [fs.createReadStream](http://nodejs.org/api/fs.html#fs_fs_createreadstream_path_options).
## <a name="create-write-stream"></a> createWriteStream(path, [options])
Just an alias to vanilla [fs.createWriteStream](http://nodejs.org/api/fs.html#fs_fs_createwritestream_path_options).
## <a name="cwd"></a> cwd([path])

@@ -212,4 +225,4 @@ Returns Current Working Directory (CWD) for this instance of jetpack, or creates new jetpack object with given path as its internal CWD.

## <a name="inspect"></a> inspect(path)
also **inspectAsync(path)**
## <a name="inspect"></a> inspect(path, [options])
also **inspectAsync(path, [options])**

@@ -220,2 +233,4 @@ Inspects given path (replacement for fs.stat).

`path` path to inspect.
`options` (optional). Possible values:
* `checksum` if specified will return checksum of inspected file. Possible values are strings `'md5'` or `'sha1'`. If given path is directory this field is ignored and omited.

@@ -229,11 +244,50 @@ **returns:**

type: "file", // possible values: "file", "dir"
size: 123 // size in bytes, this is returned only for files
size: 123, // size in bytes, this is returned only for files
md5: '900150983cd24fb0d6963f7d28e17f72' // (if checksum option was specified)
}
```
Yep, not so much for now. Will be extended in the future.
## <a name="list"></a> list(path, [mode])
also **listAsync(path, [mode])**
## <a name="inspect-tree"></a> inspectTree(path, [options])
also **inspectTreeAsync(path, [options])**
Calls [inspect](#inspect) recursively on given path so it creates tree of all directories and sub-directories inside it.
**parameters:**
`path` the path to inspect.
`options` (optional). Possible values:
* `checksum` if specified will also calculate checksum of every item in the tree. Possible values are strings `'md5'` or `'sha1'`. Checksums for directories are calculated as checksum of all children' checksums plus their filenames (see example below).
**returns:**
`null` if given path doesn't exist.
Otherwise tree of inspect objects like:
```javascript
{
name: 'my_dir',
type: 'dir',
size: 123, // this is combined size of all items in this directory
md5: '11c68d9ad988ff4d98768193ab66a646',
// checksum of this directory was calculated as:
// md5(child[0].name + child[0].md5 + child[1].name + child[1].md5)
children: [
{
name: 'empty',
type: 'dir',
size: 0, // the directory is empty
md5: null, // can't calculate checksum of empty directory
children: []
},{
name: 'file.txt',
type: 'file',
size: 123,
md5: '900150983cd24fb0d6963f7d28e17f72'
}
]
}
```
## <a name="list"></a> list(path, [useInspect])
also **listAsync(path, [useInspect])**
Lists the contents of directory.

@@ -243,8 +297,9 @@

`path` path to directory you would like to list.
`mode` (optional) the degree of accuracy you would like to get back. Possible values:
* `'simple'` (default) returns just a list of filenames (the same as `fs.readdir()`)
* `'inspect'` performs [inspect](#inspect) on every item, and returns array of those objects
`useInspect` (optional) the type of data this call should return. Possible values:
* `false` (default) returns just a list of filenames (the same as `fs.readdir()`)
* `true` performs [inspect](#inspect) on every item in directory, and returns array of those objects
* `object` if object has been passed to this parameter, it is treated as `options` parameter for [inspect](#inspect) method, and will alter returned inspect objects
**returns:**
Array of strings or objects depending on call properies.
`Array` of strings or objects depending on call properies. Or `null` if given path doesn't exist.

@@ -294,3 +349,4 @@

* `'json'` content will be returned as parsed JSON object.
* `'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.
* `'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.
`options` (optional) is an object with possible fields:

@@ -311,4 +367,4 @@ * `safe` if set to `true` the file will be read in ["safe mode"](#safe-mode).

`options` (optional) additional conditions to removal process. Is an object with possible fields:
* `only` (`Array` of patterns) will delete **only** items matching any of specified pattern. Pattern is a `String` of .gitignore-like notation [(read more on that)](#matching-paths).
* `allBut` (`Array` of patterns) will delete **everything except** items matching any of specified pattern. Pattern is a `String` of .gitignore-like notation [(read more on that)](#matching-paths). If `only` was also specified this field is ignored.
* `only` (`Array` of globs) will delete **only** items matching any of specified glob patterns [(read more on that)](#matching-paths).
* `allBut` (`Array` of globs) will delete **everything except** items matching any of specified glob patterns [(read more on that)](#matching-paths). If `only` was also specified this field is ignored.

@@ -349,34 +405,2 @@ **returns:**

## <a name="tree"></a> tree(path)
also **treeAsync(path)**
Calls [inspect](#inspect) recursively on given path so it creates tree of all directories and sub-directories inside it.
**parameters:**
`path` the path to inspect.
**returns:**
`null` if given path doesn't exist.
Otherwise tree of inspect objects like:
```javascript
{
name: 'my_dir',
type: 'dir',
size: 123, // this is combined size of all items in this directory
children: [
{
name: 'empty',
type: 'dir',
size: 0, // the directory is empty
children: []
},{
name: 'file.txt',
type: 'file',
size: 123
}
]
}
```
## <a name="write"></a> write(path, data, [options])

@@ -392,2 +416,3 @@ also **writeAsync(path, data, [options])**

* `jsonIndent` (defaults to 0) if writing JSON data this tells how many spaces should one indentation have.
* `safe` if set to `true` the file will be written in ["safe mode"](#safe-mode).

@@ -441,3 +466,3 @@ **returns:**

### <a name="matching-paths"></a> Filtering things to copy/remove
### <a name="matching-paths"></a> Filtering things to copy/remove with "globs"
[Copy](#copy) and [remove](#remove) have option for blacklisting and whitelisting things inside directory which will be affected by the operation. For instance:

@@ -444,0 +469,0 @@ ```javascript

@@ -145,2 +145,19 @@ "use strict";

it("throws if source path doesn't exist", function (done) {
// SYNC
try {
jetpack.copy('a', 'b', { allBut: ['c'] }); // allBut used because then jetpack code follows more comlicated path
throw "to make sure this code throws"
} catch (err) {
expect(err.code).toBe('ENOENT');
}
// ASYNC
jetpack.copyAsync('a', 'b', { allBut: ['c'] })
.catch(function (err) {
expect(err.code).toBe('ENOENT');
done();
});
});
describe('overwriting behaviour', function () {

@@ -147,0 +164,0 @@

@@ -8,3 +8,3 @@ "use strict";

var helper = require('./helper');
var inspector = require('../lib/inspector');
var jetpack = require('..');

@@ -34,7 +34,7 @@ beforeEach(helper.beforeEach);

// SYNC
var data = inspector.inspect('dir/file.txt');
var data = jetpack.inspect('dir/file.txt');
expectations(data);
// ASYNC
inspector.inspectAsync('dir/file.txt')
jetpack.inspectAsync('dir/file.txt')
.then(function (data) {

@@ -56,7 +56,7 @@ expectations(data);

// SYNC
var data = inspector.inspect('dir/empty');
var data = jetpack.inspect('dir/empty');
expectations(data);
// ASYNC
inspector.inspectAsync('dir/empty')
jetpack.inspectAsync('dir/empty')
.then(function (data) {

@@ -70,7 +70,7 @@ expectations(data);

// SYNC
var data = inspector.inspect('nonexistent');
var data = jetpack.inspect('nonexistent');
expect(data).toBe(null);
// ASYNC
inspector.inspectAsync('nonexistent')
jetpack.inspectAsync('nonexistent')
.then(function (data) {

@@ -82,2 +82,48 @@ expect(data).toBe(null);

it('can output md5 checksum of a file', function (done) {
function expectations(data) {
expect(data).toEqual({
name: 'file.txt',
type: 'file',
size: 3,
md5: '900150983cd24fb0d6963f7d28e17f72' // md5 of 'abc'
});
}
// SYNC
var data = jetpack.inspect('dir/file.txt', { checksum: 'md5' });
expectations(data);
// ASYNC
jetpack.inspectAsync('dir/file.txt', { checksum: 'md5' })
.then(function (data) {
expectations(data);
done();
});
});
it('can output sha1 checksum of a file', function (done) {
function expectations(data) {
expect(data).toEqual({
name: 'file.txt',
type: 'file',
size: 3,
sha1: 'a9993e364706816aba3e25717850c26c9cd0d89d' // sha1 of 'abc'
});
}
// SYNC
var data = jetpack.inspect('dir/file.txt', { checksum: 'sha1' });
expectations(data);
// ASYNC
jetpack.inspectAsync('dir/file.txt', { checksum: 'sha1' })
.then(function (data) {
expectations(data);
done();
});
});
});

@@ -94,7 +140,7 @@

// SYNC
var list = inspector.list('dir');
var list = jetpack.list('dir');
expectations(list);
// ASYNC
inspector.listAsync('dir')
jetpack.listAsync('dir')
.then(function (list) {

@@ -125,7 +171,7 @@ expectations(list);

// SYNC
var list = inspector.list('dir', 'inspect');
var list = jetpack.list('dir', true);
expectations(list);
// ASYNC
inspector.listAsync('dir', 'inspect')
jetpack.listAsync('dir', true)
.then(function (list) {

@@ -137,9 +183,40 @@ expectations(list);

it('lists inspect objects with config', function (done) {
function expectations(data) {
expect(data).toEqual([
{
name: 'empty',
type: 'dir',
},{
name: 'file.txt',
type: 'file',
size: 3,
md5: '900150983cd24fb0d6963f7d28e17f72' // md5 of 'abc'
},{
name: 'subdir',
type: 'dir',
}
]);
}
// SYNC
var list = jetpack.list('dir', { checksum: 'md5' });
expectations(list);
// ASYNC
jetpack.listAsync('dir', { checksum: 'md5' })
.then(function (list) {
expectations(list);
done();
});
});
it("returns null if path doesn't exist", function (done) {
// SYNC
var data = inspector.list('nonexistent');
var data = jetpack.list('nonexistent');
expect(data).toBe(null);
// ASYNC
inspector.listAsync('nonexistent')
jetpack.listAsync('nonexistent')
.then(function (data) {

@@ -153,3 +230,3 @@ expect(data).toBe(null);

describe('tree', function () {
describe('inspectTree', function () {

@@ -190,7 +267,7 @@ it('crawls a directory tree', function (done) {

// SYNC
var tree = inspector.tree('dir');
var tree = jetpack.inspectTree('dir');
expectations(tree);
// ASYNC
inspector.treeAsync('dir')
jetpack.inspectTreeAsync('dir')
.then(function (tree) {

@@ -202,2 +279,54 @@ expectations(tree);

it('can compute md5 checksum of whole tree', function (done) {
function expectations(data) {
expect(data).toEqual({
name: 'dir',
type: 'dir',
size: 7,
md5: '0dc3266b245151cda5c56c7f62439202',
// md5 of 'emptyfile.txt900150983cd24fb0d6963f7d28e17f72subdir11c68d9ad988ff4d98768193ab66a646'
children: [
{
name: 'empty',
type: 'dir',
size: 0,
md5: null, // empty directory can't have md5
children: []
},{
name: 'file.txt',
type: 'file',
size: 3,
md5: '900150983cd24fb0d6963f7d28e17f72' // md5 of 'abc'
},{
name: 'subdir',
type: 'dir',
size: 4,
md5: '11c68d9ad988ff4d98768193ab66a646',
// md5 of 'file.txt025e4da7edac35ede583f5e8d51aa7ec'
children: [
{
name: 'file.txt',
type: 'file',
size: 4,
md5: '025e4da7edac35ede583f5e8d51aa7ec' // md5 of 'defg'
}
]
}
]
});
}
// SYNC
var tree = jetpack.inspectTree('dir', { checksum: 'md5' });
expectations(tree);
// ASYNC
jetpack.inspectTreeAsync('dir', { checksum: 'md5' })
.then(function (tree) {
expectations(tree);
done();
});
});
it('if given path is a file still works OK', function (done) {

@@ -214,7 +343,7 @@

// SYNC
var tree = inspector.tree('dir/file.txt');
var tree = jetpack.inspectTree('dir/file.txt');
expectations(tree);
// ASYNC
inspector.treeAsync('dir/file.txt')
jetpack.inspectTreeAsync('dir/file.txt')
.then(function (tree) {

@@ -228,7 +357,7 @@ expectations(tree);

// SYNC
var data = inspector.tree('nonexistent');
var data = jetpack.inspectTree('nonexistent');
expect(data).toBe(null);
// ASYNC
inspector.treeAsync('nonexistent')
jetpack.inspectTreeAsync('nonexistent')
.then(function (data) {

@@ -235,0 +364,0 @@ expect(data).toBe(null);

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc