Skip to content

Commit aa8c682

Browse files
committed
Extend collection from ContentModelNode
Calculate contentType of a collection at the top level ContentModel and pass it down to the collection. Collection accesses it via settings.contentType. Fix root collection json rendering path. Add a getSlug template method to ContentModelEntryNode. It's called before setting permalink and outputPath. Allows outliers like collection to implement a custom slug mechanism and let it cascade to permalink and outputPath. For that reason exactly, add an __originalAttributes__ field to what parseTextEntry returns. In it, there are non-overridden values of title and slug. So, collection can ignore auto-slugging in case slug is null in the front-matter. That allows collection acting like root. Implement a serialize method at the top level ContentModel class, serialize itself before passing its tree down to model renders. Serialize every model before passing itself to template in render.
1 parent bc5c9dc commit aa8c682

File tree

12 files changed

+463
-396
lines changed

12 files changed

+463
-396
lines changed

src/compiler/contentModel/index.js

Lines changed: 55 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@ const { resolve } = require('path')
22
const _ = require('lodash')
33
const frontMatter = require('front-matter')
44
const ImmutableStack = require('../../lib/ImmutableStack')
5-
const { isTemplateFile } = require('./helpers')
5+
const { removeExtension, isTemplateFile } = require('../../lib/contentModelHelpers')
66
const createMatchers = require('./matchers')
7+
78
const models = {
89
Homepage: require('./models/homepage'),
910
Subpage: require('./models/subpage'),
10-
collection: require('./models/collection'),
11+
Collection: require('./models/collection'),
1112
Asset: require('./models/asset')
1213
}
1314

