Skip to content

Commit

Permalink
feat: proper jsdocs, cleaner option handling code
Browse files Browse the repository at this point in the history
  • Loading branch information
webketje committed Jan 30, 2022
1 parent 2ea03de commit 4684767
Showing 1 changed file with 84 additions and 42 deletions.
126 changes: 84 additions & 42 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,62 @@ const substitute = require('substitute');

const error = debug.extend('error');

/**
* [Slugify options](https://github.com/simov/slugify#options)
*
* @typedef {Object} SlugifyOptions
* @property {boolean} extend extend known unicode symbols with a `{'char': 'replacement'}` object
* @property {string} [replacement='-'] replace spaces with replacement character, defaults to `-`
* @property {RegExp} [remove] remove characters that match regex
* @property {boolean} [lower=true] convert to lower case, defaults to `true`
* @property {boolean} [strict=false] strip special characters except replacement, defaults to `false`
* @property {string} [locale] language code of the locale to use
* @property {boolean} trim trim leading and trailing replacement chars, defaults to `true`
*/

/**
* @callback slugFunction
* @param {string} filepath
* @returns {string} slug
*/

/**
* Linkset definition
*
* @typedef {Object} Linkset
* @property {boolean} [isDefault] Whether this linkset should be used as the default instead
* @property {Object.<string,*>} match An object whose key:value pairs will be used to match files and transform their permalinks according to the rules in this linkset
* @property {string} pattern A permalink pattern to transform file paths into, e.g. `blog/:date/:title`
* @property {SlugifyOptions|slugFunction} [slug] [Slugify options](https://github.com/simov/slugify) or a custom slug function of the form `(pathpart) => string`
* @property {string} [date='YYYY/MM/DD'] [Moment.js format string](https://momentjs.com/docs/#/displaying/format/) to transform Date link parts into, defaults to `YYYY/MM/DD`.
*/

/**
* `@metalsmith/permalinks` options & default linkset
*
* @typedef {Object} Options
* @property {string} [pattern] A permalink pattern to transform file paths into, e.g. `blog/:date/:title`
* @property {string} [date='YYYY/MM/DD'] [Moment.js format string](https://momentjs.com/docs/#/displaying/format/) to transform Date link parts into, defaults to `YYYY/MM/DD`.
* @property {boolean|'folder'} [relative=true] When `true` (by default), will duplicate sibling files so relative links keep working in resulting structure. Turn off by setting `false`. Can also be set to `folder`, which uses a strategy that considers files in folder as siblings if the folder is named after the html file.
* @property {string} [indexFile='index.html'] Basename of the permalinked file (default: `index.html`)
* @property {boolean|Function} [unique] Set to `true` to add a number to duplicate permalinks (default: `false`), or specify a custom duplicate handling callback of the form `(permalink, files, file, options) => string`
* @property {boolean} [duplicatesFail=false] Set to `true` to throw an error if multiple file path transforms result in the same permalink. `false` by default
* @property {Linkset[]} [linksets] An array of additional linksets
* @property {SlugifyOptions|slugFunction} [slug] [Slugify options](https://github.com/simov/slugify) or a custom slug function of the form `(pathpart) => string`
*/

/** @type {Options} */
const defaultOptions = {
pattern: null,
date: 'YYYY/MM/DD',
slug: { lower: true },
relative: true,
indexFile: 'index.html',
unique: false,
duplicatesFail: false,
linksets: [],
}

/**
* Maps the slugify function to slug to maintain compatibility
*
Expand All @@ -16,19 +72,20 @@ const error = debug.extend('error');
*
* @return {String}
*/
const slug = (text, options = {}) => {
// extend if it's an object
if (typeof options.extend === 'object' && options.extend !== null) {
slugify.extend(options.extend);
}
function slugFn(options = defaultOptions) {
return text => {
if (typeof options.extend === 'object' && options.extend !== null) {
slugify.extend(options.extend);
}

return slugify(text, Object.assign({}, { lower: true }, options));
return slugify(text, Object.assign({}, { lower: true }, options));
}
};

/**
* Re-links content
*
* @param {Object} data
* @param {import('metalsmith').File} data
* @param {Object} moved
*
* @return {Void}
Expand All @@ -45,39 +102,33 @@ const relink = (data, moved) => {
/**
* Normalize an options argument.
*
* @param {String/Object} options
*
* @param {string|Options} options
* @return {Object}
*/
const normalize = options => {
const normalizeOptions = options => {
if (typeof options === 'string') {
options = { pattern: options };
}

options = options || {};
options.date =
typeof options.date === 'string'
? format(options.date)
: format('YYYY/MM/DD');
options.relative = Object.prototype.hasOwnProperty.call(options, 'relative')
? options.relative
: true;
options.linksets = options.linksets || [];
options = Object.assign({}, defaultOptions, options)
options.date = format(options.date)
if (typeof options.slug !== 'function') {
options.slug = slugFn(options.slug)
}
return options;
};

/**
* Return a formatter for a given moment.js format `string`.
*
* @param {String} string
* @param {string} string
* @return {Function}
*/
const format = string => date => moment(date).utc().format(string);

/**
* Get a list of sibling and children files for a given `file` in `files`.
*
* @param {String} file
* @param {string} file
* @param {Object} files
* @return {Object}
*/
Expand All @@ -104,7 +155,7 @@ const family = (file, files) => {
/**
* Get a list of files that exists in a folder named after `file` for a given `file` in `files`.
*
* @param {String} file
* @param {string} file
* @param {Object} files
* @return {Object}
*/
Expand Down Expand Up @@ -151,7 +202,7 @@ const resolve = str => {
/**
* Replace a `pattern` with a file's `data`.
*
* @param {String} pattern (optional)
* @param {string} pattern (optional)
* @param {Object} data
* @param {Object} options
*
Expand All @@ -168,10 +219,7 @@ const replace = (pattern, data, options) => {
if (val instanceof Date) {
ret[key] = options.date(val);
} else {
ret[key] =
typeof options.slug === 'function'
? options.slug(val.toString())
: slug(val.toString(), options.slug);
ret[key] = options.slug(val.toString());
}
}

Expand All @@ -181,7 +229,7 @@ const replace = (pattern, data, options) => {
/**
* Get the params from a `pattern` string.
*
* @param {String} pattern
* @param {string} pattern
* @return {Array}
*/
const params = pattern => {
Expand All @@ -195,26 +243,20 @@ const params = pattern => {
/**
* Check whether a file is an HTML file.
*
* @param {String} str The path
* @return {Boolean}
* @param {string} str The path
* @return {boolean}
*/
const html = str => path.extname(str) === '.html';

/**
* Metalsmith plugin that renames files so that they're permalinked properly
* for a static site, aka that `about.html` becomes `about/index.html`.
*
* @param {Object} options
* @property {String} pattern
* @property {String/Function} date
* @property {String} indexFile
* @property {Boolean/Function} unique
* @property {Boolean} duplicatesFail
*
* @return {Function}
* @param {Options} options
* @returns {import('metalsmith').Plugin}
*/
const plugin = options => {
options = normalize(options);
function inititalizePermalinks(options) {
options = normalizeOptions(options);

const { linksets } = options;
let defaultLinkset = linksets.find(ls => {
Expand Down Expand Up @@ -340,4 +382,4 @@ const plugin = options => {
};

// Expose `plugin`
module.exports = plugin;
module.exports = inititalizePermalinks;

0 comments on commit 4684767

Please sign in to comment.