@metalsmith/collections 1.3.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.cjs CHANGED
@@ -1,90 +1,116 @@
1
1
  'use strict';
2
2
 
3
3
  var get = require('lodash.get');
4
- var readMetadata = require('read-metadata');
4
+ var path = require('path');
5
5
 
6
6
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
7
7
 
8
8
  var get__default = /*#__PURE__*/_interopDefaultLegacy(get);
9
9
 
10
- function sortBy(key) {
10
+ function sortBy(key, order) {
11
+ order = order === 'asc' ? -1 : 1;
11
12
  let getKey = x => x[key];
12
-
13
13
  if (key.includes('.')) {
14
14
  getKey = x => get__default["default"](x, key);
15
15
  }
16
-
17
16
  return function defaultSort(a, b) {
18
17
  a = getKey(a);
19
18
  b = getKey(b);
20
- if (!a && !b) return 0;
21
- if (!a) return -1;
22
- if (!b) return 1;
23
- if (b > a) return -1;
24
- if (a > b) return 1;
25
- return 0;
19
+ let ret;
20
+ if (!a && !b) ret = 0;else if (!a) ret = 1 * order;else if (!b) ret = -1 * order;else if (b > a) ret = 1 * order;else if (a > b) ret = -1 * order;else ret = 0;
21
+ return ret;
26
22
  };
27
- } // for backwards-compatibility only, date makes as little sense as "pubdate" or any custom key
28
-
29
-
30
- const defaultSort = sortBy('date');
23
+ }
31
24
 
25
+ /**
26
+ * @param {import('metalsmith').File[]} items
27
+ * @param {CollectionConfig} config
28
+ */
29
+ function Collection(items, {
30
+ metadata,
31
+ ...config
32
+ }) {
33
+ const collection = [...items];
34
+ Object.assign(collection, metadata);
35
+ collection.config = config;
36
+ collection.constructor = Collection;
37
+ Object.seal(collection);
38
+ return collection;
39
+ }
40
+ const defaultSort = sortBy('path', 'asc');
32
41
  const defaultFilter = () => true;
42
+
33
43
  /**
34
44
  * @typedef {Object} CollectionConfig
35
- * @property {string|string[]} pattern - One or more glob patterns to match files to a collection
36
- * @property {string|(a,b) => 0|1|-1} sortBy - A key to sort by (e.g. `date`,`title`, ..) or a custom sort function
37
- * @property {number} limit - Limit the amount of items in a collection to `limit`
38
- * @property {boolean} refer - Adds `next` and `previous` keys to file metadata of matched files
39
- * @property {boolean} reverse - Whether to invert the sorting function results (asc/descending)
40
- * @property {Function} filterBy - A function that gets a `Metalsmith.File` as first argument and returns `true` for every file to include in the collection
41
- * @property {Object|string} metadata - An object with metadata to attach to the collection, or a `json`/`yaml`filepath string to load data from (relative to `Metalsmith.directory`)
45
+ * @property {string|string[]} [pattern] - One or more glob patterns to match files to a collection
46
+ * @property {string|(a,b) => 0|1|-1} [sort] - a sort string of the format `'<key_or_keypath>:<asc|desc>'`, followed by the sort order, or a custom sort function
47
+ * @property {number} [limit] - Limit the amount of items in a collection to `limit`
48
+ * @property {boolean} [refer] - Adds `next`, `previous`, `first` and `last` keys to `file.collection[name]` metadata of matched files
49
+ * @property {Function} [filter] - A function that gets a `Metalsmith.File` as first argument and returns `true` for every file to include in the collection
50
+ * @property {Object|string} [metadata] - An object with metadata to attach to the collection, or a `json`/`yaml`filepath string to load data from (relative to `Metalsmith.directory`)
42
51
  */
43
52
 
44
53
  /** @type {CollectionConfig} */
