From 3462bfffa60038a68ffe82df54c77938588e9c03 Mon Sep 17 00:00:00 2001 From: Kevin Van Lierde Date: Mon, 7 Aug 2023 22:22:00 +0200 Subject: [PATCH] BREAKING: Make metadata accessible from Collection array instead of '.metadata' property --- src/index.js | 45 +++++++++++++++++++++++++++------------------ test/index.cjs | 43 ++++++++++++++++++++++++++++++++++++------- 2 files changed, 63 insertions(+), 25 deletions(-) diff --git a/src/index.js b/src/index.js index ea8fb8a..49e2b2a 100755 --- a/src/index.js +++ b/src/index.js @@ -22,6 +22,19 @@ function sortBy(key, order) { } } +/** + * @param {import('metalsmith').File[]} items + * @param {CollectionConfig} config + */ +function Collection(items, { metadata, ...config }) { + const collection = [...items] + Object.assign(collection, metadata) + collection.config = config + collection.constructor = Collection + Object.seal(collection) + return collection +} + const defaultSort = sortBy('path', 'asc') const defaultFilter = () => true @@ -140,11 +153,11 @@ function collections(options) { debug('Identified %s collections: %s', mappedCollections.length, collectionNames.join()) - mappedCollections.forEach((collection) => { - const { pattern, filter, sort, refer, limit } = collection - const name = collection.name + mappedCollections.forEach((collectionConfig) => { + const { pattern, filter, sort, refer, limit } = collectionConfig + const name = collectionConfig.name const matches = [] - debug('Processing collection %s with options %s:', name, collection) + debug('Processing collection %s with options %s:', name, collectionConfig) // first match by pattern if provided if (pattern) { @@ -159,8 +172,8 @@ function collections(options) { } else if (typeof data.collection === 'string') { data.collection = [data.collection] } - if (!data.collection.includes(collection.name)) { - data.collection = [...data.collection, collection.name] + if (!data.collection.includes(collectionConfig.name)) { + data.collection = [...data.collection, collectionConfig.name] } return data }) @@ -173,27 +186,24 @@ function collections(options) { Object.values(files).filter((file) => { const patternMatched = matches.includes(file) const isInCollection = Array.isArray(file.collection) - ? file.collection.includes(collection.name) - : file.collection === collection.name + ? file.collection.includes(collectionConfig.name) + : file.collection === collectionConfig.name return !patternMatched && isInCollection }) ) - if (Object.prototype.hasOwnProperty.call(metadata, name)) { - debug('Warning: overwriting previously set metadata property %s', name) - } // apply sort, filter, limit options in this order - let currentCollection = (metadata.collections[name] = matches) - + let currentCollection = matches // safely add to and remove from the sorting context 'path' property const originalPaths = [] currentCollection.forEach((item) => { if (item.path) originalPaths.push([item, item.path]) item.path = metalsmith.path(Object.entries(files).find((entry) => entry[1] === item)[0]) }) - currentCollection = currentCollection.sort(sort) - currentCollection = metadata.collections[name] = currentCollection.filter(filter).slice(0, limit) + + currentCollection = currentCollection.sort(sort).filter(filter).slice(0, limit) + currentCollection.forEach((item) => { const original = originalPaths.find(([file]) => file === item) if (original) { @@ -203,9 +213,8 @@ function collections(options) { } }) - if (collection.metadata) { - currentCollection.metadata = collection.metadata - } + metadata.collections[name] = Collection(currentCollection, collectionConfig) + if (refer) { const lastIndex = currentCollection.length - 1 currentCollection.forEach((file, i) => { diff --git a/test/index.cjs b/test/index.cjs index eb7e12c..f866b55 100755 --- a/test/index.cjs +++ b/test/index.cjs @@ -292,38 +292,67 @@ describe('@metalsmith/collections', function () { }) }) - it('should add metadata objects to collections', function (done) { + it('should add metadata objects to collections', function () { const metalsmith = Metalsmith('test/fixtures/basic') + return metalsmith + .use( + collections({ + articles: { + metadata: { name: 'Batman', test: 'Batman' } + } + }) + ) + .build() + .then(() => { + const m = metalsmith.metadata() + assert.strictEqual(m.collections.articles.test, 'Batman') + }) + }) + + it('should provide access to collection config via collection metadata', function () { + const metalsmith = Metalsmith('test/fixtures/basic') + return metalsmith + .use(collections({ articles: { refer: false }})) + .build() + .then(() => { + const m = metalsmith.metadata() + assert.strictEqual(m.collections.articles.config.limit, Infinity) + assert.strictEqual(m.collections.articles.config.refer, false) + }) + }) + + it('should load collection metadata from a JSON file', function (done) { + const metalsmith = Metalsmith('test/fixtures/metadata') metalsmith .use( collections({ articles: { - metadata: { name: 'Batman' } + metadata: 'metadata.json' } }) ) .build(function (err) { if (err) return done(err) const m = metalsmith.metadata() - assert.strictEqual('Batman', m.collections.articles.metadata.name) + assert.strictEqual('Batman', m.collections.articles.name) done() }) }) - it('should load collection metadata from a JSON file', function (done) { + it('should load collection metadata from a YAML file', function (done) { const metalsmith = Metalsmith('test/fixtures/metadata') metalsmith .use( collections({ articles: { - metadata: 'metadata.json' + metadata: 'metadata.yaml' } }) ) .build(function (err) { if (err) return done(err) const m = metalsmith.metadata() - assert.strictEqual('Batman', m.collections.articles.metadata.name) + assert.strictEqual('Batman', m.collections.articles.name) done() }) }) @@ -341,7 +370,7 @@ describe('@metalsmith/collections', function () { .build(function (err) { if (err) return done(err) const m = metalsmith.metadata() - assert.strictEqual('Batman', m.collections.articles.metadata.name) + assert.strictEqual('Batman', m.collections.articles.name) done() }) })