@@ -88,7 +89,7 @@ const linkBack = (post, entry, key) => {
8889

8990
const linkEntries = (contentModel) => {
9091
contentModel.collections.forEach(collection => {
91-
collection.posts.forEach(post => {
92+
collection.subtree.posts.forEach(post => {
9293
const fields = Object.keys(post)
9394
Object.keys(post).forEach(key => {
9495
const value = post[key]
@@ -141,6 +142,15 @@ const defaultContentModelSettings = {
141142
mode: 'start'
142143
}
143144
class ContentModel {
145+
static serialize(contentModel) {
146+
return {
147+
homepage: models.Homepage.serialize(contentModel.homepage),
148+
subpages: contentModel.subpages.map(models.Subpage.serialize),
149+
collections: contentModel.collections.map(models.Collection.serialize),
150+
assets: contentModel.assets.map(models.Asset.serialize)
151+
}
152+
}
153+
144154
constructor(contentModelSettings = defaultContentModelSettings, contentTypes = []) {
145155
this.settings = {
146156
...defaultContentModelSettings,
@@ -172,47 +182,35 @@ class ContentModel {
172182
permalink: this.settings.permalinkPrefix
173183
}])
174184

175-
this.models = {
176-
collection: models.collection({
177-
defaultCategoryName: this.settings.defaultCategoryName,
178-
collectionAliases: [
179-
...this.contentTypes
180-
.filter(ct => ct.model === 'collection')
181-
.map(ct => ct.collectionAlias),
182-
...(indexProps.attributes?.collectionAliases || [])
183-
],
184-
mode: this.settings.mode
185-
}, this.contentTypes, this.matchers),
186-
187-
Subpage: models.Subpage,
188-
189-
Homepage: models.Homepage,
190-
191-
Asset: models.Asset
192-
}
193-
194185
this.contentModel = {
195-
homepage: new this.models.Homepage({
196-
name: 'index',
197-
extension: 'md',
198-
content: ''
199-
}, context, { homepageDirectory: this.settings.homepageDirectory }),
186+
homepage: new models.Homepage(
187+
{ name: 'index', extension: 'md', content: '' },
188+
context,
189+
{ homepageDirectory: this.settings.homepageDirectory }
190+
),
200191
subpages: [],
201192
collections: [],
202193
assets: []
203194
}
204195

196+
this.collectionAliases = [
197+
...this.contentTypes
198+
.filter(ct => ct.model === 'collection')
199+
.map(ct => ct.collectionAlias),
200+
...(indexProps.attributes?.collectionAliases || [])
201+
]
202+
205203
fileSystemTree.forEach(node => {
206204
if (this.matchers.homepage(node)) {
207-
this.contentModel.homepage = new this.models.Homepage(node, context, {
205+
this.contentModel.homepage = new models.Homepage(node, context, {
208206
homepageDirectory: this.settings.homepageDirectory
209207
})
210208
return
211209
}
212210

213211
if (this.matchers.subpage(node)) {
214212
return this.contentModel.subpages.push(
215-
new this.models.Subpage(node, context, {
213+
new models.Subpage(node, context, {
216214
pagesDirectory: this.settings.pagesDirectory
217215
})
218216
)
@@ -222,22 +220,39 @@ class ContentModel {
222220
return node.children.forEach(childNode => {
223221
if (this.matchers.subpage(childNode)) {
224222
this.contentModel.subpages.push(
225-
new this.models.subpage(childNode, context, {
223+
new models.subpage(childNode, context, {
226224
pagesDirectory: this.settings.pagesDirectory
227225
})
228226
)
229227
} else if (this.matchers.asset(childNode)) {
230228
this.contentModel.assets.push(
231-
new this.models.Asset(childNode, context, {
229+
new models.Asset(childNode, context, {
232230
assetsDirectory: this.settings.assetsDirectory
233231
})
234232
)
235233
}
236234
})
237235
}
238236

239-
if (this.models.collection.match(node)) {
240-
const collection = this.models.collection.create(node, context)
237+
if (this.matchers.collection(node, this.collectionAliases)) {
238+
const indexFile = node.children.find(
239+
this.matchers.collectionIndexFile(this.collectionAliases)
240+
)
241+
242+
const contentType = this.contentTypes
243+
.filter(ct => ct.model === 'collection')
244+
.find(ct => {
245+
return ct.collectionAlias === (indexFile ? removeExtension(indexFile.name) : node.name)
246+
})
247+
248+
const collection = new models.Collection(node, context, {
249+
defaultCategoryName: this.settings.defaultCategoryName,
250+
collectionAliases: this.collectionAliases,
251+
mode: this.settings.mode,
252+
contentTypes: this.contentTypes,
253+
contentType
254+
})
255+
241256
if (this.draftCheck(collection)) {
242257
this.contentModel.collections.push(collection)
243258
}
@@ -247,7 +262,7 @@ class ContentModel {
247262
if (this.matchers.assetsDirectory(node)) {
248263
return this.contentModel.assets.push(
249264
...node.children.map(childNode => {
250-
return new this.models.Asset(childNode, context, {
265+
return new models.Asset(childNode, context, {
251266
assetsDirectory: this.settings.assetsDirectory
252267
})
253268
})
@@ -256,7 +271,7 @@ class ContentModel {
256271

257272
if (this.matchers.asset(node)) {
258273
return this.contentModel.assets.push(
259-
new this.models.Asset(node, context, {
274+
new models.Asset(node, context, {
260275
assetsDirectory: this.settings.assetsDirectory
261276
})
262277
)
@@ -271,7 +286,7 @@ class ContentModel {
271286
linkEntries(this.contentModel)
272287

273288
this.contentModel.collections.forEach(collection => {
274-
this.models.collection.afterEffects(this.contentModel, collection)
289+
collection.afterEffects(this.contentModel)
275290
})
276291

277292
this.contentModel.subpages.forEach(subpage => {
@@ -288,7 +303,7 @@ class ContentModel {
288303
render(renderer) {
289304
const renderHomepage = () => {
290305
return this.contentModel.homepage.render(renderer, {
291-
contentModel: this.contentModel,
306+
contentModel: ContentModel.serialize(this.contentModel),
292307
settings: this.settings,
293308
debug: this.settings.debug
294309
})
@@ -297,8 +312,8 @@ class ContentModel {
297312
const renderCollections = () => {
298313
return Promise.all(
299314
this.contentModel.collections.map(collection => {
300-
return this.models.collection.render( renderer, collection, {
301-
contentModel: this.contentModel,
315+
return collection.render(renderer, {
316+
contentModel: ContentModel.serialize(this.contentModel),
302317
settings: this.settings,
303318
debug: this.settings.debug
304319
})
@@ -310,7 +325,7 @@ class ContentModel {
310325
return Promise.all(
311326
this.contentModel.subpages.map(subpage => {
312327
return subpage.render(renderer, {
313-
contentModel: this.contentModel,
328+
contentModel: ContentModel.serialize(this.contentModel),
314329
settings: this.settings,
315330
debug: this.settings.debug
316331
})

src/compiler/contentModel/matchers.js

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,25 @@ module.exports = function createMatchers(settings) {
2626
return matchers.homepageFile(fsNode) || matchers.homepageDirectory(fsNode)
2727
},
2828

29-
collection: fsNode => {},
29+
collectionIndexFile: (collectionAliases) => (fsNode) => {
30+
const indexFileNameOptions = [ ...collectionAliases, 'collection' ].filter(Boolean)
31+
32+
return isTemplateFile(fsNode) && fsNode.name.match(
33+
new RegExp(`^(${indexFileNameOptions.join('|')})\\..+$`)
34+
)
35+
},
36+
37+
collectionDataFile: (fsNode, parentNode) => {
38+
return fsNode.name.match(new RegExp(`^${parentNode.name}\\.json$`, 'i'))
39+
},
40+
41+
collection: (fsNode, collectionAliases) => {
42+
const hasCollectionIndex = fsNode.children?.find(matchers.collectionIndexFile(collectionAliases))
43+
const hasCollectionData = fsNode.children?.find(childNode => {
44+
return matchers.collectionDataFile(childNode, fsNode)
45+
})
46+
return hasCollectionIndex || hasCollectionData
47+
},
3048

3149
category: (fsNode) => {
3250
fsNode.children?.find(childNode => {

src/compiler/contentModel/models/asset.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ const defaultSettings = {
66
assetsDirectory: 'assets'
77
}
88
class Asset extends ContentModelResourceNode {
9+
static serialize(asset) {
10+
return asset
11+
}
12+
913
constructor(fsNode, context, settings = defaultSettings) {
1014
super(fsNode, context, settings)
1115
}

src/compiler/contentModel/models/attachment.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
const ContentModelResourceNode = require('../../../lib/ContentModelResourceNode')
22

33
class Attachment extends ContentModelResourceNode {
4+
static serialize(attachment) {
5+
return attachment
6+
}
7+
48
constructor(fsNode, context) {
59
super(fsNode, context)
610
}

src/compiler/contentModel/models/collection/category.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,10 @@ class Category extends ContentModelEntryNode {
4040
const data = {
4141
...category,
4242
facets: category.facets.map(models.facet().serialize),
43-
posts: category.subtree.posts,
44-
levelPosts: category.subtree.levelPosts,
45-
categories: category.subtree.categories,
46-
attachments: category.subtree.attachments
43+
posts: category.subtree.posts.map(models.Post.serialize),
44+
levelPosts: category.subtree.levelPosts.map(models.Post.serialize),
45+
categories: category.subtree.categories.map(Category.serialize),
46+
attachments: category.subtree.attachments.map(models.Attachment.serialize)
4747
}
4848

4949
if (entriesAlias) {

0 commit comments

Comments
 (0)