@metalsmith/collections 1.1.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/CHANGELOG.md +79 -0
- package/LICENSE +22 -0
- package/README.md +250 -0
- package/lib/index.js +236 -0
- package/package.json +66 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
### Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file. Dates are displayed in UTC.
|
|
4
|
+
|
|
5
|
+
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
6
|
+
|
|
7
|
+
#### [v1.1.0](https://github.com/metalsmith/collections/compare/v1.0.0...v1.1.0)
|
|
8
|
+
|
|
9
|
+
- Added standardised code formatting and QA [`#86`](https://github.com/metalsmith/collections/pull/86)
|
|
10
|
+
- Updated History with v1 PRs [`#85`](https://github.com/metalsmith/collections/pull/85)
|
|
11
|
+
- Added better JSDoc types, return named plugin function [`3aa3443`](https://github.com/metalsmith/collections/commit/3aa3443802c2f814c90cf39c7b43de8fc3d3ff13)
|
|
12
|
+
- Updated multimatch to 4.0.0, debug to 4.3.3 [`71d6f65`](https://github.com/metalsmith/collections/commit/71d6f65b9ec5572196e17dfebf5cff2361853f9d)
|
|
13
|
+
|
|
14
|
+
<!-- auto-changelog-above -->
|
|
15
|
+
|
|
16
|
+
# [1.0.0][] / 2018-10-17
|
|
17
|
+
|
|
18
|
+
- Fixed API and merged many PRs
|
|
19
|
+
- Allow metadata-based filtering with `filterBy` option
|
|
20
|
+
- removed unused module
|
|
21
|
+
- Add documentation: `sortBy` can be a function
|
|
22
|
+
- display only matching files when debugging
|
|
23
|
+
- assign data.path where undefined
|
|
24
|
+
- Clear collections
|
|
25
|
+
- Added multiple collections syntax to Readme.md
|
|
26
|
+
|
|
27
|
+
#### [0.7.0][] / 2015-02-07
|
|
28
|
+
|
|
29
|
+
- Allow front matter and pattern collections.
|
|
30
|
+
- Added the ability to limit the size of a collection
|
|
31
|
+
- Allow collections through metadata alone
|
|
32
|
+
- add ability to disable next/previous references
|
|
33
|
+
|
|
34
|
+
#### [0.6.0][] / 2014-08-12
|
|
35
|
+
|
|
36
|
+
- Added the ability to set multiple collections
|
|
37
|
+
|
|
38
|
+
#### [0.5.1][] / 2014-08-05
|
|
39
|
+
|
|
40
|
+
- Fixed bug with require statement
|
|
41
|
+
|
|
42
|
+
#### [0.5.0][] / 2014-08-04
|
|
43
|
+
|
|
44
|
+
- Added the ability to add metadata to collections
|
|
45
|
+
|
|
46
|
+
#### [0.4.1][] - May 4, 2014
|
|
47
|
+
|
|
48
|
+
- fix empty collections
|
|
49
|
+
|
|
50
|
+
#### [0.4.0][] - March 25, 2014
|
|
51
|
+
|
|
52
|
+
- add option for `sortBy` to be a sorting function
|
|
53
|
+
|
|
54
|
+
#### [0.3.0][] - March 24, 2014
|
|
55
|
+
|
|
56
|
+
- add `collection` property to each file for pattern matches
|
|
57
|
+
|
|
58
|
+
#### [0.2.0][] - March 20, 2014
|
|
59
|
+
|
|
60
|
+
- add collections dictionary to global metadata
|
|
61
|
+
|
|
62
|
+
#### [0.1.0][] - March 6, 2014
|
|
63
|
+
|
|
64
|
+
- add matching by pattern
|
|
65
|
+
- add shorthand for pattern matching
|
|
66
|
+
- add previous and next references
|
|
67
|
+
|
|
68
|
+
#### [0.0.3][] - February 6, 2014
|
|
69
|
+
|
|
70
|
+
- add debug statements
|
|
71
|
+
- swap to `extend` from `defaults` to avoid cloning
|
|
72
|
+
|
|
73
|
+
#### [0.0.2][] - February 6, 2014
|
|
74
|
+
|
|
75
|
+
- swap to `merge` to not act on clones
|
|
76
|
+
|
|
77
|
+
#### [0.0.1][] - February 5, 2014
|
|
78
|
+
|
|
79
|
+
:sparkles:
|
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2021 webketje
|
|
4
|
+
Copyright (c) 2014-2021 Segment
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
# @metalsmith/collections
|
|
2
|
+
|
|
3
|
+
A [Metalsmith](https://github.com/metalsmith/metalsmith) plugin that lets you group files together into an ordered collection, like blog posts. That way you can loop over them to generate an index, or add 'next' and 'previous' links between them.
|
|
4
|
+
|
|
5
|
+
[![metalsmith: core plugin][metalsmith-badge]][metalsmith-url]
|
|
6
|
+
[![npm version][npm-badge]][npm-url]
|
|
7
|
+
[![ci: build][ci-badge]][ci-url]
|
|
8
|
+
[![code coverage][codecov-badge]][codecov-url]
|
|
9
|
+
[![license: MIT][license-badge]][license-url]
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- can match files by `collection` metadata
|
|
14
|
+
- can match files by pattern
|
|
15
|
+
- can limit the number of files in a collection
|
|
16
|
+
- can filter files in a collection based on metadata
|
|
17
|
+
- adds collections to global metadata
|
|
18
|
+
- adds `next` and `previous` references to each file in the collection
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
NPM:
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
npm install @metalsmith/collections
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Yarn:
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
yarn add @metalsmith/collections
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Usage
|
|
35
|
+
|
|
36
|
+
There are two ways to create collections (they can be used together):
|
|
37
|
+
|
|
38
|
+
- **by pattern** - this is just passing a globbing pattern that will group any files that match into the same collection. The passed pattern can be a single pattern (as a string) or an array of globing patterns. For more information read the [multimatch patterns documentation](https://www.npmjs.com/package/multimatch#how-multiple-patterns-work).
|
|
39
|
+
- **by metadata** - this is adding a specific `collection` metadata field to each item that you want to add to a collection.
|
|
40
|
+
|
|
41
|
+
The simplest way to create a collection is to use a pattern to match the files you want to group together:
|
|
42
|
+
|
|
43
|
+
```js
|
|
44
|
+
const collections = require('@metalsmith/collections')
|
|
45
|
+
|
|
46
|
+
metalsmith.use(
|
|
47
|
+
collections({
|
|
48
|
+
articles: '*.md'
|
|
49
|
+
})
|
|
50
|
+
)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Which is just a shorthand. You could also add additional options:
|
|
54
|
+
|
|
55
|
+
```js
|
|
56
|
+
metalsmith.use(
|
|
57
|
+
collections({
|
|
58
|
+
articles: {
|
|
59
|
+
pattern: '*.md',
|
|
60
|
+
sortBy: 'date',
|
|
61
|
+
reverse: true
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
But you can also match based on a `collection` property in each file's metadata by omitting a pattern, and adding the property to your files:
|
|
68
|
+
|
|
69
|
+
```js
|
|
70
|
+
metalsmith.use(
|
|
71
|
+
collections({
|
|
72
|
+
articles: {
|
|
73
|
+
sortBy: 'date',
|
|
74
|
+
reverse: true
|
|
75
|
+
}
|
|
76
|
+
})
|
|
77
|
+
)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
```markdown
|
|
81
|
+
---
|
|
82
|
+
title: My Article
|
|
83
|
+
collection: articles
|
|
84
|
+
date: 2021-12-01
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
My article contents...
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Multiple collections can also be assigned per file:
|
|
91
|
+
|
|
92
|
+
```markdown
|
|
93
|
+
---
|
|
94
|
+
title: My Article
|
|
95
|
+
collection:
|
|
96
|
+
- articles
|
|
97
|
+
- news
|
|
98
|
+
date: 2021-12-01
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
My article contents...
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
All of the files with a matching `collection` will be added to an array that is exposed as a key of the same name on the global Metalsmith `metadata`.
|
|
105
|
+
You can omit passing any options to the plugin when matching based on a `collection` property.
|
|
106
|
+
|
|
107
|
+
Adds a `path` property to the collection item's data which contains the file path of the generated file. For example, this can be used in mustache templates to create links:
|
|
108
|
+
|
|
109
|
+
```html
|
|
110
|
+
<h1><a href="/{{ path }}">{{ title }}</a></h1>
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
The sorting method can be overridden with a custom function in order to sort the files in any order you prefer. For instance, this function sorts the "subpages" collection by a numerical "index" property but places unindexed items last.
|
|
114
|
+
|
|
115
|
+
```js
|
|
116
|
+
metalsmith.use(
|
|
117
|
+
collections({
|
|
118
|
+
subpages: {
|
|
119
|
+
sortBy: function(a, b) {
|
|
120
|
+
let aNum, bNum
|
|
121
|
+
|
|
122
|
+
aNum = +a.index
|
|
123
|
+
bNum = +b.index
|
|
124
|
+
|
|
125
|
+
// Test for NaN
|
|
126
|
+
if (aNum != aNum && bNum != bNum) return 0
|
|
127
|
+
if (aNum != aNum) return 1
|
|
128
|
+
if (bNum != bNum) return -1
|
|
129
|
+
|
|
130
|
+
// Normal comparison, want lower numbers first
|
|
131
|
+
if (aNum > bNum) return 1
|
|
132
|
+
if (bNum > aNum) return -1
|
|
133
|
+
return 0
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
})
|
|
137
|
+
)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
The `filterBy` function is passed a single argument which corresponds to each file's metadata. You can use the metadata to perform comparisons or carry out other decision-making logic. If the function you supply evaluates to `true`, the file will be added to the collection. If it evaluates to `false`, the file will not be added.
|
|
141
|
+
|
|
142
|
+
### Collection Metadata
|
|
143
|
+
|
|
144
|
+
Additional metadata can be added to the collection object.
|
|
145
|
+
|
|
146
|
+
```js
|
|
147
|
+
metalsmith.use(
|
|
148
|
+
collections({
|
|
149
|
+
articles: {
|
|
150
|
+
sortBy: 'date',
|
|
151
|
+
reverse: true,
|
|
152
|
+
metadata: {
|
|
153
|
+
name: 'Articles',
|
|
154
|
+
description: 'The Articles listed here...'
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
})
|
|
158
|
+
)
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Collection metadata can also be assigned from a `json` or `yaml` file.
|
|
162
|
+
|
|
163
|
+
```js
|
|
164
|
+
metalsmith.use(
|
|
165
|
+
collections({
|
|
166
|
+
articles: {
|
|
167
|
+
sortBy: 'date',
|
|
168
|
+
reverse: true,
|
|
169
|
+
metadata: 'path/to/file.json'
|
|
170
|
+
}
|
|
171
|
+
})
|
|
172
|
+
)
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
On each collection definition, it's possible to add a `limit` option so that the
|
|
176
|
+
collection length is not higher than the given limit:
|
|
177
|
+
|
|
178
|
+
```js
|
|
179
|
+
metalsmith.use(
|
|
180
|
+
collections({
|
|
181
|
+
lastArticles: {
|
|
182
|
+
sortBy: 'date',
|
|
183
|
+
limit: 10
|
|
184
|
+
}
|
|
185
|
+
})
|
|
186
|
+
)
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
By adding `refer: false` to your options, it will skip adding the "next" and
|
|
190
|
+
"previous" links to your articles.
|
|
191
|
+
|
|
192
|
+
```js
|
|
193
|
+
metalsmith.use(
|
|
194
|
+
collections({
|
|
195
|
+
articles: {
|
|
196
|
+
refer: false
|
|
197
|
+
}
|
|
198
|
+
})
|
|
199
|
+
)
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Debug
|
|
203
|
+
|
|
204
|
+
To log debug output, set the `DEBUG` environment variable to `@metalsmith/collections`:
|
|
205
|
+
|
|
206
|
+
Linux/Mac:
|
|
207
|
+
|
|
208
|
+
```sh
|
|
209
|
+
DEBUG=@metalsmith/collections
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Windows:
|
|
213
|
+
|
|
214
|
+
```cmd
|
|
215
|
+
set "DEBUG=@metalsmith/collections"
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## CLI Usage
|
|
219
|
+
|
|
220
|
+
Add the `@metalsmith/collections` key to your `metalsmith.json` `plugins` key:
|
|
221
|
+
|
|
222
|
+
```json
|
|
223
|
+
{
|
|
224
|
+
"plugins": [
|
|
225
|
+
{
|
|
226
|
+
"@metalsmith/collections": {
|
|
227
|
+
"articles": {
|
|
228
|
+
"sortBy": "date",
|
|
229
|
+
"reverse": true
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
]
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## License
|
|
238
|
+
|
|
239
|
+
[MIT](LICENSE)
|
|
240
|
+
|
|
241
|
+
[npm-badge]: https://img.shields.io/npm/v/@metalsmith/collections.svg
|
|
242
|
+
[npm-url]: https://www.npmjs.com/package/@metalsmith/collections
|
|
243
|
+
[ci-badge]: https://app.travis-ci.com/github/metalsmith/collections.svg?branch=master
|
|
244
|
+
[ci-url]: https://app.travis-ci.com/github/metalsmith/collections
|
|
245
|
+
[metalsmith-badge]: https://img.shields.io/badge/metalsmith-plugin-green.svg?longCache=true
|
|
246
|
+
[metalsmith-url]: http://metalsmith.io
|
|
247
|
+
[codecov-badge]: https://img.shields.io/coveralls/github/metalsmith/collections
|
|
248
|
+
[codecov-url]: https://coveralls.io/github/metalsmith/collections
|
|
249
|
+
[license-badge]: https://img.shields.io/github/license/metalsmith/collections
|
|
250
|
+
[license-url]: LICENSE
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
var debug = require('debug')('@metalsmith/collections')
|
|
2
|
+
var multimatch = require('multimatch')
|
|
3
|
+
var unique = require('uniq')
|
|
4
|
+
var loadMetadata = require('read-metadata').sync
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Expose `plugin`.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
module.exports = plugin
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @typedef {Object} CollectionConfig
|
|
14
|
+
* @property {String|String[]} pattern - One or more glob patterns to match files to a collection
|
|
15
|
+
* @property {'date'|Function} sortBy
|
|
16
|
+
* @property {Boolean} reverse - Whether to invert the sorting function results (asc/descending)
|
|
17
|
+
* @property {Function} filterBy - A function that gets a `Metalsmith.File` as first argument and returns `true` for every file to include in the collection
|
|
18
|
+
* @property {Object} metadata - An object with metadata to attach to the collection
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Metalsmith plugin that adds `collections` of files to the global
|
|
23
|
+
* metadata as a sorted array.
|
|
24
|
+
*
|
|
25
|
+
* @param {Object.<String,CollectionConfig|String>} opts
|
|
26
|
+
* @return {import('metalsmith').Plugin}
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
function plugin(opts) {
|
|
30
|
+
opts = normalize(opts)
|
|
31
|
+
var keys = Object.keys(opts)
|
|
32
|
+
var match = matcher(opts)
|
|
33
|
+
|
|
34
|
+
return function collections(files, metalsmith, done) {
|
|
35
|
+
var metadata = metalsmith.metadata()
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Clear collections (to prevent multiple additions of the same file)
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
keys.forEach(function(key) {
|
|
42
|
+
metadata[key] = []
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Clear collections (to prevent multiple additions of the same file when running via metalsmith-browser-sync)
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
keys.forEach(function(key) {
|
|
50
|
+
metadata[key] = []
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Find the files in each collection.
|
|
55
|
+
*/
|
|
56
|
+
|
|
57
|
+
Object.keys(files).forEach(function(file) {
|
|
58
|
+
var data = files[file]
|
|
59
|
+
|
|
60
|
+
data.path = data.path || file
|
|
61
|
+
|
|
62
|
+
const matches = match(file, data)
|
|
63
|
+
if (matches.length) {
|
|
64
|
+
debug('processing file: %s', file)
|
|
65
|
+
|
|
66
|
+
matches.forEach(function(key) {
|
|
67
|
+
if (key && keys.indexOf(key) < 0) {
|
|
68
|
+
opts[key] = {}
|
|
69
|
+
keys.push(key)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
metadata[key] = metadata[key] || []
|
|
73
|
+
// Check if the user supplied a filter function. If so, pass the file metadata to it and
|
|
74
|
+
// only add files that pass the filter test.
|
|
75
|
+
if (typeof opts[key].filterBy == 'function') {
|
|
76
|
+
var filterFunc = opts[key].filterBy
|
|
77
|
+
if (filterFunc(data)) {
|
|
78
|
+
metadata[key].push(data)
|
|
79
|
+
}
|
|
80
|
+
} else {
|
|
81
|
+
// If no filter function is provided, add every file to the collection.
|
|
82
|
+
metadata[key].push(data)
|
|
83
|
+
}
|
|
84
|
+
})
|
|
85
|
+
}
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Ensure that a default empty collection exists.
|
|
90
|
+
*/
|
|
91
|
+
|
|
92
|
+
keys.forEach(function(key) {
|
|
93
|
+
metadata[key] = metadata[key] || []
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Sort the collections.
|
|
98
|
+
*/
|
|
99
|
+
|
|
100
|
+
keys.forEach(function(key) {
|
|
101
|
+
debug('sorting collection: %s', key)
|
|
102
|
+
var settings = opts[key]
|
|
103
|
+
var sort = settings.sortBy || 'date'
|
|
104
|
+
var col = metadata[key]
|
|
105
|
+
|
|
106
|
+
if ('function' == typeof sort) {
|
|
107
|
+
col.sort(sort)
|
|
108
|
+
} else {
|
|
109
|
+
col.sort(function(a, b) {
|
|
110
|
+
a = a[sort]
|
|
111
|
+
b = b[sort]
|
|
112
|
+
if (!a && !b) return 0
|
|
113
|
+
if (!a) return -1
|
|
114
|
+
if (!b) return 1
|
|
115
|
+
if (b > a) return -1
|
|
116
|
+
if (a > b) return 1
|
|
117
|
+
return 0
|
|
118
|
+
})
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (settings.reverse) col.reverse()
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Add `next` and `previous` references and apply the `limit` option
|
|
126
|
+
*/
|
|
127
|
+
|
|
128
|
+
keys.forEach(function(key) {
|
|
129
|
+
debug('referencing collection: %s', key)
|
|
130
|
+
var settings = opts[key]
|
|
131
|
+
var col = metadata[key]
|
|
132
|
+
var last = col.length - 1
|
|
133
|
+
if (opts[key].limit && opts[key].limit < col.length) {
|
|
134
|
+
col = metadata[key] = col.slice(0, opts[key].limit)
|
|
135
|
+
last = opts[key].limit - 1
|
|
136
|
+
}
|
|
137
|
+
if (settings.refer === false) return
|
|
138
|
+
col.forEach(function(file, i) {
|
|
139
|
+
if (0 != i) file.previous = col[i - 1]
|
|
140
|
+
if (last != i) file.next = col[i + 1]
|
|
141
|
+
})
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Add collection metadata
|
|
146
|
+
*/
|
|
147
|
+
|
|
148
|
+
keys.forEach(function(key) {
|
|
149
|
+
debug('adding metadata: %s', key)
|
|
150
|
+
var settings = opts[key]
|
|
151
|
+
var col = metadata[key]
|
|
152
|
+
col.metadata = typeof settings.metadata === 'string' ? loadMetadata(settings.metadata) : settings.metadata
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Add them grouped together to the global metadata.
|
|
157
|
+
*/
|
|
158
|
+
|
|
159
|
+
metadata.collections = {}
|
|
160
|
+
keys.forEach(function(key) {
|
|
161
|
+
return (metadata.collections[key] = metadata[key])
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
done()
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Normalize an `options` dictionary.
|
|
170
|
+
*
|
|
171
|
+
* @param {Object.<string,CollectionConfig>} options
|
|
172
|
+
*/
|
|
173
|
+
|
|
174
|
+
function normalize(options) {
|
|
175
|
+
options = options || {}
|
|
176
|
+
|
|
177
|
+
for (var key in options) {
|
|
178
|
+
var val = options[key]
|
|
179
|
+
if ('string' == typeof val) options[key] = { pattern: val }
|
|
180
|
+
if (val instanceof Array) options[key] = { pattern: val }
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return options
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Generate a matching function for a given set of `collections`.
|
|
188
|
+
*
|
|
189
|
+
* @param {Object.<String, CollectionConfig>} collections
|
|
190
|
+
* @return {Function}
|
|
191
|
+
*/
|
|
192
|
+
|
|
193
|
+
function matcher(cols) {
|
|
194
|
+
var keys = Object.keys(cols)
|
|
195
|
+
var matchers = {}
|
|
196
|
+
|
|
197
|
+
keys.forEach(function(key) {
|
|
198
|
+
var opts = cols[key]
|
|
199
|
+
if (!opts.pattern) {
|
|
200
|
+
return
|
|
201
|
+
}
|
|
202
|
+
matchers[key] = {
|
|
203
|
+
match: function(file) {
|
|
204
|
+
return multimatch(file, opts.pattern)
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
return function(file, data) {
|
|
210
|
+
var matches = []
|
|
211
|
+
|
|
212
|
+
if (data.collection) {
|
|
213
|
+
var collection = data.collection
|
|
214
|
+
if (!Array.isArray(collection)) {
|
|
215
|
+
collection = [collection]
|
|
216
|
+
}
|
|
217
|
+
collection.forEach(function(key) {
|
|
218
|
+
matches.push(key)
|
|
219
|
+
|
|
220
|
+
if (key && keys.indexOf(key) < 0) {
|
|
221
|
+
debug('adding new collection through metadata: %s', key)
|
|
222
|
+
}
|
|
223
|
+
})
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
for (var key in matchers) {
|
|
227
|
+
var m = matchers[key]
|
|
228
|
+
if (m.match(file).length) {
|
|
229
|
+
matches.push(key)
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
data.collection = unique(matches)
|
|
234
|
+
return data.collection
|
|
235
|
+
}
|
|
236
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@metalsmith/collections",
|
|
3
|
+
"description": "A Metalsmith plugin that adds collections of files to the global metadata.",
|
|
4
|
+
"keywords": [
|
|
5
|
+
"collections",
|
|
6
|
+
"metalsmith",
|
|
7
|
+
"metalsmith-plugin",
|
|
8
|
+
"static-site"
|
|
9
|
+
],
|
|
10
|
+
"homepage": "https://github.com/metalsmith/collections#readme",
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/metalsmith/collections/issues"
|
|
13
|
+
},
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "https://github.com/metalsmith/collections.git"
|
|
17
|
+
},
|
|
18
|
+
"version": "1.1.0",
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"main": "lib/index.js",
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"debug": "^4.3.3",
|
|
23
|
+
"extend": "^3.0.0",
|
|
24
|
+
"multimatch": "^4.0.0",
|
|
25
|
+
"read-metadata": "^1.0.0",
|
|
26
|
+
"uniq": "^1.0.1"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"auto-changelog": "^2.3.0",
|
|
30
|
+
"coveralls": "^3.1.1",
|
|
31
|
+
"eslint": "^8.4.1",
|
|
32
|
+
"eslint-config-prettier": "^8.3.0",
|
|
33
|
+
"metalsmith": "^2.3.0",
|
|
34
|
+
"mocha": "^7.2.0",
|
|
35
|
+
"nodemon": "^1.18.4",
|
|
36
|
+
"nyc": "^15.1.0",
|
|
37
|
+
"prettier": "^1.19.1",
|
|
38
|
+
"release-it": "^14.11.8"
|
|
39
|
+
},
|
|
40
|
+
"directories": {
|
|
41
|
+
"lib": "lib",
|
|
42
|
+
"test": "test"
|
|
43
|
+
},
|
|
44
|
+
"files": [
|
|
45
|
+
"lib/*"
|
|
46
|
+
],
|
|
47
|
+
"scripts": {
|
|
48
|
+
"changelog": "auto-changelog -u --starting-date 2021-12-01 --sort-commits date-desc --commit-limit false --ignore-commit-pattern '(dev|Release|Merge)'",
|
|
49
|
+
"test": "nyc mocha",
|
|
50
|
+
"coverage": "nyc report --reporter=text-lcov > ./coverage.info",
|
|
51
|
+
"coveralls": "npm run coverage && cat ./coverage.info | coveralls",
|
|
52
|
+
"format": "prettier --write \"**/*.{yml,md,js,json}\"",
|
|
53
|
+
"lint": "eslint --cache --fix-dry-run .",
|
|
54
|
+
"dev": "nodemon --exec 'npm test'",
|
|
55
|
+
"release": "release-it ."
|
|
56
|
+
},
|
|
57
|
+
"publishConfig": {
|
|
58
|
+
"access": "public"
|
|
59
|
+
},
|
|
60
|
+
"peerDependencies": {
|
|
61
|
+
"metalsmith": "^2.3.0"
|
|
62
|
+
},
|
|
63
|
+
"engines": {
|
|
64
|
+
"node": ">=8"
|
|
65
|
+
}
|
|
66
|
+
}
|