@metalsmith/collections 1.2.1 → 1.3.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/README.md +8 -5
- package/lib/index.cjs +221 -0
- package/lib/index.d.ts +55 -0
- package/lib/index.js +134 -114
- package/package.json +30 -18
- package/CHANGELOG.md +0 -89
package/README.md
CHANGED
|
@@ -36,9 +36,12 @@ yarn add @metalsmith/collections
|
|
|
36
36
|
Pass options to `@metalsmith/collections` in the plugin chain:
|
|
37
37
|
|
|
38
38
|
```js
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
import Metalsmith from 'metalsmith'
|
|
40
|
+
import markdown from '@metalsmith/markdown'
|
|
41
|
+
import collections from '@metalsmith/collections'
|
|
42
|
+
import { dirname } from 'path'
|
|
43
|
+
|
|
44
|
+
const __dirname = dirname(new URL(import.meta.url).pathname)
|
|
42
45
|
|
|
43
46
|
// defaults, only create collections based on file metadata
|
|
44
47
|
Metalsmith(__dirname)
|
|
@@ -323,8 +326,8 @@ Add the `@metalsmith/collections` key to your `metalsmith.json` `plugins` key:
|
|
|
323
326
|
|
|
324
327
|
[npm-badge]: https://img.shields.io/npm/v/@metalsmith/collections.svg
|
|
325
328
|
[npm-url]: https://www.npmjs.com/package/@metalsmith/collections
|
|
326
|
-
[ci-badge]: https://
|
|
327
|
-
[ci-url]: https://
|
|
329
|
+
[ci-badge]: https://github.com/metalsmith/collections/actions/workflows/test.yml/badge.svg
|
|
330
|
+
[ci-url]: https://github.com/metalsmith/collections/actions/workflows/test.yml
|
|
328
331
|
[metalsmith-badge]: https://img.shields.io/badge/metalsmith-plugin-green.svg?longCache=true
|
|
329
332
|
[metalsmith-url]: http://metalsmith.io
|
|
330
333
|
[codecov-badge]: https://img.shields.io/coveralls/github/metalsmith/collections
|
package/lib/index.cjs
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var get = require('lodash.get');
|
|
4
|
+
var readMetadata = require('read-metadata');
|
|
5
|
+
|
|
6
|
+
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
7
|
+
|
|
8
|
+
var get__default = /*#__PURE__*/_interopDefaultLegacy(get);
|
|
9
|
+
|
|
10
|
+
function sortBy(key) {
|
|
11
|
+
let getKey = x => x[key];
|
|
12
|
+
|
|
13
|
+
if (key.includes('.')) {
|
|
14
|
+
getKey = x => get__default["default"](x, key);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return function defaultSort(a, b) {
|
|
18
|
+
a = getKey(a);
|
|
19
|
+
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;
|
|
26
|
+
};
|
|
27
|
+
} // for backwards-compatibility only, date makes as little sense as "pubdate" or any custom key
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
const defaultSort = sortBy('date');
|
|
31
|
+
|
|
32
|
+
const defaultFilter = () => true;
|
|
33
|
+
/**
|
|
34
|
+
* @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`)
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
/** @type {CollectionConfig} */
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
const defaultOptions = {
|
|
48
|
+
pattern: null,
|
|
49
|
+
reverse: false,
|
|
50
|
+
metadata: null,
|
|
51
|
+
limit: Infinity,
|
|
52
|
+
refer: true,
|
|
53
|
+
sortBy: defaultSort,
|
|
54
|
+
filterBy: defaultFilter
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Normalize options
|
|
58
|
+
* @param {Object.<string,CollectionConfig>} options
|
|
59
|
+
*/
|
|
60
|
+
|
|
61
|
+
function normalizeOptions(options) {
|
|
62
|
+
options = options || {};
|
|
63
|
+
|
|
64
|
+
for (const config in options) {
|
|
65
|
+
let normalized = options[config];
|
|
66
|
+
|
|
67
|
+
if (typeof normalized === 'string' || Array.isArray(normalized)) {
|
|
68
|
+
normalized = {
|
|
69
|
+
pattern: normalized
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
normalized = Object.assign({}, defaultOptions, normalized);
|
|
74
|
+
|
|
75
|
+
if (typeof normalized.metadata === 'string') {
|
|
76
|
+
normalized.metadata = readMetadata.sync(normalized.metadata);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (typeof normalized.sortBy === 'string') {
|
|
80
|
+
normalized.sortBy = sortBy(normalized.sortBy);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
options[config] = normalized;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return options;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Add `collections` of files to the global metadata as a sorted array.
|
|
90
|
+
* @example
|
|
91
|
+
* metalsmith.use(collections({
|
|
92
|
+
* posts: 'posts/*.md',
|
|
93
|
+
* portfolio: {
|
|
94
|
+
* pattern: 'portfolio/*.md',
|
|
95
|
+
* metadata: { title: 'My portfolio' },
|
|
96
|
+
* sortBy: 'order'
|
|
97
|
+
* }
|
|
98
|
+
* }))
|
|
99
|
+
*
|
|
100
|
+
* @param {Object.<string,CollectionConfig|string>} options
|
|
101
|
+
* @return {import('metalsmith').Plugin}
|
|
102
|
+
*/
|
|
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
|
+
});
|
|
113
|
+
return function collections(files, metalsmith, done) {
|
|
114
|
+
const metadata = metalsmith.metadata();
|
|
115
|
+
const fileNames = Object.keys(files);
|
|
116
|
+
const debug = metalsmith.debug('@metalsmith/collections');
|
|
117
|
+
metadata.collections = {};
|
|
118
|
+
fileNames.forEach(filePath => {
|
|
119
|
+
// add path property to file metadata for convenience
|
|
120
|
+
// this is for backward-compatibility only and is pretty useless
|
|
121
|
+
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
|
+
|
|
125
|
+
if (file.collection) {
|
|
126
|
+
(Array.isArray(file.collection) ? file.collection : [file.collection]).forEach(name => {
|
|
127
|
+
if (!collectionNames.includes(name)) {
|
|
128
|
+
collectionNames.push(name);
|
|
129
|
+
const normalized = Object.assign({}, defaultOptions);
|
|
130
|
+
mappedCollections.push(Object.assign({
|
|
131
|
+
name
|
|
132
|
+
}, normalized));
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
debug('Identified %s collections: %s', mappedCollections.length, collectionNames.join());
|
|
138
|
+
mappedCollections.forEach(collection => {
|
|
139
|
+
const {
|
|
140
|
+
pattern,
|
|
141
|
+
filterBy,
|
|
142
|
+
sortBy,
|
|
143
|
+
reverse,
|
|
144
|
+
refer,
|
|
145
|
+
limit
|
|
146
|
+
} = collection;
|
|
147
|
+
const name = collection.name;
|
|
148
|
+
const matches = [];
|
|
149
|
+
debug('Processing collection %s with options %s:', name, collection); // first match by pattern if provided
|
|
150
|
+
|
|
151
|
+
if (pattern) {
|
|
152
|
+
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
|
|
154
|
+
// and might also be included in multiple collections
|
|
155
|
+
|
|
156
|
+
if (!data.collection) {
|
|
157
|
+
data.collection = [];
|
|
158
|
+
} else if (typeof data.collection === 'string') {
|
|
159
|
+
data.collection = [data.collection];
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (!data.collection.includes(collection.name)) {
|
|
163
|
+
data.collection = [...data.collection, collection.name];
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return data;
|
|
167
|
+
}));
|
|
168
|
+
} // next match by "collection" key, but only push if the files haven't been added through pattern matching first
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
matches.push.apply(matches, Object.values(files).filter(file => {
|
|
172
|
+
const patternMatched = matches.includes(file);
|
|
173
|
+
const isInCollection = Array.isArray(file.collection) ? file.collection.includes(collection.name) : file.collection === collection.name;
|
|
174
|
+
return !patternMatched && isInCollection;
|
|
175
|
+
}));
|
|
176
|
+
|
|
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
|
+
});
|
|
202
|
+
} 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
|
+
});
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
metadata.collections[name] = metadata[name];
|
|
213
|
+
debug('Added %s files to collection %s', metadata[name].length, name);
|
|
214
|
+
});
|
|
215
|
+
done();
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
initializeCollections.defaults = defaultOptions;
|
|
220
|
+
|
|
221
|
+
module.exports = initializeCollections;
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import Metalsmith from "metalsmith";
|
|
2
|
+
|
|
3
|
+
export default initializeCollections;
|
|
4
|
+
export type CollectionConfig = {
|
|
5
|
+
/**
|
|
6
|
+
* - One or more glob patterns to match files to a collection
|
|
7
|
+
*/
|
|
8
|
+
pattern: string | string[];
|
|
9
|
+
/**
|
|
10
|
+
* - A key to sort by (e.g. `date`,`title`, ..) or a custom sort function
|
|
11
|
+
*/
|
|
12
|
+
sortBy: string | ((a: any, b: any) => 0 | 1 | -1);
|
|
13
|
+
/**
|
|
14
|
+
* - Limit the amount of items in a collection to `limit`
|
|
15
|
+
*/
|
|
16
|
+
limit: number;
|
|
17
|
+
/**
|
|
18
|
+
* - Adds `next` and `previous` keys to file metadata of matched files
|
|
19
|
+
*/
|
|
20
|
+
refer: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* - Whether to invert the sorting function results (asc/descending)
|
|
23
|
+
*/
|
|
24
|
+
reverse: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* - A function that gets a `Metalsmith.File` as first argument and returns `true` for every file to include in the collection
|
|
27
|
+
*/
|
|
28
|
+
filterBy: Function;
|
|
29
|
+
/**
|
|
30
|
+
* - An object with metadata to attach to the collection, or a `json`/`yaml`filepath string to load data from (relative to `Metalsmith.directory`)
|
|
31
|
+
*/
|
|
32
|
+
metadata: any | string;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Add `collections` of files to the global metadata as a sorted array.
|
|
36
|
+
* @example
|
|
37
|
+
* metalsmith.use(collections({
|
|
38
|
+
* posts: 'posts/*.md',
|
|
39
|
+
* portfolio: {
|
|
40
|
+
* pattern: 'portfolio/*.md',
|
|
41
|
+
* metadata: { title: 'My portfolio' },
|
|
42
|
+
* sortBy: 'order'
|
|
43
|
+
* }
|
|
44
|
+
* }))
|
|
45
|
+
*
|
|
46
|
+
* @param {Object.<string,CollectionConfig|string>} options
|
|
47
|
+
*/
|
|
48
|
+
declare function initializeCollections(options: {
|
|
49
|
+
[x: string]: CollectionConfig | string;
|
|
50
|
+
}): Metalsmith.Plugin;
|
|
51
|
+
declare namespace initializeCollections {
|
|
52
|
+
export { defaultOptions as defaults };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
declare const defaultOptions: CollectionConfig;
|
package/lib/index.js
CHANGED
|
@@ -1,11 +1,29 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const loadMetadata = require('read-metadata').sync
|
|
4
|
-
const get = require('lodash.get')
|
|
5
|
-
// for backwards-compatibility only, date makes as little sense as "pubdate" or any custom key
|
|
6
|
-
const defaultSort = sortBy('date')
|
|
7
|
-
const defaultFilter = () => true
|
|
1
|
+
import get from 'lodash.get';
|
|
2
|
+
import { sync } from 'read-metadata';
|
|
8
3
|
|
|
4
|
+
function sortBy(key) {
|
|
5
|
+
let getKey = x => x[key];
|
|
6
|
+
|
|
7
|
+
if (key.includes('.')) {
|
|
8
|
+
getKey = x => get(x, key);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return function defaultSort(a, b) {
|
|
12
|
+
a = getKey(a);
|
|
13
|
+
b = getKey(b);
|
|
14
|
+
if (!a && !b) return 0;
|
|
15
|
+
if (!a) return -1;
|
|
16
|
+
if (!b) return 1;
|
|
17
|
+
if (b > a) return -1;
|
|
18
|
+
if (a > b) return 1;
|
|
19
|
+
return 0;
|
|
20
|
+
};
|
|
21
|
+
} // for backwards-compatibility only, date makes as little sense as "pubdate" or any custom key
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
const defaultSort = sortBy('date');
|
|
25
|
+
|
|
26
|
+
const defaultFilter = () => true;
|
|
9
27
|
/**
|
|
10
28
|
* @typedef {Object} CollectionConfig
|
|
11
29
|
* @property {string|string[]} pattern - One or more glob patterns to match files to a collection
|
|
@@ -18,6 +36,8 @@ const defaultFilter = () => true
|
|
|
18
36
|
*/
|
|
19
37
|
|
|
20
38
|
/** @type {CollectionConfig} */
|
|
39
|
+
|
|
40
|
+
|
|
21
41
|
const defaultOptions = {
|
|
22
42
|
pattern: null,
|
|
23
43
|
reverse: false,
|
|
@@ -26,170 +46,170 @@ const defaultOptions = {
|
|
|
26
46
|
refer: true,
|
|
27
47
|
sortBy: defaultSort,
|
|
28
48
|
filterBy: defaultFilter
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function sortBy(key) {
|
|
32
|
-
let getKey = (x) => x[key]
|
|
33
|
-
if (key.includes('.')) {
|
|
34
|
-
getKey = (x) => get(x, key)
|
|
35
|
-
}
|
|
36
|
-
return function defaultSort(a, b) {
|
|
37
|
-
a = getKey(a)
|
|
38
|
-
b = getKey(b)
|
|
39
|
-
if (!a && !b) return 0
|
|
40
|
-
if (!a) return -1
|
|
41
|
-
if (!b) return 1
|
|
42
|
-
if (b > a) return -1
|
|
43
|
-
if (a > b) return 1
|
|
44
|
-
return 0
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
49
|
+
};
|
|
48
50
|
/**
|
|
49
51
|
* Normalize options
|
|
50
52
|
* @param {Object.<string,CollectionConfig>} options
|
|
51
53
|
*/
|
|
54
|
+
|
|
52
55
|
function normalizeOptions(options) {
|
|
53
|
-
options = options || {}
|
|
56
|
+
options = options || {};
|
|
54
57
|
|
|
55
58
|
for (const config in options) {
|
|
56
|
-
let normalized = options[config]
|
|
59
|
+
let normalized = options[config];
|
|
60
|
+
|
|
57
61
|
if (typeof normalized === 'string' || Array.isArray(normalized)) {
|
|
58
|
-
normalized = {
|
|
62
|
+
normalized = {
|
|
63
|
+
pattern: normalized
|
|
64
|
+
};
|
|
59
65
|
}
|
|
60
|
-
|
|
66
|
+
|
|
67
|
+
normalized = Object.assign({}, defaultOptions, normalized);
|
|
68
|
+
|
|
61
69
|
if (typeof normalized.metadata === 'string') {
|
|
62
|
-
normalized.metadata =
|
|
70
|
+
normalized.metadata = sync(normalized.metadata);
|
|
63
71
|
}
|
|
72
|
+
|
|
64
73
|
if (typeof normalized.sortBy === 'string') {
|
|
65
|
-
normalized.sortBy = sortBy(normalized.sortBy)
|
|
74
|
+
normalized.sortBy = sortBy(normalized.sortBy);
|
|
66
75
|
}
|
|
67
|
-
|
|
76
|
+
|
|
77
|
+
options[config] = normalized;
|
|
68
78
|
}
|
|
69
79
|
|
|
70
|
-
return options
|
|
80
|
+
return options;
|
|
71
81
|
}
|
|
72
|
-
|
|
73
82
|
/**
|
|
74
|
-
*
|
|
75
|
-
*
|
|
83
|
+
* Add `collections` of files to the global metadata as a sorted array.
|
|
84
|
+
* @example
|
|
85
|
+
* metalsmith.use(collections({
|
|
86
|
+
* posts: 'posts/*.md',
|
|
87
|
+
* portfolio: {
|
|
88
|
+
* pattern: 'portfolio/*.md',
|
|
89
|
+
* metadata: { title: 'My portfolio' },
|
|
90
|
+
* sortBy: 'order'
|
|
91
|
+
* }
|
|
92
|
+
* }))
|
|
76
93
|
*
|
|
77
94
|
* @param {Object.<string,CollectionConfig|string>} options
|
|
78
95
|
* @return {import('metalsmith').Plugin}
|
|
79
96
|
*/
|
|
80
|
-
function initializeCollections(options) {
|
|
81
|
-
options = normalizeOptions(options)
|
|
82
|
-
const collectionNames = Object.keys(options)
|
|
83
|
-
const mappedCollections = collectionNames.map((name) => {
|
|
84
|
-
return Object.assign({ name: name }, options[name])
|
|
85
|
-
})
|
|
86
97
|
|
|
87
|
-
return function collections(files, metalsmith, done) {
|
|
88
|
-
const metadata = metalsmith.metadata()
|
|
89
|
-
const fileNames = Object.keys(files)
|
|
90
98
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
99
|
+
function initializeCollections(options) {
|
|
100
|
+
options = normalizeOptions(options);
|
|
101
|
+
const collectionNames = Object.keys(options);
|
|
102
|
+
const mappedCollections = collectionNames.map(name => {
|
|
103
|
+
return Object.assign({
|
|
104
|
+
name: name
|
|
105
|
+
}, options[name]);
|
|
106
|
+
});
|
|
107
|
+
return function collections(files, metalsmith, done) {
|
|
108
|
+
const metadata = metalsmith.metadata();
|
|
109
|
+
const fileNames = Object.keys(files);
|
|
110
|
+
const debug = metalsmith.debug('@metalsmith/collections');
|
|
111
|
+
metadata.collections = {};
|
|
112
|
+
fileNames.forEach(filePath => {
|
|
94
113
|
// add path property to file metadata for convenience
|
|
95
114
|
// this is for backward-compatibility only and is pretty useless
|
|
96
|
-
const file = files[filePath]
|
|
97
|
-
file.path = file.path || filePath
|
|
98
|
-
|
|
99
|
-
// dynamically add collections with default options when encountered in file metadata,
|
|
115
|
+
const file = files[filePath];
|
|
116
|
+
file.path = file.path || filePath; // dynamically add collections with default options when encountered in file metadata,
|
|
100
117
|
// and not explicitly defined in plugin options
|
|
118
|
+
|
|
101
119
|
if (file.collection) {
|
|
102
|
-
|
|
120
|
+
(Array.isArray(file.collection) ? file.collection : [file.collection]).forEach(name => {
|
|
103
121
|
if (!collectionNames.includes(name)) {
|
|
104
|
-
collectionNames.push(name)
|
|
105
|
-
const normalized = Object.assign({}, defaultOptions)
|
|
106
|
-
mappedCollections.push(Object.assign({
|
|
122
|
+
collectionNames.push(name);
|
|
123
|
+
const normalized = Object.assign({}, defaultOptions);
|
|
124
|
+
mappedCollections.push(Object.assign({
|
|
125
|
+
name
|
|
126
|
+
}, normalized));
|
|
107
127
|
}
|
|
108
|
-
})
|
|
128
|
+
});
|
|
109
129
|
}
|
|
110
|
-
})
|
|
130
|
+
});
|
|
131
|
+
debug('Identified %s collections: %s', mappedCollections.length, collectionNames.join());
|
|
132
|
+
mappedCollections.forEach(collection => {
|
|
133
|
+
const {
|
|
134
|
+
pattern,
|
|
135
|
+
filterBy,
|
|
136
|
+
sortBy,
|
|
137
|
+
reverse,
|
|
138
|
+
refer,
|
|
139
|
+
limit
|
|
140
|
+
} = collection;
|
|
141
|
+
const name = collection.name;
|
|
142
|
+
const matches = [];
|
|
143
|
+
debug('Processing collection %s with options %s:', name, collection); // first match by pattern if provided
|
|
111
144
|
|
|
112
|
-
|
|
145
|
+
if (pattern) {
|
|
146
|
+
matches.push.apply(matches, metalsmith.match(pattern, fileNames).map(filepath => {
|
|
147
|
+
const data = files[filepath]; // pattern-matched files might or might not have a "collection" property defined in front-matter
|
|
148
|
+
// and might also be included in multiple collections
|
|
149
|
+
|
|
150
|
+
if (!data.collection) {
|
|
151
|
+
data.collection = [];
|
|
152
|
+
} else if (typeof data.collection === 'string') {
|
|
153
|
+
data.collection = [data.collection];
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (!data.collection.includes(collection.name)) {
|
|
157
|
+
data.collection = [...data.collection, collection.name];
|
|
158
|
+
}
|
|
113
159
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
const matches = []
|
|
118
|
-
debug('Processing collection %s with options %s:', name, collection)
|
|
160
|
+
return data;
|
|
161
|
+
}));
|
|
162
|
+
} // next match by "collection" key, but only push if the files haven't been added through pattern matching first
|
|
119
163
|
|
|
120
|
-
// first match by pattern if provided
|
|
121
|
-
if (pattern) {
|
|
122
|
-
matches.push.apply(
|
|
123
|
-
matches,
|
|
124
|
-
multimatch(fileNames, pattern).map((filepath) => {
|
|
125
|
-
const data = files[filepath]
|
|
126
|
-
// pattern-matched files might or might not have a "collection" property defined in front-matter
|
|
127
|
-
// and might also be included in multiple collections
|
|
128
|
-
if (!data.collection) {
|
|
129
|
-
data.collection = []
|
|
130
|
-
} else if (typeof data.collection === 'string') {
|
|
131
|
-
data.collection = [data.collection]
|
|
132
|
-
}
|
|
133
|
-
if (!data.collection.includes(collection.name)) {
|
|
134
|
-
data.collection = [...data.collection, collection.name]
|
|
135
|
-
}
|
|
136
|
-
return data
|
|
137
|
-
})
|
|
138
|
-
)
|
|
139
|
-
}
|
|
140
164
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
const isInCollection = Array.isArray(file.collection)
|
|
147
|
-
? file.collection.includes(collection.name)
|
|
148
|
-
: file.collection === collection.name
|
|
149
|
-
return !patternMatched && isInCollection
|
|
150
|
-
})
|
|
151
|
-
)
|
|
165
|
+
matches.push.apply(matches, Object.values(files).filter(file => {
|
|
166
|
+
const patternMatched = matches.includes(file);
|
|
167
|
+
const isInCollection = Array.isArray(file.collection) ? file.collection.includes(collection.name) : file.collection === collection.name;
|
|
168
|
+
return !patternMatched && isInCollection;
|
|
169
|
+
}));
|
|
152
170
|
|
|
153
171
|
if (Object.prototype.hasOwnProperty.call(metadata, name)) {
|
|
154
|
-
debug('Warning: overwriting previously set metadata property %s', name)
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
|
|
172
|
+
debug('Warning: overwriting previously set metadata property %s', name);
|
|
173
|
+
} // apply sort, reverse, filter, limit options in this order
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
metadata[name] = matches.sort(sortBy);
|
|
158
177
|
|
|
159
178
|
if (reverse) {
|
|
160
|
-
metadata[name].reverse()
|
|
179
|
+
metadata[name].reverse();
|
|
161
180
|
}
|
|
162
181
|
|
|
163
|
-
metadata[name] = metadata[name].filter(filterBy).slice(0, limit)
|
|
182
|
+
metadata[name] = metadata[name].filter(filterBy).slice(0, limit);
|
|
164
183
|
|
|
165
184
|
if (collection.metadata) {
|
|
166
|
-
metadata[name].metadata = collection.metadata
|
|
185
|
+
metadata[name].metadata = collection.metadata;
|
|
167
186
|
}
|
|
187
|
+
|
|
168
188
|
if (refer) {
|
|
169
189
|
if (reverse) {
|
|
170
190
|
metadata[name].forEach((file, i) => {
|
|
171
191
|
Object.assign(file, {
|
|
172
192
|
next: i > 0 ? metadata[name][i - 1] : null,
|
|
173
193
|
previous: i < metadata[name].length - 1 ? metadata[name][i + 1] : null
|
|
174
|
-
})
|
|
175
|
-
})
|
|
194
|
+
});
|
|
195
|
+
});
|
|
176
196
|
} else {
|
|
177
197
|
metadata[name].forEach((file, i) => {
|
|
178
198
|
Object.assign(file, {
|
|
179
199
|
previous: i > 0 ? metadata[name][i - 1] : null,
|
|
180
200
|
next: i < metadata[name].length - 1 ? metadata[name][i + 1] : null
|
|
181
|
-
})
|
|
182
|
-
})
|
|
201
|
+
});
|
|
202
|
+
});
|
|
183
203
|
}
|
|
184
204
|
}
|
|
185
205
|
|
|
186
|
-
metadata.collections[name] = metadata[name]
|
|
187
|
-
debug('Added %s files to collection %s', metadata[name].length, name)
|
|
188
|
-
})
|
|
189
|
-
done()
|
|
190
|
-
}
|
|
206
|
+
metadata.collections[name] = metadata[name];
|
|
207
|
+
debug('Added %s files to collection %s', metadata[name].length, name);
|
|
208
|
+
});
|
|
209
|
+
done();
|
|
210
|
+
};
|
|
191
211
|
}
|
|
192
212
|
|
|
193
|
-
initializeCollections.defaults = defaultOptions
|
|
213
|
+
initializeCollections.defaults = defaultOptions;
|
|
194
214
|
|
|
195
|
-
|
|
215
|
+
export { initializeCollections as default };
|
package/package.json
CHANGED
|
@@ -15,26 +15,35 @@
|
|
|
15
15
|
"type": "git",
|
|
16
16
|
"url": "https://github.com/metalsmith/collections.git"
|
|
17
17
|
},
|
|
18
|
-
"version": "1.
|
|
18
|
+
"version": "1.3.0",
|
|
19
19
|
"license": "MIT",
|
|
20
|
-
"
|
|
20
|
+
"source": "src/index.js",
|
|
21
|
+
"main": "lib/index.cjs",
|
|
22
|
+
"module": "lib/index.js",
|
|
23
|
+
"type": "module",
|
|
24
|
+
"types": "./lib/index.d.ts",
|
|
25
|
+
"exports": {
|
|
26
|
+
"import": "./lib/index.js",
|
|
27
|
+
"require": "./lib/index.cjs"
|
|
28
|
+
},
|
|
21
29
|
"dependencies": {
|
|
22
|
-
"debug": "^4.3.3",
|
|
23
30
|
"lodash.get": "^4.4.2",
|
|
24
|
-
"multimatch": "^4.0.0",
|
|
25
31
|
"read-metadata": "^1.0.0"
|
|
26
32
|
},
|
|
27
33
|
"devDependencies": {
|
|
28
|
-
"auto-changelog": "^2.
|
|
34
|
+
"auto-changelog": "^2.4.0",
|
|
29
35
|
"coveralls": "^3.1.1",
|
|
30
|
-
"eslint": "^8.
|
|
31
|
-
"eslint-config-prettier": "^8.
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
36
|
+
"eslint": "^8.20.0",
|
|
37
|
+
"eslint-config-prettier": "^8.5.0",
|
|
38
|
+
"eslint-plugin-import": "^2.26.0",
|
|
39
|
+
"eslint-plugin-node": "^11.1.0",
|
|
40
|
+
"metalsmith": "^2.5.0",
|
|
41
|
+
"microbundle": "^0.15.0",
|
|
42
|
+
"mocha": "^9.2.2",
|
|
43
|
+
"nodemon": "^2.0.19",
|
|
35
44
|
"nyc": "^15.1.0",
|
|
36
|
-
"prettier": "^2.
|
|
37
|
-
"release-it": "^
|
|
45
|
+
"prettier": "^2.7.1",
|
|
46
|
+
"release-it": "^15.2.0"
|
|
38
47
|
},
|
|
39
48
|
"directories": {
|
|
40
49
|
"lib": "lib",
|
|
@@ -45,21 +54,24 @@
|
|
|
45
54
|
],
|
|
46
55
|
"scripts": {
|
|
47
56
|
"changelog": "auto-changelog -u --starting-date 2021-12-01 --sort-commits date-desc --commit-limit false --ignore-commit-pattern '(dev|Release|Merge)'",
|
|
48
|
-
"test": "nyc mocha",
|
|
49
57
|
"coverage": "nyc report --reporter=text-lcov > ./coverage.info",
|
|
50
|
-
"coveralls": "npm run coverage && cat ./coverage.info | coveralls",
|
|
51
58
|
"format": "prettier --write \"**/*.{yml,md,js,json}\"",
|
|
52
|
-
"
|
|
59
|
+
"format:check": "prettier --list-different \"**/*.{yml,md,js,json}\"",
|
|
60
|
+
"lint": "eslint --fix .",
|
|
61
|
+
"lint:check": "eslint --fix-dry-run .",
|
|
53
62
|
"dev": "nodemon --exec 'npm test'",
|
|
54
|
-
"release": "release-it ."
|
|
63
|
+
"release": "release-it .",
|
|
64
|
+
"build": "microbundle --target node --no-sourcemap -f cjs,esm --strict --generateTypes=false",
|
|
65
|
+
"pretest": "npm run build",
|
|
66
|
+
"test": "nyc mocha"
|
|
55
67
|
},
|
|
56
68
|
"publishConfig": {
|
|
57
69
|
"access": "public"
|
|
58
70
|
},
|
|
59
71
|
"peerDependencies": {
|
|
60
|
-
"metalsmith": "^2.
|
|
72
|
+
"metalsmith": "^2.5.0"
|
|
61
73
|
},
|
|
62
74
|
"engines": {
|
|
63
|
-
"node": ">=
|
|
75
|
+
"node": ">=12"
|
|
64
76
|
}
|
|
65
77
|
}
|
package/CHANGELOG.md
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
### Changelog
|
|
2
|
-
#### [v1.2.1](https://github.com/metalsmith/collections/compare/v1.2.1...v1.2.0) / 2022-02-03
|
|
3
|
-
|
|
4
|
-
- Fixes [`#99`](https://github.com/metalsmith/collections/issues/99): collection key on file metadata - no dupes, no nested arrays
|
|
5
|
-
- Fixes regression: incorrect previous & next refs when reverse: true
|
|
6
|
-
- Fixes typo's in README
|
|
7
|
-
#### [v1.2.0](https://github.com/metalsmith/collections/compare/v1.2.0...v1.1.0) / 2022-01-29
|
|
8
|
-
|
|
9
|
-
- Feature: sortBy now also understands nested metadata properties, e.g. `sortBy: 'meta.display.order'`
|
|
10
|
-
- Fixed JSDoc typo that made type hints unavailable
|
|
11
|
-
- Documented limit & refer options
|
|
12
|
-
- Improved README.md with more elaborate examples
|
|
13
|
-
- Refactored to cleaner code
|
|
14
|
-
- Removed dependencies: `extend`,`uniq`
|
|
15
|
-
- Added dependency `lodash.get`
|
|
16
|
-
- Added core-plugin tests
|
|
17
|
-
- Updated devDependencies release-it, prettier, eslint
|
|
18
|
-
|
|
19
|
-
#### [v1.1.0](https://github.com/metalsmith/collections/compare/v1.0.0...v1.1.0) / 2021-15-12
|
|
20
|
-
|
|
21
|
-
- Added standardised code formatting and QA [`#86`](https://github.com/metalsmith/collections/pull/86)
|
|
22
|
-
- Updated History with v1 PRs [`#85`](https://github.com/metalsmith/collections/pull/85)
|
|
23
|
-
- Added better JSDoc types, return named plugin function [`3aa3443`](https://github.com/metalsmith/collections/commit/3aa3443802c2f814c90cf39c7b43de8fc3d3ff13)
|
|
24
|
-
- Updated multimatch to 4.0.0, debug to 4.3.3 [`71d6f65`](https://github.com/metalsmith/collections/commit/71d6f65b9ec5572196e17dfebf5cff2361853f9d)
|
|
25
|
-
|
|
26
|
-
# [1.0.0][] / 2018-10-17
|
|
27
|
-
|
|
28
|
-
- Fixed API and merged many PRs
|
|
29
|
-
- Allow metadata-based filtering with `filterBy` option
|
|
30
|
-
- removed unused module
|
|
31
|
-
- Add documentation: `sortBy` can be a function
|
|
32
|
-
- display only matching files when debugging
|
|
33
|
-
- assign data.path where undefined
|
|
34
|
-
- Clear collections
|
|
35
|
-
- Added multiple collections syntax to Readme.md
|
|
36
|
-
|
|
37
|
-
#### [0.7.0][] / 2015-02-07
|
|
38
|
-
|
|
39
|
-
- Allow front matter and pattern collections.
|
|
40
|
-
- Added the ability to limit the size of a collection
|
|
41
|
-
- Allow collections through metadata alone
|
|
42
|
-
- add ability to disable next/previous references
|
|
43
|
-
|
|
44
|
-
#### [0.6.0][] / 2014-08-12
|
|
45
|
-
|
|
46
|
-
- Added the ability to set multiple collections
|
|
47
|
-
|
|
48
|
-
#### [0.5.1][] / 2014-08-05
|
|
49
|
-
|
|
50
|
-
- Fixed bug with require statement
|
|
51
|
-
|
|
52
|
-
#### [0.5.0][] / 2014-08-04
|
|
53
|
-
|
|
54
|
-
- Added the ability to add metadata to collections
|
|
55
|
-
|
|
56
|
-
#### [0.4.1][] - May 4, 2014
|
|
57
|
-
|
|
58
|
-
- fix empty collections
|
|
59
|
-
|
|
60
|
-
#### [0.4.0][] - March 25, 2014
|
|
61
|
-
|
|
62
|
-
- add option for `sortBy` to be a sorting function
|
|
63
|
-
|
|
64
|
-
#### [0.3.0][] - March 24, 2014
|
|
65
|
-
|
|
66
|
-
- add `collection` property to each file for pattern matches
|
|
67
|
-
|
|
68
|
-
#### [0.2.0][] - March 20, 2014
|
|
69
|
-
|
|
70
|
-
- add collections dictionary to global metadata
|
|
71
|
-
|
|
72
|
-
#### [0.1.0][] - March 6, 2014
|
|
73
|
-
|
|
74
|
-
- add matching by pattern
|
|
75
|
-
- add shorthand for pattern matching
|
|
76
|
-
- add previous and next references
|
|
77
|
-
|
|
78
|
-
#### [0.0.3][] - February 6, 2014
|
|
79
|
-
|
|
80
|
-
- add debug statements
|
|
81
|
-
- swap to `extend` from `defaults` to avoid cloning
|
|
82
|
-
|
|
83
|
-
#### [0.0.2][] - February 6, 2014
|
|
84
|
-
|
|
85
|
-
- swap to `merge` to not act on clones
|
|
86
|
-
|
|
87
|
-
#### [0.0.1][] - February 5, 2014
|
|
88
|
-
|
|
89
|
-
:sparkles:
|