@metalsmith/default-values
Version:
A metalsmith plugin for setting default values to file metadata.
99 lines (90 loc) • 3.2 kB
JavaScript
import { Buffer } from 'buffer';
import get from 'dlv';
import { dset } from 'dset';
/**
* Sets defaults for object values
* @param {Array<Array<*>>} defaults
* @param {'keep'|'overwrite'} strategy
* @return {import('.').DefaultSetter} Takes an object and sets defaults
*/
function set_defaults(defaults, strategy) {
return (item, context) => {
const delta = {};
defaults.forEach(([key, defaultValue]) => {
const value = get(item, key);
if (strategy === 'overwrite' || value === void 0 || value === null || Buffer.isBuffer(value) && value.toString().trim().length === 0) {
if (typeof defaultValue === 'function') defaultValue = defaultValue(item, context);
if (Buffer.isBuffer(value) && !Buffer.isBuffer(defaultValue)) defaultValue = Buffer.from(defaultValue);
dset(item, key, defaultValue);
dset(delta, key, defaultValue);
}
});
return delta;
};
}
/**
* @callback DefaultSetter
* @param {import('metalsmith').File} file
* @param {Object<string, *>} metadata
*/
/**
* @typedef {Object} DefaultsSet
* @property {string|string[]} [pattern="**"] 1 or more glob patterns to match files. Defaults to `'**'` (all).
* @property {Object<string, *>} [defaults={}] an object whose keys will be set as file metadata keys
* @property {'keep'|'overwrite'} [strategy="keep"] Strategy to handle setting defaults to keys that are aleady defined. Defaults to `'keep'`
*/
/** @type {DefaultsSet} */
const defaultDefaultsSet = {
defaults: {},
strategy: 'keep',
pattern: '**'
};
/**
* Set `defaults` to file metadata matching `pattern`'s.
*
* @param {DefaultsSet|DefaultsSet[]} options an array of defaults sets to add to files matched by pattern
* @return {import('metalsmith').Plugin}
*
* @example
* metalsmith.use(defaultValues({
pattern: 'posts/*.md',
defaults: {
layout: 'post.hbs',
draft: false,
date(post) {
return post.stats.ctime
}
}
}))
**/
function defaultValues(options) {
return function defaultValues(files, metalsmith, done) {
const debug = metalsmith.debug('@metalsmith/default-values');
if (!Array.isArray(options) && typeof options === 'object' && options !== null) {
options = [options];
}
debug('Running with options: %O ', options);
const defaultSets = (options || []).map(defaultsSet => Object.assign({}, defaultDefaultsSet, defaultsSet));
// Loop through configurations
defaultSets.forEach(function ({
pattern,
defaults,
strategy
}) {
const matches = metalsmith.match(pattern, Object.keys(files));
const defaultsEntries = Object.entries(defaults);
debug.info('Matched %s files to pattern "%s": %o', matches.length, pattern, matches);
if (matches.length) {
const setDefaults = set_defaults(defaultsEntries, strategy);
matches.forEach(file => {
const changed = setDefaults(files[file], metalsmith.metadata());
debug.info('Values set for file "%s": %O', file, changed);
});
} else {
debug.warn('No matches for pattern "%s"', pattern);
}
});
done();
};
}
export { defaultValues as default };