45
-
46
-
47
54
  const defaultOptions = {
48
55
  pattern: null,
49
- reverse: false,
50
56
  metadata: null,
51
57
  limit: Infinity,
52
58
  refer: true,
53
- sortBy: defaultSort,
54
- filterBy: defaultFilter
59
+ sort: defaultSort,
60
+ filter: defaultFilter
55
61
  };
62
+
56
63
  /**
57
64
  * Normalize options
58
65
  * @param {Object.<string,CollectionConfig>} options
66
+ * @param {import('metalsmith').Files} files
67
+ * @param {import('metalsmith')} metalsmith
68
+ * @throws {}
59
69
  */
60
-
61
- function normalizeOptions(options) {
70
+ function normalizeOptions(options, files, metalsmith) {
62
71
  options = options || {};
63
-
72
+ const matter = metalsmith.matter;
64
73
  for (const config in options) {
65
74
  let normalized = options[config];
66
-
67
75
  if (typeof normalized === 'string' || Array.isArray(normalized)) {
68
76
  normalized = {
69
77
  pattern: normalized
70
78
  };
71
79
  }
72
-
73
80
  normalized = Object.assign({}, defaultOptions, normalized);
74
-
75
81
  if (typeof normalized.metadata === 'string') {
76
- normalized.metadata = readMetadata.sync(normalized.metadata);
82
+ const absPath = path.resolve(metalsmith.source(), normalized.metadata);
83
+ const inSourcePath = path.relative(metalsmith.source(), absPath);
84
+ const metadataFile = files[inSourcePath];
85
+ if (!metadataFile) {
86
+ const err = new Error(`No collection metadata file at "${absPath}"`);
87
+ err.name = '@metalsmith/collections';
88
+ throw err;
89
+ }
90
+ normalized.metadata = matter.parse(matter.wrap(metadataFile.contents.toString()));
77
91
  }
78
92
 
79
- if (typeof normalized.sortBy === 'string') {
80
- normalized.sortBy = sortBy(normalized.sortBy);
93
+ // remap sort option
94
+ let sort = normalized.sort;
95
+ if (typeof sort === 'string') {
96
+ if (!sort.includes(':')) sort += ':desc';
97
+ const [key, order] = sort.split(':');
98
+ sort = sortBy(key, order);
81
99
  }
82
-
100
+ normalized.sort = sort;
83
101
  options[config] = normalized;
84
102
  }
85
-
86
103
  return options;
87
104
  }
105
+
106
+ /**
107
+ * @typedef {import('../lib/index').ReferencesArray}
108
+ * @property {import('metalsmith').File[]} previous
109
+ * @property {import('metalsmith').File[]} next
110
+ * @property {import('metalsmith').File} first
111
+ * @property {import('metalsmith').File} last
112
+ */
113
+
88
114
  /**
89
115
  * Add `collections` of files to the global metadata as a sorted array.
90
116
  * @example
@@ -93,35 +119,37 @@ function normalizeOptions(options) {
93
119
  * portfolio: {
94
120
  * pattern: 'portfolio/*.md',
95
121
  * metadata: { title: 'My portfolio' },
96
- * sortBy: 'order'
122
+ * sort: 'date:desc'
97
123
  * }
98
124
  * }))
99
125
  *
100
126
  * @param {Object.<string,CollectionConfig|string>} options
101
127
  * @return {import('metalsmith').Plugin}
102
128
  */
103
-
104
-
105
- function initializeCollections(options) {
106
- options = normalizeOptions(options);
107
- const collectionNames = Object.keys(options);
108
- const mappedCollections = collectionNames.map(name => {
109
- return Object.assign({
110
- name: name
111
- }, options[name]);
112
- });
129
+ function collections(options) {
113
130
  return function collections(files, metalsmith, done) {
114
- const metadata = metalsmith.metadata();
131
+ try {
132
+ options = normalizeOptions(options, files, metalsmith);
133
+ } catch (err) {
134
+ done(err);
135
+ }
136
+ const collectionNames = Object.keys(options);
137
+ const mappedCollections = collectionNames.map(name => {
138
+ return Object.assign({
139
+ name: name
140
+ }, options[name]);
141
+ });
115
142
  const fileNames = Object.keys(files);
116
143
  const debug = metalsmith.debug('@metalsmith/collections');
117
- metadata.collections = {};
144
+ metalsmith.metadata({
145
+ collections: {}
146
+ });
147
+ const metadata = metalsmith.metadata();
118
148
  fileNames.forEach(filePath => {
119
- // add path property to file metadata for convenience
120
- // this is for backward-compatibility only and is pretty useless
121
149
  const file = files[filePath];
122
- file.path = file.path || filePath; // dynamically add collections with default options when encountered in file metadata,
123
- // and not explicitly defined in plugin options
124
150
 
151
+ // dynamically add collections with default options when encountered in file metadata,
152
+ // and not explicitly defined in plugin options
125
153
  if (file.collection) {
126
154
  (Array.isArray(file.collection) ? file.collection : [file.collection]).forEach(name => {
127
155
  if (!collectionNames.includes(name)) {
@@ -135,87 +163,90 @@ function initializeCollections(options) {
135
163
  }
136
164
  });
137
165
  debug('Identified %s collections: %s', mappedCollections.length, collectionNames.join());
138
- mappedCollections.forEach(collection => {
166
+ mappedCollections.forEach(collectionConfig => {
139
167
  const {
140
168
  pattern,
141
- filterBy,
142
- sortBy,
143
- reverse,
169
+ filter,
170
+ sort,
144
171
  refer,
145
172
  limit
146
- } = collection;
147
- const name = collection.name;
173
+ } = collectionConfig;
174
+ const name = collectionConfig.name;
148
175
  const matches = [];
149
- debug('Processing collection %s with options %s:', name, collection); // first match by pattern if provided
176
+ debug('Processing collection %s with options %O:', name, collectionConfig);
150
177
 
178
+ // first match by pattern if provided
151
179
  if (pattern) {
152
180
  matches.push.apply(matches, metalsmith.match(pattern, fileNames).map(filepath => {
153
- const data = files[filepath]; // pattern-matched files might or might not have a "collection" property defined in front-matter
181
+ const data = files[filepath];
182
+ // pattern-matched files might or might not have a "collection" property defined in front-matter
154
183
  // and might also be included in multiple collections
155
-
156
184
  if (!data.collection) {
157
185
  data.collection = [];
158
186
  } else if (typeof data.collection === 'string') {
159
187
  data.collection = [data.collection];
160
188
  }
161
-
162
- if (!data.collection.includes(collection.name)) {
163
- data.collection = [...data.collection, collection.name];
189
+ if (!data.collection.includes(collectionConfig.name)) {
190
+ data.collection = [...data.collection, collectionConfig.name];
164
191
  }
165
-
166
192
  return data;
167
193
  }));
168
- } // next match by "collection" key, but only push if the files haven't been added through pattern matching first
169
-
194
+ }
170
195
 
196
+ // next match by "collection" key, but only push if the files haven't been added through pattern matching first
171
197
  matches.push.apply(matches, Object.values(files).filter(file => {
172
198
  const patternMatched = matches.includes(file);
173
- const isInCollection = Array.isArray(file.collection) ? file.collection.includes(collection.name) : file.collection === collection.name;
199
+ const isInCollection = Array.isArray(file.collection) ? file.collection.includes(collectionConfig.name) : file.collection === collectionConfig.name;
174
200
  return !patternMatched && isInCollection;
201
+ }).map(file => {
202
+ if (!file.collection) {
203
+ file.collection = [];
204
+ } else if (typeof file.collection === 'string') {
205
+ file.collection = [file.collection];
206
+ }
207
+ return file;
175
208
  }));
176
209
 
177
- if (Object.prototype.hasOwnProperty.call(metadata, name)) {
178
- debug('Warning: overwriting previously set metadata property %s', name);
179
- } // apply sort, reverse, filter, limit options in this order
180
-
181
-
182
- metadata[name] = matches.sort(sortBy);
183
-
184
- if (reverse) {
185
- metadata[name].reverse();
186
- }
187
-
188
- metadata[name] = metadata[name].filter(filterBy).slice(0, limit);
189
-
190
- if (collection.metadata) {
191
- metadata[name].metadata = collection.metadata;
192
- }
193
-
194
- if (refer) {
195
- if (reverse) {
196
- metadata[name].forEach((file, i) => {
197
- Object.assign(file, {
198
- next: i > 0 ? metadata[name][i - 1] : null,
199
- previous: i < metadata[name].length - 1 ? metadata[name][i + 1] : null
200
- });
201
- });
210
+ // apply sort, filter, limit options in this order
211
+
212
+ let currentCollection = matches;
213
+ // safely add to and remove from the sorting context 'path' property
214
+ const originalPaths = [];
215
+ currentCollection.forEach(item => {
216
+ if (item.path) originalPaths.push([item, item.path]);
217
+ item.path = metalsmith.path(Object.entries(files).find(entry => entry[1] === item)[0]);
218
+ });
219
+ currentCollection = currentCollection.sort(sort).filter(filter).slice(0, limit);
220
+ currentCollection.forEach(item => {
221
+ const original = originalPaths.find(([file]) => file === item);
222
+ if (original) {
223
+ item.path = original[1];
202
224
  } else {
203
- metadata[name].forEach((file, i) => {
204
- Object.assign(file, {
205
- previous: i > 0 ? metadata[name][i - 1] : null,
206
- next: i < metadata[name].length - 1 ? metadata[name][i + 1] : null
207
- });
208
- });
225
+ delete item.path;
209
226
  }
227
+ });
228
+ metadata.collections[name] = Collection(currentCollection, collectionConfig);
229
+ if (refer) {
230
+ const lastIndex = currentCollection.length - 1;
231
+ currentCollection.forEach((file, i) => {
232
+ file.collection[name] = Object.assign(file.collection[name] || {}, {
233
+ previous: [],
234
+ next: [],
235
+ first: currentCollection[0],
236
+ last: currentCollection[lastIndex]
237
+ });
238
+ // previous and next are arrays in which resp. the last & first item are merged
239
+ // so users can easily get a single prev/next vs a list. Without it, getting the single prev is tricky, eg in NJK: {% set coll = collection.some.previous | last %}{{ coll.title }}
240
+ if (i > 0) file.collection[name].previous = Object.assign(currentCollection.slice(0, i), currentCollection[i - 1]);
241
+ if (i < lastIndex) file.collection[name].next = Object.assign(currentCollection.slice(i + 1), currentCollection[i + 1]);
242
+ });
210
243
  }
211
-
212
- metadata.collections[name] = metadata[name];
213
- debug('Added %s files to collection %s', metadata[name].length, name);
244
+ debug('Added %s files to collection %s', currentCollection.length, name);
214
245
  });
215
246
  done();
216
247
  };
217
248
  }
249
+ collections.defaults = defaultOptions;
218
250
 
219
- initializeCollections.defaults = defaultOptions;
220
-
221
- module.exports = initializeCollections;
251
+ module.exports = collections;
252
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sources":["../src/index.js"],"sourcesContent":["import get from 'lodash.get'\nimport { relative, resolve } from 'path'\n\nfunction sortBy(key, order) {\n order = order === 'asc' ? -1 : 1\n let getKey = (x) => x[key]\n if (key.includes('.')) {\n getKey = (x) => get(x, key)\n }\n return function defaultSort(a, b) {\n a = getKey(a)\n b = getKey(b)\n let ret\n if (!a && !b) ret = 0\n else if (!a) ret = 1 * order\n else if (!b) ret = -1 * order\n else if (b > a) ret = 1 * order\n else if (a > b) ret = -1 * order\n else ret = 0\n\n return ret\n }\n}\n\n/**\n * @param {import('metalsmith').File[]} items\n * @param {CollectionConfig} config\n */\nfunction Collection(items, { metadata, ...config }) {\n const collection = [...items]\n Object.assign(collection, metadata)\n collection.config = config\n collection.constructor = Collection\n Object.seal(collection)\n return collection\n}\n\nconst defaultSort = sortBy('path', 'asc')\nconst defaultFilter = () => true\n\n/**\n * @typedef {Object} CollectionConfig\n * @property {string|string[]} [pattern] - One or more glob patterns to match files to a collection\n * @property {string|(a,b) => 0|1|-1} [sort] - a sort string of the format `'<key_or_keypath>:<asc|desc>'`, followed by the sort order, or a custom sort function\n * @property {number} [limit] - Limit the amount of items in a collection to `limit`\n * @property {boolean} [refer] - Adds `next`, `previous`, `first` and `last` keys to `file.collection[name]` metadata of matched files\n * @property {Function} [filter] - A function that gets a `Metalsmith.File` as first argument and returns `true` for every file to include in the collection\n * @property {Object|string} [metadata] - An object with metadata to attach to the collection, or a `json`/`yaml`filepath string to load data from (relative to `Metalsmith.directory`)\n */\n\n/** @type {CollectionConfig} */\nconst defaultOptions = {\n pattern: null,\n metadata: null,\n limit: Infinity,\n refer: true,\n sort: defaultSort,\n filter: defaultFilter\n}\n\n/**\n * Normalize options\n * @param {Object.<string,CollectionConfig>} options\n * @param {import('metalsmith').Files} files\n * @param {import('metalsmith')} metalsmith\n * @throws {}\n */\nfunction normalizeOptions(options, files, metalsmith) {\n options = options || {}\n const matter = metalsmith.matter\n\n for (const config in options) {\n let normalized = options[config]\n if (typeof normalized === 'string' || Array.isArray(normalized)) {\n normalized = { pattern: normalized }\n }\n normalized = Object.assign({}, defaultOptions, normalized)\n if (typeof normalized.metadata === 'string') {\n const absPath = resolve(metalsmith.source(), normalized.metadata)\n const inSourcePath = relative(metalsmith.source(), absPath)\n const metadataFile = files[inSourcePath]\n if (!metadataFile) {\n const err = new Error(`No collection metadata file at \"${absPath}\"`)\n err.name = '@metalsmith/collections'\n throw err\n }\n normalized.metadata = matter.parse(matter.wrap(metadataFile.contents.toString()))\n }\n\n // remap sort option\n let sort = normalized.sort\n if (typeof sort === 'string') {\n if (!sort.includes(':')) sort += ':desc'\n const [key, order] = sort.split(':')\n sort = sortBy(key, order)\n }\n normalized.sort = sort\n\n options[config] = normalized\n }\n\n return options\n}\n\n/**\n * @typedef {import('../lib/index').ReferencesArray}\n * @property {import('metalsmith').File[]} previous\n * @property {import('metalsmith').File[]} next\n * @property {import('metalsmith').File} first\n * @property {import('metalsmith').File} last\n */\n\n/**\n * Add `collections` of files to the global metadata as a sorted array.\n * @example\n * metalsmith.use(collections({\n * posts: 'posts/*.md',\n * portfolio: {\n * pattern: 'portfolio/*.md',\n * metadata: { title: 'My portfolio' },\n * sort: 'date:desc'\n * }\n * }))\n *\n * @param {Object.<string,CollectionConfig|string>} options\n * @return {import('metalsmith').Plugin}\n */\nfunction collections(options) {\n return function collections(files, metalsmith, done) {\n try {\n options = normalizeOptions(options, files, metalsmith)\n } catch (err) {\n done(err)\n }\n const collectionNames = Object.keys(options)\n const mappedCollections = collectionNames.map((name) => {\n return Object.assign({ name: name }, options[name])\n })\n\n const fileNames = Object.keys(files)\n const debug = metalsmith.debug('@metalsmith/collections')\n\n metalsmith.metadata({ collections: {} })\n const metadata = metalsmith.metadata()\n\n fileNames.forEach((filePath) => {\n const file = files[filePath]\n\n // dynamically add collections with default options when encountered in file metadata,\n // and not explicitly defined in plugin options\n if (file.collection) {\n ;(Array.isArray(file.collection) ? file.collection : [file.collection]).forEach((name) => {\n if (!collectionNames.includes(name)) {\n collectionNames.push(name)\n const normalized = Object.assign({}, defaultOptions)\n mappedCollections.push(Object.assign({ name }, normalized))\n }\n })\n }\n })\n\n debug('Identified %s collections: %s', mappedCollections.length, collectionNames.join())\n\n mappedCollections.forEach((collectionConfig) => {\n const { pattern, filter, sort, refer, limit } = collectionConfig\n const name = collectionConfig.name\n const matches = []\n debug('Processing collection %s with options %O:', name, collectionConfig)\n\n // first match by pattern if provided\n if (pattern) {\n matches.push.apply(\n matches,\n metalsmith.match(pattern, fileNames).map((filepath) => {\n const data = files[filepath]\n // pattern-matched files might or might not have a \"collection\" property defined in front-matter\n // and might also be included in multiple collections\n if (!data.collection) {\n data.collection = []\n } else if (typeof data.collection === 'string') {\n data.collection = [data.collection]\n }\n if (!data.collection.includes(collectionConfig.name)) {\n data.collection = [...data.collection, collectionConfig.name]\n }\n return data\n })\n )\n }\n\n // next match by \"collection\" key, but only push if the files haven't been added through pattern matching first\n matches.push.apply(\n matches,\n Object.values(files)\n .filter((file) => {\n const patternMatched = matches.includes(file)\n const isInCollection = Array.isArray(file.collection)\n ? file.collection.includes(collectionConfig.name)\n : file.collection === collectionConfig.name\n return !patternMatched && isInCollection\n })\n .map((file) => {\n if (!file.collection) {\n file.collection = []\n } else if (typeof file.collection === 'string') {\n file.collection = [file.collection]\n }\n return file\n })\n )\n\n // apply sort, filter, limit options in this order\n\n let currentCollection = matches\n // safely add to and remove from the sorting context 'path' property\n const originalPaths = []\n currentCollection.forEach((item) => {\n if (item.path) originalPaths.push([item, item.path])\n item.path = metalsmith.path(Object.entries(files).find((entry) => entry[1] === item)[0])\n })\n\n currentCollection = currentCollection.sort(sort).filter(filter).slice(0, limit)\n\n currentCollection.forEach((item) => {\n const original = originalPaths.find(([file]) => file === item)\n if (original) {\n item.path = original[1]\n } else {\n delete item.path\n }\n })\n\n metadata.collections[name] = Collection(currentCollection, collectionConfig)\n\n if (refer) {\n const lastIndex = currentCollection.length - 1\n currentCollection.forEach((file, i) => {\n file.collection[name] = Object.assign(file.collection[name] || {}, {\n previous: [],\n next: [],\n first: currentCollection[0],\n last: currentCollection[lastIndex]\n })\n // previous and next are arrays in which resp. the last & first item are merged\n // so users can easily get a single prev/next vs a list. Without it, getting the single prev is tricky, eg in NJK: {% set coll = collection.some.previous | last %}{{ coll.title }}\n if (i > 0)\n file.collection[name].previous = Object.assign(currentCollection.slice(0, i), currentCollection[i - 1])\n if (i < lastIndex)\n file.collection[name].next = Object.assign(currentCollection.slice(i + 1), currentCollection[i + 1])\n })\n }\n\n debug('Added %s files to collection %s', currentCollection.length, name)\n })\n done()\n }\n}\n\ncollections.defaults = defaultOptions\n\nexport default collections\n"],"names":["sortBy","key","order","getKey","x","includes","get","defaultSort","a","b","ret","Collection","items","metadata","config","collection","Object","assign","constructor","seal","defaultFilter","defaultOptions","pattern","limit","Infinity","refer","sort","filter","normalizeOptions","options","files","metalsmith","matter","normalized","Array","isArray","absPath","resolve","source","inSourcePath","relative","metadataFile","err","Error","name","parse","wrap","contents","toString","split","collections","done","collectionNames","keys","mappedCollections","map","fileNames","debug","forEach","filePath","file","push","length","join","collectionConfig","matches","apply","match","filepath","data","values","patternMatched","isInCollection","currentCollection","originalPaths","item","path","entries","find","entry","slice","original","lastIndex","i","previous","next","first","last","defaults"],"mappings":"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"}
package/lib/index.d.ts CHANGED
@@ -1,36 +1,48 @@
1
1
  import Metalsmith from "metalsmith";
2
2
 
3
- export default initializeCollections;
3
+ export default collections;
4
4
  export type CollectionConfig = {
5
5
  /**
6
6
  * - One or more glob patterns to match files to a collection
7
7
  */
8
- pattern: string | string[];
8
+ pattern?: string | string[] | null;
9
9
  /**
10
- * - A key to sort by (e.g. `date`,`title`, ..) or a custom sort function
10
+ * - a sort string of the format `'<key_or_keypath>:<asc|desc>'`, followed by the sort order, or a custom sort function
11
+ * @default 'path:asc'
12
+ * @example
13
+ * 'date'
14
+ * 'pubdate:desc'
15
+ * 'order:asc'
11
16
  */
12
- sortBy: string | ((a: any, b: any) => 0 | 1 | -1);
17
+ sort?: string | ((a: any, b: any) => 0 | 1 | -1);
13
18
  /**
14
19
  * - Limit the amount of items in a collection to `limit`
15
20
  */
16
- limit: number;
21
+ limit?: number;
17
22
  /**
18
- * - Adds `next` and `previous` keys to file metadata of matched files
23
+ * - Adds `next`, `previous`, `first` and `last` keys to `file.collection[name]` metadata of matched files
24
+ * @default true
19
25
  */
20
- refer: boolean;
21
- /**
22
- * - Whether to invert the sorting function results (asc/descending)
23
- */
24
- reverse: boolean;
26
+ refer?: boolean;
25
27
  /**
26
28
  * - A function that gets a `Metalsmith.File` as first argument and returns `true` for every file to include in the collection
29
+ * @default () => true
27
30
  */
28
- filterBy: Function;
31
+ filter?: Function;
29
32
  /**
30
33
  * - An object with metadata to attach to the collection, or a `json`/`yaml`filepath string to load data from (relative to `Metalsmith.directory`)
31
34
  */
32
- metadata: any | string;
35
+ metadata?: any | string | null;
33
36
  };
37
+
38
+ /** Collection ordering metadata at `files[path].collection[name]` */
39
+ export type ReferencesArray = string[] & {
40
+ previous: Metalsmith.File[] & Metalsmith.File;
41
+ next: Metalsmith.File[] & Metalsmith.File;
42
+ first: Metalsmith.File;
43
+ last: Metalsmith.File;
44
+ }
45
+
34
46
  /**
35
47
  * Add `collections` of files to the global metadata as a sorted array.
36
48
  * @example
@@ -39,16 +51,16 @@ export type CollectionConfig = {
39
51
  * portfolio: {
40
52
  * pattern: 'portfolio/*.md',
41
53
  * metadata: { title: 'My portfolio' },
42
- * sortBy: 'order'
54
+ * sort: 'order:asc'
43
55
  * }
44
56
  * }))
45
57
  *
46
58
  * @param {Object.<string,CollectionConfig|string>} options
47
59
  */
48
- declare function initializeCollections(options: {
60
+ declare function collections(options: {
49
61
  [x: string]: CollectionConfig | string;
50
62
  }): Metalsmith.Plugin;
51
- declare namespace initializeCollections {
63
+ declare namespace collections {
52
64
  export { defaultOptions as defaults };
53
65
  }
54
66