Socket
Socket
Sign inDemoInstall

folder-hash

Package Overview
Dependencies
Maintainers
1
Versions
24
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

folder-hash - npm Package Compare versions

Comparing version 1.0.5 to 1.1.0

135

index.js

@@ -6,10 +6,18 @@ "use strict"

var crypto = require('crypto');
var minimatch = require('minimatch');
if (typeof Promise === 'undefined') require('when/es6-shim/Promise');
var algo = 'sha1';
var encoding = 'base64'; // 'base64', 'hex' or 'binary'
var defaultOptions = {
algo: 'sha1', // see crypto.getHashes() for options
encoding: 'base64', // 'base64', 'hex' or 'binary'
excludes: [],
match: {
basename: true,
path: true
}
};
module.exports = {
hashElement: createHash
hashElement: hashElement
}

@@ -19,8 +27,19 @@

* Create a hash over a folder or file, using either promises or error-first-callbacks.
* The parameter directoryPath is optional. This function may be called
* as createHash(filename, folderpath, fn(err, hash) {}), createHash(filename, folderpath)
* or as createHash(path, fn(err, hash) {}), createHash(path)
*
* Examples:
* - hashElement(filename, folderpath, options, fn(err, hash) {}), hashElement(filename, folderpath, options);
* - hashElement(path, fn(err, hash) {}), hashElement(path)
*
* @param {string} name - element name or an element's path
* @param {string} [dir] - directory that contains the element (if omitted is generated from name)
* @param {Object} [options] - Options
* @param {string} [options.algo='sha1'] - checksum algorithm, see options in crypto.getHashes()
* @param {string} [options.encoding='base64'] - encoding of the resulting hash. One of 'base64', 'hex' or 'binary'
* @param {string[]} [options.excludes=[]] - Array of optional exclude file glob patterns, see minimatch doc
* @param {bool} [options.match.basename=true] - Match the exclude patterns to the file/folder name
* @param {bool} [options.match.path=true] - Match the exclude patterns to the file/folder path
* @param {fn} [callback] - Error-first callback function
*/
function createHash(name, directoryPath, callback) {
var promise = parseParameters(name, directoryPath);
function hashElement(name, directoryPath, options, callback) {
var promise = parseParameters(arguments);
var callback = arguments[arguments.length-1];

@@ -39,17 +58,52 @@

function parseParameters(name, directoryPath) {
if (!isString(name)) {
function parseParameters(args) {
var elementBasename = args[0],
elementDirname = args[1],
options = args[2];
if (!isString(elementBasename)) {
return Promise.reject(new TypeError('First argument must be a string'));
}
if (!isString(directoryPath)) {
directoryPath = path.dirname(name);
name = path.basename(name);
if (!isString(elementDirname)) {
elementDirname = path.dirname(elementBasename);
elementBasename = path.basename(elementBasename);
options = args[1];
}
return hashElementPromise(name, directoryPath);
// parse options (fallback default options)
if (!isObject(options)) options = {};
['algo', 'encoding', 'excludes'].forEach(function(key) {
if (!options.hasOwnProperty(key)) options[key] = defaultOptions[key];
});
if (!options.match) options.match = {};
if (!options.match.hasOwnProperty('basename')) options.match.basename = defaultOptions.match.basename;
if (!options.match.hasOwnProperty('path')) options.match.path = defaultOptions.match.path;
if (!options.excludes || !Array.isArray(options.excludes) || options.excludes.length == 0) {
options.excludes = undefined;
} else {
// combine globs into one single RegEx
options.excludes = new RegExp(options.excludes.reduce(function (acc, exclude) {
return acc + '|' + minimatch.makeRe(exclude).source;
}, '').substr(1));
}
//console.log('parsed options:', options);
return hashElementPromise(elementBasename, elementDirname, options);
}
function hashElementPromise(name, directoryPath) {
var filepath = path.join(directoryPath, name);
function hashElementPromise(basename, dirname, options) {
var filepath = path.join(dirname, basename);
if (options.match.basename && options.excludes && options.excludes.test(basename)) {
//console.log('regex', options.excludes, 'matched to', basename);
return Promise.resolve(undefined);
}
if (options.match.path && options.excludes && options.excludes.test(filepath)) {
//console.log('regex', options.excludes, 'matched to', filepath);
return Promise.resolve(undefined);
}
return new Promise(function (resolve, reject, notify) {

@@ -62,7 +116,7 @@ fs.stat(filepath, function (err, stats) {

if (stats.isDirectory()) {
resolve(hashFolderPromise(name, directoryPath));
resolve(hashFolderPromise(basename, dirname, options));
} else if (stats.isFile()) {
resolve(hashFilePromise(name, directoryPath));
resolve(hashFilePromise(basename, dirname, options));
} else {
resolve({ name: name, hash: 'unknown element type' });
resolve({ name: basename, hash: 'unknown element type' });
}

@@ -74,8 +128,13 @@ });

function hashFolderPromise(foldername, directoryPath) {
var TAG = 'hashFolderPromise(' + foldername + ', ' + directoryPath + '):';
function hashFolderPromise(foldername, directoryPath, options) {
var folderPath = path.join(directoryPath, foldername);
var notExcluded = function notExcluded(basename) {
return !(options.match.basename && options.excludes && options.excludes.test(basename));
}
return new Promise(function (resolve, reject, notify) {
fs.readdir(folderPath, function (err, files) {
if (err) {
var TAG = 'hashFolderPromise(' + foldername + ', ' + directoryPath + '):';
console.error(TAG, err);

@@ -85,10 +144,8 @@ reject(err);

var children = files.map(function (child) {
return hashElementPromise(child, folderPath);
var children = files.filter(notExcluded).map(function (child) {
return hashElementPromise(child, folderPath, options);
});
var allChildren = Promise.all(children);
return allChildren.then(function (children) {
var hash = new HashedFolder(foldername, children);
return Promise.all(children).then(function (children) {
var hash = new HashedFolder(foldername, children.filter(notUndefined), options);
resolve(hash);

@@ -101,6 +158,6 @@ });

function hashFilePromise(filename, directoryPath) {
function hashFilePromise(filename, directoryPath, options) {
return new Promise(function (resolve, reject, notify) {
try {
var hash = crypto.createHash(algo);
var hash = crypto.createHash(options.algo);
hash.write(filename);

@@ -112,3 +169,3 @@

f.on('end', function () {
var hashedFile = new HashedFile(filename, hash);
var hashedFile = new HashedFile(filename, hash, options);
resolve(hashedFile);

@@ -124,7 +181,7 @@ });

var HashedFolder = function (name, children) {
var HashedFolder = function (name, children, options) {
this.name = name;
this.children = children;
var hash = crypto.createHash(algo);
var hash = crypto.createHash(options.algo);
hash.write(name);

@@ -137,3 +194,3 @@ children.forEach(function (child) {

this.hash = hash.digest(encoding);
this.hash = hash.digest(options.encoding);
}

@@ -158,5 +215,5 @@

var HashedFile = function (name, hash) {
var HashedFile = function (name, hash, options) {
this.name = name;
this.hash = hash.digest(encoding);
this.hash = hash.digest(options.encoding);
}

@@ -173,1 +230,9 @@

}
function isObject(obj) {
return obj != null && typeof obj === 'object'
}
function notUndefined(obj) {
return typeof obj !== undefined;
}
{
"name": "folder-hash",
"version": "1.0.5",
"version": "1.1.0",
"description": "Create a hash checksum over a folder and its content - its children and their content",

@@ -8,3 +8,5 @@ "main": "index.js",

"start": "node sample.js",
"test": "mocha --reporter spec test"
"test": "mocha --reporter spec test",
"cover": "node node_modules/istanbul/lib/cli.js cover --dir test_coverage node_modules/mocha/bin/_mocha test",
"doc": "./node_modules/.bin/jsdoc index.js"
},

@@ -21,2 +23,3 @@ "author": {

"dependencies": {
"minimatch": "^3.0.3",
"when": "^3.7.7"

@@ -27,5 +30,10 @@ },

"chai-as-promised": "^6.0.0",
"istanbul": "^0.4.5",
"jsdoc": "^3.4.3",
"mocha": "^3.2.0",
"rimraf": "^2.5.2"
},
"engines": {
"node": ">=0.10.5"
}
}

@@ -40,3 +40,11 @@ # folderHash

});
// pass options (example: exclude dotFiles)
var options = { excludes: ['.*'], match: { basename: true, path: false } };
hasher.hashElement(__dirname, options, function (error, hash)) {
if (error) return console.error('hashing failed:', error);
console.log('Result for folder "' + __dirname + '":');
console.log(hash.toString());
});
### With callbacks

@@ -57,4 +65,148 @@

});
// pass options (example: exclude dotFiles)
var options = { excludes: ['**/.*'], match: { basename: false, path: true } };
hasher.hashElement(__dirname, options, function (error, hash)) {
if (error) return console.error('hashing failed:', error);
console.log('Result for folder "' + __dirname + '":');
console.log(hash.toString());
});
### Parameters for the hashElement function
<table>
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Attributes</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>name</td>
<td>
<span>string</span>
</td>
<td>
</td>
<td>element name or an element's path</td>
</tr>
<tr>
<td>dir</td>
<td>
<span>string</span>
</td>
<td>
&lt;optional&gt;<br>
</td>
<td>directory that contains the element (if omitted is generated from name)</td>
</tr>
<tr>
<td>options</td>
<td>
<span>Object</span>
</td>
<td>
&lt;optional&gt;<br>
</td>
<td>
Options object (see below)
</td>
</tr>
<tr>
<td>callback</td>
<td>
<span>fn</span>
</td>
<td>
&lt;optional&gt;<br>
</td>
<td>Error-first callback function</td>
</tr>
</tbody>
</table>
#### Options object properties
<table>
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Attributes</th>
<th>Default</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>algo</td>
<td>
<span>string</span>
</td>
<td>
&lt;optional&gt;<br>
</td>
<td>
'sha1'
</td>
<td>checksum algorithm, see options in crypto.getHashes()</td>
</tr>
<tr>
<td>encoding</td>
<td>
<span>string</span>
</td>
<td>
&lt;optional&gt;<br>
</td>
<td>
'base64'
</td>
<td>encoding of the resulting hash. One of 'base64', 'hex' or 'binary'</td>
</tr>
<tr>
<td>excludes</td>
<td>
<span>Array.&lt;string&gt;</span>
</td>
<td>
&lt;optional&gt;<br>
</td>
<td>
[]
</td>
<td>Array of optional exclude file glob patterns, see minimatch doc</td>
</tr>
<tr>
<td>match.basename</td>
<td>
<span>bool</span>
</td>
<td>
&lt;optional&gt;<br>
</td>
<td>
true
</td>
<td>Match the exclude patterns to the file/folder name</td>
</tr>
<tr>
<td>match.path</td>
<td>
<span>bool</span>
</td>
<td>
&lt;optional&gt;<br>
</td>
<td>
true
</td>
<td>Match the exclude patterns to the file/folder path</td>
</tr>
</tbody>
</table>
## Behavior

@@ -61,0 +213,0 @@ The behavior is documented and verified in the unit tests. Execute `npm test` or `mocha test`, and have a look at the _test_ subfolder.

@@ -56,2 +56,4 @@

writeFileSync(path.join(sampleFolder, 'f3', 'subfolder1', 'file1'), 'This is another text');
mkdirSync(path.join(sampleFolder, 'empty'));
done();

@@ -58,0 +60,0 @@ });

@@ -23,2 +23,3 @@

folderHash.hashElement().should.be.rejectedWith(TypeError);
folderHash.hashElement(function () {}).should.be.rejectedWith(TypeError);
});

@@ -37,2 +38,16 @@ });

});
it('with options passed', function () {
var options = {
algo: 'sha1',
encoding: 'base64',
excludes: [],
match: {
basename: false,
path: false
}
};
return folderHash.hashElement('file1', sampleFolder, options)//.should.eventually.have.property('hash');
.then((a) => console.log('a:', a)).catch(b => console.error('b', b));
});
});

@@ -61,2 +76,13 @@

});
describe('and', function () {
it('should return a string representation', function () {
folderHash.hashElement('./', sampleFolder)
.then(function (hash) {
var str = hash.toString();
assert.ok(str);
assert.ok(str.length > 10);
})
});
});
});

@@ -139,2 +165,12 @@

});
it('f2/subfolder1 should equal f3/subfolder1 if file1 is ignored', function () {
return Promise.all([
folderHash.hashElement(path.join(sampleFolder, 'f3/subfolder1'), { excludes: ['**/.*', 'file1'] }),
folderHash.hashElement(path.join(sampleFolder, 'f2/subfolder1'), { excludes: ['**/.*', 'file1'] })
]).then(function (hashes) {
assert.ok(hashes.length == 2, 'should have returned two hashes');
assert.equal(hashes[0].hash, hashes[1].hash);
})
});
});

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

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

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc