Skip to content

Commit 4684767

Browse files
committedJan 30, 2022
feat: proper jsdocs, cleaner option handling code
1 parent 2ea03de commit 4684767

File tree

1 file changed

+84
-42
lines changed

1 file changed

+84
-42
lines changed
 

‎lib/index.js

+84-42
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,62 @@ const substitute = require('substitute');
88

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

11+
/**
12+
* [Slugify options](https://github.com/simov/slugify#options)
13+
*
14+
* @typedef {Object} SlugifyOptions
15+
* @property {boolean} extend extend known unicode symbols with a `{'char': 'replacement'}` object
16+
* @property {string} [replacement='-'] replace spaces with replacement character, defaults to `-`
17+
* @property {RegExp} [remove] remove characters that match regex
18+
* @property {boolean} [lower=true] convert to lower case, defaults to `true`
19+
* @property {boolean} [strict=false] strip special characters except replacement, defaults to `false`
20+
* @property {string} [locale] language code of the locale to use
21+
* @property {boolean} trim trim leading and trailing replacement chars, defaults to `true`
22+
*/
23+
24+
/**
25+
* @callback slugFunction
26+
* @param {string} filepath
27+
* @returns {string} slug
28+
*/
29+
30+
/**
31+
* Linkset definition
32+
*
33+
* @typedef {Object} Linkset
34+
* @property {boolean} [isDefault] Whether this linkset should be used as the default instead
35+
* @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
36+
* @property {string} pattern A permalink pattern to transform file paths into, e.g. `blog/:date/:title`
37+
* @property {SlugifyOptions|slugFunction} [slug] [Slugify options](https://github.com/simov/slugify) or a custom slug function of the form `(pathpart) => string`
38+
* @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`.
39+
*/
40+
41+
/**
42+
* `@metalsmith/permalinks` options & default linkset
43+
*
44+
* @typedef {Object} Options
45+
* @property {string} [pattern] A permalink pattern to transform file paths into, e.g. `blog/:date/:title`
46+
* @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`.
47+
* @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.
48+
* @property {string} [indexFile='index.html'] Basename of the permalinked file (default: `index.html`)
49+
* @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`
50+
* @property {boolean} [duplicatesFail=false] Set to `true` to throw an error if multiple file path transforms result in the same permalink. `false` by default
51+
* @property {Linkset[]} [linksets] An array of additional linksets
52+
* @property {SlugifyOptions|slugFunction} [slug] [Slugify options](https://github.com/simov/slugify) or a custom slug function of the form `(pathpart) => string`
53+
*/
54+
55+
/** @type {Options} */
56+
const defaultOptions = {
57+
pattern: null,
58+
date: 'YYYY/MM/DD',
59+
slug: { lower: true },
60+
relative: true,
61+
indexFile: 'index.html',
62+
unique: false,
63+
duplicatesFail: false,
64+
linksets: [],
65+
}
66+
1167
/**
1268
* Maps the slugify function to slug to maintain compatibility
1369
*
@@ -16,19 +72,20 @@ const error = debug.extend('error');
1672
*
1773
* @return {String}
1874
*/
19-
const slug = (text, options = {}) => {
20-
// extend if it's an object
21-
if (typeof options.extend === 'object' && options.extend !== null) {
22-
slugify.extend(options.extend);
23-
}
75+
function slugFn(options = defaultOptions) {
76+
return text => {
77+
if (typeof options.extend === 'object' && options.extend !== null) {
78+
slugify.extend(options.extend);
79+
}
2480

25-
return slugify(text, Object.assign({}, { lower: true }, options));
81+
return slugify(text, Object.assign({}, { lower: true }, options));
82+
}
2683
};
2784

2885
/**
2986
* Re-links content
3087
*
31-
* @param {Object} data
88+
* @param {import('metalsmith').File} data
3289
* @param {Object} moved
3390
*
3491
* @return {Void}
@@ -45,39 +102,33 @@ const relink = (data, moved) => {
45102
/**
46103
* Normalize an options argument.
47104
*
48-
* @param {String/Object} options
49-
*
105+
* @param {string|Options} options
50106
* @return {Object}
51107
*/
52-
const normalize = options => {
108+
const normalizeOptions = options => {
53109
if (typeof options === 'string') {
54110
options = { pattern: options };
55111
}
56-
57-
options = options || {};
58-
options.date =
59-
typeof options.date === 'string'
60-
? format(options.date)
61-
: format('YYYY/MM/DD');
62-
options.relative = Object.prototype.hasOwnProperty.call(options, 'relative')
63-
? options.relative
64-
: true;
65-
options.linksets = options.linksets || [];
112+
options = Object.assign({}, defaultOptions, options)
113+
options.date = format(options.date)
114+
if (typeof options.slug !== 'function') {
115+
options.slug = slugFn(options.slug)
116+
}
66117
return options;
67118
};
68119

69120
/**
70121
* Return a formatter for a given moment.js format `string`.
71122
*
72-
* @param {String} string
123+
* @param {string} string
73124
* @return {Function}
74125
*/
75126
const format = string => date => moment(date).utc().format(string);
76127

77128
/**
78129
* Get a list of sibling and children files for a given `file` in `files`.
79130
*
80-
* @param {String} file
131+
* @param {string} file
81132
* @param {Object} files
82133
* @return {Object}
83134
*/
@@ -104,7 +155,7 @@ const family = (file, files) => {
104155
/**
105156
* Get a list of files that exists in a folder named after `file` for a given `file` in `files`.
106157
*
107-
* @param {String} file
158+
* @param {string} file
108159
* @param {Object} files
109160
* @return {Object}
110161
*/
@@ -151,7 +202,7 @@ const resolve = str => {
151202
/**
152203
* Replace a `pattern` with a file's `data`.
153204
*
154-
* @param {String} pattern (optional)
205+
* @param {string} pattern (optional)
155206
* @param {Object} data
156207
* @param {Object} options
157208
*
@@ -168,10 +219,7 @@ const replace = (pattern, data, options) => {
168219
if (val instanceof Date) {
169220
ret[key] = options.date(val);
170221
} else {
171-
ret[key] =
172-
typeof options.slug === 'function'
173-
? options.slug(val.toString())
174-
: slug(val.toString(), options.slug);
222+
ret[key] = options.slug(val.toString());
175223
}
176224
}
177225

@@ -181,7 +229,7 @@ const replace = (pattern, data, options) => {
181229
/**
182230
* Get the params from a `pattern` string.
183231
*
184-
* @param {String} pattern
232+
* @param {string} pattern
185233
* @return {Array}
186234
*/
187235
const params = pattern => {
@@ -195,26 +243,20 @@ const params = pattern => {
195243
/**
196244
* Check whether a file is an HTML file.
197245
*
198-
* @param {String} str The path
199-
* @return {Boolean}
246+
* @param {string} str The path
247+
* @return {boolean}
200248
*/
201249
const html = str => path.extname(str) === '.html';
202250

203251
/**
204252
* Metalsmith plugin that renames files so that they're permalinked properly
205253
* for a static site, aka that `about.html` becomes `about/index.html`.
206254
*
207-
* @param {Object} options
208-
* @property {String} pattern
209-
* @property {String/Function} date
210-
* @property {String} indexFile
211-
* @property {Boolean/Function} unique
212-
* @property {Boolean} duplicatesFail
213-
*
214-
* @return {Function}
255+
* @param {Options} options
256+
* @returns {import('metalsmith').Plugin}
215257
*/
216-
const plugin = options => {
217-
options = normalize(options);
258+
function inititalizePermalinks(options) {
259+
options = normalizeOptions(options);
218260

219261
const { linksets } = options;
220262
let defaultLinkset = linksets.find(ls => {
@@ -340,4 +382,4 @@ const plugin = options => {
340382
};
341383

342384
// Expose `plugin`
343-
module.exports = plugin;
385+
module.exports = inititalizePermalinks;

0 commit comments

Comments
 (0)
Please sign in to comment.