Create a hash checksum over a folder or a file.
The hashes are propagated upwards, the hash that is returned for a folder is generated over all the hashes of its children.
The hashes are generated with the sha1 algorithm and returned in base64 encoding by default.
Each file returns a name and a hash, and each folder returns additionally an array of children (file or folder elements).
Usage
First, install folder-hash with npm install --save folder-hash
or yarn add folder-hash
.
Simple example
See file ./examples/readme-example1.js.
This example excludes all files and folders starting with a dot, (e.g. .git/ and .gitignore), the node_modules folder.
const { hashElement } = require('folder-hash');
const options = {
folders: { exclude: ['.*', 'node_modules', 'test_coverage'] },
files: { include: ['*.js', '*.json'] }
};
console.log('Creating a hash over the current folder:');
hashElement('.', options)
.then(hash => {
console.log(hash.toString());
})
.catch(error => {
return console.error('hashing failed:', error);
});
The returned information looks for example like this:
Creating a hash over the current folder:
{ name: '.', hash: 'YZOrKDx9LCLd8X39PoFTflXGpRU=,'
children: [
{ name: 'examples', hash: 'aG8wg8np5SGddTnw1ex74PC9EnM=,'
children: [
{ name: 'readme-example1.js', hash: 'Xlw8S2iomJWbxOJmmDBnKcauyQ8=' }
{ name: 'readme-with-callbacks.js', hash: 'ybvTHLCQBvWHeKZtGYZK7+6VPUw=' }
{ name: 'readme-with-promises.js', hash: '43i9tE0kSFyJYd9J2O0nkKC+tmI=' }
{ name: 'sample.js', hash: 'PRTD9nsZw3l73O/w5B2FH2qniFk=' }
]}
{ name: 'index.js', hash: 'kQQWXdgKuGfBf7ND3rxjThTLVNA=' }
{ name: 'package.json', hash: 'w7F0S11l6VefDknvmIy8jmKx+Ng=' }
{ name: 'test', hash: 'H5x0JDoV7dEGxI65e8IsencDZ1A=,'
children: [
{ name: 'parameters.js', hash: '3gCEobqzHGzQiHmCDe5yX8weq7M=' }
{ name: 'test.js', hash: 'kg7p8lbaVf1CPtWLAIvkHkdu1oo=' }
]}
]}
It is also possible to only match the full path and not the basename. The same configuration could look like this:
But unfortunately *nix and Windows behave differently, so please use caution.
const options = {
folders: {
exclude: ['.*', '**.*', '**node_modules', '**test_coverage'],
matchBasename: false, matchPath: true
},
files: {
include: ['*.js', '**/*.js', '*.json', '**/*.json'],
matchBasename: false, matchPath: true
}
};
Other examples using promises
See file ./examples/readme-with-promises.js
const path = require('path');
const { hashElement } = require('folder-hash');
hashElement('test', path.join(__dirname, '..'))
.then(hash => {
console.log('Result for folder "../test":', hash.toString(), '\n');
})
.catch(error => {
return console.error('hashing failed:', error);
});
hashElement(__dirname)
.then(hash => {
console.log(`Result for folder "${__dirname}":`);
console.log(hash.toString(), '\n');
})
.catch(error => {
return console.error('hashing failed:', error);
});
const options = { encoding: 'hex', folders: { exclude: ['.*'] } };
hashElement(__dirname, options)
.then(hash => {
console.log('Result for folder "' + __dirname + '" (with options):');
console.log(hash.toString(), '\n');
})
.catch(error => {
return console.error('hashing failed:', error);
});
Other examples using error-first callbacks
See ./examples/readme-with-callbacks.js
const path = require('path');
const { hashElement } = require('folder-hash');
hashElement('test', path.join(__dirname, '..'), (error, hash) => {
if (error) {
return console.error('hashing failed:', error);
} else {
console.log('Result for folder "../test":', hash.toString(), '\n');
}
});
hashElement(__dirname, (error, hash) => {
if (error) {
return console.error('hashing failed:', error);
} else {
console.log('Result for folder "' + __dirname + '":');
console.log(hash.toString(), '\n');
}
});
const options = { algo: 'md5', files: { exclude: ['.*'], matchBasename: true } };
hashElement(__dirname, options, (error, hash) => {
if (error) {
return console.error('hashing failed:', error);
} else {
console.log('Result for folder "' + __dirname + '":');
console.log(hash.toString());
}
});
Parameters for the hashElement function
Name | Type | Attributes | Description |
---|
name |
string
|
| element name or an element's path |
dir |
string
|
<optional>
| directory that contains the element (generated from name if omitted) |
options |
Object
|
<optional>
|
Options object (see below)
|
callback |
fn
|
<optional>
| Error-first callback function |
Options object properties
Default values
{
algo: 'sha1',
encoding: 'base64',
files: {
exclude: [],
include: [],
matchBasename: true,
matchPath: false
},
folders: {
exclude: [],
include: [],
matchBasename: true,
matchPath: false
}
}
Name | Type | Attributes | Default | Description |
---|
algo |
string
|
<optional>
|
'sha1'
| checksum algorithm, see options in crypto.getHashes() |
encoding |
string
|
<optional>
|
'base64'
| encoding of the resulting hash. One of 'base64', 'hex' or 'binary' |
files |
Object
|
<optional>
|
Rules object (see below)
|
folders |
Object
|
<optional>
|
Rules object (see below)
|
Rules object properties
Name | Type | Attributes | Default | Description |
---|
exclude |
Array.<string>
|
<optional>
|
[]
| Array of optional exclude glob patterns, see minimatch doc |
include |
Array.<string>
|
<optional>
|
[]
| Array of optional include glob patterns, see minimatch doc |
matchBasename |
bool
|
<optional>
|
true
| Match the glob patterns to the file/folder name |
matchPath |
bool
|
<optional>
|
false
| Match the glob patterns to the file/folder path |
Behavior
The behavior is documented and verified in the unit tests. Execute npm test
or mocha test
, and have a look at the test subfolder.
Creating hashes over files
The hashes are the same if:
- A file is checked again
- Two files have the same name and content (but exist in different folders)
The hashes are different if:
- A file was renamed or its content was changed
- Two files have the same name but different content
- Two files have the same content but different names
Creating hashes over folders
Content means in this case a folder's children - both the files and the subfolders with their children.
The hashes are the same if:
- A folder is checked again
- Two folders have the same name and content (but have different parent folders)
The hashes are different if:
- A file somewhere in the directory structure was renamed or its content was changed
- Two folders have the same name but different content
- Two folders have the same content but different names
License
MIT, see LICENSE.txt