@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/CHANGELOG.md ADDED
@@ -0,0 +1,70 @@
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
+ #### [v2.0.0](https://github.com/metalsmith/collections/compare/v1.3.1...v2.0.0)
8
+
9
+ - Closes #98: adds 'first' & 'last' references when refer:true [`#98`](https://github.com/metalsmith/collections/issues/98)
10
+ - BREAKING: Closes #101: condenses sortBy, reverse into sort option. Renames filterBy option to filter. [`#101`](https://github.com/metalsmith/collections/issues/101)
11
+ - Updates README.md, fixes ESLint issues, versions build to allow npm installing from repo [`f9da8e4`](https://github.com/metalsmith/collections/commit/f9da8e4d3952c3452fbef52cdc5951bd4e48b9f6)
12
+ - BREAKING: references (previous, next,..) are set on file.collection[name][previous/next] as arrays [`8c7d9d6`](https://github.com/metalsmith/collections/commit/8c7d9d68fa5b48f314707a3d29075438a8cb43f2)
13
+ - BREAKING: collections are only available via metalsmith.metadata().collections [`e8e2760`](https://github.com/metalsmith/collections/commit/e8e2760e72b06211f8d5f9f11296a82efe8efc4f)
14
+ - Require metalsmith > 2.6.0 & use metalsmith.matter instead of removed dependency read-metadata [`c0748fa`](https://github.com/metalsmith/collections/commit/c0748fa69c55456c39214121998719b01a695064)
15
+ - BREAKING: collection metadata can only be added from in-source files [`df507d6`](https://github.com/metalsmith/collections/commit/df507d6b20d9a44215dc34e3c3ce25517032c66f)
16
+ - BREAKING: Make metadata accessible from Collection array instead of '.metadata' property [`42f45c8`](https://github.com/metalsmith/collections/commit/42f45c876946f66578e770c38c3b0ac7b1a247ac)
17
+ - BREAKING: Adds 'path' property to sorting context, and changes the default sorting to path:asc [`64b5f72`](https://github.com/metalsmith/collections/commit/64b5f7203ec0afa3c9c76e29af277b4e91b61738)
18
+ - Drops support for Node < 14.14.0, updates CI, drops Gitter notification [`36eb59d`](https://github.com/metalsmith/collections/commit/36eb59daf06e35f748b3c9872e77f1ee947e63e7)
19
+ - BREAKING: no longer sets 'file.path' property [`df26510`](https://github.com/metalsmith/collections/commit/df26510b210ae2731295ff4f733c4550e32e741c)
20
+ - Better documentation for sorting + typescript [`1d3f81e`](https://github.com/metalsmith/collections/commit/1d3f81e5997375673c49efcbb5f4e7a7408068b5)
21
+
22
+ #### [v1.3.1](https://github.com/metalsmith/collections/compare/v1.3.0...v1.3.1)
23
+
24
+ > 26 November 2024
25
+
26
+ - Fix: make all option properties optional [`b85b6cf`](https://github.com/metalsmith/collections/commit/b85b6cf75f949188191415147338ae28c5b9fbac)
27
+ - Renames default export to collections for better intellisense [`61ec7f9`](https://github.com/metalsmith/collections/commit/61ec7f93fe4fac2112909b4fee233507affe05a2)
28
+ - Includes sourcemap for better stack traces [`b5b8059`](https://github.com/metalsmith/collections/commit/b5b80597cf821b3c478b864ddf5739d60aadce0d)
29
+ - Fix: conditional exports types [`e8bb72a`](https://github.com/metalsmith/collections/commit/e8bb72ac22298324669b3e7b45d7177c88b13c2a)
30
+
31
+ #### [v1.3.0](https://github.com/metalsmith/collections/compare/v1.2.2...v1.3.0)
32
+
33
+ > 27 September 2022
34
+
35
+ - Provides dual ESM/CJS bundle [`61430d4`](https://github.com/metalsmith/collections/commit/61430d489ae87df1276f61de8aad2755c0491cc9)
36
+ - switched debugger to metalsmith.debug [`8df9e65`](https://github.com/metalsmith/collections/commit/8df9e65b6b03f4c3d96a81d477a21d69aeafadbf)
37
+ - Adds Typescript types support [`9f9b36c`](https://github.com/metalsmith/collections/commit/9f9b36ca569153ad84be89facdc6a2630e86a6af)
38
+
39
+ #### [v1.2.2](https://github.com/metalsmith/collections/compare/v1.2.1...v1.2.2)
40
+
41
+ > 28 July 2022
42
+
43
+ - Resolves #102: remove multimatch, use metalsmith.match [`#102`](https://github.com/metalsmith/collections/issues/102)
44
+ - Drops support for Node < 12 [`6a7271c`](https://github.com/metalsmith/collections/commit/6a7271c9a170e88ae91e1d05e2f7162606566f3f)
45
+
46
+ #### [v1.2.1](https://github.com/metalsmith/collections/compare/v1.2.0...v1.2.1)
47
+
48
+ > 3 February 2022
49
+
50
+ - Closes #27 by adding a test for repeat builds [`#27`](https://github.com/metalsmith/collections/issues/27)
51
+ - Fixes incorrect next and previous references [`665de09`](https://github.com/metalsmith/collections/commit/665de091b3bbb7b74741d15e17e471ae225ba2ec)
52
+ - Fixes collection property on files and adds test: no dupes, no nested arrays (#99) [`727769d`](https://github.com/metalsmith/collections/commit/727769d95464e61739523538006cb863220cfae6)
53
+
54
+ #### [v1.2.0](https://github.com/metalsmith/collections/compare/v1.1.0...v1.2.0)
55
+
56
+ > 29 January 2022
57
+
58
+ - feat: refactor, clean code, remove redundant dependencies, add tests [`d481b92`](https://github.com/metalsmith/collections/commit/d481b927b6137df81e8fc71de99c1277f6a131c2)
59
+ - docs: update README, prepare changelog for v1.2 [`c004ed0`](https://github.com/metalsmith/collections/commit/c004ed00216145f3cfa82042ab9243e42c23edb3)
60
+ - [skip travis] dev: fix readme badges [`87e4d37`](https://github.com/metalsmith/collections/commit/87e4d370530065a790c0b077d820fcc47bd6594c)
61
+
62
+ #### [v1.1.0](https://github.com/metalsmith/collections/compare/v1.0.0...v1.1.0)
63
+
64
+ > 15 December 2021
65
+
66
+ - Added standardised code formatting and QA [`#86`](https://github.com/metalsmith/collections/pull/86)
67
+ - Updated History with v1 PRs [`#85`](https://github.com/metalsmith/collections/pull/85)
68
+ - Aligned dotfiles & repo files with core plugins. Added LICENSE, updated devDependencies [`0f2480b`](https://github.com/metalsmith/collections/commit/0f2480b4c2baa22268229ad3d686fb9e21773602)
69
+ - Updated multimatch to 4.0.0, debug to 4.3.3 [`71d6f65`](https://github.com/metalsmith/collections/commit/71d6f65b9ec5572196e17dfebf5cff2361853f9d)
70
+ - Added better JSDoc types, return named plugin function [`3aa3443`](https://github.com/metalsmith/collections/commit/3aa3443802c2f814c90cf39c7b43de8fc3d3ff13)
package/README.md CHANGED
@@ -10,12 +10,11 @@ A Metalsmith plugin that lets you group files together into ordered collections,
10
10
 
11
11
  ## Features
12
12
 
13
- - can match files by `collection` file metadata
14
- - can match files by pattern
13
+ - can match files by `collection` file metadata or pattern
15
14
  - can limit the number of files in a collection
16
15
  - can filter files in a collection based on file metadata
17
- - adds collections to global metadata
18
- - adds `next` and `previous` references to each file in the collection
16
+ - adds collections to global metadata under the `collections` key.
17
+ - adds `next`, `previous`, `first` and `last` references to each file's collection references
19
18
 
20
19
  ## Installation
21
20
 
@@ -44,44 +43,46 @@ import { dirname } from 'path'
44
43
  const __dirname = dirname(new URL(import.meta.url).pathname)
45
44
 
46
45
  // defaults, only create collections based on file metadata
47
- Metalsmith(__dirname)
48
- .use(markdown())
49
- .use(collections())
46
+ Metalsmith(__dirname).use(markdown()).use(collections())
50
47
 
51
48
  // defaults for a "news" collection, except pattern option
52
49
  Metalsmith(__dirname)
53
50
  .use(markdown())
54
- .use(collections({
55
- news: { pattern: 'news/**/*.html' }
56
- }))
51
+ .use(
52
+ collections({
53
+ news: { pattern: 'news/**/*.html' }
54
+ })
55
+ )
57
56
 
58
57
  // explicit defaults for a "news" collection, except pattern option
59
58
  Metalsmith(__dirname)
60
59
  .use(markdown())
61
- .use(collections({
62
- pattern: { pattern: 'news/**/*.html' },
63
- metadata: null,
64
- filterBy: () => true,
65
- sortBy: defaultSort,
66
- reverse: false,
67
- limit: Infinity,
68
- refer: true
69
- })
60
+ .use(
61
+ collections({
62
+ pattern: { pattern: 'news/**/*.html' },
63
+ metadata: null,
64
+ filter: () => true,
65
+ sort: 'date:desc',
66
+ limit: Infinity,
67
+ refer: true
68
+ })
69
+ )
70
70
  ```
71
71
 
72
- _Note: all examples in the readme use the same collections definitions under [Defining collections](#defining-collections)_
72
+ With the example above, the file `src/news/world/something.html`'s `collection` property will become `['news']` but with extra properties attached, so that `file.collection.news.previous.title` resolves, as well as `file.collection.news.previous[0].title`
73
+
74
+ _Note: all subsequent examples in the readme use the same collections definitions under [Defining collections](#defining-collections)_
73
75
 
74
76
  ### Options
75
77
 
76
78
  All options are _optional_
77
79
 
78
80
  - **pattern** `string|string[]` - one or more glob patterns to group files into a collection
79
- - **filterBy** `Function` - a function that returns `false` for files that should be filtered _out_ of the collection
81
+ - **filter** `Function` - a function that returns `false` for files that should be filtered _out_ of the collection
80
82
  - **limit** `number` - restrict the number of files in a collection to at most `limit`
81
- - **sortBy** `string|Function` - a file metadata key to sort by (for example `date` or `pubdate` or `title`), or a custom sort function
82
- - **reverse** `boolean` - whether the sort should be reversed (e.g., for a news/blog collection, you typically want `reverse: true`)
83
+ - **sort** `string|Function` - a sort string of the format `'<key_or_keypath>:<asc|desc>'`, followed by the sort order, for example: `date` or `pubdate:desc` or `order:asc`, or a custom sort function. Defaults to `path:asc` which is filesystem alphabetical order.
83
84
  - **metadata** `Object|string` - metadata to attach to the collection. Will be available as `metalsmith.metadata().collections.<name>.metadata`. This can be used for example to attach metadata for index pages. _If a string is passed, it will be interpreted as a file path to an external `JSON` or `YAML` metadata file_
84
- - **refer** `boolean` - will add `previous` and `next` keys to each file in a collection. `true` by default
85
+ - **refer** `boolean` - will add `next`, `previous`, `first` and `last` keys to each file in a collection. `true` by default
85
86
 
86
87
  ### Defining collections
87
88
 
@@ -97,11 +98,10 @@ There are 2 ways to create collections & they can be used together:
97
98
  metadata: {
98
99
  title: 'Latest news',
99
100
  description: 'All the latest in politics & world news',
100
- slug: 'news'
101
+ permalink: 'news'
101
102
  },
102
103
  pattern: 'news/**/*.html',
103
- sortBy: 'pubdate',
104
- reverse: true
104
+ sort: 'pubdate:desc'
105
105
  },
106
106
  services: 'services/**/*.html'
107
107
  })
@@ -142,33 +142,77 @@ There are 2 ways to create collections & they can be used together:
142
142
  ...contents
143
143
  ```
144
144
 
145
+ #### Sorting
146
+
147
+ By default sorting is done on `path:asc`, which is alphabetical filepath order.
148
+ When `@metalsmith/collections` runs, it temporarily adds the file `path` to the sorting context.
149
+
150
+ When the sorting order (_asc_-ending or _desc_-ending) is omitted, _desc_ ending is implied.
151
+
152
+ So `prop:asc` for the following file metadata would be ordered as:
153
+
154
+ - `pubdate:asc`: `[Date(2023-01-01), Date(2023-01-05), Date(2023-01-03)]` -> `[Date(2023-01-01), Date(2023-01-03), Date(2023-01-05)]`
155
+ - `path:asc`: `['news/one.md', 'news/two.md', 'news/three.md']` -> `['news/one.md', 'news/three.md', 'news/two.md']`
156
+ - `order:asc`: `[5,2,6]` -> `[2,5,6]`
157
+
158
+ These examples show how date-ordered collections like posts, news, feeds are sorted in _descending_ order (most recent first) and a timeline would be in _ascending_ order.
159
+
145
160
  ### Rendering collection items
146
161
 
147
- Here is an example of using [@metalsmith/layouts](https://github.com/metalsmith/layouts) with [jstransformer-handlebars](https://github.com/jstransformers/jstransformer-handlebars) to render the `something-happened.md` news item, with links to the next and previous news items (using `refer: true` options):
162
+ > [!IMPORTANT]
163
+ > Mind the difference between **collection** and **collections**: the _collections_ object is stored on `metalsmith.metadata()` and accessible to all files when using @metalsmith/layouts or in-place. Matched files each get an own _collection_ property, - an array of collection names -, with each collection also accessible by name (file.collection\[name]).
164
+
165
+ Here is an example of using [@metalsmith/permalinks](https://github.com/metalsmith/permalinks), followed by [@metalsmith/layouts](https://github.com/metalsmith/layouts) with [jstransformer-nunjucks](https://github.com/jstransformers/jstransformer-nunjucks) to render the `something-happened.md` news item, with links to the next and previous news items (using `refer: true` options):
148
166
 
149
167
  `layouts/news.njk`
150
168
 
151
- ```handlebars
152
- <h1>{{ title }}</h1> {{!-- something-happened.md title --}}
153
- <a href="/{{ collections.news.metadata.slug }}">Back to news</a> {{!-- news collection metadata.slug --}}
169
+ ```nunjucks
170
+ <h1>{{ title }}</h1>
171
+
172
+ {# permalink is expected to be set from collection metadata here #}
173
+ <a href="{{ baseurl }}/{{ collections.news.permalink }}">See all {{ collections.news.title }}</a>
174
+ {% endfor %}
154
175
  {{ contents | safe }}
155
176
  <hr>
156
- {{!-- previous & next are added by @metalsmith/collections --}}
157
- {{#if previous}}
177
+ {{#if collection.news.previous.length }}
158
178
  Read the previous news:
159
- <a href="/{{ previous.path }}">{{ previous.title }}</a>
179
+ <a href="/{{ collection.news.next.permalink }}">{{ collection.news.next.title }}</a>
160
180
  {{/if}}
161
- {{#if next}}
181
+ {{#if collection.news.next.length }}
162
182
  Read the next news:
163
- <a href="/{{ next.path }}">{{ next.title }}</a>
183
+ <a href="/{{ collection.news.previous.permalink }}">{{ collection.news.previous.title }}</a>
164
184
  {{/if}}
165
185
  ```
166
186
 
167
- _Note: If you don't need the `next` and `previous` references, you can pass the option `refer: false`_
187
+ The previous example shows how to get the "first" previous/ next references, the next example show how you can iterate over each collection and render the full list of next/ previous items.
188
+
189
+ ```nunjucks
190
+ <h1>{{ title }}</h1>
191
+
192
+ Part of: {% for name in collection -%}
193
+ <a href="{{ baseurl }}/{{ collections[name].permalink }}">{{ collections[name].title }}</a>{% if not loop.last %}, {% endif%}
194
+ {%- endfor %}
195
+ {% for name in collection %}
196
+ {% if collection[name].previous.length %}
197
+ {% for prev in collection[name].previous %}
198
+ <a href="{{ prev.permalink }}"><-- {{ name }} / {{ prev.title }}</p>
199
+ {% endfor %}
200
+ {% endif %}
201
+ {% for next in collection[name].next %}
202
+ <a href="{{ next.permalink }}"> {{ name }} / {{ next.title }} --></p>
203
+ {% endfor %}
204
+ {% endif %}
205
+ {% endfor %}
206
+ ```
207
+
208
+ The example above supposes an ordering of `pubdate:desc` (newest to oldest) or similar, which is why the "next news" corresponds to the `previous` property.
209
+ If one would map the news dates they would be like: `['2023-01-20', 2023-01-10', '2023-01-01']`.
210
+
211
+ _Note: If you don't need the `next`, `previous`, `first` or `last` references, you can pass the option `refer: false`_
168
212
 
169
213
  ### Rendering collection index
170
214
 
171
- All matched files are added to an array that is exposed as a key of metalsmith global metadata, for example the `news` collection would be accessible at `Metalsmith.metadata().collections.news `. Below is an example of how you could render an index page for the `news` collection:
215
+ All matched files are added to an array that is exposed as a key of metalsmith global metadata, for example the `news` collection would be accessible at `Metalsmith.metadata().collections.news `. Below is a handlebarsexample of how you could render an index page for the `news` collection:
172
216
 
173
217
  `layouts/news-index.hbs`
174
218
 
@@ -176,12 +220,11 @@ All matched files are added to an array that is exposed as a key of metalsmith g
176
220
  <h1>{{ title }}</h1> {{!-- news collection metadata.title --}}
177
221
  <p>{{ description }}</p> {{!-- news collection metadata.description --}}
178
222
  <hr>
179
- {{!-- previous & next are added by @metalsmith/collections --}}
180
223
  {{#if collections.news.length }}
181
224
  <ul>
182
225
  {{#each collections.news}}
183
226
  <li>
184
- <h3><a href="/{{path}}">{{ title }}</a></h3>
227
+ <h3><a href="{{ baseurl }}/{{ permalink }}">{{ title }}</a></h3>
185
228
  <p>{{ excerpt }}</p>
186
229
  </li>
187
230
  {{/each}}
@@ -194,13 +237,13 @@ No news at the moment...
194
237
 
195
238
  ### Custom sorting, filtering and limiting
196
239
 
197
- You could define an `order` property on a set of files and pass `sortBy: "order"` to `@metalsmith/collections` for example, or you could override the sort with a custom function (for example to do multi-level sorting). For instance, this function sorts the "subpages" collection by a numerical "index" property but places unindexed items last.
240
+ You could define an `order` property on a set of files and pass `sort: 'order:asc'` to `@metalsmith/collections` for example, or you could override the sort with a custom function (for example to do multi-level sorting). The function below function sorts the "subpages" collection by a numerical "index" property but places unindexed items last.
198
241
 
199
242
  ```js
200
243
  metalsmith.use(
201
244
  collections({
202
245
  subpages: {
203
- sortBy: function (a, b) {
246
+ sort(a, b) {
204
247
  let aNum, bNum
205
248
 
206
249
  aNum = +a.index
@@ -221,9 +264,9 @@ metalsmith.use(
221
264
  )
222
265
  ```
223
266
 
224
- _Note: the `sortBy` option also understands nested keypaths, e.g. `display.order`_
267
+ _Note: the `sort` option also understands nested keypaths, e.g. `display.order:asc`_
225
268
 
226
- 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. The filterBy function below could work for a collection named `thisYearsNews` as it would filter out all the items that are older than this year:
269
+ The `filter` 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. The filter function below could work for a collection named `thisYearsNews` as it would filter out all the items that are older than this year:
227
270
 
228
271
  ```js
229
272
  function filterBy(file) {
@@ -240,18 +283,18 @@ metalsmith.use(
240
283
  collections({
241
284
  recentArticles: {
242
285
  pattern: 'articles/**/*.html',
243
- sortBy: 'date',
286
+ sort: 'date',
244
287
  limit: 10
245
288
  },
246
289
  archives: {
247
290
  pattern: 'archives/**/*.html',
248
- sortBy: 'date'
291
+ sort: 'date'
249
292
  }
250
293
  })
251
294
  )
252
295
  ```
253
296
 
254
- _Note: the collection is first sorted, reversed, filtered, and then limited, if applicable._
297
+ _Note: the collection is first sorted, filtered, and then limited, if applicable._
255
298
 
256
299
  ### Collection Metadata
257
300
 
@@ -271,14 +314,13 @@ metalsmith.use(
271
314
  )
272
315
  ```
273
316
 
274
- Collection metadata can be loaded from a `json` or `yaml` file (path relative to `Metalsmith.directory()`):
317
+ Collection metadata can be loaded from a `json` or `yaml` file (path relative to `Metalsmith.source()`):
275
318
 
276
319
  ```js
277
320
  metalsmith.use(
278
321
  collections({
279
322
  articles: {
280
- sortBy: 'date',
281
- reverse: true,
323
+ sort: 'date:asc',
282
324
  metadata: 'path/to/file.json'
283
325
  }
284
326
  })
@@ -311,8 +353,7 @@ Add the `@metalsmith/collections` key to your `metalsmith.json` `plugins` key:
311
353
  {
312
354
  "@metalsmith/collections": {
313
355
  "articles": {
314
- "sortBy": "date",
315
- "reverse": true
356
+ "sort": "date:asc"
316
357
  }
317
358
  }
318
359
  }