metalsmith-collections/lib/index.js

166 lines
3.6 KiB
JavaScript
Raw Normal View History

2014-02-05 15:06:46 -08:00
2014-02-06 22:55:26 -08:00
var debug = require('debug')('metalsmith-collections');
2014-02-06 23:16:04 -08:00
var extend = require('extend');
2014-03-06 14:33:37 -08:00
var Matcher = require('minimatch').Minimatch;
var unique = require('uniq');
var read = require('fs').readFileSync;
2014-08-05 10:35:59 -07:00
var loadMetadata = require('read-metadata').sync;
2014-02-05 15:06:46 -08:00
/**
* Expose `plugin`.
*/
module.exports = plugin;
/**
* Metalsmith plugin that adds `collections` of files to the global
* metadata as a sorted array.
*
* @param {Object} collections (optional)
* @return {Function}
*/
function plugin(opts){
2014-03-06 14:40:19 -08:00
opts = normalize(opts);
var keys = Object.keys(opts);
2014-03-06 14:33:37 -08:00
var match = matcher(opts);
2014-02-05 15:06:46 -08:00
return function(files, metalsmith, done){
var metadata = metalsmith.metadata();
/**
2014-03-06 14:33:37 -08:00
* Find the files in each collection.
*/
2014-02-05 15:06:46 -08:00
Object.keys(files).forEach(function(file){
2014-02-06 22:55:26 -08:00
debug('checking file: %s', file);
2014-02-05 15:06:46 -08:00
var data = files[file];
2014-03-06 14:33:37 -08:00
match(file, data).forEach(function(key){
metadata[key] = metadata[key] || [];
metadata[key].push(data);
data.collection = key;
2014-03-06 14:33:37 -08:00
});
2014-02-05 15:06:46 -08:00
});
/**
* Ensure that a default empty collection exists.
*/
keys.forEach(function(key) {
metadata[key] = metadata[key] || [];
});
/**
2014-03-25 14:15:52 -07:00
* Sort the collections.
*/
keys.forEach(function(key){
debug('sorting collection: %s', key);
var settings = opts[key];
var sort = settings.sortBy || 'date';
var col = metadata[key];
2014-03-25 14:15:52 -07:00
if ('function' == typeof sort) {
col.sort(sort);
} else {
col.sort(function(a, b){
a = a[sort];
b = b[sort];
if (!a && !b) return 0;
if (!a) return -1;
if (!b) return 1;
if (b > a) return -1;
if (a > b) return 1;
return 0;
});
}
if (settings.reverse) col.reverse();
});
/**
* Add `next` and `previous` references.
*/
keys.forEach(function(key){
debug('referencing collection: %s', key);
var col = metadata[key];
var last = col.length - 1;
col.forEach(function(file, i){
if (0 != i) file.previous = col[i-1];
if (last != i) file.next = col[i+1];
});
2014-02-05 15:06:46 -08:00
});
/**
* Add collection metadata
*/
keys.forEach(function(key){
debug('adding metadata: %s', key);
var settings = opts[key];
var col = metadata[key];
2014-07-30 10:37:46 -07:00
col.metadata = (typeof settings.metadata === 'string') ?
loadMetadata(settings.metadata) :
settings.metadata;
});
/**
* Add them grouped together to the global metadata.
*/
metadata.collections = {};
keys.forEach(function(key){
return metadata.collections[key] = metadata[key];
});
done();
2014-02-05 15:06:46 -08:00
};
2014-03-06 14:33:37 -08:00
}
2014-03-06 14:40:19 -08:00
/**
* Normalize an `options` dictionary.
*
* @param {Object} options
*/
function normalize(options){
options = options || {};
for (var key in options) {
var val = options[key];
if ('string' == typeof val) options[key] = { pattern: val };
}
return options;
}
2014-03-06 14:33:37 -08:00
/**
* Generate a matching function for a given set of `collections`.
*
* @param {Object} collections
* @return {Function}
*/
function matcher(cols){
var keys = Object.keys(cols);
var matchers = {};
keys.forEach(function(key){
var opts = cols[key];
if (!opts.pattern) return;
matchers[key] = new Matcher(opts.pattern);
});
return function(file, data){
var matches = [];
var key = data.collection;
if (key && ~keys.indexOf(key)) matches.push(key);
for (key in matchers){
var m = matchers[key];
if (m && m.match(file)) matches.push(key);
}
return unique(matches);
};
}